@suffolklitlab/alkiln 5.0.0-pre-3 → 5.0.0-pre-5
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/test_tests.yml +3 -3
- package/CHANGELOG.md +2 -0
- package/CONTRIBUTING.md +6 -0
- package/action.yml +1 -1
- package/lib/run_cucumber.js +1 -0
- package/lib/scope.js +32 -22
- package/lib/steps.js +11 -9
- package/lib/utils/files.js +1 -2
- package/npm-shrinkwrap.json +4407 -0
- package/package.json +2 -2
- package/tests/unit_tests/getSafeScenarioBaseFilename.fixtures.js +3 -0
- package/tests/unit_tests/getSafeScenarioBaseFilename.test.js +6 -0
- package/tests/unit_tests/getSafeScenarioFilename.test.js +29 -5
- package/tests/unit_tests/names.fixtures.js +4 -1
|
@@ -45,8 +45,8 @@ jobs:
|
|
|
45
45
|
- name: Set name of artifact folder with date and UTC time
|
|
46
46
|
# https://www.shell-tips.com/linux/how-to-format-date-and-time-in-linux-macos-and-bash/#how-to-format-a-date-in-bash
|
|
47
47
|
run: |
|
|
48
|
-
echo "ARTIFACT_NAME=alkiln-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)
|
|
49
|
-
echo "UNIT_TESTS_ARTIFACT_NAME=_alkiln-misc-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)
|
|
48
|
+
echo "ARTIFACT_NAME=alkiln-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
|
|
49
|
+
echo "UNIT_TESTS_ARTIFACT_NAME=_alkiln-misc-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
|
|
50
50
|
- name: Set languages
|
|
51
51
|
run: echo "EXTRA_LANGUAGES=${{ github.event.inputs.extra_languages }}" >> $GITHUB_ENV
|
|
52
52
|
if: ${{ github.event.inputs.extra_languages != '' }}
|
|
@@ -60,7 +60,7 @@ jobs:
|
|
|
60
60
|
node-version: ${{ matrix.node-version }}
|
|
61
61
|
- run: npm install
|
|
62
62
|
- run: npm run setup
|
|
63
|
-
- run: npm run test
|
|
63
|
+
- run: npm run test ${{ github.event.inputs.tags && format('{0}', github.event.inputs.tags) }}
|
|
64
64
|
# Artifacts
|
|
65
65
|
- name: upload unit tests artifacts folder
|
|
66
66
|
uses: actions/upload-artifact@v3
|
package/CHANGELOG.md
CHANGED
|
@@ -45,6 +45,7 @@ Format:
|
|
|
45
45
|
be run in any directory, not just in an npm package.
|
|
46
46
|
- Additional environment variables and their validation to allow for tests that run on a developer's server/Playground instead of through GitHub. Also, other functionality for that purpose. [Issue #661](https://github.com/SuffolkLITLab/ALKiln/issues/661)
|
|
47
47
|
- Tests for new session_vars behavior and improve previous tests.
|
|
48
|
+
- Adds `npm-shrinkwrap.json`, so installs from npm will have fixed version dependencies
|
|
48
49
|
|
|
49
50
|
### Changed
|
|
50
51
|
- upgraded cucumber v8.6.0
|
|
@@ -58,6 +59,7 @@ Format:
|
|
|
58
59
|
|
|
59
60
|
### Fixed
|
|
60
61
|
- Projects created in da each have a unique name. https://github.com/SuffolkLITLab/ALKiln/issues/663
|
|
62
|
+
- Shorten path names to try to accommodate limitations of windows systems while still keeping enough useful information to help devs identify the test outputs. https://github.com/SuffolkLITLab/ALKiln/issues/618
|
|
61
63
|
|
|
62
64
|
### Security
|
|
63
65
|
- Pass docassemble API keys through HTTP headers instead of as parameters.
|
package/CONTRIBUTING.md
CHANGED
|
@@ -112,6 +112,12 @@ Our tests require the user/developer to have a docassemble server on which they
|
|
|
112
112
|
|
|
113
113
|
When the developer commits code to GitHub, their account triggers our code, passing along variables that our code needs, like their GitHub secret of the API key for their docassemble server developer account.
|
|
114
114
|
|
|
115
|
+
## Updating dependencies
|
|
116
|
+
|
|
117
|
+
Sometimes you will have to add dependencies to ALKiln. You can do so by adding the dependency in the `package.json` "dependencies" section, specifying an exact version. Then, run `npm install` to update `npm-shrinkwrap.json` to have the new dependency.
|
|
118
|
+
|
|
119
|
+
If you have to update an existing dependency, you can change the version in `package.json`, and run `npm install` to update `npm-shrankwrap.json`.
|
|
120
|
+
|
|
115
121
|
## Very general architecture of files and folders
|
|
116
122
|
|
|
117
123
|
An honest look at our current project architecture—some of our files and folders, what they do, and how they interact.
|
package/action.yml
CHANGED
|
@@ -43,7 +43,7 @@ runs:
|
|
|
43
43
|
# Human-readable date/time:
|
|
44
44
|
# https://www.shell-tips.com/linux/how-to-format-date-and-time-in-linux-macos-and-bash/#how-to-format-a-date-in-bash
|
|
45
45
|
run: |
|
|
46
|
-
echo "ARTIFACT_NAME=alkiln-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)
|
|
46
|
+
echo "ARTIFACT_NAME=alkiln-$(date +'%Y-%m-%d at %Hh%Mm%Ss' -u)UTC" >> $GITHUB_ENV
|
|
47
47
|
if ${{ github.event.inputs.extra_languages != '' }}
|
|
48
48
|
then
|
|
49
49
|
echo "Manually set languages: ${{ github.event.inputs.extra_languages }}"
|
package/lib/run_cucumber.js
CHANGED
|
@@ -61,6 +61,7 @@ const cucumber_api = require('@cucumber/cucumber/api');
|
|
|
61
61
|
}, sources: {paths: []}}, environment);
|
|
62
62
|
|
|
63
63
|
console.log("alkiln-run: working directory: %o", codeDir);
|
|
64
|
+
console.log(`\n\n`);
|
|
64
65
|
|
|
65
66
|
const { success } = await cucumber_api.runCucumber({...runConfiguration, support});
|
|
66
67
|
console.log("alkiln-run: success: %b", success);
|
package/lib/scope.js
CHANGED
|
@@ -121,8 +121,7 @@ module.exports = {
|
|
|
121
121
|
* create it. */
|
|
122
122
|
if ( !scope.report ) { scope.report = new Map(); }
|
|
123
123
|
if ( !scope.scenario_id ) {
|
|
124
|
-
|
|
125
|
-
scope.scenario_id = `_report_${ date }`;
|
|
124
|
+
scope.scenario_id = `_report_${ Date.now() }`;
|
|
126
125
|
}
|
|
127
126
|
if ( !scope.report.get( scope.scenario_id )) {
|
|
128
127
|
scope.report.set( scope.scenario_id, {} )
|
|
@@ -243,9 +242,9 @@ module.exports = {
|
|
|
243
242
|
let filename = name_parts.join(`-`);
|
|
244
243
|
let safe_name = safe_filename( filename, { replacement: `_` });
|
|
245
244
|
// Allow room for extensions, date, etc.
|
|
246
|
-
let
|
|
245
|
+
let short_name = `${ safe_name }`.substring(0, 70);
|
|
247
246
|
|
|
248
|
-
return
|
|
247
|
+
return short_name;
|
|
249
248
|
}, // Ends scope.getSafeScenarioBaseFilename()
|
|
250
249
|
|
|
251
250
|
// TODO: Does this need a name change? getSafeScenarioBasedFilename?
|
|
@@ -254,6 +253,14 @@ module.exports = {
|
|
|
254
253
|
* a prefix the caller wants, and the base filename. We hope it can
|
|
255
254
|
* contain non-english characters too. We do not offer a suffix option
|
|
256
255
|
* because it may be cut off if the filename is too long.
|
|
256
|
+
*
|
|
257
|
+
* @Examples
|
|
258
|
+
* Return value possible formats
|
|
259
|
+
* prefix-id-scenario_description-timestamp
|
|
260
|
+
* id-scenario_description-timestamp
|
|
261
|
+
* scenario_description-timestamp
|
|
262
|
+
*
|
|
263
|
+
* @returns str
|
|
257
264
|
*/
|
|
258
265
|
let name = options.prefix || '';
|
|
259
266
|
|
|
@@ -264,23 +271,22 @@ module.exports = {
|
|
|
264
271
|
|
|
265
272
|
if ( scope.page ) {
|
|
266
273
|
let { id } = await scope.examinePageID( scope, 'none to match' );
|
|
267
|
-
|
|
274
|
+
let short_id = `${ id }`.substring(0, 20);
|
|
275
|
+
name += `${ short_id }-`;
|
|
268
276
|
}
|
|
269
277
|
|
|
270
278
|
name += scope.base_filename;
|
|
271
|
-
name += `-${
|
|
279
|
+
name += `-${ Date.now() }`;
|
|
272
280
|
|
|
273
281
|
let safe_name = safe_filename( name, { replacement: `_` });
|
|
274
|
-
|
|
275
|
-
let safer_name = safe_name.substring(0, (255 - 10));
|
|
276
|
-
return safer_name;
|
|
282
|
+
return safe_name;
|
|
277
283
|
}, // Ends scope.getSafeScenarioFilename()
|
|
278
284
|
|
|
279
285
|
getJSONFilename: async function( scope ) {
|
|
280
286
|
// Get a unique path for a json file
|
|
281
287
|
let { id } = await scope.examinePageID( scope, 'none to match' );
|
|
282
|
-
let
|
|
283
|
-
let json_path = path.join( scope.paths.scenario, `json_for-${
|
|
288
|
+
let short_id = `${ id }`.substring(0, 20);
|
|
289
|
+
let json_path = path.join( scope.paths.scenario, `json_for-${ short_id }-${ Date.now() }.json` );
|
|
284
290
|
return json_path;
|
|
285
291
|
},
|
|
286
292
|
|
|
@@ -840,7 +846,7 @@ module.exports = {
|
|
|
840
846
|
|
|
841
847
|
// Error types we haven't accounted for
|
|
842
848
|
} else {
|
|
843
|
-
result.error = "Docassemble ran into an error on the page, but ALKiln does not know what the error is. If a
|
|
849
|
+
result.error = "Docassemble ran into an error on the page, but ALKiln does not know what the error is. Check the picture of this page. If a secret variable was used, there will be no picture.";
|
|
844
850
|
} // ends if error_elem !== null
|
|
845
851
|
} // ends if error_id_elem
|
|
846
852
|
|
|
@@ -1900,7 +1906,10 @@ module.exports = {
|
|
|
1900
1906
|
examinePageID: async function ( scope, question_id = '' ) {
|
|
1901
1907
|
/* Looks for a sanitized version of the question id as it's written
|
|
1902
1908
|
* in the .yml. docassemble's way in python:
|
|
1903
|
-
* re.sub(r'[^A-Za-z0-9]+', '-', interview_status.question.id.lower())
|
|
1909
|
+
* re.sub(r'[^A-Za-z0-9]+', '-', interview_status.question.id.lower())
|
|
1910
|
+
*
|
|
1911
|
+
* @returns { question_has_id: bool, id: str, id_matches: bool }
|
|
1912
|
+
*/
|
|
1904
1913
|
let id_as_class = question_id.toLowerCase().replace(/[^A-Za-z0-9]+/g, '-');
|
|
1905
1914
|
// `.className` is the node's list of classes as a string, separated by spaces
|
|
1906
1915
|
let classes_str = await scope.page.$eval(`body`, function (elem) { return elem.className });
|
|
@@ -2235,7 +2244,7 @@ module.exports = {
|
|
|
2235
2244
|
error = await scope.checkForError( scope );
|
|
2236
2245
|
}
|
|
2237
2246
|
|
|
2238
|
-
let timeout_err_message = `The test tried to continue to the next page, but it took longer than ${ (scope.timeout/1000)/60 } min. Check the
|
|
2247
|
+
let timeout_err_message = `The test tried to continue to the next page, but it took longer than ${ (scope.timeout/1000)/60 } min. Check the picture of this page. If a secret variable was used, there will be no picture.`
|
|
2239
2248
|
if ( timedOut ) { await scope.addToReport(scope, { type: `error`, value: timeout_err_message }); }
|
|
2240
2249
|
expect( timedOut, timeout_err_message ).to.be.false;
|
|
2241
2250
|
|
|
@@ -2275,13 +2284,13 @@ module.exports = {
|
|
|
2275
2284
|
throwPageError: async function ( scope, { error_handlers = {}, id = '' }) {
|
|
2276
2285
|
/* Throw a cucumber error with the error that appeared on the page. */
|
|
2277
2286
|
if ( error_handlers.system_error !== undefined ) {
|
|
2278
|
-
let sys_err_message = `The test tried to continue to the next page after ${ id }, but there was a system error. Check the
|
|
2287
|
+
let sys_err_message = `The test tried to continue to the next page after ${ id }, but there was a system error. Check the picture of this page.`
|
|
2279
2288
|
await scope.addToReport(scope, { type: `error`, value: sys_err_message });
|
|
2280
2289
|
expect( was_system_error, sys_err_message ).to.be.false;
|
|
2281
2290
|
|
|
2282
2291
|
} else {
|
|
2283
2292
|
// If it wasn't a system error, it was a user error
|
|
2284
|
-
let user_err_message = `The test tried to continue to the next page after ${ id }, but the user got an error. Check the
|
|
2293
|
+
let user_err_message = `The test tried to continue to the next page after ${ id }, but the user got an error. Check the picture of this page.`
|
|
2285
2294
|
await scope.addToReport(scope, { type: `error`, value: user_err_message });
|
|
2286
2295
|
expect( true, user_err_message ).to.be.false;
|
|
2287
2296
|
}
|
|
@@ -2317,18 +2326,19 @@ module.exports = {
|
|
|
2317
2326
|
screenshot: async ( scope, name ) => {
|
|
2318
2327
|
/* Download and save a screenshot. `name` does not have to be
|
|
2319
2328
|
* unique as the filename will be made unique. */
|
|
2320
|
-
name = name || '';
|
|
2321
2329
|
|
|
2322
|
-
let
|
|
2330
|
+
let timestamp = Date.now();
|
|
2323
2331
|
let { id } = await scope.examinePageID( scope, 'none to match' );
|
|
2332
|
+
let short_id = `${ id }`.substring(0, 20);
|
|
2324
2333
|
// Include the custom name if it has one
|
|
2325
|
-
if ( name.length > 0 ) {
|
|
2326
|
-
|
|
2334
|
+
if ( name && name.length > 0 ) {
|
|
2335
|
+
let short_name = `${ name }`.substring(0, 70);
|
|
2336
|
+
pic_name = `pic-${ short_name }-on-${ short_id }-${ timestamp }`;
|
|
2327
2337
|
} else {
|
|
2328
|
-
|
|
2338
|
+
pic_name = `pic_on-${ short_id }-${ timestamp }`;
|
|
2329
2339
|
}
|
|
2330
2340
|
|
|
2331
|
-
await scope.take_a_screenshot( scope, { path: `./${ scope.paths.scenario }/${
|
|
2341
|
+
await scope.take_a_screenshot( scope, { path: `./${ scope.paths.scenario }/${ pic_name }.jpg` });
|
|
2332
2342
|
|
|
2333
2343
|
await scope.afterStep( scope );
|
|
2334
2344
|
}, // Ends scope.steps.screenshot()
|
package/lib/steps.js
CHANGED
|
@@ -129,7 +129,7 @@ Before(async (scenario) => {
|
|
|
129
129
|
// Make folder for this Scenario in the all-tests artifacts folder
|
|
130
130
|
scope.base_filename = await scope.getSafeScenarioBaseFilename(scope, {scenario});
|
|
131
131
|
// Add a date for uniqueness in case dev has accidentally copied a Scenario description
|
|
132
|
-
let date =
|
|
132
|
+
let date = Date.now();
|
|
133
133
|
scope.paths.scenario = `${ scope.paths.artifacts }/${ scope.base_filename }-${ date }`;
|
|
134
134
|
fs.mkdirSync( scope.paths.scenario );
|
|
135
135
|
// Store path name for this Scenario's individualized report
|
|
@@ -450,7 +450,7 @@ When(/I wait ?(?:for)? (\d*\.?\d+) seconds?/, { timeout: -1 }, async ( seconds )
|
|
|
450
450
|
);
|
|
451
451
|
});
|
|
452
452
|
|
|
453
|
-
Then(/I take a screenshot ?(?:named "([^"]+)")?/, { timeout: -1 }, async ( name ) => {
|
|
453
|
+
Then(/I take a (?:screenshot|pic) ?(?:named "([^"]+)")?/, { timeout: -1 }, async ( name ) => {
|
|
454
454
|
/* Download and save a screenshot. `name` does not have to be
|
|
455
455
|
* unique as the filename will be made unique. */
|
|
456
456
|
return wrapPromiseWithTimeout(
|
|
@@ -585,7 +585,7 @@ Then('I will be told an answer is invalid', async () => { // √
|
|
|
585
585
|
expect( was_found, no_error_msg ).to.be.true;
|
|
586
586
|
|
|
587
587
|
let was_user_error = error_handlers.complex_user_error !== undefined || error_handlers.simple_user_error !== undefined;
|
|
588
|
-
let not_user_error_msg = `The error was a system error, not an
|
|
588
|
+
let not_user_error_msg = `The error was a system error, not an invalid user answer. Check for the picture of the page's error if the step did not use any secret variables.`;
|
|
589
589
|
if ( !was_user_error ) { await scope.addToReport(scope, { type: `error`, value: not_user_error_msg }); }
|
|
590
590
|
expect( was_user_error, not_user_error_msg ).to.be.true;
|
|
591
591
|
|
|
@@ -790,8 +790,8 @@ When(/I answer randomly for at most ([0-9]+) (?:page(?:s)?|screen(?:s)?)/, { tim
|
|
|
790
790
|
*/
|
|
791
791
|
// Give each screenshots folder a time-stamped name in case the dev gets clever
|
|
792
792
|
// and use the same Scenario to run multiple randomized tests.
|
|
793
|
-
let timestamp =
|
|
794
|
-
let random_input_path = `${ scope.paths.scenario }/
|
|
793
|
+
let timestamp = Date.now();
|
|
794
|
+
let random_input_path = `${ scope.paths.scenario }/random${ timestamp }`
|
|
795
795
|
scope.paths.random_screenshots = random_input_path;
|
|
796
796
|
fs.mkdirSync( scope.paths.random_screenshots );
|
|
797
797
|
await scope.addToReport( scope, {
|
|
@@ -813,7 +813,7 @@ When(/I answer randomly for at most ([0-9]+) (?:page(?:s)?|screen(?:s)?)/, { tim
|
|
|
813
813
|
|
|
814
814
|
let no_content_err = `The interview seemed to run into an error page`
|
|
815
815
|
+ ` after the page with the question id "${ id }".`
|
|
816
|
-
+ ` See the
|
|
816
|
+
+ ` See the picture of the page in "${ random_input_path }".`;
|
|
817
817
|
|
|
818
818
|
let has_thrown = false;
|
|
819
819
|
// Ensure no infinite loop, but each page has a full timeout to run
|
|
@@ -853,7 +853,8 @@ When(/I answer randomly for at most ([0-9]+) (?:page(?:s)?|screen(?:s)?)/, { tim
|
|
|
853
853
|
let buttons = await scope.steps.set_random_page_vars( scope );
|
|
854
854
|
|
|
855
855
|
// Take a screenshot of the page before continuing or ending
|
|
856
|
-
let
|
|
856
|
+
let short_id = `${ id }`.substring(0, 20);
|
|
857
|
+
let path = `${ scope.paths.random_screenshots }/random-${ short_id }${ Date.now() }.jpg`;
|
|
857
858
|
await scope.take_a_screenshot( scope, { path: path });
|
|
858
859
|
|
|
859
860
|
// Prep for the next loop to possibly stop. Signature page buttons
|
|
@@ -1131,7 +1132,7 @@ After(async function(scenario) {
|
|
|
1131
1132
|
if ( !!scope.disable_error_screenshot ) {
|
|
1132
1133
|
scope.addToReport(scope, {
|
|
1133
1134
|
type: `row`,
|
|
1134
|
-
value: `For security, ALKiln will avoid creating a
|
|
1135
|
+
value: `For security, ALKiln will avoid creating a picture of the page for this error. It's possible a secret is being used on this screen.`
|
|
1135
1136
|
});
|
|
1136
1137
|
} else {
|
|
1137
1138
|
|
|
@@ -1144,7 +1145,8 @@ After(async function(scenario) {
|
|
|
1144
1145
|
// Save another copy in the artifact's Scenario folder
|
|
1145
1146
|
let screenshot_name = `error_on`;
|
|
1146
1147
|
let { id } = await scope.examinePageID( scope, 'none to match' );
|
|
1147
|
-
|
|
1148
|
+
let short_id = `${ id }`.substring(0, 20);
|
|
1149
|
+
screenshot_name += `-${ short_id }`;
|
|
1148
1150
|
let path_scenario = `${ scope.paths.scenario }/${ screenshot_name }.jpg`;
|
|
1149
1151
|
await scope.take_a_screenshot( scope, { path: path_scenario });
|
|
1150
1152
|
|
package/lib/utils/files.js
CHANGED
|
@@ -16,9 +16,8 @@ files.readable_date = function() {
|
|
|
16
16
|
let hours = ("0" + date.getUTCHours()).slice(-2);
|
|
17
17
|
let mins = ("0" + date.getUTCMinutes()).slice(-2);
|
|
18
18
|
let secs = ("0" + date.getUTCSeconds()).slice(-2);
|
|
19
|
-
let msecs = ("00" + date.getUTCMilliseconds()).slice(-3);
|
|
20
19
|
|
|
21
|
-
let fancy_str = `${ year }-${ month }-${ day } at ${ hours }h${ mins }m${ secs }
|
|
20
|
+
let fancy_str = `${ year }-${ month }-${ day } at ${ hours }h${ mins }m${ secs }sUTC`;
|
|
22
21
|
return fancy_str;
|
|
23
22
|
}; // Ends files.readable_date()
|
|
24
23
|
|