@suffolklitlab/alkiln 4.1.0 → 4.1.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.
@@ -31,6 +31,9 @@ jobs:
31
31
  REPO_URL: https://github.com/plocket/docassemble-ALAutomatedTestingTests
32
32
  USER1_EMAIL: ${{ secrets.USER1_EMAIL }}
33
33
  USER1_PASSWORD: ${{ secrets.USER1_PASSWORD }}
34
+ SECRET_VAR1: secret-var1-value
35
+ SECRET_VAR2: secret-var2-value
36
+ SECRET_FOR_MISSING_FIELD: secret for missing field
34
37
 
35
38
  name: Run Puppeteer tests
36
39
  steps:
package/CHANGELOG.md CHANGED
@@ -39,7 +39,7 @@ Format:
39
39
  -
40
40
  -->
41
41
  <!-- ## [Unreleased] -->
42
- ## [4.1.0] - 2022-04-01
42
+ ## [4.1.1] - 2022-04-01
43
43
  ### Added
44
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.
45
45
 
package/lib/scope.js CHANGED
@@ -22,6 +22,30 @@ let escape_regex = function( to_escape ) {
22
22
  return to_escape.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
23
23
  };
24
24
 
25
+ let get_original_row = function (row) {
26
+ /* `row` might be a row, a source row, or an original row. */
27
+
28
+ // Until we flatten row data a litte, we need to find the `orignal` row, which has the flags
29
+ let source_row = row.source || row;
30
+ let original = source_row.original || source_row;
31
+ return original;
32
+ }
33
+
34
+ let printable_var_value = function(row) {
35
+ /* `row` might be a row, a source row, or an original row. */
36
+ let original = get_original_row(row);
37
+ if ( is_secret_var(original) ) {
38
+ return original.flags.secret_name;
39
+ }
40
+ return row.value;
41
+ };
42
+
43
+ let is_secret_var = function(row) {
44
+ /* `row` might be a row, a source row, or an original row. */
45
+ let original = get_original_row(row);
46
+ return original.flags !== undefined && original.flags.secret_name !== undefined;
47
+ }
48
+
25
49
  let proxies_regex = /(\bx\.)|(\bx\[)|(\[[ijklmn]\])/g;
26
50
 
27
51
  module.exports = {
@@ -467,19 +491,29 @@ module.exports = {
467
491
 
468
492
  normalizeTable: async function ( scope, { var_data, from_story_table=true }) {
469
493
  /* Return data derived from cucumber variable-setting data.
470
- * Table must have headers. Arrays are not supported. */
494
+ * Table must have headers. Arrays are not supported. */
471
495
 
472
496
  // Support tables with no 'trigger' column
473
497
  let supported_table = [];
474
498
  for ( let row of var_data ) {
475
499
  // See tests > unit_tests > tables.fixtures.js > tables.old_to_current_formatting
500
+ let actual_var_value = row.value;
501
+ if (is_secret_var(row)) {
502
+ actual_var_value = process.env[row.flags.secret_name];
503
+ if ( actual_var_value === undefined ) {
504
+ let not_in_env_msg = `The GitHub SECRET "${ row.flags.secret_name }" doesn't exist. Check for a typo and check your workflow file.`;
505
+ await scope.addToReport( scope, { type: `error`, value: not_in_env_msg })
506
+ throw ReferenceError(`Could not find "${row.flags.secret_name }": ${not_in_env_msg}.`)
507
+ }
508
+ }
509
+
476
510
  let result = {
477
511
  original: row,
478
512
  // Give fake data if needed to prevent some kind of hidden input field from being found
479
513
  // See bug at https://github.com/plocket/docassemble-cucumber/issues/79
480
514
  // May be able to remove this once converted to `getAllFields`
481
515
  var: row.var || 'al_no_var_name',
482
- value: row.value,
516
+ value: actual_var_value,
483
517
  trigger: row.trigger || '',
484
518
  times_used: 0,
485
519
  }
@@ -487,7 +521,9 @@ module.exports = {
487
521
  supported_table.push( result );
488
522
  }
489
523
 
490
- if ( session_vars.get_debug() ) { console.log( 'scope.normalizedTable():\n', JSON.stringify( supported_table )); }
524
+ if ( session_vars.get_debug() ) {
525
+ console.log( 'scope.normalizedTable():\n', JSON.stringify( supported_table ));
526
+ }
491
527
 
492
528
  return supported_table;
493
529
  }, // Ends scope.normalizeTable()
@@ -1506,9 +1542,10 @@ module.exports = {
1506
1542
  if ( row.times_used === 0 ) {
1507
1543
  num_unused_rows += 1;
1508
1544
  let source_row = row;
1545
+ // TODO: Make the row object flatter so we don't need to dig in this way
1509
1546
  if ( row.source ) { source_row = row.source; }
1510
1547
  let original_row = source_row.original;
1511
- let msg = `Did not find a field on this page for the variable \`${ original_row.var }\` that could be set to \`${ original_row.value }\``;
1548
+ let msg = `Did not find a field on this page for the variable "${ original_row.var }" that could be set to "${ original_row.value }"`;
1512
1549
  await scope.addToReport(scope, { type: `warning`, value: msg });
1513
1550
  }
1514
1551
  }
@@ -1610,20 +1647,24 @@ module.exports = {
1610
1647
  * This may in future be used to normalize all values that need `True`/`False`
1611
1648
  * normalization.
1612
1649
  */
1613
- let value = row.value;
1650
+ let value = row.value.toLowerCase();
1651
+ let val_to_print = printable_var_value(row);
1614
1652
  let int_val = parseInt( value );
1615
1653
 
1616
1654
  // Step stuff. Take into account a lot of possible values
1617
1655
  if ( value.match( /(false|no|unchecked|uncheck|deselected|deselect)/i )) {
1656
+ // Should this also contain a warning if this is trying to set `target_number`?
1618
1657
  return `False`;
1619
1658
 
1620
1659
  } else if ( value.match( /(true|yes|checked|check|selected|select)/i )) {
1621
1660
  if ( from_story_table ) {
1622
- // Just in case, but this should never happen.
1623
1661
  if ( row.var.match( /\.there_is_another$/ ) ) {
1662
+ // `.there_is_another` should never get in here, but just in case
1624
1663
  await scope.addToReport( scope, { type: `warning`, value: `The attribute \`.there_is_another\` is invalid in story table tests. Replace it with \`.target_number\` in your \`var\` column. Set the \`value\` to the number of items in that list. This test will now set this row's \`value\` to \`False\`. See https://suffolklitlab.github.io/docassemble-AssemblyLine-documentation/docs/automated_integrated_testing#there_is_another-loop. The row data is\n${ JSON.stringify( row.original )}` });
1625
1664
  } else {
1626
- await scope.addToReport( scope, { type: `warning`, value: `${ value } is not a valid value for ${ row.var } here. This test will default to \`False\` to avoid problems.` });
1665
+ // If `target_number` is set to True instead of a number
1666
+ // Since secret vars can't be passed in a table, this should never be a secret var
1667
+ await scope.addToReport( scope, { type: `warning`, value: `${ val_to_print } value is not a valid value for ${ row.var } here. This test will default to \`False\` to avoid problems.` });
1627
1668
  }
1628
1669
  return `False`;
1629
1670
  } else { return `True`; }
@@ -1638,7 +1679,8 @@ module.exports = {
1638
1679
  return `False`;
1639
1680
 
1640
1681
  } else if ( isNaN( parseInt( value )) ) { // Loop will end
1641
- await scope.addToReport( scope, { type: `warning`, value: `${ value } is not a valid value for ${ row.var } here. This test will default to \`False\` to avoid problems.` });
1682
+ // I can't figure out how to trigger this warning either
1683
+ await scope.addToReport( scope, { type: `warning`, value: `${ val_to_print } value is not a valid value for ${ row.var } here. This test will default to \`False\` to avoid problems.` });
1642
1684
  return `False`;
1643
1685
 
1644
1686
  } else { // It's a number. Loop will continue.
@@ -1792,6 +1834,21 @@ module.exports = {
1792
1834
  await scope.setFields( scope, { var_data, ensure_navigation: false, ensure_all_vars_used: true });
1793
1835
  }, // Ends set_regular_var()
1794
1836
 
1837
+ set_secret_var: async ( scope, var_name, set_to_env_name ) => {
1838
+ /** Sets a non-story table variable to a "secret" value (i.e. an env var) */
1839
+ let var_data = await scope.normalizeTable( scope, {
1840
+ var_data: [{
1841
+ var: var_name,
1842
+ value: set_to_env_name,
1843
+ trigger: scope.trigger_not_needed_flag,
1844
+ flags: {secret_name: set_to_env_name}
1845
+ }],
1846
+ });
1847
+ // Don't continue if the variable doesn't cause navigation itself. Also,
1848
+ // if this variable cannot be set on this page, trigger an error
1849
+ await scope.setFields( scope, { var_data, ensure_navigation: false, ensure_all_vars_used: true });
1850
+ },
1851
+
1795
1852
  tap_term: async ( scope, phrase ) => {
1796
1853
  /** Tap a link that doesn't navigate. Depends on the language of the text. */
1797
1854
  const [link] = await scope.page.$x(`//a[contains(text(), "${phrase}")]`);
package/lib/steps.js CHANGED
@@ -14,13 +14,11 @@ const wrapPromiseWithTimeout = require('./cucumber_8_shim');
14
14
  const fs = require('fs');
15
15
  const path = require('path');
16
16
  const { expect } = require('chai');
17
- const puppeteer = require('puppeteer');
18
17
  const { v4: uuidv4 } = require('uuid');
19
18
 
20
19
  // Ours
21
20
  const scope = require('./scope');
22
21
  const session_vars = require('./utils/session_vars');
23
-
24
22
  /* Of Note:
25
23
  - We're using `*=` because sometimes da text has funny characters in it that are hard to anticipate
26
24
  */
@@ -735,6 +733,15 @@ When(/I set the var(?:iable)? "([^"]+)" to "([^"]+)"/, { timeout: -1 }, async (
735
733
  );
736
734
  });
737
735
 
736
+ When(/I set the var(?:iable)? "([^"]+)" to ?(?:the)? ?(?:GitHub)? secret "([^"]+)"/i, { timeout: -1 }, async ( var_name, set_to_env_name ) => {
737
+ /* Set a non-story table variable to a secrete value. Same as the above, but reads the value from `process.env` */
738
+ return wrapPromiseWithTimeout(
739
+ scope.steps.set_secret_var( scope, var_name, set_to_env_name ),
740
+ scope.timeout
741
+ );
742
+ });
743
+
744
+
738
745
  Then(/I upload "([^"]+)" to "([^"]+)"/, { timeout: -1 }, async ( filenames, var_name ) => {
739
746
  /* Uploads file (docx, jpg, etc) in same folder to input var. Can actually use
740
747
  * 'I set the var "" to ""', but this is more explicit if it's desired. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suffolklitlab/alkiln",
3
- "version": "4.1.0",
3
+ "version": "4.1.1",
4
4
  "description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -83,3 +83,21 @@ Scenario: I set text-type values
83
83
  And I tap to continue
84
84
  # Next page
85
85
  Then the question id should be "the end"
86
+
87
+ @fast @i2 @secret
88
+ Scenario: handles settings from Github secrets
89
+ Given the final Scenario status should be "failed"
90
+ And the Scenario report should include:
91
+ """
92
+ The GitHub SECRET "SECRET_NOT_THERE" doesn't exist
93
+ """
94
+ Given I start the interview at "test_secret_vars"
95
+ When I set the var "first_text_entry" to the secret "SECRET_VAR1"
96
+ And I tap to continue
97
+ Then I see the phrase "secret-var1-value"
98
+ When I tap to continue
99
+ And I set the var "second_text_entry" to the github secret "SECRET_VAR2"
100
+ And I tap to continue
101
+ Then I see the phrase "secret-var2-value"
102
+ When I tap to continue
103
+ And I set the variable "third_text_entry" to secret "SECRET_NOT_THERE"
@@ -386,6 +386,17 @@ Scenario: Fail with could not find files
386
386
  Given I start the interview at "all_tests"
387
387
  And I upload "nonexistant1.pdf, nonexistant2.pdf" to "upload_files_visible"
388
388
 
389
+ @fast @rf26 @secret @error
390
+ Scenario: Fail to find var while keeping value secret
391
+ Given the final Scenario status should be "failed"
392
+ Given the Scenario report should include:
393
+ """
394
+ Did not find a field on this page for the variable "missing_var" that could be set to "SECRET_FOR_MISSING_FIELD"
395
+ """
396
+ And I start the interview at "test_secret_vars"
397
+ And I set the var "missing_var" to the secret "SECRET_FOR_MISSING_FIELD"
398
+
399
+
389
400
  # scope.js
390
401
  # I upload "___" to "___"
391
402
  # No need to test wrong var name
@@ -409,6 +420,7 @@ Scenario: Warn when there are too many names
409
420
  And I set the name of "users[0]" to "Uli Udo User Sampson Jr"
410
421
  And I tap to continue
411
422
 
423
+
412
424
  # ===============================
413
425
  # Reports for "passed" Scenarios
414
426
  # ===============================