测试从服务返回的承诺解析

Testing promise resolving returned from service

我在测试函数返回的 promise 的 promise 解析时遇到了问题。问题是 .then() 没有被执行。

我正在测试的组件方法:

 private _openToast(): void {
        this._toast
            .action()
            .then(
                () => {
                    this.test();
                },
                () => {}
            );
    }
    
test(): void {
console.log("It's ok")
}

服务

@Injectable()
export class ToastService {
    constructor(private _toast: OuterToastService) {}

    action<ValueType>(context?: Partial<IToastContext>, config?: Partial<ToastConfig>): Promise<ValueType> {
        return this._toast.open(); // It's material-like toast service that returns promise
    }
}

并测试

describe('Component', () => {
    let component: Component;
    let fixture: ComponentFixture<Component>;
    const MockToastService = jasmine.createSpyObj('toast', ['action']);
    beforeEach(() => {
        TestBed.configureTestingModule({
            declarations: [Component],
            providers: [
                { provide: ToastService, useValue: MockToastService },
            ],
        });

        fixture = TestBed.createComponent(Component);
        component = fixture.componentInstance;
    });
    })

it('should call test() if toast accepted', () => {
            MockToastService.action.and.returnValue(Promise.resolve());
            const spy = spyOn<any>(component, 'test');

            component['_openToast']();
            expect(spy).toHaveBeenCalled();
        });

运行 测试的结果是: Expected spy test to have been called. 这意味着(我相信如此) .then() 没有被执行。为什么?

Which means (I believe so) that .then() isn't executed. Why?

您的测试是完全同步的,因此没有时间调用 this.test()。由 MockToastService 编辑的承诺 return 可能处于已解决状态,但 .then 回调仍然是异步的 运行s,下一次微任务是 运行.

要解决此问题,您需要使 openToast return 成为一个承诺,然后让您的测试等待该承诺:

private _openToast(): void {
  return this._toast.action().then(
    () => {
      this.test();
    },
    () => {}
  );
}

it("should call test() if toast accepted", () => {
  MockToastService.action.and.returnValue(Promise.resolve());
  const spy = spyOn<any>(component, "test");

  return component["_openToast"]().then(() => {
    expect(spy).toHaveBeenCalled();
  });
});

或者,您可以使用 fakeAsync 测试,然后强制刷新微任务队列:

import { fakeAsync, flushMicrotasks } from '@angular/core/testing';

it("should call test() if toast accepted", fakeAsync(() => {
  MockToastService.action.and.returnValue(Promise.resolve());
  const spy = spyOn<any>(component, "test");

  component["_openToast"]();

  flushMicrotasks();

  expect(spy).toHaveBeenCalled();
}));