@suffolklitlab/alkiln 4.0.0 → 4.1.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/CHANGELOG.md +6 -2
- package/lib/docassemble/docassemble_api_interface.js +1 -1
- package/lib/scope.js +13 -13
- package/lib/steps.js +12 -12
- package/lib/utils/langs.js +1 -1
- package/lib/utils/session_vars.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -39,6 +39,9 @@ Format:
|
|
|
39
39
|
-
|
|
40
40
|
-->
|
|
41
41
|
<!-- ## [Unreleased] -->
|
|
42
|
+
## [4.1.0] - 2022-04-01
|
|
43
|
+
### Added
|
|
44
|
+
- Step to set vars to secret variables. That is, using environment variables while hiding the names of those variables in the report, errors, and console logs.
|
|
42
45
|
|
|
43
46
|
## [4.0.0] - 2022-03-30
|
|
44
47
|
### Added
|
|
@@ -57,10 +60,11 @@ Format:
|
|
|
57
60
|
- BREAKING: Update action.yml node to v17
|
|
58
61
|
- BREAKING: Use alkiln v4 package.json we create during the test run in `action.yml` (as discussed in #489)
|
|
59
62
|
- BREAKING: Use API key to access da server, create projects, pull code, delete projects, and check for server restart.
|
|
63
|
+
- BREAKING: Throw an error for uploading nonexistent file, changed to error instead of warning in reports.
|
|
64
|
+
- Update test setup interview to v4 of ALKiln.
|
|
60
65
|
- Remove and ignore package-lock.json so that our tests will behave more like our users' tests
|
|
61
66
|
- Add warning in steps.js for name input with too many parts. Add test in reports.
|
|
62
|
-
- fix typo in the report
|
|
63
|
-
- Throw an error for uploading nonexistent file, changed to error instead of warning in reports.
|
|
67
|
+
- fix typo in the report
|
|
64
68
|
- Allow a developer to wait as a first Step. See #387.
|
|
65
69
|
|
|
66
70
|
<!-- ## [3.0.1-peer-deps.1] - 2021-12-07 -->
|
|
@@ -243,7 +243,7 @@ da_i.loop_to_create_project = async function( creation_options ) {
|
|
|
243
243
|
throw error;
|
|
244
244
|
|
|
245
245
|
} // ends type of non-response error
|
|
246
|
-
} // ends type of
|
|
246
|
+
} // ends type of response error
|
|
247
247
|
} // ends try
|
|
248
248
|
} // ends while
|
|
249
249
|
}; // Ends da_i.loop_to_create_project()
|
package/lib/scope.js
CHANGED
|
@@ -63,7 +63,7 @@ module.exports = {
|
|
|
63
63
|
}, // Ends scope.setReportScenarioStatus()
|
|
64
64
|
|
|
65
65
|
convertToOriginalStoryTableRow: async function( scope, { row_data }) {
|
|
66
|
-
/* Returns the original data of row into a string
|
|
66
|
+
/* Returns the original data of row into a string formatted as a story table row.
|
|
67
67
|
* Should this show the actual row data that was used instead? That could
|
|
68
68
|
* be pretty confusing to most devs. */
|
|
69
69
|
let source_row = row_data.source || row_data;
|
|
@@ -113,7 +113,7 @@ module.exports = {
|
|
|
113
113
|
}, // Ends scope.addReportHeading()
|
|
114
114
|
|
|
115
115
|
getPrintableReport: async function( scope ) {
|
|
116
|
-
/* Return a string
|
|
116
|
+
/* Return a string generated from test report data. */
|
|
117
117
|
let report = `Assembly Line Kiln Automated Testing Report - ${ (new Date()).toUTCString() }\n`;
|
|
118
118
|
|
|
119
119
|
// First list failed scenarios, then non-passed scenarios, then passed scenarios
|
|
@@ -137,7 +137,7 @@ module.exports = {
|
|
|
137
137
|
}, // Ends scope.getPrintableReport()
|
|
138
138
|
|
|
139
139
|
getPrintableScenario: async function( scope, { scenario }) {
|
|
140
|
-
/* Return a string
|
|
140
|
+
/* Return a string generated from scenario list of report items. */
|
|
141
141
|
let [ scenario_id, data ] = scenario;
|
|
142
142
|
let report = ``;
|
|
143
143
|
for ( let line of data.lines ) {
|
|
@@ -391,7 +391,7 @@ module.exports = {
|
|
|
391
391
|
scope.page.waitForSelector(`fieldset.da-field-buttons button[type="submit"]`), // other pages (this is the most consistent way)
|
|
392
392
|
scope.page.waitForSelector(`fieldset .dasigsave`), // signature page
|
|
393
393
|
]);
|
|
394
|
-
|
|
394
|
+
await elem.evaluate( el => { return el.className });
|
|
395
395
|
// Waits for navigation or user error
|
|
396
396
|
await scope.tapElement( scope, elem );
|
|
397
397
|
},
|
|
@@ -414,7 +414,7 @@ module.exports = {
|
|
|
414
414
|
await scope.page.goto(interview_url, { waitUntil: 'domcontentloaded', timeout: scope.timeout })
|
|
415
415
|
|
|
416
416
|
let load_result = await scope.getLoadData( scope );
|
|
417
|
-
// Errors, or reaching timeout, causes an
|
|
417
|
+
// Errors, or reaching timeout, causes an exception and is shown to the developer at the end
|
|
418
418
|
if ( load_result.error ) {
|
|
419
419
|
await scope.addToReport(scope, { type: `error`, value: `On final attempt to load interview, got "${ load_result.error }"` });
|
|
420
420
|
expect( load_result.error ).to.equal( '' );
|
|
@@ -639,7 +639,7 @@ module.exports = {
|
|
|
639
639
|
|
|
640
640
|
// Make sure this selector matches only one node
|
|
641
641
|
let matching_nodes = $( selector );
|
|
642
|
-
// This check is here to ensure
|
|
642
|
+
// This check is here to ensure safety of future development. If there is more
|
|
643
643
|
// or less than one match, this code may have unexpected behavior later.
|
|
644
644
|
// Really need everything to be unique here if at all possible. Shall we resort
|
|
645
645
|
// to parents and n-th child?
|
|
@@ -860,7 +860,7 @@ module.exports = {
|
|
|
860
860
|
let uses_proxies = false; // See "proxies" notes further down
|
|
861
861
|
let trigger_might_be_needed = true;
|
|
862
862
|
|
|
863
|
-
// There are
|
|
863
|
+
// There are multiple guesses because field names are sometimes encoded
|
|
864
864
|
for ( let guess of field.guesses ) {
|
|
865
865
|
for ( let table_row of var_data ) {
|
|
866
866
|
let this_row_matches_this_field = false;
|
|
@@ -1085,7 +1085,7 @@ module.exports = {
|
|
|
1085
1085
|
|
|
1086
1086
|
let { tag, type } = field;
|
|
1087
1087
|
// We use the last match. We wrote a warning for the user if there were
|
|
1088
|
-
//
|
|
1088
|
+
// multiple matches in the story that the last value will be used. In future,
|
|
1089
1089
|
// Steps will be able to set this data gradually and we don't want the developer
|
|
1090
1090
|
// to get confused thinking that an earlier Step was used instead of a later one.
|
|
1091
1091
|
let row = matching_input_rows[ matching_input_rows.length - 1 ];
|
|
@@ -1360,7 +1360,7 @@ module.exports = {
|
|
|
1360
1360
|
},
|
|
1361
1361
|
|
|
1362
1362
|
examinePageID: async function ( scope, question_id = '' ) {
|
|
1363
|
-
/* Looks for a
|
|
1363
|
+
/* Looks for a sanitized version of the question id as it's written
|
|
1364
1364
|
* in the .yml. docassemble's way in python:
|
|
1365
1365
|
* re.sub(r'[^A-Za-z0-9]+', '-', interview_status.question.id.lower()) */
|
|
1366
1366
|
let id_as_class = question_id.toLowerCase().replace(/[^A-Za-z0-9]+/g, '-');
|
|
@@ -1605,7 +1605,7 @@ module.exports = {
|
|
|
1605
1605
|
* we believe we've set it up so that people will make it a number.
|
|
1606
1606
|
* Sometimes this will be from `.there_is_another`. We think we've ensured
|
|
1607
1607
|
* that it will only come from Steps and should be `True` or `False`.
|
|
1608
|
-
* This feels precarious, but I can't see another
|
|
1608
|
+
* This feels precarious, but I can't see another permutation.
|
|
1609
1609
|
*
|
|
1610
1610
|
* This may in future be used to normalize all values that need `True`/`False`
|
|
1611
1611
|
* normalization.
|
|
@@ -1680,7 +1680,7 @@ module.exports = {
|
|
|
1680
1680
|
// All results are lists to match `$x`
|
|
1681
1681
|
let possible_errors = {
|
|
1682
1682
|
complex_user_error: await scope.page.$$('.alert-danger'),
|
|
1683
|
-
// The below does not work if there's not a space
|
|
1683
|
+
// The below does not work if there's not a space between ':' and 'none'
|
|
1684
1684
|
simple_user_error: await scope.page.$x(`//*[contains(@class, "da-has-error")][not(contains(@style,"display: none"))]`),
|
|
1685
1685
|
system_error: await scope.page.$x( '//meta[@content="docassemble: Error"]' ),
|
|
1686
1686
|
};
|
|
@@ -1703,13 +1703,13 @@ module.exports = {
|
|
|
1703
1703
|
throwPageError: async function ( scope, { error_handlers = {}, id = '' }) {
|
|
1704
1704
|
/* Throw a cucumber error with the error that appeared on the page. */
|
|
1705
1705
|
if ( error_handlers.system_error !== undefined ) {
|
|
1706
|
-
let sys_err_message = `The test tried to continue to the next page, but there was a system error. Check the screenshot.`
|
|
1706
|
+
let sys_err_message = `The test tried to continue to the next page after ${ id }, but there was a system error. Check the screenshot.`
|
|
1707
1707
|
await scope.addToReport(scope, { type: `error`, value: sys_err_message });
|
|
1708
1708
|
expect( was_system_error, sys_err_message ).to.be.false;
|
|
1709
1709
|
|
|
1710
1710
|
} else {
|
|
1711
1711
|
// If it wasn't a system error, it was a user error
|
|
1712
|
-
let user_err_message = `The test tried to continue to the next page, but the user got an error. Check the screenshot.`
|
|
1712
|
+
let user_err_message = `The test tried to continue to the next page after ${ id }, but the user got an error. Check the screenshot.`
|
|
1713
1713
|
await scope.addToReport(scope, { type: `error`, value: user_err_message });
|
|
1714
1714
|
expect( true, user_err_message ).to.be.false;
|
|
1715
1715
|
}
|
package/lib/steps.js
CHANGED
|
@@ -33,7 +33,7 @@ require("dotenv").config(); // Where did this go?
|
|
|
33
33
|
1. 'choice' to have a more specific way to access each item. For
|
|
34
34
|
example, for a list collect or other things that have multiple
|
|
35
35
|
things with the same text on the page.
|
|
36
|
-
1. Figure out how to test allowing
|
|
36
|
+
1. Figure out how to test allowing flexibility for coder. For example:
|
|
37
37
|
there is placeholder text for the title of the form and if it's not
|
|
38
38
|
defined, placeholder text should appear (though that behavior may
|
|
39
39
|
bear discussion).
|
|
@@ -180,7 +180,7 @@ Given(/I start the interview at "([^"]+)"(?: in lang "([^"]+)")?/, {timeout: -1}
|
|
|
180
180
|
|
|
181
181
|
// If response has a file in it that matches the file we are downloading
|
|
182
182
|
if ( response._headers['content-disposition'] && (response._headers['content-disposition']).includes(`attachment;filename=${scope.toDownload}`) ) {
|
|
183
|
-
// We're
|
|
183
|
+
// We're choosing to avoid removing the event listener in case removal
|
|
184
184
|
// would prevent downloading other files. The listener should get
|
|
185
185
|
// destroyed when the page closes anyway.
|
|
186
186
|
|
|
@@ -219,7 +219,7 @@ Given(/I start the interview at "([^"]+)"(?: in lang "([^"]+)")?/, {timeout: -1}
|
|
|
219
219
|
await custom_lang_timeout;
|
|
220
220
|
|
|
221
221
|
|
|
222
|
-
let
|
|
222
|
+
let custom_afterStep_timeout = new Promise(async ( resolve, reject ) => {
|
|
223
223
|
let page_timeout = setTimeout(function() { reject(`\`afterStep()\` took too long.`); }, scope.timeout);
|
|
224
224
|
// self-invoke an anonymous async function so we don't have to
|
|
225
225
|
// abstract the details of resolving and rejecting.
|
|
@@ -230,8 +230,8 @@ Given(/I start the interview at "([^"]+)"(?: in lang "([^"]+)")?/, {timeout: -1}
|
|
|
230
230
|
// prevent temporary hang at end of tests
|
|
231
231
|
finally { clearTimeout( page_timeout ); }
|
|
232
232
|
})();
|
|
233
|
-
}); // ends
|
|
234
|
-
await
|
|
233
|
+
}); // ends custom_afterStep_timeout
|
|
234
|
+
await custom_afterStep_timeout;
|
|
235
235
|
});
|
|
236
236
|
|
|
237
237
|
Given(/I (?:sign|log) ?(?:in)?(?:on)?(?:to the server)? with(?: the email)? "([^"]+)" and(?: the password)? "([^"]+)"(?: SECRETs)?/i, {timeout: -1}, async ( email, password ) => {
|
|
@@ -252,7 +252,7 @@ Given(/I (?:sign|log) ?(?:in)?(?:on)?(?:to the server)? with(?: the email)? "([^
|
|
|
252
252
|
);
|
|
253
253
|
});
|
|
254
254
|
|
|
255
|
-
// I am using a
|
|
255
|
+
// I am using a mobile/pc
|
|
256
256
|
When(/I am using an? (.*)/, async ( device ) => {
|
|
257
257
|
// Let developer pick mobile device if they want to
|
|
258
258
|
// TODO: Add tablet?
|
|
@@ -350,7 +350,7 @@ When(/^(?:the user gets)?(?:I get)? to ?(?:the)?(?: ?question)?(?: id)? "([^"]+)
|
|
|
350
350
|
for ( let row of supported_table ) {
|
|
351
351
|
row.report_str = `${ await scope.convertToOriginalStoryTableRow(scope, { row_data: row }) }`;
|
|
352
352
|
}
|
|
353
|
-
// Sort into
|
|
353
|
+
// Sort into alphabetical order, as is recommended for writing story tables
|
|
354
354
|
let sorted_rows = supported_table.sort( function ( row1, row2 ) {
|
|
355
355
|
if( row1.report_str < row2.report_str ) { return -1; }
|
|
356
356
|
if( row1.report_str > row2.report_str ) { return 1; }
|
|
@@ -404,7 +404,7 @@ When(/I wait (\d*\.?\d+) seconds?/, { timeout: -1 }, async ( seconds ) => {
|
|
|
404
404
|
* - Should this really reset the 'navigated' flag? Should the below
|
|
405
405
|
* return succeed or fail? e.g:
|
|
406
406
|
* I tap to continue; I wait 10 seconds; I arrive at the next page;
|
|
407
|
-
* Maybe the '
|
|
407
|
+
* Maybe the 'navigated' flag should only be reset just before trying to
|
|
408
408
|
* navigate (after pressing a button)
|
|
409
409
|
*/
|
|
410
410
|
return wrapPromiseWithTimeout(
|
|
@@ -426,7 +426,7 @@ Then(/I take a screenshot ?(?:named "([^"]+)")?/, { timeout: -1 }, async ( name
|
|
|
426
426
|
When("I do nothing", async () => { await scope.afterStep(scope); }); // √
|
|
427
427
|
|
|
428
428
|
Then('the question id should be {string}', { timeout: -1 }, async ( question_id ) => {
|
|
429
|
-
/* Looks for a
|
|
429
|
+
/* Looks for a sanitized version of the question id as it's written
|
|
430
430
|
* in the .yml. docassemble's way */
|
|
431
431
|
let { question_has_id, id, id_matches } = await scope.examinePageID( scope, question_id );
|
|
432
432
|
|
|
@@ -449,7 +449,7 @@ Then('the question id should be {string}', { timeout: -1 }, async ( question_id
|
|
|
449
449
|
});
|
|
450
450
|
|
|
451
451
|
// Allow emphasis with capital letters
|
|
452
|
-
Then(/I should see the phrase "([^"]+)"/i, async ( phrase ) => { // √
|
|
452
|
+
Then(/I ?(?:should)? see the phrase "([^"]+)"/i, async ( phrase ) => { // √
|
|
453
453
|
/* In Chrome, this `innerText` gets only visible text */
|
|
454
454
|
const bodyText = await scope.page.$eval('body', elem => elem.innerText);
|
|
455
455
|
|
|
@@ -567,7 +567,7 @@ Then('I arrive at the next page', async () => { // √
|
|
|
567
567
|
|
|
568
568
|
// Link observations have the 'Escape' button link in mind
|
|
569
569
|
Then('I should see the link {string}', async ( linkText ) => { // √
|
|
570
|
-
/*
|
|
570
|
+
/* Loosely match link visible text. Should probably deprecate this. */
|
|
571
571
|
let [link] = await scope.page.$x(`//a[contains(text(), "${linkText}")]`);
|
|
572
572
|
|
|
573
573
|
let msg = `Cannot find a link with the text "${ linkText }".`;
|
|
@@ -668,7 +668,7 @@ Then(/I get the(?: page's)?(?: JSON)? var(?:iable)?s and val(?:ue)?s/i, { timeou
|
|
|
668
668
|
* to get the variable values on the page of the interview and add
|
|
669
669
|
* them to the report.
|
|
670
670
|
*
|
|
671
|
-
*
|
|
671
|
+
* Variations:
|
|
672
672
|
* I get the page's JSON variables and values
|
|
673
673
|
* I get the json vars and vals
|
|
674
674
|
* I get the page's vars and vals
|
package/lib/utils/langs.js
CHANGED
|
@@ -20,7 +20,7 @@ for ( let full_path of filepaths ) { // Handle old language files before creati
|
|
|
20
20
|
// Don't apply this to the example test that this package always provides
|
|
21
21
|
if ( full_path.includes( 'example_test.feature' )) { continue; }
|
|
22
22
|
|
|
23
|
-
// Delete
|
|
23
|
+
// Delete already existing non-default language files and skip the rest of this. For example,
|
|
24
24
|
// if 3 languages were tested previously and now only two are being tested.
|
|
25
25
|
if ( full_path.includes( flag )) {
|
|
26
26
|
fs.unlinkSync( full_path );
|
|
@@ -10,7 +10,7 @@ require('dotenv').config();
|
|
|
10
10
|
/* This file provides user info variables. E.g. server address. They're either
|
|
11
11
|
* `process.env` vars or vars that have been built from `process.env` vars.
|
|
12
12
|
* It is meant to avoid duplication, make testing easier, and leave room for
|
|
13
|
-
* future
|
|
13
|
+
* future manipulation. No other file should need to use `process.env`.
|
|
14
14
|
*
|
|
15
15
|
* We have a bunch of `.get_foo()` functions partly because it makes the code
|
|
16
16
|
* much easier to test.
|
|
@@ -105,7 +105,7 @@ session_vars.get_project_name = function () {
|
|
|
105
105
|
|
|
106
106
|
session_vars.delete_project_name = function () {
|
|
107
107
|
/* Delete the file storing the name of the docassemble project */
|
|
108
|
-
// Avoid race
|
|
108
|
+
// Avoid race conditions possibly caused by checking for existence first
|
|
109
109
|
// Delete file if possible
|
|
110
110
|
try {
|
|
111
111
|
fs.unlinkSync( project_name_file_path );
|