This repository has been archived by the owner on Mar 19, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathaxe-injector.js
82 lines (68 loc) · 2.65 KB
/
axe-injector.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
class AxeInjector {
constructor({ driver, config, axeSource = null }) {
this.driver = driver;
this.axeSource = axeSource || require('axe-core').source;
this.config = config ? JSON.stringify(config) : '';
this.didLogError = false;
this.errorHandler = this.errorHandler.bind(this);
}
// Single-shot error handler. Ensures we don't log more than once.
errorHandler() {
// We've already "warned" the user. No need to do it again (mostly for backwards compatiability)
if (this.didLogError) {
return;
}
this.didLogError = true;
// eslint-disable-next-line no-console
console.log('Failed to inject axe-core into one of the iframes!');
}
// Get axe-core source (and configuration)
get script() {
return `
${this.axeSource}
${this.config ? `axe.configure(${this.config})` : ''}
axe.configure({ branding: { application: 'webdriverjs' } })
`;
}
// Inject into the provided `frame` and its child `frames`
async handleFrame(frame) {
// Switch context to the frame and inject our `script` into it
await this.driver.switchTo().frame(frame);
await this.driver.executeScript(this.script);
// Get all of <iframe>s at this level
const frames = await this.driver.findElements({ tagName: 'iframe' });
// Inject into each frame. Handling errors to ensure an issue on a single frame won't stop the rest of the injections.
return Promise.all(
frames.map(childFrame =>
this.handleFrame(childFrame).catch(this.errorHandler)
)
);
}
// Inject into all frames.
async injectIntoAllFrames() {
// Ensure we're "starting" our loop at the top-most frame
await this.driver.switchTo().defaultContent();
// Inject the script into the top-level
// XXX: if this `executeScript` fails, we *want* to error, as we cannot run axe-core.
await this.driver.executeScript(this.script);
// Get all of <iframe>s at this level
const frames = await this.driver.findElements({ tagName: 'iframe' });
// Inject the script into all child frames. Handle errors to ensure we don't stop execution if we fail to inject.
await Promise.all(
frames.map(childFrame =>
this.handleFrame(childFrame).catch(this.errorHandler)
)
);
// Move back to the top-most frame
return this.driver.switchTo().defaultContent();
}
// Inject axe, invoking the provided callback when done
inject(callback) {
this.injectIntoAllFrames()
.then(() => callback())
// For now, we intentionally ignore errors here, as
// allowing them to bubble up would be a breaking change.
.catch(() => callback());
}
}
module.exports = AxeInjector;