Skip to content
This repository

setup() methods are called prematurely when tests are loaded asynchronously #320

Closed
wants to merge 1 commit into from

3 participants

Max Cantor Philipp Scheit Jörn Zaefferer
Max Cantor

I believe this might be an example of this problem in the wild.

If tests are loaded asynchronously, the document is loaded before they are read, which changes the values of config.autorun and config.blocking and eventually causes the callbacks queued in Test.queue() to be run out-of-sequence.

This pull request contains a separate test HTML file with accompanying JS tests that exemplify the problem.

The exact sequence of problematic events goes like this:

  1. DOM loads
  2. QUnit.load() completes, and calls QUnit.start()
  3. QUnit.start() sets config.blocking to false, then calls process()
  4. There's nothing in the queue, so process() calls done()
  5. done() sets config.autorun to true
  6. Test A queues init(), which is autorun by synchronize()
  7. Test A queues the inner run(), which is autorun
  8. Test A queues setup(), which is autorun
  9. Test A queues run(), which is autorun; now we're blocking.
  10. Test A queues teardown() and finish(). queue is now [A.teardown, A.finish]
  11. Test B queues init() and inner run(). queue is now [A.teardown, A.finish, B.init, B.run]
  12. Test C queues init() and inner run(). queue is now [A.teardown, A.finish, B.init, B.run, C.init, C.run]
  13. Test A's teardown() and finish() are run; no more blocking. queue is now [B.init, B.run, C.init, C.run]
  14. Test B's init() and inner run() are run. queue is now [C.init, C.run]
  15. Test B queues setup(). queue is now [C.init, C.run, B.setup]
  16. synchronize() queues Test B's setup() and kicks off process()
  17. process() runs the next functions in the queue, which are Test C's init() and run().
  18. Test C queues setup(). queue is now [B.setup, C.setup]

And now you're thinking with portals.

Philipp Scheit

nice job, good test though, i had the same idea with the array for the stack exchange post but yours is more elegant.

Jörn Zaefferer
Owner

Usually what you need to do here is to set QUnit.config.autorun = false, then call QUnit.start() once you're done loading tests. Certainly needs (better) documentation, but I don't think there's much the framework could do.

Jörn Zaefferer
Owner

There's an example for using QUnit.config.autostart in the API documentation now: http://api.qunitjs.com/QUnit.config/

Beyond that I would need more input to address this, until then I've got to assume the above is a valid solution.

Jörn Zaefferer jzaefferer closed this October 01, 2012
Philipp Scheit

thanks, that solved it. I'm glad that you have now a real api documentation.

Max Cantor

@jzaefferer - How about adding QUnit.config.autostart to the file in my test? I don't think there's already a test for this functionality (is there?)

Jörn Zaefferer
Owner

@mcantor good suggestion, thanks. Landed in 4e03a4b

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

Sep 19, 2012
Max Cantor add a test that exemplifies the async load problem 71dc6f3
This page is out of date. Refresh to see the latest.
26  test/async.html
... ...
@@ -0,0 +1,26 @@
  1
+<!DOCTYPE html>
  2
+<html>
  3
+<head>
  4
+	<meta charset="UTF-8" />
  5
+	<title>QUnit Test Suite</title>
  6
+	<link rel="stylesheet" href="../qunit/qunit.css">
  7
+</head>
  8
+<body>
  9
+	<div id="qunit"></div>
  10
+	<div id="qunit-fixture">test markup</div>
  11
+	<script type="text/javascript" src="../qunit/qunit.js"></script>
  12
+	<script type="text/javascript">
  13
+		// Simulate a delay in retrieving the tests, as when they are loaded
  14
+		// asynchronously using steal, etc.
  15
+		// This results in the document loading before any tests are loaded,
  16
+		// which means config.autorun is true and config.blocking is false.
  17
+		var head= document.getElementsByTagName('head')[0];
  18
+		var script= document.createElement('script');
  19
+		script.type= 'text/javascript';
  20
+		script.src= 'async_setup.js';
  21
+		setTimeout(function() {
  22
+			head.appendChild(script);
  23
+		}, 1000);
  24
+	</script>
  25
+</body>
  26
+</html>
27  test/async_setup.js
... ...
@@ -0,0 +1,27 @@
  1
+var empty_me = ['start'];
  2
+
  3
+module("multiple async tests with setup", {
  4
+	setup: function() {
  5
+		empty_me = [];
  6
+	}
  7
+});
  8
+
  9
+asyncTest("async A", function() {
  10
+	equal(empty_me.length, 0, "setup should have emptied the array.");
  11
+	empty_me.push('A');
  12
+	start();
  13
+});
  14
+
  15
+asyncTest("async B", function() {
  16
+	equal(empty_me.length, 0, "setup should have emptied the array.");
  17
+	empty_me.push('B');
  18
+	start();
  19
+});
  20
+
  21
+asyncTest("async C", function() {
  22
+	equal(empty_me.length, 0, "setup should have emptied the array.");
  23
+	empty_me.push('C');
  24
+	start();
  25
+});
  26
+
  27
+
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.