@applitools/core 4.74.2 → 4.75.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +15 -20
  3. package/dist/automation/abort.js +8 -18
  4. package/dist/automation/close.js +8 -27
  5. package/dist/automation/get-results.js +3 -11
  6. package/dist/automation/utils/make-environment-loggers.js +39 -0
  7. package/dist/automation/utils/to-environment-key.js +6 -1
  8. package/dist/classic/check-and-close.js +26 -69
  9. package/dist/classic/check.js +85 -354
  10. package/dist/classic/get-base-eyes.js +15 -54
  11. package/dist/classic/open-eyes.js +17 -10
  12. package/dist/classic/utils/capture.js +209 -0
  13. package/dist/get-typed-eyes.js +2 -2
  14. package/dist/offline/run-offline-snapshots.js +3 -1
  15. package/dist/tasks/abort.js +32 -0
  16. package/dist/tasks/aborted-check.js +14 -0
  17. package/dist/tasks/classic/capture.js +54 -0
  18. package/dist/tasks/classic/steps.js +51 -0
  19. package/dist/tasks/classic/upload.js +40 -0
  20. package/dist/tasks/close.js +31 -0
  21. package/dist/tasks/fill.js +13 -0
  22. package/dist/tasks/get-results.js +29 -0
  23. package/dist/tasks/graph.js +6 -0
  24. package/dist/tasks/index.js +20 -0
  25. package/dist/tasks/lifecycle.js +101 -0
  26. package/dist/tasks/match.js +109 -0
  27. package/dist/tasks/open.js +38 -0
  28. package/dist/tasks/queries.js +39 -0
  29. package/dist/tasks/types.js +2 -0
  30. package/dist/tasks/ufg/create-render-target.js +16 -0
  31. package/dist/tasks/ufg/recheck.js +49 -0
  32. package/dist/tasks/ufg/render.js +66 -0
  33. package/dist/tasks/ufg/steps.js +51 -0
  34. package/dist/tasks/upload-target.js +10 -0
  35. package/dist/ufg/check-and-close.js +32 -137
  36. package/dist/ufg/check.js +39 -175
  37. package/dist/ufg/get-base-eyes.js +34 -72
  38. package/dist/ufg/open-eyes.js +14 -8
  39. package/package.json +6 -5
  40. package/types/automation/abort.d.ts +2 -3
  41. package/types/automation/close.d.ts +2 -3
  42. package/types/automation/types.d.ts +13 -16
  43. package/types/automation/utils/make-environment-loggers.d.ts +3 -0
  44. package/types/classic/get-base-eyes.d.ts +5 -9
  45. package/types/classic/open-eyes.d.ts +4 -3
  46. package/types/classic/types.d.ts +1 -1
  47. package/types/classic/utils/capture.d.ts +21 -0
  48. package/types/tasks/abort.d.ts +11 -0
  49. package/types/tasks/aborted-check.d.ts +9 -0
  50. package/types/tasks/classic/capture.d.ts +10 -0
  51. package/types/tasks/classic/steps.d.ts +17 -0
  52. package/types/tasks/classic/upload.d.ts +14 -0
  53. package/types/tasks/close.d.ts +9 -0
  54. package/types/tasks/fill.d.ts +8 -0
  55. package/types/tasks/get-results.d.ts +6 -0
  56. package/types/tasks/graph.d.ts +3 -0
  57. package/types/tasks/index.d.ts +3 -0
  58. package/types/tasks/lifecycle.d.ts +23 -0
  59. package/types/tasks/match.d.ts +13 -0
  60. package/types/tasks/open.d.ts +10 -0
  61. package/types/tasks/queries.d.ts +15 -0
  62. package/types/tasks/types.d.ts +187 -0
  63. package/types/tasks/ufg/create-render-target.d.ts +11 -0
  64. package/types/tasks/ufg/recheck.d.ts +20 -0
  65. package/types/tasks/ufg/render.d.ts +15 -0
  66. package/types/tasks/ufg/steps.d.ts +15 -0
  67. package/types/tasks/upload-target.d.ts +5 -0
  68. package/types/ufg/get-base-eyes.d.ts +5 -10
  69. package/types/ufg/open-eyes.d.ts +4 -3
  70. package/types/ufg/types.d.ts +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.75.0](https://github.com/Applitools-Dev/sdk/compare/js/core@4.74.2...js/core@4.75.0) (2026-11-05)
4
+
5
+
6
+ ### Features
7
+
8
+ * run the Eyes session lifecycle on the task graph | AD-16964 ([#4361](https://github.com/Applitools-Dev/sdk/issues/4361)) ([51eb00f](https://github.com/Applitools-Dev/sdk/commit/51eb00f60f5e95a91689f170192b4d7d580437af))
9
+
10
+
11
+ ### Code Refactoring
12
+
13
+ * split deps from after, typed labels, filler awaits | AD-16964 ([#4362](https://github.com/Applitools-Dev/sdk/issues/4362)) ([6aaf46b](https://github.com/Applitools-Dev/sdk/commit/6aaf46be75059911917c8c31e8e008126cea2c5a))
14
+
15
+
16
+ ### Dependencies
17
+
18
+ * @applitools/task-manager bumped to 1.0.0
19
+ #### Features
20
+
21
+ * dependency-aware task graph package | AD-16964 ([#4360](https://github.com/Applitools-Dev/sdk/issues/4360)) ([6690133](https://github.com/Applitools-Dev/sdk/commit/66901337363cfec42b8cd7caa0f41e8ea3f71a6c))
22
+ * run the Eyes session lifecycle on the task graph | AD-16964 ([#4361](https://github.com/Applitools-Dev/sdk/issues/4361)) ([51eb00f](https://github.com/Applitools-Dev/sdk/commit/51eb00f60f5e95a91689f170192b4d7d580437af))
23
+
24
+
25
+ #### Code Refactoring
26
+
27
+ * split deps from after, typed labels, filler awaits | AD-16964 ([#4362](https://github.com/Applitools-Dev/sdk/issues/4362)) ([6aaf46b](https://github.com/Applitools-Dev/sdk/commit/6aaf46be75059911917c8c31e8e008126cea2c5a))
28
+
29
+
30
+ #### Miscellaneous Chores
31
+
32
+ * release as 1.0.0 | AD-16964 ([d1b823c](https://github.com/Applitools-Dev/sdk/commit/d1b823c2974ca64e50ff0c53890ed0594a53dc74))
33
+ * @applitools/ufg-client bumped to 1.26.0
34
+ #### Features
35
+
36
+ * run the Eyes session lifecycle on the task graph | AD-16964 ([#4361](https://github.com/Applitools-Dev/sdk/issues/4361)) ([51eb00f](https://github.com/Applitools-Dev/sdk/commit/51eb00f60f5e95a91689f170192b4d7d580437af))
37
+
38
+
39
+ #### Code Refactoring
40
+
41
+ * split deps from after, typed labels, filler awaits | AD-16964 ([#4362](https://github.com/Applitools-Dev/sdk/issues/4362)) ([6aaf46b](https://github.com/Applitools-Dev/sdk/commit/6aaf46be75059911917c8c31e8e008126cea2c5a))
42
+ * @applitools/nml-client bumped to 1.12.13
43
+
44
+ * @applitools/core-base bumped to 1.42.0
45
+ #### Features
46
+
47
+ * run the Eyes session lifecycle on the task graph | AD-16964 ([#4361](https://github.com/Applitools-Dev/sdk/issues/4361)) ([51eb00f](https://github.com/Applitools-Dev/sdk/commit/51eb00f60f5e95a91689f170192b4d7d580437af))
48
+
49
+
50
+ #### Code Refactoring
51
+
52
+ * split deps from after, typed labels, filler awaits | AD-16964 ([#4362](https://github.com/Applitools-Dev/sdk/issues/4362)) ([6aaf46b](https://github.com/Applitools-Dev/sdk/commit/6aaf46be75059911917c8c31e8e008126cea2c5a))
53
+ * @applitools/ec-client bumped to 1.12.57
54
+
55
+
3
56
  ## [4.74.2](https://github.com/Applitools-Dev/sdk/compare/js/core@4.74.1...js/core@4.74.2) (2026-11-04)
4
57
 
5
58
 
package/README.md CHANGED
@@ -63,8 +63,8 @@ check()
63
63
  2. **Scroll root / lazy load** — the driver scrolls and waits for deferred content
64
64
  3. **Screenshot** — a full-page or viewport PNG is captured locally
65
65
  4. **DOM capture** (optional) — if `sendDom=true`, the serialized DOM is captured for Root Cause Analysis (RCA)
66
- 5. **Session open** (lazy) — `getBaseEyes()` opens the Applitools test session on first use
67
- 6. **Upload + compare** — `baseEyes.check()` uploads the image+DOM and triggers comparison
66
+ 5. **Session open** (lazy) — the environment's `open` task runs once a check needs it
67
+ 6. **Upload + compare** — the `upload` task uploads the image+DOM (`baseEyes.uploadTarget()`), then the `match` task triggers comparison (`baseEyes.match()`)
68
68
 
69
69
  ### matchTimeout behavior
70
70
 
@@ -98,14 +98,14 @@ check()
98
98
  │ ├── createRenderTargetFromSnapshot()
99
99
  │ │ └── ufgClient.uploadResources() ← CSS, fonts, images → UFG CDN
100
100
  │ │
101
- │ ├── getBaseEyes() ← open test session (lazy, per environment)
101
+ │ ├── open task ← open test session (lazy, per environment)
102
102
  │ │
103
103
  │ ├── ufgClient.render()
104
104
  │ │ └── UFG renders DOM in target browser/device → returns rendered image
105
105
  │ │
106
- │ └── baseEyes.check() ← compare rendered image against baseline
106
+ │ └── baseEyes.match() ← compare rendered image against baseline
107
107
  │
108
- └── all environment promises queued in eyes.storage
108
+ └── each environment's tasks run on core's task graph (src/tasks/)
109
109
  ```
110
110
 
111
111
  ### Key files
@@ -123,8 +123,8 @@ check()
123
123
  2. **DOM snapshot** — the page's full DOM (HTML, CSS, iframes) is serialized and resources are collected
124
124
  3. **Resource upload** — CSS, fonts, images are uploaded to the UFG CDN (cached by URL to avoid re-uploads)
125
125
  4. **Render request** — sent to the UFG rendering farm per target environment (browser + viewport or device)
126
- 5. **Session open** (lazy, per environment) — `getBaseEyes()` opens one Applitools session per environment
127
- 6. **Compare** — `baseEyes.check()` receives the rendered image reference (`renderId`) and triggers comparison
126
+ 5. **Session open** (lazy, per environment) — each environment's `open` task opens its Applitools session
127
+ 6. **Compare** — the `match` task sends the rendered image reference (`renderId`) to `baseEyes.match()`, which triggers comparison
128
128
 
129
129
  ### Environment targeting
130
130
 
@@ -171,7 +171,7 @@ Two distinct environment shapes flow through classic check. Confusing them is th
171
171
  | **Requested environment** (also called *unique environment*) | `RenderEnvironment` | `{iosDeviceInfo: {deviceName: 'iPhone 12'}}` or `{name: 'chrome', width: 1280, height: 800}` | Comes from `settings.environments` (user input). After `uniquifyEnvironments()`, duplicates get a synthetic `environmentId` to map to separate sessions. |
172
172
  | **Actual / exact environment** | `ExactEnvironment` | `{environmentId, deviceName, os, viewportSize, requested: <RenderEnvironment>}` | Returned by `takeWebScreenshot` / `takeNMLScreenshot` after the device is resolved. The flat shape that `core-base` and the Applitools server understand. Always has `requested` pointing back to the original `RenderEnvironment`. |
173
173
 
174
- **Key invariant:** `toEnvironmentKey(exactEnvironment)` === `toEnvironmentKey(requestedEnvironment)` because `toEnvironmentKey` uses `env.requested ?? env`. This is how the `makeGetBaseEyes` cache correctly matches an early session-open (keyed on the requested environment) to the later check (keyed on the exact environment).
174
+ **Key invariant:** `toEnvironmentKey(exactEnvironment)` === `toEnvironmentKey(requestedEnvironment)` because `toEnvironmentKey` uses `env.requested ?? env`. This is how a check keyed on the exact environment finds the open declared for the requested one.
175
175
 
176
176
  **Known bug:** In the `matchTimeout` path, `base.openEyes` is called with the *requested* environment (`{iosDeviceInfo: ...}`) instead of the *exact* environment (`{deviceName, os, viewportSize, ...}`). `core-base/server/requests.ts` reads the flat fields (`os`, `deviceName`, `viewportSize`) which are `undefined` on the requested form, so the session opens on the server with empty environment info. This only affects NML (iOS/Android native) environments since web environments are not transformed and `exactEnvironment === requestedEnvironment`.
177
177
 
@@ -179,22 +179,17 @@ Two distinct environment shapes flow through classic check. Confusing them is th
179
179
 
180
180
  ## Session Lifecycle (Both Strategies)
181
181
 
182
- Sessions are opened **lazily** — the Applitools test session is not created during `openEyes()`, but on the first `getBaseEyes()` call within a check. This avoids charging concurrency for tests that open but never check.
182
+ Sessions are opened **lazily** — `openEyes()` declares a lazy `open` task per environment (`src/tasks/`); the first check's steps activate it, and a close or abort dismisses one nothing needed. This avoids charging concurrency for tests that open but never check.
183
183
 
184
184
  ```
185
- openEyes() → creates in-memory Eyes object, no server call
186
- check() → getBaseEyes() → POST /api/sessions (first time only)
187
- check() → getBaseEyes() → returns cached session (subsequent calls)
188
- close() / abort() → closes all open sessions, awaits all queued jobs
185
+ openEyes() → declares lazy opens, no server call
186
+ check() → activates the env's open → POST /api/sessions (first time only)
187
+ close() → one close task per environment, after its last step
188
+ abort() → one abort task per environment, as soon as it is open (doesn't wait for steps)
189
189
  ```
190
190
 
191
191
  ---
192
192
 
193
- ## Storage Model
193
+ ## Task Graph
194
194
 
195
- Both strategies push check promises into `eyes.storage`, a `Map<environmentKey, {eyes, jobs[]}>`:
196
-
197
- - `eyes` — a controlled promise resolving to the base eyes session
198
- - `jobs` — array of check promises for that environment
199
-
200
- `close()` waits for all jobs across all environments before collecting results.
195
+ Both strategies add their steps to core's task graph (`src/tasks/`), each task labeled `{session, env}`; close, abort and getResults query it for each environment's tasks.
@@ -2,9 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeAbort = void 0;
4
4
  const uniquify_environments_1 = require("./utils/uniquify-environments");
5
- function makeAbort({ eyes, driver, controller, environments: defaultEnvironments, logger: mainLogger, }) {
5
+ const tasks_1 = require("../tasks");
6
+ function makeAbort({ eyes, driver, controller, logger: mainLogger }) {
6
7
  return async function abort({ settings, logger = mainLogger, } = {}) {
7
- var _a;
8
8
  logger = logger.extend(mainLogger);
9
9
  logger.log('Command "abort" is called with settings', settings);
10
10
  if (!eyes.running) {
@@ -15,6 +15,7 @@ function makeAbort({ eyes, driver, controller, environments: defaultEnvironments
15
15
  ;
16
16
  eyes.running = false;
17
17
  }
18
+ // Signal in-flight checks; queued and later steps self-abort (they read `signal`/`baseEyes.running`).
18
19
  controller.abort();
19
20
  settings !== null && settings !== void 0 ? settings : (settings = {});
20
21
  if (!settings.testMetadata && driver) {
@@ -25,23 +26,12 @@ function makeAbort({ eyes, driver, controller, environments: defaultEnvironments
25
26
  logger.warn('Command "abort" received an error during extracting driver metadata', error);
26
27
  }
27
28
  }
28
- (_a = settings.environments) !== null && _a !== void 0 ? _a : (settings.environments = defaultEnvironments);
29
- if (eyes.storage.size === 0 && settings.environments && settings.environments.length > 0) {
30
- const uniqueEnvironments = (0, uniquify_environments_1.uniquifyEnvironments)(settings.environments);
31
- logger.log('Command "abort" starting filler tests for environments', uniqueEnvironments);
32
- await Promise.all(uniqueEnvironments.map(environment => eyes.getBaseEyes({ settings: { environment }, logger })));
29
+ const fillers = (0, tasks_1.declareFillers)(eyes, settings.environments && (0, uniquify_environments_1.uniquifyEnvironments)(settings.environments), logger);
30
+ if (fillers.length > 0) {
31
+ logger.log('Command "abort" starting filler tests for environments', fillers.map(open => open.labels.env));
32
+ await Promise.all(fillers.map(open => open.promise));
33
33
  }
34
- eyes.storage.forEach(async (item) => {
35
- var _a, _b;
36
- try {
37
- const eyes = await item.eyes;
38
- await eyes.abort({ settings, logger });
39
- }
40
- catch (error) {
41
- logger.warn('Command "abort" received an error during waiting for eyes instances in background', error);
42
- await ((_b = (_a = error === null || error === void 0 ? void 0 : error.info) === null || _a === void 0 ? void 0 : _a.eyes) === null || _b === void 0 ? void 0 : _b.abort({ settings, logger }));
43
- }
44
- });
34
+ (0, tasks_1.abortSession)(eyes.session, { settings, logger });
45
35
  };
46
36
  }
47
37
  exports.makeAbort = makeAbort;
@@ -2,9 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeClose = void 0;
4
4
  const uniquify_environments_1 = require("./utils/uniquify-environments");
5
- function makeClose({ eyes, driver, environments: defaultEnvironments, logger: mainLogger, }) {
5
+ const tasks_1 = require("../tasks");
6
+ function makeClose({ eyes, driver, logger: mainLogger }) {
6
7
  return async function close({ settings, logger = mainLogger, } = {}) {
7
- var _a;
8
8
  logger = logger.extend(mainLogger);
9
9
  logger.log('Command "close" is called with settings', settings);
10
10
  if (!eyes.running) {
@@ -16,6 +16,7 @@ function makeClose({ eyes, driver, environments: defaultEnvironments, logger: ma
16
16
  eyes.running = false;
17
17
  }
18
18
  settings !== null && settings !== void 0 ? settings : (settings = {});
19
+ // testMetadata must be set before the closes are added — a fused matchandend reports self-heal from it.
19
20
  if (!settings.testMetadata && driver) {
20
21
  try {
21
22
  settings.testMetadata = await driver.getSessionMetadata();
@@ -24,32 +25,12 @@ function makeClose({ eyes, driver, environments: defaultEnvironments, logger: ma
24
25
  logger.warn('Command "close" received an error during extracting driver metadata', error);
25
26
  }
26
27
  }
27
- (_a = settings.environments) !== null && _a !== void 0 ? _a : (settings.environments = defaultEnvironments);
28
- if (eyes.storage.size === 0 && settings.environments && settings.environments.length > 0) {
29
- const uniqueEnvironments = (0, uniquify_environments_1.uniquifyEnvironments)(settings.environments);
30
- logger.log('Command "close" starting filler tests for environments', settings.environments);
31
- await Promise.all(uniqueEnvironments.map(environment => eyes.getBaseEyes({ settings: { environment }, logger })));
28
+ const fillers = (0, tasks_1.declareFillers)(eyes, settings.environments && (0, uniquify_environments_1.uniquifyEnvironments)(settings.environments), logger);
29
+ if (fillers.length > 0) {
30
+ logger.log('Command "close" starting filler tests for environments', fillers.map(open => open.labels.env));
31
+ await Promise.all(fillers.map(open => open.promise));
32
32
  }
33
- eyes.storage.forEach(item => {
34
- const closePromise = (async () => {
35
- var _a, _b;
36
- try {
37
- const [eyes] = await Promise.all([item.eyes, ...item.jobs]);
38
- try {
39
- await eyes.close({ settings, logger });
40
- }
41
- catch (error) {
42
- logger.warn('Command "close" received an error during performing, trying to perform abort instead', error);
43
- await eyes.abort({ settings, logger });
44
- }
45
- }
46
- catch (error) {
47
- logger.warn('Command "close" received an error during waiting for eyes instances in background', error);
48
- await ((_b = (_a = error.info) === null || _a === void 0 ? void 0 : _a.eyes) === null || _b === void 0 ? void 0 : _b.abort({ settings, logger }));
49
- }
50
- })();
51
- item.jobs.push(closePromise);
52
- });
33
+ (0, tasks_1.closeSession)(eyes.session, { settings, logger });
53
34
  };
54
35
  }
55
36
  exports.makeClose = makeClose;
@@ -1,21 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeGetResults = void 0;
4
+ const tasks_1 = require("../tasks");
4
5
  function makeGetResults({ eyes, logger: mainLogger }) {
5
6
  return async function getResults({ settings, logger = mainLogger, } = {}) {
6
7
  logger = logger.extend(mainLogger);
7
8
  logger.log('Command "getResults" is called with settings', settings);
8
- return Promise.all(Array.from(eyes.storage.values(), async (item) => {
9
- try {
10
- const [eyes] = await Promise.all([item.eyes, ...item.jobs]);
11
- const [result] = await eyes.getResults({ settings, logger });
12
- return { ...result, environment: eyes.test.environment };
13
- }
14
- catch (error) {
15
- logger.fatal('Command "getResults" received an error', error, 'during performing with settings', settings);
16
- throw error;
17
- }
18
- }));
9
+ const results = await Promise.all((0, tasks_1.activeEnvironmentKeys)(eyes.session).map(key => (0, tasks_1.getResults)(eyes.session, key, { settings, logger })));
10
+ return results;
19
11
  };
20
12
  }
21
13
  exports.makeGetResults = makeGetResults;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.makeEnvironmentLoggers = void 0;
27
+ const to_environment_key_1 = require("./to-environment-key");
28
+ const utils = __importStar(require("@applitools/utils"));
29
+ // One `environment-*` tag per environment, extended onto each caller's logger so per-call tags are kept.
30
+ function makeEnvironmentLoggers() {
31
+ const tags = new Map();
32
+ return function getEnvironmentLogger(environment, logger) {
33
+ const key = (0, to_environment_key_1.toEnvironmentKey)(environment);
34
+ if (!tags.has(key))
35
+ tags.set(key, `environment-${utils.general.shortid()}`);
36
+ return logger.extend({ tags: [tags.get(key)] });
37
+ };
38
+ }
39
+ exports.makeEnvironmentLoggers = makeEnvironmentLoggers;
@@ -26,6 +26,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.toEnvironmentKey = void 0;
27
27
  const utils = __importStar(require("@applitools/utils"));
28
28
  function toEnvironmentKey(environment) {
29
- return JSON.stringify(utils.types.has(environment, 'requested') ? environment.requested : environment);
29
+ return JSON.stringify(utils.types.has(environment, 'requested') ? environment.requested : environment, sortKeys);
30
30
  }
31
31
  exports.toEnvironmentKey = toEnvironmentKey;
32
+ function sortKeys(_key, value) {
33
+ return utils.types.isPlainObject(value)
34
+ ? Object.fromEntries(Object.entries(value).sort(([a], [b]) => (a < b ? -1 : 1)))
35
+ : value;
36
+ }
@@ -35,9 +35,12 @@ const wait_for_lazy_load_1 = require("../automation/utils/wait-for-lazy-load");
35
35
  const uniquify_environments_1 = require("../automation/utils/uniquify-environments");
36
36
  const to_environment_key_1 = require("../automation/utils/to-environment-key");
37
37
  const abort_error_1 = require("../errors/abort-error");
38
+ const tasks_1 = require("../tasks");
39
+ const steps_1 = require("../tasks/classic/steps");
38
40
  const chalk_1 = __importDefault(require("chalk"));
39
41
  const utils = __importStar(require("@applitools/utils"));
40
42
  const lang = __importStar(require("../lang"));
43
+ const ABORTED = 'Command "checkAndClose" was aborted before checking';
41
44
  function makeCheckAndClose({ eyes, target: defaultTarget, environments: defaultEnvironments = [], spec, signal, logger: mainLogger, }) {
42
45
  return async function checkAndClose({ target = defaultTarget, settings = {}, logger = mainLogger, } = {}) {
43
46
  var _a, _b, _c;
@@ -56,6 +59,8 @@ function makeCheckAndClose({ eyes, target: defaultTarget, environments: defaultE
56
59
  let driver;
57
60
  if ((0, driver_1.isDriver)(target, spec)) {
58
61
  driver = await (0, driver_1.makeDriver)({ spec, driver: target, reset: target === defaultTarget, logger });
62
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted)
63
+ return (0, tasks_1.addAbortedCheck)(eyes, uniqueEnvironments, ABORTED, logger);
59
64
  await driver.currentContext.setScrollingElement((_b = settings.scrollRootElement) !== null && _b !== void 0 ? _b : null);
60
65
  const driverEnvironment = await driver.getEnvironment();
61
66
  uniqueEnvironments.forEach(environment => {
@@ -162,76 +167,28 @@ function makeCheckAndClose({ eyes, target: defaultTarget, environments: defaultE
162
167
  baseTargets.push(target);
163
168
  baseSettings.push(settings);
164
169
  }
165
- const promises = exactEnvironments.map(async (environment, index) => {
166
- var _a, _b, _c, _d;
167
- const environmentLogger = logger.extend({ tags: [`environment-${utils.general.shortid()}`] });
168
- try {
169
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
170
- environmentLogger.warn('Command "checkAndClose" was aborted before checking');
171
- throw new abort_error_1.AbortError('Command "checkAndClose" was aborted before checking');
172
- }
173
- const baseEyes = await eyes.getBaseEyes({ settings: { environment, driver }, logger: environmentLogger });
174
- try {
175
- if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
176
- environmentLogger.warn('Command "checkAndClose" was aborted before checking');
177
- throw new abort_error_1.AbortError('Command "checkAndClose" was aborted before checking');
178
- }
179
- else if (!baseEyes.running) {
180
- environmentLogger.warn(`Check on environment with id "${(_a = baseEyes.test.environment) === null || _a === void 0 ? void 0 : _a.environmentId}" was aborted during one of the previous steps`);
181
- throw new abort_error_1.AbortError(`Check on environment with id "${(_b = baseEyes.test.environment) === null || _b === void 0 ? void 0 : _b.environmentId}" was aborted during one of the previous steps`);
182
- }
183
- if (settings.assumesMutability) {
184
- void eyes.core.logEvent({
185
- settings: {
186
- level: 'Notice',
187
- event: {
188
- type: 'eyes.check',
189
- message: 'Assuming mutability for check Target',
190
- test: {
191
- checkName: settings.name,
192
- batchId: baseEyes.test.batchId,
193
- sessionId: baseEyes.test.sessionId,
194
- testName: baseEyes.test.testName,
195
- testId: baseEyes.test.testId,
196
- userTestId: baseEyes.test.userTestId,
197
- appId: baseEyes.test.appId,
198
- baselineId: baseEyes.test.baselineId,
199
- environmentId: (_c = baseEyes.test.environment) === null || _c === void 0 ? void 0 : _c.environmentId,
200
- },
201
- isNew: baseEyes.test.isNew,
202
- resultsUrl: baseEyes.test.resultsUrl,
203
- },
204
- ...eyes.test.eyesServer,
205
- },
206
- logger: environmentLogger,
207
- });
208
- }
209
- await baseEyes.checkAndClose({
210
- target: baseTargets[index],
211
- settings: baseSettings[index],
212
- logger: environmentLogger,
213
- });
214
- }
215
- catch (error) {
216
- environmentLogger.error(`Check on environment with id "${(_d = baseEyes.test.environment) === null || _d === void 0 ? void 0 : _d.environmentId}" failed due to an error`, error);
217
- if (baseEyes.running && !(signal === null || signal === void 0 ? void 0 : signal.aborted))
218
- await baseEyes.abort({ logger: environmentLogger, settings: { reason: error } });
219
- }
220
- }
221
- catch (error) {
222
- environmentLogger.error(`Environment with id ${environment.environmentId} failed before checking started due to an error`, error);
223
- error.info = { ...error.info, userTestId: eyes.test.userTestId, environment: environment };
224
- throw error;
225
- }
226
- });
170
+ const mutability = settings.assumesMutability ? { eyes, checkName: settings.name } : undefined;
227
171
  exactEnvironments.forEach((environment, index) => {
228
- const key = (0, to_environment_key_1.toEnvironmentKey)(environment);
229
- let item = eyes.storage.get(key);
230
- if (!item) {
231
- item = { eyes: utils.promises.makeControlledPromise(), jobs: [] };
232
- eyes.storage.set(key, item);
233
- }
234
- item.jobs.push(promises[index]);
172
+ const environmentLogger = eyes.getEnvironmentLogger(environment, logger);
173
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted)
174
+ return (0, tasks_1.addAbortedCheck)(eyes, [environment], ABORTED, environmentLogger);
175
+ const open = { eyes, environment, driver, logger: environmentLogger };
176
+ (0, steps_1.addCheckAndClose)(eyes.session, (0, to_environment_key_1.toEnvironmentKey)(environment), {
177
+ open,
178
+ upload: { target: baseTargets[index], settings: baseSettings[index], signal, logger: environmentLogger },
179
+ inputs: {
180
+ canFuse: true,
181
+ mutability,
182
+ signal,
183
+ onError: (error, baseEyes) => {
184
+ var _a;
185
+ environmentLogger.error(`Check on environment with id "${(_a = baseEyes.test.environment) === null || _a === void 0 ? void 0 : _a.environmentId}" failed due to an error`, error);
186
+ error.info = { ...error.info, userTestId: eyes.test.userTestId, environment };
187
+ },
188
+ logger: environmentLogger,
189
+ },
190
+ settings: baseSettings[index],
191
+ });
235
192
  });
236
193
  };
237
194
  }