测试诺言从服务返回

发布于 2025-01-28 03:04:32 字数 1822 浏览 3 评论 0原文

我在测试承诺从功能中返回的承诺的诺言有问题。问题是。然后未执行。

我正在测试的组件方法:

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

运行测试的结果是: 预期的间谍测试已被调用。 这意味着(我相信)。为什么?

I've got a problem with testing promise resolving of promise returned from function. The problem is that .then() isn't executed.

Components method that I'm testing:

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

Service

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

And test

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

Result of running test is:
Expected spy test to have been called.
Which means (I believe so) that .then() isn't executed. Why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

⊕婉儿 2025-02-04 03:04:32

这意味着(我相信)。为什么?

您的测试完全是同步的,因此没有时间来调用this.test()。 MockToastService返回的承诺可能处于解决状态,但是。然后回调仍然异步运行,下次Microtasks运行。

要解决此问题,您需要使Opentoast返回诺言,然后进行测试等待该诺言:

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

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

Your test is entirely synchronous, so it's not giving time for this.test() to be called. The promise returned by MockToastService may be in a resolved state, but the .then callback still runs asynchronously, the next time microtasks are run.

To fix this, you'll need to make openToast return a promise, and then have your test wait for that promise:

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

Alternatively, you can use a fakeAsync test, and then force the microtask queue to flush:

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();
}));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文