@applitools/eyes-cypress 3.60.5 → 3.60.7

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/CHANGELOG.md CHANGED
@@ -1,5 +1,87 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.60.7](https://github.com/Applitools-Dev/sdk/compare/js/eyes-cypress@3.60.6...js/eyes-cypress@3.60.7) (2026-06-18)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * attribute diff failures to correct test when failCypressOnDiff=true | FLD-4628 ([#3923](https://github.com/Applitools-Dev/sdk/issues/3923)) ([0e3af19](https://github.com/Applitools-Dev/sdk/commit/0e3af19421a08d83d35e1d36c0e3879eeabc6378))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * @applitools/utils bumped to 1.15.0
14
+ #### Features
15
+
16
+ * one-time per-execution summary logEvent in storybook | AD-14305 ([#3911](https://github.com/Applitools-Dev/sdk/issues/3911)) ([59e3a5d](https://github.com/Applitools-Dev/sdk/commit/59e3a5dccf74aa1ac1158024316bd305e3515afa))
17
+ * @applitools/req bumped to 1.11.1
18
+ #### Bug Fixes
19
+
20
+ * bundle node-fetch into dist to drop node-domexception dep warning | FLD-4197 ([#3899](https://github.com/Applitools-Dev/sdk/issues/3899)) ([9c3dc52](https://github.com/Applitools-Dev/sdk/commit/9c3dc52866a4a665f1578c39ff43cd0ee5f63492))
21
+
22
+
23
+
24
+ * @applitools/logger bumped to 2.2.13
25
+
26
+ * @applitools/dom-snapshot bumped to 4.17.4
27
+
28
+ * @applitools/socket bumped to 1.3.14
29
+
30
+ * @applitools/image bumped to 1.2.12
31
+
32
+ * @applitools/dom-capture bumped to 11.8.2
33
+
34
+ * @applitools/driver bumped to 1.26.4
35
+
36
+ * @applitools/spec-driver-webdriver bumped to 1.6.4
37
+
38
+ * @applitools/spec-driver-selenium bumped to 1.8.4
39
+
40
+ * @applitools/spec-driver-playwright bumped to 1.9.4
41
+
42
+ * @applitools/spec-driver-puppeteer bumped to 1.8.4
43
+
44
+ * @applitools/screenshoter bumped to 3.12.23
45
+
46
+ * @applitools/nml-client bumped to 1.11.33
47
+
48
+ * @applitools/tunnel-client bumped to 1.12.1
49
+
50
+ * @applitools/ufg-client bumped to 1.22.4
51
+
52
+ * @applitools/core-base bumped to 1.35.3
53
+
54
+ * @applitools/ec-client bumped to 1.12.35
55
+
56
+ * @applitools/core bumped to 4.65.2
57
+
58
+ * @applitools/core-universal bumped to 1.0.21
59
+
60
+ * @applitools/eyes bumped to 1.43.4
61
+
62
+ * @applitools/test-server bumped to 1.4.5
63
+
64
+
65
+ ## [3.60.6](https://github.com/Applitools-Dev/sdk/compare/js/eyes-cypress@3.60.5...js/eyes-cypress@3.60.6) (2026-06-15)
66
+
67
+
68
+ ### Dependencies
69
+
70
+ * @applitools/core-base bumped to 1.35.2
71
+ #### Bug Fixes
72
+
73
+ * re-trigger release for packages missed in the AD-14089 release | AD-14089 ([#3925](https://github.com/Applitools-Dev/sdk/issues/3925)) ([0880c34](https://github.com/Applitools-Dev/sdk/commit/0880c34b66221025e70ca7e3e3fab7b45a9f8d9e))
74
+ * @applitools/nml-client bumped to 1.11.32
75
+
76
+ * @applitools/ec-client bumped to 1.12.34
77
+
78
+ * @applitools/core bumped to 4.65.1
79
+
80
+ * @applitools/core-universal bumped to 1.0.20
81
+
82
+ * @applitools/eyes bumped to 1.43.3
83
+
84
+
3
85
  ## [3.60.5](https://github.com/Applitools-Dev/sdk/compare/js/eyes-cypress@3.60.4...js/eyes-cypress@3.60.5) (2026-06-14)
4
86
 
5
87
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/eyes-cypress",
3
- "version": "3.60.5",
3
+ "version": "3.60.7",
4
4
  "homepage": "https://applitools.com/tutorials/sdks/cypress",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "main": "./index.js",
@@ -52,12 +52,12 @@
52
52
  "setup": "run --top-level xvfb:setup"
53
53
  },
54
54
  "dependencies": {
55
- "@applitools/core": "4.65.0",
56
- "@applitools/core-universal": "1.0.19",
57
- "@applitools/eyes": "1.43.2",
55
+ "@applitools/core": "4.65.2",
56
+ "@applitools/core-universal": "1.0.21",
57
+ "@applitools/eyes": "1.43.4",
58
58
  "@applitools/functional-commons": "1.6.0",
59
- "@applitools/logger": "2.2.12",
60
- "@applitools/utils": "1.14.5",
59
+ "@applitools/logger": "2.2.13",
60
+ "@applitools/utils": "1.15.0",
61
61
  "boxen": "5.1.2",
62
62
  "chalk": "3.0.0",
63
63
  "semver": "7.6.2",
@@ -69,7 +69,7 @@
69
69
  "@applitools/bongo": "^5.10.0",
70
70
  "@applitools/generic": "^3.9.2",
71
71
  "@applitools/snaptdout": "^1.1.1",
72
- "@applitools/test-server": "^1.4.4",
72
+ "@applitools/test-server": "^1.4.5",
73
73
  "@applitools/test-utils": "^1.5.17",
74
74
  "@types/he": "^1",
75
75
  "@types/node": "^12.20.55",
@@ -1,4 +1,4 @@
1
- /* global Cypress,cy,after */
1
+ /* global Cypress,cy,after,afterEach */
2
2
  'use strict'
3
3
  const spec = require('../../dist/browser/spec-driver')
4
4
  const Refer = require('../../dist/browser/refer')
@@ -26,10 +26,39 @@ let manager,
26
26
  _summary,
27
27
  connectedToUniversal,
28
28
  openAndGlobalConfig,
29
- isOpen = false
29
+ isOpen = false,
30
+ // Per-test diff-attribution state: did the current test open Eyes, and has it already been checked.
31
+ eyesOpenedInTest = false,
32
+ currentTestHandled = false
30
33
 
31
34
  const deleteTest = options => socket.request('Core.deleteTest', options)
32
35
 
36
+ const DIFFS_OR_ERRORS_MESSAGE = 'Eyes-Cypress detected diffs or errors'
37
+
38
+ // When per-test attribution is on, throws on a diff/error from within the current test's own execution
39
+ // context so Cypress blames the test that produced it. Called from eyesClose() (after it closes Eyes)
40
+ // and from the afterEach() hook; currentTestHandled makes it run once per test. It does NOT close Eyes —
41
+ // closing would change abort / duplicate-removal semantics for tests that intentionally leave Eyes open,
42
+ // and the results are available from the checks alone.
43
+ async function throwOnDiffForCurrentTest() {
44
+ if (currentTestHandled || !isOpen) return
45
+ currentTestHandled = true
46
+
47
+ if (!perTestDiffAttribution) return
48
+
49
+ // Awaiting the results blocks the test until its UFG render completes — required for correct attribution.
50
+ const results = await socket.request('Eyes.getResults', {eyes, settings: {throwErr: false}})
51
+ if (results && results.length > 0) {
52
+ // TAP files are written once in the after() hook, not here.
53
+ const resultConfig = makeResultConfig({shouldCreateTapFile: false})
54
+ const message = await socket.request('Test.printTestResults', {testResults: results, resultConfig})
55
+ printToLog(`Eyes: per-test diff check message: ${message}`)
56
+ if (message && message.includes(DIFFS_OR_ERRORS_MESSAGE)) {
57
+ throw new Error(message)
58
+ }
59
+ }
60
+ }
61
+
33
62
  async function getSummary() {
34
63
  if (_summary) return _summary
35
64
  await Promise.all(closePromiseArr)
@@ -67,6 +96,10 @@ const shouldCallAfterHook =
67
96
 
68
97
  const notFailCypressAfterAllSpecs = !Cypress.config('appliConfFile').failCypressAfterAllSpecs
69
98
 
99
+ // True when diffs are attributed per-test (thrown from the test's own context) instead of batched into
100
+ // the spec-level after() hook.
101
+ const perTestDiffAttribution = Cypress.config('eyesFailCypressOnDiff') && notFailCypressAfterAllSpecs
102
+
70
103
  Cypress.Commands.add('eyesGetAllTestResults', () => {
71
104
  Cypress.log({name: 'Eyes: getAllTestResults'})
72
105
  printToLog(
@@ -112,12 +145,26 @@ if (shouldCallAfterHook) {
112
145
  isCurrentTestDisabled = false
113
146
  return
114
147
  }
148
+ // Always finalize results and run post-spec tasks (e.g. writing TAP files) here. With per-test
149
+ // attribution on, the afterEach() hook below already throws diffs against the correct test, so
150
+ // suppress the throw here — throwing in this spec-level after() hook would re-blame the last test.
115
151
  const summary = await getSummary()
116
- await throwErrorIfExistsInSummary(summary, Cypress.config('eyesFailCypressOnDiff'), false)
152
+ await throwErrorIfExistsInSummary(summary, Cypress.config('eyesFailCypressOnDiff'), false, perTestDiffAttribution)
117
153
  })
118
154
  })
119
155
  }
120
156
 
157
+ // With per-test attribution on, check each test's Eyes from an afterEach() hook — which runs in that
158
+ // test's own context — so a diff is blamed on the test that produced it. Covers the common case where
159
+ // the test relies on the SDK's automatic post-spec close. (Does not close Eyes — see throwOnDiffForCurrentTest.)
160
+ if (perTestDiffAttribution) {
161
+ afterEach(() => {
162
+ if (!eyesOpenedInTest) return
163
+ eyesOpenedInTest = false
164
+ return cy.then({timeout: 86400000}, () => throwOnDiffForCurrentTest())
165
+ })
166
+ }
167
+
121
168
  let isCurrentTestDisabled
122
169
 
123
170
  Cypress.Commands.add('eyesOpen', function (args = {}) {
@@ -169,6 +216,8 @@ Cypress.Commands.add('eyesOpen', function (args = {}) {
169
216
 
170
217
  eyes = await socket.request('EyesManager.openEyes', {manager, target, config: openAndGlobalConfig})
171
218
  isOpen = true
219
+ eyesOpenedInTest = true
220
+ currentTestHandled = false
172
221
  })
173
222
  })
174
223
 
@@ -191,22 +240,25 @@ Cypress.Commands.add('eyesCheckWindow', (args = {}) => {
191
240
  })
192
241
 
193
242
  Cypress.Commands.add('eyesClose', () => {
194
- return cy.then({timeout: 86400000}, () => {
195
- if (isCurrentTestDisabled) return
196
- if (!isOpen) throw new EyesNotOpenError('eyesClose')
197
-
198
- Cypress.log({name: 'Eyes: close'})
243
+ return cy.then({timeout: 86400000}, async () => {
199
244
  if (isCurrentTestDisabled) {
200
245
  isCurrentTestDisabled = false
201
246
  return
202
247
  }
248
+ if (!isOpen) throw new EyesNotOpenError('eyesClose')
203
249
 
204
- // Eyes.close in core is not waiting on results anymore. So we should return it in order to await it
250
+ Cypress.log({name: 'Eyes: close'})
251
+
252
+ // Eyes.close in core no longer waits on results, so await it explicitly.
205
253
  const p = socket.request('Eyes.close', {eyes, config: openAndGlobalConfig}).catch(err => {
206
254
  console.log('Error in cy.eyesClose', err)
207
255
  })
208
256
  closePromiseArr.push(p)
209
- return p
257
+ await p
258
+
259
+ // Run the per-test diff check inside the test's own context (the afterEach() hook does the same for
260
+ // tests that don't call eyesClose(); currentTestHandled prevents doing it twice).
261
+ await throwOnDiffForCurrentTest()
210
262
  })
211
263
  })
212
264
 
@@ -243,15 +295,24 @@ function isNonVisualTestError(testResult) {
243
295
  return result
244
296
  }
245
297
 
246
- async function throwErrorIfExistsInSummary(summary, shouldThrowError, shouldDisplayCriticalErrors) {
247
- const resultConfig = {
298
+ function makeResultConfig({shouldThrowError = true, shouldCreateTapFile}) {
299
+ return {
248
300
  showLogs: Cypress.config('appliConfFile').showLogs,
249
- shouldThrowError: shouldThrowError,
301
+ shouldThrowError,
250
302
  isTextTerminal: Cypress.config('isTextTerminal'),
251
303
  tapDirPath: Cypress.config('appliConfFile').tapDirPath,
252
304
  tapFileName: Cypress.config('appliConfFile').tapFileName,
253
- shouldCreateTapFile: shouldDoPostSpecTasks,
305
+ shouldCreateTapFile,
254
306
  }
307
+ }
308
+
309
+ async function throwErrorIfExistsInSummary(
310
+ summary,
311
+ shouldThrowError,
312
+ shouldDisplayCriticalErrors,
313
+ suppressDiffThrow = false,
314
+ ) {
315
+ const resultConfig = makeResultConfig({shouldThrowError, shouldCreateTapFile: shouldDoPostSpecTasks})
255
316
  const testResults = summary.results?.map(({result}) => result) ?? []
256
317
  const filteredTestResults = shouldDisplayCriticalErrors
257
318
  ? testResults.filter(testResult => testResult.error && isNonVisualTestError(testResult))
@@ -263,9 +324,10 @@ async function throwErrorIfExistsInSummary(summary, shouldThrowError, shouldDisp
263
324
  }, results message: ${message}`,
264
325
  )
265
326
  if (
266
- (!!getGlobalConfigProperty('eyesFailCypressOnDiff') &&
327
+ (!suppressDiffThrow &&
328
+ !!getGlobalConfigProperty('eyesFailCypressOnDiff') &&
267
329
  message &&
268
- message.includes('Eyes-Cypress detected diffs or errors')) ||
330
+ message.includes(DIFFS_OR_ERRORS_MESSAGE)) ||
269
331
  (shouldDisplayCriticalErrors && filteredTestResults.length > 0 && message)
270
332
  ) {
271
333
  printToLog('Eyes: throwErrorIfExistsInSummary throwing error')