方法一:模板
我们可以将最后发出的值绑定到模板并检查它。
{
moduleMetadata: { imports: [InputCheckboxModule] },
template: `
<checkbox (changeValue)="value = $event" [selected]="checked" label="Awesome">
</checkbox>
<div id="changeValue">{{ value }}</div> <!-- ❗️ -->
`,
}
it("emits `changeValue`", () => {
// ...
cy.get("#changeValue").contains("true"); // ❗️
});
方法2:窗口
我们可以将最后发出的值分配给全局window
对象,在赛普拉斯中检索它并验证该值。
export default {
title: "InputCheckbox",
component: InputCheckboxComponent,
argTypes: {
selected: { type: "boolean", defaultValue: false },
label: { type: "string", defaultValue: "Default label" },
},
} as Meta;
const Template: Story<InputCheckboxComponent> = (
args: InputCheckboxComponent
) =>
({
moduleMetadata: { imports: [InputCheckboxModule] },
component: InputCheckboxComponent,
props: args,
} as StoryFnAngularReturnType);
export const E2E = Template.bind({});
E2E.args = {
label: 'E2e label',
selected: true,
changeValue: value => (window.changeValue = value), // ❗️
};
it("emits `changeValue`", () => {
// ...
cy.window().its("changeValue").should("equal", true); // ❗️
});
方法 3:角度
我们可以使用存储在全局命名空间中的Angular 函数ng
来获取对 Angular 组件的引用并监视输出。
⚠️注意:
ng.getComponent()
仅当 Angular 在开发模式下运行时可用。即enableProdMode()
不调用。
- 设置
process.env.NODE_ENV = "development";
以.storybook/main.js
防止 Storybook 在 prod 模式下构建 Angular(请参阅源代码)。
export const E2E = Template.bind({});
E2E.args = {
label: 'E2e label',
selected: true,
// Story stays unchanged
};
describe("InputCheckbox", () => {
beforeEach(() => {
cy.visit(
"/iframe.html?id=inputcheckboxcomponent--e-2-e",
registerComponentOutputs("checkbox") // ❗️
);
});
it("emits `changeValue`", () => {
// ...
cy.get("@changeValue").should("be.calledWith", true); // ❗️
});
});
function registerComponentOutputs(
componentSelector: string
): Partial<Cypress.VisitOptions> {
return {
// https://docs.cypress.io/api/commands/visit.html#Provide-an-onLoad-callback-function
onLoad(win) {
const componentElement: HTMLElement = win.document.querySelector(
componentSelector
);
// https://angular.io/api/core/global/ngGetComponent
const component = win.ng.getComponent(componentElement);
// Spy on all `EventEmitters` (i.e. `emit()`) and create equally named alias
Object.keys(component)
.filter(key => !!component[key].emit)
.forEach(key => cy.spy(component[key], "emit").as(key)); // ❗️
},
};
}
概括
- 我喜欢在方法 1 中没有魔法。它易于阅读和理解。不幸的是,它需要指定一个带有用于验证输出的附加元素的模板。
- 方法 2 的优点是我们不再需要指定模板。但是我们需要为每个
@Output
我们想要测试的额外代码添加。此外,它使用全局window
来“交流”。
- Apprach 3 也不需要模板。它的优点是 Storybook 代码(故事)不需要任何调整。我们只需要传递一个参数
cy.visit()
(很可能已经使用)就可以执行检查了。因此,如果我们想通过 Storybook 的iframe
. 最后但同样重要的是,我们检索对 Angular 组件的引用。有了这个,我们还可以直接在组件本身上调用方法或设置属性。这ng.applyChanges
似乎为额外的测试用例打开了一些大门。