在页面刷新时,单元测试在通过和失败之间交替进行

Qunit test alternates between pass and fail on page refresh

本文关键字:之间 失败 刷新 单元测试      更新时间:2023-09-26

我有两个相互产生副作用的测试。我理解为什么,因为我正在替换在第二个测试中内部调用的jQuery内置函数。然而,我不明白的是为什么考试时而通过时而失败。

这个问题是类似的,但是,我没有直接在unit-fixturediv上做任何事情。

这是我的测试

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');
});

测试将开始通过,但当我刷新时,它们将在通过和失败之间切换。

为什么会发生这种情况?即使在url中添加GET参数,也会在页面上产生相同的行为。

在失败的情况下,测试失败是因为内部jQuery在设置submit()处理程序时调用.on()。但为什么在这种情况下,测试并不总是失败呢?在页面刷新期间保持状态的浏览器在做什么?

更新:

下面是正在测试的代码:

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;
}();

我已经修改了@Ben's fiddle,以便将您的代码包含在您的两个测试中。我修改了你的一些代码,使它能正常运行。当您点击运行按钮时,所有的测试都会通过。当您再次点击运行按钮时,第二个测试("交替通过和失败")将失败——这基本上是模拟您最初的问题。

问题是你的第一个测试("总是通过测试")改变全局状态通过替换jQuery.fn.on函数与覆盖的一个。因此,当测试按顺序运行时,第二个测试("交替通过和失败")使用不正确的覆盖jQuery.fn.on函数并失败。每个单元测试应该将全局状态返回到其测试前状态,以便其他测试可以基于相同的假设运行。

它在通过和失败之间交替的原因是,在底层,QUnit总是先运行失败的测试(它通过cookie或本地存储以某种方式记住这一点,我不太确定)。当它首先运行失败的测试时,第二个测试在第一个测试之前运行;因此,第二个测试获得了jQuery的原生on函数并正常工作。当您第三次运行它时,测试将以其"原始"顺序运行,而第二次测试将使用覆盖的on函数并失败。

这是工作小提琴。我通过缓存原始var jQueryOn = jQuery.fn.on;函数并在测试结束时通过:jQuery.fn.on = jQueryOn;重新设置它,在测试后添加了"取消覆盖"on函数的修复。您可能可以使用QUnit的模块teardown()方法来更好地实现此功能。

您可以查看https://github.com/jquery/qunit/issues/74获取更多信息。

如果没有更多的信息,我不确定我能解决这个问题,但我可以指出一些可能的问题。

第一个测试似乎在第2行

有无效的语法
var panelId = '#PanelMyTab');

但这可能是一个输入错误,因为你说第一个总是通过的。

我假设第一个测试通过(和有效)loadTab(事件,ui)必须运行jQuery.fn.on(),没有它没有断言已经运行。其中做一些测试与jQuery UI选项卡,似乎是这样的情况(只是不确定如果这是你的意图)。

我不确定把这些断言放在那个函数中是否明智,而且你必须明白,你已经用一个不做任何事情的函数覆盖了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');

其他两个是在一个提交函数中,看起来不像是作为测试的一部分调用的。

请记住,这些测试是同步的,所以它不会等到你点击提交后才运行测试并失败。

下面是一个例子

test('asynchronous test', function() {
    setTimeout(function() {
        ok(true);
    }, 100)
})

将失败,因为ok在测试后100毫秒运行。

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()开始!

还有一个asyncTest()在api中详细说明在这里

最后,看起来你是在尝试用这些测试调试你的代码。使用chrome开发工具或firefox中的firebug在代码中设置断点,并使用console.log()和console.dir()输出信息会容易得多。

也就是说我不知道它是如何为你工作的,所以我可能会错过一些东西:)如果你仍然卡住了,看看你是否可以添加一些更多的周围代码和你想要实现的目标。希望对你有帮助。

PS:最后还有一个};,在你给我们的代码中无效,可能在实际应用中相关;)