history.back 在 Karma 中表现不尽如人意

history.back not behaving as expected in Karma

当我 运行 像这样的基本测试用例时:

  fdescribe('Browser back button', () => {

    fit('should return to previous', async () => {

      const originalHref = window.location.href;
      window.history.pushState({}, 'Test', '/test');
      window.history.back();  // This doesn't seem to be working.
      expect(window.location.href).toEqual(originalHref);
    });

我收到一条失败消息“预期 'http://localhost:9876/test' 等于 'http://localhost:9876/context.html'”。很明显,pushState() 有效,但 back() 无效。

Karma 运行s 在内部 iframe 中进行测试。当我按顺序将前三行粘贴到浏览器的 JavaScript 控制台时,导航按预期工作。因此,在这种情况下,window 的行为与内部 iframe 的行为之间一定存在某些不同之处。

这是 Chrome 上的 Karma 5.1。

有什么想法吗?

问题是 history.back() API 是异步的

This method is asynchronous. Add a listener for the popstate event in order to determine when the navigation has completed.

所以导航返回被触发但是测试没有等待它完成并且检查失败。

我们需要通过添加 done 参数将测试转换为异步测试(这是我知道的一种方法,也许还有其他方法)。并使用 popstate 事件处理程序等待导航并完成测试。

fdescribe('Browser back button', () => {
  fit('should return to previous', (done) => {
    const originalHref = window.location.href;
    window.history.pushState({}, 'Test', '/test');

    window.history.back(); // gets executed asynchonously
    window.addEventListener('popstate', () => {
      // history.back() is done now
      expect(window.location.href).toEqual(originalHref);
      done();
    })
  });
});

Vitalii 的答案是最普遍适用的答案,因为它仅依赖浏览器内置插件。这是 Angular 用户的基本套件,基于他们的代码。

import { ComponentFixture, TestBed } from '@angular/core/testing';

import { MyComponent } from './my.component';
import { Location } from '@angular/common';

describe('MyComponent', () => {
  let component: MyComponent;
  let fixture: ComponentFixture<MyComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
        declarations: [ MyComponent ],
      })
      .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  fdescribe('Browser back button', () => {

    let location: Location;
    let currentUrl: string;
    const previousUrl = '/test';

    beforeEach(() => {
      location = TestBed.inject(Location);
      currentUrl = location.normalize(window.location.href);
      location.go(previousUrl);
      location.go(currentUrl);
    });

    afterEach(() => location.go(currentUrl));

    fit('should return to previous', done => {
      location.subscribe(e => {
        expect(e.url).toEqual(previousUrl);
        done();
      });
      location.back();
    });
  });
});

要自定义后退按钮的行为,请重命名 'should return to previous' 以描述您希望按钮执行的任何操作,并相应地更新测试。