angularunit-testingngx-cookie-service

Unit Test Error when having CookieService as argument in constructor of tested component


I would like to test a function. To call that function in unit test I need to create an instance of the component class. The component class contains different services as arguments in the constructor including the service CookieService. The service depends on the third-library 'ngx-cookie' which has setters and getters.

I tried to mock the service to be able to create an instance of the component class like this:

import {CookieService} from "ngx-cookie-service";
....
    
 beforeEach(async(() => {
            const mockedFormBuilder = jasmine.createSpyObj('FormBuilder', ['control', 'array', 'group']);
            
            const get = function get(name: string): string {
            
                return 'test...';
            };

    TestBed.configureTestingModule({
                declarations: [HelloWorldComponent,...],
                imports: [
                    ...    
                ],
                providers: [
                    {provide: FormBuilder, useValue: mockedFormBuilder},
                    {provide: CookieService, useValue: get('name')},
                ]
    
            })
                .compileComponents();
    
        }));

describe('getArr', () => {

    it('should return array', () => {

        const text = 'text@domain.com';
        const textArr = ['text@domain.com']

        let getArr: string[];


        // @ts-ignore
        getArr = new HelloWorldComponent(FormBuilder,CookieService).getTextArray(tex);

        expect(getArr).toBe(textArr);
    })
})

Following error appears when running the test:

TypeError: this.cookieService.get is not a function
    at <Jasmine>
    at new HelloWorldComponent(http://localhost:9876/_karma_webpack_/src/app/helloworld.component.ts:63:51)
    at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/src/app/helloworld.component.spec.ts:113:28)
    at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:359:1)
    at ProxyZoneSpec.onInvoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:308:1)
    at ZoneDelegate.invoke (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:358:1)
    at Zone.run (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:124:1)
    at runInTestZone (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:561:1)
    at UserContext.<anonymous> (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:576:1)

This is how the ComponentClass looks like:

export class HelloWorldComponent {
   constructor(private fb: FormBuilder, private cookieService:CookieService){
     const cookie:string=this.cookieService.get('somename')
   }
}

I understand that the cookieService has no function but a getter and setter, but I do not quite get how to mock the getter and how to correctly insert it in providers

Does someone came accross the same error when testing and how did you solved it?

Any help would be very appreciated!


Update: Use Stub Service

export class CookieServiceStub{
    cookie:string= 'gdhjgsfgsjdfg';
    get (name:string):string{
        return this.cookie;
    }
}

In Spec file: ...

TestBed.configureTestingModule({
                declarations: [HelloWorldComponent,...],
                imports: [
                    ...    
                ],
                providers: [
                    {provide: FormBuilder, useValue: mockedFormBuilder},
                    {provide: CookieService, useClass:CookieServiceStub},
                ]

            })
                .compileComponents();

        }));

Solution

  • You are currently providing the result of the call get('name') as the value of your CookieService service. I think this is incorrect... here:

    {provide: CookieService, useValue: get('name')}
    

    It is a little easier to create a Stub Class in this case:

    first figure in your component the functions you are calling from the service, then create a Stub Class for it:

    class CookieServiceStub{
      get(name: string) {
        return 'your value'
      }
    
      secondFunction() {} 
      // add as many as necessary
    }
    

    Then you can replace your provision of the CookieService with your stub class:

    {provide: CookieService, useClass: CookieServiceStub}
    

    Also in your test, you are creating a new instance of the component class, out of angular's scope, This needs to be adjusted. Instead of doing this:

    getArr = new HelloWorldComponent(FormBuilder,CookieService).getTextArray(tex);
    

    you should create it with the TestBed:

    ...  
      let component: HelloWorldComponent;
      beforeEach(() => {
        fixture = TestBed.createComponent(HelloWorldComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
      });
    
      describe('getArr', () => {
        it('should return array', () => {
            const text = 'text@domain.com';
            const textArr = ['text@domain.com']
    
            let getArr: string[];
    
            getArr = component.getTextArray(tex);
    
            expect(getArr.length).toBe(1);
            expect(getArr[0]).toBe(text);
        })
    })
    ...