10

我有两个相互引起副作用的测试。我理解为什么我要替换在第二个测试中内部调用的 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 参数添加到 url 也会在页面上产生相同的行为。

在失败的情况下,测试失败,因为在设置处理程序.on()时内部 jQuery 正在调用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;
}();
4

2 回答 2

6

我已经修改了@Ben 的小提琴,将您的代码包含在您的两个测试中。我修改了您的一些代码以使其正常运行。当您点击运行按钮时,所有测试都将通过。当您再次按下运行按钮时,第二个测试(“交替通过和失败”)将失败 - 这基本上是在模拟您的原始问题。

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

它在通过和失败之间交替的原因是在引擎盖下 QUnit 总是首先运行失败的测试(它通过 cookie 或本地存储以某种方式记住这一点,我不确定)。当它首先运行失败的测试时,第二个测试在第一个之前运行;结果,第二个测试得到了 jQuery 的原生on函数并且可以工作。当您第三次运行它时,测试将按其“原始”顺序运行,第二次测试将使用覆盖的on函数并失败。

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

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

于 2013-06-06T18:59:58.487 回答
0

我不确定我是否可以在没有更多信息的情况下解决这个问题,但我可以指出一些可能的问题。

第一个测试在第 2 行似乎有无效的语法

var panelId = '#PanelMyTab');

但这可能是一个类型错误,正如你所说,第一个总是通过。

我假设要通过第一个测试(并且有效),loadTab(event,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');

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

请记住,这些测试是同步的,因此它不会等待您在运行测试和失败之前点击提交。

这是一个例子

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

测试后 100 毫秒运行 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 中还有一个 asyncTest() 详细说明

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

话虽这么说,我根本不知道它对你是如何工作的,所以我可能会遗漏一些东西:) 如果你仍然卡住了,看看你是否可以添加更多的周围代码以及你想要实现的目标。希望这可以帮助。

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

于 2013-06-02T23:07:58.060 回答