@suffolklitlab/alkiln 5.4.0 → 5.4.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.
- package/CHANGELOG.md +5 -0
- package/lib/run_cucumber.js +67 -34
- package/lib/scope.js +23 -46
- package/lib/utils/session_vars.js +56 -7
- package/npm-shrinkwrap.json +24 -2583
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -44,6 +44,11 @@ Format:
|
|
|
44
44
|
-->
|
|
45
45
|
<!-- ## [Unreleased] -->
|
|
46
46
|
|
|
47
|
+
## [5.4.1] - 2023-10-18
|
|
48
|
+
|
|
49
|
+
### Internal
|
|
50
|
+
- BREAKS ALKilnInThePlayground v1.2.0 and below (as we discussed) as that project is still exploratory. Can now take the location of the "sources" folder or folders as an argument in the command line. The formats are `npm run cucumber @tags -- --sources=./foo` and `alkiln-run @tags --sources=./foo`.
|
|
51
|
+
|
|
47
52
|
## [5.4.0] - 2023-10-14
|
|
48
53
|
|
|
49
54
|
### Added
|
package/lib/run_cucumber.js
CHANGED
|
@@ -6,64 +6,97 @@ const session_vars = require('./utils/session_vars');
|
|
|
6
6
|
|
|
7
7
|
const cucumber_api = require('@cucumber/cucumber/api');
|
|
8
8
|
|
|
9
|
-
(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"publishQuiet": true,
|
|
16
|
-
"require": "./lib/index.js",
|
|
17
|
-
"format": ["progress", "summary:cucumber-report.txt"],
|
|
18
|
-
"paths": ["docassemble/*/data/sources/*.feature"],
|
|
19
|
-
"retry": 1,
|
|
20
|
-
}
|
|
21
|
-
|
|
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`);
|
|
9
|
+
function build_config( command_args ) {
|
|
10
|
+
// Turn all the paths to the sources folders into paths to the feature files
|
|
11
|
+
let sources_paths = session_vars.get_sources_paths();
|
|
12
|
+
let feature_paths = [];
|
|
13
|
+
for ( let source of sources_paths ) {
|
|
14
|
+
feature_paths.push( `${ source }/*.feature` );
|
|
28
15
|
}
|
|
29
16
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
17
|
+
const config = {
|
|
18
|
+
publishQuiet: true,
|
|
19
|
+
require: `./lib/index.js`,
|
|
20
|
+
format: [`progress`, `summary:cucumber-report.txt`],
|
|
21
|
+
paths: feature_paths,
|
|
22
|
+
retry: 1,
|
|
33
23
|
}
|
|
34
24
|
|
|
25
|
+
// Normalize tag expressions, if there are any
|
|
26
|
+
let tags = command_args[`_`];
|
|
35
27
|
if (tags.length > 0) {
|
|
36
28
|
let joined_tags = '';
|
|
37
29
|
// Cucumber expects tags in boolean expressions, like (@a0 or @a1) and @random.
|
|
38
30
|
// 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(
|
|
31
|
+
if (tags.every((val) => val.startsWith(`@`))) {
|
|
32
|
+
joined_tags = tags.join(` or `);
|
|
41
33
|
}
|
|
42
34
|
// 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) =>
|
|
35
|
+
else if (tags.every((val) => !val.startsWith(`@`))) {
|
|
36
|
+
joined_tags = tags.map((val) => `@` + val).join(` or `);
|
|
45
37
|
}
|
|
46
38
|
// If it's a mix of tags and no tags, it's probably a boolean expression!
|
|
47
39
|
else {
|
|
48
|
-
joined_tags = tags.join(
|
|
40
|
+
joined_tags = tags.join(` `);
|
|
49
41
|
}
|
|
50
42
|
|
|
51
|
-
|
|
52
|
-
}
|
|
43
|
+
config.tags = joined_tags;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return config;
|
|
47
|
+
}; // Ends build_config()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
(async function main() {
|
|
51
|
+
/** Create the cucumber config, run the tests, create and
|
|
52
|
+
* manipluate the output. */
|
|
53
|
+
const environment = { cwd: process.cwd() };
|
|
54
|
+
console.log("alkiln-run: environment: %o", environment);
|
|
55
|
+
|
|
56
|
+
// We'll use the user info to construct the possible paths to /sources
|
|
57
|
+
let id = session_vars.get_user_id();
|
|
58
|
+
// `project` is the name in the server docassemble "Project" page
|
|
59
|
+
let project = session_vars.get_user_project_name();
|
|
60
|
+
|
|
61
|
+
// process.argv is a list of strings of commands and args.
|
|
62
|
+
// If using `npm run cucumber`, use `--` before `--sources=./foo`
|
|
63
|
+
let argv = require(`minimist`)( process.argv.slice(2), {
|
|
64
|
+
default: {
|
|
65
|
+
sources: [
|
|
66
|
+
`./docassemble/*/data/sources`, // In GitHub folder
|
|
67
|
+
`/usr/share/docassemble/files/playgroundsources/${id}/${project}/*.feature`, // From playground without S3
|
|
68
|
+
`/tmp/playgroundsources/${id}/${project}/*.feature` // From playground with S3
|
|
69
|
+
],
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Make sure `sources` is always a list
|
|
74
|
+
let sources_list = argv.sources;
|
|
75
|
+
if ( typeof argv.sources === `string` ) {
|
|
76
|
+
sources_list = [ argv.sources ];
|
|
77
|
+
}
|
|
53
78
|
|
|
79
|
+
let one_dir_exists = session_vars.set_sources_paths( sources_list );
|
|
80
|
+
if ( !one_dir_exists ) {
|
|
81
|
+
// If we don't throw, it'll be more confusing when no tests run
|
|
82
|
+
throw new ReferenceError( `ALKiln ERROR: ALKiln can't find your "sources" folder(s). See above for details.`);
|
|
83
|
+
}
|
|
84
|
+
|
|
54
85
|
const { runConfiguration } = await cucumber_api.loadConfiguration({
|
|
55
|
-
provided:
|
|
86
|
+
provided: build_config( argv ),
|
|
56
87
|
}, environment);
|
|
88
|
+
|
|
57
89
|
console.log("alkiln-run: runConfiguration: %o", runConfiguration);
|
|
90
|
+
|
|
58
91
|
var path = require('path');
|
|
59
92
|
var codeDir = path.dirname(require.main.filename);
|
|
93
|
+
console.log("alkiln-run: working directory: %o", codeDir);
|
|
60
94
|
const support = await cucumber_api.loadSupport({ support: {
|
|
61
|
-
requireModules: [`${ codeDir }/index.js`],
|
|
62
|
-
requirePaths: [ `${ codeDir }/index.js`],
|
|
95
|
+
requireModules: [ `${ codeDir }/index.js` ],
|
|
96
|
+
requirePaths: [ `${ codeDir }/index.js` ],
|
|
63
97
|
importPaths: [],
|
|
64
98
|
}, sources: {paths: []}}, environment);
|
|
65
99
|
|
|
66
|
-
console.log("alkiln-run: working directory: %o", codeDir);
|
|
67
100
|
console.log(`\n\n`);
|
|
68
101
|
|
|
69
102
|
const { success } = await cucumber_api.runCucumber({...runConfiguration, support});
|
|
@@ -86,6 +119,6 @@ const cucumber_api = require('@cucumber/cucumber/api');
|
|
|
86
119
|
|
|
87
120
|
// Put it in the correct file in the correct folder
|
|
88
121
|
let artifacts_path = session_vars.get_artifacts_path_name();
|
|
89
|
-
fs.appendFileSync( `${ artifacts_path}/${ log.debug_log_file }`, data);
|
|
122
|
+
fs.appendFileSync( `${ artifacts_path }/${ log.debug_log_file }`, data);
|
|
90
123
|
});
|
|
91
124
|
})();
|
package/lib/scope.js
CHANGED
|
@@ -1681,75 +1681,52 @@ module.exports = {
|
|
|
1681
1681
|
}, // Ends scope.today_to_date()
|
|
1682
1682
|
|
|
1683
1683
|
findFiles: async function( scope, {to_find_names}) {
|
|
1684
|
+
/** Returns a list of paths to the sources folder associated
|
|
1685
|
+
* with the given list of file names.
|
|
1686
|
+
*
|
|
1687
|
+
* @param to_find_names { [str] } List of file names
|
|
1688
|
+
*
|
|
1689
|
+
* @returns { [str] } sources folder paths
|
|
1690
|
+
*/
|
|
1684
1691
|
// First make sure the list of files was defined. Don't remove spaces yet -
|
|
1685
1692
|
// allow a typo where someone forgot to include a space after a comma.
|
|
1693
|
+
// TODO: wish we had the var name here that folks are trying to set
|
|
1686
1694
|
if ( to_find_names.length === 0 ) {
|
|
1687
|
-
reports.addToReport( scope, {
|
|
1688
|
-
type: `error`,
|
|
1689
|
-
value: `Your list of files to find is empty.`
|
|
1690
|
-
});
|
|
1691
|
-
return [];
|
|
1692
|
-
}
|
|
1693
|
-
|
|
1694
|
-
let dirs = [];
|
|
1695
|
-
if ( session_vars.get_origin() === `playground` ) {
|
|
1696
|
-
let files_playground = fg.sync(
|
|
1697
|
-
[ `/usr/share/docassemble/files/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}` ],
|
|
1698
|
-
{ onlyFiles: false, suppressErrors: true }
|
|
1699
|
-
);
|
|
1700
|
-
let files_s3 = fg.sync(
|
|
1701
|
-
[ `/tmp/playgroundsources/${session_vars.get_user_id()}/${session_vars.get_user_project_name()}` ],
|
|
1702
|
-
{ onlyFiles: false, suppressErrors: true }
|
|
1703
|
-
);
|
|
1704
|
-
|
|
1705
|
-
dirs = files_playground.concat( files_s3 );
|
|
1706
|
-
} else {
|
|
1707
|
-
dirs = fg.sync(
|
|
1708
|
-
[ `**/docassemble/**/data/sources` ],
|
|
1709
|
-
{ onlyFiles: false, suppressErrors: true }
|
|
1710
|
-
);
|
|
1711
|
-
}
|
|
1712
|
-
|
|
1713
|
-
if ( session_vars.get_debug() ) {
|
|
1714
|
-
console.log( `All discovered dirs to find files from:`, dirs );
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
|
-
// Make sure sources directory exists and has files in it
|
|
1718
|
-
if ( dirs.length === 0 ) {
|
|
1719
1695
|
reports.addToReport( scope, {
|
|
1720
1696
|
type: `warning`,
|
|
1721
|
-
value: `
|
|
1722
|
-
+ `but ALKiln couldn't find the directory or it was empty.`
|
|
1697
|
+
value: `Your Step is missing the names of which file(s) to use.`
|
|
1723
1698
|
});
|
|
1724
1699
|
return [];
|
|
1725
1700
|
}
|
|
1726
1701
|
|
|
1727
|
-
|
|
1702
|
+
let sources_dirs = session_vars.get_sources_paths();
|
|
1703
|
+
// Get the full paths of all the existing files
|
|
1728
1704
|
let paths = [];
|
|
1729
1705
|
let missing_files = []; // For any user warnings
|
|
1730
|
-
for ( let name of to_find_names) {
|
|
1731
|
-
|
|
1706
|
+
for ( let name of to_find_names ) {
|
|
1707
|
+
|
|
1732
1708
|
let trimmed_name = name.trim();
|
|
1733
1709
|
let matching_paths = [];
|
|
1734
|
-
|
|
1735
|
-
for ( let one_dir of
|
|
1736
|
-
|
|
1737
|
-
|
|
1710
|
+
// Look for the file in all "sources" folders
|
|
1711
|
+
for ( let one_dir of sources_dirs ) {
|
|
1712
|
+
let new_paths = fg.sync(
|
|
1713
|
+
[ `${ one_dir }/${ trimmed_name }` ],
|
|
1714
|
+
{ suppressErrors: true }
|
|
1715
|
+
);
|
|
1738
1716
|
matching_paths.push( ...new_paths );
|
|
1739
|
-
}
|
|
1717
|
+
}
|
|
1740
1718
|
|
|
1741
1719
|
if ( matching_paths.length === 0 ) {
|
|
1742
1720
|
missing_files.push( trimmed_name );
|
|
1743
1721
|
} else {
|
|
1744
1722
|
paths.push( ...matching_paths );
|
|
1745
1723
|
}
|
|
1746
|
-
|
|
1747
1724
|
} // ends for each file
|
|
1748
1725
|
|
|
1749
1726
|
if ( missing_files.length > 0 ) {
|
|
1750
1727
|
reports.addToReport( scope, {
|
|
1751
1728
|
type: `warning`,
|
|
1752
|
-
value: `ALKiln could not find "${ missing_files.join('", "') }" in
|
|
1729
|
+
value: `ALKiln could not find "${ missing_files.join('", "') }" in the folder(s) at "${ sources_dirs.join('", "') }".`
|
|
1753
1730
|
});
|
|
1754
1731
|
}
|
|
1755
1732
|
|
|
@@ -1758,7 +1735,7 @@ module.exports = {
|
|
|
1758
1735
|
return [];
|
|
1759
1736
|
}
|
|
1760
1737
|
return paths;
|
|
1761
|
-
},
|
|
1738
|
+
}, // Ends scope.findFiles()
|
|
1762
1739
|
|
|
1763
1740
|
uploadFiles: async function ( scope, { handle, answer }) {
|
|
1764
1741
|
/* Try to upload one or more files to a file-type input field.
|
|
@@ -1999,7 +1976,7 @@ module.exports = {
|
|
|
1999
1976
|
}
|
|
2000
1977
|
if ( num_unused_rows > 0 ) {
|
|
2001
1978
|
let { id } = await scope.examinePageID( scope, 'none to match' );
|
|
2002
|
-
let msg = `
|
|
1979
|
+
let msg = `Error on page "${id}". See screenshot and see text above for more details.`;
|
|
2003
1980
|
reports.addToReport(scope, { type: `error`, value: msg });
|
|
2004
1981
|
expect( num_unused_rows, msg ).to.equal( 0 );
|
|
2005
1982
|
}
|
|
@@ -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
|
|
|
@@ -37,13 +38,6 @@ session_vars.get_origin = function () {
|
|
|
37
38
|
};
|
|
38
39
|
session_vars.get_user_project_name = function () { return process.env._PROJECT_NAME || null; };
|
|
39
40
|
session_vars.get_user_id = function () { return process.env._USER_ID || null; };
|
|
40
|
-
session_vars.get_tags = function () {
|
|
41
|
-
if ( process.env._TAGS ) {
|
|
42
|
-
return process.env._TAGS.split(` `);
|
|
43
|
-
} else {
|
|
44
|
-
return [];
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
41
|
|
|
48
42
|
// More complex logic
|
|
49
43
|
session_vars.get_server_reload_timeout = function () {
|
|
@@ -210,6 +204,61 @@ session_vars.get_artifacts_path_name = function () {
|
|
|
210
204
|
}
|
|
211
205
|
}; // Ends get_artifacts_path_name()
|
|
212
206
|
|
|
207
|
+
session_vars.set_sources_paths = function ( paths ) {
|
|
208
|
+
/** Returns whether at least one of the given path exists. Store
|
|
209
|
+
* a list of the existing paths. Warn of any missing paths. Can be
|
|
210
|
+
* used for getting, e.g .feature files, files to upload, etc.
|
|
211
|
+
*
|
|
212
|
+
* Our code should ensure this gets run before cucumber tests get triggered.
|
|
213
|
+
*
|
|
214
|
+
* @param paths { [str] } List of paths to the 'sources' folder.
|
|
215
|
+
*
|
|
216
|
+
* @returns bool
|
|
217
|
+
*/
|
|
218
|
+
|
|
219
|
+
// Check every path, tracking which exist and which are missing
|
|
220
|
+
let existing_paths = [];
|
|
221
|
+
let missing_paths = [];
|
|
222
|
+
for ( let path of paths ) {
|
|
223
|
+
let dirs = fg.sync(
|
|
224
|
+
[ path ],
|
|
225
|
+
{ onlyFiles: false, suppressErrors: true }
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
if ( dirs.length > 0 ) {
|
|
229
|
+
existing_paths.push( ...dirs );
|
|
230
|
+
} else {
|
|
231
|
+
missing_paths.push( path );
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Warn about missing paths
|
|
236
|
+
if ( missing_paths.length > 0 ) {
|
|
237
|
+
console.warn(
|
|
238
|
+
`ALKiln WARNING: ALKiln can't find folders at "${ paths.join(", ") }".`
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// If no paths were valid
|
|
243
|
+
if ( existing_paths.length <= 0 ) {
|
|
244
|
+
session_vars._sources_paths = null;
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Otherwise, store valid paths
|
|
249
|
+
session_vars._sources_paths = existing_paths;
|
|
250
|
+
return true;
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
session_vars.get_sources_paths = function () {
|
|
254
|
+
/** Get the "sources" folder path. Should never be undefined during
|
|
255
|
+
* a run of the test. run_cucumber.js should make sure it has
|
|
256
|
+
* a default value.
|
|
257
|
+
*
|
|
258
|
+
* @returns str || null */
|
|
259
|
+
return session_vars._sources_paths;
|
|
260
|
+
};
|
|
261
|
+
|
|
213
262
|
session_vars.validateEnvironment = function() {
|
|
214
263
|
/** Throw a useful error for the developer if any of the env vars
|
|
215
264
|
* required by absolutely all tests are missing. Gather all
|