@applitools/core 4.18.2 → 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 +69 -0
- package/dist/autonomous/core.js +1 -1
- package/dist/autonomous/create-render-target.js +2 -15
- package/dist/autonomous/take-snapshots.js +6 -2
- package/dist/classic/core.js +2 -2
- package/dist/classic/utils/take-dom-capture.js +1 -0
- package/dist/cli/cli.js +20 -0
- package/dist/core.js +6 -3
- package/dist/make-manager.js +4 -3
- package/dist/open-eyes.js +61 -1
- package/dist/run-offline-snapshots.js +346 -0
- package/dist/ufg/check.js +40 -96
- package/dist/ufg/core.js +4 -3
- package/dist/ufg/create-render-target-from-snapshot.js +21 -0
- package/dist/ufg/get-ufg-client.js +2 -2
- package/dist/ufg/take-snapshots.js +4 -6
- package/dist/ufg/utils/generate-safe-selectors.js +18 -18
- package/dist/ufg/utils/take-dom-snapshots.js +13 -14
- package/dist/{log-event.js → utils/ensure-offline-folder.js} +15 -11
- package/package.json +13 -12
- package/types/autonomous/create-render-target.d.ts +2 -2
- package/types/autonomous/start-renders.d.ts +2 -2
- package/types/autonomous/take-snapshots.d.ts +3 -2
- package/types/autonomous/types.d.ts +5 -5
- package/types/classic/core.d.ts +2 -1
- package/types/classic/utils/take-dom-capture.d.ts +8 -0
- package/types/make-manager.d.ts +2 -1
- package/types/run-offline-snapshots.d.ts +5 -0
- package/types/ufg/core.d.ts +2 -1
- package/types/ufg/create-render-target-from-snapshot.d.ts +8 -0
- package/types/ufg/get-ufg-client.d.ts +2 -1
- package/types/ufg/take-snapshots.d.ts +4 -6
- package/types/ufg/types.d.ts +3 -3
- package/types/ufg/utils/generate-safe-selectors.d.ts +18 -12
- package/types/utils/ensure-offline-folder.d.ts +1 -0
- package/types/log-event.d.ts +0 -12
|
@@ -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
|
|
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
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
|
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
|
|
123
|
-
|
|
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
|
-
|
|
132
|
-
|
|
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 =
|
|
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
|
|
177
|
-
includeFullPageSize: Boolean(settings.pageId),
|
|
178
|
-
environment: { ...
|
|
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((
|
|
188
|
-
|
|
189
|
-
|
|
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 =
|
|
194
|
-
baseTarget.name =
|
|
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 ${
|
|
242
|
-
error.info = { ...error.info, userTestId: eyes.test.userTestId, environment
|
|
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:
|
|
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({
|
|
36
|
-
var _a
|
|
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 =
|
|
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((
|
|
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,
|