1

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 = '[email protected]';
        const textArr = ['[email protected]']

        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();

        }));

2 Answers 2

2

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 = '[email protected]';
        const textArr = ['[email protected]']

        let getArr: string[];

        getArr = component.getTextArray(tex);

        expect(getArr.length).toBe(1);
        expect(getArr[0]).toBe(text);
    })
})
...
Sign up to request clarification or add additional context in comments.

10 Comments

Ok thank I will try this. Can I ask you a general question, where do I create the Stub Class in the folder from the service or what is here the best practice?
I usually have a folder for class stubs, especially when stubbing imported libs. But I don't think there is a written best practice for this..."Keep it simple" is what I go for
So I tried this but still get the same error. Is it because for the service the third library ngx-cookie-service is used?
no... this approach should stub any angular service, i does not matter if it is coming from an imported lib or from your code. did you change the "useValue" for "useClass" ?
Thanks for the clarification. Yes I changed it to useClass. I can update my question
|
0

jasmine.createSpyObj is used to create mocks that will spy on methods. It will return an object for each property defined in the spy.

You can create a mockCookieService and add the get method

mockCookieService = jasmine.createSpyObj('CookieService', ['get']);

Try like this:

describe('Service: ', () => {

  let mockCookieService;

  beforeEach(() => {
    mockCookieService = jasmine.createSpyObj('CookieService', ['get']);

    TestBed.configureTestingModule({
      imports: [
          ...
      ],
      providers: [
        { provide: CookieService, useValue: mockCookieService },
      ]
    });

  });

You can refer this article

3 Comments

I tried this already but get the same error :/
In your test module - try importing CookieModule.forRoot()
I as well read about this, but get the error :TS2304: Cannot find name 'CookieModule'. I think the prject uses here the wrong version

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.