2

I am using jasmine to write a unit test in angular. The method uses the the window.navigator property. The property is defined outside the method like below

declare var navigator: any;
navigator = window.navigator;

In the method to be tested the below code is present which is to be tested

let locale = navigator.language || navigator.userLanguage || navigator.browserLanguage; 

The first condition navigator.language gets covered automatically while running the unit test. I want to cover all branches of this code ie, I want to cover all OR conditions while testing. How do I mock the navigator in unit test?

s_v
  • 132
  • 1
  • 14
  • 1
    Please, have a look at this [answer](https://stackoverflow.com/questions/46806185/jasmine-js-testing-spy-on-window-navigator-useragent). – Anand Bhushan Jun 07 '19 at 06:15
  • A more specific link to the answer referred by Anand: https://stackoverflow.com/a/56625422/1094673 – Bob Jun 19 '23 at 16:17

2 Answers2

2

I created a custom InjectionToken for it, which can easily be passed in via constructor in Service-tests:


app/tokens/navigator.injection-token.ts:

import { InjectionToken } from '@angular/core';

export const NavigatorToken = new InjectionToken('navigator-token');

app/app.module.ts:

import { NavigatorToken } from './tokens/navigator.injection-token.ts';

@NgModule({
  providers: [
    {
      provide: NavigatorToken,
      useValue: navigator,
    }
  ]
})
export class AppModule {}

app/services/language-service.ts:

export class MyService {
  constructor(@Inject(NavigatorToken) private navigatorInstance: typeof navigator) {}

  get browserLanguage(): string {
    return this.navigatorInstance.language;
  }
}

Test:

describe('MyService', () => {
  let service: MyService;

  beforeEach(() => {
    service = new MyService({ language: 'mock-lang' } as any);
  });

  it('should work', () => {
    expect(service.browserLanguage).toBe('mock-lang');
  });
});
jlang
  • 929
  • 11
  • 32
0

I created a method to return the navigator instead of refering it directly and then mocked the same method in the spec file.

In the component.ts file-

// method that returns navigator object
public getNavigatorReference(): any {
    return navigator;
}

// method that uses the above method
private methodThatUsesNavigator(): void {
   let navigatorReference = this.getNavigatorReference();
   let locale = navigatorReference.language || navigatorReference.userLanguage || 
   navigatorReference.browserLanguage;
...
}

In the spec file -

Object.defineProperty(navigator, 'userLanguage', {
      get: function () { return 'en'; }
});
s_v
  • 132
  • 1
  • 14
  • This is not the way to go, Angular encourages you to use the DI for exact this type of testing purposes – jlang Jul 12 '23 at 13:50