@suffolklitlab/alkiln 5.14.0 → 5.15.0-deps-2

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.
Files changed (37) hide show
  1. package/.github/workflows/github_server.yml +1 -1
  2. package/.github/workflows/playground.yml +2 -1
  3. package/CHANGELOG.md +29 -0
  4. package/action.yml +26 -10
  5. package/action_for_github_server/action.yml +31 -27
  6. package/docs/4_environments.md +2 -2
  7. package/docs/artifacts_folder_name.md +121 -71
  8. package/lib/docassemble/server_install.js +0 -2
  9. package/lib/docassemble/setup.js +1 -3
  10. package/lib/docassemble/takedown.js +2 -2
  11. package/lib/globals.js +10 -0
  12. package/lib/run_cucumber.js +40 -53
  13. package/lib/scope.js +32 -0
  14. package/lib/setup/TestGenerator.js +1757 -0
  15. package/lib/setup/artifacts.js +20 -0
  16. package/lib/setup/generate.js +42 -0
  17. package/lib/setup/get_Gherkin_AST.js +26 -0
  18. package/lib/setup/validate.js +89 -0
  19. package/lib/steps.js +53 -19
  20. package/lib/utils/Log.js +302 -149
  21. package/lib/utils/get_error_stacks.js +16 -0
  22. package/lib/utils/pdf_reader.js +9 -2
  23. package/lib/utils/reports.js +43 -23
  24. package/lib/utils/session_vars.js +77 -57
  25. package/lib/utils/set_sources_paths.js +98 -0
  26. package/npm-shrinkwrap.json +739 -924
  27. package/package.json +17 -10
  28. package/tests/log_codes/check_codes.sh +17 -13
  29. package/tests/log_codes/log_code_expected_instances.txt +58 -0
  30. package/tests/unit_tests/constrained_random_answers/invalid.fixtures.js +178 -0
  31. package/tests/unit_tests/constrained_random_answers/invalid.test.js +251 -0
  32. package/tests/unit_tests/constrained_random_answers/valid.fixtures.js +957 -0
  33. package/tests/unit_tests/constrained_random_answers/valid.test.js +563 -0
  34. package/tests/unit_tests/log.test.js +17 -41
  35. package/_alkiln_meta/gherkin_parsed_example.json +0 -1546
  36. package/_alkiln_meta/shift_logs.js +0 -75
  37. /package/docs/{expected_inernal_results.md → expected_internal_results.md} +0 -0
package/package.json CHANGED
@@ -1,18 +1,22 @@
1
1
  {
2
2
  "name": "@suffolklitlab/alkiln",
3
- "version": "5.14.0",
3
+ "version": "5.15.0-deps-2",
4
4
  "description": "Integrated automated end-to-end testing with docassemble, puppeteer, and cucumber.",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
7
7
  "test": "npm run unit && npm run codes && npm run cucumber",
8
- "cucumber": "./lib/run_cucumber.js",
9
8
  "local": "npm run setup && npm run cucumber; npm run takedown",
10
- "pass": "npm run cucumber 'not @error and not @temp_error'",
11
- "fail": "npm run cucumber '@error'",
12
- "setup": "./lib/docassemble/setup.js",
13
9
  "takedown": "./lib/docassemble/takedown.js",
10
+ "setup": "./lib/docassemble/setup.js",
14
11
  "server_install": "./lib/docassemble/server_install.js",
15
- "unit": "mocha tests/unit_tests/*.test.*",
12
+ "pass": "npm run cucumber 'not @error and not @temp_error'",
13
+ "fail": "npm run cucumber '@error'",
14
+ "cucumber": "npm run build && ./lib/run_cucumber.js",
15
+ "build": "npm run artifacts && npm run validate && npm run generate",
16
+ "validate": "./lib/setup/validate.js",
17
+ "generate": "./lib/setup/generate.js",
18
+ "artifacts": "./lib/setup/artifacts.js",
19
+ "unit": "npm run artifacts && mocha --recursive 'tests/unit_tests/**/*.test.*'",
16
20
  "codes": "tests/log_codes/check_codes.sh ."
17
21
  },
18
22
  "repository": {
@@ -37,7 +41,7 @@
37
41
  "@axe-core/puppeteer": "4.7.3",
38
42
  "@cucumber/cucumber": "9.3.0",
39
43
  "@faker-js/faker": "7.3.0",
40
- "axios": "1.7.3",
44
+ "axios": "1.9.0",
41
45
  "chai": "4.2.0",
42
46
  "cheerio": "1.0.0-rc.10",
43
47
  "deep-equal-in-any-order": "2.0.0",
@@ -46,8 +50,8 @@
46
50
  "fast-glob": "3.2.12",
47
51
  "minimatch": "3.0.5",
48
52
  "minimist": "1.2.8",
49
- "mocha": "9.2.2",
50
- "pdfjs-dist": "3.11.174",
53
+ "mocha": "11.5.0",
54
+ "pdfjs-dist": "5.2.133",
51
55
  "puppeteer": "22.15.0",
52
56
  "qs": "6.10.3",
53
57
  "sanitize-filename": "1.6.3",
@@ -57,6 +61,9 @@
57
61
  "alkiln-server-install": "./lib/docassemble/server_install.js",
58
62
  "alkiln-setup": "./lib/docassemble/setup.js",
59
63
  "alkiln-takedown": "./lib/docassemble/takedown.js",
60
- "alkiln-run": "./lib/run_cucumber.js"
64
+ "alkiln-run": "./lib/run_cucumber.js",
65
+ "alkiln-artifacts": "./lib/setup/artifacts.js",
66
+ "alkiln-validate": "./lib/setup/validate.js",
67
+ "alkiln-generate": "./lib/setup/generate.js"
61
68
  }
62
69
  }
@@ -11,12 +11,13 @@ exit_code=0
11
11
 
12
12
  echo " -------------------------------------------------------
13
13
  | Usage: |
14
- | bash $(basename $0) [dir] [c file] [c folder] [-l arg]
14
+ | bash $(basename $0) [dir] [c file] [c folder] |
15
15
  | dir: The directory in which to search for logs |
16
16
  | c file: Name of the log instance counter file |
17
17
  | c folder: Path to the folder of the log counter file |
18
- | -l arg: \"1\" prints extra logs |
19
18
  -------------------------------------------------------"
19
+ # | bash $(basename $0) [dir] [c file] [c folder] [-l arg]
20
+ # | -l arg: \"1\" prints extra logs |
20
21
 
21
22
  # Get flags and their values
22
23
  loudness="0"
@@ -56,7 +57,7 @@ fi
56
57
  # removed and are no longer used. Syntax used works with GitHub cli - [[:digit:]]
57
58
  # https://stackoverflow.com/a/6901221
58
59
  # Exclude files and paths
59
- instances=$(find "$where_to_look" -type f ! -name "CONTRIBUTING.md" ! -name "$expected_instances_file" ! -name "debug_log.txt" ! -name "cucumber-report.txt" ! -path "*/tests/*" ! -path "*/node_modules/*" ! -path "*/ALKilnTests/*" ! -path "*/alkiln-*/*" ! -path "*/_alkiln*/*" ! -path "*/docs/decisions/*" ! -path "*/\.*" -print0 | xargs -0 -P 4 grep -0 -ro 'ALK[[:digit:]][[:digit:]][[:digit:]][[:digit:]]' | grep -v -- '--' )
60
+ instances=$(find "$where_to_look" -type f ! -name "CONTRIBUTING.md" ! -name "$expected_instances_file" ! -name "debug_log.txt" ! -name "cucumber-report.txt" ! -name "_alkiln*" ! -path "*/tests/*" ! -path "*/node_modules/*" ! -path "*/ALKilnTests/*" ! -path "*/alkiln-*/*" ! -path "*/_alkiln*/*" ! -path "*/docs/*" ! -path "*/\.*" -print0 | xargs -0 -P 4 grep -0 -ro 'ALK[[:digit:]][[:digit:]][[:digit:]][[:digit:]]' | grep -v -- '--' )
60
61
 
61
62
  if [[ "$loudness" != "0" ]]; then
62
63
  total_instances=$(echo "$instances" | wc -l)
@@ -101,7 +102,7 @@ fi
101
102
  indx=0
102
103
  too_many=()
103
104
  missing=()
104
- while [ "$indx" -lt "$highest_code" ]; do
105
+ while [ "$indx" -le "$highest_code" ]; do
105
106
  # Turn the index into a log code by prepending ALK and adding leading zeros
106
107
  log_code=$(printf "ALK%04d" "$indx")
107
108
  # Count ";" - a stand-in for the number of
@@ -126,24 +127,27 @@ while [ "$indx" -lt "$highest_code" ]; do
126
127
  # To add to the list of strings to print later
127
128
  short_msg="$log_code $num_paths/$num_expected"
128
129
  long_msg="$log_code act/exp "
129
- long_msg+="$num_paths/$num_expected:"
130
+ long_msg+="$num_paths/$num_expected"
131
+ if [ "$num_paths" -gt "$num_expected" ]; then
132
+ long_msg+=":"
133
+ fi
130
134
  long_msg+=$(echo "${codes_unique_paths[$indx]}" | sed 's/;/\n - /g')
131
135
 
132
136
  # missing
133
137
  if [ "$num_paths" -lt "$num_expected" ]; then
134
- if [[ "$loudness" != "0" ]]; then
138
+ # if [[ "$loudness" != "0" ]]; then
135
139
  missing+=("$long_msg")
136
- else
137
- missing+=("$short_msg")
138
- fi
140
+ # else
141
+ # missing+=("$short_msg")
142
+ # fi
139
143
 
140
144
  # too_many
141
145
  elif [ "$num_paths" -gt "$num_expected" ]; then
142
- if [[ "$loudness" != "0" ]]; then
146
+ # if [[ "$loudness" != "0" ]]; then
143
147
  too_many+=("$long_msg")
144
- else
145
- too_many+=("$short_msg")
146
- fi
148
+ # else
149
+ # too_many+=("$short_msg")
150
+ # fi
147
151
  fi
148
152
 
149
153
  let indx++
@@ -5,8 +5,11 @@ Why we need duplicate codes sometimes: GitHub actions sometimes don't have ways
5
5
  The script that tests the log codes will ignore this file (or any file with this name), and any file with these names: check_codes.sh, debug_log.txt, cucumber-report.txt. It will also ignore files in folders with these names:, node_modules, ALKilnTests, alkiln-*, _alkiln*. That list might get updated, so for an up-to-date list, always check the file check_codes.sh where we use `--exclude=` and such.
6
6
 
7
7
  Reasons for deletion:
8
+ 0000 - unknown
8
9
  0053 - duplicate log
9
10
  0173 - redundant
11
+ 0181 - unknown
12
+ 0223 - changed Log behavior ("Only logs that throw should give a value to `error`.")
10
13
 
11
14
  ALK0000:0
12
15
  ALK0001:1
@@ -231,3 +234,58 @@ ALK0219:1
231
234
  ALK0220:1
232
235
  ALK0221:1
233
236
  ALK0222:1
237
+ ALK0223:0
238
+ ALK0224:1
239
+ ALK0225:1
240
+ ALK0226:1
241
+ ALK0227:1
242
+ ALK0228:1
243
+ ALK0229:1
244
+ ALK0230:1
245
+ ALK0231:1
246
+ ALK0232:1
247
+ ALK0233:1
248
+ ALK0234:1
249
+ ALK0235:1
250
+ ALK0236:1
251
+ ALK0237:1
252
+ ALK0238:1
253
+ ALK0239:1
254
+ ALK0240:1
255
+ ALK0241:1
256
+ ALK0242:1
257
+ ALK0243:1
258
+ ALK0244:1
259
+ ALK0245:1
260
+ ALK0246:1
261
+ ALK0247:1
262
+ ALK0248:1
263
+ ALK0249:1
264
+ ALK0250:1
265
+ ALK0251:1
266
+ ALK0252:1
267
+ ALK0253:1
268
+ ALK0254:1
269
+ ALK0255:1
270
+ ALK0256:1
271
+ ALK0257:1
272
+ ALK0258:1
273
+ ALK0259:1
274
+ ALK0260:1
275
+ ALK0261:1
276
+ ALK0262:1
277
+ ALK0263:1
278
+ ALK0264:1
279
+ ALK0265:1
280
+ ALK0266:1
281
+ ALK0267:1
282
+ ALK0268:1
283
+ ALK0269:1
284
+ ALK0270:1
285
+ ALK0271:1
286
+ ALK0272:1
287
+ ALK0273:1
288
+ ALK0274:1
289
+ ALK0275:1
290
+ ALK0276:1
291
+ ALK0277:1
@@ -0,0 +1,178 @@
1
+ /** Actual and expected values for INvalid constrained random answer tests. */
2
+
3
+ module.exports = fixts = {};
4
+
5
+ /** Research notes
6
+ *
7
+ * Valid: A feature is valid without a description
8
+ * Valid: A scenario is valid without a description
9
+ *
10
+ * TODO
11
+ * Research: Can we get back null or undefined without syntax errors? (unlikely)
12
+ * Research: Can a feature.children item exist without having a `.scenario`
13
+ * prop? (unlikely)
14
+ * */
15
+
16
+ fixts.generator_missing_Feature = {};
17
+ fixts.generator_missing_Feature.arg = `Scenario: Invalid feature file`;
18
+ fixts.generator_missing_Feature.expected = null;
19
+ fixts.generator_missing_Feature.error_codes = [ `ALK0232` ];
20
+ fixts.generator_missing_Feature.log_codes = [ `ALK0232` ];
21
+
22
+ fixts.generator_missing_contents = {};
23
+ fixts.generator_missing_contents.arg = ``;
24
+ fixts.generator_missing_contents.expected = null;
25
+ fixts.generator_missing_contents.error_codes = [ `ALK0233` ];
26
+ fixts.generator_missing_contents.log_codes = [ `ALK0233` ];
27
+
28
+ fixts.generator_0_Scenarios = {};
29
+ fixts.generator_0_Scenarios.arg = `Feature: No scenarios`;
30
+ fixts.generator_0_Scenarios.expected = null;
31
+ fixts.generator_0_Scenarios.error_codes = [ `ALK0235` ];
32
+ fixts.generator_0_Scenarios.log_codes = [ `ALK0235` ];
33
+
34
+
35
+ /**
36
+ * Missing fore_Step keywords
37
+ * Missing constraints Step keywords
38
+ * */
39
+
40
+ fixts.missing_fore_Step_keywords = {};
41
+ fixts.missing_fore_Step_keywords.arg =
42
+ `Feature: I generate constrained random tests
43
+
44
+ Scenario: I fail with missing keywords for a fore Step
45
+ Given ALKiln makes 2
46
+ Given the final Scenario status should be "failed"
47
+ Given I start the interview at "test_kickout"
48
+ And ALKiln tests get to "end" with:
49
+ | var | possible_values |
50
+ | user_choice | correct;; wrong |
51
+ `;
52
+ fixts.missing_fore_Step_keywords.expected = null;
53
+ fixts.missing_fore_Step_keywords.error_codes = [ `ALK0242`, `ALK0263` ];
54
+ fixts.missing_fore_Step_keywords.log_codes = [
55
+ `ALK0237`,
56
+ `ALK0242`,
57
+ `ALK0263`,
58
+ ];
59
+
60
+
61
+ fixts.missing_constraints_Step_keywords = {};
62
+ fixts.missing_constraints_Step_keywords.arg =
63
+ `Feature: I generate constrained random tests
64
+
65
+ Scenario: I fail with missing keywords for a constraints Step
66
+ Given ALKiln makes 2 constrained random answers tests
67
+ Given the final Scenario status should be "failed"
68
+ Given I start the interview at "test_kickout"
69
+ And tests get to "end" with:
70
+ | var | possible_values |
71
+ | user_choice | correct;; wrong |
72
+ `;
73
+ fixts.missing_constraints_Step_keywords.expected = null;
74
+ fixts.missing_constraints_Step_keywords.error_codes = [ `ALK0256`, `ALK0263` ];
75
+ fixts.missing_constraints_Step_keywords.log_codes = [
76
+ `ALK0237`, `ALK0243`, `ALK0244`,
77
+ `ALK0245`, `ALK0248`, `ALK0249`,
78
+ `ALK0256`,
79
+ `ALK0263`,
80
+ ];
81
+
82
+
83
+ fixts.missing_table = {};
84
+ fixts.missing_table.arg =
85
+ `Feature: I generate constrained random tests
86
+
87
+ Scenario: I fail with the first missing table
88
+ Given ALKiln makes 2 constrained random answers tests
89
+ Given the final Scenario status should be "failed"
90
+ Given I start the interview at "test_kickout"
91
+ And ALKiln tests get to "end" with:
92
+ And ALKiln tests get to "end" with:
93
+ `;
94
+ // ======= ENDS ARG ======= //
95
+ fixts.missing_table.expected = null;
96
+ fixts.missing_table.error_codes = [ `ALK0251`, `ALK0263` ];
97
+ fixts.missing_table.log_codes = [
98
+ `ALK0237`, `ALK0243`, `ALK0244`,
99
+ `ALK0245`, `ALK0248`, `ALK0249`, `ALK0246`,
100
+ `ALK0251`,
101
+ `ALK0263`,
102
+ ];
103
+
104
+
105
+ fixts.missing_ids = {};
106
+ fixts.missing_ids.arg =
107
+ `Feature: I generate constrained random tests
108
+
109
+ Scenario: I fail with missing quoted ids in constrained random answers
110
+ Given ALKiln makes 2 constrained random answers tests
111
+ Given the final Scenario status should be "failed"
112
+ Given I start the interview at "test_kickout"
113
+ And ALKiln will get to end with:
114
+ | var | possible_values |
115
+ | user_choice | correct;; wrong |
116
+ `;
117
+ // ======= ENDS ARG ======= //
118
+ fixts.missing_ids.expected = null;
119
+ fixts.missing_ids.error_codes = [ `ALK0250`, `ALK0263` ];
120
+ fixts.missing_ids.log_codes = [
121
+ `ALK0237`, `ALK0243`, `ALK0244`,
122
+ `ALK0245`, `ALK0248`, `ALK0249`, `ALK0246`,
123
+ `ALK0250`,
124
+ `ALK0263`,
125
+ ];
126
+
127
+
128
+ // A valid generator Scenario, but an erroring test when run in cucumber, so it
129
+ // will error here instead
130
+ fixts.only_row_is_header = {};
131
+ fixts.only_row_is_header.arg =
132
+ `Feature: I generate constrained random tests
133
+
134
+ Scenario: Non-table row after table header
135
+ Given ALKiln makes 2 constrained random answers tests
136
+ Given the final Scenario status should be "failed"
137
+ Given I start the interview at "test_kickout"
138
+ And ALKiln will get to "end" with:
139
+ | var | possible_values |
140
+ Then non-table line
141
+ | user_choice | correct;; wrong |
142
+ `;
143
+ fixts.only_row_is_header.expected = null;
144
+ fixts.only_row_is_header.error_codes = [`ALK0252`, `ALK0263`];
145
+ fixts.only_row_is_header.log_codes = [
146
+ `ALK0237`, `ALK0243`, `ALK0244`,
147
+ `ALK0245`, `ALK0248`, `ALK0249`, `ALK0246`,
148
+ `ALK0252`,
149
+ `ALK0263`,
150
+ ];
151
+
152
+ /**
153
+ * No test for a table interrupted in the middle of regular rows (the parser
154
+ * can't detect it)
155
+ * */
156
+
157
+
158
+ fixts.multiple_scenarios = {};
159
+ fixts.multiple_scenarios.arg =
160
+ `Feature: It is invalid to have multiple Scenarios in one generator file
161
+
162
+ Scenario: The first of 2 Scenarios
163
+ Given ALKiln makes 1 constrained random answers tests
164
+ Given I start the interview at "test_kickout"
165
+ And ALKiln will get to "end" with:
166
+ | var | possible_values |
167
+ | user_choice | correct;; wrong |
168
+
169
+ Scenario: The second of 2 Scenarios
170
+ Given ALKiln makes 1 constrained random answers tests
171
+ Given I start the interview at "test_kickout"
172
+ And ALKiln will get to "end" with:
173
+ | var | possible_values |
174
+ | user_choice | correct;; wrong |
175
+ `;
176
+ fixts.multiple_scenarios.expected = null;
177
+ fixts.multiple_scenarios.error_codes = [`ALK0236`];
178
+ fixts.multiple_scenarios.log_codes = [`ALK0236`];
@@ -0,0 +1,251 @@
1
+ const chai = require(`chai`);
2
+ const expect = chai.expect;
3
+
4
+ const TestGenerator = require(`../../../lib/setup/TestGenerator.js`);
5
+ const Log = require(`../../../lib/utils/Log.js`);
6
+ const fixtures = require(`./invalid.fixtures.js`);
7
+
8
+
9
+ function get_error_codes({ errors }) {
10
+ /** Returns a list of ALKiln ALK#### codes from Error stacks
11
+ *
12
+ * @param {object} obj - Named arguments
13
+ * @param {[Error]} obj.errors - List of Error instances
14
+ *
15
+ * @returns {[str]} - List of ALKiln log codes in the errors
16
+ * */
17
+ let codes = [];
18
+ for ( let error of errors ) {
19
+ let matches = error.stack.match(/ALK\d\d\d\d/gm);
20
+ if ( matches ) {
21
+ codes.push( ...matches );
22
+ }
23
+ }
24
+
25
+ return codes;
26
+ };
27
+
28
+
29
+ function get_log_codes({ logger }) {
30
+ /** Returns a list of ALKiln codes from arguments sent to a Log instance
31
+ *
32
+ * @params {object} obj - Named arguments
33
+ * @params {Log} obj.logger - An instance of Log
34
+ * @params {object} obj.logger.opts - Options passed to the Log instance
35
+ * @params {str} obj.logger.opts.code - ALK#### formatted log code
36
+ * @params {[str]} obj.logger.logs - Additional messages to be logged
37
+ *
38
+ * @returns {[str]} - List of ALKiln log codes in the collection of logs
39
+ * */
40
+ let codes = [];
41
+
42
+ for ( let record of logger.internal_log_records ) {
43
+ codes.push( record.opts.code );
44
+ }
45
+
46
+ return codes;
47
+ }
48
+
49
+ /** Variables that will change their values for each `it()` */
50
+ const logger = new Log({ context: `invalid generators unit tests` });
51
+ let fixture = null;
52
+ let new_contents = null;
53
+ let errors = null;
54
+ let actual = null;
55
+ function mutate_globals_with({ testing_vals }) {
56
+ /** Set up values for parsing, parse, record values. Mutates in-scope
57
+ * variables in a way that helps chaijs (mocha really) get the right
58
+ * values to the right places.
59
+ *
60
+ * @params {object} testing_vals - Arguments to pass to the function and
61
+ * expected values
62
+ *
63
+ * @returns {undefined}
64
+ * */
65
+ // Reset log codes
66
+ logger.clear_internal_log_records();
67
+
68
+ // Fresh namespace
69
+ let generator = new TestGenerator();
70
+ // Mutates `fixture`
71
+ fixture = testing_vals;
72
+ // Mutates `new_contents` and `error`
73
+ ({ new_contents, errors } = generator.parse_file({
74
+ file_text: fixture.arg,
75
+ generator_path: `used_in_warning_logs`,
76
+ logger
77
+ }) );
78
+ };
79
+
80
+ describe(`Constrained random answers parser,`, function () {
81
+
82
+ describe(`when given a missing Feature keyword`, function () {
83
+
84
+ before(function () { mutate_globals_with({ testing_vals: fixtures.generator_missing_Feature }); });
85
+
86
+ let outer = fixtures.generator_missing_Feature;
87
+
88
+ it(`returns \`null\` for contents value`, function () {
89
+ expect( new_contents ).to.equal( fixture.expected );
90
+ });
91
+ it(`has these exact error codes: ${ JSON.stringify( outer.error_codes )}`, function () {
92
+ expect( get_error_codes({ errors: errors }) )
93
+ .to.have.all.members( fixture.error_codes );
94
+ });
95
+ it(`has these exact _log_ codes: ${ JSON.stringify( outer.log_codes )}`, function () {
96
+ expect( get_log_codes({ logger }) ).to.have.all.members( fixture.log_codes );
97
+ });
98
+
99
+ });
100
+
101
+ describe(`when given an empty string`, function () {
102
+
103
+ before(function () { mutate_globals_with({ testing_vals: fixtures.generator_missing_contents }); });
104
+
105
+ let outer = fixtures.generator_missing_contents;
106
+
107
+ it(`returns \`null\` for contents value`, function () {
108
+ expect( new_contents ).to.equal( fixture.expected );
109
+ });
110
+ it(`has these exact error codes: ${ JSON.stringify( outer.error_codes )}`, function () {
111
+ expect( get_error_codes({ errors: errors }) )
112
+ .to.have.all.members( fixture.error_codes );
113
+ });
114
+ it(`has these exact _log_ codes: ${ JSON.stringify( outer.log_codes )}`, function () {
115
+ expect( get_log_codes({ logger }) ).to.have.all.members( fixture.log_codes );
116
+ });
117
+
118
+ });
119
+
120
+ describe(`when given generator text missing Scenarios`, function () {
121
+
122
+ before(function () { mutate_globals_with({ testing_vals: fixtures.generator_0_Scenarios }); });
123
+
124
+ let outer = fixtures.generator_0_Scenarios;
125
+
126
+ it(`returns \`null\` for contents value`, function () {
127
+ expect( new_contents ).to.equal( fixture.expected );
128
+ });
129
+ it(`has these exact error codes: ${ JSON.stringify( outer.error_codes )}`, function () {
130
+ expect( get_error_codes({ errors: errors }) )
131
+ .to.have.all.members( fixture.error_codes );
132
+ });
133
+ it(`has these exact _log_ codes: ${ JSON.stringify( outer.log_codes )}`, function () {
134
+ expect( get_log_codes({ logger }) ).to.have.all.members( fixture.log_codes );
135
+ });
136
+
137
+ });
138
+
139
+ describe(`when given an invalid generator Scenario`, function () {
140
+
141
+ describe(`where a num tests fore Step is missing keywords,`, function () {
142
+
143
+ before(function () { mutate_globals_with({ testing_vals: fixtures.missing_fore_Step_keywords }); });
144
+
145
+ let outer = fixtures.missing_fore_Step_keywords;
146
+
147
+ it(`returns \`null\` for contents value`, function () {
148
+ expect( new_contents ).to.equal( fixture.expected );
149
+ });
150
+ it(`has these exact error codes: ${ JSON.stringify( outer.error_codes )}`, function () {
151
+ expect( get_error_codes({ errors: errors }) ).to.have.all.members( fixture.error_codes );
152
+ });
153
+ it(`has these exact _log_ codes: ${ JSON.stringify( outer.log_codes )}`, function () {
154
+ expect( get_log_codes({ logger }) ).to.have.all.members( fixture.log_codes );
155
+ });
156
+
157
+ });
158
+
159
+ describe(`where a constraints Step is missing keywords,`, function () {
160
+
161
+ before(function () { mutate_globals_with({ testing_vals: fixtures.missing_constraints_Step_keywords }); });
162
+
163
+ let outer = fixtures.missing_constraints_Step_keywords;
164
+
165
+ it(`returns \`null\` for contents value`, function () {
166
+ expect( new_contents ).to.equal( fixture.expected );
167
+ });
168
+ it(`has these exact error codes: ${ JSON.stringify( outer.error_codes )}`, function () {
169
+ expect( get_error_codes({ errors: errors }) ).to.have.all.members( fixture.error_codes );
170
+ });
171
+ it(`has these exact _log_ codes: ${ JSON.stringify( outer.log_codes )}`, function () {
172
+ expect( get_log_codes({ logger }) ).to.have.all.members( fixture.log_codes );
173
+ });
174
+
175
+ });
176
+
177
+ describe(`that is missing a table,`, function () {
178
+
179
+ before(function () { mutate_globals_with({ testing_vals: fixtures.missing_table }); });
180
+
181
+ let outer = fixtures.missing_table;
182
+
183
+ it(`returns \`null\` for contents value`, function () {
184
+ expect( new_contents ).to.equal( fixture.expected );
185
+ });
186
+ it(`has these exact error codes: ${ JSON.stringify( outer.error_codes )}`, function () {
187
+ expect( get_error_codes({ errors: errors }) ).to.have.all.members( fixture.error_codes );
188
+ });
189
+ it(`has these exact _log_ codes: ${ JSON.stringify( outer.log_codes )}`, function () {
190
+ expect( get_log_codes({ logger }) ).to.have.all.members( fixture.log_codes );
191
+ });
192
+
193
+ });
194
+
195
+ describe(`that has no quoted ids,`, function () {
196
+
197
+ before(function () { mutate_globals_with({ testing_vals: fixtures.missing_ids }); });
198
+
199
+ let outer = fixtures.missing_ids;
200
+
201
+ it(`returns \`null\` for contents value`, function () {
202
+ expect( new_contents ).to.equal( fixture.expected );
203
+ });
204
+ it(`has these exact error codes: ${ JSON.stringify( outer.error_codes )}`, function () {
205
+ expect( get_error_codes({ errors: errors }) ).to.have.all.members( fixture.error_codes );
206
+ });
207
+ it(`has these exact _log_ codes: ${ JSON.stringify( outer.log_codes )}`, function () {
208
+ expect( get_log_codes({ logger }) ).to.have.all.members( fixture.log_codes );
209
+ });
210
+
211
+ });
212
+
213
+ describe(`that has no header row,`, function () {
214
+
215
+ before(function () { mutate_globals_with({ testing_vals: fixtures.only_row_is_header }); });
216
+
217
+ let outer = fixtures.only_row_is_header;
218
+
219
+ it(`returns \`null\` for contents value`, function () {
220
+ expect( new_contents ).to.equal( fixture.expected );
221
+ });
222
+ it(`has these exact error codes: ${ JSON.stringify( outer.error_codes )}`, function () {
223
+ expect( get_error_codes({ errors: errors }) ).to.have.all.members( fixture.error_codes );
224
+ });
225
+ it(`has these exact _log_ codes: ${ JSON.stringify( outer.log_codes )}`, function () {
226
+ expect( get_log_codes({ logger }) ).to.have.all.members( fixture.log_codes );
227
+ });
228
+
229
+ });
230
+
231
+ describe(`that has multiple Scenarios,`, function () {
232
+
233
+ before(function () { mutate_globals_with({ testing_vals: fixtures.multiple_scenarios }); });
234
+
235
+ let outer = fixtures.multiple_scenarios;
236
+
237
+ it(`returns \`null\` for contents value`, function () {
238
+ expect( new_contents ).to.equal( fixture.expected );
239
+ });
240
+ it(`has these exact error codes: ${ JSON.stringify( outer.error_codes )}`, function () {
241
+ expect( get_error_codes({ errors: errors }) ).to.have.all.members( fixture.error_codes );
242
+ });
243
+ it(`has these exact _log_ codes: ${ JSON.stringify( outer.log_codes )}`, function () {
244
+ expect( get_log_codes({ logger }) ).to.have.all.members( fixture.log_codes );
245
+ });
246
+
247
+ });
248
+
249
+ });
250
+
251
+ });