使用 Jasmine、JQuery Mobile 和 Async AJAX 请求的组合测试 DOM



我目前正在开发一个移动应用程序,我决定使用JQuery Mobile实现。但是,由于它将是一个官方应用程序,因此需要我对其进行测试,因此我决定使用我在学校学会处理的Jasmine。

目前我有一个客户端和服务器端,它使用 AJAX ($.getJSON) 请求进行通信。

当其中一个 AJAX 请求被转发到其callback方法时,它将调用一个 Notification 类来实现一个包含通知的div

我目前的问题是,当我使用以下代码时,它似乎总是在工作:

window.setTimeout(function () {
    var expectedResult = "error";
    var result = $("#test .ui-content .contentContainer .notification").text();
    expect(result).toEqual(expectedResult);
}, 4000);

然而,几天后,我开始了一个新模块,并编辑了这些值,它继续工作,这将是非常错误的,因为它的旧的 - 不存在 - 代码。

所以我注意到这个单元测试实际上从未奏效。

所以我开始寻找替代方法并找到了runswaitsFor功能,但我似乎无法让它们工作。

所以这里有一个测试:

it('should display an error when trying to add a new contact', function () {
    runs(function () {
        var contact = new Contact();
        contact.addContact();
    });
    waitsFor(function () {
        expect($("#test .ui-content .contentContainer .notification")).toBeVisible();
    }, 5000);
    var expectedResult = "asdf";
    var result = $("#test .ui-content .contentContainer .notification").text();
    expect(result).toEqual(expectedResult);
});

回调方法:

this.addContact_callback = function (data) {
    $('#createContactForm')[0].reset();
    $('.ui-dialog').dialog('close');
    window.setTimeout(function () {
        (new Contact()).retrieveContactList();
        (new NotificationBox()).show(data.message[0], data.message[1]);
    }, 250)
};

我的通知:

function NotificationBox() {
    this.show = function (message, type) {
        var activePage = $("body .ui-page-active").attr("id");
        var create = "<div class='notification " + type + "'>" + message + "</div>";
        $("#" + activePage + " .ui-content .contentContainer .notification").remove();
        $("#" + activePage + " .ui-content .contentContainer").prepend(
            $(create).hide().fadeIn('slow').delay(2500).fadeOut('slow', function () {
                $(this).remove();
            })
        );
    };
}

我希望有人能够为我提供解决这个主要问题的方法。

你的真诚,拉尔西1

您误用了waitsFor方法。如果您阅读了官方文档,waitsFor需要返回一个值,该值指示等待时间是否已结束。

您可能想执行以下操作:

waitsFor(function () {
    return $("#test .ui-content .contentContainer .notification").is(":visible");
}, 5000);

您还缺少测试最后一部分的运行块。

runs(function () {
    var expectedResult = "asdf";
    var result = $("#test .ui-content .contentContainer .notification").text();
    expect(result).toEqual(expectedResult);
});

尽管它可能不被视为解决方案,但它确实创建了更好的可管理和可测试的代码。

在我给定的代码示例中,我将代码转发到外部回调方法,就像我在给定的代码中使用addContact_callback一样。跟踪实际结果的唯一方法是确定 notification 元素类的文本是什么。

话虽如此,很明显,如果您遇到此问题,您可能编写了脏代码。

出于这个原因,我将我的代码更改为更好的代码,它使用内部回调方法。这意味着代码看起来像这样:

function handleSomething () {
    this.retrieveSomething(function (data) {
        console.log(data);
    });
}
function retrieveSomething (callback) {
    $.ajax({
        type: "GET",
        url: "127.0.0.1/my.php",
        success: function (data, status, xhr) {
            return callback($.parseJSON(data);
        }
    });
}

这样可以确保我的代码更容易测试,因为我可以为单元测试实现自定义回调函数。

还记得旧的单元测试吗? 嗯,这是从:

window.setTimeout(function () {
    var expectedResult = "error";
    var result = $("#test .ui-content .contentContainer .notification").text();
    expect(result).toEqual(expectedResult);
}, 4000);

自:

var contact = new Contact();
contact.retrieveSomething(function (data) {
    var expectedResult = (new Contact()).errorMessages[4];
    expect(data.message).toBe(expectedResult);
});

结论:确保始终可以测试返回输出,而不是简单地将其移动到 UI,然后尝试测试结果是否与预期相同。

最新更新