-
Notifications
You must be signed in to change notification settings - Fork 742
/
collect-results-from-frames.js
132 lines (119 loc) · 3.29 KB
/
collect-results-from-frames.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
function err(message, node) {
'use strict';
var selector;
if (axe._tree) {
selector = axe.utils.getSelector(node);
}
return new Error(message + ': ' + (selector || node));
}
/**
* Sends a command to an instance of axe in the specified frame
* @param {Element} node The frame element to send the message to
* @param {Object} parameters Parameters to pass to the frame
* @param {Function} callback Function to call when results from the frame has returned
*/
axe.utils.sendCommandToFrame = function(node, parameters, resolve, reject) {
'use strict';
var win = node.contentWindow;
if (!win) {
axe.log('Frame does not have a content window', node);
resolve(null);
return;
}
// give the frame .5s to respond to 'axe.ping', else log failed response
var timeout = setTimeout(function() {
// This double timeout is important for allowing iframes to respond
// DO NOT REMOVE
timeout = setTimeout(function() {
if (!parameters.debug) {
resolve(null);
} else {
reject(err('No response from frame', node));
}
}, 0);
}, 500);
// send 'axe.ping' to the frame
axe.utils.respondable(win, 'axe.ping', null, undefined, function(
pingResponse
) {
if (!pingResponse || !pingResponse.axe === true) {
return;
}
clearTimeout(timeout);
// 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));
}, frameWaitTime);
// send 'axe.start' and send the callback if it responded
axe.utils.respondable(win, 'axe.start', parameters, undefined, function(
data
) {
clearTimeout(timeout);
if (data instanceof Error === false) {
resolve(data);
} else {
reject(data);
}
});
});
};
/**
* Sends a message to axe running in frames to start analysis and collate results (via `mergeResults`)
* @private
* @param {Context} context The resolved Context object
* @param {Object} options Options object (as passed to `runRules`)
* @param {string} command Command sent to all frames
* @param {Array} parameter Array of values to be passed along side the command
* @param {Function} callback Function to call when results from all frames have returned
*/
function collectResultsFromFrames(
context,
options,
command,
parameter,
resolve,
reject
) {
'use strict';
var q = axe.utils.queue();
var frames = context.frames;
// Tell each axe running in each frame to collect results
frames.forEach(function(frame) {
var params = {
options: options,
command: command,
parameter: parameter,
context: {
initiator: false,
page: context.page,
include: frame.include || [],
exclude: frame.exclude || []
}
};
q.defer(function(res, rej) {
var node = frame.node;
axe.utils.sendCommandToFrame(
node,
params,
function(data) {
if (data) {
return res({
results: data,
frameElement: node,
frame: axe.utils.getSelector(node)
});
}
res(null);
},
rej
);
});
});
// Combine results from all frames and give it back
q.then(function(data) {
resolve(axe.utils.mergeResults(data, options));
}).catch(reject);
}
axe.utils.collectResultsFromFrames = collectResultsFromFrames;