@applitools/core 4.24.2 → 4.26.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.26.0](https://github.com/Applitools-Dev/sdk/compare/js/core@4.25.0...js/core@4.26.0) (2024-12-05)
4
+
5
+
6
+ ### Features
7
+
8
+ * deterministic output for offline mode ([#2666](https://github.com/Applitools-Dev/sdk/issues/2666)) ([0e158c4](https://github.com/Applitools-Dev/sdk/commit/0e158c4ea62c4681513a952a9e2a681c4618a6bd))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * coded regions dynamic regions with `By` locators ([#2660](https://github.com/Applitools-Dev/sdk/issues/2660)) ([e71b3ae](https://github.com/Applitools-Dev/sdk/commit/e71b3aec7241e61c9ba0d637e6242cedd8f4be7b))
14
+
15
+
16
+ ### Dependencies
17
+
18
+ * @applitools/ufg-client bumped to 1.15.0
19
+ #### Features
20
+
21
+ * deterministic output for offline mode ([#2666](https://github.com/Applitools-Dev/sdk/issues/2666)) ([0e158c4](https://github.com/Applitools-Dev/sdk/commit/0e158c4ea62c4681513a952a9e2a681c4618a6bd))
22
+ * @applitools/core-base bumped to 1.20.0
23
+ #### Features
24
+
25
+ * deterministic output for offline mode ([#2666](https://github.com/Applitools-Dev/sdk/issues/2666)) ([0e158c4](https://github.com/Applitools-Dev/sdk/commit/0e158c4ea62c4681513a952a9e2a681c4618a6bd))
26
+ * @applitools/ec-client bumped to 1.9.16
27
+
28
+
29
+ ## [4.25.0](https://github.com/Applitools-Dev/sdk/compare/js/core@4.24.2...js/core@4.25.0) (2024-11-29)
30
+
31
+
32
+ ### Features
33
+
34
+ * offline cli with config ([#2646](https://github.com/Applitools-Dev/sdk/issues/2646)) ([0589dc4](https://github.com/Applitools-Dev/sdk/commit/0589dc429a0c94451e957932106f258dadfd88cc))
35
+
3
36
  ## [4.24.2](https://github.com/Applitools-Dev/sdk/compare/js/core@4.24.1...js/core@4.24.2) (2024-11-27)
4
37
 
5
38
 
package/dist/cli/cli.js CHANGED
@@ -32,7 +32,6 @@ const core_server_1 = require("../universal/core-server");
32
32
  const core_server_process_1 = require("../universal/core-server-process");
33
33
  const logs_1 = require("../troubleshoot/logs");
34
34
  const check_network_1 = require("../troubleshoot/check-network");
35
- const run_offline_snapshots_1 = require("../run-offline-snapshots");
36
35
  const yargs_1 = __importDefault(require("yargs"));
37
36
  const utils = __importStar(require("@applitools/utils"));
38
37
  const fs_1 = __importDefault(require("fs"));
@@ -152,29 +151,5 @@ void yargs_1.default
152
151
  handler: async () => {
153
152
  await (0, check_network_1.checkNetwork)();
154
153
  },
155
- })
156
- .command({
157
- command: 'run-offline-snapshots',
158
- builder: yargs => yargs
159
- .options({
160
- offlineLocationPath: {
161
- description: 'path to offline snapshots folder',
162
- type: 'string',
163
- },
164
- failOnDiff: {
165
- description: 'should exit process with non-zero exit code, thereby failing the CI job',
166
- type: 'boolean',
167
- default: false,
168
- },
169
- })
170
- .fail((_msg, err, _yargs) => {
171
- if (err) {
172
- console.error(err.message);
173
- process.exit(1);
174
- }
175
- }),
176
- handler: async (args) => {
177
- await (0, run_offline_snapshots_1.runOfflineSnapshots)(args);
178
- },
179
154
  })
180
155
  .wrap(yargs_1.default.terminalWidth()).argv;
package/dist/index.js CHANGED
@@ -35,3 +35,4 @@ __exportStar(require("./autonomous/core"), exports);
35
35
  __exportStar(require("@applitools/driver/dist/debug"), exports);
36
36
  exports.formatters = __importStar(require("./utils/format-results"));
37
37
  exports.logs = __importStar(require("./troubleshoot/logs"));
38
+ __exportStar(require("./offline/run-offline-snapshots"), exports);
@@ -0,0 +1,42 @@
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.mergeConfigs = void 0;
27
+ const utils = __importStar(require("@applitools/utils"));
28
+ function mergeConfigs(base, other) {
29
+ return Object.entries(other).reduce((base, [key, value]) => {
30
+ if (utils.types.has(base, key) &&
31
+ utils.types.isObject(value) &&
32
+ !(value instanceof String) &&
33
+ !utils.types.isArray(value)) {
34
+ base[key] = mergeConfigs(base[key], value);
35
+ }
36
+ else if (value !== undefined) {
37
+ base[key] = value;
38
+ }
39
+ return base;
40
+ }, { ...base });
41
+ }
42
+ exports.mergeConfigs = mergeConfigs;
@@ -29,36 +29,42 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.runOfflineSnapshots = void 0;
30
30
  const fs_1 = __importDefault(require("fs"));
31
31
  const path_1 = __importDefault(require("path"));
32
- const core_1 = require("./core");
33
- const get_ufg_client_1 = require("./ufg/get-ufg-client");
32
+ const core_1 = require("../core");
33
+ const get_ufg_client_1 = require("../ufg/get-ufg-client");
34
34
  const logger_1 = require("@applitools/logger");
35
- const to_base_check_settings_1 = require("./automation/utils/to-base-check-settings");
35
+ const to_base_check_settings_1 = require("../automation/utils/to-base-check-settings");
36
36
  const chalk_1 = __importDefault(require("chalk"));
37
37
  const utils = __importStar(require("@applitools/utils"));
38
+ const merge_configs_1 = require("./merge-configs");
38
39
  async function runOfflineSnapshots(options) {
40
+ var _a, _b;
39
41
  if (!options.offlineLocationPath)
40
42
  throw new Error('offlineLocationPath is required');
43
+ const offlineLocationPath = path_1.default.resolve(options.offlineLocationPath);
41
44
  const startTime = Date.now();
42
- const logger = (0, logger_1.makeLogger)({ format: { label: 'offline-exec' } });
45
+ const logger = (_a = options.logger) !== null && _a !== void 0 ? _a : (0, logger_1.makeLogger)({ format: { label: 'offline-exec' } });
46
+ const eyesServerSettings = { ...(_b = options.config) === null || _b === void 0 ? void 0 : _b.open, ...options };
43
47
  const core = (0, core_1.makeCore)();
44
- const account = await core.getAccountInfo({ settings: options });
48
+ const account = await core.getAccountInfo({ settings: eyesServerSettings });
45
49
  const ufgClient = await (0, get_ufg_client_1.makeGetUFGClient)({ logger })({
46
50
  settings: { ...account.eyesServer, ...account.ufgServer },
47
51
  });
48
- const executionFolders = (await fs_1.default.promises.readdir(options.offlineLocationPath)).filter(filename => /execution\-\d+/.test(filename));
49
- if (executionFolders.length === 1) {
50
- logger.console.log(`Running execution ${executionFolders[0]} from folder ${path_1.default.resolve(options.offlineLocationPath)}`);
52
+ const testFolders = (await fs_1.default.promises.readdir(offlineLocationPath))
53
+ .filter(filename => filename.startsWith('test-'))
54
+ .sort();
55
+ if (testFolders.length === 1) {
56
+ logger.console.log(`Running single test from folder ${offlineLocationPath}`);
51
57
  }
52
- else if (executionFolders.length === 0) {
53
- logger.console.log('No execution artifacts were found at', options.offlineLocationPath);
58
+ else if (testFolders.length === 0) {
59
+ logger.console.log('No test artifacts were found at', offlineLocationPath);
54
60
  }
55
61
  else {
56
- logger.console.log(`Running the following executions from folder ${options.offlineLocationPath} :\n ${executionFolders.join('\n ')}`);
62
+ logger.console.log(`Running ${testFolders.length} tests from folder ${offlineLocationPath}`);
57
63
  }
58
- if (executionFolders.length === 0) {
59
- throw new Error(`Unable to find offline executions in ${options.offlineLocationPath}`);
64
+ if (testFolders.length === 0) {
65
+ throw new Error(`Unable to find offline executions in ${offlineLocationPath}`);
60
66
  }
61
- const allTestResults = (await Promise.all(executionFolders.map(runExecution))).flat();
67
+ const allTestResults = await runTests(testFolders);
62
68
  const { isSuccess, outputStr } = processResults({ testResults: allTestResults, totalTime: Date.now() - startTime });
63
69
  if (!isSuccess && options.failOnDiff) {
64
70
  throw new Error(outputStr);
@@ -66,29 +72,27 @@ async function runOfflineSnapshots(options) {
66
72
  else {
67
73
  logger.console.log(outputStr);
68
74
  }
69
- async function runExecution(executionName) {
70
- const executionLogger = logger.extend({ tags: [executionName] });
71
- const executionPath = path_1.default.resolve(options.offlineLocationPath, executionName);
72
- executionLogger.log('handling execution', executionPath);
73
- const testFolders = (await fs_1.default.promises.readdir(executionPath)).filter(foldername => foldername.startsWith('test-'));
74
- executionLogger.log('running tests', testFolders);
75
+ return allTestResults;
76
+ async function runTests(testFolders) {
77
+ logger.log('running tests', testFolders);
75
78
  const results = await Promise.all(testFolders.map(async (testFolder) => {
76
79
  const testLogger = logger.extend({ tags: [testFolder] });
77
- const testPath = path_1.default.resolve(executionPath, testFolder);
78
- const openSettings = (await fs_1.default.promises
79
- .readFile(path_1.default.resolve(testPath, 'settings.json'), 'utf-8')
80
- .then(JSON.parse));
80
+ const testPath = path_1.default.join(offlineLocationPath, testFolder);
81
+ const fileOpenSettings = await fs_1.default.promises
82
+ .readFile(path_1.default.join(testPath, 'settings.json'), 'utf-8')
83
+ .then(JSON.parse);
84
+ const openSettings = (0, merge_configs_1.mergeConfigs)(fileOpenSettings, options.config.open);
81
85
  logger.console.log(`Running test: ${openSettings.testName} (${formatEnvironment(openSettings.environment)})`);
82
- return runTest(executionPath, testPath, openSettings, testLogger);
86
+ return runTest(testPath, openSettings, testLogger);
83
87
  }));
84
88
  const batchIds = [...new Set(results.map(t => t.batchId))];
85
89
  const allTestResults = results.map(t => t.results);
86
- executionLogger.log('done running all tests', allTestResults);
90
+ logger.log('done running all tests', allTestResults);
87
91
  await core.closeBatch({ settings: batchIds.map(batchId => ({ batchId, ...account.eyesServer })) });
88
- executionLogger.log('done execution', executionName);
92
+ logger.log('done closing batches');
89
93
  return allTestResults;
90
94
  }
91
- async function runTest(executionPath, testPath, openSettings, logger) {
95
+ async function runTest(testPath, openSettings, logger) {
92
96
  const environment = await ufgClient.getActualEnvironment({
93
97
  settings: { environment: openSettings.environment.requested },
94
98
  });
@@ -106,17 +110,17 @@ async function runOfflineSnapshots(options) {
106
110
  const checkFolders = (await fs_1.default.promises.readdir(testPath)).filter(folderpath => folderpath.startsWith('check-'));
107
111
  logger.log('running checks for test', testPath, ':', checkFolders);
108
112
  const targets = (await Promise.all(checkFolders.map(checkFolder => fs_1.default.promises.readFile(path_1.default.resolve(testPath, checkFolder, 'snapshot.json'), 'utf-8').then(JSON.parse))));
109
- await uploadResources(executionPath, targets, logger);
113
+ await uploadResources(targets, logger);
110
114
  // logger.log('resource hashes for test', testFolder, ':', resourceHashes)
111
115
  logger.log('uploaded resources for test', testPath);
112
116
  await Promise.all(targets.map((target, index) => runCheck(eyes, target, index, logger)));
113
- await eyes.close({
114
- settings: await fs_1.default.promises.readFile(path_1.default.resolve(testPath, 'close.json'), 'utf-8').then(JSON.parse),
115
- });
117
+ const fileCloseSettings = await fs_1.default.promises.readFile(path_1.default.resolve(testPath, 'close.json'), 'utf-8').then(JSON.parse);
118
+ const closeSettings = (0, merge_configs_1.mergeConfigs)(fileCloseSettings, options.config.close);
119
+ await eyes.close({ settings: closeSettings });
116
120
  logger.log('done running test', logger);
117
121
  return { batchId: openSettings.batch.id, results: (await eyes.getResults({ logger }))[0] };
118
122
  }
119
- async function uploadResources(executionPath, targets, logger) {
123
+ async function uploadResources(targets, logger) {
120
124
  const uploadLogger = logger.extend({ tags: ['upload-resources'] });
121
125
  const promises = targets.map(async ({ target }) => {
122
126
  let resourcePromises = Object.values(target.resources)
@@ -125,7 +129,7 @@ async function runOfflineSnapshots(options) {
125
129
  const contentfuleResource = {
126
130
  id: '',
127
131
  url: '',
128
- value: await fs_1.default.promises.readFile(path_1.default.resolve(executionPath, 'resources', resource.hash)),
132
+ value: await fs_1.default.promises.readFile(path_1.default.join(offlineLocationPath, 'resources', resource.hash)),
129
133
  contentType: resource.contentType,
130
134
  hash: resource,
131
135
  };
@@ -135,7 +139,7 @@ async function runOfflineSnapshots(options) {
135
139
  resource: {
136
140
  id: '',
137
141
  url: '',
138
- value: await fs_1.default.promises.readFile(path_1.default.resolve(executionPath, 'resources', target.snapshot.hash)),
142
+ value: await fs_1.default.promises.readFile(path_1.default.join(offlineLocationPath, 'resources', target.snapshot.hash)),
139
143
  contentType: target.snapshot.contentType,
140
144
  hash: target.snapshot,
141
145
  },
@@ -180,9 +184,10 @@ async function runOfflineSnapshots(options) {
180
184
  baseSettings.stepIndex = index;
181
185
  baseTarget.source = target.target.source; // TODO verify
182
186
  // baseTarget.name = snapshot.title // TODO figure out
187
+ const mergedCheckSettings = (0, merge_configs_1.mergeConfigs)(baseSettings, options.config.check);
183
188
  await eyes.check({
184
189
  target: { ...baseTarget, isTransformed: true },
185
- settings: baseSettings,
190
+ settings: mergedCheckSettings,
186
191
  logger: checkLogger,
187
192
  });
188
193
  }
@@ -25,7 +25,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.toSafeCheckSettings = void 0;
27
27
  const utils = __importStar(require("@applitools/utils"));
28
- const regionTypes = ['ignore', 'layout', 'strict', 'content', 'floating', 'accessibility'];
28
+ const regionTypes = ['ignore', 'layout', 'strict', 'content', 'floating', 'accessibility', 'dynamic'];
29
29
  function toSafeCheckSettings({ settings }) {
30
30
  const calculate = regionTypes.flatMap(regionType => {
31
31
  var _a;
@@ -32,7 +32,7 @@ const path_1 = __importDefault(require("path"));
32
32
  const utils = __importStar(require("@applitools/utils"));
33
33
  function ensureOfflineFolder() {
34
34
  const offlineLocationPath = utils.general.getEnvValue('OFFLINE_LOCATION_PATH')
35
- ? path_1.default.resolve(utils.general.getEnvValue('OFFLINE_LOCATION_PATH'), `execution-${Date.now()}`)
35
+ ? path_1.default.resolve(utils.general.getEnvValue('OFFLINE_LOCATION_PATH'))
36
36
  : undefined;
37
37
  if (offlineLocationPath) {
38
38
  fs_1.default.mkdirSync(offlineLocationPath, { recursive: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/core",
3
- "version": "4.24.2",
3
+ "version": "4.26.0",
4
4
  "homepage": "https://applitools.com",
5
5
  "bugs": {
6
6
  "url": "https://github.com/applitools/eyes.sdk.javascript1/issues"
@@ -28,8 +28,8 @@
28
28
  "./package.json": "./package.json"
29
29
  },
30
30
  "bin": {
31
- "eyes": "./dist/cli/cli.js",
32
- "eyes-check-network": "./dist/troubleshoot/check-network.js"
31
+ "eyes-check-network": "./dist/troubleshoot/check-network.js",
32
+ "eyes-core": "./dist/cli/cli.js"
33
33
  },
34
34
  "main": "./dist/index.js",
35
35
  "types": "./types/index.d.ts",
@@ -58,7 +58,7 @@
58
58
  "setup": "run --top-level browsers:setup"
59
59
  },
60
60
  "sea": {
61
- "bin": "eyes",
61
+ "bin": "eyes-core",
62
62
  "certs": {
63
63
  "win": {
64
64
  "cert": "env.CODE_SIGNING_CERT_WIN",
@@ -74,11 +74,11 @@
74
74
  }
75
75
  },
76
76
  "dependencies": {
77
- "@applitools/core-base": "1.19.3",
77
+ "@applitools/core-base": "1.20.0",
78
78
  "@applitools/dom-capture": "11.5.2",
79
79
  "@applitools/dom-snapshot": "4.11.11",
80
80
  "@applitools/driver": "1.20.0",
81
- "@applitools/ec-client": "1.9.15",
81
+ "@applitools/ec-client": "1.9.16",
82
82
  "@applitools/logger": "2.0.19",
83
83
  "@applitools/nml-client": "1.8.19",
84
84
  "@applitools/req": "1.7.4",
@@ -86,7 +86,7 @@
86
86
  "@applitools/snippets": "2.6.3",
87
87
  "@applitools/socket": "1.1.19",
88
88
  "@applitools/spec-driver-webdriver": "1.1.20",
89
- "@applitools/ufg-client": "1.14.1",
89
+ "@applitools/ufg-client": "1.15.0",
90
90
  "@applitools/utils": "1.7.5",
91
91
  "@types/ws": "8.5.5",
92
92
  "abort-controller": "3.0.0",
package/types/index.d.ts CHANGED
@@ -7,3 +7,4 @@ export { type SpecType, type SpecDriver, type Selector } from '@applitools/drive
7
7
  export * from '@applitools/driver/dist/debug';
8
8
  export * as formatters from './utils/format-results';
9
9
  export * as logs from './troubleshoot/logs';
10
+ export * from './offline/run-offline-snapshots';
@@ -0,0 +1 @@
1
+ export declare function mergeConfigs<TBase extends Record<string, any>>(base: TBase, other: Record<string, any>): TBase;
@@ -0,0 +1,11 @@
1
+ import { Config, type EyesServerSettings } from '../types';
2
+ import { type Logger } from '@applitools/logger';
3
+ import type { TestResult } from '@applitools/core-base';
4
+ import type { SpecType } from '@applitools/driver';
5
+ export type OfflineSnapshotsSettings = EyesServerSettings & {
6
+ offlineLocationPath: string;
7
+ failOnDiff: boolean;
8
+ config: Config<SpecType, 'ufg'>;
9
+ logger?: Logger;
10
+ };
11
+ export declare function runOfflineSnapshots(options: OfflineSnapshotsSettings): Promise<TestResult[]>;
@@ -1,6 +0,0 @@
1
- import { type EyesServerSettings } from './types';
2
- export type OfflineSnapshotsSettings = EyesServerSettings & {
3
- offlineLocationPath: string;
4
- failOnDiff: boolean;
5
- };
6
- export declare function runOfflineSnapshots(options: OfflineSnapshotsSettings): Promise<void>;