我正在尝试检查单元测试中元素可见性状态是否已更改。我正在使用.is(":visible")
进行此操作,在单元测试中,它始终报告该元素是隐藏的,但在浏览器中效果很好。
代码就是这么简单(请参阅完全正常工作的example):
<form>
<div id="field">hi</div>
<input type='checkbox' id="toggle">toggle</input>
<input type='checkbox' id="show">show</input>
<input type='checkbox' id="hide">hide</input>
</form>
$('form').on('change', 'input#toggle[type="checkbox"]', function() {
target_row = $('#field');
if (target_row.length) {
target_row.toggle("fast");
}
});
如我所写,这在浏览器中工作正常,但在以下测试中不起作用:
jest.dontMock('jquery');
jest.dontMock('../toggle.js');
$ = jQuery = require('jquery');
describe('toggle.js', function() {
var sut = require('../toggle.js');
function givenFields(formFields) {
document.documentElement.innerHTML = `
<html><body><form>
<div id="field">hi</div>
${formFields}
</form></body></html>
`;
sut.initialize();
}
it('toggles the field', function() {
givenFields(`<input type='checkbox' id="toggle">toggle</input>`);
var initiallyVisible = $("#field").is(":visible");
$('#toggle').click();
// Checking that this is not jsdom rendering issue
expect(document.hidden).toEqual(false);
expect($("#field").is(":visible")).toEqual(!initiallyVisible);
});
it('shows the field', function() {
givenFields(`<input type='checkbox' id="show">show</input>`);
$('#show').click();
expect($("#field").is(":visible")).toEqual(true);
});
});
结果是:
● toggle.js › toggles the field
expect(received).toEqual(expected)
Expected: true
Received: false
26 | expect(document.hidden).toEqual(false);
27 |
> 28 | expect($("#field").is(":visible")).toEqual(!initiallyVisible);
| ^
29 | });
30 |
31 | it('shows the field', function() {
at Object.toEqual (src/__test__/toggle.spec.js:28:40)
● toggle.js › shows the field
expect(received).toEqual(expected)
Expected: true
Received: false
34 | $('#show').click();
35 |
> 36 | expect($("#field").is(":visible")).toEqual(true);
| ^
37 | });
38 | });
39 |
at Object.toEqual (src/__test__/toggle.spec.js:36:40)
package.json
是:
{
"name": "toggle",
"devDependencies": {
"jasmine": "3.2.0",
"jest-cli": "24.1.0",
"jquery": "3.3.1"
},
"scripts": {
"test": "jest"
}
}
任何想法可能有什么问题,我该如何解决?
我不喜欢的一个选项不是解决方案,而是一种解决方法,我可以检查与DOM的交互而不是其状态。我的意思是,我可以验证对函数toggle
,show
和hide
的调用。这种方法有一个缺点,那就是它增加了复杂性,因为这将需要我在测试中保持DOM元素的状态并引入有关初始状态的假设。
答案 0 :(得分:1)
我认为第一个问题是持续时间(在本例中为“快速”),toggle和show函数不仅会改变可见性:
当提供持续时间,简单对象或单个“完成”功能时,.toggle()成为动画方法。 .toggle()方法同时对匹配元素的宽度,高度和不透明度进行动画处理。隐藏动画后,如果这些属性达到0,则显示样式属性将设置为none,以确保该元素不再影响页面的布局。
因此,您实际上要检查元素的display
。
下一个问题是,jQuery将显示设置为none
之前需要200毫秒,因此我们需要考虑这一点,这意味着我们可以编写如下内容:
it('toggles the field', function(done) {
givenFields(`
<div id="field">kuku</div>
<input type='checkbox' id="toggle">toggle</input>
`);
var initialDisplay = $("#field").css('display');
$('#toggle').click();
// Checking that this is not jsdom rendering issue
expect(document.hidden).toEqual(false);
var expectedDisplay = initialDisplay === 'block' ? 'none' : 'block'
setTimeout(function() {
expect($("#field").css('display')).toEqual(expectedDisplay);
done()
}, 200)
});
也许还有一种方法可以将jest timer-mocks注入到jquery中,从而避免了200ms的等待。会很酷,但不确定是否可行。
编辑: jQuery.fx.off = true; 效果很好,让我们拥有:
jest.dontMock('jquery');
jest.dontMock('./toggle.js');
$ = jQuery = require('jquery');
jQuery.fx.off = true;
describe('toggle.js', function() {
var sut = require('./toggle.js');
function givenFields(formFields) {
document.documentElement.innerHTML = `
<html><body><form>${formFields}</form></body></html>
`;
sut.initialize();
}
it('toggles the field', function() {
givenFields(`
<div id="field">kuku</div>
<input type='checkbox' id="toggle">toggle</input>
`);
var initialDisplay = $("#field").css('display');
$('#toggle').click();
// Checking that this is not jsdom rendering issue
expect(document.hidden).toEqual(false);
var expectedDisplay = initialDisplay === 'block' ? 'none' : 'block'
expect($("#field").css('display')).toEqual(expectedDisplay);
});
it('shows the field', function() {
givenFields(`
<div id="field">kuku</div>
<input type='checkbox' id="show">show</input>
`);
$('#show').click();
expect($("#field").is(":visible")).toEqual(true);
});
});