@suffolklitlab/alkiln 4.0.0-pre-api.7 → 4.0.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/lib/steps.js CHANGED
@@ -19,7 +19,7 @@ const { v4: uuidv4 } = require('uuid');
19
19
 
20
20
  // Ours
21
21
  const scope = require('./scope');
22
- const env_vars = require('./utils/env_vars');
22
+ const session_vars = require('./utils/session_vars');
23
23
 
24
24
  /* Of Note:
25
25
  - We're using `*=` because sometimes da text has funny characters in it that are hard to anticipate
@@ -717,7 +717,7 @@ When('I tap to continue', { timeout: -1 }, async () => {
717
717
  // --- VARIABLES-BASED STEPS ---
718
718
 
719
719
  When(/I set the var(?:iable)? "([^"]+)" to "([^"]+)"/, { timeout: -1 }, async ( var_name, set_to ) => {
720
- /* Set any variable (with or without a choice associated with it) to a value. Set:
720
+ /* Set a non-story table variable (with or without a choice associated with it) to a value. Set:
721
721
  * - Buttons associated with variables
722
722
  * - Dropdowns
723
723
  * - Checkboxes (multiple choice checkboxes must be set to "true" or "false")
@@ -725,7 +725,7 @@ When(/I set the var(?:iable)? "([^"]+)" to "([^"]+)"/, { timeout: -1 }, async (
725
725
  * - Text inputs
726
726
  * - Textareas
727
727
  *
728
- * Examples:
728
+ * Variations:
729
729
  * 1. I set the var "benefits['SSI']" to "false"
730
730
  * 1. I set the var "rent_interval" to "weekly"
731
731
  */
@@ -736,7 +736,7 @@ When(/I set the var(?:iable)? "([^"]+)" to "([^"]+)"/, { timeout: -1 }, async (
736
736
  });
737
737
 
738
738
  Then(/I upload "([^"]+)" to "([^"]+)"/, { timeout: -1 }, async ( filenames, var_name ) => {
739
- /* Uploads sibling file (docx, jpg, etc) to input var. Can actually use
739
+ /* Uploads file (docx, jpg, etc) in same folder to input var. Can actually use
740
740
  * 'I set the var "" to ""', but this is more explicit if it's desired. */
741
741
  return wrapPromiseWithTimeout(
742
742
  scope.steps.set_regular_var( scope, var_name, filenames ),
@@ -867,9 +867,9 @@ After(async function(scenario) {
867
867
  await scope.setReportScenarioStatus( scope, { status: scenario.result.status });
868
868
 
869
869
  if (scenario.result.status !== `PASSED`) {
870
- if ( env_vars.DEBUG ) {
870
+ if ( session_vars.get_debug() ) {
871
871
  console.log( `Non-passed status occurred while running test:`, scenario.result.status );
872
- // If there's a page visible, give us time to examine it
872
+ // If there's a page visible (locally), give us time to examine it
873
873
  if ( scope.page ) { await scope.page.waitForTimeout( 60 * 1000 ); }
874
874
  }
875
875
 
@@ -909,15 +909,15 @@ After(async function(scenario) {
909
909
  // Consider, instead, catching the reload error for a bad restart and just
910
910
  // re-trying at that point.
911
911
  try {
912
- await scope.page.goto(`${ env_vars.BASE_URL }/user/sign-out`, {waitUntil: `domcontentloaded`});
912
+ await scope.page.goto(`${ session_vars.get_da_server_url() }/user/sign-out`, {waitUntil: `domcontentloaded`});
913
913
  } catch ( err ) {
914
- if ( env_vars.DEBUG ) {
914
+ if ( session_vars.DEBUG ) {
915
915
  console.log( `Trying to reset for the next test a second time because the first time failed.` );
916
916
  }
917
917
 
918
918
  try {
919
- await scope.page.goto(`${ env_vars.BASE_URL }/user/sign-out`, {waitUntil: `domcontentloaded`});
920
-
919
+ await scope.page.goto(`${ session_vars.get_da_server_url() }/user/sign-out`, {waitUntil: `domcontentloaded`});
920
+
921
921
  } catch ( err ) {
922
922
  await scope.addToReport(scope, {
923
923
  type: `warning`,
@@ -4,7 +4,7 @@ let _path = require('path');
4
4
  let fs = require('fs');
5
5
  let glob = require('glob');
6
6
 
7
- let env_vars = require('./env_vars');
7
+ let session_vars = require('./session_vars');
8
8
 
9
9
  // Get the glob filepaths to find all the test files
10
10
  let dir_root = process.env.INIT_CWD; // Path to root of project
@@ -12,7 +12,7 @@ let test_glob = process.argv[2]; // String of glob (regex for filepaths)
12
12
  let filepaths = glob.sync( _path.resolve( dir_root, test_glob ) );
13
13
  let flag = '_lang_';
14
14
 
15
- let langs = env_vars.EXTRA_LANGUAGES;
15
+ let langs = session_vars.get_languages();
16
16
 
17
17
  // Generate new language files
18
18
  for ( let full_path of filepaths ) { // Handle old language files before creating new ones.
@@ -16,69 +16,22 @@ require('dotenv').config();
16
16
  * much easier to test.
17
17
  */
18
18
 
19
- const session_vars = {
20
- PLAYGROUND_ID: process.env.PLAYGROUND_ID, // Need to get rid of this in favor of API
21
- };
19
+ const session_vars = {};
22
20
 
23
21
  module.exports = session_vars;
24
22
 
25
- /**
26
- * Ensure all required environment variables exist. Add each missing variable
27
- * to an error that will be thrown at the end.
28
- *
29
- * @throws ReferenceError with a message for all missing variables.
30
- */
31
- session_vars.validateEnvironment = function() {
32
-
33
- // We are checking for BASE_URL, but we are referring it as SERVER_URL as that
34
- // is the name used in GitHub secrets, which is what most devs will be using.
35
-
36
- let errorMessage = '';
37
-
38
- // Since this code will most often be run in GitHub, I'm going to build a single error message that outlines all missing variables. Otherwise, a developer
39
- // will have to run their pipeline an incredible number of times to discover all the missing variables.
40
- if (!process.env.DOCASSEMBLE_DEVELOPER_API_KEY)
41
- {
42
- errorMessage += `\nThe DOCASSEMBLE_DEVELOPER_API_KEY GitHub secret must be defined. The DOCASSEMBLE_DEVELOPER_API_KEY is a docassemble API key you created for your server's testing account. It should have developer permissions.`
43
- }
44
- if (!process.env.PLAYGROUND_ID)
45
- {
46
- errorMessage += '\nThe PLAYGROUND_ID GitHub secret must be defined. The PLAYGROUND_ID is the ID of the Docassemble suite to run.'
47
- }
48
- if (!process.env.SERVER_URL && !process.env.BASE_URL)
49
- {
50
- errorMessage += `\nThe SERVER_URL GitHub secret must be defined. The SERVER_URL is the URL of the Docassemble Server where the tests should be run.`;
51
- }
52
- if (!process.env.REPO_URL)
53
- {
54
- errorMessage += `\nThe REPO_URL GitHub secret must be defined. The REPO_URL is the URL to the Git repo whose Actions are being run.`;
55
- }
56
- if (!process.env.BRANCH_PATH && !process.env.BRANCH_NAME)
57
- {
58
- errorMessage += `\nThe BRANCH_NAME environment variable must be defined. The BRANCH_NAME is the name of the repository branch that should be pulled into the docassemble project.`;
59
- }
60
-
61
- errorMessage = errorMessage.trim();
62
-
63
- if (errorMessage !== '') {
64
- throw new ReferenceError(errorMessage);
65
- }
66
- };
67
-
68
- session_vars.validateEnvironment();
23
+ session_vars.get_debug = function () { return process.env.DEBUG || null; };
24
+ session_vars.get_dev_api_key = function () { return process.env.DOCASSEMBLE_DEVELOPER_API_KEY || null; };
25
+ session_vars.get_repo_url = function () { return process.env.REPO_URL || null; };
69
26
 
70
- session_vars.get_dev_api_key = function () { return process.env.DOCASSEMBLE_DEVELOPER_API_KEY; };
71
27
  session_vars.get_da_server_url = function () {
72
- let url = process.env.SERVER_URL || process.env.BASE_URL;
73
- return url.replace(/\/$/g, ''); // Remove any trailing slash for safety
28
+ try {
29
+ let url = process.env.SERVER_URL || process.env.BASE_URL;
30
+ return url.replace(/\/$/g, ''); // Remove any trailing slash for safety
31
+ } catch ( error ) {
32
+ return null;
33
+ }
74
34
  };
75
- session_vars.get_debug = function () { return process.env.DEBUG; };
76
- session_vars.get_repo_url = function () { return process.env.REPO_URL; };
77
- // missing/moving functionality:
78
- // getBaseInterviewURL
79
- // Project name setting/getting
80
- // Playground id functionality needs to be transfered to api requests
81
-
82
35
 
83
36
  session_vars.get_branch_name = function () {
84
37
  /* Get the name of the repository's branch that is being tested */
@@ -102,29 +55,6 @@ session_vars.get_project_base_name = function () {
102
55
  return sanitized_name;
103
56
  };
104
57
 
105
- // // Notes: We were using `new_session=1` in the url args, but it wasn't
106
- // // always working. The idea was to save each session so we could look
107
- // // back on it if needed. Aside from the fact that you usually need to log in
108
- // // to make the sessions retrievable (though if you're using `interview_list()`
109
- // // you can get them anyway), it also has inconsistent behavior when
110
- // // `sessions are unique`` or `temporary session` or use `interview_list()`
111
- // // and/or respond immediately with a `command()`. Three ways to avoid this:
112
- // // 1. x Start a new browser instead of just a new page each time. Lengthens the tests.
113
- // // 1. √ Visit `/user/sign-out` (needed even if the user is not logged in)
114
- // // 1. x (seems to be causing a 'Unable to locate interview session' error
115
- // // instead) Use `reset=2` instead , which will not save the previous session at all. It
116
- // // Will not just restart any existing interview sessions, it will also
117
- // // clear out the browser session's memory of what other interviews the user has
118
- // // visited in the same browser session_vars.
119
- // session_vars.getBaseInterviewURL = function () {
120
- // /* Return the part of the interview URL that comes before the filename.
121
- // * Depends on the project name, which may have been changed. */
122
- // let new_session = `/interview?new_session=1&i=docassemble.playground`;
123
- // return `${ session_vars.BASE_URL }${ new_session }${ session_vars.PLAYGROUND_ID }${ session_vars.getProjectName() }%3A`;
124
- // };
125
- // // session_vars.BASE_INTERVIEW_URL = session_vars.getBaseInterviewURL();
126
-
127
-
128
58
  session_vars.get_languages = function () {
129
59
  /* Returns an array of strings, names of languages that should be tested. */
130
60
 
@@ -186,3 +116,47 @@ session_vars.delete_project_name = function () {
186
116
  return false;
187
117
  }
188
118
  };
119
+
120
+ /**
121
+ * Ensure all required environment variables exist. Add each missing variable
122
+ * to an error that will be thrown at the end.
123
+ *
124
+ * @throws ReferenceError with a message for all missing variables.
125
+ */
126
+ session_vars.validateEnvironment = function() {
127
+ /** Throw a useful error for the developer if any of the required env vars
128
+ * are missing. For most devs, these will be GitHub secrets. */
129
+
130
+ // Note: We are checking for BASE_URL, but we are referring it as SERVER_URL as that
131
+ // is the name used in GitHub secrets, which is what most devs will be using.
132
+
133
+ let errorMessage = '';
134
+
135
+ // Since this code will most often be run in GitHub, I'm going to build a single error message that outlines all missing variables. Otherwise, a developer
136
+ // will have to run their pipeline an incredible number of times to discover all the missing variables.
137
+ if ( !session_vars.get_dev_api_key() )
138
+ {
139
+ errorMessage += `\nThe DOCASSEMBLE_DEVELOPER_API_KEY GitHub secret must be defined. The DOCASSEMBLE_DEVELOPER_API_KEY is a docassemble API key you created for your server's testing account. It should have developer permissions.`
140
+ }
141
+ if ( !session_vars.get_da_server_url() )
142
+ {
143
+ errorMessage += `\nThe SERVER_URL GitHub secret must be defined. The SERVER_URL is the URL of the Docassemble Server where the tests should be run.`;
144
+ }
145
+ if ( !session_vars.get_repo_url() )
146
+ {
147
+ errorMessage += `\nThe REPO_URL GitHub secret must be defined. The REPO_URL is the URL to the Git repo whose Actions are being run.`;
148
+ }
149
+ // The branch name is always automatically defined in Github, it'll be missing only if you're running locally and missing an env var.
150
+ if ( !session_vars.get_branch_name() )
151
+ {
152
+ errorMessage += `\nThe BRANCH_NAME environment variable must be defined. The BRANCH_NAME is the name of the repository branch that should be pulled into the docassemble project.`;
153
+ }
154
+
155
+ errorMessage = errorMessage.trim();
156
+
157
+ if (errorMessage !== '') {
158
+ throw new ReferenceError(errorMessage);
159
+ }
160
+ };
161
+
162
+ session_vars.validateEnvironment();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suffolklitlab/alkiln",
3
- "version": "4.0.0-pre-api.7",
3
+ "version": "4.0.0",
4
4
  "description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -17,7 +17,7 @@
17
17
  },
18
18
  "repository": {
19
19
  "type": "git",
20
- "url": "git+https://github.com/SuffolkLITLab/alkiln.git"
20
+ "url": "git+https://github.com/SuffolkLITLab/ALKiln.git"
21
21
  },
22
22
  "keywords": [
23
23
  "docassemble",
@@ -30,9 +30,9 @@
30
30
  "author": "",
31
31
  "license": "MIT",
32
32
  "bugs": {
33
- "url": "https://github.com/SuffolkLITLab/alkiln/issues"
33
+ "url": "https://github.com/SuffolkLITLab/ALKiln/issues"
34
34
  },
35
- "homepage": "https://suffolklitlab.github.io/docassemble-AssemblyLine-documentation/docs/automated_integrated_testing",
35
+ "homepage": "https://suffolklitlab.org/docassemble-AssemblyLine-documentation/docs/automated_integrated_testing/",
36
36
  "dependencies": {
37
37
  "@cucumber/cucumber": "^7.3.2",
38
38
  "axios": "^0.24.0",
@@ -48,7 +48,6 @@
48
48
  "bin": {
49
49
  "alkiln-setup": "./lib/docassemble/setup.js",
50
50
  "alkiln-takedown": "./lib/docassemble/takedown.js",
51
- "alkiln-cucumber": "./lib/index.js",
52
51
  "alkiln-langs": "./lib/utils/langs.js"
53
52
  }
54
53
  }
@@ -4,13 +4,13 @@ Feature: Establishing steps
4
4
  Steps that establish things about the state of the test
5
5
  # In tag names, 'e' is for 'establishing'
6
6
 
7
- @slow @e1
7
+ @slow @e1 @wait
8
8
  Scenario: I am able to set a custom wait time that allows steps to run longer than the half minute default
9
9
  Given I start the interview at "all_tests"
10
10
  And the max seconds for each step in this scenario is 40
11
11
  And I wait 35 seconds
12
12
 
13
- @slow @e2
13
+ @slow @e2 @wait
14
14
  Scenario: I am able to set a custom wait time before an interview has been loaded
15
15
  Given the max seconds for each step in this scenario is 40
16
16
  And I start the interview at "all_tests"
@@ -96,7 +96,7 @@ Scenario: Test "Then I don’t continue" with an apostrophe
96
96
  Then I don’t continue
97
97
  And I will be told an answer is invalid
98
98
 
99
- @fast @o9
99
+ @fast @o9 @table
100
100
  Scenario: I can match JSON page var to str
101
101
  Given I start the interview at "all_tests.yml"
102
102
    And I get to "showifs" with this data:
@@ -138,7 +138,7 @@ Scenario: Fail with missing link with url
138
138
  And I start the interview at "all_tests"
139
139
  Then I should see the link to "http://missing-url.com"
140
140
 
141
- @slow @rf13 @error
141
+ @slow @rf13 @error @table
142
142
  Scenario: Fail with link with given text does not lead to correct url
143
143
  Given the final Scenario status should be "failed"
144
144
  Given the Scenario report should include:
@@ -166,7 +166,7 @@ Scenario: Fail with link with given text does not lead to correct url
166
166
  And I should see the link to "http://ecosia.org/"
167
167
  Then the "Link to external page" link leads to "http://wrong-url.com"
168
168
 
169
- @slow @rf14 @error
169
+ @slow @rf14 @error @table
170
170
  Scenario: Fail with link unexpectedly opens in same window
171
171
  Given the final Scenario status should be "failed"
172
172
  Given the Scenario report should include:
@@ -194,7 +194,7 @@ Scenario: Fail with link unexpectedly opens in same window
194
194
  And I should see the link to "http://ecosia.org/"
195
195
  Then the "Link to external page" link opens in the same window
196
196
 
197
- @fast @rf15 @error
197
+ @fast @rf15 @error @table
198
198
  Scenario: Fail with link unexpectedly opens in a new window
199
199
  Given the final Scenario status should be "failed"
200
200
  Given the Scenario report should include:
@@ -223,7 +223,7 @@ Scenario: Fail with link unexpectedly opens in a new window
223
223
  Then the "Link: reload the page" link opens in a new window
224
224
 
225
225
  ## Don't currently have a broken link to test and this Step is not officially supported
226
- #@fast @rf16 @error
226
+ #@fast @rf16 @error @table
227
227
  #Scenario: Fail with link leads to a broken page
228
228
  # Given the final Scenario status should be "failed"
229
229
  # Given the Scenario report should include:
@@ -321,7 +321,7 @@ Scenario: Fail with system error after Step using wrong file name as trigger
321
321
  # """
322
322
  # And I start the interview at "wrong_yaml_filename"
323
323
 
324
- @fast @rf22
324
+ @fast @rf22 @table
325
325
  Scenario: I can't match JSON page var to str
326
326
  Given the final Scenario status should be "failed"
327
327
  Given the Scenario report should include:
@@ -376,6 +376,16 @@ Scenario: Fail with 2 wrong signin secrets
376
376
  """
377
377
    Given I sign in with the email "WRONG_EMAIL_NAME" and the password "WRONG_PASSWORD_NAME"
378
378
 
379
+ @fast @rf25 @upload
380
+ Scenario: Fail with could not find files
381
+ Given the final Scenario status should be "failed"
382
+ Given the Scenario report should include:
383
+ """
384
+ Could not find "nonexistant1.pdf, nonexistant2.pdf"
385
+ """
386
+ Given I start the interview at "all_tests"
387
+ And I upload "nonexistant1.pdf, nonexistant2.pdf" to "upload_files_visible"
388
+
379
389
  # scope.js
380
390
  # I upload "___" to "___"
381
391
  # No need to test wrong var name
@@ -384,6 +394,7 @@ Scenario: Fail with 2 wrong signin secrets
384
394
  #
385
395
  # I sign
386
396
 
397
+
387
398
  # ===============================
388
399
  # Reports for Scenarios with warnings
389
400
  # ===============================
@@ -448,70 +459,27 @@ Scenario: Report still shows page id when I tap to continue without setting any
448
459
  # Next page (showifs ID SHOULD BE SHOWN IN REPORT)
449
460
  Then the question id should be "buttons yesnomaybe"
450
461
 
451
- @slow @rp2
462
+ @slow @rp2 @table
452
463
  Scenario: Report lists unused table rows
453
464
  Given the final Scenario status should be "passed"
454
465
  Given the Scenario report should include:
455
466
  """
456
-
457
- ---------------
458
- Scenario: Report lists unused table rows
459
- Tags: @reports @slow @rp2
460
- ---------------
461
- screen id: upload-files
462
- screen id: group-of-complex-fields
463
- | single_quote_dict['single_quote_key']['sq_two'] | true | |
464
- | double_quote_dict[\"double_quote_key\"]['dq_two'] | true | |
465
-
466
- Rows that got set:
467
- And I get to the question id "direct standard fields" with this data:
468
- | var | value | trigger |
469
- | double_quote_dict[\"double_quote_key\"]['dq_two'] | true | |
470
- | single_quote_dict['single_quote_key']['sq_two'] | true | |
471
467
  Unused rows:
472
468
  | extra_2 | extra 2 | |
473
469
  | extra_out_of_alphabetical_order | extra 1 | |
474
-
475
- screen id: direct-standard-fields
476
- | checkboxes_other['checkbox_other_opt_1'] | true | |
477
- | radio_yesno | False | false |
478
- | radio_other | radio_other_opt_3 | |
479
- | text_input | Regular text input field value | |
480
- | textarea | Multiline text\narea value | |
481
- | dropdown_test | dropdown_opt_2 | |
482
-
483
- Rows that got set:
484
- And I get to the question id "showifs" with this data:
485
- | var | value | trigger |
486
- | checkboxes_other['checkbox_other_opt_1'] | true | |
487
- | dropdown_test | dropdown_opt_2 | |
488
- | radio_other | radio_other_opt_3 | |
489
- | radio_yesno | False | false |
490
- | text_input | Regular text input field value | |
491
- | textarea | Multiline text\narea value | |
470
+ """
471
+ Given the Scenario report should include:
472
+ """
492
473
  Unused rows:
493
474
  | extra_3 | extra 3 | |
494
475
  | extra_4 | extra 4 | |
495
476
  | extra_5 | extra 5 | |
496
-
497
- screen id: showifs
498
- screen id: buttons-yesnomaybe
499
- | buttons_yesnomaybe | True | |
500
- screen id: buttons-other
501
- | buttons_other | button_2 | |
502
- screen id: button-continue
503
- | button_continue | True | |
504
-
505
- Rows that got set:
506
- And I get to the question id "screen features" with this data:
507
- | var | value | trigger |
508
- | button_continue | True | |
509
- | buttons_other | button_2 | |
510
- | buttons_yesnomaybe | True | |
477
+ """
478
+ Given the Scenario report should include:
479
+ """
511
480
  Unused rows:
512
481
  | extra_6 | extra 6 | |
513
482
  | extra_7 | extra 7 | |
514
-
515
483
  """
516
484
  And I start the interview at "all_tests"
517
485
    And I get to "direct standard fields" with this data:
@@ -1,4 +1,4 @@
1
- @story_tables_formats
1
+ @story_tables_formats @table
2
2
  Feature: Supported story table formats
3
3
 
4
4
  NOTE:
@@ -1,4 +1,4 @@
1
- @story_tables
1
+ @story_tables @table
2
2
  Feature: Story tables
3
3
 
4
4
  NOTE:
@@ -7,6 +7,8 @@ const fields = require('./fields.fixtures.js');
7
7
  const matches = require('./matches.fixtures.js');
8
8
  const scope = require('../../lib/scope.js');
9
9
  const getMatchingRows = scope.getMatchingRows;
10
+ // Match state var instantiated in steps.js. TODO: Add tests for such rows.
11
+ scope.row_needs_trigger_flag = `ALKiln: no trigger variable needed`;
10
12
 
11
13
  // TODO: Add tests for reports
12
14
 
@@ -188,6 +190,32 @@ describe(`For mulitple rows with the same proxies`, async function() {
188
190
  }
189
191
  });
190
192
 
193
+ // Missing table row for loop
194
+ describe(`For a second proxy loop page,`, async function() {
195
+ for ( let test_i = 0; test_i < fields.proxies_multi.length; test_i++ ) {
196
+ let field = fields.proxies_multi[ test_i ];
197
+ let curr_matches = matches.proxies_missing_loop[ test_i ];
198
+ let name = getSafeName( field );
199
+ it( `does not find any matches when table row for second loop page is missing`, async function() {
200
+ let result = await getMatchingRows( scope, { field, var_data: tables.proxies_missing_loop });
201
+ expect( result ).to.deep.equal( curr_matches );
202
+ });
203
+ }
204
+ });
205
+
206
+ // Missing trigger matches second loop
207
+ describe(`For a second proxy loop page,`, async function() {
208
+ for ( let test_i = 0; test_i < fields.proxies_multi.length; test_i++ ) {
209
+ let field = fields.proxies_multi[ test_i ];
210
+ let curr_matches = matches.proxies_missing_trigger[ test_i ];
211
+ let name = getSafeName( field );
212
+ it( `matches with a missing trigger row with the correct variable name`, async function() {
213
+ let result = await getMatchingRows( scope, { field, var_data: tables.proxies_missing_trigger });
214
+ expect( result ).to.deep.equal( curr_matches );
215
+ });
216
+ }
217
+ });
218
+
191
219
 
192
220
  // ============================
193
221
  // Signature
@@ -15,7 +15,7 @@ matches.standard = [
15
15
  [],
16
16
  [ { var: 'radio_other', value: 'radio_other_opt_2' } ],
17
17
  [],
18
- [ { var: 'text_input', value: 'Some one-line text' }, { var: 'text_input', value: 'Some conflicting text' } ],
18
+ [ { var: 'text_input', value: 'Some one-line text', "original": { var: 'text_input', value: 'Some one-line text' } }, { var: 'text_input', value: 'Some conflicting text', "original": { var: 'text_input', value: 'Some conflicting text' } } ],
19
19
  [ { var: 'textarea', value: 'Some\nmulti-line\ntext' } ],
20
20
  [ { 'var': 'date_input','value':'today-1' } ],
21
21
  [ { var: 'dropdown_test', value: 'dropdown_opt_2' } ],
@@ -111,6 +111,18 @@ matches.proxies_multi = [
111
111
  []
112
112
  ];
113
113
 
114
+ // Missing table row for second loop
115
+ matches.proxies_missing_loop = [
116
+ [],
117
+ []
118
+ ];
119
+
120
+ // Missing trigger matches second loop
121
+ matches.proxies_missing_trigger = [
122
+ [{ "trigger": "", "var": "x[i].name.first", "value": "Firstname", "original": { "trigger": "", "var": "x[i].name.first", "value": "Firstname" }}],
123
+ []
124
+ ];
125
+
114
126
 
115
127
  // ============================
116
128
  // Signature
@@ -0,0 +1,46 @@
1
+ const chai = require('chai');
2
+ const expect = chai.expect;
3
+
4
+ const session_vars = require("../../lib/utils/session_vars.js");
5
+ const validateEnvironment = session_vars.validateEnvironment;
6
+
7
+ describe('When the `session_vars` object uses', function () {
8
+ describe('validateEnvironment, it', function() {
9
+
10
+ /**
11
+ * All required variables should be defined in .env. For reference, those variables are the following:
12
+ *
13
+ * DOCASSEMBLE_DEVELOPER_API_KEY
14
+ * BASE_URL
15
+ * REPO_URL
16
+ */
17
+ it("successfully completes when all required env vars exist", function() {
18
+ session_vars.validateEnvironment();
19
+ });
20
+
21
+ /**
22
+ * This test has an ordering dependency with the test below. I'm not certain if I am getting lucky or if I need to explicitly declare the order.
23
+ */
24
+ it("throws a reference error when any var is missing", function() {
25
+ delete process.env.DOCASSEMBLE_DEVELOPER_API_KEY;
26
+
27
+ expect(session_vars.validateEnvironment).to.throw(ReferenceError, /DOCASSEMBLE_DEVELOPER_API_KEY/);
28
+ });
29
+
30
+ /**
31
+ * Delete all environment variables before validating the variables.
32
+ */
33
+ it("names all missing variables in the error, not just one", function() {
34
+ delete process.env.DOCASSEMBLE_DEVELOPER_API_KEY;
35
+ delete process.env.BASE_URL;
36
+ delete process.env.SERVER_URL;
37
+ delete process.env.REPO_URL;
38
+
39
+ // This test just tests that the variable names show up in a fixed order.
40
+ expect(session_vars.validateEnvironment).to.throw(
41
+ ReferenceError,
42
+ /DOCASSEMBLE_DEVELOPER_API_KEY.*\n.*SERVER_URL.*\n.*REPO_URL/
43
+ );
44
+ });
45
+ });
46
+ });
@@ -21,8 +21,8 @@ tables.standard = [
21
21
  { "var": "date_input","value":"today-1" },
22
22
  { "var": "radio_yesno", "value": "False" },
23
23
  { "var": "radio_other", "value": "radio_other_opt_2" },
24
- { "var": "text_input", "value": "Some one-line text" },
25
- { "var": "text_input","value":"Some conflicting text" },
24
+ { "var": "text_input", "value": "Some one-line text", "original": { "var": "text_input", "value": "Some one-line text" } },
25
+ { "var": "text_input","value":"Some conflicting text", "original": { "var": "text_input","value":"Some conflicting text" } },
26
26
  { "var": "textarea", "value": "Some\nmulti-line\ntext" },
27
27
  { "var": "dropdown_test", "value": "dropdown_opt_2" }, // May want to change `checked`
28
28
  ];
@@ -373,6 +373,16 @@ tables.proxies_multi = [
373
373
  { "trigger": "proxy_list[2].name.first", "var": "x[i].name.first", "value": "Firstname", },
374
374
  ];
375
375
 
376
+ // Missing table row for second loop
377
+ tables.proxies_missing_loop = [
378
+ { "trigger": "proxy_list[0].name.first", "var": "x[i].name.first", "value": "Firstname", "original": { "trigger": "proxy_list[0].name.first", "var": "x[i].name.first", "value": "Firstname" } },
379
+ ];
380
+
381
+ // Missing trigger matches second loop
382
+ tables.proxies_missing_trigger = [
383
+ { "trigger": "", "var": "x[i].name.first", "value": "Firstname", "original": { "trigger": "", "var": "x[i].name.first", "value": "Firstname" }},
384
+ ];
385
+
376
386
 
377
387
  // ============================
378
388
  // Signature