RequireJs loading modules - Qunit

2020-02-06 09:59发布

问题:

I am pretty new to RequireJS, and having trouble in writing QUnit to a source code which has logic to load modules dynamically using requireJS.

Below is the source code: factory/Factory.js *

getPage: function (callback) {

    //doSomething here

    require(['page/something'], function() {

         callback();

    })
}

The module 'page/something' is never loaded while running QUnit, and callback is never invoked. Is there anything I'm missing here? Appreciate your response.

**QUnit factory/FactoryTests.js*

define(['underscore', 'factory/Factory'],
       function (_, Factory) {

           module("Factory", {
               setup:function () {
               },
               teardown:function () {
               }
           });

           test("GetPage", function () {
              var isCallbackInvoked = false;
              var mockCallback = function () {
                  isCallbackInvoked = true;
              }

              Factory.getPage(mockCallback);
              ok(isCallbackInvoked);

           });

});

*test-require-config.js**

require.config({

    baseUrl: "../../resources/js",

    paths:{
        jquery:'../jquery-1.8.2',
    jquery_star_rating : '../jquery/jquery.rating',
        underscore:'..underscore-1.4.1',
        backbone:'../backbone-0.9.2',
        jquery_star_rating : '../jquery.rating',
        text : '../require-text-2.0.3',
        sinon: '../../../../sinon',
    },
    shim:{
        underscore:{
            exports:'_'
        },
        backbone:{
            deps:["jquery", "underscore"],
            exports:"Backbone"
        }
        jquery_star_rating : {
            deps : ['jquery']
        }
    }

});

var dependencies = [
    'jquery',
    'jquery_star_rating',
    'underscore',
    'backbone',       
    'sinon',
];

require(dependencies, function () {

    require(['../../../../test/js/testsuite'], function(suite){

    })

});

testsuite.js

function () {

    QUnit.config.autostart = false;

    var testModules = [       
        "factory/FactoryTests.js"
    ];

    require(testModules, QUnit.start);
}());

Thanks!!

回答1:

First, a clarification: What does your QUnit test page look like? I'm guess it's either listing zero tests, or is a blank page.

If that's the case, I had a lot of trouble with the same thing. The "right" answer is exactly what you are doing. But after a lot of stepping through code, in my setup, QUnit was still starting before any of my tests were defined, despite setting QUnit.config.autostart = false.

At the end of testsuite.js, try calling QUnit.load() instead of QUnit.start() (you can probably drop the autostart = false, too). This is an undocumented function, but it was the only thing that worked for me. I believe it's the function QUnit attaches to the onLoad event by default. Unfortunately, with RequireJS, the onLoad triggers before most of your js files have loaded.



回答2:

I have tackled this problem today and I am adding the info I gathered to @keithjgrant correct answer.

From RequireJs documents:

QUnit

Despite QUnit having problems being loaded as an async module, you can get it to work by including it in a script tag before require.js, then turning off autostart, and then manually calling start() once your modules with tests are loaded. However, start needs to be called from inside a timer. Here's the full harness.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>QUnit Test Suite</title>
    <link rel="stylesheet" href="qunit-git.css">
    <script data-main="main" type="text/javascript" src="libs/require.js"></script>
    <script src="libs/qunit-git.js"></script>
    <script type="text/javascript">
        window.addEventListener("load", function onLoad() {
            QUnit.config.autostart = false;
                        // Without this setTimeout, the specs don't always get execute in webKit browsers

            setTimeout(function () {
                                //load tests using require
                require(['firstUse/example_test'], function (one) {
                    //now trigger them.
                    QUnit.start();
                });

            }, 10);
            window.removeEventListener("load", onLoad, true);
        }, true);
    </script>
</head>
<body>
    <div id="qunit">
    </div>
</body>
</html>

Use Qunit.stop() if you need to stop the tests, do some more async work then start them again with QUnit.start().

From the QUnit source code

Unit.load = function() {
  ...

  if ( config.autostart ) {
    QUnit.start();
  }
};

if ( defined.document ) {
   addEvent( window, "load", QUnit.load );
}

I have investigated why using my different approach of calling QUnit with RequireJs was not working. I've found the same solution @keithjgrant suggested.

While debugging my code which called QUnit from RequireJs, it seems the window load event has already been dispatched. The document.readyState was 'complete' .Since the addEventHandler for the load event does not behave like a promise, adding a handler to an already fired event does not trigger the handler.

Calling the QUnit.load function explicitly, fixed my problem. One needs to consider though how to find at that calling point if the window had finished loading. You can do this with JQquery, or with part of the JQuery code from which I took document.readyState == 'complete' from.



回答3:

You can do like this:

    <!DOCTYPE html>
<html>
<head>
    <title>Example Test Runner</title>
    <link rel="stylesheet" href="//code.jquery.com/qunit/qunit-1.15.0.css">
    <script src="../libraries/qunit/qunit/qunit.js" data-main="testsuite.js"></script>
    <script>
        QUnit.config.autostart = false;
    </script>
    <!-- Load RequireJS & the testsuite -->
    <script src="../libraries/requirejs/require.js" data-main="testsuite.js"></script>
</head>
<body>
<div id="qunit"></div>
</body>
</html>

So requirejs will start to work after setting an option to QUnit.