testaro 5.19.0 → 6.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.
package/run.js CHANGED
@@ -1549,7 +1549,7 @@ const injectLaunches = acts => {
1549
1549
  }
1550
1550
  };
1551
1551
  // Handles a request.
1552
- exports.handleRequest = async report => {
1552
+ exports.doJob = async report => {
1553
1553
  // If the report object is valid:
1554
1554
  if(isValidReport(report)) {
1555
1555
  // Add a start time to the log.
@@ -1,25 +1,24 @@
1
1
  /*
2
- runHost.js
3
- Runs a host job and writes a report file.
2
+ runScript.js
3
+ Runs a script and writes a report file.
4
4
  */
5
5
 
6
6
  // ########## IMPORTS
7
7
 
8
- const {handleRequest} = require('./run');
8
+ const {doJob} = require('./run');
9
9
 
10
10
  // ########## FUNCTIONS
11
11
 
12
- // Runs one script and sends the report to the parent.
13
- const runHost = async (id, scriptJSON, hostJSON) => {
12
+ // Runs a script and returns the report.
13
+ const runScript = async (id, scriptJSON) => {
14
14
  const report = {
15
15
  id,
16
- host: JSON.parse(hostJSON),
17
16
  log: [],
18
17
  script: JSON.parse(scriptJSON),
19
18
  acts: []
20
19
  };
21
20
  let reportJSON = JSON.stringify(report, null, 2);
22
- await handleRequest(report);
21
+ await doJob(report);
23
22
  report.acts.forEach(act => {
24
23
  try {
25
24
  JSON.stringify(act);
@@ -37,15 +36,13 @@ const runHost = async (id, scriptJSON, hostJSON) => {
37
36
  });
38
37
  try {
39
38
  reportJSON = JSON.stringify(report, null, 2);
39
+ return reportJSON;
40
40
  }
41
41
  catch(error) {
42
42
  console.log(`ERROR: report for host ${id} not JSON (${error.message})`);
43
+ return '';
43
44
  }
44
- process.send(reportJSON, () => {
45
- process.disconnect();
46
- process.exit();
47
- });
48
45
  };
49
46
 
50
47
  // ########## OPERATION
51
- runHost(... process.argv.slice(2));
48
+ runScript(... process.argv.slice(2));
@@ -2,6 +2,7 @@
2
2
  "id": "simple",
3
3
  "what": "Test example.com with bulk",
4
4
  "strict": true,
5
+ "timeLimit": 10,
5
6
  "commands": [
6
7
  {
7
8
  "type": "launch",
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "tp16",
2
+ "id": "tp18",
3
3
  "what": "Alfa, Axe, Continuum, HTML CodeSniffer, IBM, Nu Html Checker, Tenon, WAVE, and 22 custom tests",
4
4
  "strict": true,
5
5
  "timeLimit": 500,
@@ -11,7 +11,7 @@
11
11
  },
12
12
  {
13
13
  "type": "url",
14
- "which": "https://*",
14
+ "which": "https://example.com/",
15
15
  "what": "any page"
16
16
  },
17
17
  {
@@ -35,7 +35,7 @@
35
35
  },
36
36
  {
37
37
  "type": "url",
38
- "which": "https://*",
38
+ "which": "https://example.com/",
39
39
  "what": "any page"
40
40
  },
41
41
  {
package/tests/titledEl.js CHANGED
@@ -11,8 +11,8 @@ exports.reporter = async (page, withItems) => {
11
11
  // FUNCTION DEFINITION START
12
12
  // Returns a space-minimized copy of a string.
13
13
  const compact = string => string
14
- ? string.replace(/[\t\n]/g, '').replace(/\s{2,}/g, ' ').trim()
15
- : '';
14
+ ? string.replace(/[\t\n]/g, '').replace(/\s{2,}/g, ' ').trim()
15
+ : '';
16
16
  // FUNCTION DEFINITION END
17
17
  return badTitleElements.map(element => ({
18
18
  tagName: element.tagName,
@@ -2,7 +2,7 @@
2
2
  // Validator for Testaro tests.
3
3
 
4
4
  const fs = require('fs').promises;
5
- const {handleRequest} = require(`${__dirname}/../../run`);
5
+ const {doJob} = require(`${__dirname}/../../run`);
6
6
  const validateTests = async () => {
7
7
  const totals = {
8
8
  attempts: 0,
@@ -18,7 +18,7 @@ const validateTests = async () => {
18
18
  const report = {script};
19
19
  report.log = [];
20
20
  report.acts = [];
21
- await handleRequest(report);
21
+ await doJob(report);
22
22
  const {log, acts} = report;
23
23
  if (log.length === 2 && log[1].event === 'endTime' && /^\d{4}-.+$/.test(log[1].value)) {
24
24
  console.log('Success: Log has been correctly populated');
@@ -0,0 +1,57 @@
1
+ // high.js
2
+ // Validator for high-level invocation of Testaro.
3
+
4
+ // ########## IMPORTS
5
+
6
+ const fs = require('fs/promises');
7
+
8
+ // ########## CONSTANTS
9
+
10
+ const projectRoot = `${__dirname}/../..`;
11
+ process.env.REPORTDIR = `${projectRoot}/temp`;
12
+ const reportDir = process.env.REPORTDIR;
13
+ process.env.SCRIPTDIR = `${projectRoot}/samples`;
14
+
15
+ // ########## OPERATION
16
+
17
+ // Run the simple script and write a report.
18
+ const {runJob} = require(`${projectRoot}/high`);
19
+ runJob('simple')
20
+ .then(
21
+ // When the report has been written:
22
+ async () => {
23
+ // Open it.
24
+ const fileNames = await fs.readdir(reportDir);
25
+ const reportNames = fileNames.filter(name => name.endsWith('-simple.json'));
26
+ if (reportNames.length) {
27
+ try {
28
+ // Check its log and act lengths against expectations.
29
+ const reportJSON = await fs.readFile(`${reportDir}/${reportNames[0]}`);
30
+ const report = JSON.parse(reportJSON);
31
+ const {log, acts} = report;
32
+ if (log.length !== 2) {
33
+ console.log(
34
+ `Failure: log length is ${log.length} instead of 2 (see temp/${reportNames[0]}})`
35
+ );
36
+ }
37
+ else if (acts.length !== 3) {
38
+ console.log(
39
+ `Failure: acts length is ${acts.length} instead of 3 (see temp/${reportNames[0]}})`
40
+ );
41
+ }
42
+ else {
43
+ console.log(`Success (report is in temp/${reportNames[0]})`);
44
+ }
45
+ }
46
+ catch(error) {
47
+ console.log(`ERROR: ${error.message}`);
48
+ }
49
+ }
50
+ else {
51
+ console.log('ERROR: report not found');
52
+ }
53
+ },
54
+ error => {
55
+ console.log(`ERROR running script (${error.message})`);
56
+ }
57
+ );
@@ -13,8 +13,8 @@ const validate = async () => {
13
13
  log: [],
14
14
  acts: []
15
15
  };
16
- const {handleRequest} = require('../../run');
17
- await handleRequest(report);
16
+ const {doJob} = require('../../run');
17
+ await doJob(report);
18
18
  const {log, acts} = report;
19
19
  if (log.length !== 2) {
20
20
  console.log(`Failure: log length is ${log.length} instead of 2`);
@@ -2,7 +2,7 @@
2
2
  // Test executor for tenon sample script.
3
3
 
4
4
  const fs = require('fs');
5
- const {handleRequest} = require('../../run');
5
+ const {doJob} = require('../../run');
6
6
  const scriptJSON = fs.readFileSync('samples/scripts/tenon.json', 'utf8');
7
7
  const script = JSON.parse(scriptJSON);
8
8
  const report = {
@@ -12,7 +12,7 @@ const report = {
12
12
  acts: []
13
13
  };
14
14
  (async () => {
15
- await handleRequest(report);
15
+ await doJob(report);
16
16
  console.log(`Report log:\n${JSON.stringify(report.log, null, 2)}\n`);
17
17
  console.log(`Report acts:\n${JSON.stringify(report.acts, null, 2)}`);
18
18
  })();
@@ -3,7 +3,7 @@
3
3
  // Execution example: node validation/executors/test focOp
4
4
 
5
5
  const fs = require('fs').promises;
6
- const {handleRequest} = require(`${__dirname}/../../run`);
6
+ const {doJob} = require(`${__dirname}/../../run`);
7
7
  const test = process.argv[2];
8
8
  const validateTests = async () => {
9
9
  const scriptFileNames = await fs.readdir(`${__dirname}/../tests/scripts`);
@@ -16,7 +16,7 @@ const validateTests = async () => {
16
16
  const report = {script};
17
17
  report.log = [];
18
18
  report.acts = [];
19
- await handleRequest(report);
19
+ await doJob(report);
20
20
  const {log, acts} = report;
21
21
  if (log.length === 2 && log[1].event === 'endTime' && /^\d{4}-.+$/.test(log[1].value)) {
22
22
  console.log('Success: Log has been correctly populated');
@@ -2,7 +2,7 @@
2
2
  // Validator for Testaro tests.
3
3
 
4
4
  const fs = require('fs').promises;
5
- const {handleRequest} = require(`${__dirname}/../../run`);
5
+ const {doJob} = require(`${__dirname}/../../run`);
6
6
  const validateTests = async () => {
7
7
  const totals = {
8
8
  attempts: 0,
@@ -18,7 +18,7 @@ const validateTests = async () => {
18
18
  const report = {script};
19
19
  report.log = [];
20
20
  report.acts = [];
21
- await handleRequest(report);
21
+ await doJob(report);
22
22
  const {log, acts} = report;
23
23
  if (log.length === 2 && log[1].event === 'endTime' && /^\d{4}-.+$/.test(log[1].value)) {
24
24
  console.log('Success: Log has been correctly populated');
package/watch.js CHANGED
@@ -1,54 +1,53 @@
1
1
  /*
2
2
  watch.js
3
- Watches for jobs and runs them.
3
+ Watches for a script and runs it.
4
+ Arguments:
5
+ 0. Watch type: 'dir' or 'net'.
6
+ 1. How long to watch: 'once' or 'forever'.
7
+ 2. How often to check in seconds.
8
+ Usage example: node watch dir once 15
4
9
  */
5
10
 
6
11
  // ########## IMPORTS
7
12
 
8
13
  // Module to keep secrets local.
9
- // require('dotenv').config({override: true});
10
14
  require('dotenv').config();
11
15
  // Module to read and write files.
12
16
  const fs = require('fs/promises');
13
17
  // Module to perform tests.
14
- const {handleRequest} = require('./run');
15
- // Module to convert a script and a batch to a batch-based array of scripts.
16
- const {batchify} = require('./batchify');
18
+ const {doJob} = require('./run');
17
19
 
18
20
  // ########## CONSTANTS
19
21
 
20
- const watchType = process.env.WATCH_TYPE;
22
+ const watchType = process.argv[2];
23
+ const watchForever = process.argv[3] === 'forever';
24
+ const interval = Number.parseInt(process.argv[4]);
21
25
  let client;
22
26
  if (watchType === 'net') {
23
27
  client = require(process.env.PROTOCOL || 'https');
24
28
  }
25
29
  const jobURL = process.env.JOB_URL;
26
- const authCode = process.env.AUTH_CODE;
27
- const jobDir = process.env.JOBDIR;
28
- const exJobDir = process.env.EXJOBDIR;
30
+ const worker = process.env.WORKER;
31
+ const watchDir = process.env.WATCHDIR;
32
+ const doneDir = process.env.DONEDIR;
29
33
  const reportURL = process.env.REPORT_URL;
30
34
  const reportDir = process.env.REPORTDIR;
31
- const interval = process.env.INTERVAL;
32
- // Values of process.env properties are coerced to strings.
33
- const watchForever = process.env.WATCH_FOREVER == 'true';
34
35
 
35
36
  // ########## FUNCTIONS
36
37
 
37
38
  // Checks for a directory job.
38
39
  const checkDirJob = async () => {
39
- const jobDirFileNames = await fs.readdir(jobDir);
40
+ const jobDirFileNames = await fs.readdir(watchDir);
40
41
  const jobFileNames = jobDirFileNames.filter(fileName => fileName.endsWith('.json'));
41
42
  if (jobFileNames.length) {
42
- const firstJobID = jobFileNames[0].slice(0, -5);
43
- const jobJSON = await fs.readFile(`${jobDir}/${jobFileNames[0]}`, 'utf8');
43
+ const scriptJSON = await fs.readFile(`${watchDir}/${jobFileNames[0]}`, 'utf8');
44
44
  try {
45
- const job = JSON.parse(jobJSON, null, 2);
46
- job.jobID = firstJobID;
47
- return job;
45
+ const script = JSON.parse(scriptJSON, null, 2);
46
+ return script;
48
47
  }
49
48
  catch(error) {
50
49
  return {
51
- error: 'ERROR: Job was not JSON',
50
+ error: 'ERROR: Script was not JSON',
52
51
  message: error.message
53
52
  };
54
53
  }
@@ -59,8 +58,8 @@ const checkDirJob = async () => {
59
58
  };
60
59
  // Checks for a network job.
61
60
  const checkNetJob = async () => {
62
- const job = await new Promise(resolve => {
63
- const wholeURL = `${process.env.PROTOCOL}://${jobURL}?authCode=${authCode}`;
61
+ const script = await new Promise(resolve => {
62
+ const wholeURL = `${process.env.PROTOCOL}://${jobURL}?worker=${worker}`;
64
63
  const request = client.request(wholeURL, response => {
65
64
  const chunks = [];
66
65
  response.on('data', chunk => {
@@ -68,18 +67,10 @@ const checkNetJob = async () => {
68
67
  });
69
68
  response.on('end', () => {
70
69
  try {
71
- const jobJSON = chunks.join('');
72
- const job = JSON.parse(jobJSON);
73
- // If a qualifying job was received:
74
- if (job.jobID) {
75
- // Return it.
76
- resolve(job);
77
- }
78
- // Otherwise, i.e. if there was no qualifying job:
79
- else {
80
- // Return this.
81
- resolve({});
82
- }
70
+ const scriptJSON = chunks.join('');
71
+ const script = JSON.parse(scriptJSON);
72
+ // Return it.
73
+ resolve(script);
83
74
  }
84
75
  catch(error) {
85
76
  resolve({
@@ -92,20 +83,21 @@ const checkNetJob = async () => {
92
83
  });
93
84
  request.end();
94
85
  });
95
- return job;
86
+ return script;
96
87
  };
97
88
  // Writes a directory report.
98
89
  const writeDirReport = async report => {
99
- const {id, jobID} = report;
100
- if (id && jobID) {
101
- const reportJSON = JSON.stringify(report, null, 2);
90
+ const scriptID = report && report.script && report.script.id;
91
+ if (scriptID) {
102
92
  try {
103
- await fs.writeFile(`${reportDir}/${id}.json`, reportJSON);
104
- console.log(`Report ${id}.json saved`);
93
+ const reportJSON = JSON.stringify(report, null, 2);
94
+ const reportName = `${report.timeStamp}-${scriptID}.json`;
95
+ await fs.writeFile(`${reportDir}/${reportName}`, reportJSON);
96
+ console.log(`Report ${reportName} saved`);
105
97
  return true;
106
98
  }
107
99
  catch(error) {
108
- console.log(`ERROR: Failed to write report ${id} for job ${jobID}`);
100
+ console.log(`ERROR: Failed to write report (${error.message})`);
109
101
  return false;
110
102
  }
111
103
  }
@@ -113,7 +105,7 @@ const writeDirReport = async report => {
113
105
  // Submits a network report.
114
106
  const writeNetReport = async report => {
115
107
  const ack = await new Promise(resolve => {
116
- const wholeURL = `${process.env.PROTOCOL}://${reportURL}?authCode=${authCode}`;
108
+ const wholeURL = `${process.env.PROTOCOL}://${reportURL}?worker=${worker}`;
117
109
  const request = client.request(wholeURL, {method: 'POST'}, response => {
118
110
  const chunks = [];
119
111
  response.on('data', chunk => {
@@ -134,15 +126,15 @@ const writeNetReport = async report => {
134
126
  });
135
127
  request.write(JSON.stringify(report, null, 2));
136
128
  request.end();
137
- console.log(`Report with ID ${report.id} submitted`);
129
+ console.log(`Report ${report.timeStamp}-${report.script.id} submitted`);
138
130
  });
139
131
  return ack;
140
132
  };
141
133
  // Archives a job.
142
- const exifyJob = async (job) => {
143
- const jobJSON = JSON.stringify(job, null, 2);
144
- await fs.writeFile(`${exJobDir}/${job.timeStamp}.json`, jobJSON);
145
- await fs.rm(`${jobDir}/${job.jobID}.json`);
134
+ const archiveJob = async script => {
135
+ const jobJSON = JSON.stringify(script, null, 2);
136
+ await fs.writeFile(`${doneDir}/${script.timeStamp}-${script.id}.json`, jobJSON);
137
+ await fs.rm(`${watchDir}/${script.id}.json`);
146
138
  };
147
139
  // Waits.
148
140
  const wait = ms => {
@@ -152,117 +144,84 @@ const wait = ms => {
152
144
  }, ms);
153
145
  });
154
146
  };
155
- // Runs one script and writes or sends a report.
156
- const runHost = async (jobID, timeStamp, id, script) => {
157
- const report = {
158
- jobID,
159
- timeStamp,
160
- id,
161
- log: [],
162
- script,
163
- acts: []
164
- };
165
- await handleRequest(report);
166
- if (watchType === 'dir') {
167
- return await writeDirReport(report);
168
- }
169
- else {
170
- const ack = await writeNetReport(report);
171
- if (ack.error) {
172
- console.log(JSON.stringify(ack, null, 2));
173
- return false;
174
- }
175
- else {
176
- return true;
177
- }
178
- }
179
- };
180
- // Runs a job and returns a report file for the script or each host.
181
- const runJob = async job => {
182
- const {jobID, script, batch} = job;
183
- if (jobID) {
184
- if (script) {
185
- try {
186
- // Identify the start time and a time stamp.
187
- const timeStamp = Math.floor((Date.now() - Date.UTC(2022, 1)) / 2000).toString(36);
188
- job.timeStamp = timeStamp;
189
- // If there is a batch:
190
- if (batch) {
191
- // Convert the script to a set of host scripts.
192
- const specs = batchify(script, batch, timeStamp);
193
- // For each host script:
194
- let success = true;
195
- while (specs.length && success) {
196
- // Run it and write or submit a report with a host-suffixed time-stamp ID.
197
- const spec = specs.shift();
198
- const {id} = spec;
199
- const hostScript = spec.script;
200
- success = await runHost(jobID, timeStamp, id, hostScript);
201
- }
202
- return success;
147
+ // Runs a script, time-stamps it, and returns a report.
148
+ const runJob = async script => {
149
+ const {id} = script;
150
+ if (id) {
151
+ try {
152
+ // Identify the start time and a time stamp.
153
+ const timeStamp = Math.floor((Date.now() - Date.UTC(2022, 1)) / 2000).toString(36);
154
+ script.timeStamp = timeStamp;
155
+ // Initialize a report.
156
+ const report = {
157
+ log: [],
158
+ script,
159
+ acts: []
160
+ };
161
+ await doJob(report);
162
+ if (watchType === 'dir') {
163
+ return await writeDirReport(report);
164
+ }
165
+ else {
166
+ const ack = await writeNetReport(report);
167
+ if (ack.error) {
168
+ console.log(JSON.stringify(ack, null, 2));
169
+ return false;
203
170
  }
204
- // Otherwise, i.e. if there is no batch:
205
171
  else {
206
- // Run the script and submit a report with a timestamp ID.
207
- return await runHost(jobID, timeStamp, timeStamp, script);
172
+ return true;
208
173
  }
209
174
  }
210
- catch(error) {
211
- console.log(`ERROR: ${error.message}\n${error.stack}`);
212
- return {
213
- error: `ERROR: ${error.message}\n${error.stack}`
214
- };
215
- }
216
175
  }
217
- else {
218
- console.log('ERROR: no script specified');
176
+ catch(error) {
177
+ console.log(`ERROR: ${error.message}\n${error.stack}`);
219
178
  return {
220
- error: 'ERROR: no script specified'
179
+ error: `ERROR: ${error.message}\n${error.stack}`
221
180
  };
222
181
  }
223
182
  }
224
183
  else {
225
- console.log('ERROR: no job ID property in job');
184
+ console.log('ERROR: script has no id');
226
185
  return {
227
- error: 'ERROR: no job ID property in job'
186
+ error: 'ERROR: script has no id'
228
187
  };
229
188
  }
230
189
  };
231
- // Repeatedly checks for jobs, runs them, and submits reports.
190
+ // Checks for a job, performs it, and submits a report, once or repeatedly.
232
191
  const cycle = async forever => {
233
- const intervalMS = Number.parseInt(interval);
192
+ const intervalMS = 1000 * Number.parseInt(interval);
234
193
  let statusOK = true;
235
194
  let empty = false;
236
195
  console.log(`Watching started with intervals of ${interval} seconds when idle`);
237
196
  while (statusOK) {
238
197
  if (empty) {
239
- await wait(1000 * intervalMS);
198
+ await wait(intervalMS);
240
199
  }
241
200
  // Check for a job.
242
- let job;
201
+ let script;
243
202
  if (watchType === 'dir') {
244
- job = await checkDirJob();
203
+ script = await checkDirJob();
245
204
  }
246
205
  else if (watchType === 'net') {
247
- job = await checkNetJob();
206
+ script = await checkNetJob();
248
207
  }
249
208
  else {
250
- job = {};
209
+ script = {};
251
210
  console.log('ERROR: invalid WATCH_TYPE environment variable');
252
211
  statusOK = false;
253
212
  }
254
213
  // If there was one:
255
- if (job.jobID) {
256
- // Run it.
257
- console.log(`Running job ${job.jobID}`);
258
- statusOK = await runJob(job);
259
- console.log(`Job ${job.jobID} finished with time stamp ${job.timeStamp}`);
214
+ if (script.id) {
215
+ // Run it, add a timestamp to it, and save a report.
216
+ console.log(`Running script ${script.id}`);
217
+ statusOK = await runJob(script);
218
+ console.log(`Job ${script.id} finished with time stamp ${script.timeStamp}`);
260
219
  if (statusOK) {
261
- // If the job was a file:
220
+ // If the script was in a directory:
262
221
  if (watchType === 'dir') {
263
- // Archive it.
264
- await exifyJob(job);
265
- console.log(`Job archived as ${job.timeStamp}.json`);
222
+ // Archive the script.
223
+ await archiveJob(script);
224
+ console.log(`Script ${script.id}.json archived as ${script.timeStamp}-${script.id}.json`);
266
225
  }
267
226
  // If watching was specified for only 1 job, stop.
268
227
  statusOK = forever;
package/batchify.js DELETED
@@ -1,25 +0,0 @@
1
- /*
2
- batchify.js
3
- Creates a set of scripts from a script and a batch.
4
- */
5
-
6
- // Converts a script to a batch-based array of scripts.
7
- exports.batchify = (script, batch, timeStamp) => {
8
- const {hosts} = batch;
9
- const specs = hosts.map(host => {
10
- const newScript = JSON.parse(JSON.stringify(script));
11
- newScript.commands.forEach(command => {
12
- if (command.type === 'url') {
13
- command.which = host.which;
14
- command.what = host.what;
15
- }
16
- });
17
- const spec = {
18
- id: `${timeStamp}-${host.id}`,
19
- host,
20
- script: newScript
21
- };
22
- return spec;
23
- });
24
- return specs;
25
- };