@axe-core/playwright 4.6.2-alpha.379 → 4.7.0

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/dist/index.js CHANGED
@@ -1,402 +1,369 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
10
11
  };
11
- var __generator = (this && this.__generator) || function (thisArg, body) {
12
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
- function verb(n) { return function (v) { return step([n, v]); }; }
15
- function step(op) {
16
- if (f) throw new TypeError("Generator is already executing.");
17
- while (_) try {
18
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
- if (y = 0, t) op = [op[0] & 2, t.value];
20
- switch (op[0]) {
21
- case 0: case 1: t = op; break;
22
- case 4: _.label++; return { value: op[1], done: false };
23
- case 5: _.label++; y = op[1]; op = [0]; continue;
24
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
- default:
26
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
- if (t[2]) _.ops.pop();
31
- _.trys.pop(); continue;
32
- }
33
- op = body.call(thisArg, _);
34
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
- }
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ default: () => AxeBuilder
34
+ });
35
+ module.exports = __toCommonJS(src_exports);
36
+ var import_assert = __toESM(require("assert"));
37
+ var import_axe_core = __toESM(require("axe-core"));
38
+
39
+ // src/utils.ts
40
+ var normalizeContext = (includes, excludes) => {
41
+ const base = {
42
+ exclude: [],
43
+ include: []
44
+ };
45
+ if (excludes.length && Array.isArray(base.exclude)) {
46
+ base.exclude.push(...excludes);
47
+ }
48
+ if (includes.length) {
49
+ base.include = includes;
50
+ }
51
+ return base;
52
+ };
53
+ var analyzePage = ({
54
+ context,
55
+ options
56
+ }) => {
57
+ const axeCore = window.axe;
58
+ return axeCore.run(context || document, options || {}).then((results) => {
59
+ return { error: null, results };
60
+ }).catch((err) => {
61
+ return { error: err.message, results: null };
62
+ });
63
+ };
64
+
65
+ // src/browser.ts
66
+ var axeGetFrameContexts = ({
67
+ context
68
+ }) => {
69
+ return window.axe.utils.getFrameContexts(context);
37
70
  };
38
- var __importDefault = (this && this.__importDefault) || function (mod) {
39
- return (mod && mod.__esModule) ? mod : { "default": mod };
71
+ var axeShadowSelect = ({
72
+ frameSelector
73
+ }) => {
74
+ return window.axe.utils.shadowSelect(frameSelector);
40
75
  };
41
- Object.defineProperty(exports, "__esModule", { value: true });
42
- var assert_1 = __importDefault(require("assert"));
43
- var axe_core_1 = require("axe-core");
44
- var utils_1 = require("./utils");
45
- var browser_1 = require("./browser");
46
- var AxePartialRunner_1 = __importDefault(require("./AxePartialRunner"));
47
- var AxeBuilder = /** @class */ (function () {
48
- function AxeBuilder(_a) {
49
- var page = _a.page, axeSource = _a.axeSource;
50
- this.legacyMode = false;
51
- this.page = page;
52
- this.includes = [];
53
- this.excludes = [];
54
- this.option = {};
55
- this.source = axeSource || axe_core_1.source;
56
- this.errorUrl =
57
- 'https://github.com/dequelabs/axe-core-npm/blob/develop/packages/playwright/error-handling.md';
76
+ var axeRunPartial = ({
77
+ context,
78
+ options
79
+ }) => {
80
+ return window.axe.runPartial(context, options);
81
+ };
82
+ var axeFinishRun = ({
83
+ options
84
+ }) => {
85
+ return window.axe.finishRun(JSON.parse(window.partialResults), options);
86
+ };
87
+ function chunkResultString(chunk) {
88
+ if (!window.partialResults) {
89
+ window.partialResults = "";
90
+ }
91
+ window.partialResults += chunk;
92
+ }
93
+
94
+ // src/AxePartialRunner.ts
95
+ var AxePartialRunner = class {
96
+ constructor(partialPromise, initiator = false) {
97
+ this.initiator = initiator;
98
+ this.partialPromise = caught(partialPromise);
99
+ }
100
+ partialPromise;
101
+ childRunners = [];
102
+ addChildResults(childResultRunner) {
103
+ this.childRunners.push(childResultRunner);
104
+ }
105
+ async getPartials() {
106
+ try {
107
+ const parentPartial = await this.partialPromise;
108
+ const childPromises = this.childRunners.map((childRunner) => {
109
+ return childRunner ? caught(childRunner.getPartials()) : [null];
110
+ });
111
+ const childPartials = (await Promise.all(childPromises)).flat(1);
112
+ return [parentPartial, ...childPartials];
113
+ } catch (e) {
114
+ if (this.initiator) {
115
+ throw e;
116
+ }
117
+ return [null];
58
118
  }
59
- /**
60
- * Selector to include in analysis.
61
- * This may be called any number of times.
62
- * @param String selector
63
- * @returns this
64
- */
65
- AxeBuilder.prototype.include = function (selector) {
66
- this.includes.push(selector);
67
- return this;
68
- };
69
- /**
70
- * Selector to exclude in analysis.
71
- * This may be called any number of times.
72
- * @param String selector
73
- * @returns this
74
- */
75
- AxeBuilder.prototype.exclude = function (selector) {
76
- this.excludes.push(selector);
77
- return this;
78
- };
79
- /**
80
- * Set options to be passed into axe-core
81
- * @param RunOptions options
82
- * @returns AxeBuilder
83
- */
84
- AxeBuilder.prototype.options = function (options) {
85
- this.option = options;
86
- return this;
87
- };
88
- /**
89
- * Limit analysis to only the specified rules.
90
- * Cannot be used with `AxeBuilder#withTags`
91
- * @param String|Array rules
92
- * @returns this
93
- */
94
- AxeBuilder.prototype.withRules = function (rules) {
95
- rules = Array.isArray(rules) ? rules : [rules];
96
- /* istanbul ignore next */
97
- this.option = this.option || {};
98
- this.option.runOnly = {
99
- type: 'rule',
100
- values: rules
101
- };
102
- return this;
103
- };
104
- /**
105
- * Limit analysis to only specified tags.
106
- * Cannot be used with `AxeBuilder#withRules`
107
- * @param String|Array tags
108
- * @returns this
109
- */
110
- AxeBuilder.prototype.withTags = function (tags) {
111
- tags = Array.isArray(tags) ? tags : [tags];
112
- /* istanbul ignore next */
113
- this.option = this.option || {};
114
- this.option.runOnly = {
115
- type: 'tag',
116
- values: tags
117
- };
118
- return this;
119
- };
120
- /**
121
- * Set the list of rules to skip when running an analysis.
122
- * @param String|Array rules
123
- * @returns this
124
- */
125
- AxeBuilder.prototype.disableRules = function (rules) {
126
- rules = Array.isArray(rules) ? rules : [rules];
127
- /* istanbul ignore next */
128
- this.option = this.option || {};
129
- this.option.rules = {};
130
- for (var _i = 0, rules_1 = rules; _i < rules_1.length; _i++) {
131
- var rule = rules_1[_i];
132
- this.option.rules[rule] = { enabled: false };
133
- }
134
- return this;
135
- };
136
- /**
137
- * Use frameMessenger with <same_origin_only>
138
- *
139
- * This disables use of axe.runPartial() which is called in each frame, and
140
- * axe.finishRun() which is called in a blank page. This uses axe.run() instead,
141
- * but with the restriction that cross-origin frames will not be tested.
142
- */
143
- AxeBuilder.prototype.setLegacyMode = function (legacyMode) {
144
- if (legacyMode === void 0) { legacyMode = true; }
145
- this.legacyMode = legacyMode;
146
- return this;
147
- };
148
- /**
149
- * Perform analysis and retrieve results. *Does not chain.*
150
- * @return Promise<Result | Error>
151
- */
152
- AxeBuilder.prototype.analyze = function () {
153
- return __awaiter(this, void 0, void 0, function () {
154
- var context, _a, page, options, runPartialDefined, results, partialResults, partials, error_1;
155
- return __generator(this, function (_b) {
156
- switch (_b.label) {
157
- case 0:
158
- context = (0, utils_1.normalizeContext)(this.includes, this.excludes);
159
- _a = this, page = _a.page, options = _a.option;
160
- page.evaluate(this.script());
161
- return [4 /*yield*/, page.evaluate('typeof window.axe.runPartial === "function"')];
162
- case 1:
163
- runPartialDefined = _b.sent();
164
- if (!(!runPartialDefined || this.legacyMode)) return [3 /*break*/, 3];
165
- return [4 /*yield*/, this.runLegacy(context)];
166
- case 2:
167
- results = _b.sent();
168
- return [2 /*return*/, results];
169
- case 3: return [4 /*yield*/, this.runPartialRecursive(page.mainFrame(), context)];
170
- case 4:
171
- partialResults = _b.sent();
172
- return [4 /*yield*/, partialResults.getPartials()];
173
- case 5:
174
- partials = _b.sent();
175
- _b.label = 6;
176
- case 6:
177
- _b.trys.push([6, 8, , 9]);
178
- return [4 /*yield*/, this.finishRun(partials)];
179
- case 7: return [2 /*return*/, _b.sent()];
180
- case 8:
181
- error_1 = _b.sent();
182
- throw new Error("".concat(error_1.message, "\n Please check out ").concat(this.errorUrl));
183
- case 9: return [2 /*return*/];
184
- }
185
- });
186
- });
187
- };
188
- /**
189
- * Injects `axe-core` into all frames.
190
- * @param Page - playwright page object
191
- * @returns Promise<void>
192
- */
193
- AxeBuilder.prototype.inject = function (frames) {
194
- return __awaiter(this, void 0, void 0, function () {
195
- var _i, frames_1, iframe, _a, _b, _c, _d;
196
- return __generator(this, function (_e) {
197
- switch (_e.label) {
198
- case 0:
199
- _i = 0, frames_1 = frames;
200
- _e.label = 1;
201
- case 1:
202
- if (!(_i < frames_1.length)) return [3 /*break*/, 7];
203
- iframe = frames_1[_i];
204
- _b = (_a = iframe).evaluate;
205
- return [4 /*yield*/, this.script()];
206
- case 2: return [4 /*yield*/, _b.apply(_a, [_e.sent()])];
207
- case 3:
208
- _e.sent();
209
- _d = (_c = iframe).evaluate;
210
- return [4 /*yield*/, this.axeConfigure()];
211
- case 4: return [4 /*yield*/, _d.apply(_c, [_e.sent()])];
212
- case 5:
213
- _e.sent();
214
- _e.label = 6;
215
- case 6:
216
- _i++;
217
- return [3 /*break*/, 1];
218
- case 7: return [2 /*return*/];
219
- }
220
- });
221
- });
222
- };
223
- /**
224
- * Get axe-core source and configurations
225
- * @returns String
226
- */
227
- AxeBuilder.prototype.script = function () {
228
- return this.source;
229
- };
230
- AxeBuilder.prototype.runLegacy = function (context) {
231
- return __awaiter(this, void 0, void 0, function () {
232
- var frames, axeResults;
233
- return __generator(this, function (_a) {
234
- switch (_a.label) {
235
- case 0:
236
- frames = this.page.frames();
237
- return [4 /*yield*/, this.inject(frames)];
238
- case 1:
239
- _a.sent();
240
- return [4 /*yield*/, this.page.evaluate(utils_1.analyzePage, {
241
- context: context,
242
- options: this.option
243
- })];
244
- case 2:
245
- axeResults = _a.sent();
246
- if (axeResults.error) {
247
- throw new Error(axeResults.error);
248
- }
249
- return [2 /*return*/, axeResults.results];
250
- }
251
- });
252
- });
253
- };
254
- /**
255
- * Inject `axe-core` into each frame and run `axe.runPartial`.
256
- * Because we need to inject axe into all frames all at once
257
- * (to avoid any potential problems with the DOM becoming out-of-sync)
258
- * but also need to not process results for any child frames if the parent
259
- * frame throws an error (requirements of the data structure for `axe.finishRun`),
260
- * we have to return a deeply nested array of Promises and then flatten
261
- * the array once all Promises have finished, throwing out any nested Promises
262
- * if the parent Promise is not fulfilled.
263
- * @param frame - playwright frame object
264
- * @param context - axe-core context object
265
- * @returns Promise<AxePartialRunner>
266
- */
267
- AxeBuilder.prototype.runPartialRecursive = function (frame, context) {
268
- return __awaiter(this, void 0, void 0, function () {
269
- var frameContexts, partialPromise, initiator, axePartialRunner, _i, frameContexts_1, _a, frameSelector, frameContext, childResults, iframeHandle, iframeElement, childFrame, _b;
270
- return __generator(this, function (_c) {
271
- switch (_c.label) {
272
- case 0: return [4 /*yield*/, frame.evaluate(browser_1.axeGetFrameContexts, {
273
- context: context
274
- })];
275
- case 1:
276
- frameContexts = _c.sent();
277
- partialPromise = frame.evaluate(browser_1.axeRunPartial, {
278
- context: context,
279
- options: this.option
280
- });
281
- initiator = frame === this.page.mainFrame();
282
- axePartialRunner = new AxePartialRunner_1.default(partialPromise, initiator);
283
- _i = 0, frameContexts_1 = frameContexts;
284
- _c.label = 2;
285
- case 2:
286
- if (!(_i < frameContexts_1.length)) return [3 /*break*/, 12];
287
- _a = frameContexts_1[_i], frameSelector = _a.frameSelector, frameContext = _a.frameContext;
288
- childResults = null;
289
- _c.label = 3;
290
- case 3:
291
- _c.trys.push([3, 9, , 10]);
292
- return [4 /*yield*/, frame.evaluateHandle(browser_1.axeShadowSelect, {
293
- frameSelector: frameSelector
294
- })];
295
- case 4:
296
- iframeHandle = _c.sent();
297
- iframeElement = iframeHandle.asElement();
298
- return [4 /*yield*/, iframeElement.contentFrame()];
299
- case 5:
300
- childFrame = _c.sent();
301
- if (!childFrame) return [3 /*break*/, 8];
302
- return [4 /*yield*/, this.inject([childFrame])];
303
- case 6:
304
- _c.sent();
305
- return [4 /*yield*/, this.runPartialRecursive(childFrame, frameContext)];
306
- case 7:
307
- childResults = _c.sent();
308
- _c.label = 8;
309
- case 8: return [3 /*break*/, 10];
310
- case 9:
311
- _b = _c.sent();
312
- return [3 /*break*/, 10];
313
- case 10:
314
- axePartialRunner.addChildResults(childResults);
315
- _c.label = 11;
316
- case 11:
317
- _i++;
318
- return [3 /*break*/, 2];
319
- case 12: return [2 /*return*/, axePartialRunner];
320
- }
321
- });
322
- });
119
+ }
120
+ };
121
+ var caught = ((f) => {
122
+ return (p) => (p.catch(f), p);
123
+ })(() => {
124
+ });
125
+
126
+ // src/index.ts
127
+ var { source } = import_axe_core.default;
128
+ var AxeBuilder = class {
129
+ page;
130
+ includes;
131
+ excludes;
132
+ option;
133
+ source;
134
+ legacyMode = false;
135
+ errorUrl;
136
+ constructor({ page, axeSource }) {
137
+ this.page = page;
138
+ this.includes = [];
139
+ this.excludes = [];
140
+ this.option = {};
141
+ this.source = axeSource || source;
142
+ this.errorUrl = "https://github.com/dequelabs/axe-core-npm/blob/develop/packages/playwright/error-handling.md";
143
+ }
144
+ /**
145
+ * Selector to include in analysis.
146
+ * This may be called any number of times.
147
+ * @param String selector
148
+ * @returns this
149
+ */
150
+ include(selector) {
151
+ this.includes.push(selector);
152
+ return this;
153
+ }
154
+ /**
155
+ * Selector to exclude in analysis.
156
+ * This may be called any number of times.
157
+ * @param String selector
158
+ * @returns this
159
+ */
160
+ exclude(selector) {
161
+ this.excludes.push(selector);
162
+ return this;
163
+ }
164
+ /**
165
+ * Set options to be passed into axe-core
166
+ * @param RunOptions options
167
+ * @returns AxeBuilder
168
+ */
169
+ options(options) {
170
+ this.option = options;
171
+ return this;
172
+ }
173
+ /**
174
+ * Limit analysis to only the specified rules.
175
+ * Cannot be used with `AxeBuilder#withTags`
176
+ * @param String|Array rules
177
+ * @returns this
178
+ */
179
+ withRules(rules) {
180
+ rules = Array.isArray(rules) ? rules : [rules];
181
+ this.option = this.option || {};
182
+ this.option.runOnly = {
183
+ type: "rule",
184
+ values: rules
323
185
  };
324
- AxeBuilder.prototype.finishRun = function (partialResults) {
325
- return __awaiter(this, void 0, void 0, function () {
326
- function chunkResults(result) {
327
- return __awaiter(this, void 0, void 0, function () {
328
- var chunk;
329
- return __generator(this, function (_a) {
330
- switch (_a.label) {
331
- case 0:
332
- chunk = result.substring(0, sizeLimit);
333
- return [4 /*yield*/, blankPage.evaluate(browser_1.chunkResultString, chunk)];
334
- case 1:
335
- _a.sent();
336
- if (!(result.length > sizeLimit)) return [3 /*break*/, 3];
337
- return [4 /*yield*/, chunkResults(result.substr(sizeLimit))];
338
- case 2: return [2 /*return*/, _a.sent()];
339
- case 3: return [2 /*return*/];
340
- }
341
- });
342
- });
343
- }
344
- var _a, page, options, context, blankPage, _b, _c, sizeLimit, partialString;
345
- var _this = this;
346
- return __generator(this, function (_d) {
347
- switch (_d.label) {
348
- case 0:
349
- _a = this, page = _a.page, options = _a.option;
350
- context = page.context();
351
- return [4 /*yield*/, context.newPage()];
352
- case 1:
353
- blankPage = _d.sent();
354
- (0, assert_1.default)(blankPage, 'Please make sure that you have popup blockers disabled.');
355
- blankPage.evaluate(this.script());
356
- _c = (_b = blankPage).evaluate;
357
- return [4 /*yield*/, this.axeConfigure()];
358
- case 2:
359
- _c.apply(_b, [_d.sent()]);
360
- sizeLimit = 60000000;
361
- partialString = JSON.stringify(partialResults);
362
- return [4 /*yield*/, chunkResults(partialString)];
363
- case 3:
364
- _d.sent();
365
- return [4 /*yield*/, blankPage
366
- .evaluate(browser_1.axeFinishRun, {
367
- options: options
368
- })
369
- .finally(function () { return __awaiter(_this, void 0, void 0, function () {
370
- return __generator(this, function (_a) {
371
- switch (_a.label) {
372
- case 0: return [4 /*yield*/, blankPage.close()];
373
- case 1:
374
- _a.sent();
375
- return [2 /*return*/];
376
- }
377
- });
378
- }); })];
379
- case 4: return [2 /*return*/, _d.sent()];
380
- }
381
- });
382
- });
186
+ return this;
187
+ }
188
+ /**
189
+ * Limit analysis to only specified tags.
190
+ * Cannot be used with `AxeBuilder#withRules`
191
+ * @param String|Array tags
192
+ * @returns this
193
+ */
194
+ withTags(tags) {
195
+ tags = Array.isArray(tags) ? tags : [tags];
196
+ this.option = this.option || {};
197
+ this.option.runOnly = {
198
+ type: "tag",
199
+ values: tags
383
200
  };
384
- AxeBuilder.prototype.axeConfigure = function () {
385
- return __awaiter(this, void 0, void 0, function () {
386
- var hasRunPartial;
387
- return __generator(this, function (_a) {
388
- switch (_a.label) {
389
- case 0: return [4 /*yield*/, this.page.evaluate('typeof window.axe?.runPartial === "function"')];
390
- case 1:
391
- hasRunPartial = _a.sent();
392
- return [2 /*return*/, "\n ;axe.configure({\n ".concat(!this.legacyMode && !hasRunPartial
393
- ? 'allowedOrigins: ["<unsafe_all_origins>"],'
394
- : 'allowedOrigins: ["<same_origin>"],', "\n branding: { application: 'playwright' }\n })\n ")];
395
- }
396
- });
201
+ return this;
202
+ }
203
+ /**
204
+ * Set the list of rules to skip when running an analysis.
205
+ * @param String|Array rules
206
+ * @returns this
207
+ */
208
+ disableRules(rules) {
209
+ rules = Array.isArray(rules) ? rules : [rules];
210
+ this.option = this.option || {};
211
+ this.option.rules = {};
212
+ for (const rule of rules) {
213
+ this.option.rules[rule] = { enabled: false };
214
+ }
215
+ return this;
216
+ }
217
+ /**
218
+ * Use frameMessenger with <same_origin_only>
219
+ *
220
+ * This disables use of axe.runPartial() which is called in each frame, and
221
+ * axe.finishRun() which is called in a blank page. This uses axe.run() instead,
222
+ * but with the restriction that cross-origin frames will not be tested.
223
+ */
224
+ setLegacyMode(legacyMode = true) {
225
+ this.legacyMode = legacyMode;
226
+ return this;
227
+ }
228
+ /**
229
+ * Perform analysis and retrieve results. *Does not chain.*
230
+ * @return Promise<Result | Error>
231
+ */
232
+ async analyze() {
233
+ const context = normalizeContext(this.includes, this.excludes);
234
+ const { page, option: options } = this;
235
+ page.evaluate(this.script());
236
+ const runPartialDefined = await page.evaluate(
237
+ 'typeof window.axe.runPartial === "function"'
238
+ );
239
+ let results;
240
+ if (!runPartialDefined || this.legacyMode) {
241
+ results = await this.runLegacy(context);
242
+ return results;
243
+ }
244
+ const partialResults = await this.runPartialRecursive(
245
+ page.mainFrame(),
246
+ context
247
+ );
248
+ const partials = await partialResults.getPartials();
249
+ try {
250
+ return await this.finishRun(partials);
251
+ } catch (error) {
252
+ throw new Error(
253
+ `${error.message}
254
+ Please check out ${this.errorUrl}`
255
+ );
256
+ }
257
+ }
258
+ /**
259
+ * Injects `axe-core` into all frames.
260
+ * @param Page - playwright page object
261
+ * @returns Promise<void>
262
+ */
263
+ async inject(frames) {
264
+ for (const iframe of frames) {
265
+ await iframe.evaluate(await this.script());
266
+ await iframe.evaluate(await this.axeConfigure());
267
+ }
268
+ }
269
+ /**
270
+ * Get axe-core source and configurations
271
+ * @returns String
272
+ */
273
+ script() {
274
+ return this.source;
275
+ }
276
+ async runLegacy(context) {
277
+ const frames = this.page.frames();
278
+ await this.inject(frames);
279
+ const axeResults = await this.page.evaluate(analyzePage, {
280
+ context,
281
+ options: this.option
282
+ });
283
+ if (axeResults.error) {
284
+ throw new Error(axeResults.error);
285
+ }
286
+ return axeResults.results;
287
+ }
288
+ /**
289
+ * Inject `axe-core` into each frame and run `axe.runPartial`.
290
+ * Because we need to inject axe into all frames all at once
291
+ * (to avoid any potential problems with the DOM becoming out-of-sync)
292
+ * but also need to not process results for any child frames if the parent
293
+ * frame throws an error (requirements of the data structure for `axe.finishRun`),
294
+ * we have to return a deeply nested array of Promises and then flatten
295
+ * the array once all Promises have finished, throwing out any nested Promises
296
+ * if the parent Promise is not fulfilled.
297
+ * @param frame - playwright frame object
298
+ * @param context - axe-core context object
299
+ * @returns Promise<AxePartialRunner>
300
+ */
301
+ async runPartialRecursive(frame, context) {
302
+ const frameContexts = await frame.evaluate(axeGetFrameContexts, {
303
+ context
304
+ });
305
+ const partialPromise = frame.evaluate(axeRunPartial, {
306
+ context,
307
+ options: this.option
308
+ });
309
+ const initiator = frame === this.page.mainFrame();
310
+ const axePartialRunner = new AxePartialRunner(partialPromise, initiator);
311
+ for (const { frameSelector, frameContext } of frameContexts) {
312
+ let childResults = null;
313
+ try {
314
+ const iframeHandle = await frame.evaluateHandle(axeShadowSelect, {
315
+ frameSelector
397
316
  });
398
- };
399
- return AxeBuilder;
400
- }());
401
- exports.default = AxeBuilder;
402
- //# sourceMappingURL=index.js.map
317
+ const iframeElement = iframeHandle.asElement();
318
+ const childFrame = await iframeElement.contentFrame();
319
+ if (childFrame) {
320
+ await this.inject([childFrame]);
321
+ childResults = await this.runPartialRecursive(
322
+ childFrame,
323
+ frameContext
324
+ );
325
+ }
326
+ } catch {
327
+ }
328
+ axePartialRunner.addChildResults(childResults);
329
+ }
330
+ return axePartialRunner;
331
+ }
332
+ async finishRun(partialResults) {
333
+ const { page, option: options } = this;
334
+ const context = page.context();
335
+ const blankPage = await context.newPage();
336
+ (0, import_assert.default)(
337
+ blankPage,
338
+ "Please make sure that you have popup blockers disabled."
339
+ );
340
+ blankPage.evaluate(this.script());
341
+ blankPage.evaluate(await this.axeConfigure());
342
+ const sizeLimit = 6e7;
343
+ const partialString = JSON.stringify(partialResults);
344
+ async function chunkResults(result) {
345
+ const chunk = result.substring(0, sizeLimit);
346
+ await blankPage.evaluate(chunkResultString, chunk);
347
+ if (result.length > sizeLimit) {
348
+ return await chunkResults(result.substr(sizeLimit));
349
+ }
350
+ }
351
+ await chunkResults(partialString);
352
+ return await blankPage.evaluate(axeFinishRun, {
353
+ options
354
+ }).finally(async () => {
355
+ await blankPage.close();
356
+ });
357
+ }
358
+ async axeConfigure() {
359
+ const hasRunPartial = await this.page.evaluate(
360
+ 'typeof window.axe?.runPartial === "function"'
361
+ );
362
+ return `
363
+ ;axe.configure({
364
+ ${!this.legacyMode && !hasRunPartial ? 'allowedOrigins: ["<unsafe_all_origins>"],' : 'allowedOrigins: ["<same_origin>"],'}
365
+ branding: { application: 'playwright' }
366
+ })
367
+ `;
368
+ }
369
+ };