@suffolklitlab/alkiln 5.0.2 → 5.1.0-sources-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -37,9 +37,19 @@ Format:
37
37
 
38
38
  ### Security
39
39
  -
40
+
41
+ ### Internal
42
+ -
40
43
  -->
41
44
  <!-- ## [Unreleased] -->
42
45
 
46
+ ## [5.1.0] - 2023-08-12
47
+ ### Added
48
+ - Comboboxes - can now fill in comboboxes on the latest Docassemble.
49
+
50
+ ### Fixed
51
+ - Filling out a hidden field right after a date field triggered the date's calendar popup, which I believe ate the input for the next visible field.
52
+
43
53
  ## [5.0.2] - 2023-07-20
44
54
  ### Fixed
45
55
  - Accept `SERVER_RELOAD_TIMEOUT_SECONDS` as an env var input in GitHub.
@@ -89,6 +99,10 @@ Format:
89
99
  server
90
100
  - Update dependencies. See [#727](https://github.com/SuffolkLITLab/ALKiln/pull/727).
91
101
 
102
+ ### Internal
103
+ - added a test for multiline json values (only ones set by code not by user input)
104
+ - added an internal section to the change log
105
+
92
106
  ## [4.11.1] - 2023-03-21
93
107
  ### Changed
94
108
  - Get error data from server errors
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
@@ -45,9 +36,6 @@ runs:
45
36
  echo "REPO_URL=${{ github.server_url }}/${{ github.repository }}" >> $GITHUB_ENV
46
37
  echo "BRANCH_PATH=${{ github.ref }}" >> $GITHUB_ENV
47
38
  echo "BASE_URL=${{ inputs.SERVER_URL }}" >> $GITHUB_ENV
48
- echo "PLAYGROUND_EMAIL=${{ inputs.PLAYGROUND_EMAIL }}" >> $GITHUB_ENV
49
- echo "PLAYGROUND_PASSWORD=${{ inputs.PLAYGROUND_PASSWORD }}" >> $GITHUB_ENV
50
- echo "PLAYGROUND_ID=${{ inputs.PLAYGROUND_ID }}" >> $GITHUB_ENV
51
39
  echo "DOCASSEMBLE_DEVELOPER_API_KEY=${{ inputs.DOCASSEMBLE_DEVELOPER_API_KEY }}" >> $GITHUB_ENV
52
40
  echo "ALKILN_VERSION=${{ inputs.ALKILN_VERSION }}" >> $GITHUB_ENV
53
41
  echo "MAX_SECONDS_FOR_SETUP=${{ inputs.MAX_SECONDS_FOR_SETUP }}" >> $GITHUB_ENV
@@ -6,64 +6,89 @@ const session_vars = require('./utils/session_vars');
6
6
 
7
7
  const cucumber_api = require('@cucumber/cucumber/api');
8
8
 
9
- (async function main() {
10
- let argv = process.argv;
11
-
12
- const environment = { cwd: process.cwd() };
13
- console.log("alkiln-run: environment: %o", environment);
9
+ function build_config(argv) {
10
+ // The default provided config
14
11
  const provided_config = {
15
- "publishQuiet": true,
16
- "require": "./lib/index.js",
17
- "format": ["progress", "summary:cucumber-report.txt"],
18
- "paths": ["docassemble/*/data/sources/*.feature"],
19
- "retry": 1,
12
+ publishQuiet: true,
13
+ require: `./lib/index.js`,
14
+ format: [`progress`, `summary:cucumber-report.txt`],
15
+ paths: [`${ argv.sources }/*.feature`],
16
+ retry: 1,
20
17
  }
21
18
 
22
-
23
- // If they're running it from an interview on their server instead of from GitHub
24
- if ( session_vars.get_origin() === `playground` ) {
25
- provided_config.paths.push(`/usr/share/docassemble/files/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}/*.feature`);
26
- // For S3
27
- provided_config.paths.push(`/tmp/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}/*.feature`);
28
- }
29
-
30
- let tags = argv.slice(2);
31
- if ( session_vars.get_origin() === `playground` ) {
32
- tags = session_vars.get_tags();
33
- }
19
+ let tags = argv[`_`];
20
+ // if ( session_vars.get_origin() === `playground` ) {
21
+ // tags = session_vars.get_tags();
22
+ // }
34
23
 
35
24
  if (tags.length > 0) {
36
25
  let joined_tags = '';
37
26
  // Cucumber expects tags in boolean expressions, like (@a0 or @a1) and @random.
38
27
  // If we get a list of only tags, then "or" them all together
39
- if (tags.every((val) => val.startsWith("@"))) {
40
- joined_tags = tags.join(' or ');
28
+ if (tags.every((val) => val.startsWith(`@`))) {
29
+ joined_tags = tags.join(` or `);
41
30
  }
42
31
  // If we get a list of seemingly no tags, assume they meant to use tags
43
- else if (tags.every((val) => !val.startsWith("@"))) {
44
- joined_tags = tags.map((val) => "@" + val).join(' or ');
32
+ else if (tags.every((val) => !val.startsWith(`@`))) {
33
+ joined_tags = tags.map((val) => `@` + val).join(` or `);
45
34
  }
46
35
  // If it's a mix of tags and no tags, it's probably a boolean expression!
47
36
  else {
48
- joined_tags = tags.join(' ');
37
+ joined_tags = tags.join(` `);
49
38
  }
50
39
 
51
40
  provided_config.tags = joined_tags;
52
41
  } // end if there are tags
53
42
 
43
+ return provided_config;
44
+ }; // Ends build_config()
45
+
46
+
47
+ (async function main() {
48
+ /** Create the cucumber config, run the tests, create and
49
+ * manipluate the output. */
50
+ const environment = { cwd: process.cwd() };
51
+ console.log("alkiln-run: environment: %o", environment);
52
+
53
+ console.log(`command: ${process.argv}`);
54
+
55
+ // process.argv is a list of strings of commands and args.
56
+ let argv = require(`minimist`)( process.argv.slice(2), {
57
+ default: {
58
+ // Testing from GitHub. TODO: Do we want to allow multiple sources paths?
59
+ sources: `./docassemble/*/data/sources`,
60
+ // From playground: `/usr/share/docassemble/files/playgroundsources/<user_id>/<project>/*.feature`
61
+ // From playground with S3: `/tmp/playgroundsources/<user_id>/<project>/*.feature`
62
+
63
+ // // Installed in a user Playground
64
+ // url: `<server>/interview?new_session=1&i=docassemble.playground<user_id><project>%3A`,
65
+ // // server install: `<server>/interview?new_session=1&i=docassemble.<package>%3Adata/questions/`
66
+ }
67
+ });
68
+
69
+ let dir_exists = session_vars.set_sources_path( argv.sources );
70
+ if ( !dir_exists ) {
71
+ // If we don't throw, it'll be more confusing when no tests run
72
+ throw new ReferenceError( `No folder exists at "${ argv.sources }", where ALKiln looks for your \`.feature\` files.`)
73
+ }
74
+
75
+ const provided_config = build_config( argv );
76
+
54
77
  const { runConfiguration } = await cucumber_api.loadConfiguration({
55
78
  provided: provided_config
56
79
  }, environment);
80
+
57
81
  console.log("alkiln-run: runConfiguration: %o", runConfiguration);
82
+
58
83
  var path = require('path');
59
84
  var codeDir = path.dirname(require.main.filename);
85
+ console.log("alkiln-run: working directory: %o", codeDir);
60
86
  const support = await cucumber_api.loadSupport({ support: {
61
- requireModules: [`${ codeDir }/index.js`],
62
- requirePaths: [ `${ codeDir }/index.js`],
87
+ requireModules: [ `${ codeDir }/index.js` ],
88
+ requirePaths: [ `${ codeDir }/index.js` ],
63
89
  importPaths: [],
64
90
  }, sources: {paths: []}}, environment);
65
91
 
66
- console.log("alkiln-run: working directory: %o", codeDir);
67
92
  console.log(`\n\n`);
68
93
 
69
94
  const { success } = await cucumber_api.runCucumber({...runConfiguration, support});
@@ -86,6 +111,6 @@ const cucumber_api = require('@cucumber/cucumber/api');
86
111
 
87
112
  // Put it in the correct file in the correct folder
88
113
  let artifacts_path = session_vars.get_artifacts_path_name();
89
- fs.appendFileSync( `${ artifacts_path}/${ log.debug_log_file }`, data);
114
+ fs.appendFileSync( `${ artifacts_path }/${ log.debug_log_file }`, data);
90
115
  });
91
116
  })();
package/lib/scope.js CHANGED
@@ -998,6 +998,11 @@ module.exports = {
998
998
  }
999
999
  }
1000
1000
 
1001
+ if ( !encoded_name ) {
1002
+ // Some fields, like comboboxes, have a weird var name setup
1003
+ encoded_name = $node.attr( `id` );
1004
+ }
1005
+
1001
1006
  // ====================
1002
1007
  // Table rows
1003
1008
  // ====================
@@ -1472,6 +1477,11 @@ module.exports = {
1472
1477
  */
1473
1478
  let row_used = null;
1474
1479
 
1480
+ // Skip hidden fields right away. When a date field was above a combobox,
1481
+ // interacting with the hidden field caused the date field to open its
1482
+ // calendar which blocked input to the combobox
1483
+ if ( field.type === `hidden` ) { return row_used; }
1484
+
1475
1485
  let matching_input_rows = await scope.getMatchingRows( scope, { var_data, field });
1476
1486
 
1477
1487
  // Nothing to set if there are no matching table rows
@@ -1486,6 +1496,8 @@ module.exports = {
1486
1496
 
1487
1497
  let handle = await scope.get_handle_from_field( scope, { field: field });
1488
1498
 
1499
+ // After each previous input, figure out if this input is (now/still) disabled
1500
+ // TODO: Consider testing for disabled this before we get the matching row
1489
1501
  let disabled = await handle.evaluate(( elem )=> {
1490
1502
  // da's header covers the top of the section containing the fields which means
1491
1503
  // sometimes it blocks nodes from clicks. Scroll item to the bottom instead.
@@ -1775,73 +1787,34 @@ module.exports = {
1775
1787
  // allow a typo where someone forgot to include a space after a comma.
1776
1788
  let uploads_names = answer.split(`,`);
1777
1789
  if ( uploads_names.length === 0 ) {
1778
- await scope.addToReport( scope, {
1779
- type: `error`,
1780
- value: `Your list of files to upload is empty.`
1781
- });
1782
- return false; // The row wasn't used
1783
- }
1784
-
1785
- let dirs = [];
1786
- if ( session_vars.get_origin() === `playground` ) {
1787
- let files_playground = fg.sync(
1788
- [ `/usr/share/docassemble/files/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}` ],
1789
- { onlyFiles: false, suppressErrors: true }
1790
- );
1791
- let files_s3 = fg.sync(
1792
- [ `/tmp/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}` ],
1793
- { onlyFiles: false, suppressErrors: true }
1794
- );
1795
-
1796
- dirs = files_playground.concat( files_s3 );
1797
- } else {
1798
- dirs = fg.sync(
1799
- [ `**/docassemble/**/data/sources` ],
1800
- { onlyFiles: false, suppressErrors: true }
1801
- );
1802
- }
1803
-
1804
- if ( session_vars.get_debug() ) {
1805
- console.log( `All discovered dirs to upload from:`, dirs );
1806
- }
1807
-
1808
- // Make sure sources directory exists and has files in it
1809
- if ( dirs.length === 0 ) {
1810
1790
  await scope.addToReport( scope, {
1811
1791
  type: `warning`,
1812
- value: `The test files need to be in the "sources" directory, `
1813
- + `but ALKiln couldn't find the directory or it was empty.`
1792
+ value: `Your list of files to upload is empty.`
1814
1793
  });
1815
1794
  return false; // The row wasn't used
1816
1795
  }
1817
1796
 
1818
- // Get the full paths of all the files
1819
- let dir = null;
1797
+ let dir = session_vars.get_sources_path();
1798
+ // Get the full paths of all the existing files
1820
1799
  let paths = [];
1821
1800
  let missing_files = []; // For any user warnings
1822
1801
  for ( let name of uploads_names ) {
1823
-
1824
1802
  let trimmed_name = name.trim();
1825
- let matching_paths = [];
1826
-
1827
- for ( let one_dir of dirs ) {
1828
- // accumulate all matching paths
1829
- let new_paths = fg.sync([ `${ one_dir }/${ trimmed_name }` ]);
1830
- matching_paths.push( ...new_paths );
1831
- } // ends for each dir
1832
-
1803
+ let matching_paths = fg.sync(
1804
+ [ `${ dir }/${ trimmed_name }` ],
1805
+ { suppressErrors: true }
1806
+ );
1833
1807
  if ( matching_paths.length === 0 ) {
1834
1808
  missing_files.push( trimmed_name );
1835
1809
  } else {
1836
1810
  paths.push( ...matching_paths );
1837
1811
  }
1838
-
1839
1812
  } // ends for each file
1840
1813
 
1841
1814
  if ( missing_files.length > 0 ) {
1842
1815
  await scope.addToReport( scope, {
1843
1816
  type: `warning`,
1844
- value: `ALKiln could not find "${ missing_files.join('", "') }" in any of these folders: "${ dirs.join('", "') }".`
1817
+ value: `ALKiln could not find "${ missing_files.join('", "') }" in "${ dir }".`
1845
1818
  });
1846
1819
  }
1847
1820
 
@@ -1888,8 +1861,6 @@ module.exports = {
1888
1861
  await handle.evaluate( el => { el.value = '' });
1889
1862
  await handle.focus();
1890
1863
  await handle.type( answer );
1891
- setTimeout(async () => {
1892
- }, 500)
1893
1864
  },
1894
1865
 
1895
1866
  draw_signature: async function ( scope, name ) {
@@ -1,4 +1,5 @@
1
1
  const fs = require('fs');
2
+ const fg = require('fast-glob');
2
3
  const path = require('path');
3
4
  require('dotenv').config();
4
5
 
@@ -44,6 +45,7 @@ session_vars.get_tags = function () {
44
45
  return [];
45
46
  }
46
47
  };
48
+ session_vars.get_sources = function () { return process.env._ALKILN_SOURCES || null; };
47
49
 
48
50
  // More complex logic
49
51
  session_vars.get_server_reload_timeout = function () {
@@ -210,6 +212,39 @@ session_vars.get_artifacts_path_name = function () {
210
212
  }
211
213
  }; // Ends get_artifacts_path_name()
212
214
 
215
+ session_vars.set_sources_path = function ( path ) {
216
+ /** Returns whether the given path exists or not. If it does, store
217
+ * the path to the sources folder. Can be used for getting, e.g
218
+ * .feature files, files to upload, etc. May be annoying repetition
219
+ * for some local testing.
220
+ *
221
+ * Our code should ensure this gets run before cucumber gets triggered.
222
+ *
223
+ * @returns bool */
224
+
225
+ let sources = fg.sync(
226
+ [ path ],
227
+ { onlyFiles: false, suppressErrors: true }
228
+ );
229
+
230
+ if ( sources.length > 0 ) {
231
+ session_vars._sources_path = path;
232
+ return true;
233
+ } else {
234
+ session_vars._sources_path = null;
235
+ return false;
236
+ }
237
+ };
238
+
239
+ session_vars.get_sources_path = function () {
240
+ /** Get the "sources" folder path. Should never be undefined during
241
+ * a run of the test. run_cucumber.js should make sure it has
242
+ * a default value.
243
+ *
244
+ * @returns str || null */
245
+ return session_vars._sources_path;
246
+ };
247
+
213
248
  session_vars.validateEnvironment = function() {
214
249
  /** Throw a useful error for the developer if any of the env vars
215
250
  * required by absolutely all tests are missing. Gather all
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@suffolklitlab/alkiln",
3
- "version": "5.0.0-pre-11",
3
+ "version": "5.1.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@suffolklitlab/alkiln",
9
- "version": "5.0.0-pre-11",
9
+ "version": "5.1.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@axe-core/puppeteer": "4.7.3",
@@ -19,6 +19,7 @@
19
19
  "dotenv": "8.2.0",
20
20
  "fast-glob": "3.2.12",
21
21
  "minimatch": "3.0.5",
22
+ "minimist": "1.2.8",
22
23
  "mocha": "9.2.2",
23
24
  "puppeteer": "20.8.2",
24
25
  "qs": "6.10.3",
@@ -1940,6 +1941,14 @@
1940
1941
  "node": "*"
1941
1942
  }
1942
1943
  },
1944
+ "node_modules/minimist": {
1945
+ "version": "1.2.8",
1946
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
1947
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
1948
+ "funding": {
1949
+ "url": "https://github.com/sponsors/ljharb"
1950
+ }
1951
+ },
1943
1952
  "node_modules/mitt": {
1944
1953
  "version": "3.0.0",
1945
1954
  "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz",
@@ -4516,6 +4525,11 @@
4516
4525
  "brace-expansion": "^1.1.7"
4517
4526
  }
4518
4527
  },
4528
+ "minimist": {
4529
+ "version": "1.2.8",
4530
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
4531
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
4532
+ },
4519
4533
  "mitt": {
4520
4534
  "version": "3.0.0",
4521
4535
  "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suffolklitlab/alkiln",
3
- "version": "5.0.2",
3
+ "version": "5.1.0-sources-2",
4
4
  "description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -40,6 +40,7 @@
40
40
  "dotenv": "8.2.0",
41
41
  "fast-glob": "3.2.12",
42
42
  "minimatch": "3.0.5",
43
+ "minimist": "1.2.8",
43
44
  "mocha": "9.2.2",
44
45
  "puppeteer": "20.8.2",
45
46
  "qs": "6.10.3",