@applitools/core 4.19.0 → 4.20.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,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.20.0](https://github.com/Applitools-Dev/sdk/compare/js/core@4.19.0...js/core@4.20.0) (2024-09-30)
4
+
5
+
6
+ ### Features
7
+
8
+ * offline execution ([#2528](https://github.com/Applitools-Dev/sdk/issues/2528)) ([e6c3b9e](https://github.com/Applitools-Dev/sdk/commit/e6c3b9e3315203027551da3bfdecf90490edd029))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * @applitools/ufg-client bumped to 1.13.0
14
+ #### Features
15
+
16
+ * offline execution ([#2528](https://github.com/Applitools-Dev/sdk/issues/2528)) ([e6c3b9e](https://github.com/Applitools-Dev/sdk/commit/e6c3b9e3315203027551da3bfdecf90490edd029))
17
+ * @applitools/core-base bumped to 1.17.0
18
+ #### Features
19
+
20
+ * offline execution ([#2528](https://github.com/Applitools-Dev/sdk/issues/2528)) ([e6c3b9e](https://github.com/Applitools-Dev/sdk/commit/e6c3b9e3315203027551da3bfdecf90490edd029))
21
+ * @applitools/ec-client bumped to 1.9.6
22
+
23
+
3
24
  ## [4.19.0](https://github.com/Applitools-Dev/sdk/compare/js/core@4.18.2...js/core@4.19.0) (2024-09-16)
4
25
 
5
26
 
@@ -14,7 +14,7 @@ function makeAutonomousCore({ spec, clients, base: defaultBase, asyncCache, agen
14
14
  const core = (0, core_1.makeCore)({ spec, clients, base: defaultBase, asyncCache, agentId, cwd, logger });
15
15
  return {
16
16
  type: 'autonomous',
17
- takeSnapshots: spec && (0, take_snapshots_1.makeTakeSnapshots)({ core, logger }),
17
+ takeSnapshots: spec && (0, take_snapshots_1.makeTakeSnapshots)({ core, spec, logger }),
18
18
  createRenderTarget: (0, create_render_target_1.makeCreateRenderTarget)({ core, logger }),
19
19
  startRenders: (0, start_renders_1.makeStartRenders)({ core, logger }),
20
20
  getRenderResults: (0, get_render_results_1.makeGetRenderResults)({ core, logger }),
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeCreateRenderTarget = void 0;
4
+ const create_render_target_from_snapshot_1 = require("../ufg/create-render-target-from-snapshot");
4
5
  function makeCreateRenderTarget({ core, logger: defaultLogger }) {
5
6
  return async function createRenderTarget({ snapshot, logger = defaultLogger, }) {
6
7
  const ufgClient = await core.getUFGClient({
@@ -11,21 +12,7 @@ function makeCreateRenderTarget({ core, logger: defaultLogger }) {
11
12
  },
12
13
  logger,
13
14
  });
14
- const target = await ufgClient.createRenderTarget({
15
- snapshot: snapshot.target,
16
- settings: {
17
- environment: snapshot.environment,
18
- cookies: snapshot.target.cookies,
19
- headers: {
20
- Referer: snapshot.url,
21
- 'User-Agent': snapshot.userAgent,
22
- ...snapshot.settings.headers,
23
- },
24
- proxy: snapshot.account.eyesServer.proxy,
25
- autProxy: snapshot.settings.autProxy,
26
- },
27
- logger,
28
- });
15
+ const target = await (0, create_render_target_from_snapshot_1.createRenderTargetFromSnapshot)({ ufgClient, snapshot, logger });
29
16
  return { ...snapshot, target };
30
17
  };
31
18
  }
@@ -1,12 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeTakeSnapshots = void 0;
4
+ const driver_1 = require("@applitools/driver");
4
5
  const populate_eyes_server_settings_1 = require("../utils/populate-eyes-server-settings");
5
- function makeTakeSnapshots({ core, logger: defaultLogger }) {
6
+ const uniquify_environments_1 = require("../automation/utils/uniquify-environments");
7
+ function makeTakeSnapshots({ core, spec, logger: defaultLogger }) {
6
8
  return async function takeSnapshots({ target, settings, logger = defaultLogger, }) {
7
9
  (0, populate_eyes_server_settings_1.populateEyesServerSettings)(settings);
8
10
  const account = await core.base.getAccountInfo({ settings: settings, logger });
9
- return core.takeSnapshots({ target, settings, account, logger });
11
+ settings.environments = (0, uniquify_environments_1.uniquifyEnvironments)(settings.environments);
12
+ const driver = await (0, driver_1.makeDriver)({ spec, driver: target, logger });
13
+ return core.takeSnapshots({ driver, settings, account, logger });
10
14
  };
11
15
  }
12
16
  exports.makeTakeSnapshots = makeTakeSnapshots;
@@ -34,10 +34,10 @@ const extract_text_1 = require("../automation/extract-text");
34
34
  const get_nml_client_1 = require("../automation/get-nml-client");
35
35
  const open_eyes_1 = require("./open-eyes");
36
36
  const utils = __importStar(require("@applitools/utils"));
37
- function makeCore({ spec, clients, base: defaultBase, concurrency, agentId = 'core-classic', cwd = process.cwd(), logger: defaultLogger, }) {
37
+ function makeCore({ spec, clients, base: defaultBase, concurrency, agentId = 'core-classic', cwd = process.cwd(), logger: defaultLogger, offlineLocationPath, }) {
38
38
  const logger = (0, logger_1.makeLogger)({ logger: defaultLogger, format: { label: 'core-classic' } });
39
39
  logger.log(`Core classic is initialized ${defaultBase ? 'with' : 'without'} custom base core`);
40
- const base = defaultBase !== null && defaultBase !== void 0 ? defaultBase : (0, core_base_1.makeCore)({ agentId, concurrency, cwd, logger });
40
+ const base = defaultBase !== null && defaultBase !== void 0 ? defaultBase : (0, core_base_1.makeCore)({ agentId, concurrency, cwd, logger, offlineLocationPath });
41
41
  return utils.general.extend(base, core => {
42
42
  return {
43
43
  type: 'classic',
package/dist/cli/cli.js CHANGED
@@ -32,6 +32,7 @@ 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");
35
36
  const yargs_1 = __importDefault(require("yargs"));
36
37
  const utils = __importStar(require("@applitools/utils"));
37
38
  const fs_1 = __importDefault(require("fs"));
@@ -151,5 +152,24 @@ yargs_1.default
151
152
  handler: async () => {
152
153
  await (0, check_network_1.checkNetwork)();
153
154
  },
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
+ })
165
+ .fail((_msg, err, _yargs) => {
166
+ if (err) {
167
+ console.error(err.message);
168
+ process.exit(1);
169
+ }
170
+ }),
171
+ handler: async (args) => {
172
+ await (0, run_offline_snapshots_1.runOfflineSnapshots)(args);
173
+ },
154
174
  })
155
175
  .wrap(yargs_1.default.terminalWidth()).argv;
package/dist/core.js CHANGED
@@ -41,6 +41,7 @@ const make_manager_1 = require("./make-manager");
41
41
  const close_batch_1 = require("./close-batch");
42
42
  const delete_test_1 = require("./delete-test");
43
43
  const extract_test_environment_1 = require("./utils/extract-test-environment");
44
+ const ensure_offline_folder_1 = require("./utils/ensure-offline-folder");
44
45
  const validate_sdk_version_1 = require("./utils/validate-sdk-version");
45
46
  const memory_usage_logging_1 = require("./utils/memory-usage-logging");
46
47
  const utils = __importStar(require("@applitools/utils"));
@@ -51,10 +52,11 @@ function makeCore({ spec, clients, base: defaultBase, concurrency = utils.genera
51
52
  logger.log(`Core is initialized ${defaultBase ? 'with' : 'without'} custom base core and environment `, environment);
52
53
  if (environment.sdk)
53
54
  (0, validate_sdk_version_1.validateSdkVersion)(environment.sdk, { logger });
54
- const base = defaultBase !== null && defaultBase !== void 0 ? defaultBase : (0, core_base_1.makeCore)({ agentId, concurrency, cwd, logger });
55
+ const offlineLocationPath = (0, ensure_offline_folder_1.ensureOfflineFolder)();
56
+ const base = defaultBase !== null && defaultBase !== void 0 ? defaultBase : (0, core_base_1.makeCore)({ agentId, concurrency, cwd, logger, offlineLocationPath });
55
57
  const cores = {
56
- ufg: (0, core_2.makeCore)({ spec, clients, base, asyncCache, logger }),
57
- classic: (0, core_1.makeCore)({ spec, clients, base, logger }),
58
+ ufg: (0, core_2.makeCore)({ spec, clients, base, asyncCache, logger, offlineLocationPath }),
59
+ classic: (0, core_1.makeCore)({ spec, clients, base, logger, offlineLocationPath }),
58
60
  };
59
61
  return utils.general.extend(base, core => {
60
62
  return {
@@ -76,6 +78,7 @@ function makeCore({ spec, clients, base: defaultBase, concurrency = utils.genera
76
78
  environment,
77
79
  asyncCache,
78
80
  logger,
81
+ offlineLocationPath,
79
82
  }),
80
83
  locate: (0, locate_1.makeLocate)({ spec, core, logger }),
81
84
  locateText: (0, locate_text_1.makeLocateText)({ spec, core, logger }),
@@ -30,7 +30,7 @@ const core_2 = require("./ufg/core");
30
30
  const open_eyes_1 = require("./open-eyes");
31
31
  const get_manager_results_1 = require("./get-manager-results");
32
32
  const utils = __importStar(require("@applitools/utils"));
33
- function makeMakeManager({ spec, clients, core, base: defaultBase, agentId: defaultAgentId, environment, cwd = process.cwd(), logger: mainLogger, asyncCache, }) {
33
+ function makeMakeManager({ spec, clients, core, base: defaultBase, agentId: defaultAgentId, environment, cwd = process.cwd(), logger: mainLogger, asyncCache, offlineLocationPath, }) {
34
34
  return async function makeManager({ type = 'classic', settings, logger = mainLogger, } = {}) {
35
35
  var _a, _b, _c, _d, _e, _f, _g;
36
36
  var _h, _j;
@@ -42,9 +42,10 @@ function makeMakeManager({ spec, clients, core, base: defaultBase, agentId: defa
42
42
  (_f = (_j = settings.batch).buildId) !== null && _f !== void 0 ? _f : (_j.buildId = utils.general.getEnvValue('BATCH_BUILD_ID'));
43
43
  (_g = settings.agentId) !== null && _g !== void 0 ? _g : (settings.agentId = type === 'ufg' ? defaultAgentId === null || defaultAgentId === void 0 ? void 0 : defaultAgentId.replace(/(\/\d)/, '.visualgrid$1') : defaultAgentId);
44
44
  logger.log('Command "makeManager" is called with settings', settings);
45
- const base = defaultBase !== null && defaultBase !== void 0 ? defaultBase : (0, core_base_1.makeCore)({ agentId: settings.agentId, concurrency: settings.concurrency, cwd, logger });
45
+ const base = defaultBase !== null && defaultBase !== void 0 ? defaultBase : (0, core_base_1.makeCore)({ agentId: settings.agentId, concurrency: settings.concurrency, cwd, logger, offlineLocationPath });
46
+ const fetchConcurrency = settings.fetchConcurrency;
46
47
  const cores = {
47
- ufg: (0, core_2.makeCore)({ spec, clients, base, fetchConcurrency: settings.fetchConcurrency, asyncCache, logger }),
48
+ ufg: (0, core_2.makeCore)({ spec, clients, base, fetchConcurrency, asyncCache, logger, offlineLocationPath }),
48
49
  classic: (0, core_1.makeCore)({ spec, clients, base, logger }),
49
50
  };
50
51
  const storage = [];
package/dist/open-eyes.js CHANGED
@@ -35,6 +35,7 @@ const abort_1 = require("./abort");
35
35
  const get_eyes_results_1 = require("./get-eyes-results");
36
36
  const populate_eyes_server_settings_1 = require("./utils/populate-eyes-server-settings");
37
37
  const utils = __importStar(require("@applitools/utils"));
38
+ const core_base_1 = require("@applitools/core-base");
38
39
  function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDuplicateTests, core, cores, spec, environment, logger: mainLogger, asyncCache, }) {
39
40
  return async function openEyes({ type = defaultType, settings, config, target, logger = mainLogger, }) {
40
41
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
@@ -98,7 +99,9 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
98
99
  },
99
100
  logger,
100
101
  });
101
- const eyes = await getTypedEyes({ logger });
102
+ const eyes = await getTypedEyes({ logger }).catch(error => {
103
+ throw refineMissingApiKeyException(error, environment === null || environment === void 0 ? void 0 : environment.sdk);
104
+ });
102
105
  return utils.general.extend(eyes, eyes => {
103
106
  var _a, _b;
104
107
  return ({
@@ -113,6 +116,63 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
113
116
  };
114
117
  }
115
118
  exports.makeOpenEyes = makeOpenEyes;
119
+ function refineMissingApiKeyException(error, sdk) {
120
+ var _a;
121
+ if (!sdk || typeof sdk !== 'object')
122
+ return error;
123
+ try {
124
+ if (error instanceof core_base_1.MissingApiKeyError) {
125
+ const apiKeyTutorials = {
126
+ python: {
127
+ 'eyes-selenium': 'api-ref/sdk-api/selenium/python/#API',
128
+ 'eyes-playwright': 'api-ref/sdk-api/playwright/python/#API',
129
+ 'eyes-robotframework': 'api-ref/sdk-api/robot/#API',
130
+ 'eyes-images': undefined,
131
+ },
132
+ ruby: {
133
+ eyes_images: 'api-ref/sdk-api/selenium/ruby/#API',
134
+ eyes_appium: undefined,
135
+ eyes_selenium: undefined,
136
+ eyes_universal: undefined,
137
+ eyes_capybara: undefined,
138
+ eyes_calabash: undefined,
139
+ },
140
+ java: {
141
+ java_appium: undefined,
142
+ java_selenium: 'api-ref/sdk-api/selenium/java/#API',
143
+ java_playwright: 'api-ref/sdk-api/playwright/java/#API',
144
+ java_images: undefined,
145
+ },
146
+ dotnet: {
147
+ 'eyes-selenium': 'api-ref/sdk-api/selenium/csharp/#API',
148
+ 'eyes-playwright': 'api-ref/sdk-api/playwright/csharp/#API',
149
+ 'eyes-appium': undefined,
150
+ 'eyes-appium2': undefined,
151
+ 'eyes-images': undefined,
152
+ },
153
+ js: {
154
+ 'eyes-images': undefined,
155
+ 'eyes-webdriverio': 'api-ref/sdk-api/wdio/#API',
156
+ 'eyes-selenium': 'api-ref/sdk-api/selenium/javascript/#API',
157
+ 'eyes-playwright': 'api-ref/sdk-api/playwright/javascript/#API',
158
+ 'eyes-puppeteer': 'api-ref/sdk-api/puppeteer/javascript/#API',
159
+ 'eyes-storybook': 'api-ref/sdk-api/storybook/#API',
160
+ 'eyes-cypress': 'api-ref/sdk-api/cypress/#API',
161
+ },
162
+ };
163
+ const { lang, name } = sdk !== null && sdk !== void 0 ? sdk : {};
164
+ const path = (_a = apiKeyTutorials[lang]) === null || _a === void 0 ? void 0 : _a[name];
165
+ if (path) {
166
+ error.message = error.message.replace('Default.html#cshid=api', path);
167
+ }
168
+ }
169
+ }
170
+ catch {
171
+ // if it fails, no harm done. The error message is fine without this refinement
172
+ return error;
173
+ }
174
+ return error;
175
+ }
116
176
  function getLatestCommitInfoFromEnvVars(logger) {
117
177
  const timestamp = utils.general.getEnvValue('GIT_LATEST_COMMIT_TIMESTAMP');
118
178
  const sha = utils.general.getEnvValue('GIT_LATEST_COMMIT_SHA');
@@ -0,0 +1,346 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.runOfflineSnapshots = void 0;
30
+ const fs_1 = __importDefault(require("fs"));
31
+ const path_1 = __importDefault(require("path"));
32
+ const tar = __importStar(require("tar"));
33
+ const core_1 = require("./core");
34
+ const get_ufg_client_1 = require("./ufg/get-ufg-client");
35
+ const logger_1 = require("@applitools/logger");
36
+ const to_base_check_settings_1 = require("./automation/utils/to-base-check-settings");
37
+ const chalk_1 = __importDefault(require("chalk"));
38
+ const utils = __importStar(require("@applitools/utils"));
39
+ async function runOfflineSnapshots(options) {
40
+ if (!options.offlineLocationPath)
41
+ throw new Error('offlineLocationPath is required');
42
+ const startTime = Date.now();
43
+ const logger = (0, logger_1.makeLogger)({ format: { label: 'offline-exec' } });
44
+ const core = (0, core_1.makeCore)();
45
+ const account = await core.getAccountInfo({ settings: options });
46
+ const ufgClient = await (0, get_ufg_client_1.makeGetUFGClient)({ logger })({
47
+ settings: { ...account.eyesServer, ...account.ufgServer },
48
+ });
49
+ const executionFiles = (await fs_1.default.promises.readdir(options.offlineLocationPath)).filter(filename => filename.endsWith('.tar.gz'));
50
+ if (executionFiles.length === 1) {
51
+ logger.console.log(`Running execution ${executionFiles[0]} from folder ${path_1.default.resolve(options.offlineLocationPath)}`);
52
+ }
53
+ else if (executionFiles.length === 0) {
54
+ logger.console.log('No execution artifacts were found at', options.offlineLocationPath);
55
+ }
56
+ else {
57
+ logger.console.log(`Running the following executions from folder ${options.offlineLocationPath} :\n ${executionFiles.join('\n ')}`);
58
+ }
59
+ if (executionFiles.length === 0) {
60
+ throw new Error(`Unable to find offline executions in ${options.offlineLocationPath}`);
61
+ }
62
+ const allTestResults = (await Promise.all(executionFiles.map(runExecution))).flat();
63
+ const { exitCode, outputStr } = processResults({ testResults: allTestResults, totalTime: Date.now() - startTime });
64
+ if (exitCode) {
65
+ throw new Error(outputStr);
66
+ }
67
+ else {
68
+ logger.console.log(outputStr);
69
+ }
70
+ async function runExecution(executionFile) {
71
+ const executionName = executionFile.replace('.tar.gz', '');
72
+ const executionLogger = logger.extend({ tags: [executionName] });
73
+ executionLogger.log('unpacking execution', executionFile);
74
+ await tar.extract({
75
+ file: path_1.default.resolve(options.offlineLocationPath, executionFile),
76
+ gzip: true,
77
+ C: options.offlineLocationPath,
78
+ });
79
+ const executionPath = path_1.default.resolve(options.offlineLocationPath, executionName);
80
+ executionLogger.log('handling execution', executionPath);
81
+ const testFolders = (await fs_1.default.promises.readdir(executionPath)).filter(foldername => foldername.startsWith('test-'));
82
+ executionLogger.log('running tests', testFolders);
83
+ const results = await Promise.all(testFolders.map(async (testFolder) => {
84
+ const testLogger = logger.extend({ tags: [testFolder] });
85
+ const testPath = path_1.default.resolve(executionPath, testFolder);
86
+ const openSettings = (await fs_1.default.promises
87
+ .readFile(path_1.default.resolve(testPath, 'settings.json'), 'utf-8')
88
+ .then(JSON.parse));
89
+ logger.console.log(`Running test: ${openSettings.testName} (${formatEnvironment(openSettings.environment)})`);
90
+ return runTest(executionPath, testPath, openSettings, testLogger);
91
+ }));
92
+ const batchIds = [...new Set(results.map(t => t.batchId))];
93
+ const allTestResults = results.map(t => t.results);
94
+ executionLogger.log('done running all tests', allTestResults);
95
+ // @ts-expect-error // we use node v12 types, therefore it's not aware of the existence of `fs.promises.rm`
96
+ await fs_1.default.promises.rm(executionPath, { recursive: true });
97
+ await core.closeBatch({ settings: batchIds.map(batchId => ({ batchId, ...account.eyesServer })) });
98
+ executionLogger.log('one execution', executionFile);
99
+ return allTestResults;
100
+ }
101
+ async function runTest(executionPath, testPath, openSettings, logger) {
102
+ const environment = await ufgClient.getActualEnvironment({
103
+ settings: { environment: openSettings.environment.requested },
104
+ });
105
+ const eyes = await core.base.openEyes({
106
+ settings: {
107
+ ...openSettings,
108
+ environment: {
109
+ ...openSettings.environment,
110
+ ...environment,
111
+ },
112
+ ...account.eyesServer,
113
+ },
114
+ logger,
115
+ });
116
+ const checkFolders = (await fs_1.default.promises.readdir(testPath)).filter(folderpath => folderpath.startsWith('check-'));
117
+ logger.log('running checks for test', testPath, ':', checkFolders);
118
+ 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))));
119
+ await uploadResources(executionPath, targets, logger);
120
+ // logger.log('resource hashes for test', testFolder, ':', resourceHashes)
121
+ logger.log('uploaded resources for test', testPath);
122
+ await Promise.all(targets.map((target, index) => runCheck(eyes, target, index, logger)));
123
+ await eyes.close({
124
+ settings: await fs_1.default.promises.readFile(path_1.default.resolve(testPath, 'close.json'), 'utf-8').then(JSON.parse),
125
+ });
126
+ logger.log('done running test', logger);
127
+ return { batchId: openSettings.batch.id, results: (await eyes.getResults({ logger }))[0] };
128
+ }
129
+ async function uploadResources(executionPath, targets, logger) {
130
+ const uploadLogger = logger.extend({ tags: ['upload-resources'] });
131
+ const promises = targets.map(async ({ target }) => {
132
+ let resourcePromises = Object.values(target.resources)
133
+ .filter(isHashedResource)
134
+ .map(async (resource) => {
135
+ const contentfuleResource = {
136
+ id: '',
137
+ url: '',
138
+ value: await fs_1.default.promises.readFile(path_1.default.resolve(executionPath, 'resources', resource.hash)),
139
+ contentType: resource.contentType,
140
+ hash: resource,
141
+ };
142
+ return ufgClient.uploadResource({ resource: contentfuleResource, logger: uploadLogger });
143
+ });
144
+ resourcePromises = resourcePromises.concat(ufgClient.uploadResource({
145
+ resource: {
146
+ id: '',
147
+ url: '',
148
+ value: await fs_1.default.promises.readFile(path_1.default.resolve(executionPath, 'resources', target.snapshot.hash)),
149
+ contentType: target.snapshot.contentType,
150
+ hash: target.snapshot,
151
+ },
152
+ logger: uploadLogger,
153
+ }));
154
+ return Promise.all(resourcePromises);
155
+ });
156
+ await Promise.all(promises);
157
+ function isHashedResource(resource) {
158
+ return 'hash' in resource;
159
+ }
160
+ }
161
+ async function runCheck(eyes, target, index, logger) {
162
+ var _a;
163
+ const checkLogger = logger.extend({ tags: [`check-${index}`] });
164
+ const { elementReferences: selectors, getBaseCheckSettings } = (0, to_base_check_settings_1.toBaseCheckSettings)({
165
+ settings: target.settings,
166
+ });
167
+ const { renderId, selectorRegions, ...baseTarget } = await ufgClient.render({
168
+ target: target.target,
169
+ settings: {
170
+ ...target.settings,
171
+ region: (_a = selectors.target) !== null && _a !== void 0 ? _a : target.settings.region,
172
+ scrollRootElement: selectors.scrolling,
173
+ selectorsToCalculate: selectors.calculate,
174
+ includeFullPageSize: Boolean(target.settings.pageId),
175
+ environment: target.settings.environment,
176
+ uploadUrl: account.uploadUrl,
177
+ stitchingServiceUrl: account.stitchingServiceUrl,
178
+ },
179
+ logger: checkLogger,
180
+ });
181
+ const baseSettings = getBaseCheckSettings({
182
+ calculatedRegions: selectors.calculate.map((_, index) => {
183
+ var _a;
184
+ return ({
185
+ regions: (_a = selectorRegions === null || selectorRegions === void 0 ? void 0 : selectorRegions[index]) !== null && _a !== void 0 ? _a : [],
186
+ });
187
+ }),
188
+ });
189
+ baseSettings.renderId = renderId;
190
+ baseSettings.stepIndex = index;
191
+ baseTarget.source = target.target.source; // TODO verify
192
+ // baseTarget.name = snapshot.title // TODO figure out
193
+ await eyes.check({
194
+ target: { ...baseTarget, isTransformed: true },
195
+ settings: baseSettings,
196
+ logger: checkLogger,
197
+ });
198
+ }
199
+ }
200
+ exports.runOfflineSnapshots = runOfflineSnapshots;
201
+ function uniq(arr) {
202
+ return [...new Set(arr)];
203
+ }
204
+ function processResults({ testResults, totalTime, saveNewTests = true, failOnDiff = true, }) {
205
+ let outputStr = '\n';
206
+ const pluralize = utils.general.pluralize;
207
+ const testResultsWithErrors = testResults.filter(r => r && r.reason);
208
+ const unresolved = testResults.filter(r => r.isDifferent && !r.isAborted);
209
+ const passedOrNew = testResults.filter(r => r.status === 'Passed' || (r.isNew && !r.isAborted));
210
+ const aborted = testResults.filter(r => r.isAborted);
211
+ const newTests = testResults.filter(r => r.isNew && !r.isAborted);
212
+ const failedTests = testResults.filter(r => !r.reason && !r.isNew && !r.isAborted && !r.isDifferent && r.status === 'Failed');
213
+ const newTestsSize = newTests.length;
214
+ const warnForUnsavedNewTests = !!(!saveNewTests && newTestsSize);
215
+ const errMessagesToExclude = ['detected differences', 'Please approve the new baseline', 'is failed! See details at'];
216
+ const errors = testResultsWithErrors
217
+ .filter(r => !errMessagesToExclude.some(msg => { var _a, _b; return (_b = (_a = r.reason) === null || _a === void 0 ? void 0 : _a.message) === null || _b === void 0 ? void 0 : _b.includes(msg); }))
218
+ .map(r => ({
219
+ error: r.reason,
220
+ title: r.name,
221
+ }));
222
+ const hasResults = unresolved.length || passedOrNew.length || aborted.length;
223
+ const seeDetailsStr = hasResults && `See details at ${(passedOrNew[0] || unresolved[0] || aborted[0]).appUrls.batch}`;
224
+ if (hasResults) {
225
+ outputStr += `${seeDetailsStr}\n\n`;
226
+ }
227
+ outputStr += '[EYES: TEST RESULTS]:\n\n';
228
+ if (passedOrNew.length > 0) {
229
+ outputStr += testResultsOutput(passedOrNew, warnForUnsavedNewTests);
230
+ }
231
+ if (failedTests.length > 0) {
232
+ outputStr += testResultsOutput(failedTests, warnForUnsavedNewTests);
233
+ }
234
+ if (unresolved.length > 0) {
235
+ outputStr += testResultsOutput(unresolved, warnForUnsavedNewTests);
236
+ }
237
+ if (aborted.length > 0) {
238
+ outputStr += testResultsOutput(aborted, warnForUnsavedNewTests);
239
+ }
240
+ if (errors.length) {
241
+ const sortedErrors = errors.sort((a, b) => a.title.localeCompare(b.title));
242
+ outputStr += uniq(sortedErrors.map(({ title, error }) => `${title} - ${chalk_1.default.red('Failed')}. ${error.message || error.toString()}`)).join('\n');
243
+ outputStr += '\n';
244
+ }
245
+ if (!errors.length && !hasResults) {
246
+ outputStr += 'Test is finished but no results returned.\n';
247
+ }
248
+ const unresolvedOrFailed = unresolved.concat(failedTests);
249
+ if (errors.length && !unresolvedOrFailed.length) {
250
+ outputStr += chalk_1.default.red(`\nA total of ${errors.length} test${pluralize(errors.length)} failed for unexpected error${pluralize(errors.length)}.`);
251
+ }
252
+ else if (unresolvedOrFailed.length && !errors.length) {
253
+ outputStr += chalk_1.default.keyword(failedTests.length ? 'red' : 'orange')(`\nA total of ${unresolvedOrFailed.length} difference${pluralize(unresolvedOrFailed.length, [
254
+ 's were',
255
+ ' was',
256
+ ])} found.`);
257
+ }
258
+ else if (unresolvedOrFailed.length || errors.length) {
259
+ outputStr += chalk_1.default.red(`\nA total of ${unresolvedOrFailed.length} difference${pluralize(unresolvedOrFailed.length, [
260
+ 's were',
261
+ ' was',
262
+ ])} found and ${errors.length} test${pluralize(errors.length)} failed for ${pluralize(errors.length, [
263
+ '',
264
+ 'an ',
265
+ ])}unexpected error${pluralize(errors.length)}.`);
266
+ }
267
+ else if (warnForUnsavedNewTests) {
268
+ const countText = newTestsSize > 1 ? `are ${newTestsSize} new tests` : `is a new test: '${newTests[0].name}'`;
269
+ outputStr += chalk_1.default.red(`\n'saveNewTests' was set to false and there ${countText}. Please approve ${pluralize(newTestsSize, [
270
+ 'their',
271
+ 'its',
272
+ ])} baseline${pluralize(newTestsSize)} in Eyes dashboard.\n`);
273
+ }
274
+ else if (passedOrNew.length) {
275
+ outputStr += chalk_1.default.green(`\nNo differences were found!`);
276
+ }
277
+ if (hasResults) {
278
+ outputStr += `\n${seeDetailsStr}\nTotal time: ${Math.round(totalTime / 1000)} seconds\n`;
279
+ }
280
+ // if (Number(testConcurrency) === 5) {
281
+ // outputStr += `\n${concurrencyMsg}\n`
282
+ // }
283
+ let exitCode;
284
+ if (errors.length) {
285
+ exitCode = 1;
286
+ }
287
+ else if (failOnDiff) {
288
+ exitCode = !warnForUnsavedNewTests && passedOrNew.length && !unresolvedOrFailed.length ? 0 : 1;
289
+ }
290
+ else {
291
+ exitCode = 0;
292
+ }
293
+ return {
294
+ outputStr,
295
+ exitCode,
296
+ };
297
+ }
298
+ function testResultsOutput(results, warnForUnsavedNewTests) {
299
+ let outputStr = '';
300
+ const sortedTestResults = results.sort((a, b) => a.name.localeCompare(b.name));
301
+ sortedTestResults.forEach(result => {
302
+ const testTitle = `${result.name} [${result.hostApp}] [${result.hostDisplaySize.width}x${result.hostDisplaySize.height}] - `;
303
+ if (result.isAborted) {
304
+ outputStr += `${testTitle}${chalk_1.default.keyword('red')(`Aborted`)}\n`;
305
+ }
306
+ else if (result.isNew) {
307
+ const newResColor = warnForUnsavedNewTests ? 'orange' : 'blue';
308
+ outputStr += `${testTitle}${chalk_1.default.keyword(newResColor)('New')}\n`;
309
+ }
310
+ else if (result.status === 'Passed') {
311
+ outputStr += `${testTitle}${chalk_1.default.green('Passed')}\n`;
312
+ }
313
+ else if (result.status === 'Failed') {
314
+ outputStr += `${testTitle}${chalk_1.default.keyword('red')('Failed')}\n`;
315
+ }
316
+ else {
317
+ outputStr += `${testTitle}${chalk_1.default.keyword('orange')(`Unresolved`)}\n`;
318
+ }
319
+ });
320
+ outputStr += '\n';
321
+ return outputStr;
322
+ }
323
+ function formatEnvironment(environment) {
324
+ const env = environment.requested;
325
+ if (isChromeEmulation(env)) {
326
+ return `${env.chromeEmulationInfo.deviceName}${env.chromeEmulationInfo.screenOrientation ? ` [${env.chromeEmulationInfo.screenOrientation}]` : ''}`;
327
+ }
328
+ else if (isIOSDevice(env)) {
329
+ return `${env.iosDeviceInfo.deviceName}${env.iosDeviceInfo.screenOrientation ? ` [${env.iosDeviceInfo.screenOrientation}]` : ''}`;
330
+ }
331
+ else if (isAndroidDevice(env)) {
332
+ return `${env.androidDeviceInfo.deviceName}${env.androidDeviceInfo.screenOrientation ? ` [${env.androidDeviceInfo.screenOrientation}]` : ''}`;
333
+ }
334
+ else {
335
+ return `${env.name} [${env.width}x${env.height}]`;
336
+ }
337
+ function isChromeEmulation(env) {
338
+ return env.chromeEmulationInfo;
339
+ }
340
+ function isIOSDevice(env) {
341
+ return env.iosDeviceInfo;
342
+ }
343
+ function isAndroidDevice(env) {
344
+ return env.androidDeviceInfo;
345
+ }
346
+ }
package/dist/ufg/check.js CHANGED
@@ -28,29 +28,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.makeCheck = void 0;
30
30
  const driver_1 = require("@applitools/driver");
31
- const take_dom_snapshots_1 = require("./utils/take-dom-snapshots");
32
- const to_base_check_settings_1 = require("../automation/utils/to-base-check-settings");
33
- const to_generated_selectors_1 = require("./utils/to-generated-selectors");
34
31
  const uniquify_environments_1 = require("../automation/utils/uniquify-environments");
35
32
  const to_environment_key_1 = require("../automation/utils/to-environment-key");
36
33
  const abort_error_1 = require("../errors/abort-error");
37
34
  const utils = __importStar(require("@applitools/utils"));
38
35
  const lang = __importStar(require("../lang"));
39
36
  const chalk_1 = __importDefault(require("chalk"));
37
+ const take_snapshots_1 = require("./take-snapshots");
38
+ const create_render_target_from_snapshot_1 = require("./create-render-target-from-snapshot");
39
+ const to_base_check_settings_1 = require("../automation/utils/to-base-check-settings");
40
40
  function makeCheck({ eyes, target: defaultTarget, environments: defaultEnvironments = [], spec, signal, logger: mainLogger, }) {
41
41
  return async function check({ target = defaultTarget, settings = {}, logger = mainLogger, } = {}) {
42
- var _a, _b;
42
+ var _a;
43
43
  logger = logger.extend(mainLogger);
44
44
  logger.log('Command "check" is called with settings', settings);
45
45
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
46
46
  logger.warn('Command "check" was called after test was already aborted');
47
47
  throw new abort_error_1.AbortError('Command "check" was called after test was already aborted');
48
48
  }
49
- const { elementReferences, getBaseCheckSettings } = (0, to_base_check_settings_1.toBaseCheckSettings)({ settings });
50
- const { elementReferencesToMark, getGeneratedSelectors } = (0, to_generated_selectors_1.toGeneratedSelectors)({
51
- elementReferences,
52
- transformElementReference: elementReference => { var _a; return ((0, driver_1.isSelector)(elementReference) && ((_a = spec === null || spec === void 0 ? void 0 : spec.toSimpleCommonSelector) === null || _a === void 0 ? void 0 : _a.call(spec, elementReference))) || undefined; },
53
- });
54
49
  const uniqueEnvironments = (0, uniquify_environments_1.uniquifyEnvironments)((_a = settings.environments) !== null && _a !== void 0 ? _a : defaultEnvironments);
55
50
  const ufgClient = await eyes.core.getUFGClient({
56
51
  settings: {
@@ -61,66 +56,27 @@ function makeCheck({ eyes, target: defaultTarget, environments: defaultEnvironme
61
56
  logger,
62
57
  });
63
58
  let snapshots;
64
- let snapshotUrl;
65
- let snapshotTitle;
66
- let userAgent;
67
- const driver = spec && (0, driver_1.isDriver)(target, spec)
68
- ? await (0, driver_1.makeDriver)({ spec, driver: target, reset: target === defaultTarget, logger })
69
- : undefined;
70
- if (driver) {
71
- const environment = await driver.getEnvironment();
72
- const currentContext = driver.currentContext;
73
- await currentContext.setScrollingElement((_b = settings.scrollRootElement) !== null && _b !== void 0 ? _b : null);
74
- if (environment.isWeb) {
75
- userAgent = await driver.getUserAgentLegacy();
76
- snapshots = await (0, take_dom_snapshots_1.takeDomSnapshots)({
77
- driver,
78
- settings: {
79
- ...eyes.test.eyesServer,
80
- waitBeforeCapture: settings.waitBeforeCapture,
81
- disableBrowserFetching: settings.disableBrowserFetching,
82
- layoutBreakpoints: settings.layoutBreakpoints,
83
- environments: uniqueEnvironments,
84
- skipResources: ufgClient.getCachedResourceUrls(),
85
- lazyLoad: settings.lazyLoad,
86
- elementReferences: elementReferencesToMark,
87
- },
88
- provides: {
89
- getChromeEmulationDevices: ufgClient.getChromeEmulationDevices,
90
- getIOSDevices: ufgClient.getIOSDevices,
91
- },
92
- logger,
93
- });
94
- }
95
- else {
96
- const nmlClient = await eyes.core.getNMLClient({
97
- driver,
98
- settings: { ...eyes.test.eyesServer, supportedEnvironmentsUrl: eyes.test.supportedEnvironmentsUrl },
99
- logger,
100
- });
101
- snapshots = (await nmlClient.takeSnapshots({
102
- settings: {
103
- ...eyes.test.eyesServer,
104
- waitBeforeCapture: settings.waitBeforeCapture,
105
- environments: uniqueEnvironments,
106
- },
107
- logger,
108
- }));
109
- }
110
- await currentContext.focus();
111
- snapshotUrl = await driver.getUrl();
112
- snapshotTitle = await driver.getTitle();
59
+ let driver;
60
+ if (spec && (0, driver_1.isDriver)(target, spec)) {
61
+ const takeSnapshots = (0, take_snapshots_1.makeTakeSnapshots)({ core: eyes.core, spec, signal, logger });
62
+ driver = await (0, driver_1.makeDriver)({ spec, driver: target, logger });
63
+ snapshots = await takeSnapshots({
64
+ driver,
65
+ account: eyes.test.account,
66
+ settings: { ...settings, environments: uniqueEnvironments },
67
+ logger,
68
+ });
113
69
  }
114
70
  else {
71
+ // TODO (amit)
115
72
  snapshots = !utils.types.isArray(target) ? Array(uniqueEnvironments.length).fill(target) : target;
116
- snapshotUrl = utils.types.has(snapshots[0], 'url') ? snapshots[0].url : undefined;
117
73
  }
118
- const generatedSelectors = snapshots.map(snapshot => getGeneratedSelectors(utils.types.has(snapshot, 'generatedSelectors') ? snapshot.generatedSelectors : undefined));
119
- const promises = uniqueEnvironments.map(async (environment, index) => {
74
+ const promises = snapshots.map(async (snapshot, i) => {
120
75
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
121
76
  const environmentLogger = logger.extend({ tags: [`environment-${utils.general.shortid()}`] });
122
- const ufgEnvironment = environment;
123
- if (utils.types.has(ufgEnvironment, 'name') && ufgEnvironment.name === 'edge') {
77
+ const { target } = snapshot;
78
+ const environment = uniqueEnvironments[i];
79
+ if (utils.types.has(environment, 'name') && environment.name === 'edge') {
124
80
  environmentLogger.console.log(chalk_1.default.yellow(lang.edgeUfgEnvironmentDeprecatedWarning));
125
81
  }
126
82
  try {
@@ -128,26 +84,10 @@ function makeCheck({ eyes, target: defaultTarget, environments: defaultEnvironme
128
84
  environmentLogger.warn('Command "check" was aborted before rendering');
129
85
  throw new abort_error_1.AbortError('Command "check" was aborted before rendering');
130
86
  }
131
- const { cookies, ...snapshot } = snapshots[index];
132
- const selectors = generatedSelectors[index];
133
- if (utils.types.has(ufgEnvironment, 'iosDeviceInfo') || utils.types.has(ufgEnvironment, 'androidDeviceInfo')) {
134
- ufgEnvironment.type = utils.types.has(snapshot, 'cdt') ? 'web' : 'native';
87
+ if (utils.types.has(environment, 'iosDeviceInfo') || utils.types.has(environment, 'androidDeviceInfo')) {
88
+ environment.type = utils.types.has(target, 'cdt') ? 'web' : 'native';
135
89
  }
136
- const renderTargetPromise = ufgClient.createRenderTarget({
137
- snapshot,
138
- settings: {
139
- environment: ufgEnvironment,
140
- cookies,
141
- headers: {
142
- Referer: snapshotUrl,
143
- 'User-Agent': userAgent,
144
- ...settings.headers,
145
- },
146
- proxy: eyes.test.eyesServer.proxy,
147
- autProxy: settings.autProxy,
148
- },
149
- logger: environmentLogger,
150
- });
90
+ const renderTargetPromise = (0, create_render_target_from_snapshot_1.createRenderTargetFromSnapshot)({ ufgClient, snapshot, logger: environmentLogger });
151
91
  const baseEyes = await eyes.getBaseEyes({ settings: { environment, driver }, logger: environmentLogger });
152
92
  try {
153
93
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
@@ -167,31 +107,35 @@ function makeCheck({ eyes, target: defaultTarget, environments: defaultEnvironme
167
107
  environmentLogger.warn(`Render on environment with id "${(_c = baseEyes.test.environment) === null || _c === void 0 ? void 0 : _c.environmentId}" was aborted during one of the previous steps`);
168
108
  throw new abort_error_1.AbortError(`Render on environment with id "${(_d = baseEyes.test.environment) === null || _d === void 0 ? void 0 : _d.environmentId}" was aborted during one of the previous steps`);
169
109
  }
110
+ const { elementReferences: selectors, getBaseCheckSettings } = (0, to_base_check_settings_1.toBaseCheckSettings)({
111
+ settings: snapshot.settings,
112
+ });
170
113
  const { renderId, selectorRegions, ...baseTarget } = await ufgClient.render({
171
114
  target: renderTarget,
172
115
  settings: {
173
- ...settings,
174
- region: (_e = selectors.target) !== null && _e !== void 0 ? _e : settings.region,
116
+ ...snapshot.settings,
117
+ region: (_e = selectors.target) !== null && _e !== void 0 ? _e : snapshot.settings.region,
175
118
  scrollRootElement: selectors.scrolling,
176
- selectorsToCalculate: selectors.calculate.flatMap(({ safeSelector }) => safeSelector !== null && safeSelector !== void 0 ? safeSelector : []),
177
- includeFullPageSize: Boolean(settings.pageId),
178
- environment: { ...ufgEnvironment, environmentId: baseEyes.test.environment.environmentId },
119
+ selectorsToCalculate: selectors.calculate,
120
+ includeFullPageSize: Boolean(snapshot.settings.pageId),
121
+ environment: { ...environment, environmentId: baseEyes.test.environment.environmentId },
179
122
  uploadUrl: baseEyes.test.uploadUrl,
180
123
  stitchingServiceUrl: baseEyes.test.stitchingServiceUrl,
181
124
  },
182
125
  signal,
183
126
  logger: environmentLogger,
184
127
  });
185
- let offset = 0;
186
128
  const baseSettings = getBaseCheckSettings({
187
- calculatedRegions: selectors.calculate.map(({ originalSelector, safeSelector }) => ({
188
- selector: originalSelector !== null && originalSelector !== void 0 ? originalSelector : undefined,
189
- regions: safeSelector ? selectorRegions[offset++] : [],
190
- })),
129
+ calculatedRegions: selectors.calculate.map((_, index) => {
130
+ var _a;
131
+ return ({
132
+ regions: (_a = selectorRegions === null || selectorRegions === void 0 ? void 0 : selectorRegions[index]) !== null && _a !== void 0 ? _a : [],
133
+ });
134
+ }),
191
135
  });
192
136
  baseSettings.renderId = renderId;
193
- baseTarget.source = snapshotUrl;
194
- baseTarget.name = snapshotTitle;
137
+ baseTarget.source = snapshot.url;
138
+ baseTarget.name = snapshot.title;
195
139
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
196
140
  environmentLogger.warn('Command "check" was aborted after rendering');
197
141
  throw new abort_error_1.AbortError('Command "check" was aborted after rendering');
@@ -238,8 +182,8 @@ function makeCheck({ eyes, target: defaultTarget, environments: defaultEnvironme
238
182
  }
239
183
  }
240
184
  catch (error) {
241
- environmentLogger.error(`Environment with id ${ufgEnvironment.environmentId} failed before rendering started due to an error`, error);
242
- error.info = { ...error.info, userTestId: eyes.test.userTestId, environment: ufgEnvironment };
185
+ environmentLogger.error(`Environment with id ${environment.environmentId} failed before rendering started due to an error`, error);
186
+ error.info = { ...error.info, userTestId: eyes.test.userTestId, environment };
243
187
  throw error;
244
188
  }
245
189
  });
package/dist/ufg/core.js CHANGED
@@ -36,10 +36,11 @@ const take_snapshots_1 = require("./take-snapshots");
36
36
  const get_ufg_client_1 = require("./get-ufg-client");
37
37
  const open_eyes_1 = require("./open-eyes");
38
38
  const utils = __importStar(require("@applitools/utils"));
39
- function makeCore({ spec, clients, base: defaultBase, asyncCache, concurrency, fetchConcurrency, agentId = 'core-ufg', cwd = process.cwd(), logger: defaultLogger, }) {
39
+ function makeCore({ spec, clients, base: defaultBase, asyncCache, concurrency, offlineLocationPath, fetchConcurrency, agentId = 'core-ufg', cwd = process.cwd(), logger: defaultLogger, }) {
40
40
  const logger = (0, logger_1.makeLogger)({ logger: defaultLogger, format: { label: 'core-ufg' } });
41
41
  logger.log(`Core ufg is initialized ${defaultBase ? 'with' : 'without'} custom base core`);
42
- const base = defaultBase !== null && defaultBase !== void 0 ? defaultBase : (0, core_base_1.makeCore)({ agentId, concurrency, cwd, logger });
42
+ const base = defaultBase !== null && defaultBase !== void 0 ? defaultBase : (0, core_base_1.makeCore)({ agentId, concurrency, cwd, logger, offlineLocationPath });
43
+ const ufgClient = clients === null || clients === void 0 ? void 0 : clients.ufg;
43
44
  return utils.general.extend(base, core => {
44
45
  return {
45
46
  type: 'ufg',
@@ -50,7 +51,7 @@ function makeCore({ spec, clients, base: defaultBase, asyncCache, concurrency, f
50
51
  locate: (0, locate_1.makeLocate)({ spec, core, logger }),
51
52
  locateText: (0, locate_text_1.makeLocateText)({ spec, core, logger }),
52
53
  extractText: (0, extract_text_1.makeExtractText)({ spec, core, logger }),
53
- getUFGClient: (0, get_ufg_client_1.makeGetUFGClient)({ client: clients === null || clients === void 0 ? void 0 : clients.ufg, fetchConcurrency, asyncCache, logger }),
54
+ getUFGClient: (0, get_ufg_client_1.makeGetUFGClient)({ client: ufgClient, fetchConcurrency, asyncCache, offlineLocationPath, logger }),
54
55
  ...(0, get_nml_client_1.makeGetNMLClient)({ client: clients === null || clients === void 0 ? void 0 : clients.nml, logger }),
55
56
  openEyes: (0, open_eyes_1.makeOpenEyes)({ spec, core, logger }),
56
57
  };
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRenderTargetFromSnapshot = void 0;
4
+ async function createRenderTargetFromSnapshot({ ufgClient, snapshot, logger, }) {
5
+ return await ufgClient.createRenderTarget({
6
+ snapshot: snapshot.target,
7
+ settings: {
8
+ environment: snapshot.environment,
9
+ cookies: snapshot.target.cookies,
10
+ headers: {
11
+ Referer: snapshot.url,
12
+ 'User-Agent': snapshot.userAgent,
13
+ ...snapshot.settings.headers,
14
+ },
15
+ proxy: snapshot.account.eyesServer.proxy,
16
+ autProxy: snapshot.settings.autProxy,
17
+ },
18
+ logger,
19
+ });
20
+ }
21
+ exports.createRenderTargetFromSnapshot = createRenderTargetFromSnapshot;
@@ -26,7 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.makeGetUFGClient = void 0;
27
27
  const ufg_client_1 = require("@applitools/ufg-client");
28
28
  const utils = __importStar(require("@applitools/utils"));
29
- function makeGetUFGClient({ client, fetchConcurrency, logger: mainLogger, asyncCache }) {
29
+ function makeGetUFGClient({ client, fetchConcurrency, offlineLocationPath, logger: mainLogger, asyncCache, }) {
30
30
  // we are caching by the server config, therefor if the user creates another Runner / manager with the same server config but different
31
31
  // fetchConcurrency, it will not take any affect.
32
32
  const getUFGClientWithCache = utils.general.cachify(getUFGClient, ([options]) => client ? 'default' : [{ ...options.settings, fetchConcurrency: undefined }]);
@@ -39,7 +39,7 @@ function makeGetUFGClient({ client, fetchConcurrency, logger: mainLogger, asyncC
39
39
  ? utils.general.getEnvValue('TUNNEL_IDS')
40
40
  : undefined;
41
41
  return (0, ufg_client_1.makeUFGClient)({
42
- settings: { ...settings, fetchConcurrency, tunnelIds, asyncCache },
42
+ settings: { ...settings, fetchConcurrency, offlineLocationPath, tunnelIds, asyncCache },
43
43
  logger,
44
44
  });
45
45
  }
@@ -28,25 +28,23 @@ const driver_1 = require("@applitools/driver");
28
28
  const take_dom_snapshots_1 = require("./utils/take-dom-snapshots");
29
29
  const to_safe_check_settings_1 = require("./utils/to-safe-check-settings");
30
30
  const to_generated_selectors_1 = require("./utils/to-generated-selectors");
31
- const uniquify_environments_1 = require("../automation/utils/uniquify-environments");
32
31
  const abort_error_1 = require("../errors/abort-error");
33
32
  const utils = __importStar(require("@applitools/utils"));
34
33
  function makeTakeSnapshots({ core, spec, signal, logger: mainLogger }) {
35
- return async function takeSnapshots({ target, settings = {}, environments: defaultEnvironments = [], account, logger = mainLogger, }) {
36
- var _a, _b;
34
+ return async function takeSnapshots({ driver, settings = {}, account, logger = mainLogger, }) {
35
+ var _a;
37
36
  logger = logger.extend(mainLogger);
38
37
  logger.log('Command "takeSnapshots" is called with settings', settings);
39
38
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
40
39
  logger.warn('Command "takeSnapshots" was called after test was already aborted');
41
40
  throw new abort_error_1.AbortError('Command "takeSnapshots" was called after test was already aborted');
42
41
  }
43
- const uniqueEnvironments = (0, uniquify_environments_1.uniquifyEnvironments)((_a = settings.environments) !== null && _a !== void 0 ? _a : defaultEnvironments);
44
- const driver = spec && target ? await (0, driver_1.makeDriver)({ spec, driver: target, logger }) : null;
42
+ const uniqueEnvironments = settings.environments;
45
43
  if (!driver)
46
44
  throw new Error('Cannot create check snapshot without a driver');
47
45
  const environment = await driver.getEnvironment();
48
46
  const currentContext = driver.currentContext;
49
- await currentContext.setScrollingElement((_b = settings.scrollRootElement) !== null && _b !== void 0 ? _b : null);
47
+ await currentContext.setScrollingElement((_a = settings.scrollRootElement) !== null && _a !== void 0 ? _a : null);
50
48
  const { elementReferences, getSafeCheckSettings } = (0, to_safe_check_settings_1.toSafeCheckSettings)({ settings });
51
49
  const { elementReferencesToMark, getGeneratedSelectors } = (0, to_generated_selectors_1.toGeneratedSelectors)({
52
50
  elementReferences,
@@ -22,17 +22,21 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
25
28
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.makeLogEvent = void 0;
27
- const populate_eyes_server_settings_1 = require("./utils/populate-eyes-server-settings");
29
+ exports.ensureOfflineFolder = void 0;
30
+ const fs_1 = __importDefault(require("fs"));
31
+ const path_1 = __importDefault(require("path"));
28
32
  const utils = __importStar(require("@applitools/utils"));
29
- function makeLogEvent({ core, logger: mainLogger }) {
30
- return async function logEvent({ settings, logger = mainLogger, }) {
31
- logger = logger.extend(mainLogger, { tags: [`log-event-${utils.general.shortid()}`] });
32
- (utils.types.isArray(settings) ? settings : [settings]).forEach(settings => {
33
- (0, populate_eyes_server_settings_1.populateEyesServerSettings)(settings);
34
- });
35
- return core.base.logEvent({ settings, logger });
36
- };
33
+ function ensureOfflineFolder() {
34
+ const offlineLocationPath = utils.general.getEnvValue('OFFLINE_LOCATION_PATH')
35
+ ? path_1.default.resolve(utils.general.getEnvValue('OFFLINE_LOCATION_PATH'), `execution-${Date.now()}`)
36
+ : undefined;
37
+ if (offlineLocationPath) {
38
+ fs_1.default.mkdirSync(offlineLocationPath, { recursive: true });
39
+ }
40
+ return offlineLocationPath;
37
41
  }
38
- exports.makeLogEvent = makeLogEvent;
42
+ exports.ensureOfflineFolder = ensureOfflineFolder;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/core",
3
- "version": "4.19.0",
3
+ "version": "4.20.0",
4
4
  "homepage": "https://applitools.com",
5
5
  "bugs": {
6
6
  "url": "https://github.com/applitools/eyes.sdk.javascript1/issues"
@@ -74,11 +74,11 @@
74
74
  }
75
75
  },
76
76
  "dependencies": {
77
- "@applitools/core-base": "1.16.1",
77
+ "@applitools/core-base": "1.17.0",
78
78
  "@applitools/dom-capture": "11.5.0",
79
79
  "@applitools/dom-snapshot": "4.11.3",
80
80
  "@applitools/driver": "1.19.1",
81
- "@applitools/ec-client": "1.9.5",
81
+ "@applitools/ec-client": "1.9.6",
82
82
  "@applitools/logger": "2.0.18",
83
83
  "@applitools/nml-client": "1.8.11",
84
84
  "@applitools/req": "1.7.2",
@@ -86,13 +86,14 @@
86
86
  "@applitools/snippets": "2.5.0",
87
87
  "@applitools/socket": "1.1.18",
88
88
  "@applitools/spec-driver-webdriver": "1.1.13",
89
- "@applitools/ufg-client": "1.12.3",
89
+ "@applitools/ufg-client": "1.13.0",
90
90
  "@applitools/utils": "1.7.4",
91
91
  "@types/ws": "8.5.5",
92
92
  "abort-controller": "3.0.0",
93
93
  "chalk": "4.1.2",
94
94
  "node-fetch": "2.6.7",
95
95
  "semver": "7.6.2",
96
+ "tar": "7.4.3",
96
97
  "webdriver": "7.31.1",
97
98
  "ws": "8.17.1",
98
99
  "yargs": "17.7.2"
@@ -1,5 +1,5 @@
1
1
  import type { Core as UFGCore } from '../ufg/types';
2
- import type { Snapshot, RenderTarget } from './types';
2
+ import type { Snapshot, RenderTargetWithSettings } from './types';
3
3
  import { type Logger } from '@applitools/logger';
4
4
  type Options = {
5
5
  core: UFGCore<any>;
@@ -8,5 +8,5 @@ type Options = {
8
8
  export declare function makeCreateRenderTarget({ core, logger: defaultLogger }: Options): ({ snapshot, logger, }: {
9
9
  snapshot: Snapshot;
10
10
  logger: Logger;
11
- }) => Promise<RenderTarget>;
11
+ }) => Promise<RenderTargetWithSettings>;
12
12
  export {};
@@ -1,12 +1,12 @@
1
1
  import type { Core as UFGCore } from '../ufg/types';
2
- import type { RenderTarget, StartedRender } from './types';
2
+ import type { RenderTargetWithSettings, StartedRender } from './types';
3
3
  import { type Logger } from '@applitools/logger';
4
4
  type Options = {
5
5
  core: UFGCore<any>;
6
6
  logger: Logger;
7
7
  };
8
8
  export declare function makeStartRenders({ core, logger: defaultLogger }: Options): ({ targets, logger, }: {
9
- targets: RenderTarget[];
9
+ targets: RenderTargetWithSettings[];
10
10
  logger: Logger;
11
11
  }) => Promise<StartedRender[]>;
12
12
  export {};
@@ -1,12 +1,13 @@
1
1
  import type { Core as UFGCore } from '../ufg/types';
2
2
  import type { DriverTarget, SnapshotSettings, Snapshot } from './types';
3
3
  import { type Logger } from '@applitools/logger';
4
- import { type SpecType } from '@applitools/driver';
4
+ import { type SpecDriver, type SpecType } from '@applitools/driver';
5
5
  type Options<TSpec extends SpecType> = {
6
6
  core: UFGCore<TSpec>;
7
+ spec: SpecDriver<TSpec>;
7
8
  logger: Logger;
8
9
  };
9
- export declare function makeTakeSnapshots<TSpec extends SpecType>({ core, logger: defaultLogger }: Options<TSpec>): ({ target, settings, logger, }: {
10
+ export declare function makeTakeSnapshots<TSpec extends SpecType>({ core, spec, logger: defaultLogger }: Options<TSpec>): ({ target, settings, logger, }: {
10
11
  target: DriverTarget<TSpec>;
11
12
  settings: SnapshotSettings<TSpec>;
12
13
  logger?: Logger | undefined;
@@ -2,7 +2,7 @@ import type { Eyes as BaseEyes, ImageTarget as BaseImageTarget, OpenSettings as
2
2
  import type * as UFGCore from '../ufg/types';
3
3
  import { type Logger } from '@applitools/logger';
4
4
  import { type SpecType } from '@applitools/driver';
5
- import { type RenderTarget as UFGRenderTarget, type StartedRender as UFGStartedRender } from '@applitools/ufg-client';
5
+ import { type RenderTarget, type StartedRender as UFGStartedRender } from '@applitools/ufg-client';
6
6
  export * from '../ufg/types';
7
7
  export interface AutonomousCore<TSpec extends SpecType> {
8
8
  readonly type: 'autonomous';
@@ -14,9 +14,9 @@ export interface AutonomousCore<TSpec extends SpecType> {
14
14
  createRenderTarget(options: {
15
15
  snapshot: UFGCore.Snapshot;
16
16
  logger?: Logger;
17
- }): Promise<RenderTarget>;
17
+ }): Promise<RenderTargetWithSettings>;
18
18
  startRenders(options: {
19
- targets: RenderTarget[];
19
+ targets: RenderTargetWithSettings[];
20
20
  logger?: Logger;
21
21
  }): Promise<StartedRender[]>;
22
22
  getRenderResults(options: {
@@ -34,8 +34,8 @@ export interface AutonomousCore<TSpec extends SpecType> {
34
34
  }): Promise<BaseEyes>;
35
35
  }
36
36
  export type SnapshotSettings<TSpec extends SpecType> = UFGCore.SnapshotSettings<TSpec> & UFGCore.EyesServerSettings;
37
- export type RenderTarget = {
38
- target: UFGRenderTarget;
37
+ export type RenderTargetWithSettings = {
38
+ target: RenderTarget;
39
39
  settings: UFGCore.SafeCheckSettings;
40
40
  environment: UFGCore.RenderEnvironment;
41
41
  account: UFGCore.Account;
@@ -13,6 +13,7 @@ type Options<TSpec extends SpecType> = {
13
13
  agentId?: string;
14
14
  cwd?: string;
15
15
  logger?: Logger;
16
+ offlineLocationPath?: string;
16
17
  };
17
- export declare function makeCore<TSpec extends SpecType>({ spec, clients, base: defaultBase, concurrency, agentId, cwd, logger: defaultLogger, }: Options<TSpec>): Core<TSpec>;
18
+ export declare function makeCore<TSpec extends SpecType>({ spec, clients, base: defaultBase, concurrency, agentId, cwd, logger: defaultLogger, offlineLocationPath, }: Options<TSpec>): Core<TSpec>;
18
19
  export {};
@@ -17,8 +17,9 @@ type Options<TSpec extends SpecType> = {
17
17
  cwd?: string;
18
18
  logger: Logger;
19
19
  asyncCache?: AsyncCache;
20
+ offlineLocationPath?: string;
20
21
  };
21
- export declare function makeMakeManager<TSpec extends SpecType>({ spec, clients, core, base: defaultBase, agentId: defaultAgentId, environment, cwd, logger: mainLogger, asyncCache, }: Options<TSpec>): <TType extends "classic" | "ufg" = "classic">({ type, settings, logger, }?: {
22
+ export declare function makeMakeManager<TSpec extends SpecType>({ spec, clients, core, base: defaultBase, agentId: defaultAgentId, environment, cwd, logger: mainLogger, asyncCache, offlineLocationPath, }: Options<TSpec>): <TType extends "classic" | "ufg" = "classic">({ type, settings, logger, }?: {
22
23
  type?: TType | undefined;
23
24
  settings?: ManagerSettings | undefined;
24
25
  logger?: Logger | undefined;
@@ -0,0 +1,5 @@
1
+ import { type EyesServerSettings } from './types';
2
+ export type OfflineSnapshotsSettings = EyesServerSettings & {
3
+ offlineLocationPath: string;
4
+ };
5
+ export declare function runOfflineSnapshots(options: OfflineSnapshotsSettings): Promise<void>;
@@ -17,6 +17,7 @@ type Options<TSpec extends SpecType> = {
17
17
  agentId?: string;
18
18
  cwd?: string;
19
19
  logger?: Logger;
20
+ offlineLocationPath?: string;
20
21
  };
21
- export declare function makeCore<TSpec extends SpecType>({ spec, clients, base: defaultBase, asyncCache, concurrency, fetchConcurrency, agentId, cwd, logger: defaultLogger, }: Options<TSpec>): Core<TSpec>;
22
+ export declare function makeCore<TSpec extends SpecType>({ spec, clients, base: defaultBase, asyncCache, concurrency, offlineLocationPath, fetchConcurrency, agentId, cwd, logger: defaultLogger, }: Options<TSpec>): Core<TSpec>;
22
23
  export {};
@@ -0,0 +1,8 @@
1
+ import { UFGClient, RenderTarget } from '@applitools/ufg-client';
2
+ import { Snapshot } from './types';
3
+ import { Logger } from '@applitools/logger';
4
+ export declare function createRenderTargetFromSnapshot({ ufgClient, snapshot, logger, }: {
5
+ ufgClient: UFGClient;
6
+ snapshot: Snapshot;
7
+ logger: Logger;
8
+ }): Promise<RenderTarget>;
@@ -5,8 +5,9 @@ type Options = {
5
5
  fetchConcurrency?: number;
6
6
  logger: Logger;
7
7
  asyncCache?: AsyncCache;
8
+ offlineLocationPath?: string;
8
9
  };
9
- export declare function makeGetUFGClient({ client, fetchConcurrency, logger: mainLogger, asyncCache }: Options): (({ settings, logger }: {
10
+ export declare function makeGetUFGClient({ client, fetchConcurrency, offlineLocationPath, logger: mainLogger, asyncCache, }: Options): (({ settings, logger }: {
10
11
  settings: UFGClientSettings;
11
12
  logger?: Logger | undefined;
12
13
  }) => Promise<UFGClient>) & {
@@ -1,18 +1,16 @@
1
- import type { DriverTarget, Core, SnapshotSettings, Account, Snapshot } from './types';
2
- import { type Environment as UFGEnvironment } from '@applitools/ufg-client';
1
+ import type { Core, SnapshotSettings, Account, Snapshot } from './types';
3
2
  import { type AbortSignal } from 'abort-controller';
4
3
  import { type Logger } from '@applitools/logger';
5
- import { type SpecType, type SpecDriver } from '@applitools/driver';
4
+ import { type SpecType, type SpecDriver, type Driver } from '@applitools/driver';
6
5
  type Options<TSpec extends SpecType> = {
7
6
  core: Core<TSpec>;
8
7
  spec: SpecDriver<TSpec>;
9
8
  signal?: AbortSignal;
10
9
  logger: Logger;
11
10
  };
12
- export declare function makeTakeSnapshots<TSpec extends SpecType>({ core, spec, signal, logger: mainLogger }: Options<TSpec>): ({ target, settings, environments: defaultEnvironments, account, logger, }: {
13
- target: DriverTarget<TSpec>;
11
+ export declare function makeTakeSnapshots<TSpec extends SpecType>({ core, spec, signal, logger: mainLogger }: Options<TSpec>): ({ driver, settings, account, logger, }: {
12
+ driver: Driver<TSpec>;
14
13
  settings?: SnapshotSettings<TSpec> | undefined;
15
- environments?: UFGEnvironment[] | undefined;
16
14
  account: Account;
17
15
  logger?: Logger | undefined;
18
16
  }) => Promise<Snapshot[]>;
@@ -1,6 +1,6 @@
1
1
  import type { MaybeArray } from '@applitools/utils';
2
2
  import type * as AutomationCore from '../automation/types';
3
- import { type SpecType, type CommonSelector } from '@applitools/driver';
3
+ import { type SpecType, type CommonSelector, type Driver } from '@applitools/driver';
4
4
  import { type Logger } from '@applitools/logger';
5
5
  import { type Proxy } from '@applitools/req';
6
6
  import { type UFGClient, type UFGClientSettings, type Selector as UFGSelector, type Environment as UFGEnvironment, type DomSnapshot as UFGDomSnapshot, type AndroidSnapshot as UFGAndroidSnapshot, type IOSSnapshot as UFGIOSSnapshot } from '@applitools/ufg-client';
@@ -13,7 +13,7 @@ export type DomSnapshot = UFGDomSnapshot & {
13
13
  };
14
14
  export type AndroidSnapshot = UFGAndroidSnapshot;
15
15
  export type IOSSnapshot = UFGIOSSnapshot;
16
- export type SnapshotTarget = MaybeArray<DomSnapshot> | MaybeArray<AndroidSnapshot> | MaybeArray<IOSSnapshot>;
16
+ export type SnapshotTarget = MaybeArray<Snapshot>;
17
17
  export type Target<TSpec extends SpecType> = SnapshotTarget | AutomationCore.Target<TSpec>;
18
18
  export interface Core<TSpec extends SpecType> extends AutomationCore.Core<TSpec> {
19
19
  readonly type: 'ufg';
@@ -22,7 +22,7 @@ export interface Core<TSpec extends SpecType> extends AutomationCore.Core<TSpec>
22
22
  logger?: Logger;
23
23
  }): Promise<UFGClient>;
24
24
  takeSnapshots?(options: {
25
- target: AutomationCore.DriverTarget<TSpec>;
25
+ driver: Driver<TSpec>;
26
26
  settings?: SnapshotSettings<TSpec>;
27
27
  account: AutomationCore.Account;
28
28
  logger?: Logger;
@@ -0,0 +1 @@
1
+ export declare function ensureOfflineFolder(): string | undefined;
@@ -1,12 +0,0 @@
1
- import type { MaybeArray } from '@applitools/utils';
2
- import type { Core, LogEventSettings } from './types';
3
- import { type Logger } from '@applitools/logger';
4
- type Options = {
5
- core: Core<any>;
6
- logger: Logger;
7
- };
8
- export declare function makeLogEvent({ core, logger: mainLogger }: Options): ({ settings, logger, }: {
9
- settings: MaybeArray<LogEventSettings>;
10
- logger?: Logger | undefined;
11
- }) => Promise<void>;
12
- export {};