9

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.

f.khantsis
  • 3,256
  • 5
  • 50
  • 67
  • Try removing LOCALE_ID from configureTestingModule, because as soon as you call compileComponents, the providers are frozen and won't be overridden. If that doesn't work, try removing compile components and creating component instance in every test. It's simpler with services, but with compoent instance, you will have to call compileComponents with every test before creating the component instance(never tried it). – Akshay Rana Oct 30 '19 at 17:49
  • I tried it, it should work – Akshay Rana Oct 30 '19 at 17:54

1 Answers1

15

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
  });
Yuri
  • 4,254
  • 1
  • 29
  • 46
Akshay Rana
  • 1,455
  • 11
  • 20
  • so why does it work in the first case, overriding `LANGUAGE_TOKEN`? – f.khantsis Oct 30 '19 at 17:58
  • You don't have LANGUAGE_TOKEN in providers array, you can also do something similar with LOCALE_ID. Remove it from providers array and just add it via overrideProviders before creating the component instance. Let me update the answer for more clearity. – Akshay Rana Oct 30 '19 at 18:03
  • 1
    In a service test, this still doesn't work. I'm getting always the value declared while configureTestingModule and not the one that i provided as an override. Any news on that? – Rambou May 29 '20 at 14:22