accessibility-checker 3.1.0 → 3.1.4

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.
Files changed (54) hide show
  1. package/README.md +3 -2
  2. package/bin/achecker.d.ts +2 -0
  3. package/bin/achecker.js +293 -177
  4. package/bin/achecker.js.map +1 -0
  5. package/index.d.ts +317 -0
  6. package/index.js +359 -13
  7. package/index.js.map +1 -0
  8. package/lib/ACBrowserManager.d.ts +22 -0
  9. package/lib/ACBrowserManager.js +237 -0
  10. package/lib/ACBrowserManager.js.map +1 -0
  11. package/lib/ACConfigManager.d.ts +6 -0
  12. package/lib/ACConfigManager.js +399 -0
  13. package/lib/ACConfigManager.js.map +1 -0
  14. package/lib/ACConstants.d.ts +17 -0
  15. package/lib/ACConstants.js +12 -38
  16. package/lib/ACConstants.js.map +1 -0
  17. package/lib/ACEngineManager.d.ts +21 -0
  18. package/lib/ACEngineManager.js +220 -0
  19. package/lib/ACEngineManager.js.map +1 -0
  20. package/lib/ACHelper.d.ts +2 -0
  21. package/lib/ACHelper.js +485 -2085
  22. package/lib/ACHelper.js.map +1 -0
  23. package/lib/ACReportManager.d.ts +586 -0
  24. package/lib/ACReportManager.js +1150 -0
  25. package/lib/ACReportManager.js.map +1 -0
  26. package/lib/api/IChecker.d.ts +131 -0
  27. package/lib/api/IChecker.js +11 -0
  28. package/lib/api/IChecker.js.map +1 -0
  29. package/lib/api/IEngine.d.ts +124 -0
  30. package/lib/api/IEngine.js +110 -0
  31. package/lib/api/IEngine.js.map +1 -0
  32. package/lib/api/IMapper.d.ts +37 -0
  33. package/lib/api/IMapper.js +18 -0
  34. package/lib/api/IMapper.js.map +1 -0
  35. package/lib/log/ACMetricsLogger.d.ts +67 -0
  36. package/lib/log/ACMetricsLogger.js +40 -66
  37. package/lib/log/ACMetricsLogger.js.map +1 -0
  38. package/lib/reporters/ACReporterCSV.d.ts +103 -0
  39. package/lib/reporters/ACReporterCSV.js +83 -152
  40. package/lib/reporters/ACReporterCSV.js.map +1 -0
  41. package/lib/reporters/ACReporterHTML.d.ts +114 -0
  42. package/lib/reporters/ACReporterHTML.js +150 -293
  43. package/lib/reporters/ACReporterHTML.js.map +1 -0
  44. package/lib/reporters/ACReporterJSON.d.ts +114 -0
  45. package/lib/reporters/ACReporterJSON.js +95 -249
  46. package/lib/reporters/ACReporterJSON.js.map +1 -0
  47. package/lib/reporters/ReportUtil.d.ts +33 -0
  48. package/lib/reporters/ReportUtil.js +65 -0
  49. package/lib/reporters/ReportUtil.js.map +1 -0
  50. package/lib/reporters/genReport.d.ts +1 -0
  51. package/lib/reporters/genReport.js +13 -11
  52. package/lib/reporters/genReport.js.map +1 -0
  53. package/package.json +4 -3
  54. package/lib/ACConfigLoader.js +0 -358
package/lib/ACHelper.js CHANGED
@@ -1,360 +1,159 @@
1
- /******************************************************************************
2
- Copyright:: 2020- IBM, Inc
3
-
4
- Licensed under the Apache License, Version 2.0 (the "License");
5
- you may not use this file except in compliance with the License.
6
- You may obtain a copy of the License at
7
-
8
- http://www.apache.org/licenses/LICENSE-2.0
9
-
10
- Unless required by applicable law or agreed to in writing, software
11
- distributed under the License is distributed on an "AS IS" BASIS,
12
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- See the License for the specific language governing permissions and
14
- limitations under the License.
15
- *****************************************************************************/
16
-
17
- const request = require("request");
18
- const fs = require("fs");
19
- const path = require("path");
20
- const DeepDiff = require("deep-diff");
21
- const ACMetricsLogger = require('./log/ACMetricsLogger');
22
- const puppeteer = require('puppeteer');
23
- const ACReporterJSON = require("./reporters/ACReporterJSON");
24
- const ACReporterHTML = require("./reporters/ACReporterHTML");
25
- const ACReporterCSV = require("./reporters/ACReporterCSV");
26
-
27
- let aChecker = {
28
- Config: null
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
+ });
29
10
  };
30
- let ace;
31
- !(function () {
32
- let reporterJSON;
33
- let reporterCSV;
34
- let reporterHTML;
35
- // Init the Metrics logger
36
- let metricsLogger;
37
-
38
- let initialize = async () => {
39
- if (aChecker.Config) return;
40
- aChecker.Config = await require("./ACConfigLoader");
41
- if (aChecker.Config.rulePack.includes("localhost")) {
42
- process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
43
- }
44
-
45
- // Only need to create a reporter once
46
- reporterHTML = reporterHTML || new ACReporterHTML(aChecker);
47
- reporterJSON = reporterJSON || new ACReporterJSON(aChecker);
48
- reporterCSV = reporterCSV || new ACReporterCSV(aChecker);
49
-
50
- // Specify if debug information should be printed or not
51
- aChecker.DEBUG = aChecker.Config.DEBUG;
52
-
53
- // Array that contains the list of entries that need to be compared between the actual and baseline objects only.
54
- // Note: This is used by the cleanComplianceObjectBeforeCompare function to filter the report based on this.
55
- aChecker.baselineIssueList = ["ruleId", "xpath"];
56
- metricsLogger = new ACMetricsLogger("accessibility-checker", logger, aChecker.Config.policies.join(","));
57
-
58
- // Initialize the scanSummary object with summary information for accessibility-checker
59
- aChecker.scanSummary = aChecker.initializeSummary();
60
-
61
- // Initialize the global object which will store all the diff results for a scan that is run, using
62
- // actual and expected.
63
- aChecker.diffResults = {};
64
-
65
- // Initialize the global object which will store all the scan results indexed by the label.
66
- aChecker.scanResults = {};
67
-
68
- aChecker.engineLoaded = false;
69
- return aChecker.loadLocalEngine();
70
- }
71
-
72
- let loggerFunction = function (output) {
73
- aChecker.DEBUG && console.log(output);
74
- };
75
-
76
- let loggerCreate = function (type) {
77
- return logger;
78
- };
79
-
80
- let logger = {
81
- debug: loggerFunction,
82
- info: loggerFunction,
83
- error: loggerFunction,
84
- warn: loggerFunction,
85
- create: loggerCreate
86
- };
87
-
88
- aChecker.getConfig = async () => {
89
- await initialize();
90
- return aChecker.Config;
91
- }
92
-
93
- /**
94
- * This function is responsible for initializing the summary object which will store all informations about the
95
- * scans that will occurs while karma is still running and running compliance scans.
96
- *
97
- * @return {Object} scanSummary - return the built scan summary object
98
- *
99
- * @memberOf this
100
- */
101
- aChecker.initializeSummary = function () {
102
- // Variable Decleration
103
- let scanSummary = {};
104
- let reportLevels = aChecker.Config.reportLevels;
105
-
106
- // Initialize counts
107
- scanSummary.counts = {};
108
-
109
- // In the case that report levels are provided then populate the count object in
110
- // scanSummary.counts object with the levels which were provided in reportLevels
111
- // array.
112
- if (reportLevels) {
113
-
114
- // Iterate over the report levels and populate the pageResultsWithCount counts
115
- // object
116
- reportLevels.forEach(function (levels) {
117
- scanSummary.counts[levels] = 0;
118
- });
119
- scanSummary.counts.ignored = 0;
120
- }
121
- // Populate the scanSummary.counts object with all the levels
122
- else {
123
- scanSummary.counts = {
124
- "violation": 0,
125
- "potentialviolation": 0,
126
- "recommendation": 0,
127
- "potentialrecommendation": 0,
128
- "manual": 0,
129
- "pass": 0
130
- };
131
- }
132
-
133
- // Add Start time when this script is loaded into browser
134
- // Start time will be in milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now.
135
- scanSummary.startReport = Date.now();
136
-
137
- // Leave end report as empty for now
138
- scanSummary.endReport = '';
139
-
140
- // Add the toolID, policies, reportLevels, failLevels and labels from the config to the summary
141
- scanSummary.toolID = aChecker.Config.toolID;
142
- scanSummary.policies = aChecker.Config.policies.join(",");
143
- scanSummary.reportLevels = aChecker.Config.reportLevels;
144
- scanSummary.labels = aChecker.Config.label;
145
- scanSummary.failLevels = aChecker.Config.failLevels;
146
-
147
- // Add scanID (UUID) to the scan summary object
148
- scanSummary.scanID = aChecker.Config.scanID;
149
-
150
- // Build the paceScanSummary object which will contains all the items that were scanned and a count
151
- // summary for each of the scanned items.
152
- scanSummary.pageScanSummary = [];
153
-
154
- return scanSummary;
155
- };
156
-
157
- function isPuppeteer(content) {
158
- if (content && content.constructor) {
159
- return content.constructor.toString().includes("Puppeteer");
160
- }
161
- return false;
162
- }
163
-
164
- function isSelenium(content) {
165
- if (content && content.constructor) {
166
- return content.constructor.toString().indexOf("Driver") !== -1 ||
167
- // check required for selenium >= 3.0.1
168
- (content.constructor.name && content.constructor.name.indexOf("Driver") !== -1);
169
- }
170
- return false;
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 };
171
36
  }
172
-
173
- function areValidPolicy(valPolicies, curPol) {
174
- let isValPol = false;
175
- let errorPolicy = "";
176
-
177
- for (let i = 0; i < curPol.length; ++i) {
178
- if (valPolicies.indexOf(curPol[i]) === -1) {
179
- errorPolicy += "" + curPol[i] + ",";
180
- } else {
181
- isValPol = true;
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.getComplianceHelper = void 0;
40
+ var ACBrowserManager_1 = require("./ACBrowserManager");
41
+ var ACConfigManager_1 = require("./ACConfigManager");
42
+ var ACEngineManager_1 = require("./ACEngineManager");
43
+ var ACReportManager_1 = require("./ACReportManager");
44
+ var loggerCreate = function (type) {
45
+ return logger;
46
+ };
47
+ var logger = {
48
+ debug: function () {
49
+ var output = [];
50
+ for (var _i = 0; _i < arguments.length; _i++) {
51
+ output[_i] = arguments[_i];
52
+ }
53
+ Config && Config.DEBUG && console.debug.apply(console, output);
54
+ },
55
+ info: function () {
56
+ var output = [];
57
+ for (var _i = 0; _i < arguments.length; _i++) {
58
+ output[_i] = arguments[_i];
59
+ }
60
+ Config && Config.DEBUG && console.info.apply(console, output);
61
+ },
62
+ error: function () {
63
+ var output = [];
64
+ for (var _i = 0; _i < arguments.length; _i++) {
65
+ output[_i] = arguments[_i];
66
+ }
67
+ Config && Config.DEBUG && console.error.apply(console, output);
68
+ },
69
+ warn: function () {
70
+ var output = [];
71
+ for (var _i = 0; _i < arguments.length; _i++) {
72
+ output[_i] = arguments[_i];
73
+ }
74
+ Config && Config.DEBUG && console.warn.apply(console, output);
75
+ },
76
+ create: loggerCreate
77
+ };
78
+ var Config;
79
+ var checkPolicy = false;
80
+ function initialize() {
81
+ return __awaiter(this, void 0, void 0, function () {
82
+ return __generator(this, function (_a) {
83
+ switch (_a.label) {
84
+ case 0:
85
+ if (Config)
86
+ return [2 /*return*/];
87
+ return [4 /*yield*/, ACConfigManager_1.ACConfigManager.getConfigUnsupported()];
88
+ case 1:
89
+ Config = _a.sent();
90
+ return [4 /*yield*/, ACReportManager_1.ACReportManager.initialize(logger)];
91
+ case 2:
92
+ _a.sent();
93
+ return [2 /*return*/, ACEngineManager_1.ACEngineManager.loadEngineLocal()];
182
94
  }
183
-
184
- }
185
- if (errorPolicy.length > 0) {
186
- errorPolicy = errorPolicy.substr(0, errorPolicy.length - 1);
187
- console.log(`[WARN] InvalidPolicies: Invalid policies "${errorPolicy}". Valid policy ids are: ${valPolicies}`);
188
- }
189
- if (!isValPol) {
190
- console.error(`[ERROR] ValidPoliciesMissing: No valid policy has been provided. Valid policy ids for the specified archive are: ${valPolicies}`);
191
- process.exit(-1);
192
- }
193
- }
194
-
195
- /**
196
- * This function loads the compliance engine.
197
- * @param {Function} callback - Provide callback function which will be executed once the engine is loaded
198
- *
199
- * @return N/A - This function will not return any thing, as it is full async
200
- */
201
- aChecker.loadEngine = async function (content) {
202
- if (isPuppeteer(content)) {
203
- aChecker.DEBUG && console.log("[INFO] aChecker.loadEngine detected Puppeteer");
204
- let page = content;
205
- const docHandle = await page.evaluateHandle('document');
206
- await page.evaluate((document, scriptUrl) => {
207
- try {
208
- if ('undefined' === typeof(ace)) {
209
- return new Promise((resolve, reject) => {
210
- let script = document.createElement('script');
211
- script.setAttribute('type', 'text/javascript');
212
- script.setAttribute('aChecker', 'ACE');
213
- script.setAttribute('src', scriptUrl);
214
- script.addEventListener('load', function () {
215
- resolve();
216
- });
217
- let heads = document.getElementsByTagName('head');
218
- if (heads.length > 0) { heads[0].appendChild(script); }
219
- else if (document.body) { document.body.appendChild(script); }
220
- else { Promise.reject("Invalid document"); }
221
- })
222
- }
223
- } catch (e) {
224
- return Promise.reject(e);
225
- }
226
- }, docHandle, aChecker.Config.rulePack + "/ace.js");
227
- return aChecker.loadLocalEngine();
228
- } else if (isSelenium(content)) {
229
- aChecker.DEBUG && console.log("[INFO] aChecker.loadEngine detected Selenium");
230
- try {
231
- let browser = content;
232
- // Selenium
233
- let scriptStr =
234
- `let cb = arguments[arguments.length - 1];
235
- try {
236
- if ('undefined' === typeof(ace)) {
237
- let script = document.createElement('script');
238
- script.setAttribute('type', 'text/javascript');
239
- script.setAttribute('aChecker', 'ACE');
240
- script.setAttribute('src', '${aChecker.Config.rulePack + "/ace.js"}');
241
- script.addEventListener('load', function() {
242
- cb();
243
95
  });
244
- let heads = document.getElementsByTagName('head');
245
- if (heads.length > 0) { heads[0].appendChild(script); }
246
- else { document.body.appendChild(script); }
247
- } else {
248
- cb();
249
- }
250
- } catch (e) {
251
- cb(e);
96
+ });
252
97
  }
253
- `
254
- let manage = browser.manage();
255
- if (manage.timeouts) {
256
- manage.timeouts().setScriptTimeout(60000);
257
- } else if (manage.setTimeouts) {
258
- manage.setTimeouts({
259
- "script": 60000
260
- })
261
- }
262
-
263
- return browser.executeAsyncScript(scriptStr).then(function (return_success) {
264
- return aChecker.loadLocalEngine();
265
- }).catch(function (err) {
266
- console.log(err);
267
- });
268
- } catch (e) {
269
- console.log(e);
98
+ try {
99
+ // If cucumber is the platform...
100
+ var AfterAll = require('cucumber').AfterAll;
101
+ AfterAll(function (done) {
102
+ var rulePack = Config.ruleServer + "/archives/" + Config.ruleArchive + "/js";
103
+ initialize().then(function () { return ACReportManager_1.ACReportManager.metricsLogger.sendLogsV2(function () { return ACBrowserManager_1.ACBrowserManager.close().then(done); }, rulePack); });
104
+ });
105
+ }
106
+ catch (e) {
107
+ if (typeof (after) !== "undefined") {
108
+ after(function (done) {
109
+ if (Config) {
110
+ var rulePack_1 = Config.ruleServer + "/archives/" + Config.ruleArchive + "/js";
111
+ initialize().then(function () { return ACReportManager_1.ACReportManager.metricsLogger.sendLogsV2(function () { return ACBrowserManager_1.ACBrowserManager.close().then(done); }, rulePack_1); });
270
112
  }
271
- } else {
272
- aChecker.DEBUG && console.log("[INFO] aChecker.loadEngine detected local");
273
- if (ace) {
274
- return Promise.resolve();
275
- } else {
276
- return aChecker.loadLocalEngine();
113
+ else {
114
+ done();
277
115
  }
278
- }
279
- };
280
-
281
- aChecker.loadLocalEngine = function () {
282
- if (ace) {
283
- return Promise.resolve();
284
- }
285
- return new Promise((resolve, reject) => {
286
- request.get(aChecker.Config.rulePack + "/ace-node.js", function (err, data) {
287
- if (!data) {
288
- console.log("Cannot read: " + aChecker.Config.rulePack + "/ace-node.js");
289
- }
290
- data = data.body;
291
- let engineDir = path.join(__dirname, "engine");
292
- if (!fs.existsSync(engineDir)) {
293
- fs.mkdirSync(engineDir);
294
- }
295
- let cacheDir = path.join(engineDir, "cache");
296
- if (!fs.existsSync(cacheDir)) {
297
- fs.mkdirSync(cacheDir);
298
- }
299
- fs.writeFile(path.join(engineDir, "ace-node.js"), data, function (err) {
300
- try {
301
- err && console.log(err);
302
- ace = require("./engine/ace-node");
303
- } catch (e) {
304
- console.log(e);
305
- return reject(e);
116
+ });
117
+ }
118
+ else {
119
+ process.on('beforeExit', function () {
120
+ return __awaiter(this, void 0, void 0, function () {
121
+ var rulePack_2;
122
+ return __generator(this, function (_a) {
123
+ if (Config) {
124
+ rulePack_2 = Config.ruleServer + "/archives/" + Config.ruleArchive + "/js";
125
+ initialize().then(function () { return ACReportManager_1.ACReportManager.metricsLogger.sendLogsV2(null, rulePack_2); });
126
+ ACBrowserManager_1.ACBrowserManager.close();
306
127
  }
307
- resolve();
128
+ return [2 /*return*/];
308
129
  });
309
130
  });
310
131
  });
311
- };
312
-
313
- /**
314
- * This function is responsible performing a scan based on the context that is provided, following are
315
- * the supported context type:
316
- * Single node (HTMLElement)
317
- * Local file path (String)
318
- * URL (String)
319
- * document node
320
- * data stream for html content (String)
321
- *
322
- * Future Items
323
- * Multiple node (Array of HTMLElements) ---> FUTURE
324
- *
325
- * @param {(String|HTMLElement|DocumentNode)} content - Provide the context to scan, which includes the items from above.
326
- * @param {String} label - Provide a label for the scan that is being performed
327
- * @param {Function} callback - Provide callback function which will be executed once the results are extracted.
328
- *
329
- * @return N/A - This function will not return any thing, as it is full asyn so scan will be performed and the call back
330
- * function which was provided will be called which will perform the verification or anything that is needed.
331
- *
332
- * PUBLIC API
333
- *
334
- * @memberOf this
335
- */
336
- aChecker.getCompliance = function (content, label, callback) {
337
- if (callback) {
338
- aChecker.getComplianceHelper(content, label)
339
- .then((result) => {
340
- callback(result.report, result.webdriver);
341
- });
342
- } else {
343
- return aChecker.getComplianceHelper(content, label);
344
- }
345
132
  }
346
-
347
- aChecker.getComplianceHelper = async function (content, label) {
348
- await initialize();
349
- aChecker.DEBUG && console.log("START 'aChecker.getCompliance' function");
350
- if (!content) {
351
- console.error("aChecker: Unable to get compliance of null or undefined object")
352
- return null;
133
+ }
134
+ function areValidPolicy(valPolicies, curPol) {
135
+ var isValPol = false;
136
+ var errorPolicy = "";
137
+ for (var i = 0; i < curPol.length; ++i) {
138
+ if (valPolicies.indexOf(curPol[i]) === -1) {
139
+ errorPolicy += "" + curPol[i] + ",";
353
140
  }
354
-
355
- // Variable Decleration
356
- let URL;
357
-
141
+ else {
142
+ isValPol = true;
143
+ }
144
+ }
145
+ if (errorPolicy.length > 0) {
146
+ errorPolicy = errorPolicy.substr(0, errorPolicy.length - 1);
147
+ console.log("[WARN] InvalidPolicies: Invalid policies \"" + errorPolicy + "\". Valid policy ids are: " + valPolicies);
148
+ }
149
+ if (!isValPol) {
150
+ var errStr = "[ERROR] ValidPoliciesMissing: No valid policy has been provided. Valid policy ids for the specified archive are: " + valPolicies;
151
+ console.error(errStr);
152
+ throw new Error(errStr);
153
+ }
154
+ }
155
+ function getComplianceHelper(content, label) {
156
+ return __awaiter(this, void 0, void 0, function () {
358
157
  // Since we need to handle multiple variation of possible ways to scan items, we need to handle
359
158
  // each one differently as each one requires specific actions/setup.
360
159
  // Handle the following:
@@ -363,1759 +162,360 @@ try {
363
162
  // Local file (String)
364
163
  // URL (String)
365
164
  // document
366
-
367
- async function getParsed(content) {
368
- if (!content) return null;
369
-
370
- // Handle local file and URL's
371
- if (typeof content === "string") {
372
- let isURLRegex = /^(ftp|http|https):\/\//;
373
-
374
- if (isURLRegex.test(content)) {
375
- URL = content;
376
- }
377
-
378
- // Since this is a string, we consider this as either URL or local file
379
- // so build an iframe based on this and get the frame doc and then scan this.
380
- return aChecker.buildIframeAndGetDoc(content);
381
- } else if (isSelenium(content) || isPuppeteer(content)) {
382
-
383
- }
384
- // Handle Array of nodes
385
- else if (content instanceof Array) {
386
- // TODO: Supporting Array of nodes, possible future enhancenment
387
- }
388
- // Handle single node (HTMLElement)
389
- else if (content.nodeType === 1) {
390
- // In the case this is a node, there is nothing special that needs to be done at this time,
391
- // the engine will be able to handle this. Adding this block here as we may need to add some filtering
392
- // of rules or rule sets for this case depending on if a special ruleset needs to be created or not.
393
- content = content;
394
- }
395
- // handle scanning document
396
- else if (content.nodeType === 9) {
397
- // In the case this is a document element, simply send the document object to the engine for now
398
- // we will need to do some filtering to remove any karma related aspects, which requires to do a
399
- // document clone, and then string the karma scripts that are added and then send this document
400
- // to the engine.
401
- // TODO: Investigate best approach to perform filtering
402
- content = content;
403
- }
404
- return content;
405
- }
406
-
407
- let parsed = await getParsed(content);
408
- if (parsed === null) return null;
409
- await aChecker.loadEngine(parsed);
410
- // In the case that the label is null or undefined, throw an error using the karma API
411
- // console.error with the message of the error.
412
- if (label === null || typeof label === "undefined" || label === undefined) {
413
-
414
- // Variable Decleration
415
- let testcaseWhichIsMissingRequiredLabel = null;
416
- let generalErrorMessageLabelNotUnique = "\n[Error] labelNotProvided: Label must be provided when calling aChecker.getCompliance.";
417
-
418
- // Get the caller of the aChecker.getCompliance function which will be the testcase that is calling this function
419
- // This way we can make it the error more descriptive and would help the user identify where the issues is.
420
- // We have to build and throw an Error() object and then using the try/catch to catch this error and then extract the
421
- // stack and parse it to get the 2nd element in the stack which will be the caller of this function which will be the
422
- // testcase which called this function.
423
- try {
424
- // Throw Error() object
425
- throw new Error();
426
- } catch (exception) {
427
- // Extract the stack trace from the error object and parse it to get the single one caller up which will be the 2nd index
428
- testcaseWhichIsMissingRequiredLabel = exception.stack.split("\n")[1];
429
-
430
- // Call the Karma error API, to send message to the Karma server that there was an error on the client side
431
- console.error("Label was not provided at: " + testcaseWhichIsMissingRequiredLabel + generalErrorMessageLabelNotUnique);
432
- }
433
- }
434
-
435
- // Check to make sure that the label that is provided is unique with all the other ones
436
- // that we have gone through.
437
- let labelUnique = aChecker.isLabelUnique(label);
438
-
439
- // In the case that the label is not unique
440
- if (!labelUnique) {
441
- // Variable Decleration dependencies/tools-rules-html/v2/a11y/test/g471/Table-DataNoSummaryARIA.html
442
- let testcaseDoesNotUseUniqueLabel = null;
443
- let generalErrorMessageLabelNotUnique = "\n[Error] labelNotUnique: Label provided to aChecker.getCompliance should be unique across all testcases in a single accessibility-checker session.";
444
-
445
- // Get the caller of the aChecker.getCompliance function which will be the testcase that is calling this function
446
- // This way we can make it the error more descriptive and would help the user identify where the issues is.
447
- // We have to build and throw an Error() object and then using the try/catch to catch this error and then extract the
448
- // stack and parse it to get the 2nd element in the stack which will be the caller of this function which will be the
449
- // testcase which called this function.
450
- try {
451
- // Throw Error() object
452
- throw new Error();
453
- } catch (exception) {
454
- // Extract the stack trace from the error object and parse it to get the single one caller up which will be the 2nd index
455
- testcaseDoesNotUseUniqueLabel = exception.stack.split("\n")[1];
456
-
457
- // Call the Karma error API, to send message to the Karma server that there was an error on the client side
458
- console.error("Label \"" + label + "\" provided at: " + testcaseDoesNotUseUniqueLabel + " is not unique." + generalErrorMessageLabelNotUnique);
459
- }
460
- }
461
-
462
- // Get the Data when the scan is started
463
- // Start time will be in milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now.
464
- let policies = aChecker.Config.policies;
465
- let curPol = null;
466
- if (policies) {
467
- curPol = JSON.parse(JSON.stringify(policies));
468
- }
469
- if (isSelenium(parsed)) {
470
- aChecker.DEBUG && console.log("getComplianceHelper:Selenium");
471
- return await aChecker.getComplianceHelperSelenium(label, parsed, curPol);
472
- } else if (isPuppeteer(parsed)) {
473
- aChecker.DEBUG && console.log("getComplianceHelper:Puppeteer");
474
- return await aChecker.getComplianceHelperPuppeteer(label, parsed, curPol);
475
- } else {
476
- aChecker.DEBUG && console.log("getComplianceHelper:Local");
477
- return await aChecker.getComplianceHelperLocal(label, parsed, curPol);
478
- }
479
- }
480
-
481
- aChecker.getComplianceHelperSelenium = async (label, parsed, curPol) => {
482
- try {
483
- let startScan = Date.now();
484
- // NOTE: Engine should already be loaded
485
- let browser = parsed;
486
- // Selenium
487
- let scriptStr =
488
- `let cb = arguments[arguments.length - 1];
489
- try {
490
- let policies = ${JSON.stringify(aChecker.Config.policies)};
491
-
492
- let checker = new window.ace.Checker();
493
- setTimeout(function() {
494
- checker.check(document, policies).then(function(report) {
495
- for (const result of report.results) {
496
- delete result.node;
497
- }
498
- cb(report);
499
- })
500
- },0)
501
- } catch (e) {
502
- cb(e);
503
- }`
504
- let manage = browser.manage();
505
- if (manage.timeouts) {
506
- manage.timeouts().setScriptTimeout(60000);
507
- } else if (manage.setTimeouts) {
508
- manage.setTimeouts({
509
- "script": 60000
510
- })
511
- }
512
-
513
- let report = await browser.executeAsyncScript(scriptStr);
514
- const getPolicies = "return new window.ace.Checker().rulesetIds;";
515
- if (curPol != null && !aChecker.Config.checkPolicy) {
516
- aChecker.Config.checkPolicy = true;
517
- const valPolicies = await browser.executeScript(getPolicies);
518
- areValidPolicy(valPolicies, curPol);
519
- }
520
-
521
- // If there is something to report...
522
- if (report.results) {
523
- // Add URL to the result object
524
- const url = await browser.getCurrentUrl();
525
- report.summary = report.summary || {}
526
- report.summary.URL = url;
527
- report.counts = {}
528
- let origReport = JSON.parse(JSON.stringify(report));
529
- origReport = aChecker.buildReport(origReport, url, label, startScan);
530
-
531
- // Filter the violations based on the reporLevels
532
- report = aChecker.filterViolations(report);
533
-
534
- // Add the count object, to data a recount after the filtering of violations is done.
535
- report = aChecker.updateViolationCount(report);
536
-
537
- // Add the violation count to global summary object
538
- aChecker.addToSummaryCount(report.counts);
539
-
540
- // Build the report object for this scan, to follow a specific format. Refer to the
541
- // function prolog for more information on the object creation.
542
- report = aChecker.buildReport(report, url, label, startScan);
543
-
544
- // Add the scan results to global karma result object which can be accessed when users testcase
545
- // finishes, user can also access it to alter it for any reason.
546
- aChecker.addResultsToGlobal(report);
547
-
548
- // Need to call a karma API to send the results of a single scan to the accessibility-checker reporter so that they can be
549
- // saved to a file by the server side reporter.
550
- aChecker.sendResultsToReporter(origReport, report, "Selenium");
551
-
552
- if (aChecker.Config.captureScreenshots && browser.takeScreenshot) {
553
- const image = await browser.takeScreenshot();
554
- let screenshotResult = {
555
- image: image,
556
- label: label,
557
- scanID: report.scanID
558
- };
559
-
560
- aChecker.sendScreenShotToReporter(screenshotResult);
561
- }
562
- }
563
- return {
564
- "report": report,
565
- "webdriver": parsed
566
- }
567
- } catch (err) {
568
- console.error(err);
569
- return Promise.reject(err);
570
- };
571
- }
572
-
573
- aChecker.getComplianceHelperPuppeteer = async (label, parsed, curPol) => {
574
- try {
575
- const startScan = Date.now();
576
- // NOTE: Engine should already be loaded
577
- const page = parsed;
578
- const winHandle = await page.evaluateHandle("window");
579
- let report = await page.evaluate((window, policies) => {
580
- let checker = new window.ace.Checker();
581
- return new Promise((resolve, reject) => {
582
- setTimeout(function () {
583
- checker.check(document, policies).then(function (report) {
584
- for (const result of report.results) {
585
- delete result.node;
586
- }
587
- resolve(report);
588
- })
589
- }, 0)
590
- })
591
- }, winHandle, aChecker.Config.policies);
592
- if (curPol != null && !aChecker.Config.checkPolicy) {
593
- const valPolicies = await page.evaluate("new window.ace.Checker().rulesetIds");
594
- aChecker.Config.checkPolicy = true;
595
- areValidPolicy(valPolicies, curPol);
596
- }
597
-
598
- // If there is something to report...
599
- if (report.results) {
600
- let url = await page.evaluate("document.location.href");
601
- report.summary = report.summary || {}
602
- report.summary.URL = url;
603
- report.counts = {}
604
-
605
- let origReport = JSON.parse(JSON.stringify(report));
606
- origReport = aChecker.buildReport(origReport, url, label, startScan);
607
-
608
- // Filter the violations based on the reporLevels
609
- report = aChecker.filterViolations(report);
610
-
611
- // Add the count object, to data a recount after the filtering of violations is done.
612
- report = aChecker.updateViolationCount(report);
613
-
614
- // Add the violation count to global summary object
615
- aChecker.addToSummaryCount(report.counts);
616
-
617
- // Build the report object for this scan, to follow a specific format. Refer to the
618
- // function prolog for more information on the object creation.
619
- report = aChecker.buildReport(report, url, label, startScan);
620
-
621
- // Add the scan results to global karma result object which can be accessed when users testcase
622
- // finishes, user can also access it to alter it for any reason.
623
- aChecker.addResultsToGlobal(report);
624
-
625
- // Need to call a karma API to send the results of a single scan to the accessibility-checker reporter so that they can be
626
- // saved to a file by the server side reporter.
627
- aChecker.sendResultsToReporter(origReport, report, "Puppeteer");
628
-
629
- if (aChecker.Config.captureScreenshots) {
630
- let image = await page.screenshot({
631
- fullPage: true,
632
- encoding: "base64"
633
- });
634
- let screenshotResult = {
635
- image: image,
636
- label: label,
637
- scanID: report.scanID
638
- };
639
-
640
- aChecker.sendScreenShotToReporter(screenshotResult);
641
- }
642
- }
643
- page.aceBusy = false;
644
-
645
- return {
646
- "report": report,
647
- "puppeteer": parsed
648
- };
649
- } catch (err) {
650
- console.error(err);
651
- return Promise.reject(err);
652
- };
653
- }
654
-
655
- aChecker.getComplianceHelperLocal = async (label, parsed, curPol) => {
656
- try {
657
- let startScan = Date.now();
658
- let checker = new ace.Checker();
659
- let report = await checker.check(parsed, aChecker.Config.policies)
660
- .then(function (report) {
661
- for (const result of report.results) {
662
- delete result.node;
165
+ function getParsed(content) {
166
+ return __awaiter(this, void 0, void 0, function () {
167
+ var isURLRegex;
168
+ return __generator(this, function (_a) {
169
+ if (!content)
170
+ return [2 /*return*/, null];
171
+ // Handle local file and URL's
172
+ if (typeof content === "string") {
173
+ isURLRegex = /^(ftp|http|https):\/\//;
174
+ if (isURLRegex.test(content)) {
175
+ URL = content;
176
+ }
177
+ // Since this is a string, we consider this as either URL or local file
178
+ // so build an iframe based on this and get the frame doc and then scan this.
179
+ return [2 /*return*/, ACBrowserManager_1.ACBrowserManager.buildIframeAndGetDoc(content)];
663
180
  }
664
- return report;
665
- })
666
-
667
- if (curPol != null && !aChecker.Config.checkPolicy) {
668
- let valPolicies = new ace.Checker().rulesetIds;
669
- aChecker.Config.checkPolicy = true;
670
- areValidPolicy(valPolicies, curPol);
671
- }
672
-
673
- // If there is something to report...
674
- if (report.results) {
675
- let url = parsed.location && parsed.location.href;
676
- report.summary = report.summary || {}
677
- report.summary.URL = url;
678
- report.counts = {}
679
-
680
- let origReport = JSON.parse(JSON.stringify(report));
681
- origReport = aChecker.buildReport(origReport, url, label, startScan);
682
-
683
- // Filter the violations based on the reporLevels
684
- report = aChecker.filterViolations(report);
685
-
686
- // Add the count object, to data a recount after the filtering of violations is done.
687
- report = aChecker.updateViolationCount(report);
688
-
689
- // Add the violation count to global summary object
690
- aChecker.addToSummaryCount(report.counts);
691
-
692
- // Build the report object for this scan, to follow a specific format. Refer to the
693
- // function prolog for more information on the object creation.
694
- report = aChecker.buildReport(report, URL, label, startScan);
695
-
696
- // Add the scan results to global karma result object which can be accessed when users testcase
697
- // finishes, user can also access it to alter it for any reason.
698
- aChecker.addResultsToGlobal(report);
699
-
700
- // Need to call a karma API to send the results of a single scan to the accessibility-checker reporter so that they can be
701
- // saved to a file by the server side reporter.
702
- aChecker.sendResultsToReporter(origReport, report, "Native");
703
- }
704
-
705
- return {
706
- "report": report
707
- };
708
- } catch (err) {
709
- console.error(err);
710
- return Promise.reject(err);
711
- };
712
- }
713
-
714
- /**
715
- * This function is responsible for checking if the provided label is unique or not.
716
- *
717
- * @param {String} label - Provide the label which should be checked if it exists or not
718
- *
719
- * @return {boolean} labelExists - return false if the label is not unique, otherwise return true
720
- *
721
- * PRIVATE METHOD
722
- *
723
- * @memberOf this
724
- */
725
- aChecker.isLabelUnique = function (label) {
726
- aChecker.DEBUG && console.log("START 'aChecker.isLabelUnique' function");
727
-
728
- // Variable Decleration
729
- let labelExists = false;
730
-
731
- aChecker.DEBUG && console.log("Checking if label: " + label + " is unique.");
732
-
733
- // Check if the label that is provided was already used or not, by simply calling the some API on the array
734
- // and passing it a callback function which checks if the label exists in the global paceScanSummary object.
735
- labelExists = aChecker.scanSummary.pageScanSummary.some(function (scanSummary) {
736
- return scanSummary.label === label;
737
- });
738
-
739
- aChecker.DEBUG && console.log("END 'aChecker.isLabelUnique' function");
740
-
741
- return !labelExists;
742
- };
743
-
744
- /**
745
- * This function is responsible for sending the scan results to the karma server accessibility-checker reporter. The
746
- * accessibility-checker reporter is responsible for writing the results to a file. The reporter will also keep track of
747
- * the summary results, on the server side.
748
- *
749
- * @param {Object} results - Provide the full results object which is to be reported/saved to file.
750
- * refer to return in function "aChecker.buildReport" prolog
751
- *
752
- * @return N/A
753
- *
754
- * PRIVATE METHOD
755
- *
756
- * @memberOf this
757
- */
758
- aChecker.sendResultsToReporter = function (unFilteredResults, results, profile) {
759
- aChecker.DEBUG && console.log("sendResultsToReporter:", aChecker.Config.outputFormat);
760
- if (aChecker.Config.outputFormat.indexOf("json") != -1) {
761
- reporterJSON.report(results);
762
- }
763
- if (aChecker.Config.outputFormat.includes("csv")) {
764
- reporterCSV.report(results);
765
- }
766
- if (aChecker.Config.outputFormat.indexOf("html") != -1) {
767
- reporterHTML.report(unFilteredResults);
768
- }
769
- // Only perform the profiling if profiling was not disabled on purpose
770
- if (!aChecker.Config.label || aChecker.Config.label.indexOf("IBMa-Node-TeSt") === -1) {
771
- // Meter the usage here
772
- metricsLogger.profileV2(results.summary.scanTime, profile);
773
- }
774
- };
775
-
776
- aChecker.sendScreenShotToReporter = function (screenshotResult) {
777
- };
778
-
779
- try {
780
- // If cucumber is the platform...
781
- let {AfterAll} = require('cucumber');
782
- AfterAll(function (done) {
783
- initialize().then(() => metricsLogger.sendLogsV2(() => aChecker.close().then(done), aChecker.Config.rulePack));
784
- });
785
- } catch (e) {
786
- if (typeof (after) !== "undefined") {
787
- after(function (done) {
788
- initialize().then(() => metricsLogger.sendLogsV2(() => aChecker.close().then(done), aChecker.Config.rulePack));
789
- });
790
- } else {
791
- process.on('beforeExit', async function () {
792
- initialize().then(() => metricsLogger.sendLogsV2(null, aChecker.Config.rulePack));
793
- aChecker.close();
794
- });
795
- }
796
- }
797
-
798
- /**
799
- * This function is responsible for building the results object in a specific format which will be provided back to
800
- * the user to do any thing they want to do with it. (compare, print it, save to db, etc...)
801
- *
802
- * Note: This function converts it to match with the following format outlined at:
803
- * https://github.com/IBMa/equal-access/tree/master/karma-accessibility-checker
804
- *
805
- * @param {Object} results - The results object which we need to build the report based on, following is the format the
806
- * object needs to follow:
807
- * {
808
- * "report": {
809
- * "numChecked": 227,
810
- * "numTrigger": 1,
811
- * "ruleTime": 5,
812
- * "totalTime": 8,
813
- * "issues": [
814
- * {
815
- * "severityCode": "eISHigh",
816
- * "messageCode": "rpt.g377.elemUniqueId",
817
- * "ruleId": "377",
818
- * "help": "idhi_accessibility_check_g377.html",
819
- * "msgArgs": [
820
- * "div",
821
- * "firstDiv"
822
- * ],
823
- * "xpath": "/html[1]/body[1]/div[2]/div[2]",
824
- * "snippet": "<div id=\"firstDiv\">",
825
- * "bounds": {
826
- * "left": 10,
827
- * "top": 181,
828
- * "height": 0,
829
- * "width": 1249
830
- * },
831
- * "level": "violation"
832
- * }
833
- * ],
834
- * "docTitle": "Helo World"
835
- * },
836
- * "counts": {
837
- * "violation": 1,
838
- * "potentialviolation": 0,
839
- * "recommendation": 0,
840
- * "potentialrecommendation": 0,
841
- * "manual": 0
842
- * },
843
- * "issueMessages": {
844
- * "messages": {
845
- * "rpt.g377.elemUniqueId": "The {0} element has the id \"{1}\" that is either empty or already in use."
846
- * },
847
- * "lang": "en-us"
848
- * }
849
- * }
850
- *
851
- * @param {String} URL - The URL which the report is being built for
852
- * @param {String} label - A label to identify what this report is going to be for, in the case not using URL or local files.
853
- * @param {String} startScan - The start time of the scan.
854
- *
855
- * @return {Object} results - return the formatted results based in the following format:
856
- *
857
- * {
858
- * "scanID": "ef3aec68-f073-4f9c-b372-421ae00bd55d",
859
- * "toolID": "karma-ibma-v1.0.0",
860
- * "summary": {
861
- * "counts": {
862
- * "violation": 5,
863
- * "potentialviolation": 0,
864
- * "recommendation": 5,
865
- * "potentialrecommendation": 0,
866
- * "manual": 1
867
- * },
868
- * "scanTime": 80,
869
- * "policies": [
870
- * "CI162_5_2_DCP080115"
871
- * ],
872
- * "reportLevels": [
873
- * "violation",
874
- * "potentialviolation",
875
- * "recommendation",
876
- * "potentialrecommendation",
877
- * "manual"
878
- * ],
879
- * "startScan": "2016-06-06T00:52:41.603Z"
880
- * },
881
- * "URL": "",
882
- * "label": "unitTestContent",
883
- * "screenshot": "<placeholder>",
884
- * "issueMessages": {
885
- * "messages": {
886
- * "rpt.g377.elemUniqueId": "The {0} element has the id \"{1}\" that is either empty or already in use."
887
- * },
888
- * "lang": "en-us"
889
- * },
890
- * "reports": [
891
- * {
892
- * "frameIdx": "0",
893
- * "frameTitle": "Frame 0",
894
- * "issues": [
895
- * {
896
- * "severity": "Low",
897
- * "message": "If style sheets are ignored or unsupported, ensure that pages are still readable and usable.",
898
- * "messageCode": "rpt.g1.styleTrigger",
899
- * "ruleId": "1",
900
- * "help": "idhi_accessibility_check_g1.html",
901
- * "msgArgs": [],
902
- * "bounds": {
903
- * "left": 0,
904
- * "top": 0,
905
- * "height": 0,
906
- * "width": 0
907
- * },
908
- * "level": "manual",
909
- * "xpath": "/html[1]/head[1]/style[1]",
910
- * "snippet": "<style type=\"text/css\">"
911
- * }
912
- * ....
913
- * ]
914
- * },
915
- * {
916
- * "frameIdx": "1",
917
- * "frameTitle": "Frame 1",
918
- * "issues": [
919
- * {
920
- * "severity": "High",
921
- * "message": "The table element with WAI-ARIA presentation role has structural element(s) and/or attribute(s) td.",
922
- * "messageCode": "rpt.g471.tableStructure",
923
- * "ruleId": "471",
924
- * "help": "idhi_accessibility_check_g471.html",
925
- * "msgArgs": [
926
- * "table",
927
- * "td"
928
- * ],
929
- * "bounds": {
930
- * "left": 10,
931
- * "top": 990,
932
- * "height": 219,
933
- * "width": 335
934
- * },
935
- * "level": "violation",
936
- * "xpath": "/html[1]/body[1]/div[2]/table[3]",
937
- * "snippet": "<table id=\"layout_table3\" role=\"presentation\">"
938
- * }
939
- * ....
940
- * ]
941
- * }
942
- * ]
943
- * }
944
- *
945
- * PRIVATE METHOD
946
- *
947
- * @memberOf this
948
- */
949
- aChecker.buildReport = function (report, URL, label, startScan) {
950
- // Build the scan summary object which will be added to the build report
951
- // Note: This summary is only for this single scan.
952
- report.summary = {
953
- counts: report.counts,
954
- scanTime: report.totalTime,
955
- ruleArchive: aChecker.Config.ruleArchive,
956
- policies: aChecker.Config.policies,
957
- reportLevels: aChecker.Config.reportLevels,
958
- startScan: startScan
959
- };
960
-
961
- // Add scanID (UUID) to the individual pages
962
- report.scanID = aChecker.Config.scanID;
963
-
964
- // Add toolID to the individual pages
965
- report.toolID = aChecker.Config.toolID;
966
-
967
- // Add the URL to the object it it is defined
968
- if (URL !== null && typeof URL !== "undefined") {
969
- report.summary.URL = URL;
970
- }
971
-
972
- // Add the label to the result object, label should always be
973
- // defined no matter what as it is required to be provided by the user.
974
- report.label = label;
975
-
976
- // Add the screenshot base64 object to the results object
977
- // TODO: Find a way to actually extract the screenshot, since karma
978
- // allows the use of any browesr, some browser do not allow taking screenshot
979
- // so would have to alalyze which browser allow it and take it for only those.
980
- // PhantonJS, any selenium drived browser.
981
- //results.screenshot = "<placeholder>";
982
-
983
- // Clean up the results object
984
- delete report.counts;
985
- delete report.ruleTime;
986
- delete report.totalTime;
987
-
988
- if (aChecker.Config.disableIgnore === undefined || aChecker.Config.disableIgnore == false || aChecker.Config.disableIgnore === null) {
989
- // set ignore:true for previously seen violations
990
- // retrieve baseline
991
- let baselineReport = aChecker.getBaseline(label);
992
-
993
- // set ignore:true for previously seen violations and set ignore to false if no ignore fields exist yet
994
- if (baselineReport) {
995
- report = aChecker.ignoreExtraBaselineViolations(report, baselineReport);
996
- }
997
- else { //add ignored field
998
- report.summary.counts.ignored = 0;
999
- }
1000
- }
1001
-
1002
- let lvlIdx = {
1003
- "violation": 1,
1004
- "potentialviolation": 2,
1005
- "recommendation": 3,
1006
- "potentialrecommendation": 4,
1007
- "manual": 5,
1008
- "pass": 6
1009
- };
1010
-
1011
- report.results.sort(function (a, b) {
1012
- let aLvl = lvlIdx[a.level];
1013
- let bLvl = lvlIdx[b.level];
1014
- if (!aLvl) aLvl = 7;
1015
- if (!bLvl) bLvl = 7;
1016
- return aLvl != bLvl && aLvl - bLvl ||
1017
- b.ruleId != a.ruleId && b.ruleId - a.ruleId ||
1018
- b.path.dom - a.path.dom;
1019
- });
1020
-
1021
- return report;
1022
- };
1023
-
1024
- /**
1025
- * This function is responsible for indexing the results into global spaces based on label.
1026
- *
1027
- * @param {Object} results - Results object which will be provided to the user/wroten to the file.
1028
- * Refer to aChecker.buildReport function's return to figure out what the object
1029
- * will look like.
1030
- *
1031
- * @return - N/A - Global object is updated with the results
1032
- *
1033
- * PRIVATE METHOD
1034
- *
1035
- * @memberOf this
1036
- */
1037
- aChecker.addResultsToGlobal = function (results) {
1038
-
1039
- // Build the single page summary object to follow the following format:
1040
- // "label": "dependencies/tools-rules-html/v2/a11y/test/g471/Table-DataNoSummaryARIA.html",
1041
- // "counts": {
1042
- // "violation": 1,
1043
- // "potentialviolation": 0,
1044
- // "recommendation": 0,
1045
- // "potentialrecommendation": 0,
1046
- // "manual": 0
1047
- // }
1048
- let pageSummaryObject = {
1049
- label: results.label,
1050
- counts: results.summary.counts
1051
- };
1052
-
1053
- // Add the summary count for this scan to the pageScanSummary object which is in the global space
1054
- // Index this by the label.
1055
- aChecker.scanSummary.pageScanSummary.push(pageSummaryObject);
1056
-
1057
- // Add the scan results to global space
1058
- aChecker.scanResults[results.label] = results;
1059
- };
1060
-
1061
- let browserP;
1062
-
1063
- aChecker.getBrowserChrome = async (force) => {
1064
- if (force || !browserP) {
1065
- return browserP = puppeteer.launch({headless: aChecker.Config.headless, ignoreHTTPSErrors: aChecker.Config.ignoreHTTPSErrors || false});
1066
- } else {
1067
- return browserP;
1068
- }
1069
- }
1070
-
1071
- aChecker.close = async () => {
1072
- if (browserP) {
1073
- let browser = await browserP;
1074
- await browser.close();
1075
- browserP = null;
1076
- pages = [];
1077
- }
1078
- }
1079
-
1080
- /**
1081
- * This function is responsible for building an iframe object with the provided URL or local file.
1082
- *
1083
- * @param {String} URLorLocalFile - Provide a URL or local file to scan.
1084
- *
1085
- * @return {Object} content - return an object which contains the iframeDoc and also the URL or
1086
- * local file name.
1087
- *
1088
- * PRIVATE METHOD
1089
- *
1090
- * @memberOf this
1091
- */
1092
- let numInits = 0;
1093
- let pages = [];
1094
- aChecker.buildIframeAndGetDoc = async function (URLorLocalFileorContent) {
1095
- const MAX_TABS = aChecker.Config.maxTabs;
1096
- const browser = await aChecker.getBrowserChrome();
1097
-
1098
- // Clear out any pages that are already closed
1099
- pages = pages.map((page) => !page.isClosed() ? page : null);
1100
-
1101
- // If there's an existing, ready page, use it
1102
- let availPage;
1103
- for (const page of pages) {
1104
- if (!availPage) {
1105
- if (!page.aceBusy) {
1106
- availPage = page;
1107
- page.aceBusy = true;
1108
- }
1109
- }
1110
- }
1111
-
1112
- if (!availPage) {
1113
- // All pages are busy. Should we create a new one?
1114
- if (pages.length+numInits >= MAX_TABS) {
1115
- // Too many pages, restart
1116
- return new Promise((resolve, reject) => {
1117
- setTimeout(async () => {
1118
- resolve(await aChecker.buildIframeAndGetDoc(URLorLocalFileorContent));
1119
- }, 500);
1120
- });
1121
- } else {
1122
- // Let's create a new page
1123
- ++numInits;
1124
-
1125
- let newPage = await browser.newPage();
1126
- newPage.on('console', msg => {
1127
- for (let i = 0; i < msg.args.length; ++i)
1128
- console.log(`${i}: ${msg.args[i]}`);
181
+ else if (ACEngineManager_1.ACEngineManager.isSelenium(content) || ACEngineManager_1.ACEngineManager.isPuppeteer(content) || ACEngineManager_1.ACEngineManager.isPlaywright(content)) {
182
+ }
183
+ // Handle Array of nodes
184
+ else if (content instanceof Array) {
185
+ // TODO: Supporting Array of nodes, possible future enhancenment
186
+ }
187
+ // Handle single node (HTMLElement)
188
+ else if (content.nodeType === 1) {
189
+ // In the case this is a node, there is nothing special that needs to be done at this time,
190
+ // the engine will be able to handle this. Adding this block here as we may need to add some filtering
191
+ // of rules or rule sets for this case depending on if a special ruleset needs to be created or not.
192
+ content = content;
193
+ }
194
+ // handle scanning document
195
+ else if (content.nodeType === 9) {
196
+ // In the case this is a document element, simply send the document object to the engine for now
197
+ // we will need to do some filtering to remove any karma related aspects, which requires to do a
198
+ // document clone, and then string the karma scripts that are added and then send this document
199
+ // to the engine.
200
+ // TODO: Investigate best approach to perform filtering
201
+ content = content;
202
+ }
203
+ return [2 /*return*/, content];
1129
204
  });
1130
- newPage.aceBusy = true;
1131
- availPage = newPage;
1132
- pages.push(newPage);
1133
- --numInits;
1134
- }
1135
- }
1136
-
1137
- let err = null,
1138
- retVal = null;
1139
- async function nav() {
1140
- try {
1141
- if (URLorLocalFileorContent.toLowerCase().includes("<html")) {
1142
- // await page.goto(`data:text/html,encodeURIComponent(${URLorLocalFileorContent})`, { waitUntil: 'networkidle0' });
1143
- let urlStr = "data:text/html;charset=utf-8," + encodeURIComponent(URLorLocalFileorContent);
1144
- await availPage.goto(urlStr);
1145
- } else {
1146
- await availPage.goto(URLorLocalFileorContent);
1147
- }
1148
- } catch (e) {
1149
- err = `${e.message} ${URLorLocalFileorContent}`;
1150
- console.error(err);
1151
- return null;
1152
- }
1153
- return availPage;
1154
- }
1155
- try {
1156
- retVal = await nav();
1157
- } catch (e) {
1158
- }
1159
- if (!retVal) {
1160
- // Page bad or unable to navigate, start over
1161
- page.close();
1162
- return new Promise((resolve, reject) => {
1163
- setTimeout(async () => {
1164
- resolve(await aChecker.buildIframeAndGetDoc(URLorLocalFileorContent));
1165
- }, 0);
1166
205
  });
1167
206
  }
1168
- if (retVal === null) {
1169
- console.log("[Internal Error:load content]", err);
1170
- }
1171
-
1172
- return retVal;
1173
- };
1174
-
1175
- /**
1176
- * This function is responsible for filtering the violations so that, only the violations levels that
1177
- * are provided in reportLevels are presented in the report.
1178
- *
1179
- * TODO: Possibly we can add this to the engine, so that the results are not provided by the engine
1180
- * when user has provided the reportLevels object.
1181
- *
1182
- * @param {Object} results - Provide the violation results, which follow the following format:
1183
- * {
1184
- * "report": {
1185
- * "numChecked": 227,
1186
- * "numTrigger": 1,
1187
- * "ruleTime": 5,
1188
- * "totalTime": 8,
1189
- * "issues": [
1190
- * {
1191
- * "severityCode": "eISHigh",
1192
- * "messageCode": "rpt.g377.elemUniqueId",
1193
- * "ruleId": "377",
1194
- * "help": "idhi_accessibility_check_g377.html",
1195
- * "msgArgs": [
1196
- * "div",
1197
- * "firstDiv"
1198
- * ],
1199
- * "xpath": "/html[1]/body[1]/div[2]/div[2]",
1200
- * "snippet": "<div id=\"firstDiv\">",
1201
- * "bounds": {
1202
- * "left": 10,
1203
- * "top": 181,
1204
- * "height": 0,
1205
- * "width": 1249
1206
- * },
1207
- * "level": "violation"
1208
- * }
1209
- * ],
1210
- * "docTitle": "Helo World"
1211
- * },
1212
- * "counts": {
1213
- * "level.violation": 1,
1214
- * "level.potentialviolation": 0,
1215
- * "level.recommendation": 0,
1216
- * "level.potentialrecommendation": 0,
1217
- * "level.manual": 0
1218
- * },
1219
- * "issueMessages": {
1220
- * "messages": {
1221
- * "rpt.g377.elemUniqueId": "The {0} element has the id \"{1}\" that is either empty or already in use."
1222
- * },
1223
- * "lang": "en-us"
1224
- * }
1225
- * }
1226
- *
1227
- * @return {Object} results - return results object which only contains the violation that were requested,
1228
- * follows the following format:
1229
- * {
1230
- * "report": {
1231
- * "numChecked": 227,
1232
- * "numTrigger": 1,
1233
- * "ruleTime": 5,
1234
- * "totalTime": 8,
1235
- * "issues": [
1236
- * {
1237
- * "severityCode": "eISHigh",
1238
- * "messageCode": "rpt.g377.elemUniqueId",
1239
- * "ruleId": "377",
1240
- * "help": "idhi_accessibility_check_g377.html",
1241
- * "msgArgs": [
1242
- * "div",
1243
- * "firstDiv"
1244
- * ],
1245
- * "xpath": "/html[1]/body[1]/div[2]/div[2]",
1246
- * "snippet": "<div id=\"firstDiv\">",
1247
- * "bounds": {
1248
- * "left": 10,
1249
- * "top": 181,
1250
- * "height": 0,
1251
- * "width": 1249
1252
- * },
1253
- * "level": "violation"
1254
- * }
1255
- * ],
1256
- * "docTitle": "Helo World"
1257
- * },
1258
- * "counts": {
1259
- * "level.violation": 1,
1260
- * "level.potentialviolation": 0,
1261
- * "level.recommendation": 0,
1262
- * "level.potentialrecommendation": 0,
1263
- * "level.manual": 0
1264
- * },
1265
- * "issueMessages": {
1266
- * "messages": {
1267
- * "rpt.g377.elemUniqueId": "The {0} element has the id \"{1}\" that is either empty or already in use."
1268
- * },
1269
- * "lang": "en-us"
1270
- * }
1271
- * }
1272
- *
1273
- * The return object is pretty much filtered failures (results.report.fail), wrapped around another object with extra frameIdx value.
1274
- *
1275
- * PRIVATE METHOD
1276
- *
1277
- * @memberOf this
1278
- */
1279
- aChecker.filterViolations = function (report) {
1280
-
1281
- // Variable Decleration
1282
- let reportLevels = aChecker.Config.reportLevels;
1283
- let pageResults = report.results;
1284
- for (let iDis = 0; aChecker.Config.disable && iDis < aChecker.Config.disable.length; ++iDis) {
1285
- aChecker.Config.disable[iDis] = "" + aChecker.Config.disable[iDis];
1286
- }
1287
- // Loop over all the violations and filter them, if the violation level does not match with, what user has
1288
- // requested to be reported. Also handle hidden at this point right now.
1289
- // TODO: Posible to filter the results directly in the engine, to avoid the need to do all this in each of the tools.
1290
- for (let i = 0; i < pageResults.length; ++i) {
1291
-
1292
- // Set the default ignore value to false if disableIgnore field in config file is not true
1293
- if (aChecker.Config.disableIgnore === undefined || aChecker.Config.disableIgnore == false || aChecker.Config.disableIgnore === null){
1294
- pageResults[i].ignored = false;
1295
- }
1296
- if (aChecker.Config.disable && aChecker.Config.disable.indexOf(pageResults[i].ruleId) !== -1) {
1297
- pageResults.splice(i--, 1);
1298
- continue;
1299
- }
1300
- // Remove violation which are not in the reportLevels
1301
- if (reportLevels) {
1302
- // Fetch the level from the results
1303
- let reportLevel = pageResults[i].value;
1304
- if (reportLevel[1] === "PASS") {
1305
- reportLevel = "pass";
1306
- } else if ((reportLevel[0] === "VIOLATION" || reportLevel[0] === "RECOMMENDATION") && reportLevel[1] === "MANUAL") {
1307
- reportLevel = "manual";
1308
- } else if (reportLevel[0] === "VIOLATION") {
1309
- if (reportLevel[1] === "FAIL") {
1310
- reportLevel = "violation";
1311
- } else if (reportLevel[1] === "POTENTIAL") {
1312
- reportLevel = "potentialviolation";
207
+ var URL, parsed, testcaseWhichIsMissingRequiredLabel, generalErrorMessageLabelNotUnique, labelUnique, testcaseDoesNotUseUniqueLabel, generalErrorMessageLabelNotUnique, policies, curPol;
208
+ return __generator(this, function (_a) {
209
+ switch (_a.label) {
210
+ case 0: return [4 /*yield*/, initialize()];
211
+ case 1:
212
+ _a.sent();
213
+ Config.DEBUG && console.log("START 'aChecker.getCompliance' function");
214
+ if (!content) {
215
+ console.error("aChecker: Unable to get compliance of null or undefined object");
216
+ return [2 /*return*/, null];
1313
217
  }
1314
- } else if (reportLevel[0] === "RECOMMENDATION") {
1315
- if (reportLevel[1] === "FAIL") {
1316
- reportLevel = "recommendation";
1317
- } else if (reportLevel[1] === "POTENTIAL") {
1318
- reportLevel = "potentialrecommendation";
218
+ return [4 /*yield*/, getParsed(content)];
219
+ case 2:
220
+ parsed = _a.sent();
221
+ if (parsed === null)
222
+ return [2 /*return*/, null];
223
+ return [4 /*yield*/, ACEngineManager_1.ACEngineManager.loadEngine(parsed)];
224
+ case 3:
225
+ _a.sent();
226
+ // In the case that the label is null or undefined, throw an error using the karma API
227
+ // console.error with the message of the error.
228
+ if (label === null || typeof label === "undefined" || label === undefined) {
229
+ testcaseWhichIsMissingRequiredLabel = null;
230
+ generalErrorMessageLabelNotUnique = "\n[Error] labelNotProvided: Label must be provided when calling aChecker.getCompliance.";
231
+ // Get the caller of the aChecker.getCompliance function which will be the testcase that is calling this function
232
+ // This way we can make it the error more descriptive and would help the user identify where the issues is.
233
+ // We have to build and throw an Error() object and then using the try/catch to catch this error and then extract the
234
+ // stack and parse it to get the 2nd element in the stack which will be the caller of this function which will be the
235
+ // testcase which called this function.
236
+ try {
237
+ // Throw Error() object
238
+ throw new Error();
239
+ }
240
+ catch (exception) {
241
+ // Extract the stack trace from the error object and parse it to get the single one caller up which will be the 2nd index
242
+ testcaseWhichIsMissingRequiredLabel = exception.stack.split("\n")[1];
243
+ // Call the Karma error API, to send message to the Karma server that there was an error on the client side
244
+ console.error("Label was not provided at: " + testcaseWhichIsMissingRequiredLabel + generalErrorMessageLabelNotUnique);
245
+ }
1319
246
  }
1320
- }
1321
- pageResults[i].level = reportLevel;
1322
-
1323
- // Make sure the level is actually defined before trying to perform any action on it
1324
- if (reportLevel !== null && typeof reportLevel !== "undefined") {
1325
- // Remove the violation from the object if report level is not in the reportLevels array.
1326
- if (reportLevels.indexOf(reportLevel) === -1) {
1327
- pageResults.splice(i--, 1);
1328
- continue;
247
+ labelUnique = ACReportManager_1.ACReportManager.isLabelUnique(label);
248
+ // In the case that the label is not unique
249
+ if (!labelUnique) {
250
+ testcaseDoesNotUseUniqueLabel = null;
251
+ generalErrorMessageLabelNotUnique = "\n[Error] labelNotUnique: Label provided to aChecker.getCompliance should be unique across all testcases in a single accessibility-checker session.";
252
+ // Get the caller of the aChecker.getCompliance function which will be the testcase that is calling this function
253
+ // This way we can make it the error more descriptive and would help the user identify where the issues is.
254
+ // We have to build and throw an Error() object and then using the try/catch to catch this error and then extract the
255
+ // stack and parse it to get the 2nd element in the stack which will be the caller of this function which will be the
256
+ // testcase which called this function.
257
+ try {
258
+ // Throw Error() object
259
+ throw new Error();
260
+ }
261
+ catch (exception) {
262
+ // Extract the stack trace from the error object and parse it to get the single one caller up which will be the 2nd index
263
+ testcaseDoesNotUseUniqueLabel = exception.stack.split("\n")[1];
264
+ // Call the Karma error API, to send message to the Karma server that there was an error on the client side
265
+ console.error("Label \"" + label + "\" provided at: " + testcaseDoesNotUseUniqueLabel + " is not unique." + generalErrorMessageLabelNotUnique);
266
+ }
1329
267
  }
1330
- } else {
1331
- // In the case that level is null or not found remove this violation from the results.
1332
- pageResults.splice(i--, 1);
1333
- }
1334
- }
1335
- }
1336
-
1337
- return report;
1338
- };
1339
-
1340
- /**
1341
- * This function is responsible for iterating over all the issue elements and updating the counts object.
1342
- *
1343
- * @param {Object} pageResults - Provide the page results object, in the following format:
1344
- * {
1345
- * "report": {
1346
- * "numChecked": 227,
1347
- * "numTrigger": 1,
1348
- * "ruleTime": 5,
1349
- * "totalTime": 8,
1350
- * "issues": [
1351
- * {
1352
- * "severityCode": "eISHigh",
1353
- * "messageCode": "rpt.g377.elemUniqueId",
1354
- * "ruleId": "377",
1355
- * "help": "idhi_accessibility_check_g377.html",
1356
- * "msgArgs": [
1357
- * "div",
1358
- * "firstDiv"
1359
- * ],
1360
- * "xpath": "/html[1]/body[1]/div[2]/div[2]",
1361
- * "snippet": "<div id=\"firstDiv\">",
1362
- * "bounds": {
1363
- * "left": 10,
1364
- * "top": 181,
1365
- * "height": 0,
1366
- * "width": 1249
1367
- * },
1368
- * "level": "violation"
1369
- * }
1370
- * ],
1371
- * "docTitle": "Helo World"
1372
- * },
1373
- * "counts": {
1374
- * "level.violation": 1,
1375
- * "level.potentialviolation": 0,
1376
- * "level.recommendation": 0,
1377
- * "level.potentialrecommendation": 0,
1378
- * "level.manual": 0
1379
- * },
1380
- * "issueMessages": {
1381
- * "messages": {
1382
- * "rpt.g377.elemUniqueId": "The {0} element has the id \"{1}\" that is either empty or already in use."
1383
- * },
1384
- * "lang": "en-us"
1385
- * }
1386
- * }
1387
- * ......
1388
- *
1389
- * @return {Object} pageResults - return the results object with the count object updated
1390
- * {
1391
- * "report": {
1392
- * "numChecked": 227,
1393
- * "numTrigger": 1,
1394
- * "ruleTime": 5,
1395
- * "totalTime": 8,
1396
- * "issues": [
1397
- * {
1398
- * "severityCode": "eISHigh",
1399
- * "messageCode": "rpt.g377.elemUniqueId",
1400
- * "ruleId": "377",
1401
- * "help": "idhi_accessibility_check_g377.html",
1402
- * "msgArgs": [
1403
- * "div",
1404
- * "firstDiv"
1405
- * ],
1406
- * "xpath": "/html[1]/body[1]/div[2]/div[2]",
1407
- * "snippet": "<div id=\"firstDiv\">",
1408
- * "bounds": {
1409
- * "left": 10,
1410
- * "top": 181,
1411
- * "height": 0,
1412
- * "width": 1249
1413
- * },
1414
- * "level": "violation"
1415
- * }
1416
- * ],
1417
- * "docTitle": "Helo World"
1418
- * },
1419
- * "counts": {
1420
- * "level.violation": 1,
1421
- * "level.potentialviolation": 0,
1422
- * "level.recommendation": 0,
1423
- * "level.potentialrecommendation": 0,
1424
- * "level.manual": 0
1425
- * },
1426
- * "issueMessages": {
1427
- * "messages": {
1428
- * "rpt.g377.elemUniqueId": "The {0} element has the id \"{1}\" that is either empty or already in use."
1429
- * },
1430
- * "lang": "en-us"
1431
- * }
1432
- * }
1433
- *
1434
- * PRIVATE METHOD
1435
- *
1436
- * @memberOf this
1437
- */
1438
- aChecker.updateViolationCount = function (report) {
1439
-
1440
- // Variable Decleration
1441
- let reportLevels = aChecker.Config.reportLevels;
1442
-
1443
- // Build violation count object which will contain the updated count based on filter which
1444
- // which occured in filterViolations function.
1445
- let violationCount = {};
1446
-
1447
- // In the case that report levels are provided then populate the count object in
1448
- // violationCount object with the levels which were provided in reportLevels
1449
- // array/
1450
- if (reportLevels) {
1451
-
1452
- // Iterate over the report levels and populate the pageResultsWithCount counts
1453
- // object
1454
- reportLevels.forEach(function (levels) {
1455
- violationCount[levels] = 0;
1456
- });
1457
-
1458
- }
1459
- // Populate the pageResultsWithCount counts object with all the levels
1460
- else {
1461
- violationCount = {
1462
- "violation": 0,
1463
- "potentialviolation": 0,
1464
- "recommendation": 0,
1465
- "potentialrecommendation": 0,
1466
- "manual": 0,
1467
- "pass": 0
1468
- };
1469
- }
1470
-
1471
- // Iterate over the page results
1472
- for (const item of report.results) {
1473
- if (item.level in violationCount) {
1474
- ++violationCount[item.level];
1475
- }
1476
- }
1477
-
1478
- // Update the results count object with the new one which considers filtered results
1479
- report.counts = violationCount;
1480
-
1481
- return report;
1482
- };
1483
-
1484
- /**
1485
- * This function is responsible for updating/creating the global violation summary for the engine karma run
1486
- * for browser that it is running on. Will take the pageCount object which is part of the page object and
1487
- * add extract the values for each of the levels and add them to the global object. This will provide an overall
1488
- * summary of violations for all testcases run and all scans done.
1489
- *
1490
- * @param {Object} pageCount - Provide the page count object, in the following format:
1491
- *
1492
- * @return N/A - Global summary object is updated with the counts
1493
- *
1494
- * PRIVATE METHOD
1495
- *
1496
- * @memberOf this
1497
- */
1498
- aChecker.addToSummaryCount = function (pageCount) {
1499
-
1500
- // Variable Decleration
1501
- let ACScanSummary = aChecker.scanSummary.counts || {};
1502
- let addedToSummary = false;
1503
-
1504
- // In the case ACScanSummary is empty, simply assign pageCount to ACScanSummary
1505
- if (Object.keys(ACScanSummary).length === 0) {
1506
-
1507
- // Set pageCount as the summary count
1508
- ACScanSummary = pageCount;
1509
-
1510
- addedToSummary = true;
1511
- }
1512
-
1513
- // In the case that this is not first scan, handle adding up the summary
1514
- if (!addedToSummary) {
1515
- // Go through the pageCount object and for each of the levels, extract the value
1516
- // and add it to the accessibility-checker violation summary object.
1517
- // This will keep track of an overall summary of the violations for all testscases, that
1518
- // were run for a single karma run.
1519
- for (let level in pageCount) {
1520
- ACScanSummary[level] += pageCount[level];
1521
- }
1522
- }
1523
-
1524
- // Assign the new violation summary back to the global object
1525
- aChecker.scanSummary.counts = ACScanSummary;
1526
- };
1527
-
1528
- /**
1529
- * This function is responsible for comparing the scan results with baseline or checking that there are
1530
- * no violations which fall into the failsLevels levels. In the case a baseline is found then baseline will
1531
- * be used to perform the check, in the case no baseline is provided then we comply with only failing if
1532
- * there is a sinble violation which falls into failLevels.
1533
- *
1534
- * @param {Object} actual - the actual results object provided by the user, this object should follow the
1535
- * same format as outlined in the return of aChecker.buildReport function.
1536
- *
1537
- * @return {int} - return 0 in the case actual matches baseline or no violations fall into failsLevels,
1538
- * return 1 in the case actual results does not match baseline results,
1539
- * return 2 in the case that there is a failure based on failLevels (this means no baseline found).
1540
- * return -1 in the case that there is an exception that occured in the results object which came from the scan engine.
1541
- *
1542
- * PUBLIC API
1543
- *
1544
- * @memberOf this
1545
- */
1546
- aChecker.assertCompliance = function (actualResults) {
1547
-
1548
- // In the case that the details object contains Error object, this means that the scan engine through an
1549
- // exception, therefore we should not compare results just fail instead.
1550
- if (actualResults.details instanceof Error) {
1551
- return -1;
1552
- }
1553
-
1554
- // Get the label directly from the results object, the same label has to match
1555
- // the baseline object which is available in the global space.
1556
- let label = actualResults.label;
1557
-
1558
- // Fetch the baseline object based on the label provided
1559
- let expected = aChecker.getBaseline(label);
1560
-
1561
- // In the case there are no baseline found then run a different assertion algo,
1562
- // when there is baseline compare the baselines in the case there is no baseline then
1563
- // check to make sure there are no violations that are listed in the fails on.
1564
- if (expected !== null && typeof (expected) !== "undefined") {
1565
- // Run the diff algo to get the list of differences
1566
- let differences = aChecker.diffResultsWithExpected(actualResults, expected, true);
1567
-
1568
- //console.log(JSON.stringify(differences, null, ' '));
1569
-
1570
- // In the case that there are no differences then that means it passed
1571
- if (differences === null || typeof (differences) === "undefined") {
1572
- return 0;
1573
- } else {
1574
- // Re-sort results and check again
1575
- let modActual = JSON.parse(JSON.stringify(actualResults.results));
1576
- modActual.sort((a, b) => {
1577
- let cc = b.category.localeCompare(a.category);
1578
- if (cc != 0) return cc;
1579
- let pc = b.path.dom.localeCompare(a.path.dom);
1580
- if (pc !== 0) return pc;
1581
- return b.ruleId.localeCompare(a.ruleId);
1582
- })
1583
- let modExpected = JSON.parse(JSON.stringify(expected.results));
1584
- modExpected.sort((a, b) => {
1585
- let cc = b.category.localeCompare(a.category);
1586
- if (cc != 0) return cc;
1587
- let pc = b.path.dom.localeCompare(a.path.dom);
1588
- if (pc !== 0) return pc;
1589
- return b.ruleId.localeCompare(a.ruleId);
1590
- })
1591
- let differences2 = aChecker.diffResultsWithExpected({
1592
- results: modActual,
1593
- summary: actualResults.summary
1594
- }, {
1595
- results: modExpected ,
1596
- summary: expected.summary
1597
- }, true);
1598
- if (differences2 === null || typeof (differences2) === "undefined") {
1599
- return 0;
1600
- } else {
1601
- // In the case that there are failures add the whole diff array to
1602
- // global space indexed by the label so that user can access it.
1603
- aChecker.diffResults[label] = differences;
1604
-
1605
- return 1;
1606
- }
1607
- }
1608
- } else {
1609
- // In the case that there was no baseline data found compare the results based on
1610
- // the failLevels array, which was defined by the user.
1611
- let returnCode = aChecker.compareBasedOnFailLevels(actualResults);
1612
-
1613
- // In the case there are no violations that match the fail on then return as success
1614
- if (returnCode === 0) {
1615
- return returnCode;
1616
- } else {
1617
- // In the case there are some violation that match in the fail on then return 2
1618
- // to identify that there was a failure, and we used a 2nd method for compare.
1619
- return 2;
1620
- }
1621
- }
1622
- };
1623
-
1624
- /**
1625
- * This function is responsible for checking if any of the issues reported have any level that falls
1626
- * into the failsLevel array.
1627
- *
1628
- * @param {Object} results - Provide the scan results, object which would be in the
1629
- * the same format as outlined in the return of aChecker.buildReport function.
1630
- *
1631
- * @return {int} - return 1 in the case a single issue was found which is in the failsLevel array.
1632
- * return -1 in the case that there is an exception that occured in the results object which came from the scan engine.
1633
- *
1634
- * PRIVATE METHOD
1635
- *
1636
- * @memberOf this
1637
- */
1638
- aChecker.compareBasedOnFailLevels = function (report) {
1639
-
1640
- // In the case that the details object contains Error object, this means that the scan engine through an
1641
- // exception, therefore we should not compare results just fail instead.
1642
- if (report.details instanceof Error) {
1643
- return -1;
1644
- }
1645
-
1646
- // Variable Decleration
1647
- let failLevels = aChecker.Config.failLevels;
1648
-
1649
- // Loop over all the issues to check for any level that is in failLevels
1650
- // console.log(report);
1651
- for (const issue of report.results) {
1652
- // In the case current level is in the failsLevel array them fail, with out checking further
1653
- // currently we are not saving exactly which results failed, as all the issues are going to be saved to
1654
- // results file.
1655
- if (failLevels.indexOf(issue.level) > -1) {
1656
- // return 1 as there was a fialure
1657
- return 1;
1658
- }
1659
- }
1660
-
1661
- // return 0 as there were no levels that fall into the failLevels
1662
- return 0;
1663
- };
1664
-
1665
- /**
1666
- * This function is responsible for comparing actual with expected and returning all the differences as an array.
1667
- *
1668
- * @param {Object} actual - Provide the actual object to be used for compare
1669
- * @param {Object} expected - Provide the expected object to be used for compare
1670
- * @param {boolean} clean - Provide a boolean if both the actual and expected objects need to be cleaned
1671
- * cleaning refers to converting the objects to match with a basic compliance
1672
- * compare of xpath and ruleId.
1673
- *
1674
- * @return {Object} differences - return an array of diff objects that were found, following is the format of the object:
1675
- * [
1676
- * {
1677
- * "kind": "E",
1678
- * "path": [
1679
- * "reports",
1680
- * 0,
1681
- * "issues",
1682
- * 10,
1683
- * "xpath"
1684
- * ],
1685
- * "lhs": "/html[1]/body[1]/div[2]/table[5]",
1686
- * "rhs": "/html[1]/body[1]/div[2]/table[5]d",
1687
- * },
1688
- * {
1689
- * "kind": "E",
1690
- * "path": [
1691
- * "label"
1692
- * ],
1693
- * "lhs": "Table-layoutMultiple",
1694
- * "rhs": "dependencies/tools-rules-html/v2/a11y/test/g471/Table-layoutMultiple.html",
1695
- * }
1696
- * ]
1697
- *
1698
- * PUBLIC API
1699
- *
1700
- * @memberOf this
1701
- */
1702
- aChecker.diffResultsWithExpected = function (actual, expected, clean) {
1703
-
1704
- // In the case clean is set to true then run the cleanComplianceObjectBeforeCompare function on
1705
- // both the actual and expected objects passed in. This is to make sure that the objcet follow a
1706
- // simalar structure before compareing the objects.
1707
- if (clean) {
1708
- // Clean actual and expected objects
1709
- actual = aChecker.cleanComplianceObjectBeforeCompare(actual);
1710
- expected = aChecker.cleanComplianceObjectBeforeCompare(expected);
1711
- }
1712
-
1713
- // Run Deep diff function to compare the actual and expected values.
1714
- let differences = DeepDiff.diff(actual, expected);
1715
-
1716
- // Return the results of the diff, which will include the differences between the objects
1717
- return differences;
1718
- };
1719
-
1720
- /**
1721
- * This function is responsible for cleaning up the compliance baseline or actual results, based on
1722
- * a pre-defined set of criterias, such as the following:
1723
- * 1. No need to compare summary object
1724
- * 2. Only need to compare the ruleId and xpath in for each of the issues
1725
- *
1726
- * @param {Object} objectToClean - Provide either an baseline or actual results object which would be in the
1727
- * the same format as outlined in the return of aChecker.buildReport function.
1728
- *
1729
- * @return {Object} objectToClean - return an object that was cleaned to only contain the information that is
1730
- * needed for compare. Following is a sample of how the cleaned object will look like:
1731
- * {
1732
- * "label": "unitTestContent",
1733
- * "reports": [
1734
- * {
1735
- * "frameIdx": "0",
1736
- * "frameTitle": "Frame 0",
1737
- * "issues": [
1738
- * {
1739
- * "ruleId": "1",
1740
- * "xpath": "/html[1]/head[1]/style[1]"
1741
- * }
1742
- * ....
1743
- * ]
1744
- * },
1745
- * {
1746
- * "frameIdx": "1",
1747
- * "frameTitle": "Frame 1",
1748
- * "issues": [
1749
- * {
1750
- * "ruleId": "471",
1751
- * "xpath": "/html[1]/body[1]/div[2]/table[3]"
1752
- * }
1753
- * ....
1754
- * ]
1755
- * }
1756
- * ]
1757
- * }
1758
- *
1759
- * PRIVATE METHOD
1760
- *
1761
- * @memberOf this
1762
- */
1763
- aChecker.cleanComplianceObjectBeforeCompare = function (objectToClean) {
1764
- // Clone the object so that we do not reference the original or else it causes the original
1765
- // results object or baseline object to get updated, which we do not want as users are allowed
1766
- // access to the raw results object and baseline object.
1767
- // Convert the object into string and then parse it as a JSON object which will lose its reference
1768
- objectToClean = JSON.parse(JSON.stringify(objectToClean));
1769
-
1770
- // Remove the summary object, scanID, toolID, issueMessage
1771
- delete objectToClean.summary;
1772
- delete objectToClean.nls;
1773
- delete objectToClean.scanID;
1774
- delete objectToClean.toolID;
1775
- delete objectToClean.issueMessages;
1776
- delete objectToClean.numExecuted;
1777
-
1778
-
1779
- // Loop over all the issues and remove the keys that are not needed for the compare
1780
- // Only leave the ruleId and xpath keys for compare.
1781
- for (let idx = 0; idx < objectToClean.results.length; ++idx) {
1782
- const issue = objectToClean.results[idx];
1783
- if (issue.level === "pass") {
1784
- objectToClean.results.splice(idx--, 1);
1785
- } else {
1786
- issue.xpath = issue.path.dom;
1787
- // Loop over all the keys in a single issue object and remove all the
1788
- // keys that are not needed for compare
1789
- Object.keys(issue).forEach(function (key) {
1790
- // Remove all the keys which are not in the baselineIssueList
1791
- if (aChecker.baselineIssueList.indexOf(key) === -1) {
1792
- delete issue[key];
268
+ policies = Config.policies;
269
+ curPol = null;
270
+ if (policies) {
271
+ curPol = JSON.parse(JSON.stringify(policies));
1793
272
  }
1794
- });
1795
- // Make sure that the xpath in the case there is a [1] we replace it with ""
1796
- // to support some browser which return it differently
1797
- issue.xpath = issue.xpath.replace(/\[1\]/g, "");
1798
- }
1799
- };
1800
-
1801
- return objectToClean;
1802
- };
1803
-
1804
- /**
1805
- * This function is responsible for getting the baseline object for a label that was provided.
1806
- *
1807
- * @param {String} label - Provide a lable for which to get the baseline for.
1808
- *
1809
- * @return {Object} - return the baseline object from global space based on label provided, the object will be
1810
- * in the same format as outlined in the return of aChecker.buildReport function.
1811
- *
1812
- * PUBLIC API
1813
- *
1814
- * @memberOf this
1815
- */
1816
- aChecker.getBaseline = function (label) {
1817
- try {
1818
- return require(path.join(path.join(process.cwd(), aChecker.Config.baselineFolder), label));
1819
- } catch (e) {
1820
- return null;
1821
- }
1822
- };
1823
-
1824
- /**
1825
- * This function is responsible for getting the diff results based on label for a scan that was already performed.
1826
- *
1827
- * @param {String} label - Provide a lable for which to get the diff results for.
1828
- *
1829
- * @return {Object} - return the diff results object from global space based on label provided, the object will be
1830
- * in the same format as outlined in the return of aChecker.diffResultsWithExpected function.
1831
- *
1832
- * PUBLIC API
1833
- *
1834
- * @memberOf this
1835
- */
1836
- aChecker.getDiffResults = function (label) {
1837
- return aChecker.diffResults && aChecker.diffResults[label];
1838
- };
1839
-
1840
- /**
1841
- * This function is responsible for printing the scan results to console.
1842
- *
1843
- * @param {Object} results - Provide the results from the scan.
1844
- *
1845
- * @return {String} resultsString - String representation of the results/violations.
1846
- *
1847
- * PUBLIC API
1848
- *
1849
- * @memberOf this
1850
- */
1851
- aChecker.stringifyResults = function (report) {
1852
- // console.log(report);
1853
- // Variable Decleration
1854
- let resultsString = `Scan: ${report.label}\n`;
1855
-
1856
- // Loop over the reports and build the string version of the the issues within each report
1857
- report.results && report.results.forEach(function (issue) {
1858
- if (aChecker.Config.reportLevels.includes(issue.level)) {
1859
- // Build string of the issues with only level, messageCode, xpath and snippet.
1860
- resultsString += "- Message: " + issue.message +
1861
- "\n Level: " + issue.level +
1862
- "\n XPath: " + issue.path.dom +
1863
- "\n Snippet: " + issue.snippet +
1864
- "\n Help: " + aChecker.getHelpURL(issue.ruleId) +
1865
- "\n";
273
+ if (!ACEngineManager_1.ACEngineManager.isSelenium(parsed)) return [3 /*break*/, 5];
274
+ Config.DEBUG && console.log("getComplianceHelper:Selenium");
275
+ return [4 /*yield*/, getComplianceHelperSelenium(label, parsed, curPol)];
276
+ case 4: return [2 /*return*/, _a.sent()];
277
+ case 5:
278
+ if (!ACEngineManager_1.ACEngineManager.isPuppeteer(parsed)) return [3 /*break*/, 7];
279
+ Config.DEBUG && console.log("getComplianceHelper:Puppeteer");
280
+ return [4 /*yield*/, getComplianceHelperPuppeteer(label, parsed, curPol)];
281
+ case 6: return [2 /*return*/, _a.sent()];
282
+ case 7:
283
+ if (!ACEngineManager_1.ACEngineManager.isPlaywright(parsed)) return [3 /*break*/, 9];
284
+ Config.DEBUG && console.log("getComplianceHelper:Playwright");
285
+ return [4 /*yield*/, getComplianceHelperPuppeteer(label, parsed, curPol)];
286
+ case 8: return [2 /*return*/, _a.sent()];
287
+ case 9:
288
+ Config.DEBUG && console.log("getComplianceHelper:Local");
289
+ return [4 /*yield*/, getComplianceHelperLocal(label, parsed, curPol)];
290
+ case 10: return [2 /*return*/, _a.sent()];
1866
291
  }
1867
292
  });
1868
-
1869
- return resultsString;
1870
- };
1871
-
1872
- /**
1873
- * This function is responsible for building the full help file URL using rule server.
1874
- *
1875
- * @param {String} helpFileName - Provide the help file name
1876
- *
1877
- * @return {String} helpFileName - The full help file URL
1878
- *
1879
- * PRIVATE METHOD
1880
- *
1881
- * @memberOf this
1882
- */
1883
- aChecker.getHelpURL = function (ruleId) {
1884
- return new ace.Checker().engine.getHelp(ruleId);
1885
- };
1886
-
1887
- aChecker.getRulesets = function () {
1888
- return new ace.Checker().rulesets;
1889
- };
1890
-
1891
- aChecker.ruleIdToLegacyId = {
1892
- "RPT_List_Misuse": "3",
1893
- "RPT_Marquee_Trigger": "5",
1894
- "RPT_Headers_FewWords": "7",
1895
- "WCAG20_Input_ExplicitLabelImage": "10",
1896
- "RPT_Img_UsemapValid": "11",
1897
- "WCAG20_Object_HasText": "20",
1898
- "WCAG20_Applet_HasAlt": "21",
1899
- "RPT_Media_AudioTrigger": "24",
1900
- "RPT_Blockquote_HasCite": "25",
1901
- "RPT_Meta_Refresh": "33",
1902
- "WCAG20_Frame_HasTitle": "39",
1903
- "WCAG20_Input_ExplicitLabel": "41",
1904
- "RPT_Media_AltBrief": "99",
1905
- "WCAG20_A_TargetAndText": "112",
1906
- "WCAG20_Area_HasAlt": "240",
1907
- "RPT_Media_ImgColorUsage": "245",
1908
- "WCAG20_Meta_RedirectZero": "254",
1909
- "RPT_Elem_Deprecated": "256",
1910
- "RPT_Blockquote_WrapsTextQuote": "263",
1911
- "RPT_Elem_EventMouseAndKey": "269",
1912
- "WCAG20_Doc_HasTitle": "273",
1913
- "RPT_Block_ShouldBeHeading": "322",
1914
- "WCAG20_Form_HasSubmit": "324",
1915
- "RPT_Elem_UniqueId": "377",
1916
- "RPT_Font_ColorInForm": "394",
1917
- "RPT_Label_UniqueFor": "398",
1918
- "RPT_Img_AltCommonMisuse": "453",
1919
- "RPT_Img_LongDescription2": "454",
1920
- "WCAG20_Img_HasAlt": "455",
1921
- "RPT_Style_BackgroundImage": "456",
1922
- "RPT_Pre_ASCIIArt": "458",
1923
- "RPT_Media_VideoReferenceTrigger": "511",
1924
- "RPT_Media_AudioVideoAltFilename": "460",
1925
- "RPT_Style_ColorSemantics1": "466",
1926
- "WCAG20_Select_HasOptGroup": "467",
1927
- "RPT_List_UseMarkup": "468",
1928
- "RPT_Script_OnclickHTML1": "470",
1929
- "WCAG20_Table_Structure": "471",
1930
- "WCAG20_Img_AltTriggerNonDecorative": "473",
1931
- "WCAG20_Blink_AlwaysTrigger": "478",
1932
- "RPT_Blink_CSSTrigger1": "479",
1933
- "RPT_Html_SkipNav": "481",
1934
- "RPT_Title_Valid": "484",
1935
- "RPT_Header_HasContent": "488",
1936
- "WCAG20_Html_HasLang": "490",
1937
- "WCAG20_Form_TargetAndText": "491",
1938
- "WCAG20_A_HasText": "495",
1939
- "WCAG20_Fieldset_HasLegend": "497",
1940
- "RPT_Media_VideoObjectTrigger": "501",
1941
- "RPT_Text_SensoryReference": "502",
1942
- "RPT_Embed_AutoStart": "503",
1943
- "RPT_Style_HinderFocus1": "506",
1944
- "WCAG20_Elem_Lang_Valid": "507",
1945
- "WCAG20_Img_LinkTextNotRedundant": "1000",
1946
- "RPT_Style_ExternalStyleSheet": "1073",
1947
- "RPT_Header_Trigger": "1002",
1948
- "RPT_Script_OnclickHTML2": "1007",
1949
- "WCAG20_Table_CapSummRedundant": "1011",
1950
- "WCAG20_Input_LabelBefore": "1017",
1951
- "WCAG20_Input_LabelAfter": "1018",
1952
- "WCAG20_Embed_HasNoEmbed": "1020",
1953
- "WCAG20_Table_Scope_Valid": "1025",
1954
- "WCAG20_Img_TitleEmptyWhenAltNull": "1027",
1955
- "WCAG20_Input_InFieldSet": "1028",
1956
- "WCAG20_Input_RadioChkInFieldSet": "1029",
1957
- "WCAG20_Select_NoChangeAction": "1035",
1958
- "WCAG20_Input_HasOnchange": "1050",
1959
- "RPT_Embed_HasAlt": "1051",
1960
- "Valerie_Noembed_HasContent": "1052",
1961
- "Valerie_Caption_HasContent": "1053",
1962
- "Valerie_Caption_InTable": "1054",
1963
- "Valerie_Label_HasContent": "1055",
1964
- "Valerie_Elem_DirValid": "1056",
1965
- "Valerie_Frame_SrcHtml": "1057",
1966
- "Valerie_Table_DataCellRelationships": "1059",
1967
- "RPT_Table_LayoutTrigger": "1060",
1968
- "RPT_Table_DataHeadingsAria": "1061",
1969
- "WCAG20_Label_RefValid": "1062",
1970
- "WCAG20_Elem_UniqueAccessKey": "1063",
1971
- "WCAG20_Script_FocusBlurs": "1064",
1972
- "HAAC_Img_UsemapAlt": "1067",
1973
- "WCAG20_Text_Emoticons": "1068",
1974
- "WCAG20_Style_BeforeAfter": "1069",
1975
- "WCAG20_Text_LetterSpacing": "1070",
1976
- "Rpt_Aria_ValidRole": "1074",
1977
- "Rpt_Aria_ValidPropertyValue": "1076",
1978
- "Rpt_Aria_ValidIdRef": "1077",
1979
- "Rpt_Aria_RequiredProperties": "1079",
1980
- "Rpt_Aria_EmptyPropertyValue": "1082",
1981
- "Rpt_Aria_ValidProperty": "1083",
1982
- "Rpt_Aria_InvalidTabindexForActivedescendant": "1084",
1983
- "Rpt_Aria_MissingFocusableChild": "1086",
1984
- "Rpt_Aria_MissingKeyboardHandler": "1087",
1985
- "WCAG20_Img_PresentationImgHasNonNullAlt": "1090",
1986
- "Rpt_Aria_MultipleSearchLandmarks": "1097",
1987
- "Rpt_Aria_MultipleApplicationLandmarks": "1099",
1988
- "Rpt_Aria_ApplicationLandmarkLabel": "1100",
1989
- "Rpt_Aria_MultipleDocumentRoles": "1101",
1990
- "WCAG20_Label_TargetInvisible": "1112",
1991
- "HAAC_Video_HasNoTrack": "1117",
1992
- "HAAC_Audio_Video_Trigger": "1119",
1993
- "HAAC_Input_HasRequired": "1124",
1994
- "HAAC_Aria_ImgAlt": "1128",
1995
- "HAAC_BackgroundImg_HasTextOrTitle": "1132",
1996
- "HAAC_Accesskey_NeedLabel": "1140",
1997
- "HAAC_Aria_Or_HTML5_Attr": "1141",
1998
- "HAAC_Canvas": "1143",
1999
- "HAAC_Figure_label": "1144",
2000
- "HAAC_Input_Placeholder": "1145",
2001
- "HAAC_Aria_Native_Host_Sematics": "1146",
2002
- "RPT_Form_ChangeEmpty": "1147",
2003
- "IBMA_Color_Contrast_WCAG2AA": "1148",
2004
- "IBMA_Color_Contrast_WCAG2AA_PV": "1149",
2005
- "WCAG20_Body_FirstASkips_Native_Host_Sematics": "1150",
2006
- "WCAG20_Body_FirstAContainsSkipText_Native_Host_Sematics": "1151",
2007
- "Rpt_Aria_RequiredChildren_Native_Host_Sematics": "1152",
2008
- "Rpt_Aria_RequiredParent_Native_Host_Sematics": "1153",
2009
- "Rpt_Aria_EventHandlerMissingRole_Native_Host_Sematics": "1154",
2010
- "Rpt_Aria_WidgetLabels_Implicit": "1156",
2011
- "Rpt_Aria_OrphanedContent_Native_Host_Sematics": "1157",
2012
- "Rpt_Aria_RegionLabel_Implicit": "1158",
2013
- "Rpt_Aria_MultipleMainsVisibleLabel_Implicit": "1159",
2014
- "Rpt_Aria_MultipleBannerLandmarks_Implicit": "1160",
2015
- "Rpt_Aria_MultipleComplementaryLandmarks_Implicit": "1161",
2016
- "Rpt_Aria_MultipleContentinfoLandmarks_Implicit": "1162",
2017
- "Rpt_Aria_MultipleFormLandmarks_Implicit": "1163",
2018
- "Rpt_Aria_MultipleNavigationLandmarks_Implicit": "1164",
2019
- "Rpt_Aria_ComplementaryLandmarkLabel_Implicit": "1165",
2020
- "Rpt_Aria_MultipleArticleRoles_Implicit": "1166",
2021
- "Rpt_Aria_ArticleRoleLabel_Implicit": "1167",
2022
- "Rpt_Aria_MultipleGroupRoles_Implicit": "1168",
2023
- "Rpt_Aria_GroupRoleLabel_Implicit": "1169",
2024
- "Rpt_Aria_MultipleContentinfoInSiblingSet_Implicit": "1170",
2025
- "Rpt_Aria_OneBannerInSiblingSet_Implicit": "1172",
2026
- "Rpt_Aria_ContentinfoWithNoMain_Implicit": "1173",
2027
- "Rpt_Aria_ComplementaryRequiredLabel_Implicit": "1174",
2028
- "Rpt_Aria_MultipleRegionsUniqueLabel_Implicit": "1176",
2029
- "IBMA_Focus_Tabbable": "1177",
2030
- "IBMA_Focus_MultiTab": "1178",
2031
- "WCAG20_Table_SummaryAria3": "1179",
2032
- "RPT_Style_Trigger2": "1180",
2033
- "Rpt_Aria_MultipleMainsRequireLabel_Implicit_2": "1182",
2034
- "HAAC_Media_DocumentTrigger2": "1183",
2035
- "HAAC_Aria_ErrorMessage": "1184",
2036
- "HAAC_List_Group_ListItem": "1185",
2037
- "HAAC_ActiveDescendantCheck": "1186",
2038
- "HAAC_Application_Role_Text": "1187",
2039
- "Rpt_Aria_MultipleToolbarUniqueLabel": "1188",
2040
- "HAAC_Combobox_ARIA_11_Guideline": "1193",
2041
- "HAAC_Combobox_Must_Have_Text_Input": "1194",
2042
- "HAAC_Combobox_DOM_Focus": "1195",
2043
- "HAAC_Combobox_Autocomplete": "1196",
2044
- "HAAC_Combobox_Autocomplete_Invalid": "1197",
2045
- "HAAC_Combobox_Expanded": "1198",
2046
- "HAAC_Combobox_Popup": "1199",
2047
- "WCAG21_Style_Viewport": "1200",
2048
- "WCAG21_Label_Accessible": "1202",
2049
- "WCAG21_Input_Autocomplete": "1203",
2050
- "WCAG20_Input_VisibleLabel": "1204"
2051
- }
2052
-
2053
- aChecker.ignoreExtraBaselineViolations = function (actualReport, baselineReport) {
2054
- let result = null;
2055
- let existingRuleIDs = [];
2056
- // Using for loop to make is sync code
2057
- let ignoredCount = 0;
2058
- let changedCounts = actualReport.summary.counts;
2059
-
2060
- let currentActualReport = actualReport.results;
2061
- const currentBaselineReport = baselineReport;
2062
- // a report exists in the baseline for the iframe
2063
- if (currentBaselineReport && currentBaselineReport.length === 1) {
2064
- let legacyBaseline = !!currentBaselineReport[0].issues;
2065
- for (const issue of currentActualReport) {
2066
- let currentRuleID = issue.ruleId;
2067
- let currentLevel = issue.level;
2068
- let currentXPATH = issue.path.dom;
2069
- //check if the issue exists in baseline already
2070
- let result =
2071
- legacyBaseline && currentBaselineReport[0].issues.filter(issue => issue.ruleId in aChecker.ruleIdToLegacyId && aChecker.ruleIdToLegacyId[issue.ruleId] === currentRuleID && issue.level === currentLevel && issue.xpath === currentXPATH)
2072
- || !legacyBaseline && currentBaselineReport.results.filter(issue => issue.ruleId === currentRuleID && issue.level === currentLevel && issue.dom.path === currentXPATH);
2073
- if (result && result.length !== 0) {
2074
- //violation exists in baseline, add ignore:true
2075
- issue.ignored = true;
2076
- ignoredCount++;
2077
- if (issue.level === "violation") {
2078
- changedCounts.violation--;
2079
- }
2080
- if (issue.level === "potentialviolation") {
2081
- changedCounts.potentialviolation--;
2082
- }
2083
- if (issue.level === "recommendation") {
2084
- changedCounts.recommendation--;
293
+ });
294
+ }
295
+ exports.getComplianceHelper = getComplianceHelper;
296
+ function getComplianceHelperSelenium(label, parsed, curPol) {
297
+ return __awaiter(this, void 0, void 0, function () {
298
+ var startScan, browser, scriptStr, manage, report, getPolicies, valPolicies, finalReport, url, origReport, counts, image, screenshotResult, err_1;
299
+ return __generator(this, function (_a) {
300
+ switch (_a.label) {
301
+ case 0:
302
+ _a.trys.push([0, 7, , 8]);
303
+ startScan = Date.now();
304
+ browser = parsed;
305
+ scriptStr = "let cb = arguments[arguments.length - 1];\ntry {\nlet policies = " + JSON.stringify(Config.policies) + ";\n\nlet checker = new window.ace.Checker();\nsetTimeout(function() {\n checker.check(document, policies).then(function(report) {\n for (const result of report.results) {\n delete result.node;\n }\n cb(report);\n })\n},0)\n} catch (e) {\ncb(e);\n}";
306
+ manage = browser.manage();
307
+ if (manage.timeouts) {
308
+ manage.timeouts().setScriptTimeout(60000);
2085
309
  }
2086
- if (issue.level === "potentialrecommendation") {
2087
- changedCounts.potentialrecommendation--;
310
+ else if (manage.setTimeouts) {
311
+ manage.setTimeouts({
312
+ "script": 60000
313
+ });
2088
314
  }
2089
- if (issue.level === "manual") {
2090
- changedCounts.manual--;
315
+ return [4 /*yield*/, browser.executeAsyncScript(scriptStr)];
316
+ case 1:
317
+ report = _a.sent();
318
+ report = ACReportManager_1.ACReportManager.setLevels(report);
319
+ getPolicies = "return new window.ace.Checker().rulesetIds;";
320
+ if (!(curPol != null && !checkPolicy)) return [3 /*break*/, 3];
321
+ checkPolicy = true;
322
+ return [4 /*yield*/, browser.executeScript(getPolicies)];
323
+ case 2:
324
+ valPolicies = _a.sent();
325
+ areValidPolicy(valPolicies, curPol);
326
+ _a.label = 3;
327
+ case 3:
328
+ finalReport = void 0;
329
+ if (!report.results) return [3 /*break*/, 6];
330
+ return [4 /*yield*/, browser.getCurrentUrl()];
331
+ case 4:
332
+ url = _a.sent();
333
+ origReport = JSON.parse(JSON.stringify(report));
334
+ origReport = ACReportManager_1.ACReportManager.buildReport(origReport, {}, url, label, startScan);
335
+ // Filter the violations based on the reportLevels
336
+ report = ACReportManager_1.ACReportManager.filterViolations(report);
337
+ counts = ACReportManager_1.ACReportManager.getCounts(report);
338
+ // Add the violation count to global summary object
339
+ ACReportManager_1.ACReportManager.addToSummaryCount(counts);
340
+ // Build the report object for this scan, to follow a specific format. Refer to the
341
+ // function prolog for more information on the object creation.
342
+ finalReport = ACReportManager_1.ACReportManager.buildReport(report, counts, url, label, startScan);
343
+ // Add the scan results to global karma result object which can be accessed when users testcase
344
+ // finishes, user can also access it to alter it for any reason.
345
+ ACReportManager_1.ACReportManager.addResultsToGlobal(finalReport);
346
+ // Need to call a karma API to send the results of a single scan to the accessibility-checker reporter so that they can be
347
+ // saved to a file by the server side reporter.
348
+ ACReportManager_1.ACReportManager.sendResultsToReporter(origReport, finalReport, "Selenium");
349
+ if (!(Config.captureScreenshots && browser.takeScreenshot)) return [3 /*break*/, 6];
350
+ return [4 /*yield*/, browser.takeScreenshot()];
351
+ case 5:
352
+ image = _a.sent();
353
+ screenshotResult = {
354
+ image: image,
355
+ label: label,
356
+ scanID: finalReport.scanID
357
+ };
358
+ ACReportManager_1.ACReportManager.sendScreenShotToReporter(screenshotResult);
359
+ _a.label = 6;
360
+ case 6: return [2 /*return*/, {
361
+ "report": finalReport,
362
+ "webdriver": parsed
363
+ }];
364
+ case 7:
365
+ err_1 = _a.sent();
366
+ console.error(err_1);
367
+ return [2 /*return*/, Promise.reject(err_1)];
368
+ case 8:
369
+ ;
370
+ return [2 /*return*/];
371
+ }
372
+ });
373
+ });
374
+ }
375
+ function getComplianceHelperPuppeteer(label, parsed, curPol) {
376
+ return __awaiter(this, void 0, void 0, function () {
377
+ var startScan, page, report, valPolicies, finalReport, url, origReport, counts, image, screenshotResult, err_2;
378
+ return __generator(this, function (_a) {
379
+ switch (_a.label) {
380
+ case 0:
381
+ _a.trys.push([0, 7, , 8]);
382
+ startScan = Date.now();
383
+ page = parsed;
384
+ return [4 /*yield*/, page.evaluate(function (policies) {
385
+ var checker = new window.ace.Checker();
386
+ return new Promise(function (resolve, reject) {
387
+ setTimeout(function () {
388
+ checker.check(document, policies).then(function (report) {
389
+ for (var _i = 0, _a = report.results; _i < _a.length; _i++) {
390
+ var result = _a[_i];
391
+ delete result.node;
392
+ }
393
+ resolve(report);
394
+ });
395
+ }, 0);
396
+ });
397
+ }, Config.policies)];
398
+ case 1:
399
+ report = _a.sent();
400
+ report = ACReportManager_1.ACReportManager.setLevels(report);
401
+ if (!(curPol != null && !checkPolicy)) return [3 /*break*/, 3];
402
+ return [4 /*yield*/, page.evaluate("new window.ace.Checker().rulesetIds")];
403
+ case 2:
404
+ valPolicies = _a.sent();
405
+ checkPolicy = true;
406
+ areValidPolicy(valPolicies, curPol);
407
+ _a.label = 3;
408
+ case 3:
409
+ finalReport = void 0;
410
+ if (!report.results) return [3 /*break*/, 6];
411
+ return [4 /*yield*/, page.evaluate("document.location.href")];
412
+ case 4:
413
+ url = _a.sent();
414
+ origReport = JSON.parse(JSON.stringify(report));
415
+ origReport = ACReportManager_1.ACReportManager.buildReport(origReport, {}, url, label, startScan);
416
+ // Filter the violations based on the reporLevels
417
+ report = ACReportManager_1.ACReportManager.filterViolations(report);
418
+ counts = ACReportManager_1.ACReportManager.getCounts(report);
419
+ // Add the violation count to global summary object
420
+ ACReportManager_1.ACReportManager.addToSummaryCount(counts);
421
+ // Build the report object for this scan, to follow a specific format. Refer to the
422
+ // function prolog for more information on the object creation.
423
+ finalReport = ACReportManager_1.ACReportManager.buildReport(report, counts, url, label, startScan);
424
+ // Add the scan results to global karma result object which can be accessed when users testcase
425
+ // finishes, user can also access it to alter it for any reason.
426
+ ACReportManager_1.ACReportManager.addResultsToGlobal(finalReport);
427
+ // Need to call a karma API to send the results of a single scan to the accessibility-checker reporter so that they can be
428
+ // saved to a file by the server side reporter.
429
+ ACReportManager_1.ACReportManager.sendResultsToReporter(origReport, finalReport, "Puppeteer");
430
+ if (!Config.captureScreenshots) return [3 /*break*/, 6];
431
+ return [4 /*yield*/, page.screenshot({
432
+ fullPage: true,
433
+ encoding: "base64"
434
+ })];
435
+ case 5:
436
+ image = _a.sent();
437
+ screenshotResult = {
438
+ image: image,
439
+ label: label,
440
+ scanID: Config.scanID
441
+ };
442
+ ACReportManager_1.ACReportManager.sendScreenShotToReporter(screenshotResult);
443
+ _a.label = 6;
444
+ case 6:
445
+ page.aceBusy = false;
446
+ return [2 /*return*/, {
447
+ "report": finalReport,
448
+ "puppeteer": parsed
449
+ }];
450
+ case 7:
451
+ err_2 = _a.sent();
452
+ console.error(err_2);
453
+ return [2 /*return*/, Promise.reject(err_2)];
454
+ case 8:
455
+ ;
456
+ return [2 /*return*/];
457
+ }
458
+ });
459
+ });
460
+ }
461
+ function getComplianceHelperLocal(label, parsed, curPol) {
462
+ return __awaiter(this, void 0, void 0, function () {
463
+ var startScan, checker, report, valPolicies, finalReport, url, origReport, counts, err_3;
464
+ return __generator(this, function (_a) {
465
+ switch (_a.label) {
466
+ case 0:
467
+ _a.trys.push([0, 2, , 3]);
468
+ startScan = Date.now();
469
+ checker = ACEngineManager_1.ACEngineManager.getChecker();
470
+ return [4 /*yield*/, checker.check(parsed, Config.policies)
471
+ .then(function (report) {
472
+ for (var _i = 0, _a = report.results; _i < _a.length; _i++) {
473
+ var result = _a[_i];
474
+ delete result.node;
475
+ }
476
+ return report;
477
+ })];
478
+ case 1:
479
+ report = _a.sent();
480
+ report = ACReportManager_1.ACReportManager.setLevels(report);
481
+ if (curPol != null && !checkPolicy) {
482
+ valPolicies = checker.rulesetIds;
483
+ checkPolicy = true;
484
+ areValidPolicy(valPolicies, curPol);
2091
485
  }
2092
- if (issue.level === "pass") {
2093
- changedCounts.pass--;
486
+ finalReport = void 0;
487
+ // If there is something to report...
488
+ if (report.results) {
489
+ url = parsed.location && parsed.location.href;
490
+ origReport = JSON.parse(JSON.stringify(report));
491
+ origReport = ACReportManager_1.ACReportManager.buildReport(origReport, {}, url, label, startScan);
492
+ // Filter the violations based on the reporLevels
493
+ report = ACReportManager_1.ACReportManager.filterViolations(report);
494
+ counts = ACReportManager_1.ACReportManager.getCounts(report);
495
+ // Add the violation count to global summary object
496
+ ACReportManager_1.ACReportManager.addToSummaryCount(counts);
497
+ // Build the report object for this scan, to follow a specific format. Refer to the
498
+ // function prolog for more information on the object creation.
499
+ finalReport = ACReportManager_1.ACReportManager.buildReport(report, counts, URL, label, startScan);
500
+ // Add the scan results to global karma result object which can be accessed when users testcase
501
+ // finishes, user can also access it to alter it for any reason.
502
+ ACReportManager_1.ACReportManager.addResultsToGlobal(finalReport);
503
+ // Need to call a karma API to send the results of a single scan to the accessibility-checker reporter so that they can be
504
+ // saved to a file by the server side reporter.
505
+ ACReportManager_1.ACReportManager.sendResultsToReporter(origReport, finalReport, "Native");
2094
506
  }
2095
-
2096
- } else {
2097
- issue.ignored = false;
2098
- }
507
+ return [2 /*return*/, {
508
+ "report": finalReport
509
+ }];
510
+ case 2:
511
+ err_3 = _a.sent();
512
+ console.error(err_3);
513
+ return [2 /*return*/, Promise.reject(err_3)];
514
+ case 3:
515
+ ;
516
+ return [2 /*return*/];
2099
517
  }
2100
-
2101
- }
2102
-
2103
- // adding ignore count to summary
2104
- changedCounts.ignored = ignoredCount;
2105
- actualReport.summary.counts = changedCounts
2106
- return actualReport;
2107
- }
2108
-
2109
- })();
2110
- module.exports = {
2111
- getCompliance: aChecker.getCompliance,
2112
- assertCompliance: aChecker.assertCompliance,
2113
- getDiffResults: aChecker.getDiffResults,
2114
- getBaseline: aChecker.getBaseline,
2115
- diffResultsWithExpected: aChecker.diffResultsWithExpected,
2116
- stringifyResults: aChecker.stringifyResults,
2117
- getConfig: aChecker.getConfig,
2118
- close: aChecker.close,
2119
- ruleIdToLegacyId: aChecker.ruleIdToLegacyId,
2120
- cleanComplianceObjectBeforeCompare: aChecker.cleanComplianceObjectBeforeCompare
2121
- }
518
+ });
519
+ });
520
+ }
521
+ //# sourceMappingURL=ACHelper.js.map