@suffolklitlab/alkiln 5.0.1 → 5.0.2-feat-github-server-1

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.
@@ -0,0 +1,37 @@
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
+ # Only test 2 tests - one uses an env var, the other uses AL.
11
+ # They test if env vars get set correctly and depencencies get
12
+ # pulled in correctly.
13
+ default: '@e6 or @al1'
14
+
15
+ jobs:
16
+
17
+ github-server-tests:
18
+ runs-on: ubuntu-latest
19
+ strategy:
20
+ matrix:
21
+ node-version: [18.x]
22
+
23
+ env:
24
+ USER1_EMAIL: ${{ secrets.USER1_EMAIL }}
25
+ USER1_PASSWORD: ${{ secrets.USER1_PASSWORD }}
26
+ SECRET_VAR1: secret-var1-value
27
+ SECRET_VAR2: secret-var2-value
28
+ SECRET_FOR_MISSING_FIELD: secret for missing field
29
+
30
+ steps:
31
+ - uses: actions/checkout@v3
32
+ - name: Run ALKiln on the GitHub server
33
+ uses: SuffolkLITLab/ALKiln/github_server@start_server_take_2
34
+ with:
35
+ CONFIG_CONTENTS: "${{ secrets.CONFIG_CONTENTS }}"
36
+ ALKILN_VERSION: 5.0.2-feat-github-server-1
37
+ - run: echo "Finished running on the GitHub server"
package/CHANGELOG.md CHANGED
@@ -40,6 +40,10 @@ Format:
40
40
  -->
41
41
  <!-- ## [Unreleased] -->
42
42
 
43
+ ## [5.0.2] - 2023-07-20
44
+ ### Fixed
45
+ - Accept `SERVER_RELOAD_TIMEOUT_SECONDS` as an env var input in GitHub.
46
+
43
47
  ## [5.0.1] - 2023-07-18
44
48
  ### Changed
45
49
  - Increment version of ALKiln that action.yml is using.
package/action.yml CHANGED
@@ -5,15 +5,6 @@ inputs:
5
5
  SERVER_URL:
6
6
  description: 'The url of your docassemble server. This should be in your GitHub SECRETS or the SECRETS of your org.'
7
7
  required: true
8
- PLAYGROUND_EMAIL:
9
- description: 'The email of your docassemble testing account. This should be in your GitHub SECRETS or the SECRETS of your org.'
10
- required: true
11
- PLAYGROUND_PASSWORD:
12
- description: 'The password of your docassemble testing account. This should be in your GitHub SECRETS or the SECRETS of your org.'
13
- required: true
14
- PLAYGROUND_ID:
15
- description: 'The id of your docassemble testing account. This should be in your GitHub SECRETS or the SECRETS of your org.'
16
- required: true
17
8
  DOCASSEMBLE_DEVELOPER_API_KEY:
18
9
  description: 'API key of the testing account with developer permissions on your docassemble server.'
19
10
  required: true
@@ -28,6 +19,10 @@ inputs:
28
19
  description: "Amount of time to give the Project to upload your package's GitHub code."
29
20
  required: false
30
21
  default: '120'
22
+ SERVER_RELOAD_TIMEOUT_SECONDS:
23
+ description: "Max amount of time to give the server to reload if it needs to"
24
+ required: false
25
+ # no default to let the custom Scenario timeouts create the reload timeout
31
26
 
32
27
  runs:
33
28
  using: "composite"
@@ -41,17 +36,15 @@ runs:
41
36
  echo "REPO_URL=${{ github.server_url }}/${{ github.repository }}" >> $GITHUB_ENV
42
37
  echo "BRANCH_PATH=${{ github.ref }}" >> $GITHUB_ENV
43
38
  echo "BASE_URL=${{ inputs.SERVER_URL }}" >> $GITHUB_ENV
44
- echo "PLAYGROUND_EMAIL=${{ inputs.PLAYGROUND_EMAIL }}" >> $GITHUB_ENV
45
- echo "PLAYGROUND_PASSWORD=${{ inputs.PLAYGROUND_PASSWORD }}" >> $GITHUB_ENV
46
- echo "PLAYGROUND_ID=${{ inputs.PLAYGROUND_ID }}" >> $GITHUB_ENV
47
39
  echo "DOCASSEMBLE_DEVELOPER_API_KEY=${{ inputs.DOCASSEMBLE_DEVELOPER_API_KEY }}" >> $GITHUB_ENV
48
40
  echo "ALKILN_VERSION=${{ inputs.ALKILN_VERSION }}" >> $GITHUB_ENV
49
41
  echo "MAX_SECONDS_FOR_SETUP=${{ inputs.MAX_SECONDS_FOR_SETUP }}" >> $GITHUB_ENV
42
+ echo "SERVER_RELOAD_TIMEOUT_SECONDS=${{ inputs.SERVER_RELOAD_TIMEOUT_SECONDS }}" >> $GITHUB_ENV
50
43
  echo "_ORIGIN=github" >> $GITHUB_ENV
51
44
  shell: bash
52
45
  - name: "ALKiln: confirm info"
53
46
  run: |
54
- 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\n"
47
+ 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"
55
48
  shell: bash
56
49
 
57
50
  # Install node
@@ -90,10 +83,10 @@ runs:
90
83
 
91
84
  # ##################################
92
85
  # # A developer's workflow should look similar to the below
93
- # # In place of `uses: suffolkLITLab/ALKiln@releases/v4`, they
86
+ # # In place of `uses: suffolkLITLab/ALKiln@v5`, they
94
87
  # # might use another version.
95
88
  #
96
- # name: Use the ALKiln testing framework v4 to run tests
89
+ # name: ALKiln v5 tests
97
90
  # on:
98
91
  # push:
99
92
  # workflow_dispatch:
@@ -108,9 +101,9 @@ runs:
108
101
  # runs-on: ubuntu-latest
109
102
  # name: Run interview tests
110
103
  # steps:
111
- # - uses: actions/checkout@v2
104
+ # - uses: actions/checkout@v3
112
105
  # - name: Use ALKiln to run tests
113
- # uses: suffolkLITLab/ALKiln@releases/v4
106
+ # uses: suffolkLITLab/ALKiln@v5
114
107
  # with:
115
108
  # SERVER_URL: "${{ secrets.SERVER_URL }}"
116
109
  # DOCASSEMBLE_DEVELOPER_API_KEY: "${{ secrets.DOCASSEMBLE_DEVELOPER_API_KEY }}"
@@ -0,0 +1,57 @@
1
+ name: "ALKiln/github_server: Isolated docassemble tests"
2
+ description: "Automatically test docassemble interviews on GitHub's servers, in an isolated environment. Avoids docassemble reload errors and other external factors."
3
+
4
+
5
+ inputs:
6
+ CONFIG_CONTENTS:
7
+ description: "The contents of the config file of the docassemble server"
8
+ required: false
9
+ # This is necessary to test pre-releases at the very least. It does seem
10
+ # strange considering we're controlling everything through the action, but
11
+ # that actually doesn't touch the npm version that's pulled in.
12
+ ALKILN_VERSION:
13
+ description: 'Version of ALKiln to get from npm.'
14
+ required: false
15
+ default: '^5.0.0'
16
+ MAX_SECONDS_FOR_SETUP:
17
+ description: "Amount of time to give the Project to upload your package's GitHub code."
18
+ required: false
19
+ default: '120'
20
+ SERVER_RELOAD_TIMEOUT_SECONDS:
21
+ description: "Max amount of time to give the server to reload if it needs to"
22
+ required: false
23
+ # no default to let the custom Scenario timeouts create the reload timeout
24
+
25
+
26
+ runs:
27
+ using: "composite"
28
+ steps:
29
+ - name: "github_server: Set environment variables"
30
+ run: |
31
+ echo "DA_ADMIN_API_KEY=abcd1234abcd1234abcd5678abdc5678" >> $GITHUB_ENV
32
+ shell: bash
33
+ - name: "github_server: Download and start docker"
34
+ run: |
35
+ mkdir /tmp/config
36
+ echo "$CONFIG_CONTENTS" > /tmp/config/myconfig.yml
37
+ docker pull brycewilley/smoldocassemble
38
+ docker run --env DA_ADMIN_EMAIL="admin@example.com" --env DA_ADMIN_PASSWORD="password" --env DA_ADMIN_API_KEY="${{ env.DA_ADMIN_API_KEY }}" --env DA_CONFIG=/tmp/config/myconfig.yml --volume /tmp/config:/tmp/config --cap-add SYS_PTRACE --memory="4gb" -d -p 80:80 jhpyle/docassemble
39
+ # TODO before merge: do a while loop here until `localhost` shows "It's ready"
40
+ sleep 600
41
+ sleep 600
42
+ curl localhost
43
+ shell: bash
44
+ - name: "github_server: Install the package"
45
+ run: alkiln-startserver
46
+ shell: bash
47
+ - name: "github_server: Run Kiln"
48
+ # TODO: Research how to get this to always be the same branch we're on
49
+ uses: SuffolkLITLab/ALKiln@v5
50
+ with:
51
+ SERVER_URL: "http://localhost"
52
+ DOCASSEMBLE_DEVELOPER_API_KEY: "${{ env.DA_ADMIN_API_KEY }}"
53
+ - name: Docker logs
54
+ # TODO: create an arifact for this instead
55
+ run: |
56
+ docker logs $(docker ps --filter "ancestor=jhpyle/docassemble" --format {{.ID}})
57
+ shell: bash
@@ -54,6 +54,22 @@ da.create_project = async function ( project_name, timeout ) {
54
54
  }
55
55
  }; // Ends da.create_project()
56
56
 
57
+ da.install_on_server = async function ( github_repo, branch_name, timeout ) {
58
+ let options = {
59
+ method: 'POST',
60
+ url: `${ session_vars.get_da_server_url() }/api/package`,
61
+ data: qs.stringify( {
62
+ key: session_vars.get_dev_api_key(),
63
+ github_url: github_repo,
64
+ branch: branch_name
65
+ }),
66
+ timeout: timeout,
67
+ };
68
+ console.log("%o", options);
69
+
70
+ return await axios.request(options);
71
+ };
72
+
57
73
 
58
74
  // node -e 'require("./lib/docassemble/docassemble_api_REST.js").pull()'
59
75
  da.pull = async function ( timeout ) {
@@ -79,13 +95,21 @@ da.pull = async function ( timeout ) {
79
95
  }; // Ends da.pull()
80
96
 
81
97
 
98
+ da.has_playground_task_finished = async function ( task_id, timeout ) {
99
+ return await da.has_task_finished( "/api/restart_status", task_id, timeout);
100
+ }
101
+
102
+ da.has_package_task_finished = async function ( task_id, timeout ) {
103
+ return await da.has_task_finished( "/api/package_update_status", task_id, timeout);
104
+ }
105
+
82
106
  // node -e 'require("./lib/docassemble/docassemble_api_REST.js").has_task_finished()'
83
- da.has_task_finished = async function ( task_id, timeout ) {
107
+ da.has_task_finished = async function ( api_endpoint, task_id, timeout ) {
84
108
  /* Check task status based on `task_id`. */
85
109
  let options = {
86
110
  method: 'GET',
87
111
  headers: {'X-API-Key': session_vars.get_dev_api_key()},
88
- url: `${ session_vars.get_da_server_url() }/api/restart_status`,
112
+ url: `${ session_vars.get_da_server_url() }${ api_endpoint }`,
89
113
  params: {
90
114
  task_id: task_id,
91
115
  },
@@ -330,8 +330,30 @@ da_i.pull = async function ( pull_options ) {
330
330
  }; // Ends da_i.pull()
331
331
 
332
332
 
333
+ da_i.install_on_server = async function ( install_options ) {
334
+ let { timeout } = install_options || { timeout: DEFAULT_MAX_REQUEST_MS };
335
+
336
+ try {
337
+ let response = await _da_REST.install_on_server(
338
+ session_vars.get_repo_url(),
339
+ session_vars.get_branch_name(),
340
+ timeout
341
+ );
342
+ if ( response && response.status === 200 ) {
343
+ // console.log("%o", response);
344
+ log.debug({ pre: `install task id: ${ response.data.task_id }` });
345
+ return response.data.task_id;
346
+ }
347
+ // console.log(`${ response.status }: ${ response.data }`);
348
+ return null;
349
+ } catch (error ) {
350
+ log.error({ pre: `Installing on the docassemble serve ran into an unexpected error.`, data: error.toJSON()});
351
+ }
352
+
353
+ };
354
+
333
355
  // node -e 'require("./lib/docassemble/docassemble_api_interface.js").has_task_finished()'
334
- da_i.has_task_finished = async function ( task_id, options ) {
356
+ da_i.has_task_finished = async function ( api_endpoint, task_id, options ) {
335
357
  /** Check task status if it exists. If not, return true as task did
336
358
  * not require a server restart. See da_i.pull().
337
359
  * See https://docassemble.org/docs/api.html#restart_status. */
@@ -342,7 +364,7 @@ da_i.has_task_finished = async function ( task_id, options ) {
342
364
  try {
343
365
 
344
366
  // If server did need to restart, check if it's done.
345
- let response = await _da_REST.has_task_finished( task_id, timeout );
367
+ let response = await _da_REST.has_task_finished( api_endpoint, task_id, timeout );
346
368
  log.debug({ pre: `Task status: ${ response.status }. Docassemble status text: ${ response.data.status }. Task id: ${ task_id }` });
347
369
 
348
370
  if ( response.data.status === 'completed' ) {
@@ -353,16 +375,15 @@ da_i.has_task_finished = async function ( task_id, options ) {
353
375
  return false;
354
376
 
355
377
  } else if ( response.data.status === 'unknown' ) {
356
- // Server is working, but status 'unknown'? We shouldn't even
357
- // get here according to the API docs, but it feels weird to have
358
- // no default behavior. What to return? Throw?
378
+ // Server is working, but status 'unknown'? Bad design, but this
379
+ // does get returned when install packages, so return true
359
380
  log.info({
360
381
  pre: `\`task_id\` "${ task_id }" has expired. If it's been `
361
382
  + `less than 1 hour since the task started, the task is `
362
383
  + `complete. See https://docassemble.org/docs/api.html#restart_status.`,
363
- data: response,
384
+ data: response.data,
364
385
  });
365
- return null;
386
+ return true;
366
387
  } // ends status type
367
388
 
368
389
  } catch ( error ) {
@@ -378,8 +399,15 @@ da_i.has_task_finished = async function ( task_id, options ) {
378
399
 
379
400
  }; // Ends da_i.has_task_finished()
380
401
 
402
+ da_i.wait_for_playground_to_restart = async ( task_id, options ) => {
403
+ return await da_i.wait_for_server_to_restart( "/api/restart_status", task_id, options );
404
+ };
405
+
406
+ da_i.wait_for_package_to_restart = async ( task_id, options ) => {
407
+ return await da_i.wait_for_server_to_restart( "/api/package_update_status", task_id, options );
408
+ };
381
409
 
382
- da_i.wait_for_server_to_restart = async ( task_id, options ) => {
410
+ da_i.wait_for_server_to_restart = async ( api_endpoint, task_id, options ) => {
383
411
  /** Wait for the server to finish restarting in case a module needs to load.
384
412
  * This is a polling function because things may be returned
385
413
  * that aren't equivalent to the server being done with a task. */
@@ -410,7 +438,7 @@ da_i.wait_for_server_to_restart = async ( task_id, options ) => {
410
438
  while ( !done_restarting && num_tries <= max_loops ) {
411
439
  num_tries++;
412
440
  // 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 } );
441
+ done_restarting = await da_i.has_task_finished( api_endpoint, task_id, { timeout: wait_for_response } );
414
442
  if ( !done_restarting ) {
415
443
  if ( num_tries < max_loops ) {
416
444
  // Show a slightly different message after a number of tries to reassure
@@ -11,9 +11,18 @@ let get_base_interview_url = async function () {
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
  let server_url = session_vars.get_da_server_url();
14
- let dev_id = await docassemble_api_interface.get_dev_id();
15
- let project_name = session_vars.get_project_name();
16
- return `${ server_url }/interview?new_session=1&i=docassemble.playground${ dev_id }${ project_name }%3A`;
14
+ console.log(session_vars.get_install_type());
15
+ if (session_vars.get_install_type() === "server") {
16
+ let x = `${ server_url }/interview?new_session=1&i=${session_vars.get_package_name().replace("-", ".")}%3A`;
17
+ console.log(`base_interview_url: ${x}`)
18
+ return x;
19
+ } else {
20
+ let dev_id = await docassemble_api_interface.get_dev_id();
21
+ let project_name = session_vars.get_project_name();
22
+ let x = `${ server_url }/interview?new_session=1&i=docassemble.playground${ dev_id }${ project_name }%3A`;
23
+ console.log(`base_interview_url: ${x}`)
24
+ return x;
25
+ }
17
26
  };
18
27
 
19
28
  module.exports = get_base_interview_url;
@@ -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.wait_for_server_to_restart( task_id );
42
+ await da_i.wait_for_playground_to_restart( task_id );
43
43
  }
44
44
 
45
45
  // Finish
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ const puppeteer = require('puppeteer');
3
+ const da_i = require('./docassemble_api_interface');
4
+ const session_vars = require('../utils/session_vars');
5
+
6
+ const fs = require('fs')
7
+
8
+ const startserver = async () => {
9
+ // Open the browser, login with env var creds
10
+ /*
11
+ let browser = await puppeteer.launch({headless: !session_vars.get_debug()})
12
+ let page = await browser.newPage();
13
+ // Go to the sign in page
14
+ let login_url = `${ session_vars.get_da_server_url() }/user/sign-in`;
15
+ try {
16
+ // puppeteer will ensure proper timeout.
17
+ await page.goto( login_url, { waitUntil: `domcontentloaded`, timeout: 3000 });
18
+ await page.waitForSelector( `.dabody` );
19
+ } catch ( error ) {
20
+ let err_msg = `Error occurred when ALKiln tried to go to "${ login_url }: ${ error }".`
21
+ console.log(err_msg);
22
+ throw error;
23
+ }
24
+
25
+ let email = process.env[ "DA_ADMIN_API_KEY" ];
26
+ let password = process.env[ "USER_PASSWORD" ];
27
+
28
+ // Try to log in
29
+ await page.type( `#email`, email );
30
+ await page.type( `#password`, password );
31
+ let elem = await page.$( `button[name="submit"]` );
32
+ await elem.click();
33
+ await page.waitForNavigation({waitUntil: 'domcontentloaded'});
34
+
35
+ // Wait to see the success message.
36
+ // This is a bit of an assumption and needs success and failure testing
37
+ // TODO: use a Promise.race to fail faster.
38
+ await page.waitForSelector( `.datopcenter .alert-success` );
39
+ // make an API key
40
+
41
+ // TODO(brycew): with or without the API key?
42
+ // Install the package in order to also install all of its dependencies
43
+ let api_key_url = `${ session_vars.get_da_server_url() }/manage_api?action=new`;
44
+ await page.goto( api_key_url, { waitUntil: `domcontentloaded`, timeout: 3000 });
45
+ await page.type( `#name`, "ALKiln tmp key");
46
+ await page.select( `#method`, "none");
47
+ let winner = await Promise.all([page.click(`#submit`), page.waitForNavigation({waitUntil: 'domcontentloaded'})]);
48
+ console.log(`submitted`);
49
+ const api_text = await page.$eval('body p code', elem => elem.innerText);
50
+ process.env.DOCASSEMBLE_DEVELOPER_API_KEY = api_text;
51
+ console.log(`api key: ${api_text}`);
52
+ let file = fs.writeFileSync( ".tmpenv", `export DOCASSEMBLE_DEVELOPER_API_KEY=${api_text}`);
53
+
54
+ await page.goto(`${ session_vars.get_da_server_url() }/user/sign-out`, {waitUntil: `domcontentloaded`});
55
+ console.log(`signed out`);
56
+ await browser.close();
57
+ */
58
+
59
+ let task_id = await da_i.install_on_server();
60
+ if (task_id) {
61
+ console.log("Waiting...")
62
+ await da_i.wait_for_package_to_restart(task_id);
63
+ }
64
+ console.log("Done!")
65
+ session_vars.save_install_type("server");
66
+
67
+ }; // Ends startserver();
68
+
69
+ startserver();
@@ -115,6 +115,7 @@ session_vars.get_languages = function () {
115
115
 
116
116
  const runtime_config_path = `runtime_config.json`;
117
117
  const project_name_key = `da_project_name`;
118
+ const install_type_key = `da_install_type`;
118
119
  session_vars.save_project_name = function ( project_name ) {
119
120
  /* Saves the name of the project to a json obj so deletion can use it later.
120
121
  * Built for local as well as remote testing. Assumes a kosher string.
@@ -197,6 +198,36 @@ session_vars.save_artifacts_path_name = function ( path_name ) {
197
198
  return file;
198
199
  }; // Ends save_artifacts_path_name()
199
200
 
201
+
202
+ session_vars.save_install_type = function (install_type) {
203
+ /* Save a key with the name of the current artifacts folder in case it doesn't exist. */
204
+
205
+ // Ensure artifacts path file exists
206
+ if ( !fs.existsSync( runtime_config_path ) ) {
207
+ // If the file doesn't exist, make one because next we need to read it
208
+ fs.writeFileSync( runtime_config_path, JSON.stringify( {}, null, 2 ) );
209
+ }
210
+
211
+ // Get the json, changing it, and re-write the file from scratch
212
+ let json = JSON.parse( fs.readFileSync( runtime_config_path ) );
213
+ json[ install_type_key ] = install_type;
214
+ let file = fs.writeFileSync( runtime_config_path, JSON.stringify( json, null, 2 ) );
215
+
216
+ return file;
217
+ }; // Ends save_artifacts_path_name()
218
+
219
+ session_vars.get_install_type = function () {
220
+ /* Get the name of the current artifacts path. */
221
+ try {
222
+ let json = JSON.parse( fs.readFileSync( runtime_config_path ));
223
+ let install_type = json[ install_type_key ];
224
+
225
+ return install_type;
226
+ } catch ( error ) {
227
+ return null;
228
+ }
229
+ }; // Ends get_artifacts_path_name()
230
+
200
231
  session_vars.get_artifacts_path_name = function () {
201
232
  /* Get the name of the current artifacts path. */
202
233
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suffolklitlab/alkiln",
3
- "version": "5.0.1",
3
+ "version": "5.0.2-feat-github-server-1",
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
+ "startserver": "./lib/docassemble/startserver.js",
12
13
  "unit": "mocha tests/unit_tests/*.test.*"
13
14
  },
14
15
  "repository": {
@@ -47,6 +48,7 @@
47
48
  "uuid": "8.3.2"
48
49
  },
49
50
  "bin": {
51
+ "alkiln-startserver": "./lib/docassemble/startserver.js",
50
52
  "alkiln-setup": "./lib/docassemble/setup.js",
51
53
  "alkiln-takedown": "./lib/docassemble/takedown.js",
52
54
  "alkiln-run": "./lib/run_cucumber.js"
package/tmp.bash ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/bash
2
+
3
+ npm run startserver
4
+ source .tmpenv
5
+ # (cd ../docassemble-EFSPIntegration && npm run setup)
6
+
7
+ # npm run cucumber