【问题标题】:Testing jQuery UI "Dialog" logic using Jasmine使用 Jasmine 测试 jQuery UI“对话框”逻辑
【发布时间】:2018-09-25 14:44:57
【问题描述】:

在我的 JS 视图代码中,我使用 jQuery UI Dialog 组件来呈现弹出窗口。

我这样实例化它:

var popupDialog = $("#myPopupDiv").dialog({
    title: "My dialog",
    dialogClass: "myDialogClass",
    create: createHandler,
    draggable: false,
    width: width,
    height: height,
    autoOpen: false
});

请注意,它的 autoOpen 设置为“false”。我在“创建”处理程序中打开它:

var createHandler = function(event, ui) {
    //Vi venter litt for å sikre at popupen er "klar"
    setTimeout(function () {
        popupDialog.dialog("open");
    }, 5);
};

开放逻辑包裹在setTimeout 中,以确保弹出窗口准备就绪。

代码在浏览器应用程序中运行良好,但是当我使用Jasmine test-framework 运行此代码时出现错误:

错误:无法在初始化之前调用对话框上的方法;试图调用方法'open'

测试实际上通过了,所以很明显该项目已被渲染。但我不喜欢运行测试时出现的错误!

我怀疑由于 Jasmine 测试运行得如此之快,组件还没有时间进行自我初始化。那么我如何确保组件已初始化?我认为将此逻辑放在“创建”处理程序中会解决这个问题,因为该事件是“在创建对话框时触发的。 ”,但显然不是这样的。

这是我的测试方法:

it("should show my popup", function () {

    var myPopupLink = $('.popupLink');

    myPopupLink.click();

    //Wait until popup is shown
    waitsFor(function () {
        return !$('.myDialogClass').is(":hidden");
    }, "Popupen didn't show", 1000);

    //Check that the DOM is as expected
    expect($('.myDialogClass .popupContentDiv')).toExist();
    expect(...

    //Close popup
    myPopupLink.click();
    expect($('.myDialogClass .popupContentDiv')).not.toExist();

});

有人知道如何验证弹出对话框的初始化状态吗? 还是有其他解决方法?

谢谢!

【问题讨论】:

    标签: unit-testing jquery-ui-dialog jasmine


    【解决方案1】:

    您的测试的问题在于,它更像是验收测试而不是单元测试。您尝试测试的大部分内容都是 jQueryUi 的功能。您真正想要测试的是createHandler 延迟打开了对话框。所以你的popupDialog.dialog 应该是一个间谍,你可以在其中检查它是否在延迟后被调用。

    目前您的代码真的很难测试,因为它直接基于 jquery。您应该考虑拥有可以inject your depenedencies 的函数,而不是依赖像popupDialog 这样的全局变量。

    这是一个关于如何模拟所有依赖项的示例:

    //mock out setTimeout so you dont have to wait in your test
    jasmine.Clock.useMock();
    
    //create a mock that will return from $().dialog()
    var mockDialog = jasmine.createSpy('dialog');
    // mock $ to return {dialog: mock that return {dialog: mockDialog}}
    var mock$ = spyOn(window, '$').andReturn({
      dialog:jasmine.createSpy('$').andReturn({
        dialog: mockDialog
      })
    })
    
    expect(mock$).toHaveBeenCalled();
    
    // call the create function    
    window[mock$.mostRecentCall.args[0].create]();
    
    jasmine.Clock.tick(4999);
    expect(mockDialog$).not.toHaveBeenCalled();
    jasmine.Clock.tick(5001);
    expect(mockDialog$).toHaveBeenCalledWith('open');
    

    如您所见,模拟所有 jQuery 依赖项非常复杂。因此,您可以重写代码以获得更好的可测试性,或者使用 selenium capybara 等作为验收测试来测试这些东西。

    【讨论】:

    • 感谢您的意见。出于多种原因,我们避免使用 Selenium。我们的 JavaScript 中没有太多的应用程序逻辑——它位于 Java 后端。我们希望通过 JS 测试实现的目标是 1) 使用正确的参数调用服务器,并且返回数据在 JavaScript(主干“模型”)中被正确解析,以及 2) DOM 使用它正确呈现数据。为此,我们使用 Jasmine、Jasmine-jQuery 和 Sinon 作为这些工具的用途。如果我们按照您的建议排除 jQuery 行为,我们将对 jQuery 的工作方式做出不明智的假设。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多