如何在 Jasmine/Angular 中测试 BeforeInstallPromptEvent?

How can I test the BeforeInstallPromptEvent in Jasmine/Angular?

我正在为对话框组件编写测试,它处理调用函数时手动提示的 PWA 安装事件。然后它将解决从 BeforeInstallPromptEvent.userChoice 属性.

返回的承诺

然而,当我尝试测试这个函数时,我从 jasmine 收到错误消息:

'userChoice.then is not a function'

这是我理解的,因为我尝试用 spyOn 监视它然后检查结果。

我用 Promises 尝试了一些其他的东西,因为 userChoice returns 一个已解决的 promise (https://developer.mozilla.org/en-US/docs/Web/API/BeforeInstallPromptEvent) 但到目前为止没有任何效果。

这是我要测试的功能。 BeforeInstallPromptEvent 存储在从 app.ts 传递到组件的 installEvent 对象中,然后存储在数据中。

this.data.installEvent.userChoice
            .then((choiceResult) => {
                if (choiceResult.outcome === 'accepted') {
                    doSomething();

在我的测试规范中,我使用以下内容创建了一个模拟数据对象:

const mockData = {
  installEvent: {
    prompt: () => {},
    userChoice: Promise.resolve().then(() => {
      return { choiceResult: { outcome: "accepted" } };
    }),
  },
};

到目前为止我的测试规范(经过多次不同的尝试)是这样的:

it("should do something after user accepted", fakeAsync(() => {
 mockData.installEvent.userChoice.then((result) => {
      return result.choiceResult.outcome;
//this test returns true
      expect(result.choiceResult.outcome).toEqual("accepted");
    }); 
flush();
//but the function gets never called
expect(component.doSomething).toHaveBeenCalled();
});

或者在 userChoice 上使用 spyOn 函数产生错误:

it("should do something after user accepted", () => {
spyOn(mockData.installEvent, "userChoice").and.returnValue("accepted");

expect(mockData.installEvent.userChoice).toBe("accepted)
expect(component.doSomething).toHaveBeenCalled();
});

有了这个,我已经成功地测试了 data.installEvent.prompt 函数正在被调用。

但我不知道如何测试 userChoice Promise 解析为“已接受”,然后触发 if 条件。

请帮帮我。由于我是测试方面的初学者(在 Angular 中),因此最好能解释一下测试此类 Promises 背后的方法。

非常感谢您!

问题是您正在解决已经在 mockData 中的承诺,而间谍没有返回承诺。

方法一

const mockData = {
  installEvent: {
    prompt: () => {},
    userChoice: Promise.resolve({ choiceResult: { outcome: "accepted" } }),
  },
};
it("should do something after user accepted", fakeAsync(() => {
 mockData.installEvent.userChoice.then((result) => {
      // return result.choiceResult.outcome;, remove return here and only test the assertion
//this test returns true
      expect(result.choiceResult.outcome).toEqual("accepted");
      expect(component.doSomething).toHaveBeenCalled(); // make sure doSomething gets called
    }); 
flush(); // flush the promises
});

方法二(做不到)

it("should do something after user accepted", () => {
  // you can't spy on userChoice since you can only spy on methods/functions and not variables
  spyOn(mockData.installEvent, "userChoice").and.returnValue("accepted");

  expect(mockData.installEvent.userChoice).toBe("accepted)
  expect(component.doSomething).toHaveBeenCalled();
});

方法 2 无法完成,因为您只能 spyOn 方法和函数,而不能使用属性。

非常感谢@AliF50 的回答! 我尝试了方法 1,除了我后来发现的一个小错误外,它起作用了:

const mockData = {
  installEvent: {
    prompt: () => {},
    userChoice: Promise.resolve({ choiceResult: { outcome: "accepted" } }),
  },
};

需要

const mockData = {
  installEvent: {
    prompt: () => {},
    userChoice: Promise.resolve( { outcome: "accepted" } ),
  },
};

因为 beforeinstallprompt.userChoice 属性 的结构给出了一个具有关键结果的对象,如 if:

if (choiceResult.outcome === "accepted")

所以在我们的例子中解决测试规范中的承诺时的结果等于 if 条件中的 choiceResult。

更改后一切正常!