@axe-core/webdriverjs 4.3.3-alpha.224 → 4.3.3-alpha.228
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -2
- package/package.json +5 -2
- package/.eslintrc.js +0 -13
- package/error-handling.md +0 -52
- package/example-with-callback.js +0 -15
- package/example.js +0 -13
- package/src/axe-injector.ts +0 -191
- package/src/browser.ts +0 -142
- package/src/index.ts +0 -271
- package/src/types.ts +0 -29
- package/src/utils/index.ts +0 -21
- package/tests/axe-webdriverjs.spec.ts +0 -691
- package/tests/fixtures/context.html +0 -15
- package/tests/fixtures/iframe-one.html +0 -14
- package/tests/test-utils.ts +0 -49
- package/tsconfig.json +0 -15
package/README.md
CHANGED
|
@@ -6,13 +6,25 @@ Previous versions of this program were maintained at [dequelabs/axe-webdriverjs]
|
|
|
6
6
|
|
|
7
7
|
## Getting Started
|
|
8
8
|
|
|
9
|
-
Install [Node.js](https://docs.npmjs.com/getting-started/installing-node) if you haven't already.
|
|
9
|
+
Install [Node.js](https://docs.npmjs.com/getting-started/installing-node) if you haven't already.
|
|
10
10
|
|
|
11
11
|
> Download and install any necessary browser drivers on your machine's PATH. [More on Webdriver setup](https://www.selenium.dev/documentation/en/webdriver/).
|
|
12
12
|
|
|
13
13
|
Install Selenium Webdriver: `npm install selenium-webdriver --no-save`
|
|
14
14
|
|
|
15
|
-
Install @axe-core/webdriverjs and its dependencies:
|
|
15
|
+
Install @axe-core/webdriverjs and its dependencies:
|
|
16
|
+
|
|
17
|
+
NPM:
|
|
18
|
+
|
|
19
|
+
```console
|
|
20
|
+
npm install @axe-core/webdriverjs
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Yarn:
|
|
24
|
+
|
|
25
|
+
```console
|
|
26
|
+
yarn add @axe-core/webdriverjs
|
|
27
|
+
```
|
|
16
28
|
|
|
17
29
|
## Usage
|
|
18
30
|
|
|
@@ -162,3 +174,13 @@ const axe = new AxeBuilder(driver).setLegacyMode();
|
|
|
162
174
|
const result = await axe.analyze();
|
|
163
175
|
axe.setLegacyMode(false); // Disables legacy mode
|
|
164
176
|
```
|
|
177
|
+
|
|
178
|
+
### WebdriverJS Example
|
|
179
|
+
|
|
180
|
+
We have created an example [test suite](https://github.com/dequelabs/axe-core-npm/tree/develop/packages/webdriverjs/tests/examples/webdriverjs-example.ts) showcasing the functionality of axe-core WebdriverJS.
|
|
181
|
+
|
|
182
|
+
To run the test:
|
|
183
|
+
|
|
184
|
+
- Navigate to: `/webdriverjs/tests/example`
|
|
185
|
+
- Install node modules: `npm install`
|
|
186
|
+
- Run tests: `npm test`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axe-core/webdriverjs",
|
|
3
|
-
"version": "4.3.3-alpha.
|
|
3
|
+
"version": "4.3.3-alpha.228+0e566c2",
|
|
4
4
|
"description": "Provides a method to inject and analyze web pages using axe",
|
|
5
5
|
"contributors": [
|
|
6
6
|
{
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
"name": "Michael Siek (me@michaelsiek.com)"
|
|
28
28
|
}
|
|
29
29
|
],
|
|
30
|
+
"files": [
|
|
31
|
+
"/dist"
|
|
32
|
+
],
|
|
30
33
|
"repository": {
|
|
31
34
|
"type": "git",
|
|
32
35
|
"url": "https://github.com/dequelabs/axe-core-npm.git"
|
|
@@ -105,5 +108,5 @@
|
|
|
105
108
|
"functions": 85,
|
|
106
109
|
"lines": 85
|
|
107
110
|
},
|
|
108
|
-
"gitHead": "
|
|
111
|
+
"gitHead": "0e566c246a4a3ab0e5b7b129fbf7006bb67aa7b6"
|
|
109
112
|
}
|
package/.eslintrc.js
DELETED
package/error-handling.md
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Error Handling
|
|
2
|
-
|
|
3
|
-
## Table of Content
|
|
4
|
-
|
|
5
|
-
1. [Having an Out-of-date Driver](#having-an-out-of-date-driver)
|
|
6
|
-
2. [Having Popup blockers enabled](#having-popup-blockers-enabled)
|
|
7
|
-
3. [AxeBuilder.setLegacyMode(legacy: boolean)](#axebuildersetlegacymodelegacy-boolean)
|
|
8
|
-
|
|
9
|
-
Version 4.3.0 and above of the axe-core integrations use a new technique when calling `AxeBuilder.analyze()` which opens a new window at the end of a run. Many of the issues outlined in this document address common problems with this technique and their potential solutions.
|
|
10
|
-
|
|
11
|
-
### Having an Out-of-date Driver
|
|
12
|
-
|
|
13
|
-
A common problem is having an out-of-date driver. To fix this issue make sure that your local install of [geckodriver](https://github.com/mozilla/geckodriver/releases) or [chromedriver](https://chromedriver.chromium.org/downloads) is up-to-date.
|
|
14
|
-
|
|
15
|
-
An example error message for this problem will include a message about `switchToWindow`.
|
|
16
|
-
|
|
17
|
-
Example:
|
|
18
|
-
|
|
19
|
-
```console
|
|
20
|
-
(node:17566) UnhandledPromiseRejectionWarning: Error: Malformed type for "handle" parameter of command switchToWindow
|
|
21
|
-
Expected: string
|
|
22
|
-
Actual: undefined
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### Having Popup blockers enabled
|
|
26
|
-
|
|
27
|
-
Popup blockers prevent us from opening the new window when calling `AxeBuilder.analyze()`. The default configuration for most automation testing libraries should allow popups. Please make sure that you do not explicitly enable popup blockers which may cause an issue while running the tests.
|
|
28
|
-
|
|
29
|
-
### AxeBuilder.setLegacyMode(legacy: boolean)
|
|
30
|
-
|
|
31
|
-
If for some reason you are unable to run the new `AxeBuilder.analyze` technique without errors, axe provides a new chainable method that allows you to run the legacy version of `AxeBuilder.analyze`. When using this method axe excludes accessibility issues that may occur in cross-domain frames and iframes.
|
|
32
|
-
|
|
33
|
-
**Please Note:** `AxeBuilder.setLegacyMode` is deprecated and will be removed in v5.0. Please report any errors you may have while running `AxeBuilder.analyze` so that they can be fixed before the legacy version is removed.
|
|
34
|
-
|
|
35
|
-
#### Example:
|
|
36
|
-
|
|
37
|
-
```js
|
|
38
|
-
const AxeBuilder = require('@axe-core/webdriverjs');
|
|
39
|
-
const WebDriver = require('selenium-webdriver');
|
|
40
|
-
(async () => {
|
|
41
|
-
const driver = new WebDriver.Builder().forBrowser('chrome').build();
|
|
42
|
-
await driver.get('https://dequeuniversity.com/demo/mars/');
|
|
43
|
-
const results = await new AxeBuilder(driver, null, {
|
|
44
|
-
noSandbox: true
|
|
45
|
-
})
|
|
46
|
-
// enables legacy mode
|
|
47
|
-
.setLegacyMode()
|
|
48
|
-
.analyze();
|
|
49
|
-
console.log(results);
|
|
50
|
-
await driver.quit();
|
|
51
|
-
})();
|
|
52
|
-
```
|
package/example-with-callback.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
const AxeBuilder = require('@axe-core/webdriverjs');
|
|
2
|
-
const WebDriver = require('selenium-webdriver');
|
|
3
|
-
|
|
4
|
-
const driver = new WebDriver.Builder().forBrowser('chrome').build();
|
|
5
|
-
|
|
6
|
-
driver.get('https://html5-sandbox.glitch.me/').then(() => {
|
|
7
|
-
const axe = new AxeBuilder(driver, null, { noSandbox: true });
|
|
8
|
-
axe.analyze(async (err, results) => {
|
|
9
|
-
if (err) {
|
|
10
|
-
// Handle error somehow
|
|
11
|
-
}
|
|
12
|
-
console.log(results);
|
|
13
|
-
await driver.quit();
|
|
14
|
-
});
|
|
15
|
-
});
|
package/example.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
const AxeBuilder = require('@axe-core/webdriverjs');
|
|
2
|
-
const WebDriver = require('selenium-webdriver');
|
|
3
|
-
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
5
|
-
(async () => {
|
|
6
|
-
const driver = new WebDriver.Builder().forBrowser('chrome').build();
|
|
7
|
-
await driver.get('https://html5-sandbox.glitch.me/');
|
|
8
|
-
const results = await new AxeBuilder(driver, null, {
|
|
9
|
-
noSandbox: true
|
|
10
|
-
}).analyze();
|
|
11
|
-
console.log(results);
|
|
12
|
-
await driver.quit();
|
|
13
|
-
})();
|
package/src/axe-injector.ts
DELETED
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
import type { WebDriver, WebElement } from 'selenium-webdriver';
|
|
2
|
-
import { error } from 'selenium-webdriver';
|
|
3
|
-
import { source } from 'axe-core';
|
|
4
|
-
import type { AxeInjectorParams, BuilderOptions } from './types';
|
|
5
|
-
const { StaleElementReferenceError } = error;
|
|
6
|
-
|
|
7
|
-
export default class AxeInjectorLegacy {
|
|
8
|
-
private driver: WebDriver;
|
|
9
|
-
private axeSource: string;
|
|
10
|
-
private options: BuilderOptions;
|
|
11
|
-
private config: string;
|
|
12
|
-
private didLogError: boolean;
|
|
13
|
-
constructor({
|
|
14
|
-
driver,
|
|
15
|
-
axeSource,
|
|
16
|
-
builderOptions,
|
|
17
|
-
config
|
|
18
|
-
}: AxeInjectorParams) {
|
|
19
|
-
this.driver = driver;
|
|
20
|
-
this.axeSource = axeSource || source;
|
|
21
|
-
this.config = config ? JSON.stringify(config) : '';
|
|
22
|
-
this.options = builderOptions || {};
|
|
23
|
-
this.didLogError = false;
|
|
24
|
-
|
|
25
|
-
this.options.noSandbox =
|
|
26
|
-
typeof this.options.noSandbox === 'boolean'
|
|
27
|
-
? this.options.noSandbox
|
|
28
|
-
: false;
|
|
29
|
-
|
|
30
|
-
this.options.logIframeErrors =
|
|
31
|
-
typeof this.options.logIframeErrors === 'boolean'
|
|
32
|
-
? this.options.logIframeErrors
|
|
33
|
-
: false;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Checks to make sure that the error thrown was not a stale iframe
|
|
38
|
-
* @param {Error} error
|
|
39
|
-
* @returns {void}
|
|
40
|
-
*/
|
|
41
|
-
|
|
42
|
-
private errorHandler(err: Error): void {
|
|
43
|
-
// We've already "warned" the user. No need to do it again (mostly for backwards compatibility)
|
|
44
|
-
if (this.didLogError) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
this.didLogError = true;
|
|
49
|
-
let msg;
|
|
50
|
-
if (err instanceof StaleElementReferenceError) {
|
|
51
|
-
msg =
|
|
52
|
-
'Tried to inject into a removed iframe. This will not affect the analysis of the rest of the page but you might want to ensure the page has finished updating before starting the analysis.';
|
|
53
|
-
} else {
|
|
54
|
-
msg = 'Failed to inject axe-core into one of the iframes!';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (this.options.logIframeErrors) {
|
|
58
|
-
console.error(msg);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
throw new Error(msg);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Get axe-core source and configurations
|
|
67
|
-
* @returns {String}
|
|
68
|
-
*/
|
|
69
|
-
|
|
70
|
-
private get script(): string {
|
|
71
|
-
return `
|
|
72
|
-
${this.axeSource}
|
|
73
|
-
${this.config ? `axe.configure(${this.config})` : ''}
|
|
74
|
-
axe.configure({
|
|
75
|
-
branding: { application: 'webdriverjs' }
|
|
76
|
-
})
|
|
77
|
-
`;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Removes the `sandbox` attribute from iFrames
|
|
82
|
-
* @returns {Promise<void>}
|
|
83
|
-
*/
|
|
84
|
-
|
|
85
|
-
private async sandboxBuster(): Promise<void> {
|
|
86
|
-
// outer promise needed because `executeAsyncScript`
|
|
87
|
-
// does not return a "real promise" (ManagedPromise)
|
|
88
|
-
// and we want to await it.
|
|
89
|
-
return new Promise((resolve, reject) => {
|
|
90
|
-
/* eslint-disable no-undef */
|
|
91
|
-
this.driver
|
|
92
|
-
// https://github.com/vercel/pkg/issues/676
|
|
93
|
-
// we need to pass a string vs a function so we manually stringified the function
|
|
94
|
-
.executeAsyncScript(
|
|
95
|
-
`
|
|
96
|
-
var callback = arguments[arguments.length - 1];
|
|
97
|
-
var iframes = Array.from(
|
|
98
|
-
document.querySelectorAll('iframe[sandbox]')
|
|
99
|
-
);
|
|
100
|
-
var removeSandboxAttr = clone => attr => {
|
|
101
|
-
if (attr.name === 'sandbox') return;
|
|
102
|
-
clone.setAttribute(attr.name, attr.value);
|
|
103
|
-
};
|
|
104
|
-
var replaceSandboxedIframe = iframe => {
|
|
105
|
-
var clone = document.createElement('iframe');
|
|
106
|
-
var promise = new Promise(
|
|
107
|
-
iframeLoaded => (clone.onload = iframeLoaded)
|
|
108
|
-
);
|
|
109
|
-
Array.from(iframe.attributes).forEach(removeSandboxAttr(clone));
|
|
110
|
-
iframe.parentElement.replaceChild(clone, iframe);
|
|
111
|
-
return promise;
|
|
112
|
-
};
|
|
113
|
-
Promise.all(iframes.map(replaceSandboxedIframe)).then(callback);
|
|
114
|
-
`
|
|
115
|
-
)
|
|
116
|
-
// resolve the outer promise
|
|
117
|
-
.then(() => resolve())
|
|
118
|
-
.catch(e => reject(e));
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Injects into the provided `frame` and its child `frames`
|
|
124
|
-
* @param {WebElement[]} framePath
|
|
125
|
-
* @returns {Promise<void>}
|
|
126
|
-
*/
|
|
127
|
-
|
|
128
|
-
private async handleFrame(framePath: WebElement[]): Promise<void> {
|
|
129
|
-
await this.driver.switchTo().defaultContent();
|
|
130
|
-
|
|
131
|
-
for (const frame of framePath) {
|
|
132
|
-
await this.driver.switchTo().frame(frame);
|
|
133
|
-
}
|
|
134
|
-
if (this.options.noSandbox) {
|
|
135
|
-
await this.sandboxBuster();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
await this.driver.executeScript(this.script);
|
|
139
|
-
|
|
140
|
-
const ifs = await this.driver.findElements({ tagName: 'iframe' });
|
|
141
|
-
const fs = await this.driver.findElements({ tagName: 'frame' });
|
|
142
|
-
const frames = ifs.concat(fs);
|
|
143
|
-
|
|
144
|
-
for (const childFrames of frames) {
|
|
145
|
-
framePath.push(childFrames);
|
|
146
|
-
try {
|
|
147
|
-
await this.handleFrame(framePath);
|
|
148
|
-
} catch (error) {
|
|
149
|
-
this.errorHandler(error as Error);
|
|
150
|
-
} finally {
|
|
151
|
-
framePath.pop();
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Injects into all frames
|
|
158
|
-
* @returns {Promise<void>}
|
|
159
|
-
*/
|
|
160
|
-
public async injectIntoAllFrames(): Promise<void> {
|
|
161
|
-
// Ensure we're "starting" our loop at the top-most frame
|
|
162
|
-
await this.driver.switchTo().defaultContent();
|
|
163
|
-
|
|
164
|
-
// By default we do not remove the sandbox attr from iframe unless user specifies
|
|
165
|
-
if (this.options.noSandbox) {
|
|
166
|
-
// reinject any sandboxed iframes without the sandbox attribute so we can scan
|
|
167
|
-
await this.sandboxBuster();
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Inject the script into the top-level
|
|
171
|
-
// XXX: if this `executeScript` fails, we *want* to error, as we cannot run axe-core.
|
|
172
|
-
await this.driver.executeScript(this.script);
|
|
173
|
-
|
|
174
|
-
// Get all of <iframe>s and <frame>s at this level
|
|
175
|
-
const ifs = await this.driver.findElements({ tagName: 'iframe' });
|
|
176
|
-
const fs = await this.driver.findElements({ tagName: 'frame' });
|
|
177
|
-
const frames = ifs.concat(fs);
|
|
178
|
-
|
|
179
|
-
// Inject the script into all child frames. Handle errors to ensure we don't stop execution if we fail to inject.
|
|
180
|
-
for (const childFrame of frames) {
|
|
181
|
-
try {
|
|
182
|
-
await this.handleFrame([childFrame]);
|
|
183
|
-
} catch (err) {
|
|
184
|
-
this.errorHandler(err as Error);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Move back to the top-most frame
|
|
189
|
-
return this.driver.switchTo().defaultContent();
|
|
190
|
-
}
|
|
191
|
-
}
|
package/src/browser.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AxeResults,
|
|
3
|
-
ContextObject,
|
|
4
|
-
FrameContext,
|
|
5
|
-
RunOptions,
|
|
6
|
-
Spec,
|
|
7
|
-
PartialResult
|
|
8
|
-
} from 'axe-core';
|
|
9
|
-
import { WebDriver, WebElement } from 'selenium-webdriver';
|
|
10
|
-
|
|
11
|
-
type FrameContextWeb = FrameContext & {
|
|
12
|
-
frame: WebElement;
|
|
13
|
-
href: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
// https://github.com/vercel/pkg/issues/676
|
|
17
|
-
// we need to pass a string vs a function so we manually stringified the function
|
|
18
|
-
// There are no try/catch blocks needed in these scripts. If an error occurs
|
|
19
|
-
// Selenium pass them onto the catch block.
|
|
20
|
-
|
|
21
|
-
export function axeSourceInject(
|
|
22
|
-
driver: WebDriver,
|
|
23
|
-
axeSource: string,
|
|
24
|
-
config: Spec | null
|
|
25
|
-
): Promise<{ runPartialSupported: boolean }> {
|
|
26
|
-
return promisify(
|
|
27
|
-
driver.executeScript<{ runPartialSupported: boolean }>(`
|
|
28
|
-
${axeSource};
|
|
29
|
-
window.axe.configure({
|
|
30
|
-
branding: { application: 'webdriverjs' }
|
|
31
|
-
});
|
|
32
|
-
var config = ${JSON.stringify(config)};
|
|
33
|
-
if (config) {
|
|
34
|
-
window.axe.configure(config);
|
|
35
|
-
}
|
|
36
|
-
var runPartial = typeof window.axe.runPartial === 'function';
|
|
37
|
-
return { runPartialSupported: runPartial };
|
|
38
|
-
`)
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function axeRunPartial(
|
|
43
|
-
driver: WebDriver,
|
|
44
|
-
context: ContextObject,
|
|
45
|
-
options: RunOptions
|
|
46
|
-
): Promise<string> {
|
|
47
|
-
return promisify(
|
|
48
|
-
driver.executeAsyncScript<string>(`
|
|
49
|
-
var callback = arguments[arguments.length - 1];
|
|
50
|
-
var context = ${JSON.stringify(context)} || document;
|
|
51
|
-
var options = ${JSON.stringify(options)} || {};
|
|
52
|
-
window.axe.runPartial(context, options).then(res => JSON.stringify(res)).then(callback);
|
|
53
|
-
`)
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function axeFinishRun(
|
|
58
|
-
driver: WebDriver,
|
|
59
|
-
axeSource: string,
|
|
60
|
-
config: Spec | null,
|
|
61
|
-
partialResults: Array<string>,
|
|
62
|
-
options: RunOptions
|
|
63
|
-
): Promise<AxeResults> {
|
|
64
|
-
// Inject source and configuration a second time with a mock "this" context,
|
|
65
|
-
// to make it impossible to sniff the global window.axe for results.
|
|
66
|
-
return promisify(
|
|
67
|
-
driver
|
|
68
|
-
.executeAsyncScript<string>(
|
|
69
|
-
`
|
|
70
|
-
var callback = arguments[arguments.length - 1];
|
|
71
|
-
|
|
72
|
-
${axeSource};
|
|
73
|
-
window.axe.configure({
|
|
74
|
-
branding: { application: 'webdriverjs' }
|
|
75
|
-
});
|
|
76
|
-
var config = ${JSON.stringify(config)};
|
|
77
|
-
if (config) {
|
|
78
|
-
window.axe.configure(config);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
var partialResults = ${JSON.stringify(partialResults)};
|
|
82
|
-
partialResults = partialResults.map(res => JSON.parse(res));
|
|
83
|
-
var options = ${JSON.stringify(options || {})};
|
|
84
|
-
window.axe.finishRun(partialResults, options).then(res => JSON.stringify(res)).then(callback);
|
|
85
|
-
`
|
|
86
|
-
)
|
|
87
|
-
.then(res => JSON.parse(res))
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function axeGetFrameContext(
|
|
92
|
-
driver: WebDriver,
|
|
93
|
-
context: ContextObject
|
|
94
|
-
): Promise<FrameContextWeb[]> {
|
|
95
|
-
return promisify(
|
|
96
|
-
driver.executeScript<FrameContextWeb[]>(`
|
|
97
|
-
var context = ${JSON.stringify(context)}
|
|
98
|
-
var frameContexts = window.axe.utils.getFrameContexts(context);
|
|
99
|
-
return frameContexts.map(function (frameContext) {
|
|
100
|
-
return Object.assign(frameContext, {
|
|
101
|
-
href: window.location.href, // For debugging
|
|
102
|
-
frame: axe.utils.shadowSelect(frameContext.frameSelector)
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
`)
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function axeRunLegacy(
|
|
110
|
-
driver: WebDriver,
|
|
111
|
-
context: ContextObject,
|
|
112
|
-
options: RunOptions,
|
|
113
|
-
config: Spec | null
|
|
114
|
-
): Promise<AxeResults> {
|
|
115
|
-
// https://github.com/vercel/pkg/issues/676
|
|
116
|
-
// we need to pass a string vs a function so we manually stringified the function
|
|
117
|
-
return promisify(
|
|
118
|
-
driver
|
|
119
|
-
.executeAsyncScript<string>(
|
|
120
|
-
`
|
|
121
|
-
var callback = arguments[arguments.length - 1];
|
|
122
|
-
var context = ${JSON.stringify(context)} || document;
|
|
123
|
-
var options = ${JSON.stringify(options)} || {};
|
|
124
|
-
var config = ${JSON.stringify(config)} || null;
|
|
125
|
-
if (config) {
|
|
126
|
-
window.axe.configure(config);
|
|
127
|
-
}
|
|
128
|
-
window.axe.run(context, options).then(res => JSON.stringify(res)).then(callback);
|
|
129
|
-
`
|
|
130
|
-
)
|
|
131
|
-
.then(res => JSON.parse(res))
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Selenium-webdriver thenable aren't chainable. This fixes it.
|
|
137
|
-
*/
|
|
138
|
-
function promisify<T>(thenable: Promise<T>): Promise<T> {
|
|
139
|
-
return new Promise((resolve, reject) => {
|
|
140
|
-
thenable.then(resolve, reject);
|
|
141
|
-
});
|
|
142
|
-
}
|