testilo 7.1.1 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,64 @@
1
+ /*
2
+ validate.js
3
+ Validates digest module.
4
+ */
5
+
6
+ // ########## IMPORTS
7
+
8
+ // Function to process files.
9
+ const fs = require('fs/promises');
10
+ // Function to digest reports.
11
+ const {digest} = require('../../digest');
12
+ // Digesting function.
13
+ const {digester} = require('./digester');
14
+
15
+ // ########## FUNCTIONS
16
+
17
+ // Validates the digest module.
18
+ const validate = async () => {
19
+ // Get the report.
20
+ const reportJSON = await fs.readFile(`${__dirname}/report.json`, 'utf8');
21
+ const scoredReport = JSON.parse(reportJSON);
22
+ // Get the digest template.
23
+ const digestTemplate = await fs.readFile(`${__dirname}/digest.html`, 'utf8');
24
+ // Perform the digesting.
25
+ const digests = digest(digestTemplate, digester, [scoredReport]);
26
+ // Validate the digest.
27
+ if (Array.isArray(digests) && digests.length === 1) {
28
+ console.log('Success: The count of digests is correct');
29
+ }
30
+ else {
31
+ console.log('ERROR: The digests are not an array of length 1');
32
+ return;
33
+ }
34
+ const digestedReport = digests[0];
35
+ if (typeof digestedReport === 'string') {
36
+ console.log('Success: Digesting left the digest a string');
37
+ }
38
+ else {
39
+ console.log('ERROR: Digesting changed the digest type');
40
+ return;
41
+ }
42
+ if (digestedReport.includes('<h2>Introduction</h2>')) {
43
+ console.log('Success: Digesting left the static template content unchanged');
44
+ }
45
+ else {
46
+ console.log('ERROR: Digesting changed the static template content');
47
+ return;
48
+ }
49
+ if (digestedReport.includes('the web page of Example')) {
50
+ console.log('Success: Digesting interpolated the target correctly');
51
+ }
52
+ else {
53
+ console.log('ERROR: Digesting did not interpolate the target correctly');
54
+ return;
55
+ }
56
+ if (digestedReport.includes('count of tests was 1')) {
57
+ console.log('Success: Digesting interpolated the score correctly');
58
+ }
59
+ else {
60
+ console.log('ERROR: Digesting did not interpolate the score correctly');
61
+ return;
62
+ }
63
+ };
64
+ validate();
@@ -0,0 +1,43 @@
1
+ {
2
+ "id": "batch",
3
+ "what": "merge validation",
4
+ "targets": [
5
+ {
6
+ "id": "example",
7
+ "what": "Example",
8
+ "acts": {
9
+ "main": [
10
+ {
11
+ "type": "launch"
12
+ },
13
+ {
14
+ "type": "url",
15
+ "which": "https://example.com",
16
+ "what": "example"
17
+ }
18
+ ]
19
+ }
20
+ },
21
+ {
22
+ "id": "accordionexample",
23
+ "what": "Example of expanded accordion",
24
+ "acts": {
25
+ "main": [
26
+ {
27
+ "type": "launch"
28
+ },
29
+ {
30
+ "type": "url",
31
+ "which": "https://www.w3.org/WAI/ARIA/apg/example-index/accordion/accordion",
32
+ "what": "Accordion Example"
33
+ },
34
+ {
35
+ "type": "button",
36
+ "which": "Billing Address",
37
+ "what": "expand accordion"
38
+ }
39
+ ]
40
+ }
41
+ }
42
+ ]
43
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "id": "script",
3
+ "what": "merge validation",
4
+ "strict": false,
5
+ "timeLimit": 40,
6
+ "acts": [
7
+ {
8
+ "type": "placeholder",
9
+ "which": "main",
10
+ "launch": "webkit"
11
+ },
12
+ {
13
+ "type": "test",
14
+ "which": "continuum",
15
+ "what": "Continuum"
16
+ },
17
+ {
18
+ "type": "placeholder",
19
+ "which": "main",
20
+ "launch": "chromium"
21
+ },
22
+ {
23
+ "type": "test",
24
+ "which": "focAll",
25
+ "what": "Tab-focusability"
26
+ },
27
+ {
28
+ "type": "test",
29
+ "which": "bulk",
30
+ "what": "count of visible elements"
31
+ }
32
+ ]
33
+ }
@@ -0,0 +1,179 @@
1
+ /*
2
+ validate.js
3
+ Validates merge module.
4
+ */
5
+
6
+ // ########## IMPORTS
7
+
8
+ // Function to process files.
9
+ const fs = require('fs/promises');
10
+ // Function to merge a batch and a script.
11
+ const {merge} = require('../../merge');
12
+
13
+ // ########## FUNCTIONS
14
+
15
+ // Validates the merge module.
16
+ const validate = async () => {
17
+ // Get the script and the batch.
18
+ const scriptJSON = await fs.readFile(`${__dirname}/script.json`, 'utf8');
19
+ const script = JSON.parse(scriptJSON);
20
+ const batchJSON = await fs.readFile(`${__dirname}/batch.json`);
21
+ const batch = JSON.parse(batchJSON);
22
+ const requester = 'me@mydomain.tld';
23
+ // Perform the merger without and with isolation.
24
+ const jobsNoIsolation = merge(script, batch, requester, false);
25
+ const jobsYesIsolation = merge(script, batch, requester, true);
26
+ const jobArrays = [jobsNoIsolation, jobsYesIsolation];
27
+ // Validate the jobs.
28
+ if (jobsNoIsolation && jobsYesIsolation) {
29
+ console.log('Success: Both job arrays exist');
30
+ }
31
+ else {
32
+ console.log('ERROR: A job array does not exist');
33
+ return;
34
+ }
35
+ if (
36
+ jobArrays.every(array => [0, 1].every(jobIndex => Object.keys(array[jobIndex]).length === 8))
37
+ ) {
38
+ console.log('Success: Every job has 8 properties');
39
+ }
40
+ else {
41
+ console.log('ERROR: A job does not have 8 properties');
42
+ return;
43
+ }
44
+ if (jobArrays.every(array => [0, 1].every(
45
+ jobIndex => {
46
+ const job = array[jobIndex];
47
+ return job.id === `${job.timeStamp}-${job.sources.script}-${job.sources.target.id}`;
48
+ }
49
+ ))) {
50
+ console.log('Success: Every job has a correct ID');
51
+ }
52
+ else {
53
+ console.log('ERROR: A job does not have a correct ID');
54
+ return;
55
+ }
56
+ if (jobArrays.every(array => [0, 1].every(jobIndex => array[jobIndex].what === script.what))) {
57
+ console.log('Success: Every job has a correct what property');
58
+ }
59
+ else {
60
+ console.log('ERROR: A job does not have a correct what property');
61
+ return;
62
+ }
63
+ if (jobArrays.every(array => [0, 1].every(jobIndex => array[jobIndex].strict === script.strict))) {
64
+ console.log('Success: Every job has a correct strict property');
65
+ }
66
+ else {
67
+ console.log('ERROR: A job does not have a correct strict property');
68
+ return;
69
+ }
70
+ if (jobArrays.every(
71
+ array => [0, 1].every(jobIndex => array[jobIndex].timeLimit === script.timeLimit)
72
+ )) {
73
+ console.log('Success: Every job has a correct timeLimit property');
74
+ }
75
+ else {
76
+ console.log('ERROR: A job does not have a correct timeLimit property');
77
+ return;
78
+ }
79
+ if (jobArrays.every(
80
+ array => [0, 1].every(jobIndex => array[jobIndex].sources.script === script.id)
81
+ )) {
82
+ console.log('Success: Every job has a correct sources.script property');
83
+ }
84
+ else {
85
+ console.log('ERROR: A job does not have a correct sources.script property');
86
+ return;
87
+ }
88
+ if (jobArrays.every(
89
+ array => [0, 1].every(jobIndex => array[jobIndex].sources.batch === batch.id)
90
+ )) {
91
+ console.log('Success: Every job has a correct sources.batch property');
92
+ }
93
+ else {
94
+ console.log('ERROR: A job does not have a correct sources.batch property');
95
+ return;
96
+ }
97
+ if (jobArrays.every(array => [0, 1].every(
98
+ jobIndex => array[jobIndex].sources.target.id === batch.targets[jobIndex].id
99
+ ))) {
100
+ console.log('Success: Every job has a correct sources.target.id property');
101
+ }
102
+ else {
103
+ console.log('ERROR: A job does not have a correct sources.target.id property');
104
+ return;
105
+ }
106
+ if (jobArrays.every(array => [0, 1].every(
107
+ jobIndex => array[jobIndex].sources.target.what === batch.targets[jobIndex].what
108
+ ))) {
109
+ console.log('Success: Every job has a correct sources.target.what property');
110
+ }
111
+ else {
112
+ console.log('ERROR: A job does not have a correct sources.target.what property');
113
+ return;
114
+ }
115
+ if (jobArrays.every(
116
+ array => [0, 1].every(jobIndex => array[jobIndex].sources.requester === requester)
117
+ )) {
118
+ console.log('Success: Every job has a correct sources.requester property');
119
+ }
120
+ else {
121
+ console.log('ERROR: A job does not have a correct sources.requester property');
122
+ return;
123
+ }
124
+ if (jobArrays.every(array => [0, 1].every(
125
+ jobIndex => /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$/.test(array[jobIndex].creationTime)
126
+ ))) {
127
+ console.log('Success: Every job has a valid creationTime property');
128
+ }
129
+ else {
130
+ console.log('ERROR: A job does not have a valid creationTime property');
131
+ return;
132
+ }
133
+ if (
134
+ jobArrays[0][0].acts.length === 7
135
+ && jobArrays[0][1].acts.length === 9
136
+ && jobArrays[1][0].acts.length === 9
137
+ && jobArrays[1][1].acts.length === 12
138
+ ) {
139
+ console.log('Success: Every job has a correct act count');
140
+ }
141
+ else {
142
+ console.log('ERROR: A job does not have a correct act count');
143
+ return;
144
+ }
145
+ const job00Act0 = jobArrays[0][0].acts[0];
146
+ if (
147
+ job00Act0.type === 'launch'
148
+ && job00Act0.which === script.acts[0].launch
149
+ ) {
150
+ console.log('Success: Job 0 of array 0 has a correct act 0');
151
+ }
152
+ else {
153
+ console.log('ERROR: Job 0 of array 0 has an incorrect act 0');
154
+ return;
155
+ }
156
+ const job01Act3 = jobArrays[0][1].acts[3];
157
+ if (
158
+ job01Act3.type === 'test'
159
+ && job01Act3.which === 'continuum'
160
+ ) {
161
+ console.log('Success: Job 1 of array 0 has correct act 3 type and which properties');
162
+ }
163
+ else {
164
+ console.log('ERROR: Job 1 of array 0 has an incorrect act 3 type or which property');
165
+ return;
166
+ }
167
+ const job10Act7 = jobArrays[1][0].acts[7];
168
+ if (
169
+ job10Act7.type === 'url'
170
+ && job10Act7.what === 'example'
171
+ ) {
172
+ console.log('Success: Job 0 of array 1 has correct act 7 type and what properties');
173
+ }
174
+ else {
175
+ console.log('ERROR: Job 1 of array 0 has an incorrect act 7 type or what property');
176
+ return;
177
+ }
178
+ };
179
+ validate();
@@ -0,0 +1,75 @@
1
+ {
2
+ "id": "report",
3
+ "what": "Report for scoring validation",
4
+ "strict": true,
5
+ "timeLimit": 10,
6
+ "acts": [
7
+ {
8
+ "type": "launch",
9
+ "which": "chromium",
10
+ "what": "Chromium browser",
11
+ "startTime": 1662474496075,
12
+ "endTime": 1662474496453
13
+ },
14
+ {
15
+ "type": "url",
16
+ "which": "https://example.com",
17
+ "what": "Example of web page",
18
+ "startTime": 1662474496453,
19
+ "result": "https://example.com",
20
+ "endTime": 1662474501684
21
+ },
22
+ {
23
+ "type": "test",
24
+ "which": "bulk",
25
+ "what": "count of visible elements",
26
+ "startTime": 1662474501684,
27
+ "url": "https://example.com",
28
+ "result": {
29
+ "visibleElements": 100,
30
+ "success": true
31
+ },
32
+ "endTime": 1662474501866
33
+ }
34
+ ],
35
+ "sources": {
36
+ "script": "script",
37
+ "batch": "batch",
38
+ "target": {
39
+ "id": "example",
40
+ "what": "Example of web page"
41
+ },
42
+ "requester": "user@domain.tld"
43
+ },
44
+ "creationTime": "2023-11-20T15:50:27",
45
+ "timeStamp": "cc3pl",
46
+ "jobData": {
47
+ "log": [
48
+ {
49
+ "event": "startTime",
50
+ "value": "2022-09-06T14:27:55"
51
+ },
52
+ {
53
+ "event": "endTime",
54
+ "value": "2022-09-06T14:30:47"
55
+ }
56
+ ],
57
+ "timeStamp": "5lezg",
58
+ "testTimes": [
59
+ [
60
+ "bulk",
61
+ 0
62
+ ]
63
+ ],
64
+ "logCount": 10,
65
+ "logSize": 100,
66
+ "errorLogCount": 1,
67
+ "errorLogSize": 10,
68
+ "prohibitedCount": 0,
69
+ "visitTimeoutCount": 0,
70
+ "visitRejectionCount": 0,
71
+ "visitLatency": 3,
72
+ "endTime": "2022-09-06T14:30:47",
73
+ "elapsedSeconds": 5
74
+ }
75
+ }
@@ -0,0 +1,17 @@
1
+ /*
2
+ scorer
3
+ score validation
4
+ */
5
+
6
+ // Scores a report.
7
+ exports.scorer = report => {
8
+ // If there are any acts in the report:
9
+ const {acts} = report;
10
+ if (Array.isArray(acts)) {
11
+ // Add a score, consisting of the test count.
12
+ const testActs = acts.filter(act => act.type === 'test');
13
+ report.score = {
14
+ testCount: testActs.length
15
+ };
16
+ }
17
+ };
@@ -0,0 +1,62 @@
1
+ /*
2
+ validate.js
3
+ Validates score module.
4
+ */
5
+
6
+ // ########## IMPORTS
7
+
8
+ // Function to process files.
9
+ const fs = require('fs/promises');
10
+ // Function to score reports.
11
+ const {score} = require('../../score');
12
+ // Scoring function.
13
+ const {scorer} = require('./scorer');
14
+
15
+ // ########## FUNCTIONS
16
+
17
+ // Validates the score module.
18
+ const validate = async () => {
19
+ // Get the report.
20
+ const reportJSON = await fs.readFile(`${__dirname}/report.json`, 'utf8');
21
+ const rawReport = JSON.parse(reportJSON);
22
+ // Perform the scoring.
23
+ const scoredReports = score(scorer, [rawReport]);
24
+ // Validate the scored report.
25
+ if (Array.isArray(scoredReports) && scoredReports.length === 1) {
26
+ console.log('Success: The count of scored reports is correct');
27
+ }
28
+ else {
29
+ console.log('ERROR: The scored reports are not an array of length 1');
30
+ return;
31
+ }
32
+ const report = scoredReports[0];
33
+ if (report.timeLimit === 10) {
34
+ console.log('Success: Scoring left the time limit unchanged');
35
+ }
36
+ else {
37
+ console.log('ERROR: Scoring changed or deleted the time limit');
38
+ return;
39
+ }
40
+ if (report.acts && Array.isArray(report.acts) && report.acts.length === 3) {
41
+ console.log('Success: Scoring left the act count unchanged');
42
+ }
43
+ else {
44
+ console.log('ERROR: Scoring changed the act count or deleted or retyped the acts');
45
+ return;
46
+ }
47
+ if (report.acts[2].result && report.acts[2].result.visibleElements === 100) {
48
+ console.log('Success: Scoring left the bulk test result unchanged');
49
+ }
50
+ else {
51
+ console.log('ERROR: Scoring changed the bulk test result');
52
+ return;
53
+ }
54
+ if (report.score && report.score.testCount === 1) {
55
+ console.log('Success: The score was correctly added to the report');
56
+ }
57
+ else {
58
+ console.log('ERROR: The score was not correctly added to the report');
59
+ return;
60
+ }
61
+ };
62
+ validate();
package/aim.js DELETED
@@ -1,45 +0,0 @@
1
- /*
2
- aim.js
3
- Module for aiming a script at a host.
4
- Arguments:
5
- 0. script object.
6
- 1. host object.
7
- 2. email address to be notified of completion.
8
- 3?. time stamp.
9
- */
10
-
11
- // ########## FUNCTIONS
12
-
13
- // Returns a string representing the date and time.
14
- const nowString = () => (new Date()).toISOString().slice(0, 19);
15
- // Returns a script, aimed at a host, as a job.
16
- exports.aim = (script, host, requester, timeStamp = '') => {
17
- // Initialize a job based on the script.
18
- const job = JSON.parse(JSON.stringify(script));
19
- // Make all url commands in the script visit the host.
20
- job.commands.forEach(command => {
21
- if (command.type === 'url') {
22
- command.id = host.id;
23
- command.which = host.which;
24
- command.what = host.what;
25
- }
26
- });
27
- // Add source information to the script.
28
- job.sources = {
29
- script: script.id,
30
- batch: '',
31
- host,
32
- requester
33
- }
34
- // Create a job-creation time stamp, if not specified.
35
-
36
- timeStamp = timeStamp || Math.floor((Date.now() - Date.UTC(2022, 1)) / 2000).toString(36);
37
- // Change the script ID to a job ID.
38
- job.id = `${timeStamp}-${script.id}-${host.id}`;
39
- // Add the job-creation time to the script.
40
- job.jobCreationTime = nowString();
41
- // Add the time stamp to the job.
42
- job.timeStamp = timeStamp;
43
- // Return the job.
44
- return job;
45
- };
package/multiDigest.js DELETED
@@ -1,51 +0,0 @@
1
- /*
2
- multiDigest.js
3
- Creates digests from scored reports.
4
- Reads all reports in process.env.REPORTDIR_SCORED and outputs them, digested, into
5
- process.env.REPORTDIR_DIGESTED.
6
- Argument:
7
- 0. Base of name of digest proc located in process.env.DIGESTPROCDIR.
8
- Usage example: node digest dp25a
9
- */
10
-
11
- // ########## IMPORTS
12
-
13
- // Module to keep secrets.
14
- require('dotenv').config();
15
- // Module to read and write files.
16
- const fs = require('fs/promises');
17
-
18
- // ########## CONSTANTS
19
-
20
- const reportDirScored = process.env.REPORTDIR_SCORED || 'reports/scored';
21
- const reportDirDigested = process.env.REPORTDIR_DIGESTED || 'reports/digested';
22
- const digestProcDir = process.env.DIGESTPROCDIR || `${__dirname}/procs/digest`;
23
-
24
- // ########## FUNCTIONS
25
-
26
- // Replaces the placeholders in content with eponymous query parameters.
27
- const replaceHolders = (content, query) => content
28
- .replace(/__([a-zA-Z]+)__/g, (ph, qp) => query[qp]);
29
- // Creates digests.
30
- exports.multiDigest = async (digesterID, reportIDStart) => {
31
- // Identify the reports to be digested.
32
- let reportFileNames = await fs.readdir(reportDirScored);
33
- reportFileNames = reportFileNames.filter(fileName => fileName.endsWith('.json'));
34
- // For each report:
35
- const {makeQuery} = require(`${digestProcDir}/${digesterID}/index.js`);
36
- for (const fileName of reportFileNames) {
37
- const reportJSON = await fs.readFile(`${reportDirScored}/${fileName}`, 'utf8');
38
- const report = JSON.parse(reportJSON);
39
- // Define its replacements for the placeholders in the digest template.
40
- const query = {};
41
- makeQuery(report, query);
42
- // Replace the placeholders.
43
- const template = await fs.readFile(`${digestProcDir}/${digesterID}/index.html`, 'utf8');
44
- const digest = replaceHolders(template, query);
45
- // Write its digest.
46
- const fileNameBase = fileName.slice(0, -5);
47
- await fs.writeFile(`${reportDirDigested}/${fileNameBase}.html`, digest);
48
- console.log(`Report ${fileNameBase} digested and saved`);
49
- };
50
- return reportFileNames.length;
51
- };
package/multiScore.js DELETED
@@ -1,48 +0,0 @@
1
- /*
2
- multiScore.js
3
- Scores multiple Testaro reports.
4
- Reads all reports in process.env.REPORTDIR_RAW and outputs them, scored, into
5
- process.env.REPORTDIR_SCORED.
6
- Arguments:
7
- 0. Base of name of score proc located in process.env.SCOREPROCDIR.
8
- Usage example: node score sp18a
9
- */
10
-
11
- // ########## IMPORTS
12
-
13
- // Module to keep secrets.
14
- require('dotenv').config();
15
- // Module to read and write files.
16
- const fs = require('fs/promises');
17
- // Module to score reports.
18
- const {score} = require('./score');
19
-
20
- // ########## CONSTANTS
21
-
22
- const reportDirRaw = process.env.REPORTDIR_RAW || 'reports/raw';
23
- const reportDirScored = process.env.REPORTDIR_SCORED || 'reports/scored';
24
- const scoreProcDir = process.env.SCOREPROCDIR || `${__dirname}/procs/score`;
25
-
26
- // ########## FUNCTIONS
27
-
28
- // Score the specified reports and return their count.
29
- exports.multiScore = async scoreProcID => {
30
- // Get the score proc.
31
- const {scorer} = require(`${scoreProcDir}/${scoreProcID}`);
32
- // Identify the reports to be scored.
33
- let reportFileNames = await fs.readdir(reportDirRaw);
34
- reportFileNames = reportFileNames.filter(fileName => fileName.endsWith('.json'));
35
- // For each of them:
36
- for (const fileName of reportFileNames) {
37
- // Score it.
38
- const rawReportJSON = await fs.readFile(`${reportDirRaw}/${fileName}`, 'utf8');
39
- const rawReport = JSON.parse(rawReportJSON);
40
- const scoredReport = await score(scorer, rawReport);
41
- // Write it to a file.
42
- const scoredReportJSON = JSON.stringify(scoredReport, null, 2);
43
- await fs.writeFile(`${reportDirScored}/${fileName}`, `${scoredReportJSON}\n`);
44
- };
45
- console.log(
46
- `Scored reports saved in ${reportDirScored}. Report count: ${reportFileNames.length}.`
47
- );
48
- };