testaro 30.0.8 → 32.0.1

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 (212) hide show
  1. package/CONTRIBUTING.md +26 -4
  2. package/LICENSE +1 -1
  3. package/README.md +24 -2
  4. package/aceconfig.js +27 -0
  5. package/actSpecs.js +28 -1
  6. package/call.js +22 -1
  7. package/data/template.js +22 -0
  8. package/dirWatch.js +22 -0
  9. package/package.json +1 -1
  10. package/procs/aslint.js +24 -0
  11. package/procs/getLocatorData.js +29 -1
  12. package/procs/getSource.js +30 -3
  13. package/procs/isInlineLink.js +23 -0
  14. package/procs/operable.js +23 -2
  15. package/procs/sample.js +22 -0
  16. package/procs/standardize.js +28 -7
  17. package/procs/tellServer.js +24 -2
  18. package/procs/testaro.js +26 -1
  19. package/procs/visChange.js +22 -0
  20. package/run.js +373 -83
  21. package/testaro/allCaps.js +22 -0
  22. package/testaro/allHidden.js +22 -0
  23. package/testaro/allSlanted.js +22 -0
  24. package/testaro/attVal.js +22 -0
  25. package/testaro/autocomplete.js +22 -0
  26. package/testaro/bulk.js +22 -0
  27. package/testaro/buttonMenu.js +22 -0
  28. package/testaro/distortion.js +22 -0
  29. package/testaro/docType.js +22 -0
  30. package/testaro/dupAtt.js +22 -0
  31. package/testaro/elements.js +22 -0
  32. package/testaro/embAc.js +22 -0
  33. package/testaro/filter.js +22 -0
  34. package/testaro/focAll.js +22 -0
  35. package/testaro/focInd.js +22 -0
  36. package/testaro/focOp.js +22 -0
  37. package/testaro/focVis.js +22 -0
  38. package/testaro/headEl.js +22 -0
  39. package/testaro/headingAmb.js +22 -0
  40. package/testaro/hovInd.js +21 -24
  41. package/testaro/hover.js +22 -0
  42. package/testaro/labClash.js +22 -0
  43. package/testaro/lineHeight.js +22 -0
  44. package/testaro/linkAmb.js +22 -0
  45. package/testaro/linkTitle.js +22 -0
  46. package/testaro/linkUl.js +22 -0
  47. package/testaro/miniText.js +22 -0
  48. package/testaro/motion.js +22 -0
  49. package/testaro/nonTable.js +22 -0
  50. package/testaro/opFoc.js +22 -0
  51. package/testaro/pseudoP.js +25 -3
  52. package/testaro/radioSet.js +22 -0
  53. package/testaro/role.js +22 -0
  54. package/testaro/styleDiff.js +80 -1
  55. package/testaro/tabNav.js +99 -2
  56. package/testaro/targetSize.js +22 -0
  57. package/testaro/textNodes.js +25 -3
  58. package/testaro/title.js +22 -0
  59. package/testaro/zIndex.js +22 -0
  60. package/tests/alfa.js +34 -12
  61. package/tests/aslint.js +55 -17
  62. package/tests/axe.js +35 -9
  63. package/tests/htmlcs.js +109 -78
  64. package/tests/ibm.js +111 -45
  65. package/tests/nuVal.js +39 -9
  66. package/tests/qualWeb.js +49 -25
  67. package/tests/testaro.js +50 -22
  68. package/tests/wave.js +36 -10
  69. package/validation/executors/run.js +26 -2
  70. package/validation/executors/test.js +27 -3
  71. package/validation/executors/tests.js +26 -2
  72. package/validation/executors/watchDir.js +26 -2
  73. package/validation/executors/watchNet.js +26 -2
  74. package/validation/jobs/todo/README.md +22 -0
  75. package/validation/tests/targets/adbID/index.html +21 -0
  76. package/validation/tests/targets/allCaps/index.html +21 -0
  77. package/validation/tests/targets/allHidden/ariaHiddenBody.html +21 -0
  78. package/validation/tests/targets/allHidden/good.html +21 -0
  79. package/validation/tests/targets/allHidden/hiddenMain.html +21 -0
  80. package/validation/tests/targets/allHidden/mixedHidden.html +22 -1
  81. package/validation/tests/targets/allHidden/noBody.html +21 -0
  82. package/validation/tests/targets/allHidden/noMain.html +21 -0
  83. package/validation/tests/targets/allHidden/noneDoc.html +21 -0
  84. package/validation/tests/targets/allHidden/visHiddenMain.html +21 -0
  85. package/validation/tests/targets/allSlanted/index.html +21 -0
  86. package/validation/tests/targets/altScheme/index.html +21 -0
  87. package/validation/tests/targets/attVal/bad.html +21 -0
  88. package/validation/tests/targets/attVal/good.html +21 -0
  89. package/validation/tests/targets/autocomplete/bad.html +21 -0
  90. package/validation/tests/targets/autocomplete/good.html +21 -0
  91. package/validation/tests/targets/bulk/bad.html +21 -0
  92. package/validation/tests/targets/bulk/good.html +21 -0
  93. package/validation/tests/targets/buttonMenu/bad.html +21 -0
  94. package/validation/tests/targets/buttonMenu/bad.js +27 -0
  95. package/validation/tests/targets/buttonMenu/good.html +21 -0
  96. package/validation/tests/targets/buttonMenu/good.js +27 -0
  97. package/validation/tests/targets/buttonMenu/style.css +27 -0
  98. package/validation/tests/targets/captionLoc/index.html +21 -0
  99. package/validation/tests/targets/datalistRef/index.html +21 -0
  100. package/validation/tests/targets/distortion/index.html +21 -0
  101. package/validation/tests/targets/docType/bad.html +21 -0
  102. package/validation/tests/targets/docType/good.html +21 -0
  103. package/validation/tests/targets/dupAtt/bad.html +21 -0
  104. package/validation/tests/targets/dupAtt/good.html +21 -0
  105. package/validation/tests/targets/elements/index.html +21 -0
  106. package/validation/tests/targets/embAc/bad.html +21 -0
  107. package/validation/tests/targets/embAc/good.html +21 -0
  108. package/validation/tests/targets/filter/bad.html +21 -0
  109. package/validation/tests/targets/filter/good.html +21 -0
  110. package/validation/tests/targets/focAll/good.html +21 -0
  111. package/validation/tests/targets/focAll/less.html +21 -0
  112. package/validation/tests/targets/focAll/more.html +21 -0
  113. package/validation/tests/targets/focInd/bad.html +21 -0
  114. package/validation/tests/targets/focInd/good.html +21 -0
  115. package/validation/tests/targets/focOp/bad.html +21 -0
  116. package/validation/tests/targets/focOp/good.html +21 -0
  117. package/validation/tests/targets/focVis/index.html +21 -0
  118. package/validation/tests/targets/headEl/index.html +21 -0
  119. package/validation/tests/targets/headingAmb/index.html +21 -0
  120. package/validation/tests/targets/hovInd/index.html +21 -0
  121. package/validation/tests/targets/hover/bad.html +21 -0
  122. package/validation/tests/targets/hover/good.html +21 -0
  123. package/validation/tests/targets/hr/index.html +21 -0
  124. package/validation/tests/targets/imageLink/index.html +21 -0
  125. package/validation/tests/targets/labClash/bad.html +21 -0
  126. package/validation/tests/targets/labClash/good.html +21 -0
  127. package/validation/tests/targets/legendLoc/index.html +21 -0
  128. package/validation/tests/targets/lineHeight/index.html +21 -0
  129. package/validation/tests/targets/linkAmb/index.html +21 -0
  130. package/validation/tests/targets/linkExt/index.html +21 -0
  131. package/validation/tests/targets/linkOldAtt/index.html +21 -0
  132. package/validation/tests/targets/linkTitle/index.html +21 -0
  133. package/validation/tests/targets/linkTo/index.html +21 -0
  134. package/validation/tests/targets/linkUl/bad.html +21 -0
  135. package/validation/tests/targets/linkUl/good.html +21 -0
  136. package/validation/tests/targets/linkUl/na.html +21 -0
  137. package/validation/tests/targets/miniText/index.html +21 -0
  138. package/validation/tests/targets/motion/bad.css +27 -0
  139. package/validation/tests/targets/motion/bad.html +21 -0
  140. package/validation/tests/targets/motion/good.html +21 -0
  141. package/validation/tests/targets/nonTable/index.html +21 -0
  142. package/validation/tests/targets/opFoc/bad.html +21 -0
  143. package/validation/tests/targets/opFoc/good.html +21 -0
  144. package/validation/tests/targets/optRoleSel/index.html +21 -0
  145. package/validation/tests/targets/phOnly/index.html +21 -0
  146. package/validation/tests/targets/pseudoP/index.html +21 -0
  147. package/validation/tests/targets/radioSet/bad.html +21 -0
  148. package/validation/tests/targets/radioSet/good.html +21 -0
  149. package/validation/tests/targets/role/bad.html +21 -0
  150. package/validation/tests/targets/role/good.html +21 -0
  151. package/validation/tests/targets/secHeading/index.html +21 -0
  152. package/validation/tests/targets/styleDiff/bad.html +21 -0
  153. package/validation/tests/targets/styleDiff/good.html +21 -0
  154. package/validation/tests/targets/tabNav/bad.html +21 -0
  155. package/validation/tests/targets/tabNav/bad.js +27 -0
  156. package/validation/tests/targets/tabNav/good.html +21 -0
  157. package/validation/tests/targets/tabNav/good.js +27 -0
  158. package/validation/tests/targets/tabNav/style.css +27 -0
  159. package/validation/tests/targets/targetSize/index.html +21 -0
  160. package/validation/tests/targets/textNodes/index.html +21 -0
  161. package/validation/tests/targets/textSem/index.html +21 -0
  162. package/validation/tests/targets/title/bad.html +21 -0
  163. package/validation/tests/targets/title/good.html +21 -0
  164. package/validation/tests/targets/titledEl/index.html +21 -0
  165. package/validation/tests/targets/zIndex/bad.html +21 -0
  166. package/validation/tests/targets/zIndex/good.html +21 -0
  167. package/validation/validateTest.js +39 -3
  168. package/validation/watch/done/README.md +23 -1
  169. package/validation/watch/todo/README.md +23 -1
  170. package/watch.js +32 -7
  171. package/call-old.js +0 -86
  172. package/procs/allText.js +0 -76
  173. package/procs/allVis.js +0 -17
  174. package/procs/getTextNodes.js +0 -39
  175. package/procs/linksByType.js +0 -54
  176. package/procs/nav.js +0 -259
  177. package/procs/textOf.txt +0 -73
  178. package/test copy.js +0 -38
  179. package/validation/tests/old/allCaps.json +0 -102
  180. package/validation/tests/old/allHidden.json +0 -314
  181. package/validation/tests/old/attVal.json +0 -60
  182. package/validation/tests/old/autocomplete.json +0 -51
  183. package/validation/tests/old/bulk.json +0 -48
  184. package/validation/tests/old/docType.json +0 -46
  185. package/validation/tests/old/dupAtt.json +0 -51
  186. package/validation/tests/old/elements.json +0 -140
  187. package/validation/tests/old/embAc.json +0 -54
  188. package/validation/tests/old/filter.json +0 -55
  189. package/validation/tests/old/focAll.json +0 -68
  190. package/validation/tests/old/focInd.json +0 -69
  191. package/validation/tests/old/focOp.json +0 -62
  192. package/validation/tests/old/focVis.json +0 -35
  193. package/validation/tests/old/hover.json +0 -118
  194. package/validation/tests/old/labClash.json +0 -52
  195. package/validation/tests/old/linkTo.json +0 -35
  196. package/validation/tests/old/linkUl.json +0 -71
  197. package/validation/tests/old/menuNav.json +0 -106
  198. package/validation/tests/old/miniText.json +0 -36
  199. package/validation/tests/old/motion.json +0 -62
  200. package/validation/tests/old/nonTable.json +0 -37
  201. package/validation/tests/old/radioSet.json +0 -52
  202. package/validation/tests/old/role.json +0 -60
  203. package/validation/tests/old/styleDiff.json +0 -71
  204. package/validation/tests/old/tabNav.json +0 -106
  205. package/validation/tests/old/temp.js +0 -28
  206. package/validation/tests/old/textNodes.json +0 -98
  207. package/validation/tests/old/title.json +0 -46
  208. package/validation/tests/old/titledEl.json +0 -37
  209. package/validation/tests/old/zIndex.json +0 -49
  210. package/validation/tests/targets/tabNav/goodMoz.js +0 -206
  211. package/watch-old.js +0 -275
  212. package/watch-temp.js +0 -45
package/watch.js CHANGED
@@ -1,3 +1,25 @@
1
+ /*
2
+ © 2022–2023 CVS Health and/or one of its affiliates. All rights reserved.
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
21
+ */
22
+
1
23
  /*
2
24
  watch.js
3
25
  Module for watching for a job and running it when found.
@@ -142,7 +164,9 @@ const checkNetJob = async (servers, serverIndex, isForever, interval, noJobCount
142
164
  const client = server.startsWith('https://') ? httpsClient : httpClient;
143
165
  const fullURL = `${server}?agent=${agent}`;
144
166
  const logStart = `Requested job from server ${server} and got `;
145
- client.request(fullURL, response => {
167
+ // Tolerate unrecognized certificate authorities if the environment specifies.
168
+ const ruOpt = process.env.REJECT_UNAUTHORIZED === 'false' ? {rejectUnauthorized: false} : {};
169
+ client.request(fullURL, ruOpt, response => {
146
170
  const chunks = [];
147
171
  response
148
172
  // If the response to the job request threw an error:
@@ -187,7 +211,7 @@ const checkNetJob = async (servers, serverIndex, isForever, interval, noJobCount
187
211
  // Perform the job, adding result data to it.
188
212
  const testee = sources.target.which;
189
213
  console.log(
190
- `${logStart}job ${id} (${nowString()})\n>> It will test ${testee}\n>> It will send report to ${sendReportTo}`
214
+ `${logStart}job ${id} (${nowString()})\n>> It will test ${testee}\n>> It will send report to ${sendReportTo}\n`
191
215
  );
192
216
  await doJob(contentObj);
193
217
  let reportJSON = JSON.stringify(contentObj, null, 2);
@@ -202,7 +226,7 @@ const checkNetJob = async (servers, serverIndex, isForever, interval, noJobCount
202
226
  // If the response to the report threw an error:
203
227
  .on('error', async error => {
204
228
  // Report this.
205
- console.log(`${reportLogStart}error message ${error.message}`);
229
+ console.log(`${reportLogStart}error message ${error.message}\n`);
206
230
  // Check the next server.
207
231
  await checkNetJob(servers, serverIndex + 1, isForever, interval, noJobCount + 1);
208
232
  })
@@ -218,7 +242,7 @@ const checkNetJob = async (servers, serverIndex, isForever, interval, noJobCount
218
242
  const {message} = ackObj;
219
243
  if (message) {
220
244
  // Report it.
221
- console.log(`${reportLogStart}${message}`);
245
+ console.log(`${reportLogStart}${message}\n`);
222
246
  // Free the memory used by the report.
223
247
  reportJSON = '';
224
248
  contentObj = {};
@@ -229,7 +253,7 @@ const checkNetJob = async (servers, serverIndex, isForever, interval, noJobCount
229
253
  else {
230
254
  // Report it.
231
255
  console.log(
232
- `ERROR: ${reportLogStart}status ${repResponse.statusCode} and error message ${JSON.stringify(ackObj, null, 2)}`
256
+ `ERROR: ${reportLogStart}status ${repResponse.statusCode} and error message ${JSON.stringify(ackObj, null, 2)}\n`
233
257
  );
234
258
  // Check the next server, disregarding the failed job.
235
259
  await checkNetJob(
@@ -241,7 +265,7 @@ const checkNetJob = async (servers, serverIndex, isForever, interval, noJobCount
241
265
  catch(error) {
242
266
  // Report it.
243
267
  console.log(
244
- `ERROR: ${reportLogStart}status ${repResponse.statusCode}, error message ${error.message}, and response ${content.slice(0, 1000)}`
268
+ `ERROR: ${reportLogStart}status ${repResponse.statusCode}, error message ${error.message}, and response ${content.slice(0, 1000)}\n`
245
269
  );
246
270
  // Check the next server, disregarding the failed job.
247
271
  await checkNetJob(
@@ -253,7 +277,7 @@ const checkNetJob = async (servers, serverIndex, isForever, interval, noJobCount
253
277
  // If the report submission throws an error:
254
278
  .on('error', async error => {
255
279
  // Report this.
256
- console.log(`ERROR: ${reportLogStart}error message ${error.message}`);
280
+ console.log(`ERROR: ${reportLogStart}error message ${error.message}\n`);
257
281
  // Check the next server, disregarding the failed job.
258
282
  await checkNetJob(servers, serverIndex + 1, isForever, interval, noJobCount + 1);
259
283
  })
@@ -336,6 +360,7 @@ exports.dirWatch = async (isForever, interval = 300) => {
336
360
  };
337
361
  // Checks for a network job, performs it, and submits a report, once or repeatedly.
338
362
  exports.netWatch = async (isForever, interval = 300) => {
363
+ console.log('Starting netWatch');
339
364
  // If the servers to be checked are valid:
340
365
  const servers = jobURLs
341
366
  .split('+')
package/call-old.js DELETED
@@ -1,86 +0,0 @@
1
- /*
2
- call.js
3
- Invokes Testaro modules with arguments.
4
- This is the universal module for use of Testaro from a command line.
5
- Arguments:
6
- 0. function to execute.
7
- 1+. arguments to pass to the function.
8
- Usage examples:
9
- node call run ts25
10
- node call watch true true 30
11
- */
12
-
13
- // ########## IMPORTS
14
-
15
- // Module to keep secrets.
16
- require('dotenv').config();
17
- // Module to process files.
18
- const fs = require('fs/promises');
19
- // Function to process a testing request.
20
- const {doJob} = require('./run');
21
- // Function to watch for jobs.
22
- const {watch} = require('./watch');
23
-
24
- // ########## CONSTANTS
25
-
26
- const fn = process.argv[2];
27
- const fnArgs = process.argv.slice(3);
28
- const jobDir = process.env.JOBDIR;
29
- const todoDir = `${jobDir}/todo`;
30
- const reportDir = process.env.REPORTDIR;
31
- const rawDir = `${reportDir}/raw`;
32
-
33
- // ########## FUNCTIONS
34
-
35
- // Fulfills a testing request.
36
- const callRun = async jobIDStart => {
37
- // Find the job.
38
- const jobDirFileNames = await fs.readdir(todoDir);
39
- const jobFileName = jobDirFileNames.find(fileName => fileName.startsWith(jobIDStart));
40
- // If it exists:
41
- if (jobFileName) {
42
- // Get it.
43
- const jobJSON = await fs.readFile(`${todoDir}/${jobFileName}`, 'utf8');
44
- const report = JSON.parse(jobJSON);
45
- // Run it.
46
- await doJob(report);
47
- // Archive it.
48
- await fs.rename(`${todoDir}/${jobFileName}`, `${jobDir}/done/${jobFileName}`);
49
- // Save the report.
50
- await fs.writeFile(`${rawDir}/${jobFileName}`, JSON.stringify(report, null, 2));
51
- console.log(`Job completed and report ${report.id}.json saved in ${rawDir}`);
52
- }
53
- // Otherwise, i.e. if the job does not exist.
54
- else {
55
- // Report the error.
56
- console.log(`ERROR: No to-do job ID starts with ${jobIDStart}`);
57
- }
58
- };
59
- // Starts a watch.
60
- const callWatch = async (isDirWatch, interval) => {
61
- const whenType = interval > -1 ? 'repeating' : 'one-time';
62
- const whereType = isDirWatch === 'true' ? 'directory' : 'network';
63
- console.log(`Starting ${whenType} ${whereType} watch`);
64
- await watch(isDirWatch === 'true', Number.parseInt(interval, 10));
65
- };
66
-
67
- // ########## OPERATION
68
-
69
- // Execute the requested function.
70
- if (fn === 'run' && fnArgs.length === 1) {
71
- callRun(fnArgs)
72
- .then(() => {
73
- console.log('Execution completed\n');
74
- process.exit(0);
75
- });
76
- }
77
- else if (fn === 'watch' && fnArgs.length === 2) {
78
- callWatch(... fnArgs)
79
- .then(() => {
80
- console.log('Execution completed\n');
81
- process.exit(0);
82
- });
83
- }
84
- else {
85
- console.log('ERROR: Invalid statement');
86
- }
package/procs/allText.js DELETED
@@ -1,76 +0,0 @@
1
- // Returns the text associated with an element.
2
- exports.allText = async (page, elementHandle) => await page.evaluate(element => {
3
- // Identify the element, if specified, or else the focused element.
4
- const el = element || document.activeElement;
5
- // Initialize an array of its texts.
6
- const texts = [];
7
- // FUNCTION DEFINITION START
8
- // Removes excess spacing from a string.
9
- const debloat = text => text.trim().replace(/\s+/g, ' ');
10
- // FUNCTION DEFINITION END
11
- // Add any attribute label to the array.
12
- const ariaLabel = el.getAttribute('aria-label');
13
- if (ariaLabel) {
14
- const trimmedLabel = debloat(ariaLabel);
15
- if (trimmedLabel) {
16
- texts.push(trimmedLabel);
17
- }
18
- }
19
- // Add any explicit and implicit labels to the array.
20
- const labelNodeList = el.labels;
21
- if (labelNodeList && labelNodeList.length) {
22
- const labels = Array.from(labelNodeList);
23
- const labelTexts = labels
24
- .map(label => label.textContent && debloat(label.textContent))
25
- .filter(text => text);
26
- if (labelTexts.length) {
27
- texts.push(...labelTexts);
28
- }
29
- }
30
- // Add any referenced labels to the array.
31
- if (el.hasAttribute('aria-labelledby')) {
32
- const labelerIDs = el.getAttribute('aria-labelledby').split(/\s+/);
33
- labelerIDs.forEach(id => {
34
- const labeler = document.getElementById(id);
35
- if (labeler) {
36
- const labelerText = debloat(labeler.textContent);
37
- if (labelerText) {
38
- texts.push(labelerText);
39
- }
40
- }
41
- });
42
- }
43
- // Add any image text alternatives to the array.
44
- const altTexts = Array
45
- .from(element.querySelectorAll('img[alt]:not([alt=""])'))
46
- .map(img => debloat(img.alt))
47
- .join('; ');
48
- if (altTexts.length) {
49
- texts.push(altTexts);
50
- }
51
- // Add the first 100 characters of any text content of the element to the array.
52
- const ownText = element.textContent;
53
- if (ownText) {
54
- const minText = debloat(ownText);
55
- if (minText) {
56
- texts.push(minText.slice(0, 100));
57
- }
58
- }
59
- // Add any ID of the element to the array.
60
- const id = element.id;
61
- if (id) {
62
- texts.push(`#${id}`);
63
- }
64
- // Identify a concatenation of the texts.
65
- let textChain = texts.join('; ');
66
- // If it is empty:
67
- if (! textChain) {
68
- // Substitute the HTML of the element.
69
- textChain = `{${debloat(element.outerHTML)}}`;
70
- if (textChain === '{}') {
71
- textChain = '';
72
- }
73
- }
74
- // Return a concatenation of the texts in the array.
75
- return textChain;
76
- }, elementHandle);
package/procs/allVis.js DELETED
@@ -1,17 +0,0 @@
1
- // Makes all elements in a page visible.
2
- exports.allVis = async page => {
3
- await page.$$eval('body *', elements => {
4
- elements.forEach(element => {
5
- const styleDec = window.getComputedStyle(element);
6
- if (styleDec.display === 'none') {
7
- element.style.display = 'initial';
8
- }
9
- if (['hidden', 'collapse'].includes(styleDec.visibility)) {
10
- element.style.visibility = 'inherit';
11
- }
12
- });
13
- })
14
- .catch(error => {
15
- console.log(`ERROR making all elements visible (${error.message})`);
16
- });
17
- };
@@ -1,39 +0,0 @@
1
- /*
2
- getTextNodes
3
- Gets the text nodes of a page and their parent elements as a JSHandle.
4
- */
5
- exports.getTextNodes = async page => {
6
- // Identify the text nodes.
7
- const data = await page.evaluateHandle(() => {
8
- // Initialize the result.
9
- const data = [];
10
- // Collapse any adjacent text nodes.
11
- document.body.normalize();
12
- // Remove the irrelevant text content.
13
- const extraElements = Array.from(document.body.querySelectorAll('style, script, svg'));
14
- extraElements.forEach(element => {
15
- element.textContent = '';
16
- });
17
- // FUNCTION DEFINITION START
18
- // Returns a space-minimized copy of a string.
19
- const compact = string => string.replace(/\s+/g, ' ').trim();
20
- // FUNCTION DEFINITION END
21
- // Create a collection of the text nodes.
22
- const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
23
- let more = true;
24
- while(more) {
25
- if (walker.nextNode()) {
26
- const nodeText = walker.currentNode.nodeValue;
27
- const compactNodeText = compact(nodeText);
28
- if (compactNodeText) {
29
- data.push([nodeText, walker.currentNode.parentElement]);
30
- }
31
- }
32
- else {
33
- more = false;
34
- }
35
- }
36
- return data;
37
- });
38
- return data;
39
- };
@@ -1,54 +0,0 @@
1
- // Returns an object classifying the links in a page by layout.
2
- exports.linksByType = async page => await page.evaluateHandle(() => {
3
- // FUNCTION DEFINITIONS START
4
- // Removes spacing characters from a text.
5
- const despace = text => text.replace(/\s/g, '');
6
- // Returns whether a list is a list entirely of links.
7
- const isLinkList = list => {
8
- const listItems = Array.from(list.children);
9
- if (listItems.length > 1) {
10
- return listItems.length > 1 && listItems.every(item => {
11
- if (item.tagName === 'LI') {
12
- const {children} = item;
13
- if (children.length === 1) {
14
- const link = children[0];
15
- if (link.tagName === 'A') {
16
- const itemText = despace(item.textContent);
17
- const linkText = despace(link.textContent);
18
- return itemText.length === linkText.length;
19
- }
20
- else {
21
- return false;
22
- }
23
- }
24
- else {
25
- return false;
26
- }
27
- }
28
- else {
29
- return false;
30
- }
31
- });
32
- }
33
- else {
34
- return false;
35
- }
36
- };
37
- // FUNCTION DEFINITIONS END
38
- // Identify the list links in the page.
39
- const lists = Array.from(document.body.querySelectorAll('ul, ol'));
40
- const listLinks = [];
41
- lists.forEach(list => {
42
- if (isLinkList(list)) {
43
- listLinks.push(... Array.from(list.querySelectorAll('a')));
44
- }
45
- });
46
- // Identify the inline links in the page.
47
- const allLinks = Array.from(document.body.querySelectorAll('a'));
48
- const inlineLinks = allLinks.filter(link => ! listLinks.includes(link));
49
- // Return the data.
50
- return {
51
- adjacent: inlineLinks,
52
- list: listLinks
53
- };
54
- });
package/procs/nav.js DELETED
@@ -1,259 +0,0 @@
1
- // nav
2
-
3
- // ######## IMPORTS
4
-
5
- // Playwright package.
6
- const playwright = require('playwright');
7
-
8
- // ######## CONSTANTS
9
-
10
- // Strings in log messages indicating errors.
11
- const errorWords = [
12
- 'but not used',
13
- 'content security policy',
14
- 'deprecated',
15
- 'error',
16
- 'exception',
17
- 'expected',
18
- 'failed',
19
- 'invalid',
20
- 'missing',
21
- 'non-standard',
22
- 'not supported',
23
- 'refused',
24
- 'requires',
25
- 'sorry',
26
- 'suspicious',
27
- 'unrecognized',
28
- 'violates',
29
- 'warning'
30
- ];
31
-
32
- // ######## VARIABLES
33
-
34
- let browser;
35
-
36
- // ######## FUNCTIONS
37
-
38
- // Returns a string with any final slash removed.
39
- const deSlash = string => string.endsWith('/') ? string.slice(0, -1) : string;
40
- // Gets the script nonce from a response.
41
- const getNonce = async response => {
42
- let nonce = '';
43
- // If the response includes a content security policy:
44
- const headers = await response.allHeaders();
45
- const cspWithQuotes = headers && headers['content-security-policy'];
46
- if (cspWithQuotes) {
47
- // If it requires scripts to have a nonce:
48
- const csp = cspWithQuotes.replace(/'/g, '');
49
- const directives = csp.split(/ *; */).map(directive => directive.split(/ +/));
50
- const scriptDirective = directives.find(dir => dir[0] === 'script-src');
51
- if (scriptDirective) {
52
- const nonceSpec = scriptDirective.find(valPart => valPart.startsWith('nonce-'));
53
- if (nonceSpec) {
54
- // Return the nonce.
55
- nonce = nonceSpec.replace(/^nonce-/, '');
56
- }
57
- }
58
- }
59
- // Return the nonce, if any.
60
- return nonce;
61
- };
62
- // Visits a URL and returns the response of the server.
63
- const goTo = async (report, page, url, timeout, waitUntil) => {
64
- // If the URL is a file path:
65
- if (url.startsWith('file://')) {
66
- // Make it absolute.
67
- url = url.replace('file://', `file://${__dirname.replace(/procs$/, '')}`);
68
- }
69
- // Visit the URL.
70
- const startTime = Date.now();
71
- try {
72
- const response = await page.goto(url, {
73
- timeout,
74
- waitUntil
75
- });
76
- report.jobData.visitLatency += Math.round((Date.now() - startTime) / 1000);
77
- const httpStatus = response.status();
78
- // If the response status was normal:
79
- if ([200, 304].includes(httpStatus) || url.startsWith('file:')) {
80
- // If the browser was redirected in violation of a strictness requirement:
81
- const actualURL = page.url();
82
- if (report.strict && deSlash(actualURL) !== deSlash(url)) {
83
- // Return an error.
84
- console.log(`ERROR: Visit to ${url} redirected to ${actualURL}`);
85
- return {
86
- exception: 'badRedirection'
87
- };
88
- }
89
- // Otherwise, i.e. if no prohibited redirection occurred:
90
- else {
91
- // Press the Escape key to dismiss any modal dialog.
92
- await page.keyboard.press('Escape');
93
- // Return the result of the navigation.
94
- return {
95
- success: true,
96
- response
97
- };
98
- }
99
- }
100
- // Otherwise, i.e. if the response status was abnormal:
101
- else {
102
- // Return an error.
103
- console.log(`ERROR: Visit to ${url} got status ${httpStatus}`);
104
- report.jobData.visitRejectionCount++;
105
- return {
106
- success: false,
107
- error: 'badStatus'
108
- };
109
- }
110
- }
111
- catch(error) {
112
- console.log(`ERROR visiting ${url} (${error.message.slice(0, 200)})`);
113
- return {
114
- success: false,
115
- error: 'noVisit'
116
- };
117
- }
118
- };
119
- // Closes the current browser.
120
- const browserClose = async () => {
121
- if (browser) {
122
- let contexts = browser.contexts();
123
- for (const context of contexts) {
124
- await context.close();
125
- contexts = browser.contexts();
126
- }
127
- await browser.close();
128
- browser = null;
129
- }
130
- };
131
- // Launches a browser, navigates to a URL, and returns browser data.
132
- const launch = async (report, typeName, url, debug, waits, isLowMotion = false) => {
133
- // If the specified browser type exists:
134
- const browserType = playwright[typeName];
135
- if (browserType) {
136
- // Close the current browser, if any.
137
- await browserClose();
138
- // Launch a browser of the specified type.
139
- const browserOptions = {
140
- logger: {
141
- isEnabled: () => false,
142
- log: (name, severity, message) => console.log(message.slice(0, 100))
143
- }
144
- };
145
- if (debug) {
146
- browserOptions.headless = false;
147
- }
148
- if (waits) {
149
- browserOptions.slowMo = waits;
150
- }
151
- browser = await browserType.launch(browserOptions)
152
- // If the launch failed:
153
- .catch(async error => {
154
- console.log(`ERROR launching browser (${error.message.slice(0, 200)})`);
155
- // Return this.
156
- return {
157
- success: false,
158
- error: 'Browser launch failed'
159
- };
160
- });
161
- // Open a context (i.e. browser tab), with reduced motion if specified.
162
- const options = {reduceMotion: isLowMotion ? 'reduce' : 'no-preference'};
163
- const browserContext = await browser.newContext(options);
164
- // When a page (i.e. browser tab) is added to the browser context (i.e. browser window):
165
- browserContext.on('page', async page => {
166
- // If it emits a message:
167
- page.on('console', msg => {
168
- const msgText = msg.text();
169
- let indentedMsg = '';
170
- // If debugging is on:
171
- if (debug) {
172
- // Log a summary of the message on the console.
173
- const parts = [msgText.slice(0, 75)];
174
- if (msgText.length > 75) {
175
- parts.push(msgText.slice(75, 150));
176
- if (msgText.length > 150) {
177
- const tail = msgText.slice(150).slice(-150);
178
- if (msgText.length > 300) {
179
- parts.push('...');
180
- }
181
- parts.push(tail.slice(0, 75));
182
- if (tail.length > 75) {
183
- parts.push(tail.slice(75));
184
- }
185
- }
186
- }
187
- indentedMsg = parts.map(part => ` | ${part}`).join('\n');
188
- console.log(`\n${indentedMsg}`);
189
- }
190
- // Add statistics on the message to the report.
191
- const msgTextLC = msgText.toLowerCase();
192
- const msgLength = msgText.length;
193
- report.jobData.logCount++;
194
- report.jobData.logSize += msgLength;
195
- if (errorWords.some(word => msgTextLC.includes(word))) {
196
- report.jobData.errorLogCount++;
197
- report.jobData.errorLogSize += msgLength;
198
- }
199
- const msgLC = msgText.toLowerCase();
200
- if (
201
- msgText.includes('403') && (msgLC.includes('status')
202
- || msgLC.includes('prohibited'))
203
- ) {
204
- report.jobData.prohibitedCount++;
205
- }
206
- });
207
- });
208
- // Open the first page of the context.
209
- const page = await browserContext.newPage();
210
- try {
211
- // Wait until it is stable.
212
- await page.waitForLoadState('domcontentloaded', {timeout: 5000});
213
- // Navigate to the specified URL.
214
- const navResult = await goTo(report, page, url, 15000, 'domcontentloaded');
215
- // If the navigation succeeded:
216
- if (navResult.success) {
217
- // Update the name of the current browser type and store it in the page.
218
- page.browserTypeName = typeName;
219
- // Return the response of the target server, the browser context, and the page.
220
- return {
221
- success: true,
222
- response: navResult.response,
223
- browserContext,
224
- page
225
- };
226
- }
227
- // If the navigation failed:
228
- if (navResult.error) {
229
- // Return this.
230
- return {
231
- success: false,
232
- error: 'Navigation failed'
233
- };
234
- }
235
- }
236
- // If it fails to become stable after load:
237
- catch(error) {
238
- // Return this.
239
- console.log(`ERROR: Blank page load in new tab timed out (${error.message})`);
240
- return {
241
- success: false,
242
- error: 'Blank page load in new tab timed out'
243
- };
244
- }
245
- }
246
- // Otherwise, i.e. if it does not exist:
247
- else {
248
- // Return this.
249
- console.log(`ERROR: Browser of type ${typeName} could not be launched`);
250
- return {
251
- success: false,
252
- error: `${typeName} browser launch failed`
253
- };
254
- }
255
- };
256
- exports.browserClose = browserClose;
257
- exports.getNonce = getNonce;
258
- exports.goTo = goTo;
259
- exports.launch = launch;