From 8016ad15f0d8f4801bc8708af1011faebb9c31a4 Mon Sep 17 00:00:00 2001 From: Matt Isner Date: Thu, 18 Jan 2018 06:29:28 -0500 Subject: [PATCH] feat(collect-results-from-frames): add frameWaitTime option (#661) Closes https://github.com/dequelabs/axe-core/issues/660 --- doc/API.md | 1 + lib/core/utils/collect-results-from-frames.js | 6 ++- .../core/utils/collect-results-from-frames.js | 35 ++++++++++++++- .../full/frame-wait-time/frame-wait-time.html | 26 +++++++++++ .../full/frame-wait-time/frame-wait-time.js | 43 +++++++++++++++++++ .../full/frame-wait-time/frames/frame.html | 11 +++++ 6 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 test/integration/full/frame-wait-time/frame-wait-time.html create mode 100644 test/integration/full/frame-wait-time/frame-wait-time.js create mode 100644 test/integration/full/frame-wait-time/frames/frame.html 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 @@ + + + + frame-wait-time test + + + + + + + + +
+ +
+
+ + + + diff --git a/test/integration/full/frame-wait-time/frame-wait-time.js b/test/integration/full/frame-wait-time/frame-wait-time.js new file mode 100644 index 0000000000..af0df787cb --- /dev/null +++ b/test/integration/full/frame-wait-time/frame-wait-time.js @@ -0,0 +1,43 @@ + +describe('frame-wait-time option', function () { + 'use strict'; + + before(function (done) { + if (document.readyState !== 'complete') { + window.addEventListener('load', done.bind(this, null)); + } else { + done(); + } + }); + + describe('when set', function () { + var opts = { + frameWaitTime: 1 + }; + + it('should modify the default frame timeout', function (done) { + var start = new Date(); + // Run axe with an unreasonably short wait time, + // expecting the frame to time out + axe.run('main', opts, function (err, res) { + assert.isNotNull(err); + assert.isUndefined(res); + assert.equal(err.message, 'Axe in frame timed out: #frame'); + // Ensure that axe waited less than the default wait time + assert.isBelow(new Date() - start, 60000); + done(); + }); + }); + }); + + describe('when not set', function () { + + it('should use the default frame timeout', function (done) { + axe.run('main', function (err, res) { + assert.isNull(err); + assert.isAbove(res.violations.length, 0); + done(); + }); + }); + }); +}); diff --git a/test/integration/full/frame-wait-time/frames/frame.html b/test/integration/full/frame-wait-time/frames/frame.html new file mode 100644 index 0000000000..466d9bc747 --- /dev/null +++ b/test/integration/full/frame-wait-time/frames/frame.html @@ -0,0 +1,11 @@ + + + + frame-wait-time test frame + + + + +

So Dim

+ +