@suffolklitlab/alkiln 5.11.2-fix-root-dir-1 → 5.12.0
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 +40 -16
- package/.github/workflows/playground.yml +5 -10
- package/CHANGELOG.md +23 -2
- package/action.yml +74 -1
- package/action_for_github_server/action.yml +5 -3
- package/lib/run_cucumber.js +29 -10
- package/lib/scope.js +2 -4
- package/lib/steps.js +12 -12
- package/lib/utils/log.js +3 -1
- package/lib/utils/reports.js +72 -27
- package/lib/utils/session_vars.js +1 -1
- package/package.json +3 -1
- package/tests/log_codes/check_codes.sh +2 -1
|
@@ -23,8 +23,8 @@ on:
|
|
|
23
23
|
jobs:
|
|
24
24
|
|
|
25
25
|
github-server-tests:
|
|
26
|
-
#### Developer note: If
|
|
27
|
-
#### `
|
|
26
|
+
#### Developer note: If you have both `push` and `pull_request` in the
|
|
27
|
+
#### `on` section (above), this avoids running double tests when someone
|
|
28
28
|
#### on the team makes a pull request
|
|
29
29
|
# 1: Trigger job on push or dispatch from this repository
|
|
30
30
|
# 2: Trigger job on pull request from a fork
|
|
@@ -71,10 +71,10 @@ jobs:
|
|
|
71
71
|
shell: bash
|
|
72
72
|
|
|
73
73
|
#### Developer note: You can probably leave this out
|
|
74
|
-
# Optional debugging to explore things like docker issues
|
|
75
|
-
- name: Docker debug tmate session
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
# # Optional debugging to explore things like docker issues
|
|
75
|
+
# - name: Docker debug tmate session
|
|
76
|
+
# if: ${{ failure() && github.event.inputs.enable_tmate == 'true' }}
|
|
77
|
+
# uses: mxschmitt/action-tmate@v3
|
|
78
78
|
|
|
79
79
|
#### Developer note: You can probably leave this out
|
|
80
80
|
- name: Run ALKiln - Env vars for our own tests from server output
|
|
@@ -93,25 +93,49 @@ jobs:
|
|
|
93
93
|
|
|
94
94
|
- name: "Run ALKiln tests"
|
|
95
95
|
if: ${{ success() }}
|
|
96
|
+
id: alkiln
|
|
96
97
|
#### Developer note: you'll need to replace `uses: ./`
|
|
97
98
|
#### with the path to ALKiln’s repository name and branch name. For example,
|
|
98
99
|
#### for version 5, use the branch name `v5`: `uses: suffolkLITLab/ALKiln@v5`
|
|
99
100
|
uses: ./
|
|
100
|
-
#### Developer note: You can probably leave this
|
|
101
|
+
#### Developer note: You can probably leave out this `env` section
|
|
101
102
|
env:
|
|
102
|
-
|
|
103
|
+
# Internal: docassemble changes sometimes break @a11y tests. That is
|
|
104
|
+
# a da problem, not ours. We will trigger these tests manually when we
|
|
105
|
+
# want to check up on this.
|
|
106
|
+
ALKILN_TAG_EXPRESSION: "${{ (github.event.inputs.tags && format('{0}', github.event.inputs.tags)) || '(not @a11y) and (not @error)' }}"
|
|
103
107
|
with:
|
|
104
108
|
#### Developer note: Required inputs. See
|
|
105
109
|
#### https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/alkiln/writing/#sandbox-inputs
|
|
106
110
|
SERVER_URL: "${{ steps.github_server.outputs.SERVER_URL }}"
|
|
107
111
|
DOCASSEMBLE_DEVELOPER_API_KEY: "${{ steps.github_server.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}"
|
|
108
112
|
INSTALL_METHOD: "server"
|
|
109
|
-
#### Developer note:
|
|
110
|
-
####
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
#### Developer note: You can probably leave the rest out
|
|
114
|
+
#### To learn more, see https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/alkiln/writing/#optional-inputs
|
|
115
|
+
ALKILN_TAG_EXPRESSION: "${{ env.ALKILN_TAG_EXPRESSION }}"
|
|
116
|
+
ALKILN_VERSION: output
|
|
117
|
+
|
|
118
|
+
#### Developer note: Example of making an issue when tests fail
|
|
119
|
+
#### that includes the text of the failure output file
|
|
120
|
+
#### See https://cli.github.com/manual/gh_issue_create for more details
|
|
121
|
+
- shell: bash
|
|
122
|
+
if: ${{ failure() }}
|
|
123
|
+
env:
|
|
124
|
+
GH_TOKEN: ${{ github.token }}
|
|
125
|
+
PATH_TO_REPORT_FILE: "${{ steps.alkiln.outputs.PATH_TO_REPORT_FILE }}"
|
|
126
|
+
PATH_TO_UNEXPECTED_RESULTS_FILE: "${{ steps.alkiln.outputs.PATH_TO_UNEXPECTED_RESULTS_FILE }}"
|
|
127
|
+
PATH_TO_DEBUG_LOG_FILE: "${{ steps.alkiln.outputs.PATH_TO_DEBUG_LOG_FILE }}"
|
|
128
|
+
run: |
|
|
129
|
+
# Make an issue with file contents or 'no file' message as part of the body
|
|
130
|
+
|
|
131
|
+
if [ -f "${{ env.PATH_TO_UNEXPECTED_RESULTS_FILE }}" ]; then
|
|
132
|
+
UNEXPECTED_2=$(cat "${{ env.PATH_TO_UNEXPECTED_RESULTS_FILE }}")
|
|
133
|
+
else
|
|
134
|
+
UNEXPECTED_2="unexpected_results.txt does not exist. Something other than the interview tests may have failed."
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
gh issue create --body "An ALKiln test run failed. See the action at ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}.
|
|
138
|
+
|
|
139
|
+
### Results:
|
|
117
140
|
|
|
141
|
+
$UNEXPECTED_2" --repo "$GITHUB_REPOSITORY" --label "testing" --title "ALKiln tests failed"
|
|
@@ -13,8 +13,8 @@ on:
|
|
|
13
13
|
jobs:
|
|
14
14
|
|
|
15
15
|
puppeteer-tests:
|
|
16
|
-
#### Developer note: If
|
|
17
|
-
#### `
|
|
16
|
+
#### Developer note: If you have both `push` and `pull_request` in the
|
|
17
|
+
#### `on` section (above), this avoids running double tests when someone
|
|
18
18
|
#### editing the repository makes a pull request
|
|
19
19
|
# 1: Trigger job on push or dispatch from this repository
|
|
20
20
|
# 2: Trigger job on pull request from a fork
|
|
@@ -55,18 +55,13 @@ jobs:
|
|
|
55
55
|
# Place the root directory in this branch to access relative paths to action files
|
|
56
56
|
- uses: actions/checkout@v4
|
|
57
57
|
|
|
58
|
-
- name: Pause between triggers
|
|
59
|
-
if: (github.event_name == 'pull_request' && ! github.event.pull_request.head.repo.fork)
|
|
60
|
-
shell: bash
|
|
61
|
-
run: sleep 60
|
|
62
|
-
|
|
63
58
|
#### Developer note: you'll need to replace `uses: ./`
|
|
64
59
|
#### with the path to ALKiln’s repository name and branch name. For example,
|
|
65
60
|
#### for version 5, use the branch name `v5`: `uses: suffolkLITLab/ALKiln@v5`
|
|
66
61
|
- uses: ./
|
|
67
62
|
#### Developer note: You can probably leave this out
|
|
68
63
|
env:
|
|
69
|
-
ALKILN_TAG_EXPRESSION: "${{ (github.event.inputs.tags && format('{0}', github.event.inputs.tags)) || 'not @a11y' }}"
|
|
64
|
+
ALKILN_TAG_EXPRESSION: "${{ (github.event.inputs.tags && format('{0}', github.event.inputs.tags)) || '(not @a11y) and (not @error)' }}"
|
|
70
65
|
with:
|
|
71
66
|
#### Developer note: Required ALKiln inputs. You can read more at
|
|
72
67
|
#### https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/alkiln/writing/#githubNyou-inputs
|
|
@@ -77,6 +72,6 @@ jobs:
|
|
|
77
72
|
# Internal: docassemble changes sometimes break @a11y tests. That is
|
|
78
73
|
# a da problem, not ours. We will trigger these tests manually when we
|
|
79
74
|
# want to check up on this.
|
|
80
|
-
ALKILN_TAG_EXPRESSION: $ALKILN_TAG_EXPRESSION
|
|
75
|
+
ALKILN_TAG_EXPRESSION: "${{ env.ALKILN_TAG_EXPRESSION }}"
|
|
81
76
|
#### Developer note: You can probably leave this out
|
|
82
|
-
|
|
77
|
+
ALKILN_VERSION: output
|
package/CHANGELOG.md
CHANGED
|
@@ -43,11 +43,32 @@ Format:
|
|
|
43
43
|
-
|
|
44
44
|
-->
|
|
45
45
|
|
|
46
|
-
## [Unreleased]
|
|
46
|
+
<!-- ## [Unreleased] -->
|
|
47
|
+
|
|
48
|
+
## [5.12.0] - 2024-06-06
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
|
|
52
|
+
- New file with just failure results, including cucumber results when possible. It accumulates Scenario info as the tests run. Even if a test run stops early, there will still be some results.
|
|
53
|
+
- New output from ALKiln action - `PATH_TO_ARTIFACTS`. The value is `""` or the path to the folder that contains the output of the test run, if the test run actually happened. Sometimes this folder doesn't get created. For example, if there was a typo in one or more `.feature` file. For example, `"alkiln-2024-06-03 at 02h29m44sUTC"`.
|
|
54
|
+
- New outputs from the ALKiln action - `PATH_TO_REPORT_FILE`, `PATH_TO_UNEXPECTED_RESULTS_FILE`, and `PATH_TO_DEBUG_LOG_FILE`. For example, `"alkiln-2024-06-03 at 02h29m44sUTC/report.txt"`. Authors can choose to use these as they wish. For example, they can put the contents of these files in issues they create from their workflow. Closes [#701](https://github.com/SuffolkLITLab/ALKiln/issues/701).
|
|
55
|
+
- Added cucumber output to report.txt.
|
|
56
|
+
- Added more explanation for the logs that appear when test runs error in a way that prevents debug_log.txt and such files from being created. We will watch for feedback about the error data itself. It may still be too confusing.
|
|
47
57
|
|
|
48
58
|
### Changed
|
|
49
59
|
|
|
50
|
-
-
|
|
60
|
+
- report.txt accumulates over time instead of being created all at once at the end. Even if a test run stops early, there will still be some results.
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
|
|
64
|
+
- Tag expression not being parsed correctly. Surrounded `ALKILN_TAG_EXPRESSION` with `"`.
|
|
65
|
+
|
|
66
|
+
### Internal
|
|
67
|
+
|
|
68
|
+
- Download ALKiln's artifacts back into the running job.
|
|
69
|
+
- Removed our own workflow's pause between triggers.
|
|
70
|
+
- Improved our use of ALKIN_TAG_EXPRESSION env var.
|
|
71
|
+
- Exclude tests that we are aware fail. We will test those manually.
|
|
51
72
|
|
|
52
73
|
## [5.11.2] - 2024-05-17
|
|
53
74
|
|
package/action.yml
CHANGED
|
@@ -34,6 +34,20 @@ inputs:
|
|
|
34
34
|
required: false
|
|
35
35
|
default: "0.0.17"
|
|
36
36
|
|
|
37
|
+
outputs:
|
|
38
|
+
PATH_TO_ARTIFACTS:
|
|
39
|
+
description: 'An empty string ("") or the path to the artifacts folder that contains the test run output. Remember to check for the existence of the folder before using it.'
|
|
40
|
+
value: ${{ steps.alkiln_outputs.outputs.PATH_TO_ARTIFACTS }}
|
|
41
|
+
PATH_TO_REPORT_FILE:
|
|
42
|
+
description: 'An empty string ("") or the path to report.txt. Remember to check for the existence of the file before using it.'
|
|
43
|
+
value: ${{ steps.alkiln_outputs.outputs.PATH_TO_REPORT_FILE }}
|
|
44
|
+
PATH_TO_UNEXPECTED_RESULTS_FILE:
|
|
45
|
+
description: 'An empty string ("") or the path to unexpected_results.txt. Remember to check for the existence of the file before using it.'
|
|
46
|
+
value: ${{ steps.alkiln_outputs.outputs.PATH_TO_UNEXPECTED_RESULTS_FILE }}
|
|
47
|
+
PATH_TO_DEBUG_LOG_FILE:
|
|
48
|
+
description: 'An empty string ("") or the path to debug_log.txt. Remember to check for the existence of the file before using it.'
|
|
49
|
+
value: ${{ steps.alkiln_outputs.outputs.PATH_TO_DEBUG_LOG_FILE }}
|
|
50
|
+
|
|
37
51
|
runs:
|
|
38
52
|
using: "composite"
|
|
39
53
|
steps:
|
|
@@ -102,6 +116,7 @@ runs:
|
|
|
102
116
|
if: ${{ inputs.INSTALL_METHOD == 'playground' && failure() }}
|
|
103
117
|
shell: bash
|
|
104
118
|
run: |
|
|
119
|
+
# 😞 ALK0028 ERROR: Unable to create a Project
|
|
105
120
|
echo -e "\n\n====\n😞 ALK0028 ERROR: Unable to create a Project on your server's testing account or pull your package into it. Check the messages above this line.\n\n"
|
|
106
121
|
|
|
107
122
|
# Server installations - find folders and save session vars
|
|
@@ -121,7 +136,7 @@ runs:
|
|
|
121
136
|
env:
|
|
122
137
|
ALKILN_TAG_EXPRESSION: ${{ inputs.ALKILN_TAG_EXPRESSION || github.event.inputs.tags && format('{0}', github.event.inputs.tags) }}
|
|
123
138
|
shell: bash
|
|
124
|
-
run: alkiln-run $ALKILN_TAG_EXPRESSION
|
|
139
|
+
run: alkiln-run "$ALKILN_TAG_EXPRESSION"
|
|
125
140
|
|
|
126
141
|
# on playground, delete project
|
|
127
142
|
- name: "💡 ALK0032 INFO: Delete the Project from the Playground"
|
|
@@ -137,6 +152,64 @@ runs:
|
|
|
137
152
|
name: ${{ env.ARTIFACT_NAME }}
|
|
138
153
|
path: ./alkiln-*
|
|
139
154
|
|
|
155
|
+
# Download artifacts folder internally to create action output
|
|
156
|
+
- name: "💡 ALK0183 INFO: Get uploaded artifacts folder"
|
|
157
|
+
if: ${{ always() }}
|
|
158
|
+
uses: actions/download-artifact@v4
|
|
159
|
+
with:
|
|
160
|
+
name: ${{ env.ARTIFACT_NAME }}
|
|
161
|
+
|
|
162
|
+
- name: "💡 ALK0184 INFO: Prepare ALKiln output file paths"
|
|
163
|
+
if: ${{ always() }}
|
|
164
|
+
id: alkiln_outputs
|
|
165
|
+
shell: bash
|
|
166
|
+
run: |
|
|
167
|
+
# 💡 ALK0184 INFO: Prepare ALKiln output file paths
|
|
168
|
+
|
|
169
|
+
FOLDER=$(ls -d */ | grep -E '^alkiln-*' || true)
|
|
170
|
+
|
|
171
|
+
echo "Test results artifacts folder is $FOLDER"
|
|
172
|
+
|
|
173
|
+
if [[ "$FOLDER" = "" ]]; then
|
|
174
|
+
echo "Artifacts folder is missing. The path is an empty string: '$FOLDER'"
|
|
175
|
+
|
|
176
|
+
else
|
|
177
|
+
REPORT_PATH="${FOLDER}report.txt"
|
|
178
|
+
UNEXPECTED_RESULTS_PATH="${FOLDER}unexpected_results.txt"
|
|
179
|
+
DEBUG_LOG_PATH="${FOLDER}debug_log.txt"
|
|
180
|
+
|
|
181
|
+
if [ -f "$REPORT_PATH" ]; then
|
|
182
|
+
echo "$REPORT_PATH exists"
|
|
183
|
+
else
|
|
184
|
+
echo "$REPORT_PATH is missing"
|
|
185
|
+
REPORT_PATH=""
|
|
186
|
+
fi
|
|
187
|
+
|
|
188
|
+
if [ -f "$UNEXPECTED_RESULTS_PATH" ]; then
|
|
189
|
+
echo "$UNEXPECTED_RESULTS_PATH exists"
|
|
190
|
+
else
|
|
191
|
+
echo "$UNEXPECTED_RESULTS_PATH is missing"
|
|
192
|
+
UNEXPECTED_RESULTS_PATH=""
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
if [ -f "$DEBUG_LOG_PATH" ]; then
|
|
196
|
+
echo "$DEBUG_LOG_PATH exists"
|
|
197
|
+
else
|
|
198
|
+
echo "$DEBUG_LOG_PATH is missing"
|
|
199
|
+
DEBUG_LOG_PATH=""
|
|
200
|
+
fi
|
|
201
|
+
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
echo "PATH_TO_ARTIFACTS=$FOLDER" >> "$GITHUB_OUTPUT"
|
|
205
|
+
echo "PATH_TO_REPORT_FILE=$REPORT_PATH" >> "$GITHUB_OUTPUT"
|
|
206
|
+
echo "PATH_TO_UNEXPECTED_RESULTS_FILE=$UNEXPECTED_RESULTS_PATH" >> "$GITHUB_OUTPUT"
|
|
207
|
+
echo "PATH_TO_DEBUG_LOG_FILE=$DEBUG_LOG_PATH" >> "$GITHUB_OUTPUT"
|
|
208
|
+
|
|
209
|
+
# Avoid creating output from text in files
|
|
210
|
+
# Cannot properly create outputs with multi-line text. Collapses onto one line.
|
|
211
|
+
|
|
140
212
|
- shell: bash
|
|
213
|
+
if: ${{ always() }}
|
|
141
214
|
run: |
|
|
142
215
|
echo "💡 ALK0034 INFO: ALkiln finished running tests"
|
|
@@ -109,12 +109,14 @@ runs:
|
|
|
109
109
|
if: ${{ env.OUTPUT_DOCKER == 'false' }}
|
|
110
110
|
shell: bash
|
|
111
111
|
run: |
|
|
112
|
-
|
|
112
|
+
# 💡 ALK0007 INFO: ALKiln will now hide docker output
|
|
113
|
+
echo -e '===\n💡 ALK0007 INFO: ALKiln will now hide docker output to avoid possibly showing details about your config. If you want to get output to see more of what is going on, use "with:" and set the input "SHOW_DOCKER_OUTPUT" to "true". This output will only be visible to those who can already see the action output, like people with admin or write permissions.\n==='
|
|
113
114
|
- name: "💡 ALK0008 INFO: ALKiln will show docker output"
|
|
114
115
|
if: ${{ env.OUTPUT_DOCKER == 'true' }}
|
|
115
116
|
shell: bash
|
|
116
117
|
run: |
|
|
117
|
-
|
|
118
|
+
# 💡 ALK0008 INFO: ALKiln will show docker output
|
|
119
|
+
echo -e '===\n💡 ALK0008 INFO: ALKiln will show docker output. ALKiln cannot control this output. If you want to prevent output, use "with:" and set the input "SHOW_DOCKER_OUTPUT" to "false". This output will only be visible to those who can already see the action output, like people with admin or write permissions.\n==='
|
|
118
120
|
|
|
119
121
|
# TODO: Reduce these to 1 block by putting ` > /dev/null 2>&1` into an env var
|
|
120
122
|
# No docker output
|
|
@@ -156,6 +158,7 @@ runs:
|
|
|
156
158
|
if: ${{ env.OUTPUT_DOCKER == 'false' }}
|
|
157
159
|
shell: bash
|
|
158
160
|
run: |
|
|
161
|
+
# 💡 ALK0011 INFO: The following messages are not docker output
|
|
159
162
|
echo "💡 ALK0011 INFO: The following messages are not docker output, just ALKiln waiting for the server to start"
|
|
160
163
|
|
|
161
164
|
- name: "💡 ALK0012 INFO: Waiting for server to start"
|
|
@@ -245,4 +248,3 @@ runs:
|
|
|
245
248
|
if: ${{ failure() }}
|
|
246
249
|
run: |
|
|
247
250
|
echo "🤕 ALK0022 ERROR: Something went wrong. See above for more details."
|
|
248
|
-
|
package/lib/run_cucumber.js
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const cucumber_api = require('@cucumber/cucumber/api');
|
|
5
5
|
|
|
6
|
-
const log = require('./utils/log');
|
|
6
|
+
const log = require('./utils/log'); // These always log in the console
|
|
7
7
|
const session_vars = require('./utils/session_vars');
|
|
8
8
|
|
|
9
|
+
const SUMMARY_FILENAME = `cucumber-report.txt`;
|
|
10
|
+
|
|
9
11
|
function build_config( command_args ) {
|
|
10
12
|
// Turn all the paths to the sources folders into paths to the feature files
|
|
11
13
|
let sources_paths = session_vars.get_sources_paths();
|
|
@@ -17,14 +19,17 @@ function build_config( command_args ) {
|
|
|
17
19
|
const config = {
|
|
18
20
|
publishQuiet: true,
|
|
19
21
|
require: `./lib/index.js`,
|
|
20
|
-
format: [`progress`, `summary
|
|
22
|
+
format: [`progress`, `summary:${ SUMMARY_FILENAME }`],
|
|
21
23
|
paths: feature_paths,
|
|
22
24
|
retry: 1,
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
// Normalize tag expressions, if there are any
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
// Joining and splitting handles both tags surrounded with `""` or those without `""`
|
|
29
|
+
let tags = command_args[`_`].join(` `).split(` `);
|
|
30
|
+
// If there was no tag expression, `tags` is ['']. Remove that item.
|
|
31
|
+
tags = tags.filter(function(entry) { return entry !== ""; })
|
|
32
|
+
if ( tags.length > 0 ) {
|
|
28
33
|
let joined_tags = '';
|
|
29
34
|
// Cucumber expects tags in boolean expressions, like (@a0 or @a1) and @random.
|
|
30
35
|
// If we get a list of only tags, then "or" them all together
|
|
@@ -105,19 +110,21 @@ function build_config( command_args ) {
|
|
|
105
110
|
|
|
106
111
|
const { success } = await cucumber_api.runCucumber({...runConfiguration, support});
|
|
107
112
|
if ( success ) {
|
|
108
|
-
log.
|
|
113
|
+
log.success({ type: `run`, code: `ALK0054`, pre: `Tests succeeded!` });
|
|
109
114
|
} else {
|
|
110
|
-
log.error({ type: `run`, code: `ALK0055`, pre: `
|
|
115
|
+
log.error({ type: `run`, code: `ALK0055`, pre: `The test run ran into something unexpected. Look above for more details.` });
|
|
111
116
|
}
|
|
112
|
-
|
|
117
|
+
// Custom exit code. May overlap with other systems.
|
|
118
|
+
// Best info I've found via stack overflow: https://tldp.org/LDP/abs/html/exitcodes.html
|
|
119
|
+
const exitCode = success ? 0 : 50;
|
|
113
120
|
process.exitCode = exitCode;
|
|
114
121
|
|
|
115
122
|
// This is hardcoded information from `provide_config` above.
|
|
116
123
|
// This code isn't used for anything other than detecting and removing color codes.
|
|
117
|
-
let summary_file_name =
|
|
124
|
+
let summary_file_name = SUMMARY_FILENAME;
|
|
118
125
|
fs.readFile(summary_file_name, 'utf8', (err, text) => {
|
|
119
126
|
if (err) {
|
|
120
|
-
log.error({ type: `run`, code: `ALK0056`, pre: `cucumber report`, data: err });
|
|
127
|
+
log.error({ type: `internal run`, code: `ALK0056`, pre: `Failed to read cucumber report`, data: err });
|
|
121
128
|
return;
|
|
122
129
|
}
|
|
123
130
|
|
|
@@ -127,6 +134,18 @@ function build_config( command_args ) {
|
|
|
127
134
|
|
|
128
135
|
// Put it in the correct file in the correct folder
|
|
129
136
|
let artifacts_path = session_vars.get_artifacts_path_name();
|
|
130
|
-
|
|
137
|
+
try {
|
|
138
|
+
fs.appendFileSync( `${ artifacts_path }/${ log.debug_log_file }`, `\n\n${text}`);
|
|
139
|
+
} catch ( error ) {
|
|
140
|
+
log.info({ type: `internal run`, code: `ALK0182`, pre: `Something probably went wrong earlier. Look above for more details, but here's more info just in case: ALKiln was unable to write to ${ artifacts_path }/${ log.debug_log_file }.`, data: error });
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
// Add to a unexpected results file when tests themselves fail
|
|
144
|
+
if ( exitCode === 50 ) {
|
|
145
|
+
fs.appendFileSync( `${ artifacts_path }/${ log.unexpected_filename }`, `\n\n${ text }` );
|
|
146
|
+
}
|
|
147
|
+
} catch ( error ) {
|
|
148
|
+
log.info({ type: `internal run`, code: `ALK0181`, pre: `Something probably went wrong earlier. Look above for more details, but here's more info just in case: ALKiln was unable to write to ${ artifacts_path }/${ log.unexpected_filename }.`, data: error });
|
|
149
|
+
}
|
|
131
150
|
});
|
|
132
151
|
})();
|
package/lib/scope.js
CHANGED
|
@@ -3228,8 +3228,7 @@ module.exports = {
|
|
|
3228
3228
|
*
|
|
3229
3229
|
* @param expected {array} Arr of strs that should appear in the report.
|
|
3230
3230
|
*/
|
|
3231
|
-
let
|
|
3232
|
-
let scenario = [ scope.scenario_id, current_report_obj ]; // Mimic how loop works with `Map`
|
|
3231
|
+
let scenario = scope.report.get( scope.scenario_id );
|
|
3233
3232
|
let report = reports.getPrintableScenario( scenario );
|
|
3234
3233
|
let all_are_included = true;
|
|
3235
3234
|
for ( let one_expectation of expected ) {
|
|
@@ -3248,8 +3247,7 @@ module.exports = {
|
|
|
3248
3247
|
*
|
|
3249
3248
|
* @param not_expected {array} Arr of strs that should not appear in the report.
|
|
3250
3249
|
*/
|
|
3251
|
-
let
|
|
3252
|
-
let scenario = [ scope.scenario_id, current_report_obj ]; // Mimic how loop works with `Map`
|
|
3250
|
+
let scenario = scope.report.get( scope.scenario_id );
|
|
3253
3251
|
let report = reports.getPrintableScenario( scenario );
|
|
3254
3252
|
let none_included = true;
|
|
3255
3253
|
for ( let one_expectation of not_expected ) {
|
package/lib/steps.js
CHANGED
|
@@ -101,8 +101,11 @@ BeforeAll(async () => {
|
|
|
101
101
|
session_vars.save_artifacts_path_name( scope.paths.artifacts );
|
|
102
102
|
|
|
103
103
|
scope.paths.report = `${ scope.paths.artifacts }/report.txt`;
|
|
104
|
+
scope.paths.failures = `${ scope.paths.artifacts }/${ log.unexpected_filename }`;
|
|
104
105
|
scope.paths.debug_log = `${ scope.paths.artifacts }/${ log.debug_log_file }`;
|
|
105
106
|
fs.writeFileSync( scope.paths.debug_log, "" );
|
|
107
|
+
|
|
108
|
+
reports.create( scope );
|
|
106
109
|
});
|
|
107
110
|
|
|
108
111
|
Before(async (scenario) => {
|
|
@@ -1202,17 +1205,17 @@ After(async function(scenario) {
|
|
|
1202
1205
|
}
|
|
1203
1206
|
|
|
1204
1207
|
if ( scope.failed_pdf_compares.length > 0) {
|
|
1205
|
-
let msg = scope.failed_pdf_compares.reduce((str, new_msg) => `${ str }\n
|
|
1208
|
+
let msg = scope.failed_pdf_compares.reduce((str, new_msg) => `${ str }\n―――\n${ new_msg }`)
|
|
1206
1209
|
changeable_test_status = `FAILED`;
|
|
1207
1210
|
reports.addToReport(scope, {
|
|
1208
1211
|
type: `error`,
|
|
1209
1212
|
code: `ALK0093`,
|
|
1210
|
-
value: `PDF comparison failed ${ scope.failed_pdf_compares.length } time(s)\n
|
|
1213
|
+
value: `PDF comparison failed ${ scope.failed_pdf_compares.length } time(s)\n―――\n${ msg }\n―――\n`
|
|
1211
1214
|
});
|
|
1212
1215
|
}
|
|
1213
1216
|
|
|
1214
1217
|
// Record status before internal report tests can interfere with values
|
|
1215
|
-
reports.
|
|
1218
|
+
reports.saveFinalScenarioData( scope, { status: changeable_test_status });
|
|
1216
1219
|
|
|
1217
1220
|
if (changeable_test_status !== `PASSED`) {
|
|
1218
1221
|
log.debug({
|
|
@@ -1256,11 +1259,11 @@ After(async function(scenario) {
|
|
|
1256
1259
|
} // ends if not passed
|
|
1257
1260
|
|
|
1258
1261
|
// Add report text to Scenario folder after everything has been added to the report
|
|
1259
|
-
let
|
|
1260
|
-
let scenario_report_obj = [ scope.scenario_id, current_report_obj ]; // Mimic how loop works with `Map`
|
|
1262
|
+
let scenario_report_obj = scope.report.get( scope.scenario_id );
|
|
1261
1263
|
let report = reports.getPrintableScenario( scenario_report_obj );
|
|
1262
1264
|
// Save the report as in the Scenario folder
|
|
1263
1265
|
fs.writeFileSync( scope.paths.scenario_report, report );
|
|
1266
|
+
// TODO: Save any cucumber failure message for the Scenario here (instead of waiting till run_cucumber.js)
|
|
1264
1267
|
|
|
1265
1268
|
// ---------------- Check internal test results ----------------
|
|
1266
1269
|
|
|
@@ -1273,7 +1276,7 @@ After(async function(scenario) {
|
|
|
1273
1276
|
// Reset report values no matter what so they don't mess up future scenarios
|
|
1274
1277
|
scope.expected_in_report = null;
|
|
1275
1278
|
}
|
|
1276
|
-
|
|
1279
|
+
|
|
1277
1280
|
if (scope.expected_not_in_report && scope.expected_not_in_report.length > 0) {
|
|
1278
1281
|
let all_prohibited_strings_were_absent = await scope.reportDoesNotInclude(
|
|
1279
1282
|
scope,
|
|
@@ -1354,7 +1357,7 @@ After(async function(scenario) {
|
|
|
1354
1357
|
// Catch a possible reload error.
|
|
1355
1358
|
try {
|
|
1356
1359
|
// puppeteer will ensure proper timeout.
|
|
1357
|
-
await scope.page.goto(`${ session_vars.get_da_server_url() }/user/sign-out`, {waitUntil: `domcontentloaded`});
|
|
1360
|
+
await scope.page.goto(`${ session_vars.get_da_server_url() }/user/sign-out`, {waitUntil: `domcontentloaded`});
|
|
1358
1361
|
|
|
1359
1362
|
} catch ( error ) {
|
|
1360
1363
|
signout_succeeded = false;
|
|
@@ -1405,17 +1408,14 @@ After(async function(scenario) {
|
|
|
1405
1408
|
AfterAll(async function() {
|
|
1406
1409
|
// Stop collecting server response statuses
|
|
1407
1410
|
scope.stop_tracking_server_status = true;
|
|
1408
|
-
|
|
1411
|
+
|
|
1409
1412
|
let report = reports.getPrintableReport( scope );
|
|
1410
1413
|
// Log the report. Can't get this.attach() or this.log() to work in `After()` or here.
|
|
1411
1414
|
// May need newest version of cucumberjs
|
|
1412
1415
|
console.log( `\n\n${ report }` );
|
|
1413
1416
|
|
|
1414
|
-
// Save/download the report as an artifact
|
|
1415
|
-
fs.writeFileSync( scope.paths.report, report );
|
|
1416
|
-
|
|
1417
1417
|
// If there is a browser open, then close it
|
|
1418
1418
|
if (scope.browser) {
|
|
1419
1419
|
await scope.browser.close();
|
|
1420
1420
|
}
|
|
1421
|
-
});
|
|
1421
|
+
});
|
package/lib/utils/log.js
CHANGED
|
@@ -2,6 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const session_vars = require( './session_vars' );
|
|
3
3
|
|
|
4
4
|
// ? 🌈 💡 🔎 🤕 🐞
|
|
5
|
+
// Alternatives: 🩹 ❤️🩹 🚑
|
|
5
6
|
// TODO: return full message so it can be passed to manually
|
|
6
7
|
// thrown errors if needed.
|
|
7
8
|
|
|
@@ -91,4 +92,5 @@ log.add_to_debug_log = function(value) {
|
|
|
91
92
|
fs.appendFileSync(log.debug_log_file, value);
|
|
92
93
|
};
|
|
93
94
|
|
|
94
|
-
log.debug_log_file =
|
|
95
|
+
log.debug_log_file = `debug_log.txt`;
|
|
96
|
+
log.unexpected_filename = `unexpected_results.txt`;
|
package/lib/utils/reports.js
CHANGED
|
@@ -7,6 +7,13 @@ const files = require(`./files` );
|
|
|
7
7
|
|
|
8
8
|
module.exports = reports = {};
|
|
9
9
|
|
|
10
|
+
reports.title = `Assembly Line Kiln Automated Testing Report - ${ (new Date()).toUTCString() }\n`;
|
|
11
|
+
reports.failures = [ `\n\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n🤕 Failed scenarios\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n` ];
|
|
12
|
+
reports.successes = [ `\n\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n🌈 Passed scenarios\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n` ];
|
|
13
|
+
// reports.warnings = [ `\n\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n🔎 Scenarios to check\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n` ];
|
|
14
|
+
// reports.undefineds = [ `\n\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n[langs icon] Scenarios with typos\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n` ];
|
|
15
|
+
reports.others = [ `\n\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n🔎 Other scenarios that did not pass\n≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n` ];
|
|
16
|
+
|
|
10
17
|
reports.addReportHeading = function (scope, { scenario }) {
|
|
11
18
|
/** Return printable heading based on Scenario name and tags.
|
|
12
19
|
* Allow characters from other languages.
|
|
@@ -19,14 +26,14 @@ reports.addReportHeading = function (scope, { scenario }) {
|
|
|
19
26
|
tag_names.push( tag.name );
|
|
20
27
|
}
|
|
21
28
|
|
|
22
|
-
let heading = `\n
|
|
29
|
+
let heading = `\n―――――――――――――――\n`
|
|
23
30
|
+ `Scenario: ${ scenario.pickle.name }`;
|
|
24
31
|
|
|
25
32
|
if ( tag_names.length > 0 ) {
|
|
26
33
|
heading += `\nTags: ${ tag_names.join(' ') }`;
|
|
27
34
|
}
|
|
28
35
|
|
|
29
|
-
heading += `\n
|
|
36
|
+
heading += `\n―――――――――――――――`;
|
|
30
37
|
|
|
31
38
|
reports.addToReport( scope, {
|
|
32
39
|
code: `ALK0176`,
|
|
@@ -71,21 +78,30 @@ reports.addToReport = function( scope, { type, code, value }) {
|
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
// Report stuff
|
|
74
|
-
let scenario =
|
|
81
|
+
let scenario = reports.makeSureScenarioExists( scope );
|
|
75
82
|
scenario.lines.push({ type, code, value });
|
|
76
83
|
|
|
77
84
|
return scenario;
|
|
78
85
|
}; // Ends reports.addToReport()
|
|
79
86
|
|
|
80
|
-
|
|
87
|
+
reports.create = function( scope ) {
|
|
88
|
+
reports.makeSureReportExists( scope );
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
reports.makeSureReportExists = function( scope ) {
|
|
81
92
|
/** If a part of the report needs to exist right now, but doesn't exist,
|
|
82
93
|
* create it. */
|
|
83
94
|
if ( !scope.report ) { scope.report = new Map(); }
|
|
95
|
+
return this;
|
|
96
|
+
}; // Ends reports.makeSureReportExists()
|
|
97
|
+
|
|
98
|
+
reports.makeSureScenarioExists = function ( scope ) {
|
|
99
|
+
reports.makeSureReportExists( scope );
|
|
84
100
|
if ( !scope.scenario_id ) {
|
|
85
101
|
scope.scenario_id = `_report_${ Date.now() }`;
|
|
86
102
|
}
|
|
87
103
|
if ( !scope.report.get( scope.scenario_id )) {
|
|
88
|
-
scope.report.set( scope.scenario_id, {} )
|
|
104
|
+
scope.report.set( scope.scenario_id, {} );
|
|
89
105
|
scope.report.get( scope.scenario_id ).status = `in progress`;
|
|
90
106
|
}
|
|
91
107
|
|
|
@@ -93,11 +109,36 @@ let makeSureReportPartsExist = function( scope ) {
|
|
|
93
109
|
if ( !scenario.lines ) { scenario.lines = []; }
|
|
94
110
|
|
|
95
111
|
return scenario;
|
|
96
|
-
}; // Ends
|
|
112
|
+
}; // Ends reports.makeSureScenarioExists()
|
|
113
|
+
|
|
114
|
+
reports.saveFinalScenarioData = function( scope, { status=`in progress` }) {
|
|
115
|
+
this.setReportScenarioStatus( scope, { status });
|
|
116
|
+
let scenario = scope.report.get( scope.scenario_id );
|
|
117
|
+
let report = this.getPrintableScenario( scenario );
|
|
118
|
+
if ( scenario.status === `FAILED` ) { this.failures.push( report ); }
|
|
119
|
+
else if ( scenario.status === `PASSED` ) { this.successes.push( report ); }
|
|
120
|
+
// else if ( scenario.status === `WARNING` ) { passed_reports += report; this.warnings.push( report ); }
|
|
121
|
+
// else if ( scenario.status === `UNDEFINED` ) { passed_reports += report; this.undefineds.push( report ); }
|
|
122
|
+
else { this.others.push( report ); }
|
|
123
|
+
|
|
124
|
+
// Save to failures.txt (worry about optimization later)
|
|
125
|
+
if ( this.failures.length > 1 || this.others.length > 1 ) {
|
|
126
|
+
fs.writeFileSync(
|
|
127
|
+
scope.paths.failures,
|
|
128
|
+
this.title + this.getPrintableUnexpected( scope )
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
// Save to reports.txt (worry about optimization later)
|
|
132
|
+
fs.writeFileSync( scope.paths.report, this.getPrintableReport( scope ) );
|
|
133
|
+
|
|
134
|
+
return scenario;
|
|
135
|
+
}; // Ends reports.saveFinalScenarioData()
|
|
136
|
+
|
|
97
137
|
|
|
98
138
|
reports.setReportScenarioStatus = function( scope, { status=`PASSED` }) {
|
|
99
139
|
/** Add final status of scenario to scenario report object - passed, failed, etc. */
|
|
100
140
|
scope.report.get( scope.scenario_id ).status = status;
|
|
141
|
+
return scope.report.get( scope.scenario_id );
|
|
101
142
|
}; // Ends reports.setReportScenarioStatus()
|
|
102
143
|
|
|
103
144
|
reports.convertToOriginalStoryTableRow = function( scope, { row_data }) {
|
|
@@ -124,34 +165,38 @@ let trimJSON = function( str=`` ) {
|
|
|
124
165
|
}; // Ends trimJSON()
|
|
125
166
|
|
|
126
167
|
reports.getPrintableReport = function( scope ) {
|
|
127
|
-
/** Return a string generated from test report data.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
let [ scenario_id, data ] = scenario;
|
|
138
|
-
if ( data.status === `FAILED` ) { failed_reports += report; }
|
|
139
|
-
else if ( data.status === `PASSED` ) { passed_reports += report; }
|
|
140
|
-
else { other_reports += report; }
|
|
141
|
-
}; // ends for every scenario
|
|
142
|
-
|
|
143
|
-
if ( failed_reports !== `` ) { report += `\n\n===============================\n===============================\n🤕 Failed scenarios:\n${ failed_reports }`; }
|
|
144
|
-
if ( other_reports !== `` ) { report += `\n\n===============================\n===============================\n🔎 Scenarios that did not pass:\n${ other_reports }`; }
|
|
145
|
-
if ( passed_reports !== `` ) { report += `\n\n===============================\n===============================\n🌈 Passed scenarios:\n${ passed_reports }`; }
|
|
168
|
+
/** Return a string generated from test report data.
|
|
169
|
+
*
|
|
170
|
+
* First list failed scenarios, then non-passed scenarios, then passed scenarios. */
|
|
171
|
+
let report = this.getTitle( scope );
|
|
172
|
+
|
|
173
|
+
if ( this.failures.length > 1 ) { report += this.failures.join( `` ); }
|
|
174
|
+
if ( this.successes.length > 1 ) { report += this.successes.join( `` ); }
|
|
175
|
+
// if ( this.warnings.length > 1 ) {}
|
|
176
|
+
// if ( this.undefineds.length > 1 ) {}
|
|
177
|
+
if ( this.others.length > 1 ) { report += this.others.join( `` ); }
|
|
146
178
|
|
|
147
179
|
return report;
|
|
148
180
|
}; // Ends reports.getPrintableReport()
|
|
149
181
|
|
|
182
|
+
reports.getTitle = function( scope ) { return this.title; }
|
|
183
|
+
|
|
184
|
+
reports.getPrintableUnexpected = function( scope ) {
|
|
185
|
+
// Note about `> 1`: The first line of the report section always exists
|
|
186
|
+
let output = ``;
|
|
187
|
+
if ( this.failures.length > 1 ) {
|
|
188
|
+
output += this.failures.join(``);
|
|
189
|
+
}
|
|
190
|
+
if ( this.others.length > 1 ) {
|
|
191
|
+
output += this.others.join(``);
|
|
192
|
+
}
|
|
193
|
+
return output;
|
|
194
|
+
}; // Ends reports.getPrintableUnexpected()
|
|
195
|
+
|
|
150
196
|
reports.getPrintableScenario = function( scenario ) {
|
|
151
197
|
/** Return a string generated from scenario list of report items. */
|
|
152
|
-
let [ scenario_id, data ] = scenario;
|
|
153
198
|
let report = ``;
|
|
154
|
-
for ( let line of
|
|
199
|
+
for ( let line of scenario.lines ) {
|
|
155
200
|
let { type, code, value } = line;
|
|
156
201
|
report += `${ getLineText({ type, code, value }) }\n`;
|
|
157
202
|
}
|
|
@@ -107,7 +107,7 @@ session_vars.get_languages = function () {
|
|
|
107
107
|
}; // Ends session_vars.get_languages()
|
|
108
108
|
|
|
109
109
|
|
|
110
|
-
const runtime_config_path =
|
|
110
|
+
const runtime_config_path = `runtime_config.json`;
|
|
111
111
|
const project_name_key = `da_project_name`;
|
|
112
112
|
session_vars.save_project_name = function ( project_name ) {
|
|
113
113
|
/* Saves the name of the project to a json obj so deletion can use it later.
|
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suffolklitlab/alkiln",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.12.0",
|
|
4
4
|
"description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "npm run unit && npm run codes && npm run cucumber",
|
|
8
8
|
"cucumber": "./lib/run_cucumber.js",
|
|
9
9
|
"local": "npm run setup && npm run cucumber; npm run takedown",
|
|
10
|
+
"pass": "npm run cucumber 'not @error'",
|
|
11
|
+
"fail": "npm run cucumber '@error'",
|
|
10
12
|
"setup": "./lib/docassemble/setup.js",
|
|
11
13
|
"takedown": "./lib/docassemble/takedown.js",
|
|
12
14
|
"server_install": "./lib/docassemble/server_install.js",
|