@koenvanbelle/cypress-soft-assertions 1.0.7 → 1.0.8

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 (2) hide show
  1. package/dist/index.js +48 -103
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9,8 +9,9 @@
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  let softAssertionErrors = [];
11
11
  let isInSoftTest = false;
12
- let originalAssert = null;
13
- const retryWindows = new Map();
12
+ let activeFailHandler = null;
13
+ let activeSoftTestTitle = null;
14
+ let finalizerInstalled = false;
14
15
  /**
15
16
  * Track a soft assertion failure so it can be reported at test end.
16
17
  */
@@ -27,97 +28,61 @@ function captureSoftAssertion(error) {
27
28
  });
28
29
  }
29
30
  /**
30
- * Read command metadata from Cypress internals in a defensive way.
31
+ * Intercept Cypress failures and make assertion failures soft in soft_it() tests.
31
32
  */
32
- function getCurrentCommand() {
33
- const state = cy === null || cy === void 0 ? void 0 : cy.state;
34
- if (typeof state !== 'function') {
35
- return null;
36
- }
37
- return state('current') || null;
38
- }
39
- function getCommandProp(command, prop) {
40
- if (!command) {
41
- return undefined;
42
- }
43
- if (typeof command.get === 'function') {
44
- return command.get(prop);
45
- }
46
- if (command.attributes && prop in command.attributes) {
47
- return command.attributes[prop];
33
+ function setupSoftAssertions() {
34
+ if (!activeFailHandler) {
35
+ activeFailHandler = (error) => {
36
+ if (!isInSoftTest) {
37
+ throw error;
38
+ }
39
+ captureSoftAssertion(error);
40
+ return false;
41
+ };
42
+ Cypress.on('fail', activeFailHandler);
48
43
  }
49
- return command[prop];
50
- }
51
- /**
52
- * Build retry context for the currently running Cypress command.
53
- */
54
- function getAssertionContext() {
55
- const command = getCurrentCommand();
56
- const commandId = String(getCommandProp(command, 'id') || getCommandProp(command, 'chainerId') || '');
57
- const commandName = String(getCommandProp(command, 'name') || '');
58
- const timeout = Number(getCommandProp(command, 'timeout')) || Number(Cypress.config('defaultCommandTimeout'));
59
- const isRetriable = commandName === 'should' || commandName === 'and';
60
- return {
61
- commandId,
62
- timeout,
63
- isRetriable,
64
- };
65
44
  }
66
- function formatSoftAssertionError(error, timeout, isRetriable) {
67
- const message = String((error === null || error === void 0 ? void 0 : error.message) || error);
68
- if (isRetriable && !/Timed out retrying after/i.test(message)) {
69
- return {
70
- ...error,
71
- message: `Timed out retrying after ${timeout}ms: ${message}`,
72
- };
45
+ function getTestTitle(test) {
46
+ if (test && typeof test.fullTitle === 'function') {
47
+ return test.fullTitle();
73
48
  }
74
- return error;
49
+ return String((test === null || test === void 0 ? void 0 : test.title) || '');
75
50
  }
76
- /**
77
- * Intercept Chai assertions and make them soft in soft_it() tests.
78
- */
79
- function setupSoftAssertions() {
80
- if (!originalAssert) {
81
- originalAssert = chai.Assertion.prototype.assert;
51
+ function installFinalizer() {
52
+ if (finalizerInstalled) {
53
+ return;
82
54
  }
83
- chai.Assertion.prototype.assert = function (...args) {
55
+ afterEach(function () {
56
+ var _a, _b;
84
57
  if (!isInSoftTest) {
85
- return originalAssert.apply(this, args);
58
+ return;
86
59
  }
87
- const context = getAssertionContext();
88
- try {
89
- const result = originalAssert.apply(this, args);
90
- if (context.commandId) {
91
- retryWindows.delete(context.commandId);
92
- }
93
- return result;
60
+ const currentTest = (this.currentTest || this.test);
61
+ if (!currentTest || getTestTitle(currentTest) !== activeSoftTestTitle) {
62
+ return;
94
63
  }
95
- catch (rawError) {
96
- const error = formatSoftAssertionError(rawError, context.timeout, context.isRetriable);
97
- if (context.isRetriable && context.commandId) {
98
- const currentWindow = retryWindows.get(context.commandId) || {
99
- startedAt: Date.now(),
100
- timeout: context.timeout,
101
- };
102
- retryWindows.set(context.commandId, currentWindow);
103
- const elapsed = Date.now() - currentWindow.startedAt;
104
- if (elapsed < currentWindow.timeout) {
105
- throw rawError;
106
- }
107
- retryWindows.delete(context.commandId);
108
- }
109
- captureSoftAssertion(error);
64
+ const finalError = finalizeSoftTest();
65
+ if (!finalError) {
110
66
  return;
111
67
  }
112
- };
68
+ currentTest.err = finalError;
69
+ currentTest.state = 'failed';
70
+ const runner = (_b = (_a = Cypress === null || Cypress === void 0 ? void 0 : Cypress.mocha) === null || _a === void 0 ? void 0 : _a.getRunner) === null || _b === void 0 ? void 0 : _b.call(_a);
71
+ if (runner && typeof runner.fail === 'function') {
72
+ runner.fail(currentTest, finalError);
73
+ return;
74
+ }
75
+ throw finalError;
76
+ });
77
+ finalizerInstalled = true;
113
78
  }
114
79
  /**
115
80
  * Restore original Chai assertion behavior.
116
81
  */
117
82
  function restoreAssertions() {
118
- retryWindows.clear();
119
- if (originalAssert) {
120
- chai.Assertion.prototype.assert = originalAssert;
83
+ if (activeFailHandler) {
84
+ Cypress.off('fail', activeFailHandler);
85
+ activeFailHandler = null;
121
86
  }
122
87
  }
123
88
  /**
@@ -151,6 +116,7 @@ function buildSoftAssertionError() {
151
116
  function finalizeSoftTest() {
152
117
  isInSoftTest = false;
153
118
  restoreAssertions();
119
+ activeSoftTestTitle = null;
154
120
  return buildSoftAssertionError();
155
121
  }
156
122
  /**
@@ -159,52 +125,31 @@ function finalizeSoftTest() {
159
125
  function abortSoftTest() {
160
126
  isInSoftTest = false;
161
127
  restoreAssertions();
128
+ activeSoftTestTitle = null;
162
129
  }
163
130
  /**
164
131
  * Create a soft_it variant from a Mocha it function.
165
132
  */
166
133
  function createSoftIt(baseIt) {
134
+ installFinalizer();
167
135
  return function (title, fn) {
168
136
  return baseIt(title, function () {
169
137
  isInSoftTest = true;
170
138
  softAssertionErrors = [];
139
+ activeSoftTestTitle = getTestTitle(this.currentTest || this.test);
171
140
  setupSoftAssertions();
172
141
  try {
173
142
  const result = fn.call(this);
174
143
  if (result && typeof result.then === 'function') {
175
144
  return result
176
145
  .catch((error) => {
177
- if ((error === null || error === void 0 ? void 0 : error.name) === 'AssertionError') {
178
- captureSoftAssertion(error);
179
- return;
180
- }
181
146
  abortSoftTest();
182
147
  throw error;
183
- })
184
- .then(() => cy.wrap(null).then(() => {
185
- const finalError = finalizeSoftTest();
186
- if (finalError) {
187
- throw finalError;
188
- }
189
- }));
148
+ });
190
149
  }
191
- return cy.wrap(null).then(() => {
192
- const finalError = finalizeSoftTest();
193
- if (finalError) {
194
- throw finalError;
195
- }
196
- });
150
+ return result;
197
151
  }
198
152
  catch (error) {
199
- if ((error === null || error === void 0 ? void 0 : error.name) === 'AssertionError') {
200
- captureSoftAssertion(error);
201
- return cy.wrap(null).then(() => {
202
- const finalError = finalizeSoftTest();
203
- if (finalError) {
204
- throw finalError;
205
- }
206
- });
207
- }
208
153
  abortSoftTest();
209
154
  throw error;
210
155
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koenvanbelle/cypress-soft-assertions",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "A Cypress plugin that provides soft_it() for soft assertions - all assertions continue on failure and are reported together",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",