@suffolklitlab/alkiln 5.13.2 → 5.13.4
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/.github/workflows/github_server.yml +7 -7
- package/.github/workflows/playground.yml +1 -1
- package/CHANGELOG.md +32 -1
- package/action.yml +70 -28
- package/action_for_github_server/action.yml +61 -29
- package/docs/4_environments.md +243 -0
- package/docs/artifacts_folder_name.md +135 -0
- package/docs/constrained_random_tests.md +347 -0
- package/docs/decisions/006_which_log_level_to_pick_2024_09_5.md +70 -0
- package/docs/decisions/007_getting_and_storing_logs.md +179 -0
- package/docs/decisions/move_runtime_config_to_sources_folder.md +3 -0
- package/docs/decisions/reports_and_logs_2024_08_11.md +161 -0
- package/docs/kinds_of_errors.md +26 -0
- package/docs/prioritize_constrained_random_tests.md +101 -0
- package/docs/seprate_file_generation_GitHub_action.md +11 -0
- package/lib/docassemble/docassemble_api_interface.js +77 -51
- package/lib/docassemble/server_install.js +32 -9
- package/lib/docassemble/setup.js +40 -25
- package/lib/docassemble/takedown.js +33 -10
- package/lib/parse.js +36 -0
- package/lib/run_cucumber.js +115 -36
- package/lib/scope.js +69 -77
- package/lib/steps.js +70 -42
- package/lib/utils/Log.js +982 -0
- package/lib/utils/files.js +18 -11
- package/lib/utils/get_sources_paths.js +162 -0
- package/lib/utils/parse.js +1 -0
- package/lib/utils/proccess_command_line_args.js +267 -0
- package/lib/utils/reports.js +64 -17
- package/lib/utils/session_vars.js +34 -21
- package/lib/utils/time.js +44 -0
- package/package.json +1 -1
- package/tests/log_codes/check_codes.sh +2 -1
- package/tests/log_codes/log_code_expected_instances.txt +33 -9
- package/tests/unit_tests/getAllFields.test.js +5 -0
- package/tests/unit_tests/getMatchingRows.test.js +5 -0
- package/tests/unit_tests/log.test.js +581 -0
- package/tests/unit_tests/normalizeTable.test.js +5 -0
- package/lib/utils/log.js +0 -96
package/lib/scope.js
CHANGED
|
@@ -13,14 +13,12 @@ const pdf_reader = require('./utils/pdf_reader');
|
|
|
13
13
|
const session_vars = require('./utils/session_vars');
|
|
14
14
|
const get_base_interview_url = require(`./docassemble/get_base_interview_url`);
|
|
15
15
|
const time = require('./utils/time');
|
|
16
|
-
const log = require('./utils/log');
|
|
17
16
|
const { waitForTimeout } = require('./utils/time');
|
|
18
17
|
const files = require('./utils/files' );
|
|
19
18
|
const da_api = require('./docassemble/docassemble_api_interface');
|
|
20
19
|
const wrapPromiseWithTimeout = require('./cucumber_8_shim');
|
|
21
20
|
const reports = require(`./utils/reports`);
|
|
22
21
|
|
|
23
|
-
|
|
24
22
|
let ordinal_to_integer = {
|
|
25
23
|
only: 0, first: 0, second: 1, third: 2, fourth: 3, fifth: 4,
|
|
26
24
|
sixth: 5, seventh: 6, eighth: 7, ninth: 8, tenth: 9,
|
|
@@ -84,10 +82,16 @@ let toBase64 = function ( utf8_str, exclude_padding=true) {
|
|
|
84
82
|
|
|
85
83
|
let proxies_regex = /(\bx\.)|(\bx\[)|(\[[ijklmn]\])/g;
|
|
86
84
|
let da_base64_regex = /^[A-Za-z0-9+/]+$/;
|
|
85
|
+
let log = null;
|
|
87
86
|
|
|
88
87
|
module.exports = {
|
|
89
88
|
trigger_not_needed_flag: `ALKiln: no trigger variable needed`,
|
|
90
89
|
|
|
90
|
+
|
|
91
|
+
set_log: function ({ log_obj }) {
|
|
92
|
+
log = log_obj;
|
|
93
|
+
},
|
|
94
|
+
|
|
91
95
|
getSafeScenarioBaseFilename: async function( scope, { scenario }) {
|
|
92
96
|
/** Return a string that's safe to be a filename. Include the Scenario
|
|
93
97
|
* description and tags.
|
|
@@ -514,13 +518,17 @@ module.exports = {
|
|
|
514
518
|
},
|
|
515
519
|
|
|
516
520
|
continue_button_selector: `fieldset.da-field-buttons button[type="submit"].btn-primary`,
|
|
521
|
+
continue_button_selector_backup: `.da-fieldset.da-field-buttons button[type="submit"].btn-primary`,
|
|
517
522
|
signature_selector: `fieldset .dasigsave`,
|
|
523
|
+
signature_selector_backup: `.da-fieldset .dasigsave`,
|
|
518
524
|
continue: async function ( scope ) {
|
|
519
525
|
/* Presses whatever button it finds that might lead to the next page. */
|
|
520
526
|
// Any selectors I find seem somewhat precarious.
|
|
521
527
|
let elem = await Promise.race([
|
|
522
528
|
scope.page.waitForSelector(scope.continue_button_selector), // other pages (this is the most consistent way)
|
|
529
|
+
scope.page.waitForSelector(scope.continue_button_selector_backup),
|
|
523
530
|
scope.page.waitForSelector(scope.signature_selector), // signature page
|
|
531
|
+
scope.page.waitForSelector(scope.signature_selector_backup),
|
|
524
532
|
]);
|
|
525
533
|
await elem.evaluate( el => { return el.className });
|
|
526
534
|
// Waits for navigation or user error
|
|
@@ -540,9 +548,11 @@ module.exports = {
|
|
|
540
548
|
// <button type="submit" class="btn btn-da btn-danger" name="X211bHRpcGxlX2Nob2ljZQ" value="0">exit</button>
|
|
541
549
|
// `buttons:` can be used in question blocks as choices
|
|
542
550
|
let regular = await scope.page.$(scope.continue_button_selector);
|
|
551
|
+
let regular_backup = await scope.page.$(scope.continue_button_selector_backup);
|
|
543
552
|
let signature = await scope.page.$(scope.signature_selector);
|
|
553
|
+
let signature_backup = await scope.page.$(scope.signature_selector_backup);
|
|
544
554
|
|
|
545
|
-
return regular !== null || signature !== null;
|
|
555
|
+
return regular !== null || regular_backup !== null || signature !== null || signature_backup !== null;
|
|
546
556
|
|
|
547
557
|
}, // Ends scope.continue_exists()
|
|
548
558
|
|
|
@@ -692,7 +702,7 @@ module.exports = {
|
|
|
692
702
|
});
|
|
693
703
|
expect( load_result.error ).to.equal( '' );
|
|
694
704
|
} else {
|
|
695
|
-
reports.addToReport(scope, { type: `row info`, code: `ALK0117`, value: `Successfully found the interview
|
|
705
|
+
reports.addToReport(scope, { type: `row info`, code: `ALK0117`, value: `Successfully found the interview` });
|
|
696
706
|
}
|
|
697
707
|
|
|
698
708
|
return scope.page;
|
|
@@ -711,19 +721,19 @@ module.exports = {
|
|
|
711
721
|
if ( !scenario.interviews ) { scenario.interviews = {}; }
|
|
712
722
|
if ( !scenario.interviews[ vars.uid ] ) {
|
|
713
723
|
scenario.interviews[ vars.uid ] = vars;
|
|
714
|
-
log.debug({
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
});
|
|
724
|
+
log.debug({ code: `ALK0185`, context: `session_id_etc` },
|
|
725
|
+
`Saved new interview data. File path: ${ vars.i }. Session id: ${ vars.uid }.`
|
|
726
|
+
);
|
|
718
727
|
} else {
|
|
719
|
-
log.debug({
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
});
|
|
728
|
+
log.debug({ code: `ALK0186`, context: `session_id_etc` },
|
|
729
|
+
`Interview data already existed. File path: ${ vars.i }. Session id: ${ vars.uid }.`
|
|
730
|
+
);
|
|
723
731
|
}
|
|
724
732
|
return vars;
|
|
725
733
|
} else {
|
|
726
|
-
log.debug({ code: `ALK0187`,
|
|
734
|
+
log.debug({ code: `ALK0187`, context: `session_id_etc` },
|
|
735
|
+
`Found no interview data.`
|
|
736
|
+
);
|
|
727
737
|
return null;
|
|
728
738
|
}
|
|
729
739
|
}, // Ends scope.set_interview_session_data()
|
|
@@ -870,11 +880,9 @@ module.exports = {
|
|
|
870
880
|
supported_table.push( result );
|
|
871
881
|
} // ends for every row
|
|
872
882
|
|
|
873
|
-
log.debug({
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
pre: `scope.normalizedTable():\n ${JSON.stringify( supported_table )}`
|
|
877
|
-
});
|
|
883
|
+
log.debug({ code: `ALK0122`, context: `table`, },
|
|
884
|
+
`scope.normalizedTable():`, supported_table
|
|
885
|
+
);
|
|
878
886
|
|
|
879
887
|
return supported_table;
|
|
880
888
|
}, // Ends scope.normalizeTable()
|
|
@@ -916,7 +924,7 @@ module.exports = {
|
|
|
916
924
|
// All the different types of fields
|
|
917
925
|
// buttons, canvases, inputs of all kinds, selects (dropdowns), textareas. Are there more?
|
|
918
926
|
// Will deal with `option` once inside `select`
|
|
919
|
-
let all_nodes = $( `#dasigpage, fieldset button, .daquestionactionbutton, fieldset input, .da-form-group input, .da-form-group select, form select, .da-form-group textarea` );
|
|
927
|
+
let all_nodes = $( `#dasigpage, fieldset button, .da-fieldset button, .daquestionactionbutton, fieldset input, da-fieldset input, .da-form-group input, .da-form-group select, form select, .da-form-group textarea` );
|
|
920
928
|
for ( let node of all_nodes ) {
|
|
921
929
|
// Decision: Do not abstract the below. There's too much data to pass around for it to make sense
|
|
922
930
|
let $node = $( node );
|
|
@@ -1024,11 +1032,9 @@ module.exports = {
|
|
|
1024
1032
|
fields.push( field_data );
|
|
1025
1033
|
} // ends for every node
|
|
1026
1034
|
|
|
1027
|
-
log.debug({
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
pre: `page fields:\n${ JSON.stringify( fields )}`
|
|
1031
|
-
});
|
|
1035
|
+
log.debug({ code: `ALK0124`, context: `page fields`, },
|
|
1036
|
+
fields
|
|
1037
|
+
);
|
|
1032
1038
|
return fields;
|
|
1033
1039
|
}, // Ends scope.getAllFields()
|
|
1034
1040
|
|
|
@@ -1078,11 +1084,9 @@ module.exports = {
|
|
|
1078
1084
|
/* Return variable names and values combined in ways that can
|
|
1079
1085
|
* try to match table rows. Tables can have two properties:
|
|
1080
1086
|
* variable name and value. */
|
|
1081
|
-
log.debug({
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
pre: `scope.getPossibleTableRowMatchers() var_names: ${JSON.stringify(var_names)} values: ${JSON.stringify(values)}`
|
|
1085
|
-
});
|
|
1087
|
+
log.debug({ code: `ALK0126`, context: `matching`, },
|
|
1088
|
+
`scope.getPossibleTableRowMatchers() var_names:`, var_names, `values:`, values
|
|
1089
|
+
);
|
|
1086
1090
|
let possible_table_rows = [];
|
|
1087
1091
|
for ( let var_name of var_names ) {
|
|
1088
1092
|
// Inputs like textareas don't have values
|
|
@@ -1557,17 +1561,13 @@ module.exports = {
|
|
|
1557
1561
|
reports.addToReport(scope, { type: `warning`, code: `ALK0130`, value: multiple_matches_msg });
|
|
1558
1562
|
}
|
|
1559
1563
|
|
|
1560
|
-
log.debug({
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
pre: `final_matching_rows:\n${JSON.stringify( final_matching_rows )}`
|
|
1564
|
-
});
|
|
1564
|
+
log.debug({ code: `ALK0131`, context: `matching`, },
|
|
1565
|
+
`final_matching_rows:`, final_matching_rows
|
|
1566
|
+
);
|
|
1565
1567
|
if ( final_matching_rows.length == 0) {
|
|
1566
|
-
log.debug({
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
pre: `field:\n${JSON.stringify( field )}`
|
|
1570
|
-
});
|
|
1568
|
+
log.debug({ code: `ALK0132`, context: `matching`, },
|
|
1569
|
+
`0 matching rows. Field:`, field
|
|
1570
|
+
);
|
|
1571
1571
|
}
|
|
1572
1572
|
|
|
1573
1573
|
return final_matching_rows;
|
|
@@ -1653,11 +1653,9 @@ module.exports = {
|
|
|
1653
1653
|
|
|
1654
1654
|
get_handle_from_field: async function ( scope, { field }) {
|
|
1655
1655
|
/** Get the element's puppeteer handle using the field's selector. */
|
|
1656
|
-
log.debug({
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
pre: `scope.get_handle_from_field() field.selector: ${JSON.stringify(field.selector)}`
|
|
1660
|
-
});
|
|
1656
|
+
log.debug({ code: `ALK0133`, },
|
|
1657
|
+
`scope.get_handle_from_field() field.selector:`, field.selector
|
|
1658
|
+
);
|
|
1661
1659
|
let handle = await scope.page.evaluateHandle(( selector ) => {
|
|
1662
1660
|
let elem = document.querySelector( selector );
|
|
1663
1661
|
// If the element has a sibling that's a label, we need to
|
|
@@ -2169,7 +2167,9 @@ module.exports = {
|
|
|
2169
2167
|
* @param ensure_all_vars_used {bool} [false] = Default false. If true, errors if any
|
|
2170
2168
|
* object in var_data is not used during running of this function.
|
|
2171
2169
|
*/
|
|
2172
|
-
log.debug({
|
|
2170
|
+
log.debug({ code: `ALK0221`, before: `~~~~~~~~~~~~~~\n`, },
|
|
2171
|
+
`scope.setFields()`
|
|
2172
|
+
);
|
|
2173
2173
|
|
|
2174
2174
|
// Only record the page id once for each page to which we navigate
|
|
2175
2175
|
let { id } = await scope.examinePageID( scope, 'none to match' );
|
|
@@ -2213,8 +2213,7 @@ module.exports = {
|
|
|
2213
2213
|
// Accumulate number of times this row was used. Esp important for `.target_number`
|
|
2214
2214
|
await scope.increment_row_use( scope, { row: row_used });
|
|
2215
2215
|
|
|
2216
|
-
|
|
2217
|
-
|
|
2216
|
+
log.stdout({}, `\x1b[36m${ '*' }\x1b[0m`); // assumes var was set if no error occurred
|
|
2218
2217
|
}
|
|
2219
2218
|
} // ends for every non-submit-button field on the page
|
|
2220
2219
|
} // ends while fields are still being set
|
|
@@ -2259,7 +2258,7 @@ module.exports = {
|
|
|
2259
2258
|
// }
|
|
2260
2259
|
|
|
2261
2260
|
did_navigate = true;
|
|
2262
|
-
|
|
2261
|
+
log.stdout({}, `\x1b[36m${ 'v' }\x1b[0m`); // pressed button successfully
|
|
2263
2262
|
break;
|
|
2264
2263
|
|
|
2265
2264
|
} // ends if row_used
|
|
@@ -2306,7 +2305,7 @@ module.exports = {
|
|
|
2306
2305
|
// }
|
|
2307
2306
|
|
|
2308
2307
|
did_navigate = true;
|
|
2309
|
-
|
|
2308
|
+
log.stdout({}, `\x1b[36m${ '>' }\x1b[0m`); // continued successfully
|
|
2310
2309
|
} // ends if !did_navigate && ensure_navigation
|
|
2311
2310
|
|
|
2312
2311
|
if ( did_navigate && scope.check_all_for_a11y ) {
|
|
@@ -2635,6 +2634,7 @@ module.exports = {
|
|
|
2635
2634
|
|
|
2636
2635
|
let fullPage = true;
|
|
2637
2636
|
let signature_elem = await scope.page.$(scope.signature_selector);
|
|
2637
|
+
signature_elem = signature_elem || await scope.page.$(scope.signature_selector_backup);
|
|
2638
2638
|
if ( signature_elem !== null ) {
|
|
2639
2639
|
fullPage = false;
|
|
2640
2640
|
}
|
|
@@ -3102,36 +3102,30 @@ module.exports = {
|
|
|
3102
3102
|
let redirect_promise = scope.page.waitForResponse(function ( response ) {
|
|
3103
3103
|
return response.status() === 302;
|
|
3104
3104
|
}, { signal: controller.signal })
|
|
3105
|
-
.catch((
|
|
3106
|
-
log.debug({
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
data: error,
|
|
3110
|
-
});
|
|
3105
|
+
.catch(( catch_info ) => {
|
|
3106
|
+
log.debug({ code: `ALK0204`, context: `nav`, },
|
|
3107
|
+
`302 sign-in wait catch error:`, catch_info.name, catch_info,
|
|
3108
|
+
);
|
|
3111
3109
|
});
|
|
3112
3110
|
|
|
3113
3111
|
// Invalid credentials, no navigation, no sign in
|
|
3114
3112
|
let wrong_sign_in_promise = scope.page.waitForResponse(function ( response ) {
|
|
3115
3113
|
return response.status() >= 200 && response.status() < 300 && response.url().includes(`/sign-in`);
|
|
3116
3114
|
}, { signal: controller.signal })
|
|
3117
|
-
.catch((
|
|
3118
|
-
log.debug({
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
data: error,
|
|
3122
|
-
});
|
|
3115
|
+
.catch(( catch_info ) => {
|
|
3116
|
+
log.debug({ code: `ALK0205`, context: `nav`, },
|
|
3117
|
+
`200s sign-in wait catch error:`, catch_info.name, catch_info,
|
|
3118
|
+
);
|
|
3123
3119
|
});
|
|
3124
3120
|
|
|
3125
3121
|
// System error
|
|
3126
3122
|
let error_promise = scope.page.waitForResponse(function ( response ) {
|
|
3127
3123
|
return response.status() >= 500 && response.status() < 600;
|
|
3128
3124
|
}, { signal: controller.signal })
|
|
3129
|
-
.catch((
|
|
3130
|
-
log.debug({
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
data: error,
|
|
3134
|
-
});
|
|
3125
|
+
.catch(( catch_info ) => {
|
|
3126
|
+
log.debug({ code: `ALK0206`, context: `nav`, },
|
|
3127
|
+
`500s sign-in wait catch error:`, catch_info.name, catch_info,
|
|
3128
|
+
);
|
|
3135
3129
|
});
|
|
3136
3130
|
|
|
3137
3131
|
let click_promise = elem.click(); // MUST complete
|
|
@@ -3150,10 +3144,9 @@ module.exports = {
|
|
|
3150
3144
|
// Clean up unresolved promises
|
|
3151
3145
|
controller.abort();
|
|
3152
3146
|
|
|
3153
|
-
log.debug({
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
});
|
|
3147
|
+
log.debug({ code: `ALK0208`, context: `nav` },
|
|
3148
|
+
`Sign-in winner:`, winner
|
|
3149
|
+
);
|
|
3157
3150
|
|
|
3158
3151
|
return winner;
|
|
3159
3152
|
},
|
|
@@ -3176,7 +3169,7 @@ module.exports = {
|
|
|
3176
3169
|
} else {
|
|
3177
3170
|
// Try to give a random answer for that element tag
|
|
3178
3171
|
await scope.set_random_input_for[ field.tag ]( scope, { field: field });
|
|
3179
|
-
|
|
3172
|
+
log.stdout({}, `\x1b[36m${ '*' }\x1b[0m`); // assumes var was set if no error occurred
|
|
3180
3173
|
}
|
|
3181
3174
|
|
|
3182
3175
|
} // End for all page fields
|
|
@@ -3212,11 +3205,10 @@ module.exports = {
|
|
|
3212
3205
|
}
|
|
3213
3206
|
if (field == null) {
|
|
3214
3207
|
// Just skip it? Shouldn't happen but has before. Dig in more
|
|
3215
|
-
log.debug({
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
});
|
|
3208
|
+
log.debug({ code: `ALK0164`, context: `random`, },
|
|
3209
|
+
`A random button field choice was null. These were the fields to choose from:`,
|
|
3210
|
+
fields
|
|
3211
|
+
);
|
|
3220
3212
|
return;
|
|
3221
3213
|
}
|
|
3222
3214
|
let handle = await scope.get_handle_from_field( scope, { field: field });
|
package/lib/steps.js
CHANGED
|
@@ -5,6 +5,7 @@ const {
|
|
|
5
5
|
Given,
|
|
6
6
|
After,
|
|
7
7
|
Before,
|
|
8
|
+
AfterStep,
|
|
8
9
|
BeforeAll,
|
|
9
10
|
AfterAll,
|
|
10
11
|
setDefaultTimeout //,
|
|
@@ -18,7 +19,7 @@ const { v4: uuidv4 } = require('uuid');
|
|
|
18
19
|
|
|
19
20
|
// Ours
|
|
20
21
|
const scope = require('./scope');
|
|
21
|
-
const
|
|
22
|
+
const Log = require(`./utils/Log`);
|
|
22
23
|
const session_vars = require('./utils/session_vars');
|
|
23
24
|
const files = require('./utils/files' );
|
|
24
25
|
const reports = require(`./utils/reports`);
|
|
@@ -82,7 +83,9 @@ let click_with = {
|
|
|
82
83
|
pc: 'click',
|
|
83
84
|
};
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
let log = null;
|
|
87
|
+
|
|
88
|
+
BeforeAll(async function() {
|
|
86
89
|
scope.showif_timeout = 600;
|
|
87
90
|
// TODO: Do these really need to be maps? As sets, they may make the output
|
|
88
91
|
// more predictable to the user, but they add complexity.
|
|
@@ -95,29 +98,30 @@ BeforeAll(async () => {
|
|
|
95
98
|
// Store path names for files and docs created for the tests
|
|
96
99
|
scope.paths = {};
|
|
97
100
|
|
|
98
|
-
//
|
|
99
|
-
//
|
|
101
|
+
// // Make the folder to store all the files for this run of the tests
|
|
102
|
+
// scope.paths.artifacts = files.make_artifacts_folder();
|
|
103
|
+
// // Save its name in a file. `session_vars` can get it back later.
|
|
104
|
+
// // The value we are saving is used by at least run_cucumber.js.
|
|
100
105
|
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
// A little indirect, but the artifacts path should always have already been
|
|
107
|
+
// created by now, either by `run_cucumber.js` or the relevant test
|
|
108
|
+
scope.paths.artifacts = session_vars.get_artifacts_path_name();
|
|
109
|
+
log = new Log({ path: scope.paths.artifacts, context: `steps` });
|
|
110
|
+
scope.set_log({ log_obj: log });
|
|
106
111
|
|
|
107
|
-
scope.paths.
|
|
108
|
-
scope.paths.
|
|
109
|
-
scope.paths.
|
|
110
|
-
|
|
112
|
+
scope.paths.debug_log = `${ scope.paths.artifacts }/${ log.debug_log_filename }`;
|
|
113
|
+
scope.paths.report_log = `${ scope.paths.artifacts }/${ log.report_log_filename }`;
|
|
114
|
+
scope.paths.report = `${ scope.paths.artifacts }/${ log.report_filename }`;
|
|
115
|
+
scope.paths.debug_of_unexpected = `${ scope.paths.artifacts }/${ log.temp_unexpected_debug_log_filename }`;
|
|
116
|
+
scope.paths.report_of_unexpected = `${ scope.paths.artifacts }/${ log.unexpected_filename }`;
|
|
111
117
|
|
|
112
118
|
reports.create( scope );
|
|
113
119
|
});
|
|
114
120
|
|
|
115
121
|
Before(async (scenario) => {
|
|
116
122
|
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
console.log('');
|
|
120
|
-
process.stdout.write(`Scenario: ${ scenario.pickle.name }: `);
|
|
123
|
+
// Start the running "progress bar" for the Scenario
|
|
124
|
+
log.stdout({}, `\nScenario: ${ scenario.pickle.name }: `);
|
|
121
125
|
|
|
122
126
|
// Create browser, which can't be created in BeforeAll() where .driver doesn't exist for some reason
|
|
123
127
|
if (!scope.browser) {
|
|
@@ -396,11 +400,9 @@ When(/^(?:the user gets)?(?:I get)? to ?(?:the)?(?: ?question)?(?: id)? "([^"]+)
|
|
|
396
400
|
from_story_table: true,
|
|
397
401
|
});
|
|
398
402
|
|
|
399
|
-
log.debug({
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
pre: `Rows, including special rows:, ${JSON.stringify( ensured_var_data )}`,
|
|
403
|
-
});
|
|
403
|
+
log.debug({ code: `ALK0061`, context: `table`, },
|
|
404
|
+
`Rows, including special rows:`, ensured_var_data
|
|
405
|
+
);
|
|
404
406
|
|
|
405
407
|
// THIS FUNCTION ACTUALLY MATTERS
|
|
406
408
|
// Some errors happen in there to be closer to the relevant code. We'd have to try/catch anyway.
|
|
@@ -972,7 +974,7 @@ When(/I answer randomly for at most ([0-9]+) (?:page(?:s)?|screen(?:s)?)/, { tim
|
|
|
972
974
|
} // ends if !has_content
|
|
973
975
|
|
|
974
976
|
if ( buttons_exist ) {
|
|
975
|
-
|
|
977
|
+
log.stdout({}, `\x1b[36m${ 'v' }\x1b[0m`); // pressed button
|
|
976
978
|
}
|
|
977
979
|
|
|
978
980
|
resolve();
|
|
@@ -1263,11 +1265,22 @@ Then(/I fail to delete (\d) detected interview(?:s)? and get no error __internal
|
|
|
1263
1265
|
//#####################################
|
|
1264
1266
|
//#####################################
|
|
1265
1267
|
|
|
1268
|
+
AfterStep(async function({ result }) {
|
|
1269
|
+
// TODO: Abstract this
|
|
1270
|
+
if ( result.status === `PASSED` ) { log.stdout({ records_only: true }, `.`); }
|
|
1271
|
+
else if ( result.status === `FAILED` ) { log.stdout({ records_only: true }, `F`); }
|
|
1272
|
+
else if ( result.status === `UNDEFINED` ) { log.stdout({ records_only: true }, `U`); }
|
|
1273
|
+
else if ( result.status === `SKIPPED` ) { log.stdout({ records_only: true }, `-`); }
|
|
1274
|
+
else if ( result.status === `PENDING` ) { log.stdout({ records_only: true }, `P`); }
|
|
1275
|
+
});
|
|
1276
|
+
|
|
1266
1277
|
After(async function(scenario) {
|
|
1267
1278
|
|
|
1268
1279
|
// Log errors
|
|
1269
1280
|
if ( scenario.result.message ) {
|
|
1270
|
-
log.debug({
|
|
1281
|
+
log.debug({ code: `ALK0091`, context: `scenario`, },
|
|
1282
|
+
scenario.result.message
|
|
1283
|
+
);
|
|
1271
1284
|
}
|
|
1272
1285
|
|
|
1273
1286
|
let changeable_test_status = scenario.result.status;
|
|
@@ -1297,11 +1310,9 @@ After(async function(scenario) {
|
|
|
1297
1310
|
reports.saveFinalScenarioData( scope, { status: changeable_test_status });
|
|
1298
1311
|
|
|
1299
1312
|
if (changeable_test_status !== `PASSED`) {
|
|
1300
|
-
log.debug({
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
pre: `Non-passed status occurred while running test: ${changeable_test_status}`,
|
|
1304
|
-
});
|
|
1313
|
+
log.debug({ code: `ALK0094`, level: `warn`, },
|
|
1314
|
+
`Non-passed status occurred while running test: ${ changeable_test_status }`
|
|
1315
|
+
);
|
|
1305
1316
|
|
|
1306
1317
|
if ( scope.page ) {
|
|
1307
1318
|
|
|
@@ -1397,8 +1408,9 @@ After(async function(scenario) {
|
|
|
1397
1408
|
+ `Expected status: ${scope.expected_status}. `
|
|
1398
1409
|
+ `See the report for details.`;
|
|
1399
1410
|
let code = `ALK0099`;
|
|
1400
|
-
log.debug({
|
|
1401
|
-
|
|
1411
|
+
expected_status_err_msg = log.debug({ code: code, level: `error`, },
|
|
1412
|
+
msg
|
|
1413
|
+
);
|
|
1402
1414
|
}
|
|
1403
1415
|
}
|
|
1404
1416
|
scope.expected_status = null; // reset for next Scenario
|
|
@@ -1418,17 +1430,25 @@ After(async function(scenario) {
|
|
|
1418
1430
|
// Make sure that tests which ALKiln has calculated as failed
|
|
1419
1431
|
// cause a cucumber error later. Just changing the status to `FAILED`
|
|
1420
1432
|
// causes unhelpful cucumber errors. TODO: Add to internal docs.
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
});
|
|
1433
|
+
// TODO: Should we move this to where the error is thrown?
|
|
1434
|
+
log.debug({ code: force_failure_code, level: `error`, },
|
|
1435
|
+
force_failure_msg
|
|
1436
|
+
);
|
|
1426
1437
|
// TODO: Look into setDefinitionFunctionWrapper to catch errors
|
|
1427
1438
|
// of failing tests that should indeed be failing:
|
|
1428
1439
|
// https://github.com/cucumber/cucumber-js/blob/main/docs/support_files/api_reference.md#setdefinitionfunctionwrapperwrapper
|
|
1429
1440
|
need_to_force_failed_status = true;
|
|
1430
1441
|
}
|
|
1431
1442
|
|
|
1443
|
+
// Not sure if this is necessary
|
|
1444
|
+
if ( changeable_test_status === 'PASSED' ) {
|
|
1445
|
+
log.stdout({ records_only: true }, `.` );
|
|
1446
|
+
} else if ( changeable_test_status === `SKIPPED` ) {
|
|
1447
|
+
log.stdout({ records_only: true }, `-` );
|
|
1448
|
+
} else {
|
|
1449
|
+
log.stdout({ records_only: true }, changeable_test_status[0].toUpperCase() );
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1432
1452
|
let signout_succeeded = true;
|
|
1433
1453
|
let signout_error_msg = ``;
|
|
1434
1454
|
// If there is a page open, then sign out and close it
|
|
@@ -1482,9 +1502,10 @@ After(async function(scenario) {
|
|
|
1482
1502
|
// going to the wrong file). If it becomes a problem we can track it down later.
|
|
1483
1503
|
if ( visible_keys.length > 0 ) {
|
|
1484
1504
|
// Can an API key ever see an interview that it can't delete?
|
|
1485
|
-
log.
|
|
1486
|
-
|
|
1487
|
-
|
|
1505
|
+
log.debug({ code: `ALK0197`, context: `internal`, level: `warn`, }
|
|
1506
|
+
`The API key can see ${ visible_keys.length } interviews that were not deleted:`,
|
|
1507
|
+
visible_keys
|
|
1508
|
+
);
|
|
1488
1509
|
}
|
|
1489
1510
|
} catch ( error ) {
|
|
1490
1511
|
// Deleting interviews is nice, but not non-critical. Don't bother the
|
|
@@ -1494,7 +1515,9 @@ After(async function(scenario) {
|
|
|
1494
1515
|
// interview. If it becomes a problem we can track it down later.
|
|
1495
1516
|
// Consider add "internal" to docs: "If you see this, make an
|
|
1496
1517
|
// issue in ALKiln with your debug/verbose log"
|
|
1497
|
-
log.
|
|
1518
|
+
log.debug({ code: `ALK0198`, context: `internal`, level: `warn`, error },
|
|
1519
|
+
`Cleaning up interviews incomplete, but unimportant.`
|
|
1520
|
+
);
|
|
1498
1521
|
}
|
|
1499
1522
|
}
|
|
1500
1523
|
|
|
@@ -1513,11 +1536,16 @@ After(async function(scenario) {
|
|
|
1513
1536
|
throw new Error( `🤕 ${ force_failure_code } unreachable ERROR: ${ force_failure_msg }` );
|
|
1514
1537
|
|
|
1515
1538
|
} else if ( internal_errors.length > 0 ) {
|
|
1516
|
-
log.
|
|
1539
|
+
log.debug({ code: `ALK0203`, context: `internal`, level: `warn`, },
|
|
1540
|
+
`There was no need to force failed status and yet there are error messages.`,
|
|
1541
|
+
internal_errors
|
|
1542
|
+
);
|
|
1517
1543
|
}
|
|
1518
1544
|
|
|
1519
1545
|
// Find the race condition.
|
|
1520
|
-
log.debug({
|
|
1546
|
+
log.debug({ code: `ALK0100`, context: `scenario`, },
|
|
1547
|
+
`Scenario After() message:`, scenario.result.message
|
|
1548
|
+
);
|
|
1521
1549
|
|
|
1522
1550
|
});
|
|
1523
1551
|
|