diff --git a/doc/API.md b/doc/API.md index 9e4c2899e5..f095677653 100644 --- a/doc/API.md +++ b/doc/API.md @@ -337,6 +337,7 @@ Additionally, there are a number or properties that allow configuration of diffe | `iframes` | `true` | Tell axe to run inside iframes | `elementRef` | `false` | Return element references in addition to the target | `restoreScroll` | `false` | Scrolls elements back to before axe started +| `frameWaitTime` | `60000` | How long (in milliseconds) axe waits for a response from embedded frames before timing out ###### Options Parameter Examples diff --git a/lib/core/utils/collect-results-from-frames.js b/lib/core/utils/collect-results-from-frames.js index e0e219d4ce..3f000fa1de 100644 --- a/lib/core/utils/collect-results-from-frames.js +++ b/lib/core/utils/collect-results-from-frames.js @@ -39,10 +39,12 @@ axe.utils.sendCommandToFrame = function(node, parameters, resolve, reject) { axe.utils.respondable(win, 'axe.ping', null, undefined, function() { clearTimeout(timeout); - // Give aXe 30s to respond to 'axe.start' + // Give aXe 60s (or user-supplied value) to respond to 'axe.start' + var frameWaitTime = (parameters.options && parameters.options.frameWaitTime) || 60000; + timeout = setTimeout(function() { reject(err('Axe in frame timed out', node)); - }, 30000); + }, frameWaitTime); // send 'axe.start' and send the callback if it responded axe.utils.respondable(win, 'axe.start', parameters, undefined, function(data) { diff --git a/test/core/utils/collect-results-from-frames.js b/test/core/utils/collect-results-from-frames.js index 3f1fd36a17..a1a4202c2c 100644 --- a/test/core/utils/collect-results-from-frames.js +++ b/test/core/utils/collect-results-from-frames.js @@ -9,10 +9,10 @@ describe('axe.utils.collectResultsFromFrames', function () { fixture.innerHTML = ''; }); - it('should timeout after 30s', function (done) { + it('should timeout after 60s', function (done) { var orig = window.setTimeout; window.setTimeout = function (fn, to) { - if (to === 30000) { + if (to === 60000) { assert.ok('timeout set'); fn(); } else { // ping timeout @@ -37,6 +37,37 @@ describe('axe.utils.collectResultsFromFrames', function () { frame.src = '../mock/frames/results-timeout.html'; fixture.appendChild(frame); + }); + + it('should override the timeout with `options.frameWaitTime`, if provided', function (done) { + var orig = window.setTimeout; + window.setTimeout = function (fn, to) { + if (to === 90000) { + assert.ok('timeout set'); + fn(); + } else { // ping timeout + return orig(fn, to); + } + return 'cats'; + }; + + var frame = document.createElement('iframe'); + frame.addEventListener('load', function () { + var context = new Context(document); + var params = { frameWaitTime: 90000 }; + axe.utils.collectResultsFromFrames(context, params, 'stuff', 'morestuff', noop, + function (err) { + assert.instanceOf(err, Error); + assert.equal(err.message.split(/: /)[0], 'Axe in frame timed out'); + window.setTimeout = orig; + done(); + }); + }); + + frame.id = 'level0'; + frame.src = '../mock/frames/results-timeout.html'; + fixture.appendChild(frame); + }); it('should not throw given a recursive iframe', function (done) { diff --git a/test/integration/full/frame-wait-time/frame-wait-time.html b/test/integration/full/frame-wait-time/frame-wait-time.html new file mode 100644 index 0000000000..b31ea38aa8 --- /dev/null +++ b/test/integration/full/frame-wait-time/frame-wait-time.html @@ -0,0 +1,26 @@ + + +
+