@g_package/jest-cucumber-fusion 3.0.2 → 3.0.3

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/dist/index.cjs CHANGED
@@ -58,6 +58,22 @@ var asText = (value) => {
58
58
  }
59
59
  };
60
60
  var describeValue = (value) => `${typeof value} ${asText(value)}`;
61
+ var textOf = (value) => {
62
+ try {
63
+ return String(value);
64
+ } catch {
65
+ return describeValue(value);
66
+ }
67
+ };
68
+ var describeThrown = (thrown) => {
69
+ let message;
70
+ try {
71
+ message = thrown == null ? void 0 : thrown.message;
72
+ } catch {
73
+ return describeValue(thrown);
74
+ }
75
+ return textOf(message ? message : thrown);
76
+ };
61
77
 
62
78
  // src/shared-state.js
63
79
  var STORE = /* @__PURE__ */ Symbol.for("@g_package/jest-cucumber-fusion@3");
@@ -9324,9 +9340,13 @@ var parseFeature = (featureText) => {
9324
9340
  try {
9325
9341
  return { document: parser.parse(featureText), ids };
9326
9342
  } catch (parseFailure) {
9327
- throw new Error(`Error parsing feature Gherkin: ${parseFailure.message}`, {
9328
- cause: parseFailure
9329
- });
9343
+ throw new Error(
9344
+ `Error parsing feature Gherkin: ${/** @type {Error} */
9345
+ parseFailure.message}`,
9346
+ {
9347
+ cause: parseFailure
9348
+ }
9349
+ );
9330
9350
  }
9331
9351
  };
9332
9352
  var compilePickles = (document, absoluteFeatureFilePath, ids) => {
@@ -9334,7 +9354,8 @@ var compilePickles = (document, absoluteFeatureFilePath, ids) => {
9334
9354
  return compile(document, absoluteFeatureFilePath, ids);
9335
9355
  } catch (compileFailure) {
9336
9356
  throw new Error(
9337
- `Error parsing feature Gherkin: ${compileFailure.message}`,
9357
+ `Error parsing feature Gherkin: ${/** @type {Error} */
9358
+ compileFailure.message}`,
9338
9359
  {
9339
9360
  cause: compileFailure
9340
9361
  }
@@ -9649,7 +9670,7 @@ var answerFromTemplate = (loadedFeature, scenario, scenarioNameTemplate) => {
9649
9670
  } catch (templateFailure) {
9650
9671
  throw refuseUnusableName(
9651
9672
  scenario.title,
9652
- `the scenarioNameTemplate threw: ${templateFailure && templateFailure.message ? templateFailure.message : templateFailure}`,
9673
+ `the scenarioNameTemplate threw: ${describeThrown(templateFailure)}`,
9653
9674
  "make the template total over the four variables it is handed: featureTitle, featureTags, scenarioTitle and scenarioTags. A tag list may be empty, and a title may hold any character a feature file allows."
9654
9675
  );
9655
9676
  }
@@ -9706,7 +9727,13 @@ var namedScenarios = (loadedFeature, scenarios, scenarioNameTemplate) => scenari
9706
9727
  )
9707
9728
  })
9708
9729
  );
9709
- var isError = (value) => Object.prototype.toString.call(value) === "[object Error]";
9730
+ var isError = (value) => {
9731
+ try {
9732
+ return Object.prototype.toString.call(value) === "[object Error]";
9733
+ } catch {
9734
+ return false;
9735
+ }
9736
+ };
9710
9737
  var decorationOf = (stepText, stepArguments, originalMessage) => `Failing step: "${stepText}"
9711
9738
 
9712
9739
  Step arguments: ${JSON.stringify(stepArguments)}
@@ -9723,13 +9750,13 @@ var decorateInPlace = (failure, decorated) => {
9723
9750
  var decorate = (stepText, stepArguments, failure) => {
9724
9751
  if (!isError(failure))
9725
9752
  return new Error(
9726
- decorationOf(
9727
- stepText,
9728
- stepArguments,
9729
- failure && failure.message ? failure.message : failure
9730
- )
9753
+ decorationOf(stepText, stepArguments, describeThrown(failure))
9731
9754
  );
9732
- const decorated = decorationOf(stepText, stepArguments, failure.message);
9755
+ const decorated = decorationOf(
9756
+ stepText,
9757
+ stepArguments,
9758
+ textOf(failure.message)
9759
+ );
9733
9760
  try {
9734
9761
  return decorateInPlace(failure, decorated);
9735
9762
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@g_package/jest-cucumber-fusion",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
4
4
  "description": "Write cucumber test as part of a jest run (including coverage)",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -21,12 +21,13 @@
21
21
  "coverage": "node --experimental-vm-modules node_modules/jest/bin/jest.js --coverage",
22
22
  "lint": "eslint . --max-warnings 0",
23
23
  "lint:secrets": "secretlint \"**/*\"",
24
- "commit": "git-cz",
24
+ "commit": "czg",
25
25
  "semantic-release": "semantic-release",
26
26
  "fmt": "npx prettier --write .",
27
27
  "prepare": "node scripts/prepare-hooks.js",
28
28
  "build": "node scripts/build-cjs.js",
29
- "prepack": "npm run build"
29
+ "prepack": "npm run build",
30
+ "typecheck": "tsc -p jsconfig.json"
30
31
  },
31
32
  "repository": {
32
33
  "type": "git",
@@ -50,7 +51,9 @@
50
51
  "@eslint/js": "^10.0.1",
51
52
  "@secretlint/secretlint-rule-pattern": "^13.0.7",
52
53
  "@secretlint/secretlint-rule-preset-recommend": "^13.0.7",
53
- "cz-conventional-changelog": "^3.3.0",
54
+ "@types/jest": "^30.0.0",
55
+ "@types/node": "^18.19.130",
56
+ "czg": "1.14.0",
54
57
  "esbuild": "0.28.2",
55
58
  "eslint": "^10.12.0",
56
59
  "eslint-plugin-jest": "^29.16.6",
@@ -62,16 +65,12 @@
62
65
  "prettier": "3.9.9",
63
66
  "secretlint": "^13.0.7",
64
67
  "semantic-release": "^25.0.5",
65
- "tsd": "^0.33.0"
68
+ "tsd": "^0.33.0",
69
+ "typescript": "^6.0.3"
66
70
  },
67
71
  "publishConfig": {
68
72
  "access": "public"
69
73
  },
70
- "config": {
71
- "commitizen": {
72
- "path": "./node_modules/cz-conventional-changelog"
73
- }
74
- },
75
74
  "release": {
76
75
  "plugins": [
77
76
  "@semantic-release/commit-analyzer",
@@ -95,9 +95,15 @@ const parseFeature = (featureText) => {
95
95
  try {
96
96
  return { document: parser.parse(featureText), ids };
97
97
  } catch (parseFailure) {
98
- throw new Error(`Error parsing feature Gherkin: ${parseFailure.message}`, {
99
- cause: parseFailure,
100
- });
98
+ // @cucumber/gherkin throws Errors only: plain ones, or its own exceptions, which all
99
+ // extend Error (dist/Errors.js). The cast states that contract for the type check rather
100
+ // than adding a branch for a non-Error that Gherkin never throws.
101
+ throw new Error(
102
+ `Error parsing feature Gherkin: ${/** @type {Error} */ (parseFailure).message}`,
103
+ {
104
+ cause: parseFailure,
105
+ },
106
+ );
101
107
  }
102
108
  };
103
109
 
@@ -105,8 +111,9 @@ const compilePickles = (document, absoluteFeatureFilePath, ids) => {
105
111
  try {
106
112
  return gherkin.compile(document, absoluteFeatureFilePath, ids);
107
113
  } catch (compileFailure) {
114
+ // Errors only, as for the parse above.
108
115
  throw new Error(
109
- `Error parsing feature Gherkin: ${compileFailure.message}`,
116
+ `Error parsing feature Gherkin: ${/** @type {Error} */ (compileFailure).message}`,
110
117
  {
111
118
  cause: compileFailure,
112
119
  },
@@ -11,7 +11,7 @@
11
11
  //
12
12
  // Pure: no filesystem, no parser, no Jest global. The port calls it; it calls the template.
13
13
 
14
- import { describeValue } from "./value-description.js";
14
+ import { describeThrown, describeValue } from "./value-description.js";
15
15
 
16
16
  // Kept as the first line of the refusal because the previous engine used it, so anything a
17
17
  // consumer greps for still matches.
@@ -73,13 +73,10 @@ const answerFromTemplate = (loadedFeature, scenario, scenarioNameTemplate) => {
73
73
  try {
74
74
  return scenarioNameTemplate(templateVariablesFor(loadedFeature, scenario));
75
75
  } catch (templateFailure) {
76
+ // A consumer's template can throw anything; describeThrown quotes anything.
76
77
  throw refuseUnusableName(
77
78
  scenario.title,
78
- `the scenarioNameTemplate threw: ${
79
- templateFailure && templateFailure.message
80
- ? templateFailure.message
81
- : templateFailure
82
- }`,
79
+ `the scenarioNameTemplate threw: ${describeThrown(templateFailure)}`,
83
80
  "make the template total over the four variables it is handed: featureTitle, " +
84
81
  "featureTags, scenarioTitle and scenarioTags. A tag list may be empty, and a title " +
85
82
  "may hold any character a feature file allows.",
@@ -10,6 +10,7 @@
10
10
  import { findMatchingStep } from "./step-matching.js";
11
11
  import { unmatchedStepRefusal } from "./code-suggestion.js";
12
12
  import { nameForScenario } from "./scenario-name.js";
13
+ import { describeThrown, textOf } from "./value-description.js";
13
14
 
14
15
  // BIND BEFORE REGISTERING. Every step of every scenario is matched up front, so a refusal
15
16
  // (an unmatched step, an ambiguous one, an unsupported keyword) leaves Fusion() on the way
@@ -70,8 +71,15 @@ const namedScenarios = (loadedFeature, scenarios, scenarioNameTemplate) =>
70
71
  // match. Recognised by its tag rather than instanceof, which fails for an error made in another
71
72
  // realm (Node's own, from inside Jest's test context). Anything that cannot be rewritten (a
72
73
  // frozen error) is wrapped with the original as its cause; anything else thrown is wrapped.
73
- const isError = (value) =>
74
- Object.prototype.toString.call(value) === "[object Error]";
74
+ // Reading the tag can itself throw, for a Proxy whose traps throw or one that was revoked; such
75
+ // a value is no Error, so it is wrapped like any other.
76
+ const isError = (value) => {
77
+ try {
78
+ return Object.prototype.toString.call(value) === "[object Error]";
79
+ } catch {
80
+ return false;
81
+ }
82
+ };
75
83
 
76
84
  const decorationOf = (stepText, stepArguments, originalMessage) =>
77
85
  `Failing step: "${stepText}"\n\n` +
@@ -90,13 +98,13 @@ const decorateInPlace = (failure, decorated) => {
90
98
  const decorate = (stepText, stepArguments, failure) => {
91
99
  if (!isError(failure))
92
100
  return new Error(
93
- decorationOf(
94
- stepText,
95
- stepArguments,
96
- failure && failure.message ? failure.message : failure,
97
- ),
101
+ decorationOf(stepText, stepArguments, describeThrown(failure)),
98
102
  );
99
- const decorated = decorationOf(stepText, stepArguments, failure.message);
103
+ const decorated = decorationOf(
104
+ stepText,
105
+ stepArguments,
106
+ textOf(failure.message),
107
+ );
100
108
  try {
101
109
  return decorateInPlace(failure, decorated);
102
110
  } catch {
@@ -23,4 +23,32 @@ const asText = (value) => {
23
23
 
24
24
  const describeValue = (value) => `${typeof value} ${asText(value)}`;
25
25
 
26
- export { describeValue };
26
+ // How a report quotes what the consumer's code threw: its message when that is truthy,
27
+ // otherwise the value itself, as text. textOf is the text step alone, for a value already known
28
+ // to be the message.
29
+ //
30
+ // A template literal cannot make text of a Symbol, of an object with no prototype, or of an
31
+ // object whose message getter or toString throws, so quoting those crashed the report and the
32
+ // consumer saw a TypeError instead of their own failure (the PR #36 fuzz run). String() makes
33
+ // the same text as a template literal for everything else and accepts a Symbol; anything still
34
+ // unprintable is named as describeValue names it. The message is read once, so a getter that
35
+ // answers differently each time cannot be quoted as one thing and checked as another.
36
+ const textOf = (value) => {
37
+ try {
38
+ return String(value);
39
+ } catch {
40
+ return describeValue(value);
41
+ }
42
+ };
43
+
44
+ const describeThrown = (thrown) => {
45
+ let message;
46
+ try {
47
+ message = thrown == null ? undefined : thrown.message;
48
+ } catch {
49
+ return describeValue(thrown);
50
+ }
51
+ return textOf(message ? message : thrown);
52
+ };
53
+
54
+ export { describeThrown, describeValue, textOf };