@suffolklitlab/alkiln 5.8.1-feat2columns2 → 5.8.1-feat2columns4
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/github_server.yml +1 -1
- package/.github/workflows/playground.yml +1 -1
- package/CHANGELOG.md +4 -0
- package/docs/expected_inernal_results.md +15 -0
- package/lib/scope.js +13 -58
- package/lib/steps.js +45 -34
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -45,6 +45,10 @@ Format:
|
|
|
45
45
|
|
|
46
46
|
<!-- ## [Unreleased] -->
|
|
47
47
|
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- 2-column Story Tables that work without the trigger variable. Now column 1, "var", should only contain the actual variable name with no proxies (x, i, j, etc). For example, instead of `x[i].name.first` the var column should now contain `users[0].name.first`. Column 2 is the same as it was before - the answer for the field. See [#582](https://github.com/SuffolkLITLab/ALKiln/issues/582).
|
|
51
|
+
|
|
48
52
|
## [5.8.1] - 2023-12-28
|
|
49
53
|
|
|
50
54
|
### Fixed
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# What results are we expecting in our own tests?
|
|
2
|
+
|
|
3
|
+
Our internal test results look a little strange. For example, they sometimes initially look like they're failing, but eventually pass. That's because we're testing that our tests respond appropriately to authors' failures as well as successees.
|
|
4
|
+
|
|
5
|
+
These are the results that we expect:
|
|
6
|
+
|
|
7
|
+
## Cucumber feature tests {#cucumber}
|
|
8
|
+
|
|
9
|
+
- Many red `F`s in our cucumber "progress bar"
|
|
10
|
+
- Final results to show all Scenarios passing
|
|
11
|
+
- Cucumber seems to be unable to print the name of the first scenario
|
|
12
|
+
|
|
13
|
+
## Unit tests {#unit}
|
|
14
|
+
|
|
15
|
+
All these must pass
|
package/lib/scope.js
CHANGED
|
@@ -721,51 +721,6 @@ module.exports = {
|
|
|
721
721
|
return result;
|
|
722
722
|
}, // Ends scope.getLoadData()
|
|
723
723
|
|
|
724
|
-
// three_column_table_warning: async function ( scope, { var_data=null, raw_var_data=null }) {
|
|
725
|
-
|
|
726
|
-
// },
|
|
727
|
-
|
|
728
|
-
// normalize_table_base: async function ( scope, { var_data=null, raw_var_data=null }) {
|
|
729
|
-
// /* Return data derived from cucumber variable-setting data, from either an object format
|
|
730
|
-
// * (var_data) or an array format (raw_var_data). `var_data` only is used when calling
|
|
731
|
-
// * normalizeTable internally.
|
|
732
|
-
// *
|
|
733
|
-
// * Takes care of the shared funcitonality that needs to happen to all tables.
|
|
734
|
-
// */
|
|
735
|
-
|
|
736
|
-
// if (!var_data && ! raw_var_data) {
|
|
737
|
-
// let no_data_msg = `ALKiln Internal error: normalizeTable called w/o var_data or raw_var_data:` +
|
|
738
|
-
// ` open an issue at https://github.com/SuffolkLITLab/ALKiln/issues/new if you see this!`;
|
|
739
|
-
// reports.addToReport( scope, { type: `error`, value: no_data_msg });
|
|
740
|
-
// throw Error(no_data_msg);
|
|
741
|
-
// }
|
|
742
|
-
|
|
743
|
-
// // Always use the raw var data if present; it has the full first row
|
|
744
|
-
// if (raw_var_data) {
|
|
745
|
-
// var_data = raw_var_data.hashes();
|
|
746
|
-
// if (!('var' in var_data[0]) || !('value' in var_data[0])) {
|
|
747
|
-
// let raw_array = raw_var_data.raw();
|
|
748
|
-
// var_data = [];
|
|
749
|
-
// for (let row_raw of raw_array) {
|
|
750
|
-
// if (row_raw.length < 2) {
|
|
751
|
-
// let bad_table_msg = `Your Story Table has less than 2 columns.`
|
|
752
|
-
// + ` Take another look at Story Table documentation at`
|
|
753
|
-
// + ` https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/alkiln/#story-tables.`
|
|
754
|
-
// reports.addToReport( scope, { type: `error`, value: bad_table_msg})
|
|
755
|
-
// throw Error(bad_table_msg);
|
|
756
|
-
// } else if (row_raw.length == 2) {
|
|
757
|
-
// var_data.push({var: row_raw[0], value: row_raw[1]});
|
|
758
|
-
// } else {
|
|
759
|
-
// var_data.push({var: row_raw[0], value: row_raw[1], trigger: row_raw[2]});
|
|
760
|
-
// }
|
|
761
|
-
// }
|
|
762
|
-
// }
|
|
763
|
-
// }
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
// },
|
|
768
|
-
|
|
769
724
|
normalizeTable: async function ( scope, { var_data=null, raw_var_data=null }) {
|
|
770
725
|
/* Return data derived from cucumber variable-setting data, from either an object format
|
|
771
726
|
* (var_data) or an array format (raw_var_data). `var_data` only is used when calling
|
|
@@ -1482,9 +1437,12 @@ module.exports = {
|
|
|
1482
1437
|
|
|
1483
1438
|
let multiple_matches_msg = `Do you have a duplicate story table row? `
|
|
1484
1439
|
+ `Multiple story table rows match this field's variable name. `
|
|
1485
|
-
+ `The test will use the last row that matched
|
|
1486
|
-
|
|
1487
|
-
|
|
1440
|
+
+ `The test will use the last row that matched.`
|
|
1441
|
+
|
|
1442
|
+
if ( trigger_might_be_needed ) {
|
|
1443
|
+
multiple_matches_msg += ` See https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/alkiln/#trigger.`
|
|
1444
|
+
}
|
|
1445
|
+
multiple_matches_msg += `\nThe matching rows:\n${ rows_as_story_table.join(`\n`) }`
|
|
1488
1446
|
+ `\nThis field's data:\n${ JSON.stringify( field )}`;
|
|
1489
1447
|
reports.addToReport(scope, { type: `warning`, value: multiple_matches_msg });
|
|
1490
1448
|
}
|
|
@@ -2148,24 +2106,21 @@ module.exports = {
|
|
|
2148
2106
|
|
|
2149
2107
|
// If all table rows must be used and any table row was not, error
|
|
2150
2108
|
if ( ensure_all_vars_used ) {
|
|
2151
|
-
let num_unused_rows = 0;
|
|
2152
2109
|
for ( let row of var_data ) {
|
|
2153
2110
|
if ( row.times_used === 0 ) {
|
|
2154
|
-
|
|
2111
|
+
let values_used_status = 'The page is missing a value';
|
|
2155
2112
|
let source_row = row;
|
|
2156
2113
|
// TODO: Make the row object flatter so we don't need to dig in this way
|
|
2157
2114
|
if ( row.source ) { source_row = row.source; }
|
|
2158
2115
|
let original_row = source_row.original;
|
|
2159
|
-
let
|
|
2160
|
-
|
|
2116
|
+
let { id } = await scope.examinePageID( scope, 'none to match' );
|
|
2117
|
+
let msg = `In a linear Step all the values you give MUST be filled in, but ALKiln was unable `
|
|
2118
|
+
+ `to find a field on the page "${id}" for the variable "${ original_row.var }" that `
|
|
2119
|
+
+ `could be set to "${ original_row.value }". See this Scenario's HTML file for details.`;
|
|
2120
|
+
reports.addToReport(scope, { type: `error`, value: msg });
|
|
2121
|
+
expect( values_used_status, msg ).to.equal( '' );
|
|
2161
2122
|
}
|
|
2162
2123
|
}
|
|
2163
|
-
if ( num_unused_rows > 0 ) {
|
|
2164
|
-
let { id } = await scope.examinePageID( scope, 'none to match' );
|
|
2165
|
-
let msg = `Error on page "${id}". See screenshot and see text above for more details.`;
|
|
2166
|
-
reports.addToReport(scope, { type: `error`, value: msg });
|
|
2167
|
-
expect( num_unused_rows, msg ).to.equal( 0 );
|
|
2168
|
-
}
|
|
2169
2124
|
}
|
|
2170
2125
|
|
|
2171
2126
|
// If didn't already press a continue button, press one now.
|
package/lib/steps.js
CHANGED
|
@@ -106,6 +106,12 @@ BeforeAll(async () => {
|
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
Before(async (scenario) => {
|
|
109
|
+
|
|
110
|
+
// Useful for those with a lot of tests
|
|
111
|
+
// Is unable to print the first Scenario name for some reason
|
|
112
|
+
console.log('');
|
|
113
|
+
process.stdout.write(`Scenario: ${ scenario.pickle.name }: `);
|
|
114
|
+
|
|
109
115
|
// Create browser, which can't be created in BeforeAll() where .driver doesn't exist for some reason
|
|
110
116
|
if (!scope.browser) {
|
|
111
117
|
if (session_vars.get_origin() === 'playground') {
|
|
@@ -297,7 +303,9 @@ Given(/the max(?:imum)? sec(?:ond)?s for each step (?:in this scenario )?is (\d+
|
|
|
297
303
|
// Story
|
|
298
304
|
//#####################################
|
|
299
305
|
//#####################################
|
|
300
|
-
|
|
306
|
+
// TODO: Consider more permissive sentences:
|
|
307
|
+
// with(?: this data| these answers)?:?
|
|
308
|
+
// with(?:.*):?
|
|
301
309
|
When(/^(?:the user gets)?(?:I get)? to ?(?:the)?(?: ?question)?(?: id)? "([^"]+)" with this data:?/, {timeout: -1}, async (target_id, raw_var_data) => {
|
|
302
310
|
/* NO CUCUMBER TIMEOUT. Must handle timeout ourselves:
|
|
303
311
|
* https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/timeouts.md#disable-timeouts
|
|
@@ -1242,8 +1250,8 @@ Given(/the Scenario report should not include/i, async ( report_text ) => {
|
|
|
1242
1250
|
|
|
1243
1251
|
});
|
|
1244
1252
|
|
|
1245
|
-
Given(/the final Scenario status should be "(
|
|
1246
|
-
|
|
1253
|
+
Given(/the final Scenario status should be "([^"]+)"/i, async ( expected_status ) => {
|
|
1254
|
+
/** WARNING: If a Step will fail, this Step must come first.
|
|
1247
1255
|
*
|
|
1248
1256
|
* Prepare to test that the Scenario completes with the correct status. */
|
|
1249
1257
|
scope.expected_status = expected_status.toUpperCase();
|
|
@@ -1325,39 +1333,46 @@ After(async function(scenario) {
|
|
|
1325
1333
|
|
|
1326
1334
|
} // ends if not passed
|
|
1327
1335
|
|
|
1328
|
-
//
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1336
|
+
// Add report text to Scenario folder after everything has been added to the report
|
|
1337
|
+
let current_report_obj = scope.report.get( scope.scenario_id );
|
|
1338
|
+
let scenario_report_obj = [ scope.scenario_id, current_report_obj ]; // Mimic how loop works with `Map`
|
|
1339
|
+
let report = reports.getPrintableScenario( scenario_report_obj );
|
|
1340
|
+
// Save the report as in the Scenario folder
|
|
1341
|
+
fs.writeFileSync( scope.paths.scenario_report, report );
|
|
1342
|
+
|
|
1343
|
+
// ---------------- Check internal test results of this framework ----------------
|
|
1344
|
+
|
|
1337
1345
|
if ( scope.expected_in_report && scope.expected_in_report.length > 0) {
|
|
1338
|
-
let
|
|
1346
|
+
let report_includes_all_expected_strings = await scope.reportIncludesAllExpected(
|
|
1347
|
+
scope,
|
|
1348
|
+
{ expected: scope.expected_in_report }
|
|
1349
|
+
);
|
|
1350
|
+
if ( !report_includes_all_expected_strings ) { changeable_test_status = `FAILED`; }
|
|
1339
1351
|
// Reset report values no matter what so they don't mess up future scenarios
|
|
1340
1352
|
scope.expected_in_report = null;
|
|
1341
|
-
let all_were_included = await scope.reportIncludesAllExpected( scope, { expected });
|
|
1342
|
-
|
|
1343
|
-
if ( all_were_included ) { changeable_test_status = `PASSED`; }
|
|
1344
|
-
else { changeable_test_status = `FAILED`; }
|
|
1345
1353
|
}
|
|
1346
1354
|
|
|
1347
1355
|
if (scope.expected_not_in_report && scope.expected_not_in_report.length > 0) {
|
|
1348
|
-
let
|
|
1356
|
+
let all_prohibited_strings_were_absent = await scope.reportDoesNotInclude(
|
|
1357
|
+
scope,
|
|
1358
|
+
{ not_expected: scope.expected_not_in_report }
|
|
1359
|
+
);
|
|
1360
|
+
if ( !all_prohibited_strings_were_absent ) { changeable_test_status = `FAILED`;}
|
|
1349
1361
|
// Reset report values no matter what so they don't mess up future scenarios
|
|
1350
1362
|
scope.expected_not_in_report = null;
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
if ( all_were_not_there ) {
|
|
1354
|
-
changeable_test_status = `PASSED`;
|
|
1355
|
-
} else {
|
|
1356
|
-
changeable_test_status = `FAILED`;
|
|
1357
|
-
}
|
|
1363
|
+
}
|
|
1358
1364
|
|
|
1365
|
+
// The default is 'passed', which won't need to get in here
|
|
1366
|
+
if ( scope.expected_status ) {
|
|
1367
|
+
// When internal tests should fail (to test our failure conditions), passing _is_ failing
|
|
1368
|
+
expect( changeable_test_status ).to.equal( scope.expected_status );
|
|
1369
|
+
// If the status was as expected, pass this Scenario
|
|
1370
|
+
changeable_test_status = `PASSED`;
|
|
1371
|
+
scope.expected_status = null; // reset for next Scenario
|
|
1359
1372
|
}
|
|
1360
1373
|
|
|
1374
|
+
// ---------------- Ends check internal test results of this framework ----------------
|
|
1375
|
+
|
|
1361
1376
|
// If there is a page open, then sign out and close it
|
|
1362
1377
|
if ( scope.page ) {
|
|
1363
1378
|
// Catch a possible reload error.
|
|
@@ -1385,23 +1400,19 @@ After(async function(scenario) {
|
|
|
1385
1400
|
|
|
1386
1401
|
} // ends if scope.page
|
|
1387
1402
|
|
|
1388
|
-
// Add report text to Scenario folder after everything has been added to the report
|
|
1389
|
-
let current_report_obj = scope.report.get( scope.scenario_id );
|
|
1390
|
-
let scenario_report_obj = [ scope.scenario_id, current_report_obj ]; // Mimic how loop works with `Map`
|
|
1391
|
-
let report = reports.getPrintableScenario( scenario_report_obj );
|
|
1392
|
-
// Save the report as in the Scenario folder
|
|
1393
|
-
fs.writeFileSync( scope.paths.scenario_report, report );
|
|
1394
|
-
|
|
1395
1403
|
if ( changeable_test_status === `FAILED` ) {
|
|
1396
1404
|
// If the result object status wasn't failure and we still want
|
|
1397
1405
|
// the tests to fail, as with a11y tests, we can't mess with the
|
|
1398
1406
|
// cucumber result.status object because it will cause unwanted
|
|
1399
1407
|
// errors. We have to throw an error here instead.
|
|
1400
1408
|
if ( scenario.result.status !== `FAILED` ) {
|
|
1401
|
-
throw new Error(`The test failed. See the report for more information.`);
|
|
1409
|
+
throw new Error(`The test failed. See the report above for more information.`);
|
|
1402
1410
|
}
|
|
1403
1411
|
} else {
|
|
1404
|
-
//
|
|
1412
|
+
// Some internal test failures should be ok
|
|
1413
|
+
// TODO: Look into setDefinitionFunctionWrapper to catch errors
|
|
1414
|
+
// of failing tests that should indeed be failing:
|
|
1415
|
+
// https://github.com/cucumber/cucumber-js/blob/main/docs/support_files/api_reference.md#setdefinitionfunctionwrapperwrapper
|
|
1405
1416
|
scenario.result.status = changeable_test_status;
|
|
1406
1417
|
}
|
|
1407
1418
|
});
|
package/package.json
CHANGED