在自定义的Jasmine匹配器中解决和拒绝承诺
Resolved and rejected promises in a custom Jasmine Matcher
故事:
我们开发了一个定制的jasmine匹配器,它主要做两件事:
- 鼠标悬停在给定元素上
- 检查是否有带有所需文本的工具提示
toHaveTooltip: function() {
return {
compare: function(elm, expectedTooltip) {
var tooltipPage = requirePO("tooltip");
browser.actions().mouseMove(elm).perform();
browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000, "Tooltip is still not visible.");
return {
pass: tooltipPage.tooltip.getText().then(function(actualTooltip) {
return jasmine.matchersUtil.equals(actualTooltip, expectedTooltip);
}),
message: "Element does not have the tooltip '" + expectedTooltip + "'."
};
}
};
},
其中tooltipPage
是单独定义的Page Object:
var Tooltip = function () {
this.tooltip = element(by.css(".tooltip"));
};
module.exports = new Tooltip();
这种用法对我们来说非常方便,并且确实有助于遵循DRY原则,保持我们的测试代码库干净可读:
expect(page.fromDateInput).toHaveTooltip("After");
问题与疑问:
现在,我要做的是让匹配器分别处理两个用例:
- 根本没有显示鼠标上方的工具提示(这基本上是
browser.wait()
被拒绝的承诺) - 有一个工具提示,但不是想要的那个
如何改进匹配器,使其能够分别处理这两个问题并报告不同的错误?
我试过了:
toHaveTooltip: function() {
return {
compare: function(elm, expectedTooltip) {
var tooltipPage = requirePO("tooltip");
browser.actions().mouseMove(elm).perform();
return browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000, "Tooltip is still not visible.").then(function () {
return {
pass: tooltipPage.tooltip.getText().then(function(actualTooltip) {
return jasmine.matchersUtil.equals(actualTooltip, expectedTooltip);
}),
message: "Element does not have the tooltip '" + expectedTooltip + "'."
};
}, function () {
return {
pass: false,
message: "No tooltip shown on mouse over the element"
}
});
}
};
},
在这里,我试图明确地解决browser.wait()
,并分别处理"成功"answers"错误"的情况。这导致了Jasmine Spec超时和控制台上一个巨大的"红色"文本:
Expected ({ ptor_: ({ setFileDetector: Function, ...
5 minutes scrolling here
... InnerHtml: Function, getId: Function, getRawId: Function }) to have tooltip 'After'.
我恐怕不能从"compare"函数返回一个承诺。
根据jasminewd2(一个茉莉到webdriverjs的适配器。(由Protractor使用)代码-
期望解析任何对实际值和期望值给出的承诺,以及
result
对象的pass
属性。
因此,如果有一个async函数或承诺需要在自定义匹配器/期望中解决,那么它需要被包装到result.pass
值,以便量角器等待承诺被解决。
在这个问题中,jasmine spec timeout
错误是由于protractor无法理解在执行特定操作之前需要解决一个promise。为了解决这个问题,可以直接在expect语句中传递async函数,或者将其传递给result
对象的pass
值。下面是它的代码-
toHaveTooltip: function() {
return {
compare: function(elm, expectedTooltip) {
var tooltipPage = requirePO("tooltip");
browser.actions().mouseMove(elm).perform();
return {
pass: browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000, "Tooltip is still not visible.").then(function () {
tooltipPage.tooltip.getText().then(function(actualTooltip) {
return jasmine.matchersUtil.equals(actualTooltip, expectedTooltip);
}),
}, function () {
return false;
}),
message: "Error Occured"
}
}
};
},
然而,上面代码的问题是不能制作自定义错误消息。要解决这个问题,我能找到的最好方法是显式地返回result
对象,这样就可以根据需要为它分配错误消息。这里有一个例子-
var result = {};
result.pass = browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000, "Tooltip is still not visible.").then(function () {
tooltipPage.tooltip.getText().then(function(actualTooltip) {
result.message = "Element does not have the tooltip '" + expectedTooltip + "'.";
return jasmine.matchersUtil.equals(actualTooltip, expectedTooltip);
}),
}, function () {
result.message = "No tooltip shown on mouse over the element";
return false;
});
return result;
注意:如果result
对象中没有message
属性,那么protractor将尝试自己创建一个通用的错误消息,它将包含promise对象(一个以- { ptor_: ... }
开头的冗长消息),如问题所示。
希望能有所帮助。
嗯,我记得在某处读到jasmine 2不支持你正在尝试做的匹配器类型(内部有async函数),并返回承诺…我将尝试在这里找到源代码和更新。此外,你不应该在匹配器内部做鼠标动作,那不是匹配器的重点。
所以基本上我所说和建议的是:如果您想要一个干净的代码,请将以下代码导出到一个函数中并调用它。
var checkToolTipVisibility (elm, expectedTooltip) {
browser.actions().mouseMove(elm).perform();
browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000, "Tooltip is still not visible.");//optional then here if you want to fail with a timeout or something...
expect(tooltipPage.tooltip.getText()).toEqual(expectedTooltip);
}
checkToolTipVisibility(page.fromDateInput, "After");//usage
我认为这是一个非常干净和简单的解决方案,它不需要任何自定义匹配器,它是做事情的茉莉方式(不是匹配器中的异步函数),这就是我在我的代码中使用的方式,除了那些函数位于utils.js文件中,我需要时。
希望我有帮助,我将继续寻找我的第一个声明的来源!
由于某些原因,我无法让这个在Karma/Angular 2+中工作。我最终在承诺本身内调用Jasmine的全局fail
方法:
const _global: any = (typeof window === 'undefined' ? global : window);
const customMatchers: jasmine.CustomMatcherFactories = {
toPassA11y: () => {
return {
compare: (el: any): any => {
const axe = require('axe-core');
const result: any = {
message: '',
pass: true
};
axe.run((error: Error, results: any) => {
if (error) throw error;
if (results.violations.length > 0) {
_global.fail('Expected element to pass accessibility checks.');
}
});
return result;
}
};
}
};
_global.beforeEach(() => {
jasmine.addMatchers(customMatchers);
});
在规范中:
describe('Home component', () => {
it('should check accessibility', async(() => {
expect(document).toPassA11y();
}));
});
基于@Girish Sortur的完美答案,这里是匹配器的完整代码,它现在可以完美地分别处理缺失的工具提示和不同的工具提示文本情况:
toHaveTooltip: function() {
return {
compare: function(elm, expectedTooltip) {
var tooltipPage = requirePO("tooltip"),
result = {};
// mouse over the element
browser.actions().mouseMove(elm).perform();
// wait for tooltip to appear and handle errors
result.pass = browser.wait(EC.visibilityOf(tooltipPage.tooltip), 5000).then(function () {
return tooltipPage.tooltip.getText().then(function(actualTooltip) {
result.message = "Expected tooltip: '" + expectedTooltip + "'. Actual tooltip: '" + actualTooltip + "'.";
return jasmine.matchersUtil.equals(actualTooltip, expectedTooltip);
})
}, function () {
result.message = "No tooltip shown on mouse over the element";
return false;
});
return result;
}
};
},
- 简单的ES6承诺问题-交换解决和拒绝参数
- 在ES6 Promise中,我应该在解决/拒绝之前使用return吗
- 在jQuery中,.state()如何确定一个承诺是挂起的、已解决的还是被拒绝的
- 角度$q.拒绝不解决
- 在$http内解决/拒绝承诺是行不通的
- 拒绝并解决Q承诺
- 关于承诺/A+规范,是一个从未被允许解决或拒绝的承诺
- AngularJS/Karma-测试函数返回已解决或拒绝的promise
- 承诺-链接解决/拒绝
- 承诺不期望得到解决或拒绝
- 在自定义的Jasmine匹配器中解决和拒绝承诺
- 承诺API回调-如何正确解决或拒绝
- new Promise和Promise的区别.在bluebird中解决/拒绝
- 如何知道什么时候所有的承诺都被拒绝了,或者用基本的js承诺解决了
- 你是否应该在承诺中解决或拒绝后退货
- 我是否需要在早期解决/拒绝后返回?
- 麻烦的错误,未能拒绝与蓝鸟.解决得很好.错误似乎会使应用程序崩溃
- 问美元.当有一个被拒绝的承诺时,一切都解决了
- JavaScript承诺在未被拒绝或解决时是否会造成内存泄漏?
- 在外部回调中解决/拒绝承诺