我有两个测试相互造成副作用。我理解为什么我要替换在第二次测试中内部调用的jQuery内置函数。然而,我不明白为什么测试交替通过和失败。
This question is similar但是,我没有直接在qunit-fixture div上做任何事情。
以下是我的测试
test('always passing test', function() { // Always passes
var panelId = '#PanelMyTab';
var event = {};
var ui = {
tab: {
name: 'MyTab',
},
panel: panelId,
};
$('<div id="' + panelId + '">')
.append('<a href="#" class="export">Test</a>')
.append('<a href="#" class="showForm">Show Form</a>')
.appendTo('#qunit-fixture');
jQuery.fn.on = function(event, callback) {
ok(this.selector == panelId + ' .export', 'Setting export click event');
equal(callback, tickets.search.getReport, 'Callback being set');
};
loadTab(event, ui);
});
test('alternately passing and failing', function() { // Alternates between passing and failing on page refresh
expect(5);
var testUrl = 'test';
$('<div class="ui-tabs-panel">')
.append('<a href="'+ testUrl + '" id="getReport">Get Report</a>')
.append('<form action="notest" target="" class="ticketSearch"></form>')
.appendTo('#qunit-fixture');
// Setup form mocking
$('form.ticketSearch').submit(function() {
var urlPattern = new RegExp(testUrl + '$');
ok(urlPattern.test($(this).prop('action')), 'Form action set to link href');
equal($(this).prop('target'), '_blank', 'Open form on a new page');
});
var event = {
target: 'a#getReport',
};
var result = getReport(event);
var form = $('form.ticketSearch');
ok(/notest$/.test($(form).prop('action')), 'Making sure action is not replaced');
equal($(form).prop('target'), '', 'Making sure that target is not replaced');
ok(false === result, 'click event returns false to not refresh page');
});
测试将开始传递,但是当我刷新时,它们将在传递和失败之间交替。
为什么会这样?即使向网址添加GET参数,也会在网页上产生相同的行为。
在失败的情况下,测试失败,因为内部jQuery在设置.on()
处理程序时调用submit()
。但是为什么在这种情况下测试总是失败?在页面刷新期间保留状态的浏览器是什么?
更新
以下是正在测试的代码:
var tickets = function() {
var self = {
loadTab: function(event, ui) {
$(panel).find('.export').button().on('click', this.getReport);
},
search: {
getReport: function(event) {
var button = event.target;
var form = $(button).closest('div.ui-tabs-panel').find('form.ticketSearch').clone(true);
$(form).prop('action', $(button).prop('href'));
$(form).prop('target', '_blank');
$(form).submit();
return false;
}
}
};
return self;
}();
答案 0 :(得分:6)
我修改了@ Ben的fiddle,将您的代码包含在两个测试中。我修改了一些代码以使其正确运行。当您点击运行按钮时,所有测试都将通过。再次点击运行按钮时,第二次测试(“交替传递和失败”)将失败 - 这基本上模拟了您的原始问题。
问题是您的第一个测试(“总是通过测试”)通过将jQuery.fn.on
函数替换为覆盖的函数来改变全局状态。因此,当测试按顺序运行时,第二个测试(“交替传递和失败”)使用不正确的重写jQuery.fn.on
函数并失败。 每个单元测试应该将全局状态返回到其测试前状态,以便其他测试可以基于相同的假设运行。
它在pass和fail之间交替的原因是,引擎盖下QUnit总是首先运行失败的测试(它通过cookie或本地存储以某种方式记住它,我不完全确定)。当它首先运行失败的测试时,第二个测试在之前运行第一个测试;因此,第二个测试获得jQuery的原生on
功能并且有效。第三次运行时,测试将以“原始”顺序运行,第二次测试将使用重写的on
函数并失败。
这是工作fiddle。我通过缓存原始on
函数并在测试结束时通过:var jQueryOn = jQuery.fn.on;
将测试后的jQuery.fn.on = jQueryOn;
函数添加到“取消覆盖”teardown()
函数。您可以使用QUnit的模块{{1}}方法更好地实现此目的。
答案 1 :(得分:0)
我不确定如果没有更多信息我可以解决这个问题,但我可以指出一些可能的问题。
第一个测试似乎在第2行上有无效的语法
var panelId = '#PanelMyTab');
但这可能是一种类型的错误,正如你所说的那样,第一次总是过去。
我假设第一个测试要传递(并且有效),loadTab(event,ui)必须运行jQuery.fn.on(),没有它没有运行断言。使用jQuery UI Tabs进行一些测试似乎就是这种情况(只是不确定是否是你的意图)。
我不确定将这些断言放在该函数中是明智的,并且您必须明白已经使用不执行任何操作的函数覆盖了jquery函数,因此可能会导致问题。
你似乎在第二次测试中做了类似的事情,你期待5个断言,但我只能看到最后3个如何运行
ok(/notest$/.test($(form).prop('action')), 'Making sure action is not replaced');
equal($(form).prop('target'), '', 'Making sure that target is not replaced');
ok(false === result, 'click event returns false to not refresh page');
其他2个在提交函数中,看起来不像是作为测试的一部分调用的。
请记住,这些测试是同步的,所以它不会等到你在运行测试和失败之前点击提交。
这是一个例子
test('asynchronous test', function() {
setTimeout(function() {
ok(true);
}, 100)
})
在测试后100ms运行ok会失败。
test('asynchronous test', function() {
// Pause the test first
stop();
setTimeout(function() {
ok(true);
// After the assertion has been called,
// continue the test
start();
}, 100)
})
stop()告诉qunit等待,start()去!
api here
中还详细说明了asyncTest()最后,您似乎正在尝试使用这些测试来调试代码。在firefox中使用chrome开发人员工具或firebug来设置代码中的断点会更容易,并使用console.log()和console.dir()来输出信息。
话虽如此,我根本不知道它对你有什么用处,所以我可能会遗漏一些东西:)如果你仍然卡住了,看看你是否可以添加更多的周围代码以及你想要实现的目标。希望这会有所帮助。
PS:最后还有一个};
在您提供给我们的代码中无效,但可能与实际应用相关;)