断言事件被观察到

Assert that an event was observed

如何在 QUnit 测试用例中断言观察到了特定的 Backbone 事件?

该应用程序使用 Backbone.js events(Backbone.js 版本 1.3.3)在组件之间进行通信。一个简单的视图通过触发事件总线上的自定义事件来响应按钮单击:

// foo.js

const WheelView = Backbone.View.extend({

    events: {
        "click #btn-spin-wheel": "onSpinButtonClick",
    },

    onSpinButtonClick: function () {
        console.log("DEBUG: clicked #btn-spin-wheel");
        Backbone.trigger("wheel:spin");
    },
});

我想要一个QUnit测试用例(QUNIT版本1.22.0),断言“选择此按钮时,事件"foo"出现在事件总线上”。

测试用例还需要知道事件的其他方面(例如可选参数),所以我需要一个 定义在测试用例中的函数 测试用例安排作为特定事件的回调。

这是我尝试过的最新测试用例,通过为事件回调制作一个 Sinon(版本 1.9.0)间谍函数:

// test-foo.js

QUnit.module("Button “btn-spin-wheel”", {
    beforeEach: function (assert) {
        this.wheelView = new WheelView();
    },
    afterEach: function (assert) {
        delete this.wheelView;
    },
});

QUnit.test(
    "Should observe the “wheel:spin” event.",
    function (assert) {
        assert.expect(1);

        const spinWheelButton = document.querySelector(
            "#qunit-fixture #btn-spin-wheel");
        const eventListener = sinon.spy(function () {
            console.log("DEBUG:QUnit: received ‘wheel:spin’ event");
        });
        Backbone.once("wheel:spin", eventListener);

        const done = assert.async();
        window.setTimeout(function () {
            spinWheelButton.click();
            window.setTimeout(function () {
                assert.ok(eventListener.calledOnce);
            }.bind(this));
            done();
        }.bind(this), 500);
    });

console.log 调用是为了帮助我了解哪些函数正在被调用,哪些没有。我希望看到两者:

DEBUG: clicked #btn-spin-wheel
DEBUG:QUnit: received ‘wheel:spin’ event

相反,只会显示点击消息:

DEBUG: clicked #btn-spin-wheel

已确认,因为测试用例失败:

Button “btn-spin-wheel”: Should observe the “wheel:spin” event. (3, 0, 3)    579 ms
    1.  Assertion after the final `assert.async` was resolved    @ 578 ms
        Source: Assert.prototype.ok@file:///usr/share/javascript/qunit/qunit.js:1481:3

    2.  failed, expected argument to be truthy, was: false    @ 578 ms
        Expected: true
        Result: false
        Source: @file://[…]/test-foo.html:50:29

    3.  Expected 1 assertions, but 2 were run    @ 579 ms
        Source: @file://[…]/test-foo.html:36:13

Source: @file://[…]/test-foo.html:36:13

我已阅读有关 QUnit support for asynchronous testing 的信息,并且我正在尝试不同的 assert.asyncsetTimeout 用法,如文档示例中所建议的那样。至今无果。

我应该如何使用 QUnit、Sinon 和 Backbone 断言来自应用程序的特定观察事件(的存在和特定属性)?

您应该能够为您的事件注册一个侦听器并使用 assert.async 来侦听它,像这样:

var done = assert.async();
Backbone.once("wheel:spin", function(event) {
    done();
});

const spinWheelButton = document.querySelector("#qunit-fixture #btn-spin-wheel");
spinWheelButton.click();

可能只是因为 setTimeout 次调用,您的代码未按预期运行。

Here 您可以找到 QUnit async.

的更多文档

问题原来是 个测试用例之间的交互。测试用例操纵监听器并将事件触发到事件中心;但所有测试用例共享 相同 事件中心。

因此,当测试用例 运行 异步时,测试用例不会被隔离,一个中触发的事件会影响另一个。

我实施的解决方法是为每个测试用例自定义事件队列,在 QUnit.module.beforeEach….afterEach:

中管理
/**
 * Set up an event hub fixture during `testCase`.
 *
 * @param testCase: The QUnit test case during which the fixture
 * should be active.
 * @param eventHub: The Backbone.Events object on which the fixture
 * should exist.
 */
setUpEventsFixture: function (testCase, eventHub) {
    testCase.eventHubPrevious = eventHub._events;
    eventHub._events = [];
},

/**
 * Tear down an event hub fixture for `testCase`.
 *
 * @param testCase: The QUnit test case during which the fixture
 * should be active.
 * @param eventHub: The Backbone.Events object on which the fixture
 * should exist.
 */
tearDownEventsFixture: function (testCase, eventHub) {
    eventHub._events = testCase.eventHubPrevious;
},

通过在测试模块定义中使用这些:

QUnit.module("Button “btn-spin-wheel”", {
    beforeEach: function (assert) {
        setUpEventsFixture(this, Backbone);
        this.wheelView = new WheelView();
    },
    afterEach: function (assert) {
        delete this.wheelView;
        tearDownEventsFixture(this, Backbone);
    },
});

测试用例现在可以继续使用使用通用 Backbone 对象作为事件中心的代码,但它们的事件彼此隔离。