testaro 60.9.0 → 60.10.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.
- package/package.json +1 -1
- package/procs/doTestAct.js +4 -10
- package/procs/identify.js +17 -11
- package/run.js +64 -62
- package/tests/testaro.js +2 -0
package/package.json
CHANGED
package/procs/doTestAct.js
CHANGED
|
@@ -39,19 +39,12 @@ const os = require('os');
|
|
|
39
39
|
|
|
40
40
|
// CONSTANTS
|
|
41
41
|
|
|
42
|
-
const headedBrowser = process.env.HEADED_BROWSER === 'true';
|
|
43
|
-
const debug = process.env.DEBUG === 'true';
|
|
44
|
-
const waits = Number.parseInt(process.env.WAITS) || 0;
|
|
45
42
|
const tmpDir = os.tmpdir();
|
|
46
43
|
|
|
47
|
-
// VARIABLES
|
|
48
|
-
|
|
49
|
-
const actIndex = Number.parseInt(process.argv[2]);
|
|
50
|
-
|
|
51
44
|
// FUNCTIONS
|
|
52
45
|
|
|
53
46
|
// Performs the tests of the act specified by the caller.
|
|
54
|
-
const doTestAct = async
|
|
47
|
+
const doTestAct = async actIndex => {
|
|
55
48
|
const reportPath = `${tmpDir}/report.json`;
|
|
56
49
|
// Get the report from the temporary directory.
|
|
57
50
|
const reportJSON = await fs.readFile(reportPath, 'utf8');
|
|
@@ -68,6 +61,7 @@ const doTestAct = async () => {
|
|
|
68
61
|
// Launch a browser, navigate to the URL, and update the run-module page export.
|
|
69
62
|
await launch(
|
|
70
63
|
report,
|
|
64
|
+
actIndex,
|
|
71
65
|
'high',
|
|
72
66
|
browserID,
|
|
73
67
|
targetURL
|
|
@@ -88,7 +82,7 @@ const doTestAct = async () => {
|
|
|
88
82
|
page = require('../run').page;
|
|
89
83
|
}
|
|
90
84
|
}
|
|
91
|
-
// If the page exists:
|
|
85
|
+
// If the page exists or the tool is Testaro:
|
|
92
86
|
if (page || which === 'testaro') {
|
|
93
87
|
try {
|
|
94
88
|
// Make the act reporter perform the specified tests of the tool.
|
|
@@ -142,4 +136,4 @@ const doTestAct = async () => {
|
|
|
142
136
|
}
|
|
143
137
|
};
|
|
144
138
|
|
|
145
|
-
doTestAct();
|
|
139
|
+
doTestAct(Number.parseInt(process.argv[2]));
|
package/procs/identify.js
CHANGED
|
@@ -30,9 +30,7 @@
|
|
|
30
30
|
// IMPORTS
|
|
31
31
|
|
|
32
32
|
// Module to get the XPath of an element.
|
|
33
|
-
const
|
|
34
|
-
xPath: require('playwright-dompath').xPath
|
|
35
|
-
};
|
|
33
|
+
const {xPath} = require('playwright-dompath');
|
|
36
34
|
|
|
37
35
|
// FUNCTIONS
|
|
38
36
|
|
|
@@ -42,7 +40,7 @@ const boxOf = exports.boxOf = async locator => {
|
|
|
42
40
|
const isVisible = await locator.isVisible();
|
|
43
41
|
if (isVisible) {
|
|
44
42
|
const box = await locator.boundingBox({
|
|
45
|
-
timeout:
|
|
43
|
+
timeout: 100
|
|
46
44
|
});
|
|
47
45
|
if (box) {
|
|
48
46
|
Object.keys(box).forEach(dim => {
|
|
@@ -72,22 +70,30 @@ const boxToString = exports.boxToString = box => {
|
|
|
72
70
|
}
|
|
73
71
|
};
|
|
74
72
|
// Adds a box ID and a path ID to an object.
|
|
75
|
-
const addIDs = async (
|
|
73
|
+
const addIDs = async (locator, recipient) => {
|
|
74
|
+
const locatorCount = await locator.count();
|
|
76
75
|
// If there is exactly 1 of them:
|
|
77
|
-
const locatorCount = await locators.count();
|
|
78
76
|
if (locatorCount === 1) {
|
|
79
77
|
// Add the box ID of the element to the result if none exists yet.
|
|
80
78
|
if (! recipient.boxID) {
|
|
81
|
-
const box = await boxOf(
|
|
79
|
+
const box = await boxOf(locator);
|
|
82
80
|
recipient.boxID = boxToString(box);
|
|
83
81
|
}
|
|
84
82
|
// If the element has no path ID yet in the result:
|
|
85
83
|
if (! recipient.pathID) {
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
let timeout;
|
|
85
|
+
const timer = new Promise(resolve => {
|
|
86
|
+
timeout = setTimeout(() => {
|
|
87
|
+
resolve({timedOut: true})
|
|
88
|
+
clearTimeout(timeout);
|
|
89
|
+
}, 500);
|
|
90
|
+
});
|
|
91
|
+
// Use Playwright to get the XPath.
|
|
92
|
+
const pathIDPromise = xPath(locator);
|
|
93
|
+
const pathID = await Promise.race([pathIDPromise, timer]);
|
|
94
|
+
// If the XPath was computed:
|
|
90
95
|
if (typeof pathID === 'string') {
|
|
96
|
+
// Add it to the result.
|
|
91
97
|
recipient.pathID = pathID;
|
|
92
98
|
}
|
|
93
99
|
}
|
package/run.js
CHANGED
|
@@ -111,7 +111,6 @@ const tmpDir = os.tmpdir();
|
|
|
111
111
|
// Facts about the current session.
|
|
112
112
|
let actCount = 0;
|
|
113
113
|
// Facts about the current act.
|
|
114
|
-
let actIndex = 0;
|
|
115
114
|
let browser;
|
|
116
115
|
let cleanupInProgress = false;
|
|
117
116
|
let browserCloseIntentional = false;
|
|
@@ -290,9 +289,9 @@ const browserClose = exports.browserClose = async () => {
|
|
|
290
289
|
};
|
|
291
290
|
// Launches a browser and navigates to a URL.
|
|
292
291
|
const launch = exports.launch = async (
|
|
293
|
-
report, headEmulation, tempBrowserID, tempURL, retries = 2
|
|
292
|
+
report, actIndex, headEmulation, tempBrowserID, tempURL, retries = 2
|
|
294
293
|
) => {
|
|
295
|
-
const act = report.acts[actIndex];
|
|
294
|
+
const act = report.acts[actIndex] || {};
|
|
296
295
|
const {device} = report;
|
|
297
296
|
const deviceID = device && device.id;
|
|
298
297
|
const browserID = tempBrowserID || report.browserID || '';
|
|
@@ -435,12 +434,8 @@ const launch = exports.launch = async (
|
|
|
435
434
|
page = await browserContext.newPage();
|
|
436
435
|
// Wait until it is stable.
|
|
437
436
|
await page.waitForLoadState('domcontentloaded', {timeout: 5000});
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
await page.addInitScript({path: require.resolve('./dist/nameComputation.js')});
|
|
441
|
-
// Add a script to the page to:
|
|
442
|
-
await page.addInitScript(isTestaroTest => {
|
|
443
|
-
// Mask automation detection.
|
|
437
|
+
// Add a script to the page to mask automation detection.
|
|
438
|
+
await page.addInitScript(() => {
|
|
444
439
|
Object.defineProperty(navigator, 'webdriver', {get: () => undefined});
|
|
445
440
|
window.chrome = {runtime: {}};
|
|
446
441
|
Object.defineProperty(navigator, 'plugins', {
|
|
@@ -449,8 +444,60 @@ const launch = exports.launch = async (
|
|
|
449
444
|
Object.defineProperty(navigator, 'languages', {
|
|
450
445
|
get: () => ['en-US', 'en']
|
|
451
446
|
});
|
|
452
|
-
|
|
453
|
-
|
|
447
|
+
});
|
|
448
|
+
const isTestaroTest = act.type === 'test' && act.which === 'testaro';
|
|
449
|
+
// If the launch is for a testaro test act:
|
|
450
|
+
if (isTestaroTest) {
|
|
451
|
+
// Add a script to the page to add a window method to get the XPath of an element.
|
|
452
|
+
await page.addInitScript(() => {
|
|
453
|
+
window.getXPath = element => {
|
|
454
|
+
if (! element || element.nodeType !== Node.ELEMENT_NODE) {
|
|
455
|
+
return '';
|
|
456
|
+
}
|
|
457
|
+
const segments = [];
|
|
458
|
+
// As long as the current node is an element:
|
|
459
|
+
while (element && element.nodeType === Node.ELEMENT_NODE) {
|
|
460
|
+
const tag = element.tagName.toLowerCase();
|
|
461
|
+
// If it is the html element:
|
|
462
|
+
if (element === document.documentElement) {
|
|
463
|
+
// Prepend it to the segment array
|
|
464
|
+
segments.unshift('html');
|
|
465
|
+
// Stop traversing.
|
|
466
|
+
break;
|
|
467
|
+
}
|
|
468
|
+
// Otherwise, get its parent node.
|
|
469
|
+
const parent = element.parentNode;
|
|
470
|
+
// If (abnormally) the parent node is not an element:
|
|
471
|
+
if (!parent || parent.nodeType !== Node.ELEMENT_NODE) {
|
|
472
|
+
// Prepend it to the segment array.
|
|
473
|
+
segments.unshift(tag);
|
|
474
|
+
// Stop traversing, leaving the segment array partial.
|
|
475
|
+
break;
|
|
476
|
+
}
|
|
477
|
+
let subscript = '';
|
|
478
|
+
// Get the subscript of the element.
|
|
479
|
+
const cohort = Array
|
|
480
|
+
.from(parent.childNodes)
|
|
481
|
+
.filter(
|
|
482
|
+
childNode => childNode.nodeType === Node.ELEMENT_NODE
|
|
483
|
+
&& childNode.tagName === element.tagName
|
|
484
|
+
);
|
|
485
|
+
if (cohort.length > 1) {
|
|
486
|
+
subscript = `[${cohort.indexOf(element) + 1}]`;
|
|
487
|
+
}
|
|
488
|
+
// Prepend the element identifier to the segment array.
|
|
489
|
+
segments.unshift(`${tag}${subscript}`);
|
|
490
|
+
// Continue the traversal with the parent of the current element.
|
|
491
|
+
element = parent;
|
|
492
|
+
}
|
|
493
|
+
// Return the XPath.
|
|
494
|
+
return `/${segments.join('/')}`;
|
|
495
|
+
};
|
|
496
|
+
});
|
|
497
|
+
// Add a script to the page to compute the accessible name of an element.
|
|
498
|
+
await page.addInitScript({path: require.resolve('./dist/nameComputation.js')});
|
|
499
|
+
// Add a script to the page to:
|
|
500
|
+
await page.addInitScript(() => {
|
|
454
501
|
// Add a window method to compute the accessible name of an element.
|
|
455
502
|
window.getAccessibleName = element => {
|
|
456
503
|
const nameIsComputable = element
|
|
@@ -514,54 +561,8 @@ const launch = exports.launch = async (
|
|
|
514
561
|
pathID: ''
|
|
515
562
|
};
|
|
516
563
|
};
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
if (!element || element.nodeType !== Node.ELEMENT_NODE) {
|
|
520
|
-
return '';
|
|
521
|
-
}
|
|
522
|
-
const segments = [];
|
|
523
|
-
let el = element;
|
|
524
|
-
// As long as the current node is an element:
|
|
525
|
-
while (el && el.nodeType === Node.ELEMENT_NODE) {
|
|
526
|
-
const tag = el.tagName.toLowerCase();
|
|
527
|
-
// If it is the html element:
|
|
528
|
-
if (el === document.documentElement) {
|
|
529
|
-
// Prepend it to the segment array
|
|
530
|
-
segments.unshift('html');
|
|
531
|
-
// Stop traversing.
|
|
532
|
-
break;
|
|
533
|
-
}
|
|
534
|
-
// Otherwise, get its parent node.
|
|
535
|
-
const parent = el.parentNode;
|
|
536
|
-
// If (abnormally) the parent node is not an element:
|
|
537
|
-
if (!parent || parent.nodeType !== Node.ELEMENT_NODE) {
|
|
538
|
-
// Prepend it to the segment array.
|
|
539
|
-
segments.unshift(tag);
|
|
540
|
-
// Stop traversing, leaving the segment array partial.
|
|
541
|
-
break;
|
|
542
|
-
}
|
|
543
|
-
let subscript = '';
|
|
544
|
-
let sameTagCount = 0;
|
|
545
|
-
// Get the subscript of the element.
|
|
546
|
-
const cohort = Array
|
|
547
|
-
.from(parent.childNodes)
|
|
548
|
-
.filter(
|
|
549
|
-
childNode => childNode.nodeType === Node.ELEMENT_NODE
|
|
550
|
-
&& childNode.tagName === el.tagName
|
|
551
|
-
);
|
|
552
|
-
if (cohort.length > 1) {
|
|
553
|
-
subscript = `[${cohort.indexOf(el) + 1}]`;
|
|
554
|
-
}
|
|
555
|
-
// Prepend the element identifier to the segment array.
|
|
556
|
-
segments.unshift(`${tag}${subscript}`);
|
|
557
|
-
// Continue the traversal with the parent of the current element.
|
|
558
|
-
el = parent;
|
|
559
|
-
}
|
|
560
|
-
// Return the XPath.
|
|
561
|
-
return `/${segments.join('/')}`;
|
|
562
|
-
};
|
|
563
|
-
}
|
|
564
|
-
}, isTestaroTest);
|
|
564
|
+
});
|
|
565
|
+
}
|
|
565
566
|
// Navigate to the specified URL.
|
|
566
567
|
const navResult = await goTo(report, page, url, 15000, 'domcontentloaded');
|
|
567
568
|
// If the navigation succeeded:
|
|
@@ -603,7 +604,7 @@ const launch = exports.launch = async (
|
|
|
603
604
|
);
|
|
604
605
|
await wait(1000 * waitSeconds + 100);
|
|
605
606
|
// Then retry the launch and navigation.
|
|
606
|
-
return launch(report, headEmulation, tempBrowserID, tempURL, retries - 1);
|
|
607
|
+
return launch(report, actIndex, headEmulation, tempBrowserID, tempURL, retries - 1);
|
|
607
608
|
}
|
|
608
609
|
// Otherwise, i.e. if no retries remain:
|
|
609
610
|
else {
|
|
@@ -828,9 +829,8 @@ const doActs = async (report, opts = {}) => {
|
|
|
828
829
|
const standard = report.standard || 'only';
|
|
829
830
|
const reportPath = `${tmpDir}/report.json`;
|
|
830
831
|
// For each act in the report.
|
|
831
|
-
for (const
|
|
832
|
+
for (const actIndex in acts) {
|
|
832
833
|
if (signal && signal.aborted) throw new Error('doActs aborted');
|
|
833
|
-
actIndex = doActsIndex;
|
|
834
834
|
// If the job has not been aborted:
|
|
835
835
|
if (report.jobData && ! report.jobData.aborted) {
|
|
836
836
|
let act = acts[actIndex];
|
|
@@ -908,6 +908,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
908
908
|
// Launch a browser, navigate to a page, and add the result to the act.
|
|
909
909
|
await launch(
|
|
910
910
|
report,
|
|
911
|
+
actIndex,
|
|
911
912
|
'high',
|
|
912
913
|
actLaunchSpecs[0],
|
|
913
914
|
actLaunchSpecs[1]
|
|
@@ -1658,6 +1659,7 @@ const doActs = async (report, opts = {}) => {
|
|
|
1658
1659
|
// Replace the browser and navigate to the URL.
|
|
1659
1660
|
await launch(
|
|
1660
1661
|
report,
|
|
1662
|
+
'standardization',
|
|
1661
1663
|
'high',
|
|
1662
1664
|
specs[0],
|
|
1663
1665
|
specs[1]
|
package/tests/testaro.js
CHANGED
|
@@ -552,6 +552,7 @@ exports.reporter = async (page, report, actIndex) => {
|
|
|
552
552
|
// Replace the browser and the page and navigate to the target.
|
|
553
553
|
await launch(
|
|
554
554
|
report,
|
|
555
|
+
actIndex,
|
|
555
556
|
headEmulation,
|
|
556
557
|
browserID,
|
|
557
558
|
url
|
|
@@ -663,6 +664,7 @@ exports.reporter = async (page, report, actIndex) => {
|
|
|
663
664
|
// Replace the browser and the page in the run module and navigate to the target.
|
|
664
665
|
await launch(
|
|
665
666
|
report,
|
|
667
|
+
actIndex,
|
|
666
668
|
headEmulation,
|
|
667
669
|
report.browserID,
|
|
668
670
|
url
|