doc-detective 1.0.6 → 1.0.7

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/README.md CHANGED
@@ -530,9 +530,7 @@ If you opt into sending analytics, you can add additional servers that Doc Detec
530
530
 
531
531
  ```json
532
532
  {
533
- ...
534
533
  "analytics": {
535
- ...
536
534
  "customServers": [
537
535
  {
538
536
  "name": "My Analytics Server",
@@ -547,7 +545,6 @@ If you opt into sending analytics, you can add additional servers that Doc Detec
547
545
  }
548
546
  ]
549
547
  }
550
- ...
551
548
  }
552
549
  ```
553
550
 
@@ -569,15 +566,12 @@ Analytics reporting is off by default. If you want to make extra sure that Doc D
569
566
  - New/upgraded test actions:
570
567
  - New: Test if a referenced image (such as an icon) is present in the captured screenshot.
571
568
  - Upgrade: Additional `httpRequest` input sanitization.
572
- - Upgrade: `screenshot` and `startRecording` boolean for whether to perform the action or not if the expected output file already exists.
573
569
  - Upgrade: `startRecording` and `stopRecording` to support start, stop, and intermediate test action state image matching to track differences between video captures from different runs.
574
- - Upgrade: `startRecording` to store the output file in a different location if a recorded action fails. This could help with debugging.
575
- - In-content test framing to identify when content is covered by a test defined in another file. This could enable content coverage analysis.
570
+ - Content coverage analysis based on in-content test statements and markup declarations.
576
571
  - Suggest tests by parsing document text.
577
572
  - Automatically insert suggested tests based on document text.
578
573
  - Detailed field descriptions per action.
579
574
  - Refactor tests into individual files.
580
- - Rewrite cross-action recording status tracking.
581
575
 
582
576
  ## License
583
577
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doc-detective",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "Unit test documentation (and record videos of those tests).",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -22,8 +22,11 @@
22
22
  ".md",
23
23
  ".mdx"
24
24
  ],
25
- "openActionStatement": "[comment]: # (action",
26
- "closeActionStatement": ")"
25
+ "testStartStatementOpen": "[comment]: # (test start",
26
+ "testStartStatementClose": ")",
27
+ "testEndStatement": "[comment]: # (test end)",
28
+ "actionStatementOpen": "[comment]: # (action",
29
+ "actionStatementClose": ")"
27
30
  },
28
31
  {
29
32
  "extensions": [
@@ -31,8 +34,11 @@
31
34
  ".htm",
32
35
  ".xml"
33
36
  ],
34
- "openActionStatement": "<!-- action",
35
- "closeActionStatement": "-->"
37
+ "testStartStatementOpen": "<!-- test start",
38
+ "testStartStatementClose": "-->",
39
+ "testEndStatement": "<!-- test end -->",
40
+ "actionStatementOpen": "<!-- action",
41
+ "actionStatementClose": "-->"
36
42
  }
37
43
  ],
38
44
  "browserOptions": {
@@ -2,21 +2,25 @@
2
2
 
3
3
  To use Google Search to find information on kittens,
4
4
 
5
+ [comment]: # (test start {"id":"process-search-kittens" })
6
+
5
7
  1. Open [Google Search](https://www.google.com).
6
8
 
7
- [comment]: # (action {"testId":"process-search-kittens", "action":"startRecording", "overwrite":false, "filename":"results.gif", "fps":15})
8
- [comment]: # (action {"testId":"process-search-kittens", "action":"goTo", "uri":"www.google.com"})
9
+ [comment]: # (action {"action":"startRecording", "overwrite":false, "filename":"results.gif", "fps":15})
10
+ [comment]: # (action {"action":"goTo", "uri":"www.google.com"})
9
11
 
10
12
  2. In the search bar, enter "kittens", then press Enter.
11
13
 
12
- [comment]: # (action {"testId":"process-search-kittens", "action":"moveMouse", "css":"#gbqfbb", "alignH": "center", "alignV": "center"})
13
- [comment]: # (action {"testId":"process-search-kittens", "action":"wait", "duration":"5000"})
14
- [comment]: # (action {"testId":"process-search-kittens", "action":"moveMouse", "css":"[title=Search]", "alignV": "center"})
15
- [comment]: # (action {"testId":"process-search-kittens", "action":"type", "css":"[title=Search]", "keys":"kittens", "trailingSpecialKey":"Enter"})
16
- [comment]: # (action {"testId":"process-search-kittens", "action":"wait", "duration":"5000"})
17
- [comment]: # (action {"testId":"process-search-kittens", "action":"scroll", "y": 300})
18
- [comment]: # (action {"testId":"process-search-kittens", "action":"stopRecording"})
19
- [comment]: # (action {"testId":"process-search-kittens", "action":"screenshot", "filename":"results.png", "matchPrevious": true, "matchThreshold": 0.1})
14
+ [comment]: # (action {"action":"moveMouse", "css":"#gbqfbb", "alignH": "center", "alignV": "center"})
15
+ [comment]: # (action {"action":"wait", "duration":"5000"})
16
+ [comment]: # (action {"action":"moveMouse", "css":"[title=Search]", "alignV": "center"})
17
+ [comment]: # (action {"action":"type", "css":"[title=Search]", "keys":"kittens", "trailingSpecialKey":"Enter"})
18
+ [comment]: # (action {"action":"wait", "duration":"5000"})
19
+ [comment]: # (action {"action":"scroll", "y": 300})
20
+ [comment]: # (action {"action":"stopRecording"})
21
+ [comment]: # (action {"action":"screenshot", "filename":"results.png", "matchPrevious": true, "matchThreshold": 0.1})
22
+
23
+ [comment]: # (test end {"id":"process-search-kittens" })
20
24
 
21
25
  Search results appear on the page.
22
26
 
Binary file
@@ -2,20 +2,65 @@
2
2
  "tests": [
3
3
  {
4
4
  "id": "process-search-kittens",
5
+ "file": "/config/workspace/doc-detective/sample/doc-content.md",
5
6
  "actions": [
7
+ {
8
+ "action": "startRecording",
9
+ "overwrite": false,
10
+ "filename": "results.gif",
11
+ "fps": 15,
12
+ "line": 9,
13
+ "result": {
14
+ "status": "PASS",
15
+ "description": "Started recording: /config/workspace/doc-detective/sample/temp_results.mp4",
16
+ "video": "/config/workspace/doc-detective/sample/temp_results.mp4"
17
+ }
18
+ },
6
19
  {
7
20
  "action": "goTo",
8
21
  "uri": "www.google.com",
22
+ "line": 10,
9
23
  "result": {
10
24
  "status": "PASS",
11
25
  "description": "Opened URI."
12
26
  }
13
27
  },
28
+ {
29
+ "action": "moveMouse",
30
+ "css": "#gbqfbb",
31
+ "alignH": "center",
32
+ "alignV": "center",
33
+ "line": 14,
34
+ "result": {
35
+ "status": "PASS",
36
+ "description": "Moved mouse to element."
37
+ }
38
+ },
39
+ {
40
+ "action": "wait",
41
+ "duration": "5000",
42
+ "line": 15,
43
+ "result": {
44
+ "status": "PASS",
45
+ "description": "Wait complete."
46
+ }
47
+ },
48
+ {
49
+ "action": "moveMouse",
50
+ "css": "[title=Search]",
51
+ "alignV": "center",
52
+ "line": 16,
53
+ "result": {
54
+ "status": "PASS",
55
+ "description": "Moved mouse to element."
56
+ }
57
+ },
14
58
  {
15
59
  "action": "type",
16
60
  "css": "[title=Search]",
17
61
  "keys": "kittens",
18
62
  "trailingSpecialKey": "Enter",
63
+ "line": 17,
19
64
  "result": {
20
65
  "status": "PASS",
21
66
  "description": "Typed keys."
@@ -24,16 +69,35 @@
24
69
  {
25
70
  "action": "wait",
26
71
  "duration": "5000",
72
+ "line": 18,
27
73
  "result": {
28
74
  "status": "PASS",
29
75
  "description": "Wait complete."
30
76
  }
31
77
  },
78
+ {
79
+ "action": "scroll",
80
+ "y": 300,
81
+ "line": 19,
82
+ "result": {
83
+ "status": "PASS",
84
+ "description": "Scroll complete."
85
+ }
86
+ },
87
+ {
88
+ "action": "stopRecording",
89
+ "line": 20,
90
+ "result": {
91
+ "status": "PASS",
92
+ "description": "Stopped recording: /config/workspace/doc-detective/sample/results.gif"
93
+ }
94
+ },
32
95
  {
33
96
  "action": "screenshot",
34
97
  "filename": "results.png",
35
98
  "matchPrevious": false,
36
99
  "matchThreshold": 0.1,
100
+ "line": 21,
37
101
  "result": {
38
102
  "status": "PASS",
39
103
  "description": "Captured screenshot.",
@@ -45,10 +109,12 @@
45
109
  },
46
110
  {
47
111
  "id": "text-match-lucky",
112
+ "file": "/config/workspace/doc-detective/sample/doc-content.md",
48
113
  "actions": [
49
114
  {
50
115
  "action": "goTo",
51
116
  "uri": "www.google.com",
117
+ "line": 33,
52
118
  "result": {
53
119
  "status": "PASS",
54
120
  "description": "Opened URI."
@@ -58,16 +124,7 @@
58
124
  "action": "matchText",
59
125
  "css": "#gbqfbb",
60
126
  "text": "I'm Feeling Lucky",
61
- "result": {
62
- "status": "PASS",
63
- "description": "Element text matched expected text."
64
- }
65
- },
66
- {
67
- "action": "matchText",
68
- "css": "#gbqfbb",
69
- "text": "$TEXT",
70
- "env": "./sample/variables.env",
127
+ "line": 34,
71
128
  "result": {
72
129
  "status": "PASS",
73
130
  "description": "Element text matched expected text."
@@ -78,11 +135,12 @@
78
135
  },
79
136
  {
80
137
  "id": "process-lucky-shorthair",
138
+ "file": "/config/workspace/doc-detective/sample/doc-content.md",
81
139
  "actions": [
82
140
  {
83
141
  "action": "goTo",
84
- "uri": "$URL",
85
- "env": "./sample/variables.env",
142
+ "uri": "www.google.com",
143
+ "line": 38,
86
144
  "result": {
87
145
  "status": "PASS",
88
146
  "description": "Opened URI."
@@ -91,7 +149,8 @@
91
149
  {
92
150
  "action": "type",
93
151
  "css": "[title=Search]",
94
- "keys": "$SHORTHAIR_CAT_SEARCH",
152
+ "keys": "american shorthair cats",
153
+ "line": 42,
95
154
  "result": {
96
155
  "status": "PASS",
97
156
  "description": "Typed keys."
@@ -100,6 +159,7 @@
100
159
  {
101
160
  "action": "click",
102
161
  "css": "#gbqfbb",
162
+ "line": 46,
103
163
  "result": {
104
164
  "status": "PASS",
105
165
  "description": "Clicked element."
@@ -107,57 +167,6 @@
107
167
  }
108
168
  ],
109
169
  "status": "PASS"
110
- },
111
- {
112
- "id": "non-ui-tests",
113
- "actions": [
114
- {
115
- "action": "runShell",
116
- "command": "echo $USERNAME",
117
- "env": "./sample/variables.env",
118
- "result": {
119
- "status": "PASS",
120
- "description": "Executed command.",
121
- "stdout": "foo",
122
- "stderr": "",
123
- "exitCode": 0
124
- }
125
- },
126
- {
127
- "action": "checkLink",
128
- "uri": "https://www.google.com",
129
- "statusCodes": [
130
- 200
131
- ],
132
- "result": {
133
- "status": "PASS",
134
- "description": "Returned 200"
135
- }
136
- },
137
- {
138
- "action": "checkLink",
139
- "uri": "$URL",
140
- "statusCodes": [
141
- 200
142
- ],
143
- "result": {
144
- "status": "PASS",
145
- "description": "Returned 200"
146
- }
147
- },
148
- {
149
- "action": "httpRequest",
150
- "uri": "$URL",
151
- "statusCodes": [
152
- 200
153
- ],
154
- "result": {
155
- "status": "PASS",
156
- "description": "Returned 200."
157
- }
158
- }
159
- ],
160
- "status": "PASS"
161
170
  }
162
171
  ]
163
172
  }
Binary file
package/src/config.json CHANGED
@@ -22,8 +22,11 @@
22
22
  ".md",
23
23
  ".mdx"
24
24
  ],
25
- "openActionStatement": "[comment]: # (action",
26
- "closeActionStatement": ")"
25
+ "testStartStatementOpen": "[comment]: # (test start",
26
+ "testStartStatementClose": ")",
27
+ "testEndStatement": "[comment]: # (test end)",
28
+ "actionStatementOpen": "[comment]: # (action",
29
+ "actionStatementClose": ")"
27
30
  },
28
31
  {
29
32
  "extensions": [
@@ -31,8 +34,11 @@
31
34
  ".htm",
32
35
  ".xml"
33
36
  ],
34
- "openActionStatement": "<!-- action",
35
- "closeActionStatement": "-->"
37
+ "testStartStatementOpen": "<!-- test start",
38
+ "testStartStatementClose": "-->",
39
+ "testEndStatement": "<!-- test end -->",
40
+ "actionStatementOpen": "<!-- action",
41
+ "actionStatementClose": "-->"
36
42
  }
37
43
  ],
38
44
  "browserOptions": {
package/src/index.js CHANGED
@@ -2,7 +2,7 @@ const {
2
2
  setArgs,
3
3
  setConfig,
4
4
  setFiles,
5
- parseFiles,
5
+ parseTests,
6
6
  outputResults,
7
7
  log,
8
8
  } = require("./lib/utils");
@@ -30,7 +30,7 @@ async function main(config, argv) {
30
30
  log(config, "debug", files);
31
31
 
32
32
  // Set tests
33
- const tests = parseFiles(config, files);
33
+ const tests = parseTests(config, files);
34
34
  if (config.logLevel === "debug") {
35
35
  console.log("(DEBUG) TESTS:");
36
36
  tests.tests.forEach((test) => {
package/src/lib/utils.js CHANGED
@@ -11,7 +11,7 @@ const defaultConfig = require("../config.json");
11
11
  exports.setArgs = setArgs;
12
12
  exports.setConfig = setConfig;
13
13
  exports.setFiles = setFiles;
14
- exports.parseFiles = parseFiles;
14
+ exports.parseTests = parseTests;
15
15
  exports.outputResults = outputResults;
16
16
  exports.setEnvs = setEnvs;
17
17
  exports.loadEnvsForObject = loadEnvsForObject;
@@ -183,7 +183,8 @@ function selectConfig(config, argv) {
183
183
  }
184
184
 
185
185
  function setEnv(config, argv) {
186
- config.env = argv.env || process.env.DOC_ENV_PATH || config.env;
186
+ config.env =
187
+ argv.env || process.env.DOC_ENV_PATH || config.env || defaultConfig.env;
187
188
  if (config.env) {
188
189
  config.env = path.resolve(config.env);
189
190
  if (fs.existsSync(config.env)) {
@@ -202,7 +203,11 @@ function setEnv(config, argv) {
202
203
  }
203
204
 
204
205
  function setInput(config, argv) {
205
- config.input = argv.input || process.env.DOC_INPUT_PATH || config.input;
206
+ config.input =
207
+ argv.input ||
208
+ process.env.DOC_INPUT_PATH ||
209
+ config.input ||
210
+ defaultConfig.input;
206
211
  if (config.input) {
207
212
  config.input = path.resolve(config.input);
208
213
  if (fs.existsSync(config.input)) {
@@ -226,14 +231,19 @@ function setInput(config, argv) {
226
231
  }
227
232
 
228
233
  function setOutput(config, argv) {
229
- config.output = argv.output || process.env.DOC_OUTPUT_PATH || config.output;
234
+ config.output =
235
+ argv.output ||
236
+ process.env.DOC_OUTPUT_PATH ||
237
+ config.output ||
238
+ defaultConfig.output;
230
239
  config.output = path.resolve(config.output);
231
240
  log(config, "debug", `Output path set: ${config.output}`);
232
241
  return config;
233
242
  }
234
243
 
235
244
  function setSetup(config, argv) {
236
- config.setup = argv.setup || process.env.DOC_SETUP || config.setup;
245
+ config.setup =
246
+ argv.setup || process.env.DOC_SETUP || config.setup || defaultConfig.setup;
237
247
  if (config.setup === "") {
238
248
  log(config, "debug", `No setup tests.`);
239
249
  return config;
@@ -250,7 +260,11 @@ function setSetup(config, argv) {
250
260
  }
251
261
 
252
262
  function setCleanup(config, argv) {
253
- config.cleanup = argv.cleanup || process.env.DOC_CLEANUP || config.cleanup;
263
+ config.cleanup =
264
+ argv.cleanup ||
265
+ process.env.DOC_CLEANUP ||
266
+ config.cleanup ||
267
+ defaultConfig.cleanup;
254
268
  if (config.cleanup === "") {
255
269
  log(config, "debug", `No cleanup tests.`);
256
270
  return config;
@@ -270,7 +284,8 @@ function setMediaDirectory(config, argv) {
270
284
  config.mediaDirectory =
271
285
  argv.mediaDir ||
272
286
  process.env.DOC_MEDIA_DIRECTORY_PATH ||
273
- config.mediaDirectory;
287
+ config.mediaDirectory ||
288
+ defaultConfig.mediaDirectory;
274
289
  config.mediaDirectory = path.resolve(config.mediaDirectory);
275
290
  if (fs.existsSync(config.mediaDirectory)) {
276
291
  log(config, "debug", `Media directory set: ${config.mediaDirectory}`);
@@ -289,7 +304,8 @@ function setFailedTestRecording(config, argv) {
289
304
  config.saveFailedTestRecordings =
290
305
  argv.saveFailedTestRecordings ||
291
306
  process.env.DOC_SAVE_FAILED_RECORDINGS ||
292
- config.saveFailedTestRecordings;
307
+ config.saveFailedTestRecordings ||
308
+ defaultConfig.saveFailedTestRecordings;
293
309
  switch (config.saveFailedTestRecordings) {
294
310
  case true:
295
311
  case "true":
@@ -325,7 +341,8 @@ function setFailedTestDirectory(config, argv) {
325
341
  config.failedTestDirectory =
326
342
  argv.failedTestDirectory ||
327
343
  process.env.DOC_FAILED_TEST_DIRECTORY_PATH ||
328
- config.failedTestDirectory;
344
+ config.failedTestDirectory ||
345
+ defaultConfig.failedTestDirectory;
329
346
  config.failedTestDirectory = path.resolve(config.failedTestDirectory);
330
347
  if (fs.existsSync(config.failedTestDirectory)) {
331
348
  log(
@@ -348,7 +365,10 @@ function setFailedTestDirectory(config, argv) {
348
365
 
349
366
  function setRecursion(config, argv) {
350
367
  config.recursive =
351
- argv.recursive || process.env.DOC_RECURSIVE || config.recursive;
368
+ argv.recursive ||
369
+ process.env.DOC_RECURSIVE ||
370
+ config.recursive ||
371
+ defaultConfig.recursive;
352
372
  switch (config.recursive) {
353
373
  case true:
354
374
  case "true":
@@ -371,9 +391,33 @@ function setRecursion(config, argv) {
371
391
  return config;
372
392
  }
373
393
 
394
+ function setFileTypes(config, argv) {
395
+ config.fileTypes =
396
+ argv.fileTypes ||
397
+ process.env.DOC_FILE_TYPES ||
398
+ config.fileTypes ||
399
+ defaultConfig.fileTypes;
400
+ if (config.fileTypes.length > 0) {
401
+ log(config, "debug", `File types set: ${JSON.stringify(config.fileTypes)}`);
402
+ } else {
403
+ config.fileTypes = defaultConfig.fileTypes;
404
+ log(
405
+ config,
406
+ "debug",
407
+ `Invalid file type value(s). Reverted to default: ${JSON.stringify(
408
+ config.fileTypes
409
+ )}`
410
+ );
411
+ }
412
+ return config;
413
+ }
414
+
374
415
  function setTestFileExtensions(config, argv) {
375
416
  config.testExtensions =
376
- argv.ext || process.env.DOC_TEST_EXTENSTIONS || config.testExtensions;
417
+ argv.ext ||
418
+ process.env.DOC_TEST_EXTENSTIONS ||
419
+ config.testExtensions ||
420
+ defaultConfig.testExtensions;
377
421
  if (typeof config.testExtensions === "string")
378
422
  config.testExtensions = config.testExtensions
379
423
  .replace(/\s+/g, "")
@@ -401,7 +445,8 @@ function setBrowserHeadless(config, argv) {
401
445
  config.browserOptions.headless =
402
446
  argv.browserHeadless ||
403
447
  process.env.DOC_BROWSER_HEADLESS ||
404
- config.browserOptions.headless;
448
+ config.browserOptions.headless ||
449
+ defaultConfig.browserOptions.headless;
405
450
  switch (config.browserOptions.headless) {
406
451
  case true:
407
452
  case "true":
@@ -436,7 +481,8 @@ function setBrowserPath(config, argv) {
436
481
  config.browserOptions.path =
437
482
  argv.browserPath ||
438
483
  process.env.DOC_BROWSER_PATH ||
439
- config.browserOptions.path;
484
+ config.browserOptions.path ||
485
+ defaultConfig.browserOptions.path;
440
486
  if (config.browserOptions.path === "") {
441
487
  log(config, "debug", `Browser set to default Chromium install.`);
442
488
  return config;
@@ -460,7 +506,8 @@ function setBrowserHeight(config, argv) {
460
506
  config.browserOptions.height =
461
507
  argv.browserHeight ||
462
508
  process.env.DOC_BROWSER_HEIGHT ||
463
- config.browserOptions.height;
509
+ config.browserOptions.height ||
510
+ defaultConfig.browserOptions.height;
464
511
  if (typeof config.browserOptions.height === "string") {
465
512
  try {
466
513
  config.browserOptions.height = Number(config.browserOptions.height);
@@ -490,7 +537,8 @@ function setBrowserWidth(config, argv) {
490
537
  config.browserOptions.width =
491
538
  argv.browserWidth ||
492
539
  process.env.DOC_BROWSER_WIDTH ||
493
- config.browserOptions.width;
540
+ config.browserOptions.width ||
541
+ defaultConfig.browserOptions.width;
494
542
  if (typeof config.browserOptions.width === "string") {
495
543
  try {
496
544
  config.browserOptions.width = Number(config.browserOptions.width);
@@ -518,7 +566,10 @@ function setBrowserWidth(config, argv) {
518
566
 
519
567
  function setAnalytics(config, argv) {
520
568
  config.analytics.send =
521
- argv.analytics || process.env.DOC_ANALYTICS || config.analytics.send;
569
+ argv.analytics ||
570
+ process.env.DOC_ANALYTICS ||
571
+ config.analytics.send ||
572
+ defaultConfig.analytics.send;
522
573
  switch (config.analytics.send) {
523
574
  case true:
524
575
  case "true":
@@ -546,7 +597,8 @@ function setAnalyticsUserId(config, argv) {
546
597
  config.analytics.userId =
547
598
  argv.analyticsUserId ||
548
599
  process.env.DOC_ANALYTICS_USER_ID ||
549
- config.analytics.userId;
600
+ config.analytics.userId ||
601
+ defaultConfig.analytics.userId;
550
602
  log(config, "debug", `Analytics user ID set: ${config.analytics.userId}`);
551
603
  return config;
552
604
  }
@@ -556,7 +608,8 @@ function setAnalyticsDetailLevel(config, argv) {
556
608
  detailLevel =
557
609
  argv.analyticsDetailLevel ||
558
610
  process.env.DOC_ANALYTCS_DETAIL_LEVEL ||
559
- config.analytics.detailLevel;
611
+ config.analytics.detailLevel ||
612
+ defaultConfig.analytics.detailLevel;
560
613
  detailLevel = String(detailLevel).toLowerCase();
561
614
  if (enums.indexOf(detailLevel) >= 0) {
562
615
  config.analytics.detailLevel = detailLevel;
@@ -605,6 +658,8 @@ function setConfig(config, argv) {
605
658
 
606
659
  config = setRecursion(config, argv);
607
660
 
661
+ config = setFileTypes(config, argv);
662
+
608
663
  config = setTestFileExtensions(config, argv);
609
664
 
610
665
  config = setBrowserHeadless(config, argv);
@@ -686,13 +741,14 @@ function setFiles(config) {
686
741
  }
687
742
 
688
743
  // Parse files for tests
689
- function parseFiles(config, files) {
744
+ function parseTests(config, files) {
690
745
  let json = { tests: [] };
691
746
 
692
747
  // Loop through test files
693
748
  files.forEach((file) => {
694
749
  log(config, "debug", `file: ${file}`);
695
- let id = uuid.v4();
750
+ let fileId = `${uuid.v4()}`;
751
+ let id = fileId;
696
752
  let line;
697
753
  let lineNumber = 1;
698
754
  let inputFile = new nReadlines(file);
@@ -700,36 +756,135 @@ function parseFiles(config, files) {
700
756
  let fileType = config.fileTypes.find((fileType) =>
701
757
  fileType.extensions.includes(extension)
702
758
  );
759
+ let testStartStatementOpen;
760
+ let testStartStatementClose;
761
+ let testEndStatement;
762
+ let actionStatementOpen;
763
+ let actionStatementClose;
764
+
765
+ if (typeof fileType != "undefined") {
766
+ testStartStatementOpen = fileType.testStartStatementOpen;
767
+ if (!testStartStatementOpen) {
768
+ log(
769
+ config,
770
+ "warning",
771
+ `Skipping tests in ${file}. No 'testStartStatementOpen' value specified.`
772
+ );
773
+ return;
774
+ }
775
+ testStartStatementClose = fileType.testStartStatementClose;
776
+ if (!testStartStatementClose) {
777
+ log(
778
+ config,
779
+ "warning",
780
+ `Skipping tests in ${file}. No 'testStartStatementClose' value specified.`
781
+ );
782
+ return;
783
+ }
784
+ testEndStatement = fileType.testEndStatement;
785
+ if (!testEndStatement) {
786
+ log(
787
+ config,
788
+ "warning",
789
+ `Skipping tests in ${file}. No 'testEndStatement' value specified.`
790
+ );
791
+ return;
792
+ }
793
+ actionStatementOpen =
794
+ fileType.actionStatementOpen ||
795
+ fileType.openActionStatement ||
796
+ fileType.openTestStatement;
797
+ if (!actionStatementOpen) {
798
+ log(
799
+ config,
800
+ "warning",
801
+ `Skipping tests in ${file}. No 'actionStatementOpen' value specified.`
802
+ );
803
+ return;
804
+ }
805
+ actionStatementClose =
806
+ fileType.actionStatementClose ||
807
+ fileType.closeActionStatement ||
808
+ fileType.closeTestStatement;
809
+ if (!actionStatementClose) {
810
+ log(
811
+ config,
812
+ "warning",
813
+ `Skipping tests in ${file}. No 'actionStatementClose' value specified.`
814
+ );
815
+ return;
816
+ }
817
+ }
818
+
703
819
  if (!fileType && extension !== ".json") {
704
820
  // Missing filetype options
705
- console.log(
706
- `Error: Specify options for the ${extension} extension in your config file.`
821
+ log(
822
+ config,
823
+ "warning",
824
+ `Skipping file with ${extension} extension. Specify options for the ${extension} extension in your config file.`
707
825
  );
708
- exit(1);
826
+ return;
709
827
  }
710
828
 
711
829
  // If file is JSON, add tests straight to array
712
830
  if (path.extname(file) === ".json") {
713
831
  content = require(file);
714
- content.tests.forEach((test) => {
715
- json.tests.push(test);
716
- });
832
+ if (typeof content.tests === "object" && content.tests.length > 0) {
833
+ content.tests.forEach((test) => {
834
+ json.tests.push(test);
835
+ });
836
+ } else {
837
+ log(
838
+ config,
839
+ "warning",
840
+ `Skipping ${file} because of unexpected object structure.`
841
+ );
842
+ return;
843
+ }
717
844
  } else {
718
845
  // Loop through lines
719
846
  while ((line = inputFile.next())) {
720
- let lineJson = "";
721
- let subStart = "";
722
- let subEnd = "";
723
- if (line.includes(fileType.openActionStatement)) {
724
- const lineAscii = line.toString("ascii");
725
- if (fileType.closeActionStatement) {
726
- subEnd = lineAscii.lastIndexOf(fileType.closeActionStatement);
847
+ let lineJson;
848
+ let subStart;
849
+ let subEnd;
850
+ const lineAscii = line.toString("ascii");
851
+
852
+ if (line.includes(testStartStatementOpen)) {
853
+ // Test start
854
+ if (testStartStatementClose) {
855
+ subEnd = lineAscii.lastIndexOf(testStartStatementClose);
856
+ } else {
857
+ subEnd = lineAscii.length;
858
+ }
859
+ subStart =
860
+ lineAscii.indexOf(testStartStatementOpen) +
861
+ testStartStatementOpen.length;
862
+ lineJson = JSON.parse(lineAscii.substring(subStart, subEnd));
863
+ // If test is defined in this file instead of referencing a test defined in another file
864
+ if (!lineJson.file) {
865
+ test = { id, file, actions: [] };
866
+ if (lineJson.id) {
867
+ test.id = lineJson.id;
868
+ // Set ID for following actions
869
+ id = lineJson.id;
870
+ }
871
+ if (lineJson.saveFailedTestRecordings)
872
+ test.saveFailedTestRecordings = lineJson.saveFailedTestRecordings;
873
+ if (lineJson.failedTestDirectory)
874
+ test.failedTestDirectory = lineJson.failedTestDirectory;
875
+ json.tests.push(test);
876
+ }
877
+ } else if (line.includes(testEndStatement)) {
878
+ // Revert back to file-based ID
879
+ id = fileId;
880
+ } else if (line.includes(actionStatementOpen)) {
881
+ if (actionStatementClose) {
882
+ subEnd = lineAscii.lastIndexOf(actionStatementClose);
727
883
  } else {
728
884
  subEnd = lineAscii.length;
729
885
  }
730
886
  subStart =
731
- lineAscii.indexOf(fileType.openActionStatement) +
732
- fileType.openActionStatement.length;
887
+ lineAscii.indexOf(actionStatementOpen) + actionStatementOpen.length;
733
888
  lineJson = JSON.parse(lineAscii.substring(subStart, subEnd));
734
889
  if (!lineJson.testId) {
735
890
  lineJson.testId = id;