@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.
@@ -88,5 +88,5 @@ jobs:
88
88
  #### Developer note: Useful for temporarily shortening ALKiln tests
89
89
  #### to debug the docker install step
90
90
  # ALKILN_TAG_EXPRESSION: @a_tag_expression
91
- ALKILN_VERSION: 5.8.1-feat2columns2
91
+ ALKILN_VERSION: 5.8.1-feat2columns4
92
92
 
@@ -55,4 +55,4 @@ jobs:
55
55
  #### to debug the docker install step
56
56
  # ALKILN_TAG_EXPRESSION: @a_tag_expression
57
57
  #### Developer note: you probalby don't need this
58
- ALKILN_VERSION: 5.8.1-feat2columns2
58
+ ALKILN_VERSION: 5.8.1-feat2columns4
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. See `
1486
- + `https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/alkiln/#trigger.`
1487
- + `\nThe matching rows:\n${ rows_as_story_table.join(`\n`) }`
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
- num_unused_rows += 1;
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 msg = `Did not find a field on this page for the variable "${ original_row.var }" that could be set to "${ original_row.value }"`;
2160
- reports.addToReport(scope, { type: `warning`, value: msg });
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 "(passed|failed)"/i, async ( expected_status ) => {
1246
- /* WARNING: If a Step will fail, this Step must come first.
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
- // Internal tests of this framework
1329
- if ( scope.expected_status ) {
1330
- let expected = scope.expected_status;
1331
- scope.expected_status = null; // reset for next Scenario
1332
- expect( changeable_test_status ).to.equal( expected );
1333
- // If the status was as expected, pass this criteria
1334
- changeable_test_status = `PASSED`;
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 expected = scope.expected_in_report;
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 not_expected = scope.expected_not_in_report;
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
- let all_were_not_there = await scope.reportDoesNotInclude( scope, { not_expected });
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
- // Other types of errors should be ok
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suffolklitlab/alkiln",
3
- "version": "5.8.1-feat2columns2",
3
+ "version": "5.8.1-feat2columns4",
4
4
  "description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {