@suffolklitlab/alkiln 5.17.1-fix-stop-on-error-3 → 5.17.2
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.
|
@@ -36,6 +36,17 @@ jobs:
|
|
|
36
36
|
&& github.event.pull_request.head.repo.fork
|
|
37
37
|
)
|
|
38
38
|
runs-on: ubuntu-latest
|
|
39
|
+
|
|
40
|
+
env:
|
|
41
|
+
NORMAL_USER_EMAIL: "alkiln@example.com"
|
|
42
|
+
NORMAL_USER_PASSWORD: "User123^"
|
|
43
|
+
WRONG_EMAIL: "wrong_email@example.com"
|
|
44
|
+
WRONG_PASSWORD: "wrong_password"
|
|
45
|
+
INVALID_API_KEY: "invalidAPIkey"
|
|
46
|
+
EMPTY_STRING: ""
|
|
47
|
+
SECRET_VAR1: "secret-var1-value"
|
|
48
|
+
SECRET_VAR2: "secret-var2-value"
|
|
49
|
+
SECRET_FOR_MISSING_FIELD: "secret for missing field"
|
|
39
50
|
|
|
40
51
|
steps:
|
|
41
52
|
# Place the root directory in this branch to access relative paths to
|
|
@@ -51,20 +62,70 @@ jobs:
|
|
|
51
62
|
- run: echo "ALKiln finished starting the isolated GitHub docassemble server"
|
|
52
63
|
shell: bash
|
|
53
64
|
|
|
65
|
+
- name: "Add a low-level user and their API key (in an env var)"
|
|
66
|
+
env:
|
|
67
|
+
SERVER_URL: "${{ steps.github_server.outputs.SERVER_URL }}"
|
|
68
|
+
KEY: ${{ steps.github_server.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}
|
|
69
|
+
run: |
|
|
70
|
+
# Create user and their API key
|
|
71
|
+
|
|
72
|
+
# Install json processor
|
|
73
|
+
sudo apt-get install jq
|
|
74
|
+
|
|
75
|
+
# https://docassemble.org/docs/api.html#user_new
|
|
76
|
+
user_data=$(curl -X POST \
|
|
77
|
+
${{ env.SERVER_URL }}/api/user/new \
|
|
78
|
+
-H 'Content-Type: application/json' \
|
|
79
|
+
-d '{
|
|
80
|
+
"key": "${{ env.KEY }}",
|
|
81
|
+
"username": "${{ env.NORMAL_USER_EMAIL }}",
|
|
82
|
+
"password": "${{ env.NORMAL_USER_PASSWORD }}"
|
|
83
|
+
}')
|
|
84
|
+
echo "User data:"
|
|
85
|
+
echo "$user_data"
|
|
86
|
+
|
|
87
|
+
user_id=$(echo "$user_data" | jq '.user_id' -r)
|
|
88
|
+
|
|
89
|
+
# https://docassemble.org/docs/api.html#api_user_user_id_api_post
|
|
90
|
+
new_key_with_quotes=$(curl -X POST \
|
|
91
|
+
${{ env.SERVER_URL }}/api/user/"$user_id"/api \
|
|
92
|
+
-H 'Content-Type: application/json' \
|
|
93
|
+
-d '{
|
|
94
|
+
"key": "${{ env.KEY }}",
|
|
95
|
+
"name": "alkiln_key",
|
|
96
|
+
"method": "none"
|
|
97
|
+
}')
|
|
98
|
+
echo "new key (watch out, this contains actual quotation marks): $new_key_with_quotes"
|
|
99
|
+
no_end_quote="${new_key_with_quotes%\"}"
|
|
100
|
+
unquoted="${no_end_quote#\"}"
|
|
101
|
+
echo "unquoted: $unquoted"
|
|
102
|
+
|
|
103
|
+
echo "NORMAL_USER_API_KEY=$unquoted" >> "$GITHUB_ENV"
|
|
104
|
+
|
|
54
105
|
## Optional debugging to explore things like docker issues
|
|
55
106
|
#- name: Docker debug tmate session
|
|
56
107
|
# #if: ${{ failure() && github.event.inputs.enable_tmate == 'true' }}
|
|
57
108
|
# uses: mxschmitt/action-tmate@v3
|
|
58
109
|
|
|
59
|
-
- name: "
|
|
110
|
+
- name: "Create other env vars for our own tests from server output"
|
|
111
|
+
run: |
|
|
112
|
+
echo "USER1_EMAIL=${{ steps.github_server.outputs.DA_ADMIN_EMAIL }}" >> $GITHUB_ENV
|
|
113
|
+
echo "USER1_PASSWORD=${{ steps.github_server.outputs.DA_ADMIN_PASSWORD }}" >> $GITHUB_ENV
|
|
114
|
+
|
|
115
|
+
- name: "ALKiln - Run if docassemble packages get installed correctly"
|
|
60
116
|
if: ${{ success() }}
|
|
61
117
|
id: alkiln
|
|
62
118
|
uses: ./
|
|
119
|
+
env:
|
|
120
|
+
# Internal: docassemble changes sometimes break @a11y tests. That is
|
|
121
|
+
# a da problem, not ours. We will trigger these tests manually when we
|
|
122
|
+
# want to check up on this.
|
|
123
|
+
ALKILN_TAG_EXPRESSION: "${{ (github.event.inputs.tags && format('{0}', github.event.inputs.tags)) || '(not @error) and (not @temp_error)' }}"
|
|
63
124
|
with:
|
|
64
125
|
# Required inputs. See
|
|
65
126
|
# https://assemblyline.suffolklitlab.org/docs/alkiln/writing/#sandbox-inputs
|
|
66
127
|
SERVER_URL: "${{ steps.github_server.outputs.SERVER_URL }}"
|
|
67
128
|
DOCASSEMBLE_DEVELOPER_API_KEY: "${{ steps.github_server.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}"
|
|
68
129
|
INSTALL_METHOD: "server"
|
|
69
|
-
ALKILN_TAG_EXPRESSION: "
|
|
70
|
-
|
|
130
|
+
ALKILN_TAG_EXPRESSION: "${{ env.ALKILN_TAG_EXPRESSION }}"
|
|
131
|
+
# ALKIlN_VERSION:
|
|
@@ -159,7 +159,7 @@ jobs:
|
|
|
159
159
|
#### Developer note: You can probably leave the rest out
|
|
160
160
|
#### To learn more, see https://assemblyline.suffolklitlab.org/docs/alkiln/writing/#optional-inputs
|
|
161
161
|
ALKILN_TAG_EXPRESSION: "${{ env.ALKILN_TAG_EXPRESSION }}"
|
|
162
|
-
|
|
162
|
+
# ALKIlN_VERSION:
|
|
163
163
|
|
|
164
164
|
#### Developer note: Example of making an issue when tests fail
|
|
165
165
|
#### that includes the text of the failure output file
|
package/CHANGELOG.md
CHANGED
|
@@ -44,23 +44,26 @@ Format:
|
|
|
44
44
|
-
|
|
45
45
|
-->
|
|
46
46
|
|
|
47
|
-
## [Unreleased]
|
|
47
|
+
<!-- ## [Unreleased] -->
|
|
48
|
+
|
|
49
|
+
## [5.17.2] - 2026-10-29
|
|
48
50
|
|
|
49
51
|
### Added
|
|
50
52
|
|
|
51
|
-
- Step
|
|
52
|
-
- Step
|
|
53
|
+
- Step `I continue` which taps the continue button expecting to navigate to a new page in the interview. `I continue` and `I can't continue` should together replace the behaviors of `I tap to continue`.
|
|
54
|
+
- Step `I can't continue` which taps the continue button expecting to fail to navigate. It passes when there are invalid answers or when a continue button is missing. It fails on other errors, like system errors (including Assembly Line custom errors) and timeout errors. Those types of errors should always fail across the whole framework. An author could use `I can't continue` to check that the interview correctly indicated one or more invalid answers. This replaces the practice of using `I tap to continue` twice.
|
|
53
55
|
|
|
54
56
|
### Changed
|
|
55
57
|
|
|
56
|
-
- Part 2 of detecting custom AL error screen (final part): Though `I tap to continue` allows invalid answers again, it throws on other errors, like system errors (including Assembly Line custom errors) and timeout errors. Those types of errors should always fail across the whole framework. It also throws if the continue button is missing.
|
|
58
|
+
- Part 2 of detecting custom AL error screen (final part): Though `I tap to continue` allows invalid answers again, it throws on other errors, like system errors (including Assembly Line custom errors) and timeout errors. Those types of errors should always fail across the whole framework. It also throws if the continue button is missing. See [#656](https://github.com/SuffolkLITLab/ALKiln/issues/656).
|
|
57
59
|
- Extended error message when the test causes a docassemble system error page (like syntax errors, etc.) It now should contain some of the relevant contents of the page.
|
|
58
60
|
- Tweaked other log messages.
|
|
59
61
|
|
|
60
62
|
### Fixed
|
|
61
63
|
|
|
62
|
-
-
|
|
64
|
+
- Restored the documented behavior of `I tap to continue`. Specifically, the documentation describes using `I tap to continue` to potentially trigger invalid answers. To do this, these commits re-implement old behavior - `I tap to continue` never fails with invalid answers or missing continue-type buttons. Does add a small change - `I tap to continue` now throws on other errors, like system errors and timeout errors. Those types of errors should always fail across the whole framework. Note: A different behavior was proposed where an author could tap to continue once and be guaranteed no failures and then fail on a second tap to the same page. There are situations in which this would break potentially live tests. For example, an author could test multiple invalid answers in a row for the same field by cycling through `I tap to continue` and `I should see the phrase`. The proposed change would break those tests. The `I tap to continue` Step does now log its deprecation, as well as copious warnings with invalid answers or ambiguous lack of navigation. See [#1125](https://github.com/SuffolkLITLab/ALKiln/issues/1125).
|
|
63
65
|
- Ensured new file upload buttons don't warn about duplicates since they have the same selectors.
|
|
66
|
+
- Restored wait for file upload completion signals. See [#1125](https://github.com/SuffolkLITLab/ALKiln/issues/1125).
|
|
64
67
|
|
|
65
68
|
### Internal
|
|
66
69
|
|
|
@@ -69,6 +72,9 @@ Format:
|
|
|
69
72
|
- Refactored getting different types of page errors (system error pages vs. user errors.)
|
|
70
73
|
- Started refactoring out `scope.examinePageID()` which is currently doing too many things.
|
|
71
74
|
- Added tests
|
|
75
|
+
- Fixed check for previous filenames on file uploads. See [#1125](https://github.com/SuffolkLITLab/ALKiln/issues/1125).
|
|
76
|
+
- Removed `shared_names` from global scope. See [#1125](https://github.com/SuffolkLITLab/ALKiln/issues/1125).
|
|
77
|
+
- Use latest AL docassemble image to run all tests instead of just one.
|
|
72
78
|
|
|
73
79
|
## [5.17.1] - 2026-10-13
|
|
74
80
|
|
package/lib/scope.js
CHANGED
|
@@ -2330,7 +2330,7 @@ module.exports = {
|
|
|
2330
2330
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
2331
2331
|
|
|
2332
2332
|
} else if ( type === `file` ) {
|
|
2333
|
-
row_was_used = await scope.
|
|
2333
|
+
row_was_used = await scope.upload_files( scope, { handle, answer });
|
|
2334
2334
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
2335
2335
|
|
|
2336
2336
|
} else if (type == `date`) {
|
|
@@ -2410,7 +2410,7 @@ module.exports = {
|
|
|
2410
2410
|
return valid_date;
|
|
2411
2411
|
}, // Ends scope.today_to_date()
|
|
2412
2412
|
|
|
2413
|
-
|
|
2413
|
+
find_files: async function( scope, {to_find_names}) {
|
|
2414
2414
|
/** Returns a list of paths to the sources folder associated
|
|
2415
2415
|
* with the given list of file names.
|
|
2416
2416
|
*
|
|
@@ -2467,9 +2467,9 @@ module.exports = {
|
|
|
2467
2467
|
return [];
|
|
2468
2468
|
}
|
|
2469
2469
|
return paths;
|
|
2470
|
-
}, // Ends scope.
|
|
2470
|
+
}, // Ends scope.find_files()
|
|
2471
2471
|
|
|
2472
|
-
|
|
2472
|
+
upload_files: async function ( scope, { handle, answer }) {
|
|
2473
2473
|
/* Try to upload one or more files to a file-type input field.
|
|
2474
2474
|
* Does not submit, so no danger of timeout with server reload.
|
|
2475
2475
|
*
|
|
@@ -2479,8 +2479,8 @@ module.exports = {
|
|
|
2479
2479
|
// First make sure the list of files was defined. Don't remove spaces yet -
|
|
2480
2480
|
// allow a typo where someone forgot to include a space after a comma.
|
|
2481
2481
|
let to_find_names = answer.split(`,`);
|
|
2482
|
-
let paths = await scope.
|
|
2483
|
-
if (paths.length == 0) {
|
|
2482
|
+
let paths = await scope.find_files(scope, {to_find_names});
|
|
2483
|
+
if ( paths.length == 0 ) {
|
|
2484
2484
|
// The row wasn't used
|
|
2485
2485
|
return false;
|
|
2486
2486
|
}
|
|
@@ -2492,16 +2492,17 @@ module.exports = {
|
|
|
2492
2492
|
// it's not completely necessary. If the gobal `setTimeout` fires then the
|
|
2493
2493
|
// `evaluate` won't be far behind. They both use about the same timeout
|
|
2494
2494
|
// duration.
|
|
2495
|
-
let finish_uploading = handle.evaluate( async function
|
|
2495
|
+
let finish_uploading = handle.evaluate( async function (
|
|
2496
2496
|
elem, timeout, answer
|
|
2497
2497
|
) {
|
|
2498
2498
|
return new Promise (( resolve, reject ) => {
|
|
2499
2499
|
/**
|
|
2500
2500
|
* Resolve when upload completes. Logging in here will log to the hidden
|
|
2501
2501
|
* browser. Must instead pass information out with `resolve`.
|
|
2502
|
+
*
|
|
2503
|
+
* Warn about uploading the same file multiple times. It won't protect
|
|
2504
|
+
* against accidentally uploading same file to a different field.
|
|
2502
2505
|
* */
|
|
2503
|
-
// Warn about uploading the same file multiple times
|
|
2504
|
-
// Won't protect against accidentally uploading same file to diff field
|
|
2505
2506
|
|
|
2506
2507
|
// If elem.files, the author has previously set this field. Warn them.
|
|
2507
2508
|
// Example prev_filenames: "C:\\fakepath\\name_of_file.png"
|
|
@@ -2521,13 +2522,13 @@ module.exports = {
|
|
|
2521
2522
|
|
|
2522
2523
|
let result = {
|
|
2523
2524
|
ok: false, prev_filenames, type: null,
|
|
2524
|
-
code: `ALK0283`, level: `
|
|
2525
|
+
code: `ALK0283`, level: `info`, msgs: [], error: null,
|
|
2525
2526
|
};
|
|
2526
2527
|
|
|
2527
|
-
if ( prev_filenames ) {
|
|
2528
|
+
if (( prev_filenames?.length || 0) > 0 ) {
|
|
2528
2529
|
result.level = `warn`; // log level
|
|
2529
2530
|
result.type = `warning`; // report type
|
|
2530
|
-
shared_names = shared_names_list.join(`", "`);
|
|
2531
|
+
let shared_names = shared_names_list.join(`", "`);
|
|
2531
2532
|
|
|
2532
2533
|
if ( shared_names_list.length > 0 ) {
|
|
2533
2534
|
if ( all_matched ) {
|
|
@@ -2545,9 +2546,10 @@ module.exports = {
|
|
|
2545
2546
|
|
|
2546
2547
|
let timeout_id = null;
|
|
2547
2548
|
let resolve_on_change = function() {
|
|
2549
|
+
// bootstrap-fileinput starts reading
|
|
2548
2550
|
result.ok = true; // May contain warnings
|
|
2549
2551
|
clearTimeout( timeout_id );
|
|
2550
|
-
result.msgs.push(`
|
|
2552
|
+
result.msgs.push(`Started uploading these files: "${ answer }"`);
|
|
2551
2553
|
resolve( result );
|
|
2552
2554
|
};
|
|
2553
2555
|
|
|
@@ -2568,7 +2570,7 @@ module.exports = {
|
|
|
2568
2570
|
}); // ends Promise
|
|
2569
2571
|
|
|
2570
2572
|
}, scope.timeout - 100, answer ); // ends page.evaluate()
|
|
2571
|
-
|
|
2573
|
+
|
|
2572
2574
|
await handle.uploadFile(...paths);
|
|
2573
2575
|
|
|
2574
2576
|
// Wait for upload to finish. If already done, execution will continue
|
|
@@ -2589,9 +2591,31 @@ module.exports = {
|
|
|
2589
2591
|
if ( level === `throw` ) { log_type = `throw`; }
|
|
2590
2592
|
log[ log_type ]({ code, level, error, context: `file_upload`}, ...msgs );
|
|
2591
2593
|
|
|
2594
|
+
// LLM Claude (version?) description: While the bootstrap-fileinput is
|
|
2595
|
+
// reading, it disables the input, adds `is-locked` to its container
|
|
2596
|
+
// (lock()), and adds `file-thumb-loading` (_toggleLoading("show")). We'll
|
|
2597
|
+
// wait till these are gone. See GitHub #1125. @plocket tested these
|
|
2598
|
+
// classes out and said they seem legit.
|
|
2599
|
+
await scope.page.waitForFunction(
|
|
2600
|
+
( el ) => {
|
|
2601
|
+
const container = el.closest(`.file-input`);
|
|
2602
|
+
return (
|
|
2603
|
+
!el.disabled
|
|
2604
|
+
&& !( container?.classList?.contains?.(`is-locked`)
|
|
2605
|
+
|| container?.classList?.contains?.(`file-thumb-loading`)
|
|
2606
|
+
));
|
|
2607
|
+
},
|
|
2608
|
+
{ timeout: scope.timeout - 100 },
|
|
2609
|
+
handle,
|
|
2610
|
+
);
|
|
2611
|
+
|
|
2612
|
+
log.debug({ code: `ALK0297`, context: `file_upload`, level: `info`, },
|
|
2613
|
+
`Finished uploading files`
|
|
2614
|
+
);
|
|
2615
|
+
|
|
2592
2616
|
// Return whether successfully used row
|
|
2593
2617
|
return ok;
|
|
2594
|
-
}, // Ends scope.
|
|
2618
|
+
}, // Ends scope.upload_files()
|
|
2595
2619
|
|
|
2596
2620
|
setCheckbox: async function ( scope, { label, answer }) {
|
|
2597
2621
|
// Depending on the current value/status of a checkbox and the desired
|
|
@@ -3222,12 +3246,12 @@ module.exports = {
|
|
|
3222
3246
|
* further information
|
|
3223
3247
|
* 4. (optional) Unspecified non-navigation catchall comes last
|
|
3224
3248
|
*
|
|
3225
|
-
* Unfortunately, our navigation detection game is weaksauce. Navigation
|
|
3226
|
-
* detection thoughts: https://github.com/SuffolkLITLab/ALKiln/issues/229
|
|
3227
|
-
*
|
|
3228
3249
|
* See docs/decisions/017_post_navigation_custom_behavior_2026_10_26.md for
|
|
3229
3250
|
* a deeper discussion.
|
|
3230
3251
|
*
|
|
3252
|
+
* Unfortunately, our navigation detection game is weaksauce. Navigation
|
|
3253
|
+
* detection thoughts: https://github.com/SuffolkLITLab/ALKiln/issues/229
|
|
3254
|
+
*
|
|
3231
3255
|
* @param {Object} scope - Tests state object
|
|
3232
3256
|
* @param {Object} kwargs - Named arguments
|
|
3233
3257
|
* @param {str} kwargs.url - Assumed to be the url of the initial page
|
|
@@ -3241,11 +3265,11 @@ module.exports = {
|
|
|
3241
3265
|
* @returns {Object} kwrvs.error_data - Data for any errors found
|
|
3242
3266
|
* @returns {bool} kwrvs.error_data.was_found - True if the check found any
|
|
3243
3267
|
* errors
|
|
3244
|
-
* @returns {bool}
|
|
3268
|
+
* @returns {bool} kwrvs.error_data.ok - False if the check found any errors.
|
|
3245
3269
|
* Discuss: Should we only use `ok` for internal errors?
|
|
3246
|
-
* @returns {`user`|`system`}
|
|
3270
|
+
* @returns {`user`|`system`} kwrvs.error_data.type - "user" with invalid
|
|
3247
3271
|
* answers, "system" with da or AL server errors
|
|
3248
|
-
* @returns {[ElementHandle]}
|
|
3272
|
+
* @returns {[ElementHandle]} kwrvs.error_data.error_handles - List of
|
|
3249
3273
|
* puppeteer element handles the check found. There can be multiple
|
|
3250
3274
|
* invalid answer elements.
|
|
3251
3275
|
* */
|
|
@@ -3374,7 +3398,7 @@ module.exports = {
|
|
|
3374
3398
|
// still be a bit too long.
|
|
3375
3399
|
// Also, if you're debugging and you close the window early, the process
|
|
3376
3400
|
// will still take this long to exit after the tests finish. May fix
|
|
3377
|
-
// in future, but it's just during debugging, so yolo!
|
|
3401
|
+
// in future, but it's just during debugging, so yolo for now!
|
|
3378
3402
|
if ( session_vars.get_debug() ) {
|
|
3379
3403
|
await time.waitForTimeout( ( scope.timeout - (1 * 1000)) );
|
|
3380
3404
|
}
|
|
@@ -3809,7 +3833,7 @@ module.exports = {
|
|
|
3809
3833
|
}, // Ends scope.steps.get_response_filename()
|
|
3810
3834
|
|
|
3811
3835
|
compare_pdfs: async function (scope, {existing_pdf_path, new_pdf_path}) {
|
|
3812
|
-
let existing_paths = await scope.
|
|
3836
|
+
let existing_paths = await scope.find_files(scope, {to_find_names: [existing_pdf_path]});
|
|
3813
3837
|
if (existing_paths.length == 0) {
|
|
3814
3838
|
// The row wasn't used
|
|
3815
3839
|
let msg = `Could not find the existing PDF at ${ existing_pdf_path }`;
|
package/package.json
CHANGED