【问题标题】:Jasmine.js Testing - spy on window.navigator.userAgentJasmine.js 测试 - 监视 window.navigator.userAgent
【发布时间】:2018-03-30 02:12:31
【问题描述】:

我需要找到改变userAgent 值的方法。我试过spyOnwindow.navigator.userAgent。但这无济于事。

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;
    }
  }
}

规格

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

我期待1111,但得到了关于我的浏览器的真实信息。

【问题讨论】:

  • 我建议将原生 api 调用封装到紧凑的函数中(如 adequatelygood.com/Writing-Testable-JavaScript.html),并监视这些函数而不是原生 api。依赖紧密的功能使您的代码更便携(服务器端渲染、多浏览器问题等)和可测试性。我总是在用 jasmine 监视原生窗口 api 时遇到问题。

标签: angular unit-testing jasmine karma-jasmine spyon


【解决方案1】:

userAgentwindow.navigator 上的只读/常量属性。而jasmine.createSpy 通常用于创建方法而不是属性的间谍。

现在,我尝试直接执行window.navigator.userAgent = '1111';,因为window.navigator 在我的测试中很容易访问。但我收到一条错误消息:

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

所以唯一的选择是使用旧的__defineGetter__。这就是我在这里所做的:

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

而且它有效:

希望这会有所帮助!

【讨论】:

  • 为了清洁起见:测试后有什么方法可以撤消此操作?
  • 这应该使用spyOnProperty 而不是覆盖窗口实现。正确答案见stackoverflow.com/a/56625422/881643
【解决方案2】:

我得到了一个使用 Jasmine api 本身的简单解决方案。

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

根据您的要求修改每个测试中的间谍。

不确定此 API 来自哪个 Jasmine 版本,但 v3.4 支持此 API

一旦您窥探到任何全局属性,最好清除该 spy afterEach 测试。

例如。

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

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

  afterEach(function() {
    window.navigator = NAVIGATOR;
  });
}

【讨论】:

  • 这应该在“正确答案”上标明!过去一天我一直在寻找有效的答案。尴尬的是,这么简单,我应该早点想出来的。谢谢@Subroto,这对我有用。
  • 为什么需要重置导航器? spyOnProperty 应该在每个测试用例之后自动重置。退后一步,即使它没有被重置,spyOnProperty 也会更新 window.navigator.userAgent 并且更改将与原始导航器一起进行。您应该重置 window.navigator.userAgent getter。
  • 重置任何属性是好的,这样测试就不会出现一些意外行为。如果两个测试(外层)需要相同的 navigator 属性但用例不同,则重置该属性将确保不会发生意外情况。
【解决方案3】:

我意识到这已经过时了,但是为了扩展 SiddAjmera 的答案,这是我为测试特定于 safari 的行为所做的。在测试结束时,它还会重置 userAgent,因此其他测试不会受到影响(正如 Pieter De Bie 在评论中要求的那样)。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-16
    相关资源
    最近更新 更多