Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jasmine.js Testing - spy on window.navigator.userAgent

I need to find the way to change userAgent value. I tried to spyOn the window.navigator.userAgent. But that's not helping.

JS:

@Injectable()
export class DetectBrowserService {
  browserIE: boolean;
  constructor() {
    this.browserIE = this.detectExplorer();
  }

  public detectExplorer() {
    const brows = window.navigator.userAgent;
    const msie = brows.indexOf('MSIE ');
    if (msie > 0) {
      // IE 10 or older => return version number
      return true;
    }
  }
}

Spec:

it('should test window.navigator.userAgent', () => {
  const wind = jasmine.createSpy('window.navigator.userAgent');
  wind.and.returnValue('1111');
  detectBrowserService = TestBed.get(DetectBrowserService);
  console.log(window.navigator.userAgent);
});

I was expecting 1111, but got the real info about my browser.

like image 950
user3319778 Avatar asked Oct 18 '17 08:10

user3319778


3 Answers

I got a simple solution using Jasmine apis itself.

spyOnProperty(window.navigator, 'userAgent').and.returnValue('Mozilla');

modify the spy in each test as per your requirement.

Not sure from which Jasmine version this API is present, but v3.4 supports this API

Once you spy any global property, it is a good practice to clear that spy afterEach test.

Eg.

describe('Test', function() {
  const NAVIGATOR = window.navigator;

  beforeEach(function() {
    spyOnProperty(window.navigator, 'userAgent').and.returnValue('Mozilla');
  })

  afterEach(function() {
    window.navigator = NAVIGATOR;
  });
}
like image 86
phoenisx Avatar answered Nov 10 '22 22:11

phoenisx


I realize this is old, but to expand on SiddAjmera's answer, here's what I did to test a safari-specific behavior. At the end of the test, it also resets the userAgent so other tests aren't affected (as Pieter De Bie requested in a comment).

it('should redirect if the user is on safari', () => {
  const originalUserAgent = navigator.userAgent;

  fixture = TestBed.createComponent(ComponentToTest);
  component = fixture.componentInstance;

  navigator['__defineGetter__']('userAgent', () => {
    return 'safari';
  });
  fixture.detectChanges();

  component.methodToTest();

  expect(component['window'].location.href).toBe('redirecturl.com');

  // unset the userAgent after test
  navigator['__defineGetter__']('userAgent', () => {
    return originalUserAgent;
  });
});
like image 31
Paul Cullen Rowe Avatar answered Nov 10 '22 22:11

Paul Cullen Rowe


userAgent is a read-only/constant property on window.navigator. And jasmine.createSpy is generally used to create spies on methods and NOT properties.

Now, I tried directly doing window.navigator.userAgent = '1111'; as window.navigator would simply be accessible in my tests. But I was getting an error saying:

[ts] Cannot assign to 'userAgent' because it is a constant or a read-only property. (property) NavigatorID.userAgent: string

enter image description here

So the only option was to use the good old __defineGetter__. So that's what I did here:

it('should test window.navigator.userAgent', () => {
  window.navigator['__defineGetter__']('userAgent', function(){
    return '1111' // Return whatever you want here
  });
  detectBrowserService = TestBed.get(DetectBrowserService);
  console.log(window.navigator.userAgent);
});

And it works: enter image description here

Hope this helps!

like image 18
SiddAjmera Avatar answered Nov 10 '22 23:11

SiddAjmera