@suffolklitlab/alkiln 5.12.0 → 5.13.0-logs2

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 (38) hide show
  1. package/.env.example +29 -0
  2. package/.github/workflows/github_server.yml +59 -12
  3. package/.github/workflows/playground.yml +11 -4
  4. package/CHANGELOG.md +41 -1
  5. package/CONTRIBUTING.md +98 -83
  6. package/README.md +1 -1
  7. package/action.yml +69 -29
  8. package/action_for_github_server/action.yml +65 -31
  9. package/docs/decisions/006_which_log_level_to_pick_2024_09_5.md +46 -0
  10. package/docs/decisions/adopt_architectural_decision_records.md +58 -0
  11. package/docs/decisions/detect_sign_in.md +124 -0
  12. package/docs/decisions/pdfjs_version_2024_08_08.md +18 -0
  13. package/docs/decisions/reports_and_logs_2024_08_11.md +141 -0
  14. package/docs/decisions/update_puppeteer_2024_07_28.md +62 -0
  15. package/docs/story_tables.md +1 -1
  16. package/lib/docassemble/docassemble_api_REST.js +67 -1
  17. package/lib/docassemble/docassemble_api_interface.js +225 -18
  18. package/lib/docassemble/server_install.js +23 -9
  19. package/lib/docassemble/setup.js +33 -20
  20. package/lib/docassemble/takedown.js +27 -7
  21. package/lib/run_cucumber.js +83 -33
  22. package/lib/scope.js +222 -82
  23. package/lib/steps.js +206 -62
  24. package/lib/utils/files.js +8 -6
  25. package/lib/utils/log.js +477 -84
  26. package/lib/utils/reports.js +14 -5
  27. package/lib/utils/session_vars.js +25 -18
  28. package/lib/utils/time.js +44 -0
  29. package/npm-shrinkwrap.json +635 -193
  30. package/package.json +8 -8
  31. package/setup.py +1 -1
  32. package/tests/log_codes/check_codes.sh +163 -108
  33. package/tests/log_codes/log_code_expected_instances.txt +213 -0
  34. package/tests/unit_tests/getAllFields.test.js +5 -0
  35. package/tests/unit_tests/getMatchingRows.test.js +5 -0
  36. package/tests/unit_tests/log.test.js +20 -0
  37. package/tests/unit_tests/normalizeTable.test.js +5 -0
  38. package/tests/log_codes/deleted_codes.json +0 -8
package/lib/utils/log.js CHANGED
@@ -1,96 +1,489 @@
1
- const fs = require('fs');
2
- const session_vars = require( './session_vars' );
1
+ const fs = require(`fs`);
2
+ const util = require(`node:util`);
3
+ const session_vars = require( `./session_vars` );
4
+ const time = require(`./time`);
5
+ const files = require(`./files`);
3
6
 
4
- // ? 🌈 💡 🔎 🤕 🐞
7
+ // ? 🌈 💡 🔎 🤕 🐛
5
8
  // Alternatives: 🩹 ❤️‍🩹 🚑
6
9
  // TODO: return full message so it can be passed to manually
7
10
  // thrown errors if needed.
8
11
 
9
- let log = {};
10
- module.exports = log;
12
+ /**
13
+ * TODO:
14
+ * - [x] Store log filename in runtime_config
15
+ * - [x] `types` -> `context`
16
+ * - [x] Remove "cosmetic"/"plain" logs and just work that beauty into the logs themselves
17
+ * - [ ] Save logs from GitHub actions as well
18
+ * - [ ] Capture cucumber ProgressFormatter logs instead of making them ourselves?
19
+ * - [ ] Write user errors and warnings (sent to .console()) to unexpected results file
20
+ * - [ ] Write debug errors and warnings to unexpected results file?
21
+ * - [ ] write tests...?
22
+ * - [ ] Edit the decision doc? Too many individual decisions? Use separate docs instead?
23
+ * - streams vs. formatter vs. fs.appendFileSync
24
+ * - general architecture?
25
+ * - keeping report separate for now
26
+ * - try/catching everything + collecting errors
27
+ * - `throw` (non-standard) (throw errors in logs? (bad stack trace) 2 lines everywhere instead?)
28
+ * - `success` (non-standard)
29
+ * - `before` option and no others? (others can be included in message, but no way to log before the code otherwise.)
30
+ * - Name "debug" meaning change instead of "verbose"
31
+ * */
32
+ //
11
33
 
12
- let create_msg_start = function ( types, pre='', code=`? ALK0000` ) {
13
- // ? - unknown (fallback)
14
- let types_str = types.join(` `);
15
- if ( types_str.includes(`plain`) ) {
16
- return pre;
17
- } else {
18
- return `${ code } ${ types_str }: ${ pre }`;
34
+ class Log {
35
+ /** Handles logging to the console, saving to files and reports,
36
+ * and throwing errors.
37
+ *
38
+ * Use this to:
39
+ * - Log to the console
40
+ * - Save to the debug log
41
+ * - Throw errors with log codes and other info
42
+ * - Log without new lines
43
+ *
44
+ * What are the different log files:
45
+ * - report is a pretty file that is only complete at the end of all tests
46
+ * - report_log is not pretty, but has the same info as the report in case tests end early
47
+ * - debug_log is very ugly and has notes for developers
48
+ *
49
+ * TODO:
50
+ * - Save to the report and report log
51
+ *
52
+ * @params
53
+ * options { object }
54
+ * options.path { str } - Optional. The path where the final logs
55
+ * should be stored.
56
+ * options.context { str } - Optional. Info about what's creating
57
+ * this Log.
58
+ *
59
+ * We're not using console.Console or write streams because we can't
60
+ * control their life cycle in steps.js. We can't tell when to
61
+ * properly flush and end the stream in the case of a sudden failure.
62
+ * */
63
+
64
+ report_filename = `report.txt`;
65
+ report_log_filename = `report_log.txt`;
66
+ debug_log_filename = `debug_log.txt`;
67
+ unexpected_filename = `unexpected_results.txt`;
68
+
69
+ constructor({ path, context } = {}) {
70
+ // this.id = uuid();
71
+
72
+ // Make sure folder exists
73
+ if ( path ) { files.make_artifacts_folder( path ); }
74
+ // In local development and ALKilnInThePlayground, this will
75
+ // mostly be called by the `run` command.
76
+ else { path = files.make_artifacts_folder(); }
77
+
78
+ this.path = path;
79
+ session_vars.save_artifacts_path_name( this.path );
80
+
81
+ if ( context ) { context = context + ` log`; }
82
+ else { context = `log`; }
83
+ this.info({ code: `ALK0215`, context, },
84
+ `Saving files to "${ this.path }"`
85
+ );
86
+ }
87
+
88
+ console( console_opts = {}, ...logs ) {
89
+ /** Log the logs to the console at the right level and with the metadata.
90
+ * Return the start of the message - the part without the logs
91
+ *
92
+ * Questions:
93
+ * - Allow `logs` to be a string?
94
+ * - Allow `context` to be a space-separated string?
95
+ * - Throw errors? Need to manipulate call stack.
96
+ * - Turn logs that are non-strings into `JSON.stringify`d strings?
97
+ * - Should every log be able to have an error? To keep the
98
+ * signature consistent.
99
+ *
100
+ * @examples:
101
+ * Log = require('./lib/utils/log.js');
102
+ * log = new Log('_alkiln-');
103
+ *
104
+ * log.console();
105
+ * // * ALK000c console LOG [2024-08-16 00:30:39UTC]:
106
+ *
107
+ * log.console({
108
+ * level: 'info',
109
+ * icon: '&',
110
+ * code: 'ALK00t1',
111
+ * context: 'a test',
112
+ * }, 'test info log');
113
+ *
114
+ * try {
115
+ * let czar = zoo + 5;
116
+ * } catch ( error ) {
117
+ * log.console({
118
+ * level: 'error',
119
+ * before: '===\n===\n',
120
+ * icon: 'X'
121
+ * code: 'ALK00t2'
122
+ * context: 'err_test'
123
+ * error: new Error('This is an error'),
124
+ * }, 'error test log 1', 'error test log 2')
125
+ * }
126
+ * */
127
+
128
+ let { // Defaults
129
+ level = `log`,
130
+ before = ``, // different name? above? start_decorator?
131
+ icon = `*`,
132
+ code = `ALK000c`,
133
+ context = ``,
134
+ error = null,
135
+ do_throw = false,
136
+ } = console_opts;
137
+
138
+ let with_error = [...logs];
139
+ if ( error ) {
140
+ with_error.push( error );
141
+ }
142
+
143
+ let formatted_log = this.debug({ level, before, icon, code, context }, ...with_error );
144
+ // Shame to do this in .debug too, but haven't found a
145
+ // better way to return consistent values otherwise. We
146
+ // want other logs to be logged by the console in its way.
147
+ const metadata = this._format_metadata({ level, icon, code, context });
148
+
149
+ // Throw whatever we can throw
150
+ if ( do_throw ) {
151
+ let custom_msg = this._stringify_logs({ logs: [ metadata, ...logs ] });
152
+ // TODO: Save to unexpected results file
153
+ if ( error instanceof Error ) {
154
+ console.log( before + custom_msg );
155
+ throw error;
156
+ } else if ( error !== null ) {
157
+ console.log( before + custom_msg );
158
+ throw new Error( error );
159
+ } else {
160
+ console.log( before ); // Adds extra new line, unfortunately
161
+ throw new Error( custom_msg );
162
+ }
163
+ }
164
+
165
+ try {
166
+ // Otherwise, log at the given level if console has that method (`log` by default)
167
+ // If a non-standard level was passed in, like `success`, use `info` by default
168
+ if ( console[ level ]) {
169
+ // TODO: Save `warn` to unexpected results file
170
+ console[ level ]( before + metadata, ...with_error );
171
+ } else {
172
+ console.info( before + metadata, ...with_error );
173
+ }
174
+ } catch ( console_log_error ) {
175
+ // Fail silently, gather errors
176
+ try {
177
+ this.debug({
178
+ level: `warn`, icon: `🔎`, code: `ALK0211`,
179
+ context: `internal`,
180
+ error: console_log_error
181
+ }, `Skipped saving a ${ level } message to the debug log`);
182
+ } catch ( console_debug_error ) {
183
+ console.warn( `🔎 ALK0217 internal WARNING: Skipped the same log two times consecutively`, console_debug_error, console_log_error );
184
+ }
185
+ } finally {
186
+ return formatted_log;
187
+ }
188
+ }
189
+
190
+ debug( debug_opts = {}, ...logs ) {
191
+ /** Save in the debug log file and return a string version
192
+ * of the log. If there are errors, just log them too.
193
+ * Keep as much info from the caller as possible. Avoid throwing
194
+ * errors if at all possible while giving the max info possible.
195
+ * Avoid logging to the visible console.
196
+ *
197
+ * TODO: Log warning with stack trace
198
+ *
199
+ * @examples:
200
+ *
201
+ * Log = require('./lib/utils/log.js')
202
+ * log = new Log({ path: '_alkiln-' })
203
+ * log.debug()
204
+ * // 🐛 ALK000v debug DEBUG [2024-08-16 00:38:49UTC]:
205
+ * */
206
+ let {
207
+ level=`debug`,
208
+ before = ``,
209
+ icon = `🐛`,
210
+ code = `ALK000v`,
211
+ context = ``,
212
+ error = null,
213
+ } = debug_opts;
214
+
215
+ // function stackTrace() { return (new Error()).stack; }
216
+ // and
217
+ // https://stackoverflow.com/a/41820537/14144258
218
+ // var mystring=require('util').inspect(error_object);
219
+
220
+ let logging_errors = [];
221
+
222
+ // Get a proper error log if needed
223
+ if ( level === `throw` ) { level = `error`; }
224
+
225
+ let metadata = `No metadata: `;
226
+ try {
227
+ metadata = this._format_metadata({ level, icon, code, context });
228
+ } catch ( metadata_error ) {
229
+ // Consider using `util.inspect()` for the error
230
+ logging_errors.push(`🔎 ALK0212 internal WARNING: Skipped creating debug metadata\n${ metadata_error.stack }`);
231
+ }
232
+
233
+ // Include error as the last log
234
+ let with_error = [...logs];
235
+ if ( error ) {
236
+ with_error.push( error );
237
+ }
238
+
239
+ let formatted_log = `${ metadata }No formatted log.`;
240
+ try {
241
+ let stringified = this._stringify_logs({ logs: with_error });
242
+ formatted_log = `${ before }${ metadata }${ stringified }`;
243
+ } catch ( formatted_log_error ) {
244
+ // Consider using `util.inspect()` for the error
245
+ logging_errors.push(`🔎 ALK0213 internal WARNING: Skipped creating full debug log\n${ formatted_log_error.stack }`);
246
+ }
247
+
248
+ let fs_append_failed = false;
249
+ try {
250
+ fs.appendFileSync( `${ this.path }/${ this.debug_log_filename }`, `\n` + formatted_log )
251
+ } catch ( fs_append_error ) {
252
+ fs_append_failed = true;
253
+ // Consider using `util.inspect()` for the error
254
+ logging_errors.push(`🔎 ALK0214 internal WARNING: Could not append to debug log file\n${ fs_append_error.stack }`);
255
+ }
256
+
257
+ // Record any errors in the most unobtrusive way possible
258
+ if ( logging_errors.length > 0 ) {
259
+ for ( let logging_error of logging_errors ) {
260
+ if ( fs_append_failed ) {
261
+ console.warn( logging_error );
262
+ } else {
263
+ // TODO: Log warning with stack trace
264
+ fs.appendFileSync( `${ this.path }/${ this.debug_log_filename }`, `\n` + logging_error.stack );
265
+ }
266
+ }
267
+ }
268
+
269
+ return formatted_log;
270
+ }
271
+
272
+ _format_metadata( metadata_opts = {} ) {
273
+ /** Format and return the log metadata.
274
+ * Example: "💡 ALK#### internal INFO [10:24:40 pm UTC]: "
275
+ * */
276
+ let {
277
+ level=`log`,
278
+ icon = `?`,
279
+ code = `ALK000m`,
280
+ context = ``,
281
+ } = metadata_opts;
282
+
283
+ let metadata = `? ALK000m unspecified: `;
284
+ try {
285
+ let metadata_level = level;
286
+ if ( level === `warn` ) { metadata_level = `warning`; }
287
+ let level_caps = metadata_level.toUpperCase();
288
+ // For elapsed time, see https://nodejs.org/api/console.html#consoletimelabel
289
+ // Should this really be a pretty date, or should it be a raw timestamp?
290
+
291
+ // let metadata_list = [ icon, code, context, level_caps, `[${ time.log_date() }]` ];
292
+ // let metadata_list = [ icon, code, context, level_caps, `[${ time.log_date() }]` ].filter(function ( item ) {
293
+ // return item !== ``;
294
+ // }).join(` `) + `: `;
295
+
296
+ let metadata_list = [];
297
+ for ( let item of [ icon, code, context, level_caps, `[${ time.log_date() }]` ]) {
298
+ if ( item !== `` ) { metadata_list.push(item); }
299
+ }
300
+ metadata = metadata_list.join(` `) + `: `;
301
+ } catch ( metadata_error ) {
302
+ let msg = `Skipped creating metadata`;
303
+ code = `ALK0220`;
304
+ icon = `🔎`;
305
+ context = `internal logs metadata`;
306
+ try {
307
+ this.debug({ icon, level: `warn`, code, context, error: metadata_error }, msg );
308
+ } catch {
309
+ console.warn( `${ icon } ${ code } ${ context } WARNING [${ Date.now() }]: ${ msg }`, metadata_error );
310
+ }
311
+ }
312
+ return metadata;
19
313
  }
20
- };
21
-
22
- // Where is this used?
23
- log.success = function ({ type='', pre='', data='', post='', code=`ALK0000` }) {
24
- /** Log success msg with the given information and strings, prepended with `ALKiln`.
25
- * `type` is often something like 'setup', 'takedown', etc. */
26
- // √ - info (fallback)
27
- let start = create_msg_start([ type, `SUCCESS` ], pre, `🌈 ${code}` );
28
- // Log them each on a separate line
29
- console.info( `${ start }` );
30
- if ( data ) { console.info( data ); }
31
- if ( post ) { console.info( post ); }
32
- };
33
-
34
- // Where is this used?
35
- log.info = function ({ type='', pre='', data='', post='', code=`ALK0000` }) {
36
- /** Log info msg with the given information and strings, prepended with `ALKiln`.
37
- * `type` is often something like 'setup', 'takedown', etc. */
38
- // & - info (fallback)
39
- let start = create_msg_start([ type, `INFO` ], pre, `💡 ${code}` );
40
- // Log them each on a separate line
41
- console.info( `${ start }` );
42
- if ( data ) { console.info( data ); }
43
- if ( post ) { console.info( post ); }
44
- };
45
-
46
- // Where is this used?
47
- log.warn = function ({ type='', pre='', data='', post='', code=`ALK0000` }) {
48
- /** Log warning msg with the given information and strings, prepended with `ALKiln`.
49
- * `type` is often something like 'setup', 'takedown', etc. */
50
- // ! - warning (fallback)
51
- let start = create_msg_start([ type, `WARNING` ], pre, `🔎 ${code}` );
52
- // Log them each on a separate line
53
- console.warn( `${ start }` );
54
- if ( data ) { console.warn( data ); }
55
- if ( post ) { console.warn( post ); }
56
- };
57
-
58
- // Where is this used?
59
- log.error = function ({ type='', pre='', data='', post='', code=`ALK0000` }) {
60
- /** Log error msg with the given information and strings, prepended with `ALKiln`.
61
- * `type` is often something like 'setup', 'takedown', etc. */
62
- // X - error (fallback)
63
- let start = create_msg_start([ type, `ERROR` ], pre, `🤕 ${code}` );
64
- // Log them each on a separate line with extra new lines around the whole thing
65
- console.error( `\n${ start }` );
66
- if ( data ) { console.error( data ); }
67
- if ( post ) { console.error( post, `\n` ); }
68
- };
69
-
70
- log.debug = function ({ type='', pre='', data='', post='', verbose=false, code=`ALK0000` }) {
71
- /** If debugging is turned on, log a message that includes `ALKiln` and `debug` */
72
- // @ - debug (fallback)
73
- let start = create_msg_start([ type, `DEBUG` ], pre, `🐞 ${ code }` );
74
- let full = `\n${ start }`;
75
- if ( data ) { full += `\n${ data }`; }
76
- if ( post ) { full += `\n${ post }`; }
77
-
78
- // TODO: Make a verbose log instead of adding to the debug one and always add to it
79
- if ( verbose ) {
80
- log.add_to_debug_log( full );
314
+
315
+ _stringify_logs(str_log_opts = {}) {
316
+ /** Return a string - a formatted version of the list
317
+ * of logs by stringifying non-strings. An empty list
318
+ * or no argument is valid. */
319
+
320
+ let { logs = [] } = str_log_opts;
321
+
322
+ let stringified_logs = ``;
323
+ let prev_line_type = null;
324
+
325
+ try {
326
+ for ( let log of logs ) {
327
+ // TODO: Try/catch each of these?
328
+ if ( log === null || [`string`, `number`, `undefined`, `boolean`].includes( typeof(log) )) {
329
+
330
+ stringified_logs += this._stringify_inline({ prev_line_type, log });
331
+ prev_line_type = `inline`;
332
+
333
+ } else {
334
+ // For objects and errors
335
+ stringified_logs += this._stringify_object({ obj: log });
336
+ prev_line_type = `block`;
337
+ } // ends typeof log
338
+ } // Ends for logs
339
+ } catch ( stringify_error ) {
340
+ try {
341
+ // TODO: Should `stringify_error` get recorded even when util.inspect works?
342
+ stringified_logs = util.inspect( logs, { depth: 8, maxArrayLength: null, maxStringLength: null, });
343
+ } catch ( util_error ) {
344
+
345
+ if ( stringified_logs ) {
346
+ stringified_logs += `Unable to stringify logs. Got:\n${ stringified_logs }\n${ util_error.stack }\n${ stringify_error.stack }`;
347
+ } else {
348
+ stringified_logs = `Unable to stringify logs.\n${ util_error.stack }\n${ stringify_error.stack }`;
349
+ }
350
+ }
351
+ }
352
+
353
+ return stringified_logs;
354
+ } // Ends Log._stringify_logs()
355
+
356
+ _stringify_inline({ prev_line_type, log }) {
357
+ /** Format an inline log. Mostly involves fiddling with
358
+ * the start of the string. */
359
+ // An inline log's string starts with nothing if it's the first string...
360
+ let start = ``;
361
+ // ...starts after a space if its next to an inline string...
362
+ if ( prev_line_type === `inline` ) { start = ` `; }
363
+ // ...or starts on a new line if it's after a block of text,
364
+ // like an error or object.
365
+ else if ( prev_line_type === `block` ) { start = `\n`; }
366
+ return `${ start }${ log }`;
367
+ }
368
+
369
+ _stringify_object({ obj }) {
370
+ /** Try to stringify an object a few different ways. Works for
371
+ * errors too. */
372
+ try {
373
+ // A block of text (the object) always starts on a new line
374
+ // Try to stringify the object.
375
+ return `\n${ util.inspect( obj, { depth: 8, maxArrayLength: null, maxStringLength: null, } )}`;
376
+ } catch ( outer_error ) {
377
+ // If that fails, see if it has its own way of stringifying
378
+ // TODO: record these errors?
379
+ try {
380
+ return `\n${ obj }`;
381
+ } catch ( inner_error ) {
382
+ // Lastly, give at least some information
383
+ return `\nUnable to log this ${ typeof obj }`;
384
+ } // ends inner try
385
+ } // ends outer try
386
+ }
387
+
388
+ success( success_opts = {}, ...logs ) {
389
+ /** Console log success - log level with success icon. */
390
+ // Discuss: do we want to log some successes as "💡 ... SUCCESS: "?
391
+ // Should we allow callers to override levels and icons?
392
+ let {
393
+ code = `ALK000s`, before = ``, context = ``
394
+ } = success_opts;
395
+ return this.console({
396
+ level: `success`, icon: `🌈`,
397
+ before, code, context,
398
+ }, ...logs);
399
+ }
400
+
401
+ info( info_opts = {}, ...logs ) {
402
+ /** Console log info. */
403
+ let {
404
+ code = `ALK000i`, before = ``, context = ``,
405
+ } = info_opts;
406
+ return this.console({
407
+ level: `info`, icon: `💡`,
408
+ before, code, context,
409
+ }, ...logs);
410
+ }
411
+
412
+ warn( warning_opts = {}, ...logs ) {
413
+ /** Console log warning. */
414
+ let {
415
+ code = `ALK000w`, before = ``, context = ``
416
+ } = warning_opts;
417
+ return this.console({
418
+ level: `warn`, icon: `🔎`,
419
+ before, code, context,
420
+ }, ...logs);
421
+ }
422
+
423
+ throw( throw_opts = {}, ...logs ){
424
+ /** Console log and throw error.
425
+ * The `error` option is required. */
426
+ let {
427
+ code = `ALK000t`, before = ``, context = ``,
428
+ do_throw = true, error,
429
+ } = throw_opts;
430
+ return this.console({
431
+ level: `error`, icon: `🤕`,
432
+ before, code, context, error,
433
+ }, ...logs);
434
+ }
435
+
436
+ unexpected({ text = `` } = {}) {
437
+ /** TODO: Save to the unexpected results file. (Errors, maybe warnings) */
438
+ fs.appendFileSync(`${ this.path }/${ this.unexpected_filename }`, `\n${ text }` );
439
+ }
440
+
441
+ stdout(stdout_opts = {}, ...logs) {
442
+ /** Prints in the console inline and saves to the debug log
443
+ * and the report log.
444
+ *
445
+ * @params
446
+ * options { obj }
447
+ * options.records_only { bool } - Whether to only save logs
448
+ * without printing them to the console. E.g. progress
449
+ * summary characters like those that cucumber is already
450
+ * printing to the console.
451
+ * */
452
+ let {
453
+ records_only = false,
454
+ } = stdout_opts;
455
+ let whole_log = logs.join(` `);
456
+
457
+ // Write to the debug and report files
458
+ this._record_stdout({ logs });
459
+
460
+ if ( !records_only ) {
461
+ process.stdout.write( whole_log );
462
+ }
463
+
464
+ return logs;
465
+ }
466
+
467
+ _record_stdout({ logs = [] }) {
468
+ /** Save stdout output to various debug and report files. */
469
+ this.debug({ code: `ALK0219`, context: `stdout` }, ...logs);
470
+ let whole_log = logs.join(` `);
471
+ fs.appendFileSync( `${ this.path }/${ this.report_log_filename }`, whole_log );
472
+ // TODO: write to report after report metadata
81
473
  }
82
474
 
83
- if ( session_vars.get_debug() ) {
84
- // Log them each on a separate line
85
- console.log( `\n${ start }` );
86
- console.log( data );
87
- console.log( post );
475
+ clear() {
476
+ /** Empty all files possible. Mostly for testing. */
477
+ try { fs.writeFileSync( `${ this.path }/${ this.debug_log_filename }`, `` ); }
478
+ catch (error) { /* Do nothing, no file there or something */ }
479
+ try { fs.writeFileSync( `${ this.path }/${ this.report_log_filename }`, `` ); }
480
+ catch (error) { /* Do nothing, no file there or something */ }
481
+ try { fs.writeFileSync( `${ this.path }/${ this.report_filename }`, `` ); }
482
+ catch (error) { /* Do nothing, no file there or something */ }
483
+ try { fs.writeFileSync( `${ this.path }/${ this.unexpected_filename }`, `` ); }
484
+ catch (error) { /* Do nothing, no file there or something */ }
88
485
  }
89
- };
90
486
 
91
- log.add_to_debug_log = function(value) {
92
- fs.appendFileSync(log.debug_log_file, value);
93
- };
487
+ } // Ends Log{}
94
488
 
95
- log.debug_log_file = `debug_log.txt`;
96
- log.unexpected_filename = `unexpected_results.txt`;
489
+ module.exports = Log;
@@ -66,14 +66,20 @@ reports.addToReport = function( scope, { type, code, value }) {
66
66
  const MISC_ARTIFACTS_DIR = `_alkiln-misc_artifacts`;
67
67
  if ( !scope.paths ) {
68
68
  // Can this be usefully abstracted?
69
- scope.paths = { debug_log: `${ MISC_ARTIFACTS_DIR }/unit_tests_logs-${ files.readable_date() }.txt` };
69
+ let date = files.readable_date();
70
+ scope.paths = {
71
+ debug_log: `${ MISC_ARTIFACTS_DIR }/unit_tests_debug_log-${ date }.txt`,
72
+ report_log: `${ MISC_ARTIFACTS_DIR }/unit_tests_report_log-${ date }.txt`,
73
+ };
70
74
  }
71
75
 
72
76
  try {
73
77
  fs.appendFileSync( scope.paths.debug_log, `\nReport:\n${debug_line}` );
74
- } catch ( err ) {
78
+ fs.appendFileSync( scope.paths.report_log, `\nReport:\n${debug_line}` );
79
+ } catch ( file_error ) {
75
80
  fs.mkdirSync( MISC_ARTIFACTS_DIR );
76
81
  fs.appendFileSync( scope.paths.debug_log, `\nReport:\n${debug_line}` );
82
+ fs.appendFileSync( scope.paths.report_log, `\nReport:\n${debug_line}` );
77
83
  // An error in here should throw (for now)
78
84
  }
79
85
 
@@ -81,7 +87,7 @@ reports.addToReport = function( scope, { type, code, value }) {
81
87
  let scenario = reports.makeSureScenarioExists( scope );
82
88
  scenario.lines.push({ type, code, value });
83
89
 
84
- return scenario;
90
+ return getLineText({ type, code, value });
85
91
  }; // Ends reports.addToReport()
86
92
 
87
93
  reports.create = function( scope ) {
@@ -134,6 +140,9 @@ reports.saveFinalScenarioData = function( scope, { status=`in progress` }) {
134
140
  return scenario;
135
141
  }; // Ends reports.saveFinalScenarioData()
136
142
 
143
+ reports.progress = function ({ logs=[] }) {
144
+ // TODO: save stdout-style to report_log, object, and getting printable scenario
145
+ };
137
146
 
138
147
  reports.setReportScenarioStatus = function( scope, { status=`PASSED` }) {
139
148
  /** Add final status of scenario to scenario report object - passed, failed, etc. */
@@ -203,7 +212,7 @@ reports.getPrintableScenario = function( scenario ) {
203
212
  return report;
204
213
  }; // Ends reports.getPrintableScenario()
205
214
 
206
- let getLineText = function ({ type=`no type`, code=`ALK0000`, value=`` }) {
215
+ let getLineText = function ({ type=`no type`, code=`ALK00rl`, value=`` }) {
207
216
  let start = ``;
208
217
  if ( type.includes(`page_id`) ) { start += `screen id: `; }
209
218
  else if ( type.includes(`outcome`) ) { start += `\n`; } // extra new line
@@ -212,7 +221,7 @@ let getLineText = function ({ type=`no type`, code=`ALK0000`, value=`` }) {
212
221
  return `${ start }${ value }`;
213
222
  }; // Ends getLine()
214
223
 
215
- let getDebugLine = function ({ type=``, code=`ALK0000`, value=`` }) {
224
+ let getDebugLine = function ({ type=``, code=`ALK00rd`, value=`` }) {
216
225
  /** In debug log lines, include all the information possible. */
217
226
 
218
227
  // `plain` is usually used for visual clarity and shouldn't have