@suffolklitlab/alkiln 5.13.3 → 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 +24 -0
- 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 +320 -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 -1
- package/docs/decisions/reports_and_logs_2024_08_11.md +161 -0
- package/docs/kinds_of_errors.md +26 -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 +60 -75
- 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
|
@@ -1,26 +1,49 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const da_i = require('./docassemble_api_interface');
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const session_vars = require('../utils/session_vars');
|
|
5
|
+
const Log = require('../utils/Log');
|
|
6
|
+
|
|
7
|
+
const context = `takedown`;
|
|
6
8
|
|
|
7
9
|
const takedown = async () => {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
/** In the docassemble testing account identified by the
|
|
11
|
+
* DOCASSEMBLE_DEVELOPER_API_KEY secret, delete the Project created for this
|
|
12
|
+
* test. For local development, clean up Project name in the runtime_config
|
|
13
|
+
* file.
|
|
14
|
+
* */
|
|
15
|
+
log.info({ code: `ALK0177`, context, },
|
|
16
|
+
`Trying to remove the docassemble Project from the testing account.`
|
|
17
|
+
);
|
|
13
18
|
// Explicit try-catch prevents "Unhandled promise rejection error"
|
|
14
19
|
// avoids showing confusing node errors to users that they shouldn't have to fix
|
|
15
20
|
try {
|
|
16
21
|
await da_i.delete_project();
|
|
17
22
|
session_vars.delete_project_name();
|
|
18
|
-
log.
|
|
23
|
+
log.info({ code: `ALK0178`, context, },
|
|
24
|
+
`Test takedown finished successfully!`
|
|
25
|
+
);
|
|
19
26
|
} catch (error) {
|
|
20
|
-
log.
|
|
21
|
-
|
|
27
|
+
log.throw({ code: `ALK0179`, context, error: error },
|
|
28
|
+
`Unable to delete project`,
|
|
29
|
+
);
|
|
30
|
+
// we don't re-throw the exception, so make sure to exit
|
|
31
|
+
// with 1 to let GitHub Actions know the script failed
|
|
22
32
|
process.exitCode = 1;
|
|
23
33
|
}
|
|
34
|
+
|
|
35
|
+
// TODO: ? Build the final setup, run, & takedown verbose log
|
|
36
|
+
// file in here. Add to it in the GitHub action ?
|
|
24
37
|
};
|
|
25
38
|
|
|
39
|
+
// 1. session_vars - make sure all the required env vars exist
|
|
40
|
+
session_vars.validateEnvironment();
|
|
41
|
+
|
|
42
|
+
// 2. Prepare logs
|
|
43
|
+
// Local devs: This will be separate from your test artifacts paths
|
|
44
|
+
// unless you pass a `path` argument into the `cucumber` run command
|
|
45
|
+
const argv = require(`minimist`)( process.argv.slice(2) );
|
|
46
|
+
const log = new Log({ path: argv.path, context, });
|
|
47
|
+
|
|
48
|
+
// 3. run
|
|
26
49
|
takedown();
|
package/lib/parse.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
let log = `log`;
|
|
4
|
+
let args = get_command_line_args();
|
|
5
|
+
let sources_paths = get_sources_paths( args );
|
|
6
|
+
let feature_files_paths = get_feature_files( sources_paths );
|
|
7
|
+
|
|
8
|
+
let all_errors = [];
|
|
9
|
+
// Just see if any error when Gherkin parses them
|
|
10
|
+
for ( let file_path of feature_files_paths ) {
|
|
11
|
+
try {
|
|
12
|
+
Gherkin.parse( file_path );
|
|
13
|
+
} catch ( error ) {
|
|
14
|
+
all_errors.push( error );
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// let generated_files_paths = constrained_random_answer_tests.generate();
|
|
18
|
+
// // Just see if any error when Gherkin parses them
|
|
19
|
+
// for ( let generated_path of generated_files_paths ) {
|
|
20
|
+
// try {
|
|
21
|
+
// Gherkin.parse( generated_path );
|
|
22
|
+
// } catch ( error ) {
|
|
23
|
+
// all_errors.push( error );
|
|
24
|
+
// }
|
|
25
|
+
// }
|
|
26
|
+
|
|
27
|
+
let generator_errors = constrained_random_answer_tests.generate();
|
|
28
|
+
all_errors = [ ...all_errors, ...generator_errors ];
|
|
29
|
+
|
|
30
|
+
if ( all_errors.length > 0 ) {
|
|
31
|
+
// Use the Log class in here
|
|
32
|
+
for ( let one_error of all_errors ) {
|
|
33
|
+
console.log( `An error:`, one_error );
|
|
34
|
+
}
|
|
35
|
+
throw new Error( `ALKiln ran into an error when parsing the test files. See above for more details` );
|
|
36
|
+
}
|
package/lib/run_cucumber.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
+
const path = require(`path`);
|
|
4
5
|
const cucumber_api = require('@cucumber/cucumber/api');
|
|
5
6
|
|
|
6
|
-
const
|
|
7
|
+
const Log = require('./utils/Log');
|
|
7
8
|
const session_vars = require('./utils/session_vars');
|
|
8
9
|
|
|
9
10
|
const SUMMARY_FILENAME = `cucumber-report.txt`;
|
|
@@ -53,11 +54,14 @@ function build_config( command_args ) {
|
|
|
53
54
|
}; // Ends build_config()
|
|
54
55
|
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
async function main() {
|
|
57
58
|
/** Create the cucumber config, run the tests, create and
|
|
58
59
|
* manipluate the output. */
|
|
60
|
+
|
|
59
61
|
const environment = { cwd: process.cwd() };
|
|
60
|
-
log.info({
|
|
62
|
+
log.info({ code: `ALK0049`, context: `pre_run environment` },
|
|
63
|
+
environment
|
|
64
|
+
);
|
|
61
65
|
|
|
62
66
|
// We'll use the user info to construct the possible paths to /sources
|
|
63
67
|
let id = session_vars.get_user_id();
|
|
@@ -65,8 +69,9 @@ function build_config( command_args ) {
|
|
|
65
69
|
let project = session_vars.get_user_project_name();
|
|
66
70
|
|
|
67
71
|
// process.argv is a list of strings of commands and args.
|
|
68
|
-
// If using `npm run cucumber
|
|
69
|
-
|
|
72
|
+
// If using `npm run cucumber` (as opposed to the bin commands),
|
|
73
|
+
// use `--` before `--sources=./foo`
|
|
74
|
+
const argv = require(`minimist`)( process.argv.slice(2), {
|
|
70
75
|
default: {
|
|
71
76
|
sources: [
|
|
72
77
|
`./docassemble/*/data/sources`, // In GitHub folder
|
|
@@ -85,35 +90,52 @@ function build_config( command_args ) {
|
|
|
85
90
|
let one_dir_exists = session_vars.set_sources_paths( sources_list );
|
|
86
91
|
if ( !one_dir_exists ) {
|
|
87
92
|
// If we don't throw, it'll be more confusing when no tests run
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
log.throw({ code: `ALK0050`, context: `pre_run`,
|
|
94
|
+
error: new ReferenceError(
|
|
95
|
+
`ALKiln can't find your "sources" folder(s). See above for details.`
|
|
96
|
+
),
|
|
97
|
+
});
|
|
92
98
|
}
|
|
93
99
|
|
|
94
100
|
const { runConfiguration } = await cucumber_api.loadConfiguration({
|
|
95
101
|
provided: build_config( argv ),
|
|
96
102
|
}, environment);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
log.info({
|
|
103
|
+
log.info({ code: `ALK0051`, context: `pre_run config`, },
|
|
104
|
+
runConfiguration
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const codeDir = path.dirname(require.main.filename);
|
|
108
|
+
log.info({ code: `ALK0052`, context: `pre_run directory`, },
|
|
109
|
+
codeDir, `\n\n`
|
|
110
|
+
);
|
|
103
111
|
const support = await cucumber_api.loadSupport({ support: {
|
|
104
112
|
requireModules: [ `${ codeDir }/index.js` ],
|
|
105
113
|
requirePaths: [ `${ codeDir }/index.js` ],
|
|
106
114
|
importPaths: [],
|
|
107
115
|
}, sources: {paths: []}}, environment);
|
|
108
116
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
117
|
+
// ====================
|
|
118
|
+
/** Run */
|
|
119
|
+
// ====================
|
|
112
120
|
const { success } = await cucumber_api.runCucumber({...runConfiguration, support});
|
|
121
|
+
// ====================
|
|
122
|
+
|
|
123
|
+
/** Write to files.
|
|
124
|
+
*
|
|
125
|
+
* Note: Don't add to the purely report-focused files. Those are files where
|
|
126
|
+
* authors can focus on the info we give them, which they often miss in
|
|
127
|
+
* the GitHub action.
|
|
128
|
+
*/
|
|
129
|
+
|
|
113
130
|
if ( success ) {
|
|
114
|
-
log.success({
|
|
131
|
+
log.success({ code: `ALK0054`, context: `post_run`, },
|
|
132
|
+
`Tests succeeded!`
|
|
133
|
+
);
|
|
115
134
|
} else {
|
|
116
|
-
|
|
135
|
+
// Don't want to throw error here, so don't pass error object
|
|
136
|
+
log.warn({ code: `ALK0055`, context: `post_run`, },
|
|
137
|
+
`The tests ran into something unexpected. Look above for more details.`
|
|
138
|
+
);
|
|
117
139
|
}
|
|
118
140
|
// Custom exit code. May overlap with other systems.
|
|
119
141
|
// Best info I've found via stack overflow: https://tldp.org/LDP/abs/html/exitcodes.html
|
|
@@ -123,10 +145,12 @@ function build_config( command_args ) {
|
|
|
123
145
|
// This is hardcoded information from `provide_config` above.
|
|
124
146
|
// This code isn't used for anything other than detecting and removing color codes.
|
|
125
147
|
let summary_file_name = SUMMARY_FILENAME;
|
|
126
|
-
fs.readFile(summary_file_name, 'utf8', (
|
|
127
|
-
if (
|
|
148
|
+
fs.readFile(summary_file_name, 'utf8', (read_error, text) => {
|
|
149
|
+
if ( read_error ) {
|
|
128
150
|
// Something else will probably show an error that's more relevant
|
|
129
|
-
log.
|
|
151
|
+
log.warn({ code: `ALK0056`, context: `post_run error`, },
|
|
152
|
+
`Failed to read cucumber report`, read_error
|
|
153
|
+
);
|
|
130
154
|
return;
|
|
131
155
|
}
|
|
132
156
|
|
|
@@ -134,20 +158,75 @@ function build_config( command_args ) {
|
|
|
134
158
|
// https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#colors--graphics-mode
|
|
135
159
|
text = text.replace(/\x1b\[[0-9][0-9]?[0-9]?m/g, '');
|
|
136
160
|
|
|
137
|
-
// Put it in the correct file in the correct folder
|
|
138
|
-
let artifacts_path = session_vars.get_artifacts_path_name();
|
|
139
|
-
try {
|
|
140
|
-
fs.appendFileSync( `${ artifacts_path }/${ log.debug_log_file }`, `\n\n${text}`);
|
|
141
|
-
} catch ( error ) {
|
|
142
|
-
log.info({ type: `run`, code: `ALK0182`, pre: `Something probably went wrong earlier. Look above for more details, but here is more information just in case: ALKiln was unable to write to ${ artifacts_path }/${ log.debug_log_file }.`, data: error });
|
|
143
|
-
}
|
|
144
161
|
try {
|
|
145
|
-
// Add to
|
|
162
|
+
// Add to the debug and non-passed test output files
|
|
146
163
|
if ( exitCode === 50 ) {
|
|
147
|
-
|
|
164
|
+
// Save only non-passing test output to cut out cruft.
|
|
165
|
+
// Our reports save only non-passing tests to this file.
|
|
166
|
+
log.debug({ icon: `🔎`, code: `ALK0216`, context: `post_run`, level: `warn` },
|
|
167
|
+
`\n\n`, text
|
|
168
|
+
);
|
|
169
|
+
} else {
|
|
170
|
+
log.debug({ code: `ALK0225`, context: `post_run`, },
|
|
171
|
+
`\n\n`, text
|
|
172
|
+
);
|
|
148
173
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
174
|
+
|
|
175
|
+
/** Include debug info at the bottom of the unexpected results file if
|
|
176
|
+
* needed. Avoid creating the file if its not necessary. */
|
|
177
|
+
let temp_debug_unexpected_content = ``;
|
|
178
|
+
try {
|
|
179
|
+
temp_debug_unexpected_content = fs.readFileSync(`${ log.path }/${ log.temp_unexpected_debug_log_filename }`);
|
|
180
|
+
} catch ( ignore_err ) { /* Missing debug info is ok */ }
|
|
181
|
+
|
|
182
|
+
if ( temp_debug_unexpected_content !== `` ) {
|
|
183
|
+
// Add spacing before the debug content if file already has content
|
|
184
|
+
try {
|
|
185
|
+
fs.readFileSync(`${ log.path }/${ log.unexpected_filename }`); // Does it have contents?
|
|
186
|
+
fs.appendFileSync(`${ log.path }/${ log.unexpected_filename }`, `\n\n\n\n\n` );
|
|
187
|
+
} catch ( ignore_err ) { /* Missing unexpected file is ok */ }
|
|
188
|
+
|
|
189
|
+
// Add the heading for debug content
|
|
190
|
+
fs.appendFileSync( `${ log.path }/${ log.unexpected_filename }`,
|
|
191
|
+
`≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
|
|
192
|
+
🐛 Full DEBUG info (some repeated content) 🐛
|
|
193
|
+
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n\n`
|
|
194
|
+
);
|
|
195
|
+
// Add the debug content itself
|
|
196
|
+
fs.appendFileSync(`${ log.path }/${ log.unexpected_filename }`, temp_debug_unexpected_content );
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
} catch ( writing_cucumber_error ) {
|
|
200
|
+
let code = `ALK0182`;
|
|
201
|
+
let context = `post_run error`
|
|
202
|
+
let msg = `Something probably went wrong earlier. Look above for more details. Skipped writing to ${ log.path }/${ log.debug_log_filename }.`;
|
|
203
|
+
try {
|
|
204
|
+
log.warn({ code, context, }, msg, writing_cucumber_error );
|
|
205
|
+
} catch ( all_writing_error ) {
|
|
206
|
+
console.warn( `🔎 ${ code } ${ context } WARNING ${ Date.now() }: ${ msg }` );
|
|
207
|
+
console.warn( writing_cucumber_error );
|
|
208
|
+
console.warn( all_writing_error );
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
} // ends try writing to debug files
|
|
212
|
+
|
|
213
|
+
return;
|
|
152
214
|
});
|
|
153
|
-
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
// 1. session_vars - make sure all the required env vars exist
|
|
219
|
+
session_vars.validateEnvironment();
|
|
220
|
+
|
|
221
|
+
// 2. Prepare logs
|
|
222
|
+
// process.argv is a list of strings of commands and args.
|
|
223
|
+
// If using `npm run cucumber` (as opposed to the bin commands),
|
|
224
|
+
// use `--` before `--sources=./foo`
|
|
225
|
+
const argv = require(`minimist`)( process.argv.slice(2) );
|
|
226
|
+
// The artifacts folder might be getting created for the first
|
|
227
|
+
// time right here. The tests themselves should avoid creating
|
|
228
|
+
// their own file.
|
|
229
|
+
const log = new Log({ path: argv.path, context: `run` });
|
|
230
|
+
|
|
231
|
+
// 3. run
|
|
232
|
+
main();
|
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.
|
|
@@ -698,7 +702,7 @@ module.exports = {
|
|
|
698
702
|
});
|
|
699
703
|
expect( load_result.error ).to.equal( '' );
|
|
700
704
|
} else {
|
|
701
|
-
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` });
|
|
702
706
|
}
|
|
703
707
|
|
|
704
708
|
return scope.page;
|
|
@@ -717,19 +721,19 @@ module.exports = {
|
|
|
717
721
|
if ( !scenario.interviews ) { scenario.interviews = {}; }
|
|
718
722
|
if ( !scenario.interviews[ vars.uid ] ) {
|
|
719
723
|
scenario.interviews[ vars.uid ] = vars;
|
|
720
|
-
log.debug({
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
});
|
|
724
|
+
log.debug({ code: `ALK0185`, context: `session_id_etc` },
|
|
725
|
+
`Saved new interview data. File path: ${ vars.i }. Session id: ${ vars.uid }.`
|
|
726
|
+
);
|
|
724
727
|
} else {
|
|
725
|
-
log.debug({
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
});
|
|
728
|
+
log.debug({ code: `ALK0186`, context: `session_id_etc` },
|
|
729
|
+
`Interview data already existed. File path: ${ vars.i }. Session id: ${ vars.uid }.`
|
|
730
|
+
);
|
|
729
731
|
}
|
|
730
732
|
return vars;
|
|
731
733
|
} else {
|
|
732
|
-
log.debug({ code: `ALK0187`,
|
|
734
|
+
log.debug({ code: `ALK0187`, context: `session_id_etc` },
|
|
735
|
+
`Found no interview data.`
|
|
736
|
+
);
|
|
733
737
|
return null;
|
|
734
738
|
}
|
|
735
739
|
}, // Ends scope.set_interview_session_data()
|
|
@@ -876,11 +880,9 @@ module.exports = {
|
|
|
876
880
|
supported_table.push( result );
|
|
877
881
|
} // ends for every row
|
|
878
882
|
|
|
879
|
-
log.debug({
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
pre: `scope.normalizedTable():\n ${JSON.stringify( supported_table )}`
|
|
883
|
-
});
|
|
883
|
+
log.debug({ code: `ALK0122`, context: `table`, },
|
|
884
|
+
`scope.normalizedTable():`, supported_table
|
|
885
|
+
);
|
|
884
886
|
|
|
885
887
|
return supported_table;
|
|
886
888
|
}, // Ends scope.normalizeTable()
|
|
@@ -1030,11 +1032,9 @@ module.exports = {
|
|
|
1030
1032
|
fields.push( field_data );
|
|
1031
1033
|
} // ends for every node
|
|
1032
1034
|
|
|
1033
|
-
log.debug({
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
pre: `page fields:\n${ JSON.stringify( fields )}`
|
|
1037
|
-
});
|
|
1035
|
+
log.debug({ code: `ALK0124`, context: `page fields`, },
|
|
1036
|
+
fields
|
|
1037
|
+
);
|
|
1038
1038
|
return fields;
|
|
1039
1039
|
}, // Ends scope.getAllFields()
|
|
1040
1040
|
|
|
@@ -1084,11 +1084,9 @@ module.exports = {
|
|
|
1084
1084
|
/* Return variable names and values combined in ways that can
|
|
1085
1085
|
* try to match table rows. Tables can have two properties:
|
|
1086
1086
|
* variable name and value. */
|
|
1087
|
-
log.debug({
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
pre: `scope.getPossibleTableRowMatchers() var_names: ${JSON.stringify(var_names)} values: ${JSON.stringify(values)}`
|
|
1091
|
-
});
|
|
1087
|
+
log.debug({ code: `ALK0126`, context: `matching`, },
|
|
1088
|
+
`scope.getPossibleTableRowMatchers() var_names:`, var_names, `values:`, values
|
|
1089
|
+
);
|
|
1092
1090
|
let possible_table_rows = [];
|
|
1093
1091
|
for ( let var_name of var_names ) {
|
|
1094
1092
|
// Inputs like textareas don't have values
|
|
@@ -1563,17 +1561,13 @@ module.exports = {
|
|
|
1563
1561
|
reports.addToReport(scope, { type: `warning`, code: `ALK0130`, value: multiple_matches_msg });
|
|
1564
1562
|
}
|
|
1565
1563
|
|
|
1566
|
-
log.debug({
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
pre: `final_matching_rows:\n${JSON.stringify( final_matching_rows )}`
|
|
1570
|
-
});
|
|
1564
|
+
log.debug({ code: `ALK0131`, context: `matching`, },
|
|
1565
|
+
`final_matching_rows:`, final_matching_rows
|
|
1566
|
+
);
|
|
1571
1567
|
if ( final_matching_rows.length == 0) {
|
|
1572
|
-
log.debug({
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
pre: `field:\n${JSON.stringify( field )}`
|
|
1576
|
-
});
|
|
1568
|
+
log.debug({ code: `ALK0132`, context: `matching`, },
|
|
1569
|
+
`0 matching rows. Field:`, field
|
|
1570
|
+
);
|
|
1577
1571
|
}
|
|
1578
1572
|
|
|
1579
1573
|
return final_matching_rows;
|
|
@@ -1659,11 +1653,9 @@ module.exports = {
|
|
|
1659
1653
|
|
|
1660
1654
|
get_handle_from_field: async function ( scope, { field }) {
|
|
1661
1655
|
/** Get the element's puppeteer handle using the field's selector. */
|
|
1662
|
-
log.debug({
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
pre: `scope.get_handle_from_field() field.selector: ${JSON.stringify(field.selector)}`
|
|
1666
|
-
});
|
|
1656
|
+
log.debug({ code: `ALK0133`, },
|
|
1657
|
+
`scope.get_handle_from_field() field.selector:`, field.selector
|
|
1658
|
+
);
|
|
1667
1659
|
let handle = await scope.page.evaluateHandle(( selector ) => {
|
|
1668
1660
|
let elem = document.querySelector( selector );
|
|
1669
1661
|
// If the element has a sibling that's a label, we need to
|
|
@@ -2175,7 +2167,9 @@ module.exports = {
|
|
|
2175
2167
|
* @param ensure_all_vars_used {bool} [false] = Default false. If true, errors if any
|
|
2176
2168
|
* object in var_data is not used during running of this function.
|
|
2177
2169
|
*/
|
|
2178
|
-
log.debug({
|
|
2170
|
+
log.debug({ code: `ALK0221`, before: `~~~~~~~~~~~~~~\n`, },
|
|
2171
|
+
`scope.setFields()`
|
|
2172
|
+
);
|
|
2179
2173
|
|
|
2180
2174
|
// Only record the page id once for each page to which we navigate
|
|
2181
2175
|
let { id } = await scope.examinePageID( scope, 'none to match' );
|
|
@@ -2219,8 +2213,7 @@ module.exports = {
|
|
|
2219
2213
|
// Accumulate number of times this row was used. Esp important for `.target_number`
|
|
2220
2214
|
await scope.increment_row_use( scope, { row: row_used });
|
|
2221
2215
|
|
|
2222
|
-
|
|
2223
|
-
|
|
2216
|
+
log.stdout({}, `\x1b[36m${ '*' }\x1b[0m`); // assumes var was set if no error occurred
|
|
2224
2217
|
}
|
|
2225
2218
|
} // ends for every non-submit-button field on the page
|
|
2226
2219
|
} // ends while fields are still being set
|
|
@@ -2265,7 +2258,7 @@ module.exports = {
|
|
|
2265
2258
|
// }
|
|
2266
2259
|
|
|
2267
2260
|
did_navigate = true;
|
|
2268
|
-
|
|
2261
|
+
log.stdout({}, `\x1b[36m${ 'v' }\x1b[0m`); // pressed button successfully
|
|
2269
2262
|
break;
|
|
2270
2263
|
|
|
2271
2264
|
} // ends if row_used
|
|
@@ -2312,7 +2305,7 @@ module.exports = {
|
|
|
2312
2305
|
// }
|
|
2313
2306
|
|
|
2314
2307
|
did_navigate = true;
|
|
2315
|
-
|
|
2308
|
+
log.stdout({}, `\x1b[36m${ '>' }\x1b[0m`); // continued successfully
|
|
2316
2309
|
} // ends if !did_navigate && ensure_navigation
|
|
2317
2310
|
|
|
2318
2311
|
if ( did_navigate && scope.check_all_for_a11y ) {
|
|
@@ -3109,36 +3102,30 @@ module.exports = {
|
|
|
3109
3102
|
let redirect_promise = scope.page.waitForResponse(function ( response ) {
|
|
3110
3103
|
return response.status() === 302;
|
|
3111
3104
|
}, { signal: controller.signal })
|
|
3112
|
-
.catch((
|
|
3113
|
-
log.debug({
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
data: error,
|
|
3117
|
-
});
|
|
3105
|
+
.catch(( catch_info ) => {
|
|
3106
|
+
log.debug({ code: `ALK0204`, context: `nav`, },
|
|
3107
|
+
`302 sign-in wait catch error:`, catch_info.name, catch_info,
|
|
3108
|
+
);
|
|
3118
3109
|
});
|
|
3119
3110
|
|
|
3120
3111
|
// Invalid credentials, no navigation, no sign in
|
|
3121
3112
|
let wrong_sign_in_promise = scope.page.waitForResponse(function ( response ) {
|
|
3122
3113
|
return response.status() >= 200 && response.status() < 300 && response.url().includes(`/sign-in`);
|
|
3123
3114
|
}, { signal: controller.signal })
|
|
3124
|
-
.catch((
|
|
3125
|
-
log.debug({
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
data: error,
|
|
3129
|
-
});
|
|
3115
|
+
.catch(( catch_info ) => {
|
|
3116
|
+
log.debug({ code: `ALK0205`, context: `nav`, },
|
|
3117
|
+
`200s sign-in wait catch error:`, catch_info.name, catch_info,
|
|
3118
|
+
);
|
|
3130
3119
|
});
|
|
3131
3120
|
|
|
3132
3121
|
// System error
|
|
3133
3122
|
let error_promise = scope.page.waitForResponse(function ( response ) {
|
|
3134
3123
|
return response.status() >= 500 && response.status() < 600;
|
|
3135
3124
|
}, { signal: controller.signal })
|
|
3136
|
-
.catch((
|
|
3137
|
-
log.debug({
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
data: error,
|
|
3141
|
-
});
|
|
3125
|
+
.catch(( catch_info ) => {
|
|
3126
|
+
log.debug({ code: `ALK0206`, context: `nav`, },
|
|
3127
|
+
`500s sign-in wait catch error:`, catch_info.name, catch_info,
|
|
3128
|
+
);
|
|
3142
3129
|
});
|
|
3143
3130
|
|
|
3144
3131
|
let click_promise = elem.click(); // MUST complete
|
|
@@ -3157,10 +3144,9 @@ module.exports = {
|
|
|
3157
3144
|
// Clean up unresolved promises
|
|
3158
3145
|
controller.abort();
|
|
3159
3146
|
|
|
3160
|
-
log.debug({
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
});
|
|
3147
|
+
log.debug({ code: `ALK0208`, context: `nav` },
|
|
3148
|
+
`Sign-in winner:`, winner
|
|
3149
|
+
);
|
|
3164
3150
|
|
|
3165
3151
|
return winner;
|
|
3166
3152
|
},
|
|
@@ -3183,7 +3169,7 @@ module.exports = {
|
|
|
3183
3169
|
} else {
|
|
3184
3170
|
// Try to give a random answer for that element tag
|
|
3185
3171
|
await scope.set_random_input_for[ field.tag ]( scope, { field: field });
|
|
3186
|
-
|
|
3172
|
+
log.stdout({}, `\x1b[36m${ '*' }\x1b[0m`); // assumes var was set if no error occurred
|
|
3187
3173
|
}
|
|
3188
3174
|
|
|
3189
3175
|
} // End for all page fields
|
|
@@ -3219,11 +3205,10 @@ module.exports = {
|
|
|
3219
3205
|
}
|
|
3220
3206
|
if (field == null) {
|
|
3221
3207
|
// Just skip it? Shouldn't happen but has before. Dig in more
|
|
3222
|
-
log.debug({
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
});
|
|
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
|
+
);
|
|
3227
3212
|
return;
|
|
3228
3213
|
}
|
|
3229
3214
|
let handle = await scope.get_handle_from_field( scope, { field: field });
|