@suffolklitlab/alkiln 5.16.0 → 5.16.1-always-html-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.
- package/.github/workflows/da_image_v_sha_7d13853.yml +1 -0
- package/.github/workflows/github_server.yml +1 -1
- package/.github/workflows/playground.yml +3 -2
- package/CHANGELOG.md +33 -0
- package/action.yml +26 -8
- package/action_for_github_server/action.yml +3 -3
- package/lib/scope.js +41 -22
- package/lib/setup/artifacts.js +6 -1
- package/lib/steps.js +38 -20
- package/package.json +1 -1
- package/tests/log_codes/log_code_expected_instances.txt +3 -1
|
@@ -160,7 +160,7 @@ jobs:
|
|
|
160
160
|
#### Developer note: You can probably leave the rest out
|
|
161
161
|
#### To learn more, see https://assemblyline.suffolklitlab.org/docs/alkiln/writing/#optional-inputs
|
|
162
162
|
ALKILN_TAG_EXPRESSION: "${{ env.ALKILN_TAG_EXPRESSION }}"
|
|
163
|
-
|
|
163
|
+
ALKILN_VERSION: "screenshot"
|
|
164
164
|
|
|
165
165
|
#### Developer note: Example of making an issue when tests fail
|
|
166
166
|
#### that includes the text of the failure output file
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
name: Playground installation
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
push:
|
|
5
4
|
pull_request:
|
|
6
5
|
workflow_dispatch:
|
|
7
6
|
inputs:
|
|
@@ -9,6 +8,8 @@ on:
|
|
|
9
8
|
required: False
|
|
10
9
|
description: 'Optional. Use a "tag expression" specify which tagged tests to run (https://cucumber.io/docs/cucumber/api/#tag-expressions)'
|
|
11
10
|
default: ''
|
|
11
|
+
schedule:
|
|
12
|
+
- cron: "0 1 * * SUN"
|
|
12
13
|
|
|
13
14
|
jobs:
|
|
14
15
|
|
|
@@ -82,4 +83,4 @@ jobs:
|
|
|
82
83
|
# want to check up on this.
|
|
83
84
|
ALKILN_TAG_EXPRESSION: "${{ env.ALKILN_TAG_EXPRESSION }}"
|
|
84
85
|
#### Developer note: You can probably leave this out
|
|
85
|
-
|
|
86
|
+
ALKILN_VERSION: "screenshot"
|
package/CHANGELOG.md
CHANGED
|
@@ -43,6 +43,39 @@ Format:
|
|
|
43
43
|
-
|
|
44
44
|
-->
|
|
45
45
|
|
|
46
|
+
## [Unreleased]
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- On pages with sensitive answers, store the HTML of the page. The HTML excludes field values, so those sensitive answers will not be in the saved file. Still avoid taking a pic of the screen, which would reveal sensitive answers. NEVER USE REAL USERS' ANSWERS IN ALKILN TESTS. This HTML can still reveal information about a user's answers. For example, some answers will reveal new questions. That will change the code of the revealed fields and that code will be in the HTML.
|
|
51
|
+
|
|
52
|
+
- GitHub action release: Restored our GitHub action's default for ALKiln version to the latest version 5 again. Released first on GitHub actions. NPM release will come in time, but npm has no impact on GitHub action releases.
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- Fixed GitHub+You action outdated docassemble cli version causing Scenario timeouts.
|
|
57
|
+
|
|
58
|
+
### Internal
|
|
59
|
+
|
|
60
|
+
- Break out the function in `Before()` to attempt better error tracing. Goal: try to repeat this for other functions in that file.
|
|
61
|
+
|
|
62
|
+
- Updated both of our actions' dependencies (the checkout, setup-node, setup-python, upload-artifacts, download-artifacts actions). Closes [#1095](https://github.com/suffolkLITLab/aLKiln/issues/1095). Once again, action related.
|
|
63
|
+
|
|
64
|
+
## [5.16.1] - 2026-06-01
|
|
65
|
+
|
|
66
|
+
### Fixed
|
|
67
|
+
|
|
68
|
+
- In action.yml, replaced `npm rebuild` with an explicit search for existing puppeteer chrome executables. There is no fallback if all of those are missing. Addresses [#1088](https://github.com/suffolkLITLab/aLKiln/issues/1088). We hope to address the core issue when we can.
|
|
69
|
+
- Restore custom artifacts path argument to allow environments like action.yml to make and reuse their own artifacts path value in environments where it's hard to pass around return values. Closes [#1055](https://github.com/suffolkLITLab/aLKiln/issues/1055).
|
|
70
|
+
|
|
71
|
+
### Security
|
|
72
|
+
|
|
73
|
+
- Moved responsibility for security measures to ALKiln internal development by automating internal security measures with `.npmrc`. Closes [#1088](https://github.com/suffolkLITLab/aLKiln/issues/1088).
|
|
74
|
+
|
|
75
|
+
### Internal
|
|
76
|
+
|
|
77
|
+
- Avoid testing on our dev server with every push, uses cron job instead.
|
|
78
|
+
|
|
46
79
|
## [5.16.0] - 2026-05-14
|
|
47
80
|
|
|
48
81
|
### Added
|
package/action.yml
CHANGED
|
@@ -32,7 +32,7 @@ inputs:
|
|
|
32
32
|
DOCASSEMBLECLI_VERSION:
|
|
33
33
|
description: "The version of docassemblecli to install."
|
|
34
34
|
required: false
|
|
35
|
-
default: "0.0.
|
|
35
|
+
default: "0.0.25"
|
|
36
36
|
ALKILN_MAX_RANDOM_TESTS_PER_SCENARIO:
|
|
37
37
|
description: "The maximum number of tests ALKiln will generate for every Scenario that can generate tests."
|
|
38
38
|
required: false
|
|
@@ -59,7 +59,7 @@ runs:
|
|
|
59
59
|
using: "composite"
|
|
60
60
|
steps:
|
|
61
61
|
# Place the root directory in this branch
|
|
62
|
-
- uses: actions/checkout@
|
|
62
|
+
- uses: actions/checkout@v7
|
|
63
63
|
|
|
64
64
|
# Set environment variables
|
|
65
65
|
- name: "💡 ALK0023 INFO: Set environment variables"
|
|
@@ -111,18 +111,36 @@ runs:
|
|
|
111
111
|
|
|
112
112
|
# Install ALKiln during GitHub workflow
|
|
113
113
|
- name: "💡 ALK0025 INFO: Set up node"
|
|
114
|
-
uses: actions/setup-node@
|
|
114
|
+
uses: actions/setup-node@v6
|
|
115
115
|
with:
|
|
116
116
|
node-version: "24.x"
|
|
117
117
|
package-manager-cache: false
|
|
118
|
+
|
|
118
119
|
- name: "💡 ALK0026 INFO: Install ALKiln directly from npm"
|
|
119
120
|
shell: bash
|
|
120
121
|
run: |
|
|
121
122
|
log="💡 ALK0026 INFO: Install ALKiln directly from npm"
|
|
122
123
|
echo -e "\n$log" >> "${{ env.DEBUG_PATH }}"
|
|
123
|
-
npm install --ignore-scripts
|
|
124
|
-
npm rebuild -g puppeteer --update-binary
|
|
124
|
+
npm install -g --ignore-scripts "@suffolklitlab/alkiln@$ALKILN_VERSION"
|
|
125
125
|
|
|
126
|
+
BROWSER="$(
|
|
127
|
+
command -v google-chrome-stable ||
|
|
128
|
+
command -v google-chrome ||
|
|
129
|
+
command -v chrome ||
|
|
130
|
+
command -v chromium-browser ||
|
|
131
|
+
command -v chromium ||
|
|
132
|
+
true
|
|
133
|
+
)"
|
|
134
|
+
if [[ -n "$BROWSER" ]]; then
|
|
135
|
+
log_result="💡 ALK0279 INFO: Found puppeteer browser executable at '$BROWSER'"
|
|
136
|
+
echo -e "\n$log_result" >> "${{ env.DEBUG_PATH }}" && echo -e "$log_result"
|
|
137
|
+
echo "PUPPETEER_EXECUTABLE_PATH=$BROWSER" >> "$GITHUB_ENV"
|
|
138
|
+
else
|
|
139
|
+
log_result="🤕 ALK0280 INFO: Unable to find puppeteer browser executable"
|
|
140
|
+
echo -e "\n$log_result" >> "${{ env.DEBUG_PATH }}" && echo -e "$log_result"
|
|
141
|
+
# Our project uses bash error codes in the 50's. This may change.
|
|
142
|
+
exit 51
|
|
143
|
+
fi
|
|
126
144
|
|
|
127
145
|
# Files prep
|
|
128
146
|
- shell: bash
|
|
@@ -137,7 +155,7 @@ runs:
|
|
|
137
155
|
|
|
138
156
|
# Install package on playground
|
|
139
157
|
# Don't rely on the environment's version of python
|
|
140
|
-
- uses: actions/setup-python@
|
|
158
|
+
- uses: actions/setup-python@v6
|
|
141
159
|
if: ${{ inputs.INSTALL_METHOD == 'playground' }}
|
|
142
160
|
with:
|
|
143
161
|
python-version: '3.10'
|
|
@@ -195,7 +213,7 @@ runs:
|
|
|
195
213
|
# Upload artifacts that subscribers can download on the Actions summary page
|
|
196
214
|
- name: "💡 ALK0033 INFO: Upload artifacts folder"
|
|
197
215
|
if: ${{ always() }}
|
|
198
|
-
uses: actions/upload-artifact@
|
|
216
|
+
uses: actions/upload-artifact@v7
|
|
199
217
|
with:
|
|
200
218
|
name: ${{ env.ARTIFACT_FOLDER }}
|
|
201
219
|
path: ./alkiln-*
|
|
@@ -203,7 +221,7 @@ runs:
|
|
|
203
221
|
# Download artifacts folder internally to create action output
|
|
204
222
|
- name: "💡 ALK0183 INFO: Get uploaded artifacts folder"
|
|
205
223
|
if: ${{ always() }}
|
|
206
|
-
uses: actions/download-artifact@
|
|
224
|
+
uses: actions/download-artifact@v8
|
|
207
225
|
with:
|
|
208
226
|
name: ${{ env.ARTIFACT_FOLDER }}
|
|
209
227
|
|
|
@@ -49,7 +49,7 @@ runs:
|
|
|
49
49
|
using: "composite"
|
|
50
50
|
steps:
|
|
51
51
|
# Place the root directory in this branch
|
|
52
|
-
- uses: actions/checkout@
|
|
52
|
+
- uses: actions/checkout@v7
|
|
53
53
|
|
|
54
54
|
- shell: bash
|
|
55
55
|
run: |
|
|
@@ -253,7 +253,7 @@ runs:
|
|
|
253
253
|
done
|
|
254
254
|
|
|
255
255
|
# Don't rely on the environment's version of python
|
|
256
|
-
- uses: actions/setup-python@
|
|
256
|
+
- uses: actions/setup-python@v6
|
|
257
257
|
with:
|
|
258
258
|
python-version: '3.10'
|
|
259
259
|
# No output
|
|
@@ -285,7 +285,7 @@ runs:
|
|
|
285
285
|
echo "$(docker output docassemble_container)" >> "${{ env.DEBUG_LOGS_PATH }}"
|
|
286
286
|
- name: "💡 ALK0020 INFO: Upload artifacts folder"
|
|
287
287
|
if: ${{ always() && env.OUTPUT_DOCKER == 'true' }}
|
|
288
|
-
uses: actions/upload-artifact@
|
|
288
|
+
uses: actions/upload-artifact@v7
|
|
289
289
|
with:
|
|
290
290
|
name: ${{ env.GITHUB_SERVER_ARTIFACT_NAME }}
|
|
291
291
|
path: ${{ env.DEBUG_LOGS_PATH }}
|
package/lib/scope.js
CHANGED
|
@@ -2711,8 +2711,23 @@ module.exports = {
|
|
|
2711
2711
|
return scope;
|
|
2712
2712
|
}, // Ends scope.throwPageError()
|
|
2713
2713
|
|
|
2714
|
-
take_a_screenshot: async ( scope,
|
|
2715
|
-
|
|
2714
|
+
take_a_screenshot: async ( scope, {
|
|
2715
|
+
path, disable_pic=false, disable_html=false
|
|
2716
|
+
}) => {
|
|
2717
|
+
/**
|
|
2718
|
+
* Saves a jpeg screenshot and page HTML to `path`. Avoids destroying
|
|
2719
|
+
* signatures.
|
|
2720
|
+
*
|
|
2721
|
+
* @param {obj} scope - State and internal functions
|
|
2722
|
+
* @param {obj} obj - Named arguments
|
|
2723
|
+
* @param {str} obj.path - name of path where to save the files
|
|
2724
|
+
* @param {bool} [obj.disable_pic=false] - Optional. Whether to disable a
|
|
2725
|
+
* puppeteer screenshot
|
|
2726
|
+
* @param {bool} [obj.disable_html=false] - Optional. Whether to disable
|
|
2727
|
+
* saving the HTML of the page
|
|
2728
|
+
*
|
|
2729
|
+
* @returns undefined
|
|
2730
|
+
* */
|
|
2716
2731
|
|
|
2717
2732
|
let fullPage = true;
|
|
2718
2733
|
let signature_elem = await scope.page.$(scope.signature_selector);
|
|
@@ -2721,28 +2736,32 @@ module.exports = {
|
|
|
2721
2736
|
fullPage = false;
|
|
2722
2737
|
}
|
|
2723
2738
|
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
let html_path = path;
|
|
2731
|
-
if (path.endsWith(".jpg")) {
|
|
2732
|
-
html_path = html_path.substring(0, html_path.length - 4) + ".html";
|
|
2733
|
-
} else {
|
|
2734
|
-
html_path = html_path + ".html";
|
|
2739
|
+
if ( !disable_pic ){
|
|
2740
|
+
await scope.page.screenshot({
|
|
2741
|
+
path: path,
|
|
2742
|
+
type: 'jpeg',
|
|
2743
|
+
fullPage: fullPage,
|
|
2744
|
+
});
|
|
2735
2745
|
}
|
|
2736
2746
|
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2747
|
+
if ( !disable_html ) {
|
|
2748
|
+
let html_path = path;
|
|
2749
|
+
if (path.endsWith(".jpg")) {
|
|
2750
|
+
html_path = html_path.substring(0, html_path.length - 4) + ".html";
|
|
2751
|
+
} else {
|
|
2752
|
+
html_path = html_path + ".html";
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
// Also save the HTML of the page
|
|
2756
|
+
await scope.page.content().then(content => {
|
|
2757
|
+
let server_url = session_vars.get_da_server_url();
|
|
2758
|
+
content = content.replaceAll(/"(\/static\/.*\.css\?v=[^"]+")/g, server_url + "$1");
|
|
2759
|
+
content = content.replaceAll(/"(\/static\/.*\.js\?v=[^"]+")/g, server_url + "$1");
|
|
2760
|
+
content = content.replaceAll(/"(\/packagestatic\/.*\.css\?v=[^"]+")/g, server_url + "$1");
|
|
2761
|
+
content = content.replaceAll(/"(\/packagestatic\/.*\.js\?v=[^"]+")/g, server_url + "$1");
|
|
2762
|
+
fs.writeFileSync(html_path, content)
|
|
2763
|
+
});
|
|
2764
|
+
}
|
|
2746
2765
|
}, // Ends scope.take_a_screenshot()
|
|
2747
2766
|
|
|
2748
2767
|
|
package/lib/setup/artifacts.js
CHANGED
|
@@ -11,7 +11,12 @@ const Log = require(`../utils/Log.js`);
|
|
|
11
11
|
|
|
12
12
|
session_vars.delete_artifacts_path_name();
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
// process.argv is a list of strings of commands and args.
|
|
15
|
+
// If using `npm run artifacts` (as opposed to the bin commands),
|
|
16
|
+
// use `--` before, for example, `--sources=./foo`
|
|
17
|
+
// Envs like action.yml reuse their own .path when return vals are hard to get
|
|
18
|
+
const forced_path = require(`minimist`)( process.argv.slice(2) )?.path;
|
|
19
|
+
const artifacts_path = files.make_artifacts_folder( forced_path );
|
|
15
20
|
session_vars.save_artifacts_path_name( artifacts_path );
|
|
16
21
|
|
|
17
22
|
const log = new Log({ path: artifacts_path, context: `artifacts` });
|
package/lib/steps.js
CHANGED
|
@@ -114,8 +114,9 @@ BeforeAll(async function() {
|
|
|
114
114
|
reports.create( scope );
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
Before(
|
|
118
|
-
|
|
117
|
+
Before( beforeScenario );
|
|
118
|
+
async function beforeScenario( scenario ) {
|
|
119
|
+
console.log('👁️ 111 start beforeScenario');
|
|
119
120
|
// Start the running "progress bar" for the Scenario
|
|
120
121
|
log.stdout({}, `\nScenario: ${ scenario.pickle.name }: `);
|
|
121
122
|
|
|
@@ -125,15 +126,20 @@ Before(async (scenario) => {
|
|
|
125
126
|
// Will only run in the Playground outside of a sandbox. TODO: There's a
|
|
126
127
|
// better way to do this, though it's more complicated. See comments in
|
|
127
128
|
// https://github.com/SuffolkLITLab/ALKiln/issues/661
|
|
129
|
+
console.log('👁️ 112 no browser, await new local browser');
|
|
128
130
|
scope.browser = await scope.driver.launch({ args: ['--no-sandbox'] });
|
|
129
131
|
} else {
|
|
132
|
+
console.log('👁️ 113 no browser, await new remote browser');
|
|
130
133
|
scope.browser = await scope.driver.launch({ headless: !session_vars.get_debug(), devtools: session_vars.get_debug() });
|
|
131
134
|
}
|
|
132
135
|
}
|
|
136
|
+
console.log('👁️ 114 we have ensured browser exists, awaiting pages');
|
|
133
137
|
// Clean up all previously existing pages
|
|
134
138
|
for (const page of await scope.browser.pages()) {
|
|
139
|
+
console.log('👁️ 115 awaiting closing page');
|
|
135
140
|
await page.close();
|
|
136
141
|
}
|
|
142
|
+
console.log('👁️ 116 awaiting opening a new page');
|
|
137
143
|
// Make a new page
|
|
138
144
|
scope.page = await scope.browser.newPage()
|
|
139
145
|
|
|
@@ -147,8 +153,10 @@ Before(async (scenario) => {
|
|
|
147
153
|
scope.server_reload_promise = null;
|
|
148
154
|
|
|
149
155
|
reports.addReportHeading(scope, {scenario});
|
|
156
|
+
console.log('👁️ 117 awaiting getting safe scenario name');
|
|
150
157
|
// Make folder for this Scenario in the all-tests artifacts folder
|
|
151
158
|
scope.base_filename = await scope.getSafeScenarioBaseFilename(scope, {scenario});
|
|
159
|
+
console.log('👁️ 118 got safe scenario name');
|
|
152
160
|
// Add a date for uniqueness in case dev has accidentally copied a Scenario description
|
|
153
161
|
let date = Date.now();
|
|
154
162
|
scope.paths.scenario = `${ scope.paths.artifacts }/${ scope.base_filename }-${ date }`;
|
|
@@ -171,7 +179,7 @@ Before(async (scenario) => {
|
|
|
171
179
|
|
|
172
180
|
// Reset default timeout
|
|
173
181
|
scope.timeout = default_timeout;
|
|
174
|
-
}
|
|
182
|
+
}
|
|
175
183
|
|
|
176
184
|
// Add a check for an error page before each step? After each step?
|
|
177
185
|
|
|
@@ -1379,25 +1387,35 @@ After(async function(scenario) {
|
|
|
1379
1387
|
reports.addToReport(scope, {
|
|
1380
1388
|
type: `row info`,
|
|
1381
1389
|
code: `ALK0095`,
|
|
1382
|
-
|
|
1390
|
+
// Discuss: Might people use secret variables to prevent any
|
|
1391
|
+
// information about a screen from getting out? For example, they have
|
|
1392
|
+
// proprietary info in the HTML itself.
|
|
1393
|
+
value: `For security, ALKiln will avoid creating a picture of the page for this error. It's possible a secret is being used on this screen. ALKiln will save the HTML, which omits the values in the fields.`
|
|
1383
1394
|
});
|
|
1384
|
-
}
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
// Save/download a picture of the screen that's showing during the unexpected status
|
|
1398
|
+
// Save one copy in the outer-most artifact folder
|
|
1399
|
+
let scenario_filename = await scope.getSafeScenarioFilename( scope, { prefix: `error_on` });
|
|
1400
|
+
let path_outer = `${ scope.paths.artifacts }/${ scenario_filename }.jpg`;
|
|
1401
|
+
await scope.take_a_screenshot( scope, {
|
|
1402
|
+
path: path_outer,
|
|
1403
|
+
disable_pic: scope.disable_error_screenshot,
|
|
1404
|
+
disable_html: false,
|
|
1405
|
+
});
|
|
1406
|
+
|
|
1407
|
+
// Save another copy in the artifact's Scenario folder
|
|
1408
|
+
let screenshot_name = `error_on`;
|
|
1409
|
+
let { id } = await scope.examinePageID( scope, 'none to match' );
|
|
1410
|
+
let short_id = `${ id }`.substring(0, 20);
|
|
1411
|
+
screenshot_name += `-${ short_id }`;
|
|
1412
|
+
let path_scenario = `${ scope.paths.scenario }/${ screenshot_name }.jpg`;
|
|
1413
|
+
await scope.take_a_screenshot( scope, {
|
|
1414
|
+
path: path_scenario,
|
|
1415
|
+
disable_pic: scope.disable_error_screenshot,
|
|
1416
|
+
disable_html: false,
|
|
1417
|
+
});
|
|
1385
1418
|
|
|
1386
|
-
// Save/download a picture of the screen that's showing during the unexpected status
|
|
1387
|
-
// Save one copy in the outer-most artifact folder
|
|
1388
|
-
let scenario_filename = await scope.getSafeScenarioFilename( scope, { prefix: `error_on` });
|
|
1389
|
-
let path_outer = `${ scope.paths.artifacts }/${ scenario_filename }.jpg`;
|
|
1390
|
-
await scope.take_a_screenshot( scope, { path: path_outer });
|
|
1391
|
-
|
|
1392
|
-
// Save another copy in the artifact's Scenario folder
|
|
1393
|
-
let screenshot_name = `error_on`;
|
|
1394
|
-
let { id } = await scope.examinePageID( scope, 'none to match' );
|
|
1395
|
-
let short_id = `${ id }`.substring(0, 20);
|
|
1396
|
-
screenshot_name += `-${ short_id }`;
|
|
1397
|
-
let path_scenario = `${ scope.paths.scenario }/${ screenshot_name }.jpg`;
|
|
1398
|
-
await scope.take_a_screenshot( scope, { path: path_scenario });
|
|
1399
|
-
|
|
1400
|
-
} // ends if scope.disable_error_screenshot
|
|
1401
1419
|
} // ends if scope.page exists
|
|
1402
1420
|
|
|
1403
1421
|
// This has to come after the security message or security message doesn't print. Not sure why.
|
package/package.json
CHANGED