Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override a TestBed Provider for specific test

I have a component, which has two dependencies: one is LOCALE_ID defined globally in angular, another is language, defined in the Component as { provide: LANGUAGE_TOKEN, useValue: navigator.language }

For testing, I am both overriding them in TestBed for all tests, so tests don't get anything injected from the Chrome browser doing the karma tests, and tests don't have different result based on testing environment:

TestBed.configureTestingModule({
  declarations: [
    MyComponent, RouterStubComponent,
  ],
  imports: [
    MatToolbarModule, RouterTestingModule, MatIconModule, MatButtonModule,
  ],
  providers: [
    {provide: LOCALE_ID, useValue: 'en-US' },
  ]
}).compileComponents();

TestBed.overrideProvider(LOCATION_TOKEN, {useValue: locationStub});
TestBed.overrideProvider(LANGUAGE_TOKEN, {useValue: 'en-US' });

Now I have some logic in the component that depends on locale and browser language, so I need to mock them. Mocking LANGUAGE_TOKEN was super easy, barely an inconvenience:

 it('should redirect to spanish when in spanish browser', () => {
    TestBed.overrideProvider(LANGUAGE_TOKEN, {useValue: 'es'});
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

    expect(hrefSpy.calls.count()).toBe(1);
    expect(hrefSpy.calls.argsFor(0)[0]).toEqual(environment.spanUrl);
  });

However override LOCALE_ID with same code doesn't work.

  it('should ...', () => {
    TestBed.overrideProvider(LOCALE_ID, {useValue: 'es-ES'});
    console.log(TestBed.get(LOCALE_ID)); // en-US!!!!
    fixture = TestBed.createComponent(MamanComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

    expect(hrefSpy.calls.count()).toBe(1); //FAIL
    expect(hrefSpy.calls.argsFor(0)[0]).toEqual(environment.engUrl);//FAIL
  });

I was unable to find a working answer in this question either.

like image 268
f.khantsis Avatar asked Oct 30 '19 17:10

f.khantsis


People also ask

How do you override a provider?

To override a provider you need to call the Provider. override() method. This method receives a single argument called overriding . If the overriding value is a provider, this provider is called instead of the original.

What can I use instead of TestBed?

TestBed.get() was deprecated as of Angular version 9. To help minimize breaking changes, Angular introduces a new function called TestBed.inject() , which you should use instead.

What is TestBed in unit testing?

TestBed is used to configure and initialize the environment unit tests. The describe code block represents the test suite for AppComponent. It contains specs and additional code that's used for testing AppComponent. beforeEach is a global function in Jasmine that runs some setup code before each spec in the test suite.

What does TestBed createComponent do?

TestBed. createComponent() creates an instance of the BannerComponent , adds a corresponding element to the test-runner DOM, and returns a ComponentFixture . Do not re-configure TestBed after calling createComponent .


1 Answers

This is because as soon as you call compileComponents, the providers are frozen and won't be overridden.

Either remove LOCALE_ID from the providers so that it's value is not frozen. (But make sure to provide it using overrideProviders before creating the component instance):

TestBed.configureTestingModule({
  declarations: [
    MyComponent, RouterStubComponent,
  ],
  imports: [
    MatToolbarModule, RouterTestingModule, MatIconModule, MatButtonModule,
  ],
  providers: [
    --> remove 
  ]
}).compileComponents();

TestBed.overrideProvider(LOCALE_ID, {useValue: 'es-ES'});
//Add it before creating component, to have a default value in each test, add it in a beforeEach block.

Or you can call compileComponents before creating component instance in each test:

TestBed.configureTestingModule({
  declarations: [
    MyComponent, RouterStubComponent,
  ],
  imports: [
    MatToolbarModule, RouterTestingModule, MatIconModule, MatButtonModule,
  ],
  providers: [
    {provide: LOCALE_ID, useValue: 'en-US' },
  ]
});
--> remove compileComponents

Then in every test :

it('should ...', () => {
    TestBed.overrideProvider(LOCALE_ID, {useValue: 'es-ES'});
    // Add here
    TestBed.compileComponents();
    fixture = TestBed.createComponent(MamanComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();

    expect(hrefSpy.calls.count()).toBe(1); //FAIL
    expect(hrefSpy.calls.argsFor(0)[0]).toEqual(environment.engUrl);//FAIL
  });
like image 189
Akshay Rana Avatar answered Oct 13 '22 01:10

Akshay Rana