@applitools/core 4.31.4 → 4.32.1

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,29 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.32.1](https://github.com/Applitools-Dev/sdk/compare/js/core@4.32.0...js/core@4.32.1) (2025-03-04)
4
+
5
+
6
+ ### Dependencies
7
+
8
+ * @applitools/ufg-client bumped to 1.16.7
9
+ #### Bug Fixes
10
+
11
+ * handle failure for large body in render request ([a4d2c1a](https://github.com/Applitools-Dev/sdk/commit/a4d2c1a408c8ed31ecd5446415dc8af04eb7b688))
12
+ * trigger release ([#2829](https://github.com/Applitools-Dev/sdk/issues/2829)) ([c9ea327](https://github.com/Applitools-Dev/sdk/commit/c9ea327c806163e23031be7c0b5b40bf02dbebc3))
13
+
14
+ ## [4.32.0](https://github.com/Applitools-Dev/sdk/compare/js/core@4.31.4...js/core@4.32.0) (2025-03-04)
15
+
16
+
17
+ ### Features
18
+
19
+ * limit offline console logs ([#2813](https://github.com/Applitools-Dev/sdk/issues/2813)) ([9bec38b](https://github.com/Applitools-Dev/sdk/commit/9bec38b39cd7a35e574b667e8efa5016d3cf8fb3))
20
+
21
+
22
+ ### Bug Fixes
23
+
24
+ * abort offline corrupt tests ([#2827](https://github.com/Applitools-Dev/sdk/issues/2827)) ([eabca07](https://github.com/Applitools-Dev/sdk/commit/eabca07c7575433fb97f63762412ddbb492dd665))
25
+ * stale elements for webdriver sdks ([#2798](https://github.com/Applitools-Dev/sdk/issues/2798)) ([03e5fac](https://github.com/Applitools-Dev/sdk/commit/03e5fac2d3929ebe615293fd899b7e21443fb062))
26
+
3
27
  ## [4.31.4](https://github.com/Applitools-Dev/sdk/compare/js/core@4.31.3...js/core@4.31.4) (2025-02-26)
4
28
 
5
29
 
@@ -37,8 +37,13 @@ const chalk_1 = __importDefault(require("chalk"));
37
37
  const utils = __importStar(require("@applitools/utils"));
38
38
  const merge_configs_1 = require("./merge-configs");
39
39
  const format_results_1 = require("../utils/format-results");
40
+ function getConsoleLogLimit() {
41
+ var _a;
42
+ return (_a = utils.general.getEnvValue('OFFLINE_LOG_LIMIT', 'number')) !== null && _a !== void 0 ? _a : 20;
43
+ }
40
44
  async function runOfflineSnapshots(options) {
41
45
  var _a;
46
+ const limitConsoleLogs = getConsoleLogLimit();
42
47
  if (!options.offlineLocationPath)
43
48
  throw new Error('offlineLocationPath is required');
44
49
  const offlineLocationPath = path_1.default.resolve(options.offlineLocationPath);
@@ -80,14 +85,26 @@ async function runOfflineSnapshots(options) {
80
85
  return allTestResults;
81
86
  async function runTests(testFolders) {
82
87
  logger.log('running tests', testFolders);
83
- const results = await Promise.all(testFolders.map(async (testFolder) => {
88
+ const messages = [];
89
+ const testPromises = testFolders.map(async (testFolder) => {
84
90
  const testLogger = logger.extend({ tags: [testFolder] });
85
91
  const testPath = path_1.default.join(offlineLocationPath, testFolder);
86
92
  const fileOpenSettings = await fs_1.default.promises
87
93
  .readFile(path_1.default.join(testPath, 'settings.json'), 'utf-8')
88
94
  .then(JSON.parse);
89
95
  const openSettings = (0, merge_configs_1.mergeConfigs)(fileOpenSettings, options.config.open);
90
- logger.console.log(`Running test: ${openSettings.testName} (${formatEnvironment(openSettings.environment)})`);
96
+ messages.push(`Running test: ${openSettings.testName} (${formatEnvironment(openSettings.environment)})`);
97
+ return { testPath, openSettings, testLogger };
98
+ });
99
+ const preparedTests = await Promise.all(testPromises);
100
+ if (messages.length > limitConsoleLogs) {
101
+ const slice = messages.slice(0, limitConsoleLogs);
102
+ logger.console.log(slice.join('\n') + `\n... ${messages.length - limitConsoleLogs} more tests`);
103
+ }
104
+ else {
105
+ logger.console.log(messages.join('\n'));
106
+ }
107
+ const results = await Promise.all(preparedTests.map(async ({ testPath, openSettings, testLogger }) => {
91
108
  return runTest(testPath, openSettings, testLogger);
92
109
  }));
93
110
  const batchIds = [...new Set(results.map(t => t.batchId))];
@@ -115,23 +132,29 @@ async function runOfflineSnapshots(options) {
115
132
  },
116
133
  logger,
117
134
  });
118
- const checkFolders = (await fs_1.default.promises.readdir(testPath)).filter(folderpath => folderpath.startsWith('check-'));
119
- logger.log('running checks for test', testPath, ':', checkFolders);
120
- const targets = await Promise.all(checkFolders.map(async (checkFolder) => {
121
- const snapshot = await fs_1.default.promises
122
- .readFile(path_1.default.resolve(testPath, checkFolder, 'snapshot.json'), 'utf-8')
123
- .then(JSON.parse);
124
- snapshot.settings.environment.environmentId = utils.general.guid();
125
- return snapshot;
126
- }));
127
- await uploadResources(targets, logger);
128
- // logger.log('resource hashes for test', testFolder, ':', resourceHashes)
129
- logger.log('uploaded resources for test', testPath);
130
- await Promise.all(targets.map((target, index) => runCheck(eyes, target, index, logger)));
131
- const fileCloseSettings = await fs_1.default.promises.readFile(path_1.default.resolve(testPath, 'close.json'), 'utf-8').then(JSON.parse);
132
- const closeSettings = (0, merge_configs_1.mergeConfigs)(fileCloseSettings, options.config.close);
133
- await eyes.close({ settings: closeSettings });
134
- logger.log('done running test', logger);
135
+ const closeSettingsPath = path_1.default.resolve(testPath, 'close.json');
136
+ if (fs_1.default.existsSync(closeSettingsPath)) {
137
+ const checkFolders = (await fs_1.default.promises.readdir(testPath)).filter(folderpath => folderpath.startsWith('check-'));
138
+ logger.log('running checks for test', testPath, ':', checkFolders);
139
+ const targets = await Promise.all(checkFolders.map(async (checkFolder) => {
140
+ const snapshot = await fs_1.default.promises
141
+ .readFile(path_1.default.resolve(testPath, checkFolder, 'snapshot.json'), 'utf-8')
142
+ .then(JSON.parse);
143
+ snapshot.settings.environment.environmentId = utils.general.guid();
144
+ return snapshot;
145
+ }));
146
+ await uploadResources(targets, logger);
147
+ // logger.log('resource hashes for test', testFolder, ':', resourceHashes)
148
+ logger.log('uploaded resources for test', testPath);
149
+ await Promise.all(targets.map((target, index) => runCheck(eyes, target, index, logger)));
150
+ const fileCloseSettings = await fs_1.default.promises.readFile(closeSettingsPath, 'utf-8').then(JSON.parse);
151
+ const closeSettings = (0, merge_configs_1.mergeConfigs)(fileCloseSettings, options.config.close);
152
+ await eyes.close({ settings: closeSettings });
153
+ }
154
+ else {
155
+ await eyes.abort();
156
+ }
157
+ logger.log('done running test', testPath);
135
158
  return { batchId: openSettings.batch.id, results: (await eyes.getResults({ logger }))[0] };
136
159
  }
137
160
  async function uploadResources(targets, logger) {
@@ -235,16 +258,16 @@ function processResults({ testResults, totalTime, saveNewTests = true, failOnDif
235
258
  }
236
259
  outputStr += '[EYES: TEST RESULTS]:\n\n';
237
260
  if (passedOrNew.length > 0) {
238
- outputStr += testResultsOutput(passedOrNew, warnForUnsavedNewTests);
261
+ outputStr += testResultsOutput(passedOrNew, warnForUnsavedNewTests, 'Passed');
239
262
  }
240
263
  if (failedTests.length > 0) {
241
- outputStr += testResultsOutput(failedTests, warnForUnsavedNewTests);
264
+ outputStr += testResultsOutput(failedTests, warnForUnsavedNewTests, 'Failed');
242
265
  }
243
266
  if (unresolved.length > 0) {
244
- outputStr += testResultsOutput(unresolved, warnForUnsavedNewTests);
267
+ outputStr += testResultsOutput(unresolved, warnForUnsavedNewTests, 'Unresolved');
245
268
  }
246
269
  if (aborted.length > 0) {
247
- outputStr += testResultsOutput(aborted, warnForUnsavedNewTests);
270
+ outputStr += testResultsOutput(aborted, warnForUnsavedNewTests, 'Aborted');
248
271
  }
249
272
  if (errors.length) {
250
273
  const sortedErrors = errors.sort((a, b) => a.title.localeCompare(b.title));
@@ -308,28 +331,39 @@ function processResults({ testResults, totalTime, saveNewTests = true, failOnDif
308
331
  isSuccess,
309
332
  };
310
333
  }
311
- function testResultsOutput(results, warnForUnsavedNewTests) {
312
- let outputStr = '';
334
+ function testResultsOutput(results, warnForUnsavedNewTests, tag) {
335
+ const limitConsoleLogs = getConsoleLogLimit();
336
+ const truncated = [];
337
+ let limitCount = 0;
313
338
  const sortedTestResults = results.sort((a, b) => a.name.localeCompare(b.name));
314
339
  sortedTestResults.forEach(result => {
315
340
  const testTitle = `${result.name} [${result.hostApp}] [${result.hostDisplaySize.width}x${result.hostDisplaySize.height}] - `;
316
341
  if (result.isAborted) {
317
- outputStr += `${testTitle}${chalk_1.default.keyword('red')(`Aborted`)}\n`;
342
+ const str = `${testTitle}${chalk_1.default.keyword('red')(`Aborted`)}\n`;
343
+ truncated.push(str);
318
344
  }
319
345
  else if (result.isNew) {
320
346
  const newResColor = warnForUnsavedNewTests ? 'orange' : 'blue';
321
- outputStr += `${testTitle}${chalk_1.default.keyword(newResColor)('New')}\n`;
347
+ const str = `${testTitle}${chalk_1.default.keyword(newResColor)('New')}\n`;
348
+ truncated.push(str);
322
349
  }
323
350
  else if (result.status === 'Passed') {
324
- outputStr += `${testTitle}${chalk_1.default.green('Passed')}\n`;
351
+ const str = `${testTitle}${chalk_1.default.green('Passed')}\n`;
352
+ truncated.push(str);
325
353
  }
326
354
  else if (result.status === 'Failed') {
327
- outputStr += `${testTitle}${chalk_1.default.keyword('red')('Failed')}\n`;
355
+ const str = `${testTitle}${chalk_1.default.keyword('red')('Failed')}\n`;
356
+ truncated.push(str);
328
357
  }
329
358
  else {
330
- outputStr += `${testTitle}${chalk_1.default.keyword('orange')(`Unresolved`)}\n`;
359
+ const str = `${testTitle}${chalk_1.default.keyword('orange')(`Unresolved`)}\n`;
360
+ truncated.push(str);
331
361
  }
362
+ if (limitCount < limitConsoleLogs)
363
+ limitCount++;
332
364
  });
365
+ let outputStr = truncated.slice(0, limitConsoleLogs).join('');
366
+ outputStr += results.length - limitCount > 0 ? `... ${results.length - limitCount} more ${tag} tests` : '';
333
367
  outputStr += '\n';
334
368
  return outputStr;
335
369
  }
package/dist/open-eyes.js CHANGED
@@ -39,20 +39,20 @@ const core_base_1 = require("@applitools/core-base");
39
39
  const extract_git_info_1 = require("./utils/extract-git-info");
40
40
  function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDuplicateTests, core, cores, spec, environment, logger: mainLogger, asyncCache, cwd = process.cwd(), }) {
41
41
  return async function openEyes({ type = defaultType, settings: openSettings, config, target, logger = mainLogger, }) {
42
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
43
- var _w, _x, _y, _z, _0;
42
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
43
+ var _z, _0, _1, _2, _3;
44
44
  logger = logger.extend(mainLogger, { tags: [`eyes-${type}-${utils.general.shortid()}`] });
45
- const settings = { ...config === null || config === void 0 ? void 0 : config.open, ...openSettings };
45
+ const settings = { environments: config === null || config === void 0 ? void 0 : config.check.environments, ...config === null || config === void 0 ? void 0 : config.open, ...openSettings };
46
46
  const eyesServerSettings = (0, populate_eyes_server_settings_1.populateEyesServerSettings)(settings);
47
47
  logger.mask(eyesServerSettings.apiKey);
48
48
  logger.mask(eyesServerSettings.eyesServerUrl);
49
49
  (_a = settings.userTestId) !== null && _a !== void 0 ? _a : (settings.userTestId = `${settings.testName}--${utils.general.guid()}`);
50
50
  settings.batch = { ...batch, ...settings.batch };
51
- (_b = (_w = settings.batch).id) !== null && _b !== void 0 ? _b : (_w.id = (_c = utils.general.getEnvValue('BATCH_ID')) !== null && _c !== void 0 ? _c : `generated-${utils.general.guid()}`);
52
- (_d = (_x = settings.batch).buildId) !== null && _d !== void 0 ? _d : (_x.buildId = utils.general.getEnvValue('BATCH_BUILD_ID'));
53
- (_e = (_y = settings.batch).name) !== null && _e !== void 0 ? _e : (_y.name = utils.general.getEnvValue('BATCH_NAME'));
54
- (_f = (_z = settings.batch).sequenceName) !== null && _f !== void 0 ? _f : (_z.sequenceName = utils.general.getEnvValue('BATCH_SEQUENCE'));
55
- (_g = (_0 = settings.batch).notifyOnCompletion) !== null && _g !== void 0 ? _g : (_0.notifyOnCompletion = utils.general.getEnvValue('BATCH_NOTIFY', 'boolean'));
51
+ (_b = (_z = settings.batch).id) !== null && _b !== void 0 ? _b : (_z.id = (_c = utils.general.getEnvValue('BATCH_ID')) !== null && _c !== void 0 ? _c : `generated-${utils.general.guid()}`);
52
+ (_d = (_0 = settings.batch).buildId) !== null && _d !== void 0 ? _d : (_0.buildId = utils.general.getEnvValue('BATCH_BUILD_ID'));
53
+ (_e = (_1 = settings.batch).name) !== null && _e !== void 0 ? _e : (_1.name = utils.general.getEnvValue('BATCH_NAME'));
54
+ (_f = (_2 = settings.batch).sequenceName) !== null && _f !== void 0 ? _f : (_2.sequenceName = utils.general.getEnvValue('BATCH_SEQUENCE'));
55
+ (_g = (_3 = settings.batch).notifyOnCompletion) !== null && _g !== void 0 ? _g : (_3.notifyOnCompletion = utils.general.getEnvValue('BATCH_NOTIFY', 'boolean'));
56
56
  (_h = settings.keepBatchOpen) !== null && _h !== void 0 ? _h : (settings.keepBatchOpen = utils.general.getEnvValue('DONT_CLOSE_BATCHES', 'boolean'));
57
57
  (_j = settings.branchName) !== null && _j !== void 0 ? _j : (settings.branchName = utils.general.getEnvValue('BRANCH'));
58
58
  (_k = settings.parentBranchName) !== null && _k !== void 0 ? _k : (settings.parentBranchName = utils.general.getEnvValue('PARENT_BRANCH'));
@@ -92,6 +92,15 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
92
92
  const driver = target && (await (0, driver_1.makeDriver)({ spec, driver: target, logger, customConfig: settings }));
93
93
  const driverEnvironment = await (driver === null || driver === void 0 ? void 0 : driver.getEnvironment());
94
94
  const driverUrl = await (driver === null || driver === void 0 ? void 0 : driver.getDriverUrl());
95
+ const multiDeviceTargets = [];
96
+ for (const checkEnv of (_u = settings.environments) !== null && _u !== void 0 ? _u : []) {
97
+ if (utils.types.has(checkEnv, 'iosDeviceInfo') && ((_v = driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.applitoolsLib) === null || _v === void 0 ? void 0 : _v.instrumented)) {
98
+ multiDeviceTargets.push({
99
+ deviceInfo: checkEnv.iosDeviceInfo.deviceName,
100
+ orientation: (_w = checkEnv.iosDeviceInfo.screenOrientation) !== null && _w !== void 0 ? _w : 'portrait',
101
+ });
102
+ }
103
+ }
95
104
  void core.logEvent({
96
105
  settings: {
97
106
  ...settings,
@@ -99,7 +108,7 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
99
108
  event: {
100
109
  type: 'openEyes',
101
110
  userTestId: settings.userTestId,
102
- concurrency: (_u = cores === null || cores === void 0 ? void 0 : cores[type].concurrency) !== null && _u !== void 0 ? _u : core.concurrency,
111
+ concurrency: (_x = cores === null || cores === void 0 ? void 0 : cores[type].concurrency) !== null && _x !== void 0 ? _x : core.concurrency,
103
112
  environment,
104
113
  driver: {
105
114
  deviceName: driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.deviceName,
@@ -107,10 +116,11 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
107
116
  browserVersion: driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.browserVersion,
108
117
  platformName: driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.platformName,
109
118
  platformVersion: driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.platformVersion,
110
- isApplitoolsLib: (_v = driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.applitoolsLib) === null || _v === void 0 ? void 0 : _v.instrumented,
119
+ isApplitoolsLib: (_y = driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.applitoolsLib) === null || _y === void 0 ? void 0 : _y.instrumented,
111
120
  isEC: driverEnvironment === null || driverEnvironment === void 0 ? void 0 : driverEnvironment.isEC,
112
121
  },
113
122
  driverUrl,
123
+ multiDeviceTargets,
114
124
  },
115
125
  },
116
126
  logger,
@@ -32,11 +32,12 @@ const close_1 = require("../automation/close");
32
32
  const abort_1 = require("../automation/abort");
33
33
  const get_results_1 = require("../automation/get-results");
34
34
  const extract_default_environment_1 = require("./utils/extract-default-environment");
35
+ const verify_environment_info_1 = require("./utils/verify-environment-info");
35
36
  const abort_controller_1 = require("abort-controller");
36
37
  const utils = __importStar(require("@applitools/utils"));
37
38
  function makeOpenEyes({ core, spec, logger: mainLogger }) {
38
39
  return async function openEyes({ target, settings, storage = new Map(), logger = mainLogger, }) {
39
- var _a, _b, _c;
40
+ var _a, _b, _c, _d;
40
41
  logger = logger.extend(mainLogger);
41
42
  logger.log(`Command "openEyes" is called with ${target ? 'default driver' : ''}`, ...(settings ? ['and settings', settings] : []), storage.size > 0 ? 'and default eyes storage' : '');
42
43
  const driver = target && (await (0, driver_1.makeDriver)({ spec, driver: target, logger }));
@@ -54,6 +55,15 @@ function makeOpenEyes({ core, spec, logger: mainLogger }) {
54
55
  const controller = new abort_controller_1.AbortController();
55
56
  const { signal } = controller;
56
57
  const account = await core.getAccountInfo({ settings, logger });
58
+ const ufgClient = await core.getUFGClient({
59
+ settings: {
60
+ ...account.ufgServer,
61
+ eyesServerUrl: account.eyesServer.eyesServerUrl,
62
+ apiKey: account.eyesServer.apiKey,
63
+ },
64
+ logger,
65
+ });
66
+ await (0, verify_environment_info_1.verifyEnvironmentsInfo)({ environments: (_d = settings.environments) !== null && _d !== void 0 ? _d : [], ufgClient });
57
67
  return utils.general.extend({}, eyes => {
58
68
  var _a, _b, _c, _d;
59
69
  return {
@@ -6,9 +6,10 @@ const take_dom_snapshots_1 = require("./utils/take-dom-snapshots");
6
6
  const to_safe_check_settings_1 = require("./utils/to-safe-check-settings");
7
7
  const to_generated_selectors_1 = require("./utils/to-generated-selectors");
8
8
  const abort_error_1 = require("../errors/abort-error");
9
+ const filterStaleElements_1 = require("./utils/filterStaleElements");
9
10
  function makeTakeSnapshots({ core, spec, signal, logger: mainLogger }) {
10
11
  return async function takeSnapshots({ driver, settings = {}, account, logger = mainLogger, }) {
11
- var _a;
12
+ var _a, _b;
12
13
  logger = logger.extend(mainLogger);
13
14
  logger.log('Command "takeSnapshots" is called with settings', settings);
14
15
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
@@ -38,7 +39,7 @@ function makeTakeSnapshots({ core, spec, signal, logger: mainLogger }) {
38
39
  },
39
40
  logger,
40
41
  });
41
- snapshots = await (0, take_dom_snapshots_1.takeDomSnapshots)({
42
+ const takeSnapshotsSettings = {
42
43
  driver,
43
44
  settings: {
44
45
  waitBeforeCapture: settings.waitBeforeCapture,
@@ -54,7 +55,25 @@ function makeTakeSnapshots({ core, spec, signal, logger: mainLogger }) {
54
55
  getIOSDevices: ufgClient.getIOSDevices,
55
56
  },
56
57
  logger,
57
- });
58
+ };
59
+ try {
60
+ snapshots = await (0, take_dom_snapshots_1.takeDomSnapshots)(takeSnapshotsSettings);
61
+ }
62
+ catch (err) {
63
+ if ((_b = err === null || err === void 0 ? void 0 : err.message) === null || _b === void 0 ? void 0 : _b.includes('stale element')) {
64
+ snapshots = await (0, take_dom_snapshots_1.takeDomSnapshots)({
65
+ ...takeSnapshotsSettings,
66
+ settings: await (0, filterStaleElements_1.removeStaleElementsFromDomSnapshotsSettings)({
67
+ settings: takeSnapshotsSettings.settings,
68
+ context: currentContext,
69
+ targetElement: elementReferences.target,
70
+ }),
71
+ });
72
+ }
73
+ else {
74
+ throw err;
75
+ }
76
+ }
58
77
  }
59
78
  else {
60
79
  // dead code - used for NMG
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.removeStaleElementsFromDomSnapshotsSettings = exports.filterStaleElements = exports.isStale = void 0;
4
+ async function isStale({ context, element, }) {
5
+ try {
6
+ await context.execute('return arguments[0]', element);
7
+ }
8
+ catch {
9
+ return true;
10
+ }
11
+ return false;
12
+ }
13
+ exports.isStale = isStale;
14
+ async function filterStaleElements({ context, elementReferences, }) {
15
+ if (!elementReferences)
16
+ return [];
17
+ const validElements = [];
18
+ for (const element of elementReferences) {
19
+ if (!(await isStale({ context, element }))) {
20
+ validElements.push(element);
21
+ }
22
+ }
23
+ return validElements;
24
+ }
25
+ exports.filterStaleElements = filterStaleElements;
26
+ async function removeStaleElementsFromDomSnapshotsSettings({ context, settings, targetElement, }) {
27
+ // if one of the stale elements is the target element, we can't recover from it
28
+ if (await isStale({ context, element: targetElement })) {
29
+ throw new Error('Target element is stale - please make sure the element is not detached from the DOM tree. Failed to recover from stale element');
30
+ }
31
+ else {
32
+ // remove other stale elements from the array
33
+ settings.elementReferences = await filterStaleElements({
34
+ context,
35
+ elementReferences: settings.elementReferences,
36
+ });
37
+ }
38
+ return settings;
39
+ }
40
+ exports.removeStaleElementsFromDomSnapshotsSettings = removeStaleElementsFromDomSnapshotsSettings;
@@ -0,0 +1,89 @@
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.verifyEnvironmentsInfo = void 0;
27
+ const utils = __importStar(require("@applitools/utils"));
28
+ const ufg_client_1 = require("@applitools/ufg-client");
29
+ async function verifyEnvironmentsInfo({ environments, ufgClient, }) {
30
+ const invalid = [];
31
+ await Promise.all(environments.map(async (environment) => {
32
+ if (utils.types.has(environment, ['width', 'height'])) {
33
+ const browserName = environment.name || '';
34
+ if (!getAllBrowserNames().includes(browserName)) {
35
+ invalid.push(browserName);
36
+ }
37
+ }
38
+ else if (utils.types.has(environment, 'chromeEmulationInfo')) {
39
+ const devices = await ufgClient.getChromeEmulationDevices();
40
+ const deviceName = environment.chromeEmulationInfo.deviceName;
41
+ if (!devices[deviceName]) {
42
+ invalid.push(deviceName);
43
+ }
44
+ }
45
+ else if (utils.types.has(environment, 'iosDeviceInfo')) {
46
+ const devices = await ufgClient.getIOSDevices();
47
+ const deviceName = environment.iosDeviceInfo.deviceName;
48
+ if (!devices[deviceName]) {
49
+ invalid.push(deviceName);
50
+ }
51
+ }
52
+ }));
53
+ if (invalid.length > 0) {
54
+ throw new Error(`The specified UFG environment(s): ${invalid
55
+ .map(item => `"${item}"`)
56
+ .join(', ')} are either invalid or no longer supported. \nRefer to our current list of supported devices and browsers at: https://applitools.com/tutorials/concepts/test-execution/ultrafast-grid-devices-browsers \nIf you continue to experience issues, ensure that your SDK is updated to the latest version.`);
57
+ }
58
+ }
59
+ exports.verifyEnvironmentsInfo = verifyEnvironmentsInfo;
60
+ function getAllBrowserNames() {
61
+ /*
62
+ Some of the browser names are not part of the enum because they are not user facing. We support them for backward compatibility.
63
+ do not add them to the enum.
64
+ */
65
+ return [
66
+ ...Object.values(ufg_client_1.BrowserNameEnum),
67
+ 'chrome-1',
68
+ 'firefox-1',
69
+ 'edgechromium-1',
70
+ 'safari-1',
71
+ 'chrome-2',
72
+ 'firefox-2',
73
+ 'edgechromium-2',
74
+ 'safari-2',
75
+ 'chrome-canary',
76
+ 'firefox-canary',
77
+ 'edgechromium-canary',
78
+ 'safari-canary',
79
+ 'chrome-one-versions-back',
80
+ 'firefox-one-versions-back',
81
+ 'edgechromium-one-versions-back',
82
+ 'safari-one-versions-back',
83
+ 'chrome-two-version-back',
84
+ 'firefox-two-version-back',
85
+ 'edgechromium-two-version-back',
86
+ 'safari-two-version-back',
87
+ 'ie11',
88
+ ];
89
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/core",
3
- "version": "4.31.4",
3
+ "version": "4.32.1",
4
4
  "homepage": "https://applitools.com",
5
5
  "bugs": {
6
6
  "url": "https://github.com/applitools/eyes.sdk.javascript1/issues"
@@ -87,7 +87,7 @@
87
87
  "@applitools/snippets": "2.6.4",
88
88
  "@applitools/socket": "1.2.2",
89
89
  "@applitools/spec-driver-webdriver": "1.1.26",
90
- "@applitools/ufg-client": "1.16.6",
90
+ "@applitools/ufg-client": "1.16.7",
91
91
  "@applitools/utils": "1.7.8",
92
92
  "@types/ws": "8.5.5",
93
93
  "abort-controller": "3.0.0",
@@ -171,4 +171,5 @@ export type TestResult = BaseCore.TestResult & {
171
171
  };
172
172
  export type OpenSettings = BaseCore.OpenSettings & {
173
173
  disableBrokerUrlCache?: boolean;
174
+ environments?: Environment[];
174
175
  };
@@ -0,0 +1,22 @@
1
+ import type { Context, ElementReference, SpecType } from '@applitools/driver';
2
+ import { DomSnapshotsSettings } from './take-dom-snapshots';
3
+ export declare function isStale<TSpec extends SpecType>({ context, element, }: {
4
+ context: Context<TSpec>;
5
+ element: ElementReference<TSpec>;
6
+ }): Promise<boolean>;
7
+ export declare function filterStaleElements<TSpec extends SpecType>({ context, elementReferences, }: {
8
+ context: Context<TSpec>;
9
+ elementReferences: ElementReference<TSpec>[] | undefined;
10
+ }): Promise<(string | TSpec["element"] | TSpec["secondary"]["element"] | TSpec["selector"] | TSpec["secondary"]["selector"] | {
11
+ selector: string | TSpec["selector"] | TSpec["secondary"]["selector"];
12
+ type?: string | undefined;
13
+ child?: TSpec["selector"] | TSpec["secondary"]["selector"] | import("@applitools/driver").CommonSelector<TSpec["selector"] | TSpec["secondary"]["selector"]> | undefined;
14
+ shadow?: TSpec["selector"] | TSpec["secondary"]["selector"] | import("@applitools/driver").CommonSelector<TSpec["selector"] | TSpec["secondary"]["selector"]> | undefined;
15
+ frame?: TSpec["selector"] | TSpec["secondary"]["selector"] | import("@applitools/driver").CommonSelector<TSpec["selector"] | TSpec["secondary"]["selector"]> | undefined;
16
+ fallback?: TSpec["selector"] | TSpec["secondary"]["selector"] | import("@applitools/driver").CommonSelector<TSpec["selector"] | TSpec["secondary"]["selector"]> | undefined;
17
+ })[]>;
18
+ export declare function removeStaleElementsFromDomSnapshotsSettings<TSpec extends SpecType>({ context, settings, targetElement, }: {
19
+ context: Context<TSpec>;
20
+ settings: DomSnapshotsSettings<TSpec>;
21
+ targetElement: ElementReference<TSpec>;
22
+ }): Promise<DomSnapshotsSettings<TSpec>>;
@@ -0,0 +1,6 @@
1
+ import { Environment } from '../../automation/types';
2
+ import { UFGClient } from '@applitools/ufg-client';
3
+ export declare function verifyEnvironmentsInfo({ environments, ufgClient, }: {
4
+ environments: Environment[];
5
+ ufgClient: UFGClient;
6
+ }): Promise<void>;