当在被测试函数 (IIFE) 中声明文档就绪块时,QUnit 测试失败

QUnit test fails when document-ready block is declared inside the function being tested (IIFE)

我正在基于此 post 使用 jQuery 构建一个网络小部件,但有一些改进:http://alexmarandon.com/articles/web_widget_jquery/

现在我开始编写一些测试,但它们都失败了,我相信这与我在函数内声明一个文档就绪块有关,如上面 link 中所建议的。

这是小部件的精简版:

var MyWidget = (function(w, d, $, undefined){

    var _getContent = function () {
        return 'My Widget Content';
    }

    var render = function (){
        $(function(){
            var content = _getContent();
            $('#container').html(content);
        });
    }

    return {
        render: render
    }

})(window, document, jQuery, undefined);

这是测试:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>MyWidget Tests</title>
    <link rel="stylesheet" href="../bower_components/qunit/qunit/qunit.css">
</head>
<body>
    <div id="qunit"></div>
    <div id="qunit-fixture">
        <div id="container"></div>
    </div>

    <script src="../bower_components/jquery/dist/jquery.min.js"></script>
    <script src="../bower_components/qunit/qunit/qunit.js"></script>
    <script src="mywidget.js"></script>

    <script>
        QUnit.test('Test Content', function(assert){
            MyWidget.render();

            assert.equal($('#container').html(), 'My Widget Content');
        });
    </script>
</body>
</html>

结果如下:

但是,当我删除$(function(){代码时,测试通过。

知道发生了什么吗?

谢谢!

好的,我知道问题出在哪里了。我应该早点看到它。即使您的 render 函数在 文档准备就绪后被调用(因为测试在底部调用它),它 仍然是异步的 因为您使用 ready 处理程序 ($(function() {})。因此,您必须使测试异步。此外,您将不得不 (a) 在您的小部件中创建一些机制来通知调用代码它已完成(如 Promise, or jQuery's Deferred); or (b) you will need to also use a ready handler in your test. Here is a test that works with your source code (and a JSBin to see it):

QUnit.test('Test Content', function(assert){
  var done = assert.async();
  MyWidget.render();
  $(function() {
    assert.equal($('#container').html(), 'My Widget Content');
    done();
  });
});

如果你想走 jQuery 延迟路线,你可以在你的 render 来源中做这样的事情:

var render = function (){
    var defObj = jQuery.Deferred();
    $(function(){
        var content = _getContent();
        $('#container').html(content);
        defObj.resolve();
    });
    return defObj;
}

然后在你的测试中,你基本上会做我在上面的测试示例中所做的,只有 Promise 处理程序:

QUnit.test('Test Content', function(assert){
  var done = assert.async();
  MyWidget.render()
    .then(function() {
      assert.equal($('#container').html(), 'My Widget Content');
      done();
    })
    .fail(done);
  });
});