@suffolklitlab/alkiln 5.4.2 → 5.5.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 +68 -0
- package/CHANGELOG.md +9 -1
- package/action.yml +33 -10
- package/action_for_github_server/action.yml +141 -0
- package/lib/docassemble/docassemble_api_REST.js +10 -2
- package/lib/docassemble/docassemble_api_interface.js +15 -10
- package/lib/docassemble/get_base_interview_url.js +13 -3
- package/lib/docassemble/server_install.js +39 -0
- package/lib/docassemble/setup.js +1 -1
- package/lib/scope.js +55 -18
- package/lib/steps.js +15 -1
- package/lib/utils/session_vars.js +66 -13
- package/package.json +3 -1
- package/setup.py +2 -2
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: GitHub server tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
workflow_dispatch:
|
|
6
|
+
inputs:
|
|
7
|
+
tags:
|
|
8
|
+
required: False
|
|
9
|
+
description: 'Optional. Use a "tag expression" specify which tagged tests to run (https://cucumber.io/docs/cucumber/api/#tag-expressions)'
|
|
10
|
+
enable_tmate:
|
|
11
|
+
type: boolean
|
|
12
|
+
description: 'Run the build with tmate debugging enabled (https://github.com/marketplace/actions/debugging-with-tmate)'
|
|
13
|
+
required: false
|
|
14
|
+
default: false
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
|
|
18
|
+
github-server-tests:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
matrix:
|
|
22
|
+
node-version: [18.x]
|
|
23
|
+
|
|
24
|
+
env:
|
|
25
|
+
SECRET_VAR1: secret-var1-value
|
|
26
|
+
SECRET_VAR2: secret-var2-value
|
|
27
|
+
SECRET_FOR_MISSING_FIELD: secret for missing field
|
|
28
|
+
|
|
29
|
+
steps:
|
|
30
|
+
# Place the root directory in this branch
|
|
31
|
+
- uses: actions/checkout@v3
|
|
32
|
+
|
|
33
|
+
- name: Run ALKiln - Start the temporary GitHub server
|
|
34
|
+
id: github_server
|
|
35
|
+
uses: ./action_for_github_server
|
|
36
|
+
with:
|
|
37
|
+
CONFIG_CONTENTS: "${{ secrets.CONFIG_CONTENTS }}"
|
|
38
|
+
- run: echo "ALKiln finished starting the isolated GitHub docassemble server"
|
|
39
|
+
|
|
40
|
+
# Debugging on failure to explore things like config issues
|
|
41
|
+
- name: Run ALKiln - Docker failure tmate session
|
|
42
|
+
if: ${{ failure() }}
|
|
43
|
+
uses: mxschmitt/action-tmate@v3
|
|
44
|
+
|
|
45
|
+
- name: Run ALKiln - Env vars from server output
|
|
46
|
+
run: |
|
|
47
|
+
echo "USER1_EMAIL=${{ steps.github_server.outputs.DA_ADMIN_EMAIL }}" >> $GITHUB_ENV
|
|
48
|
+
echo "USER1_PASSWORD=${{ steps.github_server.outputs.DA_ADMIN_PASSWORD }}" >> $GITHUB_ENV
|
|
49
|
+
## Example of working with the docker container after it's been started
|
|
50
|
+
## For example, you can make more users with different permissions and passwords
|
|
51
|
+
#- name: Work with docker
|
|
52
|
+
# run: |
|
|
53
|
+
# container_name=$(docker ps --format '{{.Names}}' | head -n 1)
|
|
54
|
+
# echo "container_name is $container_name"
|
|
55
|
+
|
|
56
|
+
- name: "Run ALKiln tests"
|
|
57
|
+
if: ${{ success() }}
|
|
58
|
+
uses: ./
|
|
59
|
+
with:
|
|
60
|
+
SERVER_URL: "${{ steps.github_server.outputs.SERVER_URL }}"
|
|
61
|
+
DOCASSEMBLE_DEVELOPER_API_KEY: "${{ steps.github_server.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}"
|
|
62
|
+
INSTALL_METHOD: "server"
|
|
63
|
+
# Temporary while in pre-release
|
|
64
|
+
ALKILN_VERSION: "server"
|
|
65
|
+
# Has been useful for development. Can remove when more stable.
|
|
66
|
+
ALKILN_TAG_EXPRESSION: ""
|
|
67
|
+
- run: echo "ALkiln finished running ALKiln tests"
|
|
68
|
+
|
package/CHANGELOG.md
CHANGED
|
@@ -45,6 +45,14 @@ Format:
|
|
|
45
45
|
|
|
46
46
|
<!-- ## [Unreleased] -->
|
|
47
47
|
|
|
48
|
+
## [5.5.0] - 2023-10-27
|
|
49
|
+
|
|
50
|
+
### Added
|
|
51
|
+
- Added a github action that allows authors to run tests on an isolated server that ALKiln creates on GitHub. They will need to create a new GitHub workflow to run the action. This reduces flakiness that authors' servers can create during server reload caused by updating their config, pulling in a package with a module, and other such things. As with all tests, especially with end to end test, there will always be some flakiness.
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
- Continuing development of random input test: Deal with non-existent elements, add a default input `type` of 'text', only press 'Back' 10% of the time instead of potentially 50%, navigate back to the interview from an external link (that goes outside the server) if necessary. Also add more debug logs to help diagnose problems. https://github.com/SuffolkLITLab/ALKiln/pull/633
|
|
55
|
+
|
|
48
56
|
## [5.4.2] - 2023-10-22
|
|
49
57
|
|
|
50
58
|
### Changed
|
|
@@ -896,4 +904,4 @@ Format:
|
|
|
896
904
|
- `example.feature` - an example test to get a project started
|
|
897
905
|
- `github/workflows/run_form_tests.yml` - Automated github workflow to run tests when code is pushed and a manual trigger for testing without needing to push
|
|
898
906
|
- `.gitignore` - ignores files that are generated by the tests and shouldn't be added to the repo
|
|
899
|
-
- `package.json` - keep up-to-date version of this test repository and hold scripts that the automated tests run
|
|
907
|
+
- `package.json` - keep up-to-date version of this test repository and hold scripts that the automated tests run
|
package/action.yml
CHANGED
|
@@ -22,6 +22,15 @@ inputs:
|
|
|
22
22
|
description: "Max amount of time to give the server to reload if it needs to"
|
|
23
23
|
required: false
|
|
24
24
|
# no default to let the custom Scenario timeouts create the reload timeout
|
|
25
|
+
# INSTALL_LOCATION? Will that get confused with the location passed into the command line?
|
|
26
|
+
# Maybe `INSTALL_LOCATION` could be "playground", "server", or a custom path and we could handle all those.
|
|
27
|
+
INSTALL_METHOD:
|
|
28
|
+
description: "Default is 'playground'. Other option: 'server'. How to install the package onto the server."
|
|
29
|
+
required: false
|
|
30
|
+
default: "playground"
|
|
31
|
+
ALKILN_TAG_EXPRESSION:
|
|
32
|
+
description: "The tag expression to use to limit which tests to run. Default is no tag expression."
|
|
33
|
+
required: false
|
|
25
34
|
|
|
26
35
|
runs:
|
|
27
36
|
using: "composite"
|
|
@@ -46,29 +55,43 @@ runs:
|
|
|
46
55
|
echo -e "\nALKiln version is $ALKILN_VERSION\nRepo is $REPO_URL\nBranch ref is $BRANCH_PATH\nMAX_SECONDS_FOR_SETUP is $MAX_SECONDS_FOR_SETUP\nSERVER_RELOAD_TIMEOUT_SECONDS is $SERVER_RELOAD_TIMEOUT_SECONDS\n"
|
|
47
56
|
shell: bash
|
|
48
57
|
|
|
49
|
-
# Install
|
|
58
|
+
# Install
|
|
50
59
|
- name: "ALKiln: Install node packages"
|
|
51
60
|
uses: actions/setup-node@v3
|
|
52
61
|
with:
|
|
53
62
|
node-version: "18"
|
|
54
63
|
- name: Install ALKiln directly from npm
|
|
55
64
|
run: |
|
|
56
|
-
npm install -g @suffolklitlab/alkiln
|
|
65
|
+
npm install -g @suffolklitlab/alkiln@$ALKILN_VERSION
|
|
57
66
|
shell: bash
|
|
58
67
|
|
|
59
|
-
#
|
|
68
|
+
# Install on playground
|
|
60
69
|
- name: "ALKiln: Create a Project and pull the package from GitHub"
|
|
70
|
+
if: ${{ inputs.INSTALL_METHOD == 'playground' }}
|
|
61
71
|
run: alkiln-setup
|
|
62
72
|
shell: bash
|
|
73
|
+
- run: echo -e "\n\n====\nALKiln could not create a project on your server's testing account or pull your package into it. Check the messages above this line.\n\n"
|
|
74
|
+
if: ${{ inputs.INSTALL_METHOD == 'playground' && failure() }}
|
|
75
|
+
shell: bash
|
|
76
|
+
|
|
77
|
+
# Install on server
|
|
78
|
+
- name: "ALKiln: Install the GitHub package onto the server"
|
|
79
|
+
if: ${{ inputs.INSTALL_METHOD == 'server' }}
|
|
80
|
+
run: alkiln-server-install
|
|
81
|
+
shell: bash
|
|
82
|
+
- run: echo -e "\n\n====\nALKiln could not install the package on the temporary GitHub docassemble server. Check the steps above this line.\n\n"
|
|
83
|
+
if: ${{ inputs.INSTALL_METHOD == 'server' && failure() }}
|
|
84
|
+
shell: bash
|
|
85
|
+
|
|
86
|
+
# run tests
|
|
63
87
|
- name: "ALKiln: Run tests"
|
|
64
88
|
if: ${{ success() }}
|
|
65
|
-
run: alkiln-run ${{ github.event.inputs.tags && format('{0}', github.event.inputs.tags) }}
|
|
66
|
-
shell: bash
|
|
67
|
-
- run: echo -e "\n\n====ALKiln could not create a project on your server's testing account or pull your package into it. Check the messages above this line.\n\n"
|
|
68
|
-
if: ${{ failure() }}
|
|
89
|
+
run: alkiln-run ${{ inputs.ALKILN_TAG_EXPRESSION || github.event.inputs.tags && format('{0}', github.event.inputs.tags) }}
|
|
69
90
|
shell: bash
|
|
70
|
-
|
|
71
|
-
|
|
91
|
+
|
|
92
|
+
# on playground, delete project
|
|
93
|
+
- name: "ALKiln: Try to delete the project from the playground of the docassemble test account."
|
|
94
|
+
if: ${{ inputs.INSTALL_METHOD == 'playground' }}
|
|
72
95
|
run: alkiln-takedown
|
|
73
96
|
shell: bash
|
|
74
97
|
|
|
@@ -81,7 +104,7 @@ runs:
|
|
|
81
104
|
path: ./alkiln-*
|
|
82
105
|
|
|
83
106
|
# ##################################
|
|
84
|
-
# # A developer's workflow should look similar to the below
|
|
107
|
+
# # A developer's workflow should look similar to the below.
|
|
85
108
|
# # In place of `uses: suffolkLITLab/ALKiln@v5`, they
|
|
86
109
|
# # might use another version.
|
|
87
110
|
#
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
name: "ALKiln/github_server: Isolated docassemble tests"
|
|
2
|
+
description: "Download and start up a temporary docassemble server on GitHub's servers, in an isolated environment. Avoids docassemble reload errors and other external factors."
|
|
3
|
+
|
|
4
|
+
# If we want to control the version of the docassemble image, we'd have
|
|
5
|
+
# to make our own image:
|
|
6
|
+
# You can build your own image by doing git clone jhpyle/docassemble and then
|
|
7
|
+
# using git checkout to select a particular version, and then using docker build
|
|
8
|
+
# to build an image. https://docassemble.org/docs/docker.html#downgrading
|
|
9
|
+
# If we just want to use an older version of da (as long as it works with
|
|
10
|
+
# the latest image):
|
|
11
|
+
# If you have an existing container you can use dainstall from the command
|
|
12
|
+
# line to install docassemble.webapp==1.4.68
|
|
13
|
+
|
|
14
|
+
inputs:
|
|
15
|
+
CONFIG_CONTENTS:
|
|
16
|
+
description: "The contents of the config file of the docassemble server"
|
|
17
|
+
required: false
|
|
18
|
+
MAX_SECONDS_FOR_DOCKER:
|
|
19
|
+
description: "Maximum amount of seconds to give the docassemble docker container to serve the site."
|
|
20
|
+
required: false
|
|
21
|
+
default: 600 # 10 min
|
|
22
|
+
|
|
23
|
+
outputs:
|
|
24
|
+
DOCASSEMBLE_DEVELOPER_API_KEY:
|
|
25
|
+
description: "Use this inside `with:` for the ALKiln step. Temporary admin api key. It will be destroyed after the tests are done."
|
|
26
|
+
value: ${{ steps.api_key_output_step.outputs.DOCASSEMBLE_DEVELOPER_API_KEY }}
|
|
27
|
+
SERVER_URL:
|
|
28
|
+
description: "Use this inside `with:` for the ALKiln step. URL of the temporary docassemble server."
|
|
29
|
+
value: "http://localhost"
|
|
30
|
+
DA_ADMIN_EMAIL:
|
|
31
|
+
value: ${{ steps.api_key_output_step.outputs.DA_ADMIN_EMAIL }}
|
|
32
|
+
DA_ADMIN_PASSWORD:
|
|
33
|
+
value: ${{ steps.api_key_output_step.outputs.DA_ADMIN_PASSWORD }}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
runs:
|
|
37
|
+
using: "composite"
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v3
|
|
40
|
+
|
|
41
|
+
- name: "ALKiln github_server: Set environment variables"
|
|
42
|
+
run: |
|
|
43
|
+
echo "DA_ADMIN_API_KEY=abcd1234abcd1234abcd5678abdc5678" >> $GITHUB_ENV
|
|
44
|
+
echo "MAX_SECONDS_FOR_DOCKER=${{ inputs.MAX_SECONDS_FOR_DOCKER }}" >> $GITHUB_ENV
|
|
45
|
+
echo "DA_ADMIN_EMAIL=admin@example.com" >> $GITHUB_ENV
|
|
46
|
+
# Login will fail if this is "password"
|
|
47
|
+
echo "DA_ADMIN_PASSWORD=@123abcdefg" >> $GITHUB_ENV
|
|
48
|
+
shell: bash
|
|
49
|
+
- id: api_key_output_step
|
|
50
|
+
run: |
|
|
51
|
+
echo "DOCASSEMBLE_DEVELOPER_API_KEY=$DA_ADMIN_API_KEY" >> "$GITHUB_OUTPUT"
|
|
52
|
+
echo "DA_ADMIN_EMAIL=$DA_ADMIN_EMAIL" >> "$GITHUB_OUTPUT"
|
|
53
|
+
echo "DA_ADMIN_PASSWORD=$DA_ADMIN_PASSWORD" >> "$GITHUB_OUTPUT"
|
|
54
|
+
shell: bash
|
|
55
|
+
|
|
56
|
+
- name: "ALKiln github_server: Download and start docker"
|
|
57
|
+
run: |
|
|
58
|
+
mkdir /tmp/config
|
|
59
|
+
if [ -n "${{ inputs.CONFIG_CONTENTS }}" ]
|
|
60
|
+
then
|
|
61
|
+
echo "ALKiln github_server: The developer did provided a custom docassemble config file as an input into this action."
|
|
62
|
+
echo "${{ inputs.CONFIG_CONTENTS }}" > /tmp/config/myconfig.yml
|
|
63
|
+
echo "CONFIG_ARGS=--env DA_CONFIG=/tmp/config/myconfig.yml --volume /tmp/config:/tmp/config " >> $GITHUB_ENV
|
|
64
|
+
else
|
|
65
|
+
echo "ALKiln github_server: The developer did not provide a custom docassemble config file as an input into this action. Docassemble will use its default config."
|
|
66
|
+
echo "CONFIG_ARGS=" >> $GITHUB_ENV
|
|
67
|
+
fi
|
|
68
|
+
shell: bash
|
|
69
|
+
- run: |
|
|
70
|
+
docker pull jhpyle/docassemble
|
|
71
|
+
docker run --name docassemble_container \
|
|
72
|
+
--env DA_ADMIN_EMAIL="${{ env.DA_ADMIN_EMAIL }}" \
|
|
73
|
+
--env DA_ADMIN_PASSWORD="${{ env.DA_ADMIN_PASSWORD }}" \
|
|
74
|
+
--env DA_ADMIN_API_KEY="${{ env.DA_ADMIN_API_KEY }}" \
|
|
75
|
+
${{ env.CONFIG_ARGS }} \
|
|
76
|
+
--cap-add SYS_PTRACE \
|
|
77
|
+
--memory="4gb" -d -p 80:80 jhpyle/docassemble
|
|
78
|
+
shell: bash
|
|
79
|
+
- name: "ALKiln github_server: Wait for server to start"
|
|
80
|
+
run: |
|
|
81
|
+
# ALKiln github_server: Wait for server to start
|
|
82
|
+
|
|
83
|
+
# Reset the SECONDS variable
|
|
84
|
+
SECONDS=0
|
|
85
|
+
# Wait 1 minute before pinging the server constantly
|
|
86
|
+
sleep 60
|
|
87
|
+
|
|
88
|
+
response="start"
|
|
89
|
+
|
|
90
|
+
while [[ $response != *"200"* ]]; do
|
|
91
|
+
echo "ALKiln github_server: Time elapsed: $SECONDS seconds"
|
|
92
|
+
|
|
93
|
+
# Check if max seconds till loading has passed
|
|
94
|
+
if [[ $SECONDS -ge $MAX_SECONDS_FOR_DOCKER ]]; then
|
|
95
|
+
echo "ALKiln github_server Error: Timed out waiting for docker container to serve the site. If you want to give your docker container more timem to install, set the MAX_SECONDS_FOR_DOCKER input for this action."
|
|
96
|
+
exit 1
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# Set the variable to a new string value in each iteration
|
|
100
|
+
response=$(curl -o /dev/null -s -w "%{http_code}\n" http://localhost:80/health_check?ready=1)
|
|
101
|
+
echo "ALKiln github_server: response is $response"
|
|
102
|
+
|
|
103
|
+
# Check if the string includes the desired text
|
|
104
|
+
if [[ $response == *"200"* ]]; then
|
|
105
|
+
echo "ALKiln github_server: Success! The docker container is ready!"
|
|
106
|
+
else
|
|
107
|
+
echo "ALKiln github_server: The docker container isn't ready yet. Will check again in 30 seconds."
|
|
108
|
+
sleep 30
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
done
|
|
112
|
+
shell: bash
|
|
113
|
+
|
|
114
|
+
# Don't rely on the environment's version of python
|
|
115
|
+
- uses: actions/setup-python@v4
|
|
116
|
+
with:
|
|
117
|
+
python-version: '3.10'
|
|
118
|
+
- run: pip install docassemblecli
|
|
119
|
+
shell: bash
|
|
120
|
+
# Install the current directory onto the docassemble server
|
|
121
|
+
- run: dainstall . --apiurl http://localhost --apikey $DA_ADMIN_API_KEY
|
|
122
|
+
shell: bash
|
|
123
|
+
|
|
124
|
+
# Upload artifacts that subscribers can download on the Actions summary page
|
|
125
|
+
- name: "ALKiln github_server: Get path names with date and time"
|
|
126
|
+
if: ${{ always() }}
|
|
127
|
+
run: |
|
|
128
|
+
echo "GITHUB_SERVER_LOG_FILE_NAME=/tmp/alkiln_docker_logs-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC.txt" >> $GITHUB_ENV
|
|
129
|
+
echo "GITHUB_SERVER_ARTIFACT_NAME=alkiln_github_server-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
|
|
130
|
+
shell: bash
|
|
131
|
+
- name: "ALKiln github_server: Docker logs"
|
|
132
|
+
if: ${{ always() }}
|
|
133
|
+
run: |
|
|
134
|
+
echo "$(docker logs docassemble_container)" > "${{ env.GITHUB_SERVER_LOG_FILE_NAME }}"
|
|
135
|
+
shell: bash
|
|
136
|
+
- name: "ALKiln github_server: Upload artifacts folder"
|
|
137
|
+
if: ${{ always() }}
|
|
138
|
+
uses: actions/upload-artifact@v3
|
|
139
|
+
with:
|
|
140
|
+
name: ${{ env.GITHUB_SERVER_ARTIFACT_NAME }}
|
|
141
|
+
path: ${{ env.GITHUB_SERVER_LOG_FILE_NAME }}
|
|
@@ -79,13 +79,21 @@ da.pull = async function ( timeout ) {
|
|
|
79
79
|
}; // Ends da.pull()
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
da.has_playground_task_finished = async function ( task_id, timeout ) {
|
|
83
|
+
return await da.has_task_finished( "/api/restart_status", task_id, timeout);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
da.has_package_task_finished = async function ( task_id, timeout ) {
|
|
87
|
+
return await da.has_task_finished( "/api/package_update_status", task_id, timeout);
|
|
88
|
+
}
|
|
89
|
+
|
|
82
90
|
// node -e 'require("./lib/docassemble/docassemble_api_REST.js").has_task_finished()'
|
|
83
|
-
da.has_task_finished = async function ( task_id, timeout ) {
|
|
91
|
+
da.has_task_finished = async function ( api_endpoint, task_id, timeout ) {
|
|
84
92
|
/* Check task status based on `task_id`. */
|
|
85
93
|
let options = {
|
|
86
94
|
method: 'GET',
|
|
87
95
|
headers: {'X-API-Key': session_vars.get_dev_api_key()},
|
|
88
|
-
url: `${ session_vars.get_da_server_url() }
|
|
96
|
+
url: `${ session_vars.get_da_server_url() }${ api_endpoint }`,
|
|
89
97
|
params: {
|
|
90
98
|
task_id: task_id,
|
|
91
99
|
},
|
|
@@ -329,9 +329,8 @@ da_i.pull = async function ( pull_options ) {
|
|
|
329
329
|
}
|
|
330
330
|
}; // Ends da_i.pull()
|
|
331
331
|
|
|
332
|
-
|
|
333
332
|
// node -e 'require("./lib/docassemble/docassemble_api_interface.js").has_task_finished()'
|
|
334
|
-
da_i.has_task_finished = async function ( task_id, options ) {
|
|
333
|
+
da_i.has_task_finished = async function ( api_endpoint, task_id, options ) {
|
|
335
334
|
/** Check task status if it exists. If not, return true as task did
|
|
336
335
|
* not require a server restart. See da_i.pull().
|
|
337
336
|
* See https://docassemble.org/docs/api.html#restart_status. */
|
|
@@ -342,7 +341,7 @@ da_i.has_task_finished = async function ( task_id, options ) {
|
|
|
342
341
|
try {
|
|
343
342
|
|
|
344
343
|
// If server did need to restart, check if it's done.
|
|
345
|
-
let response = await _da_REST.has_task_finished( task_id, timeout );
|
|
344
|
+
let response = await _da_REST.has_task_finished( api_endpoint, task_id, timeout );
|
|
346
345
|
log.debug({ pre: `Task status: ${ response.status }. Docassemble status text: ${ response.data.status }. Task id: ${ task_id }` });
|
|
347
346
|
|
|
348
347
|
if ( response.data.status === 'completed' ) {
|
|
@@ -353,16 +352,15 @@ da_i.has_task_finished = async function ( task_id, options ) {
|
|
|
353
352
|
return false;
|
|
354
353
|
|
|
355
354
|
} else if ( response.data.status === 'unknown' ) {
|
|
356
|
-
// Server is working, but status 'unknown'?
|
|
357
|
-
// get
|
|
358
|
-
// no default behavior. What to return? Throw?
|
|
355
|
+
// Server is working, but status 'unknown'? Bad design, but this
|
|
356
|
+
// does get returned when install packages, so return true
|
|
359
357
|
log.info({
|
|
360
358
|
pre: `\`task_id\` "${ task_id }" has expired. If it's been `
|
|
361
359
|
+ `less than 1 hour since the task started, the task is `
|
|
362
360
|
+ `complete. See https://docassemble.org/docs/api.html#restart_status.`,
|
|
363
|
-
data: response,
|
|
361
|
+
data: response.data,
|
|
364
362
|
});
|
|
365
|
-
return
|
|
363
|
+
return true;
|
|
366
364
|
} // ends status type
|
|
367
365
|
|
|
368
366
|
} catch ( error ) {
|
|
@@ -378,8 +376,15 @@ da_i.has_task_finished = async function ( task_id, options ) {
|
|
|
378
376
|
|
|
379
377
|
}; // Ends da_i.has_task_finished()
|
|
380
378
|
|
|
379
|
+
da_i.wait_for_playground_to_restart = async ( task_id, options ) => {
|
|
380
|
+
return await da_i.wait_for_server_to_restart( "/api/restart_status", task_id, options );
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
da_i.wait_for_package_to_restart = async ( task_id, options ) => {
|
|
384
|
+
return await da_i.wait_for_server_to_restart( "/api/package_update_status", task_id, options );
|
|
385
|
+
};
|
|
381
386
|
|
|
382
|
-
da_i.wait_for_server_to_restart = async ( task_id, options ) => {
|
|
387
|
+
da_i.wait_for_server_to_restart = async ( api_endpoint, task_id, options ) => {
|
|
383
388
|
/** Wait for the server to finish restarting in case a module needs to load.
|
|
384
389
|
* This is a polling function because things may be returned
|
|
385
390
|
* that aren't equivalent to the server being done with a task. */
|
|
@@ -410,7 +415,7 @@ da_i.wait_for_server_to_restart = async ( task_id, options ) => {
|
|
|
410
415
|
while ( !done_restarting && num_tries <= max_loops ) {
|
|
411
416
|
num_tries++;
|
|
412
417
|
// Wait only a short time for the task to finish, not the full default timeout
|
|
413
|
-
done_restarting = await da_i.has_task_finished( task_id, { timeout: wait_for_response } );
|
|
418
|
+
done_restarting = await da_i.has_task_finished( api_endpoint, task_id, { timeout: wait_for_response } );
|
|
414
419
|
if ( !done_restarting ) {
|
|
415
420
|
if ( num_tries < max_loops ) {
|
|
416
421
|
// Show a slightly different message after a number of tries to reassure
|
|
@@ -10,10 +10,20 @@ let get_base_interview_url = async function () {
|
|
|
10
10
|
* When finishing a test, we go to the sign out page (which is supposed to help even
|
|
11
11
|
* when the user is not logged in.) We can't use `reset=2` because it caused an
|
|
12
12
|
* 'Unable to locate interview session' error. */
|
|
13
|
+
|
|
13
14
|
let server_url = session_vars.get_da_server_url();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
|
|
16
|
+
if (session_vars.get_install_method() === `server`) {
|
|
17
|
+
|
|
18
|
+
return `${ server_url }/interview?new_session=1&i=docassemble.${session_vars.get_repo_folder_name()}%3Adata/questions/`;
|
|
19
|
+
|
|
20
|
+
} else {
|
|
21
|
+
|
|
22
|
+
let dev_id = await docassemble_api_interface.get_dev_id();
|
|
23
|
+
let project_name = session_vars.get_project_name();
|
|
24
|
+
return `${ server_url }/interview?new_session=1&i=docassemble.playground${ dev_id }${ project_name }%3A`;
|
|
25
|
+
|
|
26
|
+
}
|
|
17
27
|
};
|
|
18
28
|
|
|
19
29
|
module.exports = get_base_interview_url;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const session_vars = require('../utils/session_vars');
|
|
4
|
+
const log = require('../utils/log');
|
|
5
|
+
const fg = require('fast-glob');
|
|
6
|
+
|
|
7
|
+
const server_install = async () => {
|
|
8
|
+
session_vars.save_install_method(`server`);
|
|
9
|
+
|
|
10
|
+
let current_dir = process.cwd();
|
|
11
|
+
let path = `${ current_dir }/docassemble/*`;
|
|
12
|
+
let dirs = fg.sync(
|
|
13
|
+
[ path ],
|
|
14
|
+
{
|
|
15
|
+
suppressErrors: true,
|
|
16
|
+
onlyDirectories: true
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
let folders = dirs.map(function (dir) { return dir.split('/').pop(); })
|
|
21
|
+
|
|
22
|
+
let chosen_folder = folders[0];
|
|
23
|
+
if ( folders.length === 0 ) {
|
|
24
|
+
let msg = `There are 0 folders at ${path}. Tests won't run.`;
|
|
25
|
+
log.error({ type: `setup`, data: msg })
|
|
26
|
+
throw new ReferenceError( msg );
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if ( folders.length > 1 ) {
|
|
30
|
+
log.warn({
|
|
31
|
+
type: `setup`,
|
|
32
|
+
data: `There are ${folders.length} folders at ${path}: "${folders.join('", "')}". ALKiln chose to use the folder "${chosen_folder}".`
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
session_vars.save_repo_folder_name( chosen_folder );
|
|
37
|
+
}; // Ends server_install();
|
|
38
|
+
|
|
39
|
+
server_install();
|
package/lib/docassemble/setup.js
CHANGED
|
@@ -39,7 +39,7 @@ const setup = async () => {
|
|
|
39
39
|
let task_id = await da_i.pull();
|
|
40
40
|
// Task id will be null if server did not need to restart
|
|
41
41
|
if ( task_id ) {
|
|
42
|
-
await da_i.
|
|
42
|
+
await da_i.wait_for_playground_to_restart( task_id );
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
// Finish
|
package/lib/scope.js
CHANGED
|
@@ -1246,7 +1246,7 @@ module.exports = {
|
|
|
1246
1246
|
+ `column, but it is empty. The test might get unexpected results. See `
|
|
1247
1247
|
+ `https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/automated_integrated_testing/#trigger.`
|
|
1248
1248
|
+ `\nThe row's data:\n${ row_as_story_table }`
|
|
1249
|
-
+ `\nThis field's data:\n${ JSON.stringify( field )}`;
|
|
1249
|
+
+ `\nThis field's data:\n${ JSON.stringify( field.guesses )}`;
|
|
1250
1250
|
reports.addToReport(scope, { type: `warning`, value: row_trigger_warning });
|
|
1251
1251
|
rows_without_a_trigger_name.push( row_that_matches_this_field );
|
|
1252
1252
|
} else {
|
|
@@ -1401,8 +1401,7 @@ module.exports = {
|
|
|
1401
1401
|
let elem = document.querySelector( selector );
|
|
1402
1402
|
// If the element has a sibling that's a label, we need to
|
|
1403
1403
|
// interact with that label instead.
|
|
1404
|
-
|
|
1405
|
-
if ( elem.nextSibling && elem.nextSibling.tag === `label` ) {
|
|
1404
|
+
if ( elem && elem.nextSibling && elem.nextSibling.tag === `label` ) {
|
|
1406
1405
|
return elem.nextSibling;
|
|
1407
1406
|
} else { return elem; }
|
|
1408
1407
|
// Pass in the selector as an argument
|
|
@@ -1422,14 +1421,15 @@ module.exports = {
|
|
|
1422
1421
|
// future we should look into what happens with a `fieldset` for
|
|
1423
1422
|
// `choices:`, etc.
|
|
1424
1423
|
let custom_datatype = null, matches = null;
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1424
|
+
if (elem) {
|
|
1425
|
+
let group = elem.closest( `.da-form-group` );
|
|
1426
|
+
if ( group && group.className ) {
|
|
1427
|
+
matches = ` ${ group.className } `.match(/da-field-container-datatype-([^ ]+) /);
|
|
1428
|
+
}
|
|
1429
|
+
if ( matches ) {
|
|
1430
|
+
custom_datatype = matches[1];
|
|
1431
|
+
}
|
|
1431
1432
|
}
|
|
1432
|
-
|
|
1433
1433
|
return custom_datatype;
|
|
1434
1434
|
});
|
|
1435
1435
|
|
|
@@ -1585,7 +1585,13 @@ module.exports = {
|
|
|
1585
1585
|
/* Set value of some `input` element to the given value. */
|
|
1586
1586
|
let row_was_used = true;
|
|
1587
1587
|
|
|
1588
|
-
let type = await handle.evaluate( elem => {
|
|
1588
|
+
let type = await handle.evaluate( elem => {
|
|
1589
|
+
if (elem) {
|
|
1590
|
+
return elem.getAttribute('type');
|
|
1591
|
+
} else {
|
|
1592
|
+
return 'text';
|
|
1593
|
+
}
|
|
1594
|
+
});
|
|
1589
1595
|
if ( type === `radio` || type === `checkbox` ) {
|
|
1590
1596
|
|
|
1591
1597
|
let [label] = await handle.$x(`following-sibling::label`);
|
|
@@ -1596,8 +1602,11 @@ module.exports = {
|
|
|
1596
1602
|
let name = await label.evaluate( elem => { return elem.getAttribute('for'); });
|
|
1597
1603
|
}
|
|
1598
1604
|
|
|
1599
|
-
if ( type === `radio` ) {
|
|
1600
|
-
|
|
1605
|
+
if ( type === `radio` ) {
|
|
1606
|
+
await label.evaluate( elem => { return elem.click(); });
|
|
1607
|
+
} else {
|
|
1608
|
+
await scope.setCheckbox( scope, { label, answer });
|
|
1609
|
+
}
|
|
1601
1610
|
|
|
1602
1611
|
await scope.afterStep(scope, { waitForShowIf: true });
|
|
1603
1612
|
|
|
@@ -2231,9 +2240,14 @@ module.exports = {
|
|
|
2231
2240
|
} // ends act depending values
|
|
2232
2241
|
}, // Ends scope.getThereIsAnotherValue()
|
|
2233
2242
|
|
|
2243
|
+
is_on_server_still: async function ( scope ) {
|
|
2244
|
+
let server_url = session_vars.get_da_server_url();
|
|
2245
|
+
return await scope.page.url().startsWith(server_url);
|
|
2246
|
+
},
|
|
2247
|
+
|
|
2234
2248
|
// throw_if_no_interview_content()?
|
|
2235
2249
|
has_interview_content: async function ( scope ) {
|
|
2236
|
-
/** Return false if
|
|
2250
|
+
/** Return false if there's no element indicating a da interview question,
|
|
2237
2251
|
* like a signature page, other fields, or interview text. Assumes that page has already
|
|
2238
2252
|
* finished navigating. */
|
|
2239
2253
|
let elem_da_question = await scope.page.$( `#daMainQuestion` );
|
|
@@ -2437,6 +2451,7 @@ module.exports = {
|
|
|
2437
2451
|
/** Sets a non-story table variable to a "secret" value (i.e. an env var) */
|
|
2438
2452
|
// Prevent pictures of a screen with a secret.
|
|
2439
2453
|
scope.disable_error_screenshot = true;
|
|
2454
|
+
|
|
2440
2455
|
let var_data = await scope.normalizeTable( scope, {
|
|
2441
2456
|
var_data: [{
|
|
2442
2457
|
var: var_name,
|
|
@@ -2635,7 +2650,7 @@ module.exports = {
|
|
|
2635
2650
|
*/
|
|
2636
2651
|
// Don't take a picture of a failed login in case one of the inputs is correct
|
|
2637
2652
|
scope.disable_error_screenshot = true;
|
|
2638
|
-
|
|
2653
|
+
|
|
2639
2654
|
// If there is no browser open, start a new one
|
|
2640
2655
|
if (!scope.browser) {
|
|
2641
2656
|
scope.browser = await scope.driver.launch({ headless: !session_vars.DEBUG });
|
|
@@ -2737,7 +2752,30 @@ module.exports = {
|
|
|
2737
2752
|
},
|
|
2738
2753
|
buttons: async function (scope, { fields }) {
|
|
2739
2754
|
// Get a random button
|
|
2740
|
-
let
|
|
2755
|
+
let back_btn = null;
|
|
2756
|
+
fields = fields.filter((ff) => {
|
|
2757
|
+
if (ff.selector.includes("daquestionbackbutton")) {
|
|
2758
|
+
back_btn = ff;
|
|
2759
|
+
return false;
|
|
2760
|
+
}
|
|
2761
|
+
return true;
|
|
2762
|
+
});
|
|
2763
|
+
let field = null;
|
|
2764
|
+
if (back_btn != null && Math.random() > 0.9) {
|
|
2765
|
+
// 10% chance of clicking the back button. Back buttons don't undo
|
|
2766
|
+
// external network calls or saving things to Redis, so we make sure
|
|
2767
|
+
// programs can handle (or least don't crash) when users press back
|
|
2768
|
+
field = back_btn;
|
|
2769
|
+
} else {
|
|
2770
|
+
field = faker.helpers.arrayElement( fields );
|
|
2771
|
+
}
|
|
2772
|
+
if (field == null) {
|
|
2773
|
+
// Just skip it? Shouldn't happen but has before. Dig in more
|
|
2774
|
+
if (session_vars.get_debug()) {
|
|
2775
|
+
console.log(`A random button field choice was null. These were the fields to choose from:\n${ JSON.stringify(fields, null, 2) }`);
|
|
2776
|
+
}
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2741
2779
|
let handle = await scope.get_handle_from_field( scope, { field: field });
|
|
2742
2780
|
// Send it to be tapped
|
|
2743
2781
|
await scope.funnel_the_answer( scope, { handle, field, answer: `doesn't matter` });
|
|
@@ -2806,7 +2844,6 @@ module.exports = {
|
|
|
2806
2844
|
let custom_datatype = await scope.get_custom_datatype( scope, { handle });
|
|
2807
2845
|
let is_custom_datatype = scope.get_random_input_for[ custom_datatype ] !== undefined;
|
|
2808
2846
|
if ( is_custom_datatype ) {
|
|
2809
|
-
|
|
2810
2847
|
// And the custom datatype has a hidden field (which will be the original field)
|
|
2811
2848
|
let hidden_field = await scope.get_custom_datatype_hidden_field( scope, { handle });
|
|
2812
2849
|
if ( hidden_field !== null ) {
|
|
@@ -2846,7 +2883,7 @@ module.exports = {
|
|
|
2846
2883
|
} // ends if field type is one we cover
|
|
2847
2884
|
} // ends if field type exists
|
|
2848
2885
|
|
|
2849
|
-
} // ends
|
|
2886
|
+
} // ends else after is custom datatype
|
|
2850
2887
|
|
|
2851
2888
|
}, // ends scope.set_random_input_for.input
|
|
2852
2889
|
}, // ends scope.set_random_input_for
|
package/lib/steps.js
CHANGED
|
@@ -827,6 +827,11 @@ When(/I answer randomly for at most ([0-9]+) (?:page(?:s)?|screen(?:s)?)/, { tim
|
|
|
827
827
|
if ( has_thrown ) { return; }
|
|
828
828
|
else { has_thrown = true; }
|
|
829
829
|
|
|
830
|
+
if (!( await scope.is_on_server_still(scope))) {
|
|
831
|
+
await scope.page.goBack();
|
|
832
|
+
resolve();
|
|
833
|
+
}
|
|
834
|
+
|
|
830
835
|
let has_content = await scope.has_interview_content( scope );
|
|
831
836
|
|
|
832
837
|
if ( !has_content ) {
|
|
@@ -872,6 +877,10 @@ When(/I answer randomly for at most ([0-9]+) (?:page(?:s)?|screen(?:s)?)/, { tim
|
|
|
872
877
|
await scope.continue( scope );
|
|
873
878
|
} // ends if continue exists
|
|
874
879
|
} // ends if buttons_exist
|
|
880
|
+
if (!( await scope.is_on_server_still(scope))) {
|
|
881
|
+
await scope.page.goBack();
|
|
882
|
+
resolve();
|
|
883
|
+
}
|
|
875
884
|
|
|
876
885
|
let has_content = await scope.has_interview_content( scope );
|
|
877
886
|
if ( !has_content ) {
|
|
@@ -891,7 +900,7 @@ When(/I answer randomly for at most ([0-9]+) (?:page(?:s)?|screen(?:s)?)/, { tim
|
|
|
891
900
|
|
|
892
901
|
if ( buttons_exist ) {
|
|
893
902
|
process.stdout.write(`\x1b[36m${ 'v' }\x1b[0m`); // pressed button
|
|
894
|
-
}
|
|
903
|
+
}
|
|
895
904
|
|
|
896
905
|
resolve();
|
|
897
906
|
|
|
@@ -901,6 +910,11 @@ When(/I answer randomly for at most ([0-9]+) (?:page(?:s)?|screen(?:s)?)/, { tim
|
|
|
901
910
|
if ( has_thrown ) { return; }
|
|
902
911
|
else { has_thrown = true; }
|
|
903
912
|
|
|
913
|
+
if (!( await scope.is_on_server_still(scope))) {
|
|
914
|
+
await scope.page.goBack();
|
|
915
|
+
resolve();
|
|
916
|
+
}
|
|
917
|
+
|
|
904
918
|
// Throw a specific error if there's no interview content
|
|
905
919
|
let has_content = await scope.has_interview_content( scope );
|
|
906
920
|
if ( !has_content ) {
|
|
@@ -167,14 +167,54 @@ session_vars.delete_project_name = function () {
|
|
|
167
167
|
}
|
|
168
168
|
};
|
|
169
169
|
|
|
170
|
-
// The
|
|
170
|
+
// The filepath storing the artifacts path contains the name of the current artifacts folder.
|
|
171
171
|
// The directory name it contains will be created or changed with each run of all the tests.
|
|
172
172
|
// const file_storing_artifact_path = `_alkiln_test_artifacts_dir_name.json`;
|
|
173
173
|
const artifacts_path_key = `artifacts_path`;
|
|
174
174
|
session_vars.save_artifacts_path_name = function ( path_name ) {
|
|
175
175
|
/* Save a key with the name of the current artifacts folder in case it doesn't exist. */
|
|
176
|
+
return session_vars.save_runtime_config_var({ key: artifacts_path_key, value: path_name });
|
|
177
|
+
}; // Ends save_artifacts_path_name()
|
|
178
|
+
session_vars.get_artifacts_path_name = function () {
|
|
179
|
+
/* Get the name of the current artifacts path. */
|
|
180
|
+
return session_vars.get_runtime_config_var( artifacts_path_key );
|
|
181
|
+
}; // Ends get_artifacts_path_name()
|
|
182
|
+
|
|
176
183
|
|
|
177
|
-
|
|
184
|
+
const install_method_key = `da_install_method`;
|
|
185
|
+
session_vars.save_install_method = function ( install_method ) {
|
|
186
|
+
/* Save a key with the name of the current artifacts folder in case it doesn't exist. */
|
|
187
|
+
return session_vars.save_runtime_config_var({ key: install_method_key, value: install_method });
|
|
188
|
+
}; // Ends save_install_method()
|
|
189
|
+
session_vars.get_install_method = function () {
|
|
190
|
+
/* Get the name of the current install method. */
|
|
191
|
+
return session_vars.get_runtime_config_var( install_method_key );
|
|
192
|
+
}; // Ends get_install_method()
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
const repo_folder_key = `da_repo_folder_name`;
|
|
196
|
+
session_vars.save_repo_folder_name = function (repo_folder_name) {
|
|
197
|
+
/** Save a key with the name of the main package folder in the repository. */
|
|
198
|
+
return session_vars.save_runtime_config_var({ key: repo_folder_key, value: repo_folder_name });
|
|
199
|
+
}; // Ends session_vars.save_repo_folder_name()
|
|
200
|
+
session_vars.get_repo_folder_name = function () {
|
|
201
|
+
/** Get the name of the main folder in the repository. */
|
|
202
|
+
return session_vars.get_runtime_config_var( repo_folder_key );
|
|
203
|
+
}; // Ends session_vars.get_repo_folder_name()
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
session_vars.save_runtime_config_var = function ({ key, value }) {
|
|
207
|
+
/** Write to the runtime config file by adding a key/value pair to
|
|
208
|
+
* the json object there. The functions calling this are keeping
|
|
209
|
+
* track of the key, so they're useful to keep around.
|
|
210
|
+
*
|
|
211
|
+
* @param key {str} Key to use to store `value` in runtime config file
|
|
212
|
+
* @param value {any} Value to store in runtime config file
|
|
213
|
+
*
|
|
214
|
+
* @returns file {binary?} Runtime config file
|
|
215
|
+
*/
|
|
216
|
+
|
|
217
|
+
// Ensure runtime config file exists
|
|
178
218
|
if ( !fs.existsSync( runtime_config_path ) ) {
|
|
179
219
|
// If the file doesn't exist, make one because next we need to read it
|
|
180
220
|
fs.writeFileSync( runtime_config_path, JSON.stringify( {}, null, 2 ) );
|
|
@@ -182,27 +222,35 @@ session_vars.save_artifacts_path_name = function ( path_name ) {
|
|
|
182
222
|
|
|
183
223
|
// Get the json, changing it, and re-write the file from scratch
|
|
184
224
|
let json = JSON.parse( fs.readFileSync( runtime_config_path ) );
|
|
185
|
-
json[
|
|
225
|
+
json[ key ] = value;
|
|
186
226
|
let file = fs.writeFileSync( runtime_config_path, JSON.stringify( json, null, 2 ) );
|
|
187
227
|
|
|
188
228
|
if ( session_vars.get_debug() ) {
|
|
189
|
-
console.log( `ALKiln debug: Stored
|
|
229
|
+
console.log( `ALKiln debug runtime config var: Stored "${key}" locally as "${value}".` );
|
|
190
230
|
}
|
|
191
231
|
return file;
|
|
192
|
-
}; // Ends
|
|
232
|
+
}; // Ends session_vars.save_runtime_config_var()
|
|
193
233
|
|
|
194
|
-
session_vars.
|
|
195
|
-
|
|
234
|
+
session_vars.get_runtime_config_var = function ( key ) {
|
|
235
|
+
/** Get the value of the given key from the runtime config file.
|
|
236
|
+
*
|
|
237
|
+
* @param key {str} Key in runtime config file that contains the desired value
|
|
238
|
+
* @returns value || null {any} Value of key in runtime config file. If it
|
|
239
|
+
* doesn't exist, returns null.
|
|
240
|
+
*/
|
|
196
241
|
try {
|
|
197
242
|
let json = JSON.parse( fs.readFileSync( runtime_config_path ));
|
|
198
|
-
let
|
|
243
|
+
let value = json[ key ];
|
|
244
|
+
if ( session_vars.get_debug() ) {
|
|
245
|
+
console.log( `ALKiln debug runtime config var: "${key}"" is "${value}".` );
|
|
246
|
+
}
|
|
199
247
|
|
|
200
|
-
|
|
201
|
-
return path_name;
|
|
248
|
+
return value;
|
|
202
249
|
} catch ( error ) {
|
|
203
250
|
return null;
|
|
204
251
|
}
|
|
205
|
-
}; // Ends
|
|
252
|
+
}; // Ends session_vars.get_runtime_config_var()
|
|
253
|
+
|
|
206
254
|
|
|
207
255
|
session_vars.set_sources_paths = function ( paths ) {
|
|
208
256
|
/** Returns whether at least one of the given path exists. Store
|
|
@@ -235,7 +283,7 @@ session_vars.set_sources_paths = function ( paths ) {
|
|
|
235
283
|
// Warn about missing paths
|
|
236
284
|
if ( missing_paths.length > 0 ) {
|
|
237
285
|
console.warn(
|
|
238
|
-
`ALKiln WARNING: ALKiln can't find folders at "${ paths.join(", ") }".`
|
|
286
|
+
`ALKiln WARNING: ALKiln can't find folders at "${ paths.join('", "') }".`
|
|
239
287
|
);
|
|
240
288
|
}
|
|
241
289
|
|
|
@@ -245,10 +293,14 @@ session_vars.set_sources_paths = function ( paths ) {
|
|
|
245
293
|
return false;
|
|
246
294
|
}
|
|
247
295
|
|
|
296
|
+
console.info(
|
|
297
|
+
`ALKiln info: Did find "sources" folder(s) at "${ existing_paths.join('", "') }".`
|
|
298
|
+
)
|
|
299
|
+
|
|
248
300
|
// Otherwise, store valid paths
|
|
249
301
|
session_vars._sources_paths = existing_paths;
|
|
250
302
|
return true;
|
|
251
|
-
};
|
|
303
|
+
}; // End session_vars.set_sources_paths()
|
|
252
304
|
|
|
253
305
|
session_vars.get_sources_paths = function () {
|
|
254
306
|
/** Get the "sources" folder path. Should never be undefined during
|
|
@@ -259,6 +311,7 @@ session_vars.get_sources_paths = function () {
|
|
|
259
311
|
return session_vars._sources_paths;
|
|
260
312
|
};
|
|
261
313
|
|
|
314
|
+
|
|
262
315
|
session_vars.validateEnvironment = function() {
|
|
263
316
|
/** Throw a useful error for the developer if any of the env vars
|
|
264
317
|
* required by absolutely all tests are missing. Gather all
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@suffolklitlab/alkiln",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"local": "npm run setup && npm run cucumber; npm run takedown",
|
|
10
10
|
"setup": "./lib/docassemble/setup.js",
|
|
11
11
|
"takedown": "./lib/docassemble/takedown.js",
|
|
12
|
+
"server_install": "./lib/docassemble/server_install.js",
|
|
12
13
|
"unit": "mocha tests/unit_tests/*.test.*"
|
|
13
14
|
},
|
|
14
15
|
"repository": {
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
"diff": "5.0.0"
|
|
51
52
|
},
|
|
52
53
|
"bin": {
|
|
54
|
+
"alkiln-server-install": "./lib/docassemble/server_install.js",
|
|
53
55
|
"alkiln-setup": "./lib/docassemble/setup.js",
|
|
54
56
|
"alkiln-takedown": "./lib/docassemble/takedown.js",
|
|
55
57
|
"alkiln-run": "./lib/run_cucumber.js"
|
package/setup.py
CHANGED
|
@@ -50,10 +50,10 @@ setup(name='docassemble.ALKilnTests',
|
|
|
50
50
|
author='plocket',
|
|
51
51
|
author_email='example@example.com',
|
|
52
52
|
license='The MIT License (MIT)',
|
|
53
|
-
url='https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/
|
|
53
|
+
url='https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/alkiln',
|
|
54
54
|
packages=find_packages(),
|
|
55
55
|
namespace_packages=['docassemble'],
|
|
56
|
-
install_requires=['docassemble.ALToolbox>=0.
|
|
56
|
+
install_requires=['docassemble.ALToolbox>=0.8.2', 'docassemble.AssemblyLine>=2.24.0'],
|
|
57
57
|
zip_safe=False,
|
|
58
58
|
package_data=find_package_data(where='docassemble/ALKilnTests/', package='docassemble.ALKilnTests'),
|
|
59
59
|
)
|