@applitools/eyes-cypress 3.28.3 → 3.29.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 +6 -0
- package/README.md +28 -2
- package/dist/browser/spec-driver.js +0 -8
- package/dist/expose.js +7 -0
- package/dist/plugin/concurrencyMsg.js +9 -0
- package/dist/plugin/config.js +66 -0
- package/dist/plugin/configParams.js +47 -0
- package/dist/plugin/errorDigest.js +74 -0
- package/dist/plugin/getErrorsAndDiffs.js +31 -0
- package/dist/plugin/handleTestResults.js +38 -0
- package/dist/plugin/hooks.js +43 -0
- package/dist/plugin/index.js +17 -0
- package/dist/plugin/isGlobalHooksSupported.js +10 -0
- package/dist/plugin/pluginExport.js +104 -0
- package/dist/plugin/server.js +117 -0
- package/dist/plugin/webSocket.js +129 -0
- package/index.js +3 -2
- package/package.json +37 -18
- package/src/browser/spec-driver.ts +1 -1
- package/src/expose.ts +71 -0
- package/src/plugin/{concurrencyMsg.js → concurrencyMsg.ts} +1 -1
- package/src/plugin/{config.js → config.ts} +6 -15
- package/src/plugin/{configParams.js → configParams.ts} +1 -3
- package/src/plugin/{errorDigest.js → errorDigest.ts} +34 -38
- package/src/plugin/{getErrorsAndDiffs.js → getErrorsAndDiffs.ts} +3 -8
- package/src/plugin/{handleTestResults.js → handleTestResults.ts} +17 -12
- package/src/plugin/hooks.ts +60 -0
- package/src/plugin/index.ts +37 -0
- package/src/plugin/isGlobalHooksSupported.ts +11 -0
- package/src/plugin/pluginExport.ts +118 -0
- package/src/plugin/{server.js → server.ts} +30 -33
- package/src/plugin/{webSocket.js → webSocket.ts} +34 -23
- package/src/setup/handlePlugin.js +21 -2
- package/src/setup/isPluginDefinedESM.js +5 -0
- package/index.d.ts +0 -86
- package/src/plugin/defaultPort.js +0 -1
- package/src/plugin/hooks.js +0 -41
- package/src/plugin/isGlobalHooksSupported.js +0 -13
- package/src/plugin/pluginExport.js +0 -94
- package/src/plugin/startPlugin.js +0 -15
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const ws_1 = __importDefault(require("ws"));
|
|
7
|
+
const uuid_1 = require("uuid");
|
|
8
|
+
function connectSocket(url) {
|
|
9
|
+
const socket = new ws_1.default(url);
|
|
10
|
+
let passthroughListener;
|
|
11
|
+
const listeners = new Map();
|
|
12
|
+
const queue = new Set();
|
|
13
|
+
let isReady = false;
|
|
14
|
+
attach();
|
|
15
|
+
function attach() {
|
|
16
|
+
if (socket.readyState === ws_1.default.CONNECTING)
|
|
17
|
+
socket.on('open', () => attach());
|
|
18
|
+
else if (socket.readyState === ws_1.default.OPEN) {
|
|
19
|
+
isReady = true;
|
|
20
|
+
queue.forEach((command) => command());
|
|
21
|
+
queue.clear();
|
|
22
|
+
socket.on('message', message => {
|
|
23
|
+
const { name, key, payload } = deserialize(message);
|
|
24
|
+
const fns = listeners.get(name);
|
|
25
|
+
const keyListeners = key && listeners.get(`${name}/${key}`);
|
|
26
|
+
if (fns)
|
|
27
|
+
fns.forEach(fn => fn(payload, key));
|
|
28
|
+
if (keyListeners)
|
|
29
|
+
keyListeners.forEach(fn => fn(payload, key));
|
|
30
|
+
if (!fns && !keyListeners && passthroughListener) {
|
|
31
|
+
passthroughListener(message);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function disconnect() {
|
|
37
|
+
if (!socket)
|
|
38
|
+
return;
|
|
39
|
+
socket.terminate();
|
|
40
|
+
isReady = false;
|
|
41
|
+
passthroughListener = null;
|
|
42
|
+
queue.clear();
|
|
43
|
+
}
|
|
44
|
+
function setPassthroughListener(fn) {
|
|
45
|
+
passthroughListener = fn;
|
|
46
|
+
}
|
|
47
|
+
function send(message) {
|
|
48
|
+
const command = () => socket.send(message);
|
|
49
|
+
if (isReady)
|
|
50
|
+
command();
|
|
51
|
+
else
|
|
52
|
+
queue.add(command);
|
|
53
|
+
return () => queue.delete(command);
|
|
54
|
+
}
|
|
55
|
+
function on(type, fn) {
|
|
56
|
+
const name = typeof type === 'string' ? type : `${type.name}/${type.key}`;
|
|
57
|
+
let fns = listeners.get(name);
|
|
58
|
+
if (!fns) {
|
|
59
|
+
fns = new Set();
|
|
60
|
+
listeners.set(name, fns);
|
|
61
|
+
}
|
|
62
|
+
fns.add(fn);
|
|
63
|
+
return () => off(name, fn);
|
|
64
|
+
}
|
|
65
|
+
function once(type, fn) {
|
|
66
|
+
const off = on(type, (...args) => (fn(...args), off()));
|
|
67
|
+
return off;
|
|
68
|
+
}
|
|
69
|
+
function off(name, fn) {
|
|
70
|
+
if (!fn)
|
|
71
|
+
return listeners.delete(name);
|
|
72
|
+
const fns = listeners.get(name);
|
|
73
|
+
if (!fns)
|
|
74
|
+
return false;
|
|
75
|
+
const existed = fns.delete(fn);
|
|
76
|
+
if (!fns.size)
|
|
77
|
+
listeners.delete(name);
|
|
78
|
+
return existed;
|
|
79
|
+
}
|
|
80
|
+
function emit(type, payload) {
|
|
81
|
+
return send(serialize(type, payload));
|
|
82
|
+
}
|
|
83
|
+
function request(name, payload) {
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
const key = (0, uuid_1.v4)();
|
|
86
|
+
emit({ name, key }, payload);
|
|
87
|
+
once({ name, key }, (response) => {
|
|
88
|
+
if (response.error)
|
|
89
|
+
return reject(response.error);
|
|
90
|
+
return resolve(response.result);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function ref() {
|
|
95
|
+
const command = () => socket._socket.ref();
|
|
96
|
+
if (isReady)
|
|
97
|
+
command();
|
|
98
|
+
else
|
|
99
|
+
queue.add(command);
|
|
100
|
+
return () => queue.delete(command);
|
|
101
|
+
}
|
|
102
|
+
function unref() {
|
|
103
|
+
const command = () => socket._socket.unref();
|
|
104
|
+
if (isReady)
|
|
105
|
+
command();
|
|
106
|
+
else
|
|
107
|
+
queue.add(command);
|
|
108
|
+
return () => queue.delete(command);
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
setPassthroughListener,
|
|
112
|
+
send,
|
|
113
|
+
on,
|
|
114
|
+
once,
|
|
115
|
+
off,
|
|
116
|
+
request,
|
|
117
|
+
disconnect,
|
|
118
|
+
ref,
|
|
119
|
+
unref,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
exports.default = connectSocket;
|
|
123
|
+
function serialize(type, payload) {
|
|
124
|
+
const message = typeof type === 'string' ? { name: type, payload } : { name: type.name, key: type.key, payload };
|
|
125
|
+
return JSON.stringify(message);
|
|
126
|
+
}
|
|
127
|
+
function deserialize(message) {
|
|
128
|
+
return JSON.parse(message);
|
|
129
|
+
}
|
package/index.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
module.exports =
|
|
1
|
+
const expose = require('./dist/expose')
|
|
2
|
+
module.exports = expose.default
|
|
3
|
+
Object.defineProperty(module.exports, 'default', {value: expose.default})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applitools/eyes-cypress",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.29.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git://github.com/applitools/eyes.sdk.javascript1.git",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"cypress",
|
|
12
12
|
"cy"
|
|
13
13
|
],
|
|
14
|
-
"main": "index.js",
|
|
15
|
-
"types": "./index.d.ts",
|
|
14
|
+
"main": "./index.js",
|
|
15
|
+
"types": "./types/index.d.ts",
|
|
16
16
|
"bin": {
|
|
17
17
|
"eyes-setup": "./bin/eyes-setup.js"
|
|
18
18
|
},
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"index.d.ts"
|
|
26
26
|
],
|
|
27
27
|
"scripts": {
|
|
28
|
-
"lint": "eslint \"**/*.js\"",
|
|
29
|
-
"build": "
|
|
28
|
+
"lint": "eslint \"**/*.{js,ts}\"",
|
|
29
|
+
"build": "ttsc",
|
|
30
30
|
"generate:tests": "coverage-tests generate",
|
|
31
31
|
"test": "yarn test:unit && yarn test:it && yarn test:e2e && yarn test:ts && yarn test:components && yarn test:coverage",
|
|
32
32
|
"test:sanity": "yarn test:unit && yarn test:it && yarn test:ts",
|
|
@@ -34,7 +34,16 @@
|
|
|
34
34
|
"test:it": "yarn build && mocha --no-timeouts 'test/it/**/*.test.js'",
|
|
35
35
|
"test:ts": "yarn test:ts:compile && yarn test:ts:run",
|
|
36
36
|
"test:ts:compile": "tsc --project test/e2e/ts/cypress",
|
|
37
|
-
"test:ts:run": "
|
|
37
|
+
"test:ts:run:legacy": "yarn cypress9 run --config-file ./test/e2e/ts/cypress-ts-legacy.json",
|
|
38
|
+
"cypress9": "./node_modules/cypress9/bin/cypress",
|
|
39
|
+
"test:ts:run:9": "yarn cypress9 run --project ./test/e2e/ts --config-file ./cypress-9.config.ts",
|
|
40
|
+
"cypress10": "./node_modules/cypress10/bin/cypress",
|
|
41
|
+
"test:ts:run:10": "yarn cypress10 run --project ./test/e2e/ts --config-file ./cypress-10.config.ts",
|
|
42
|
+
"cypress11": "./node_modules/cypress11/bin/cypress",
|
|
43
|
+
"test:ts:run:11": "yarn cypress11 run --project ./test/e2e/ts --config-file ./cypress-11.config.ts",
|
|
44
|
+
"cypress12": "./node_modules/cypress12/bin/cypress",
|
|
45
|
+
"test:ts:run:12": "yarn cypress12 run --project ./test/e2e/ts --config-file ./cypress-12.config.ts",
|
|
46
|
+
"test:ts:run": "yarn test:ts:run:legacy && yarn test:ts:run:9",
|
|
38
47
|
"test:coverage": "yarn generate:tests && cd test/coverage/generic && yarn && unset APPLITOOLS_API_KEY && APPLITOOLS_BATCH_NAME='JS Coverage Tests: eyes-cypress' APPLITOOLS_BATCH_ID=$(uuidgen) npx cypress run",
|
|
39
48
|
"test:e2e": "mkdir -p test/fixtures/testAppCopies && mocha --no-timeouts 'test/e2e/**/*.test.js'",
|
|
40
49
|
"test:components": "cd test/components && yarn && npx cypress run --component",
|
|
@@ -56,11 +65,13 @@
|
|
|
56
65
|
}
|
|
57
66
|
},
|
|
58
67
|
"dependencies": {
|
|
59
|
-
"@applitools/core": "1.4.
|
|
60
|
-
"@applitools/eyes-api": "1.
|
|
68
|
+
"@applitools/core": "1.4.6",
|
|
69
|
+
"@applitools/eyes-api": "1.13.1",
|
|
61
70
|
"@applitools/eyes-universal": "2.18.0",
|
|
62
71
|
"@applitools/functional-commons": "1.6.0",
|
|
63
|
-
"@applitools/logger": "1.1.
|
|
72
|
+
"@applitools/logger": "1.1.43",
|
|
73
|
+
"@applitools/utils": "1.3.28",
|
|
74
|
+
"boxen": "5.1.2",
|
|
64
75
|
"chalk": "3.0.0",
|
|
65
76
|
"semver": "7.3.8",
|
|
66
77
|
"uuid": "8.3.2",
|
|
@@ -68,26 +79,32 @@
|
|
|
68
79
|
"ws": "8.5.0"
|
|
69
80
|
},
|
|
70
81
|
"devDependencies": {
|
|
82
|
+
"@applitools/api-extractor": "^1.2.11",
|
|
71
83
|
"@applitools/bongo": "^2.2.2",
|
|
72
84
|
"@applitools/scripts": "1.2.0",
|
|
73
|
-
"@applitools/sdk-coverage-tests": "^2.7.
|
|
85
|
+
"@applitools/sdk-coverage-tests": "^2.7.8",
|
|
74
86
|
"@applitools/snaptdout": "1.0.1",
|
|
75
|
-
"@applitools/test-server": "1.1.
|
|
76
|
-
"@applitools/test-utils": "1.5.
|
|
77
|
-
"@applitools/utils": "1.3.26",
|
|
87
|
+
"@applitools/test-server": "1.1.22",
|
|
88
|
+
"@applitools/test-utils": "1.5.11",
|
|
78
89
|
"@types/node": "12",
|
|
90
|
+
"@types/semver": "^7.3.13",
|
|
91
|
+
"@types/uuid": "^9.0.0",
|
|
79
92
|
"@types/which": "^2.0.1",
|
|
80
93
|
"@types/ws": "^8.2.2",
|
|
81
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
82
|
-
"@typescript-eslint/parser": "^5.
|
|
94
|
+
"@typescript-eslint/eslint-plugin": "^5.47.1",
|
|
95
|
+
"@typescript-eslint/parser": "^5.47.1",
|
|
83
96
|
"chai": "4.2.0",
|
|
84
97
|
"chai-spies": "1.0.0",
|
|
85
98
|
"cookie-parser": "1.4.4",
|
|
86
99
|
"cypress": "9.7.0",
|
|
100
|
+
"cypress10": "npm:cypress@^10.0.0",
|
|
101
|
+
"cypress11": "npm:cypress@^11.0.0",
|
|
102
|
+
"cypress12": "npm:cypress@^12.0.0",
|
|
103
|
+
"cypress9": "npm:cypress@^9.0.0",
|
|
87
104
|
"eslint": "8.10.0",
|
|
88
105
|
"eslint-config-prettier": "^8.5.0",
|
|
89
106
|
"eslint-plugin-mocha-no-only": "1.1.0",
|
|
90
|
-
"eslint-plugin-no-only-tests": "^3.
|
|
107
|
+
"eslint-plugin-no-only-tests": "^3.1.0",
|
|
91
108
|
"eslint-plugin-node": "^11.1.0",
|
|
92
109
|
"eslint-plugin-prettier": "^4.0.0",
|
|
93
110
|
"husky": "4.3.8",
|
|
@@ -97,9 +114,11 @@
|
|
|
97
114
|
"ncp": "2.0.0",
|
|
98
115
|
"node-fetch": "2.6.0",
|
|
99
116
|
"prettier": "^2.6.2",
|
|
100
|
-
"
|
|
117
|
+
"ttypescript": "^1.5.13",
|
|
118
|
+
"typescript": "^4.7.2"
|
|
101
119
|
},
|
|
102
120
|
"engines": {
|
|
103
121
|
"node": ">=12.13.0"
|
|
104
|
-
}
|
|
122
|
+
},
|
|
123
|
+
"xvfb": true
|
|
105
124
|
}
|
|
@@ -37,7 +37,7 @@ export function childContext(_context: Context, element: HTMLIFrameElement): Con
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
export function getViewportSize():
|
|
40
|
+
export function getViewportSize(): {width: number; height: number} {
|
|
41
41
|
//@ts-ignore
|
|
42
42
|
const currWindow = cy.state('window')
|
|
43
43
|
const viewportSize = {
|
package/src/expose.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The types here are compiled via `ttsc` and `api-extractor`, and are used to describe the inputs to
|
|
3
|
+
* Eyes-Cypress custom commands. The reason they are not written in the `index.d.ts` file next to the
|
|
4
|
+
* `declare global { namespace Cypress {...}}` statement is that `api-extractor` has a limitation (at
|
|
5
|
+
* the time of writing this) that drops the `declare global` statement. So it's important to not pass
|
|
6
|
+
* `index.d.ts` through `api-extractor`,but keep the types in this file go through it, to produce the
|
|
7
|
+
* correct types for the SDK just like all other conventional SDK's.
|
|
8
|
+
**/
|
|
9
|
+
/// <reference types="cypress" />
|
|
10
|
+
import type * as api from '@applitools/eyes-api'
|
|
11
|
+
import {type EyesSelector, type TestResultsStatus} from '@applitools/eyes-api'
|
|
12
|
+
|
|
13
|
+
export type {EyesSelector, TestResultsStatus}
|
|
14
|
+
|
|
15
|
+
type MaybeArray<T> = T | T[]
|
|
16
|
+
|
|
17
|
+
type LegacyRegion = {left: number; top: number; width: number; height: number}
|
|
18
|
+
type Selector = {selector: string; type?: 'css' | 'xpath'; nodeType?: 'element' | 'shadow-root'} | 'string'
|
|
19
|
+
type Element = HTMLElement | JQuery<HTMLElement>
|
|
20
|
+
type ElementWithOptions = {element: Element; regionId?: string; padding?: any}
|
|
21
|
+
|
|
22
|
+
export type CypressCheckSettings = api.CheckSettingsAutomationPlain<Element, Selector> & {
|
|
23
|
+
tag?: CypressCheckSettings['name']
|
|
24
|
+
|
|
25
|
+
target?: 'window' | 'region'
|
|
26
|
+
selector?: Selector
|
|
27
|
+
element?: Element
|
|
28
|
+
|
|
29
|
+
ignore?: MaybeArray<NonNullable<CypressCheckSettings['ignoreRegions']>[number] | LegacyRegion | ElementWithOptions>
|
|
30
|
+
layout?: MaybeArray<NonNullable<CypressCheckSettings['layoutRegions']>[number] | LegacyRegion | ElementWithOptions>
|
|
31
|
+
content?: MaybeArray<NonNullable<CypressCheckSettings['contentRegions']>[number] | LegacyRegion | ElementWithOptions>
|
|
32
|
+
strict?: MaybeArray<NonNullable<CypressCheckSettings['strictRegions']>[number] | LegacyRegion | ElementWithOptions>
|
|
33
|
+
floating?: MaybeArray<
|
|
34
|
+
| NonNullable<CypressCheckSettings['floatingRegions']>[number]
|
|
35
|
+
| ((ElementWithOptions | Selector | LegacyRegion) & {
|
|
36
|
+
maxUpOffset?: number
|
|
37
|
+
maxDownOffset?: number
|
|
38
|
+
maxLeftOffset?: number
|
|
39
|
+
maxRightOffset?: number
|
|
40
|
+
})
|
|
41
|
+
>
|
|
42
|
+
accessibility?: MaybeArray<
|
|
43
|
+
| NonNullable<CypressCheckSettings['accessibilityRegions']>[number]
|
|
44
|
+
| ((ElementWithOptions | Selector | LegacyRegion) & {accessibilityType?: api.AccessibilityRegionTypePlain})
|
|
45
|
+
>
|
|
46
|
+
scriptHooks?: CypressCheckSettings['hooks']
|
|
47
|
+
ignoreCaret?: boolean
|
|
48
|
+
ignoreDisplacements?: boolean
|
|
49
|
+
}
|
|
50
|
+
export type CypressEyesConfig = api.ConfigurationPlain<Element, Selector> & {
|
|
51
|
+
browser?: MaybeArray<
|
|
52
|
+
| NonNullable<CypressEyesConfig['browsersInfo']>[number]
|
|
53
|
+
| {deviceName: string; screenOrientation?: api.ScreenOrientationPlain; name?: string}
|
|
54
|
+
>
|
|
55
|
+
|
|
56
|
+
batchId?: NonNullable<CypressEyesConfig['batch']>['id']
|
|
57
|
+
batchName?: NonNullable<CypressEyesConfig['batch']>['name']
|
|
58
|
+
batchSequence?: NonNullable<CypressEyesConfig['batch']>['sequenceName']
|
|
59
|
+
notifyOnCompletion?: NonNullable<CypressEyesConfig['batch']>['notifyOnCompletion']
|
|
60
|
+
|
|
61
|
+
envName?: CypressEyesConfig['environmentName']
|
|
62
|
+
|
|
63
|
+
accessibilitySettings?: NonNullable<CypressEyesConfig['defaultMatchSettings']>['accessibilitySettings']
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type CypressTestResultsSummary = api.TestResultsSummary
|
|
67
|
+
|
|
68
|
+
export {type EyesPluginConfig} from './plugin'
|
|
69
|
+
|
|
70
|
+
import plugin from './plugin'
|
|
71
|
+
export default plugin
|
|
@@ -5,4 +5,4 @@ Important notice: Your Applitools visual tests are currently running with a test
|
|
|
5
5
|
This means that only up to 5 visual tests can run in parallel, and therefore the execution might be slower.
|
|
6
6
|
If your Applitools license supports a higher concurrency level, learn how to configure it here: https://www.npmjs.com/package/@applitools/eyes-cypress#concurrency.
|
|
7
7
|
Need a higher concurrency in your account? Email us @ sdr@applitools.com with your required concurrency level.`
|
|
8
|
-
|
|
8
|
+
export default {concurrencyMsg: chalk.yellow(MSG), msgText: MSG}
|
|
@@ -1,19 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const {configParams} = require('./configParams')
|
|
1
|
+
import * as utils from '@applitools/utils'
|
|
2
|
+
import configParams from './configParams'
|
|
4
3
|
const DEFAULT_TEST_CONCURRENCY = 5
|
|
5
|
-
|
|
4
|
+
import * as uuid from 'uuid'
|
|
5
|
+
import {type EyesPluginConfig} from './'
|
|
6
6
|
|
|
7
|
-
function makeConfig() {
|
|
7
|
+
export default function makeConfig(): {config: any; eyesConfig: EyesPluginConfig} {
|
|
8
8
|
const config = utils.config.getConfig({
|
|
9
|
-
params: [
|
|
10
|
-
...configParams,
|
|
11
|
-
'failCypressOnDiff',
|
|
12
|
-
'tapDirPath',
|
|
13
|
-
'tapFileName',
|
|
14
|
-
'disableBrowserFetching',
|
|
15
|
-
'testConcurrency',
|
|
16
|
-
],
|
|
9
|
+
params: [...configParams, 'failCypressOnDiff', 'tapDirPath', 'tapFileName', 'disableBrowserFetching', 'testConcurrency'],
|
|
17
10
|
})
|
|
18
11
|
|
|
19
12
|
if ((!config.batch || !config.batch.id) && !config.batchId) {
|
|
@@ -51,5 +44,3 @@ function makeConfig() {
|
|
|
51
44
|
|
|
52
45
|
return {config, eyesConfig}
|
|
53
46
|
}
|
|
54
|
-
|
|
55
|
-
module.exports = makeConfig
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
'
|
|
2
|
-
|
|
1
|
+
type Color = 'reset' | 'green' | 'red' | 'teal' | 'orange'
|
|
3
2
|
const colors = {
|
|
4
3
|
green: '\x1b[32m',
|
|
5
4
|
red: '\x1b[31m',
|
|
@@ -7,26 +6,48 @@ const colors = {
|
|
|
7
6
|
orange: '\x1b[38;5;214m',
|
|
8
7
|
reset: '\x1b[0m',
|
|
9
8
|
}
|
|
10
|
-
|
|
11
|
-
const formatByStatus = {
|
|
9
|
+
const formatByStatus: Record<string, {color: Color; symbol: string; title: (tests: number) => string}> = {
|
|
12
10
|
Passed: {
|
|
13
11
|
color: 'green',
|
|
14
12
|
symbol: '\u2713',
|
|
15
|
-
title: tests => `Passed - ${tests} tests`,
|
|
13
|
+
title: (tests: number) => `Passed - ${tests} tests`,
|
|
16
14
|
},
|
|
17
15
|
Failed: {
|
|
18
16
|
color: 'red',
|
|
19
17
|
symbol: '\u2716',
|
|
20
|
-
title: tests => `Errors - ${tests} tests`,
|
|
18
|
+
title: (tests: number) => `Errors - ${tests} tests`,
|
|
21
19
|
},
|
|
22
20
|
Unresolved: {
|
|
23
21
|
color: 'orange',
|
|
24
22
|
symbol: '\u26A0',
|
|
25
|
-
title: tests => `Diffs detected - ${tests} tests`,
|
|
23
|
+
title: (tests: number) => `Diffs detected - ${tests} tests`,
|
|
26
24
|
},
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
function
|
|
27
|
+
function stringifyTestResults(testResults: any) {
|
|
28
|
+
const hostDisplaySize = testResults.hostDisplaySize
|
|
29
|
+
const viewport = hostDisplaySize ? `[${hostDisplaySize.width}x${hostDisplaySize.height}]` : ''
|
|
30
|
+
const testName = `${testResults.name} ${viewport}`
|
|
31
|
+
return testName + (testResults.error ? ` : ${testResults.error}` : '')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function testResultsSection(title: string, results: any) {
|
|
35
|
+
return results.length ? `${indent()}${title}${indent(3)}${results.join(indent(3))}` : ''
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function stringifyError(testResults: any) {
|
|
39
|
+
return testResults.error ? stringifyTestResults(testResults) : `[Eyes test not started] : ${testResults}`
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function indent(spaces = 2) {
|
|
43
|
+
return `\n ${' '.repeat(spaces)}`
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function hasError(testResult: any) {
|
|
47
|
+
return testResult.error || testResult instanceof Error
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default function errorDigest({passed, failed, diffs, logger, isInteractive}: any) {
|
|
30
51
|
logger.log('errorDigest: diff errors', diffs)
|
|
31
52
|
logger.log('errorDigest: test errors', failed)
|
|
32
53
|
|
|
@@ -43,9 +64,9 @@ function errorDigest({passed, failed, diffs, logger, isInteractive}) {
|
|
|
43
64
|
'\n\n'
|
|
44
65
|
)
|
|
45
66
|
|
|
46
|
-
function testResultsToString(testResultsArr, category) {
|
|
47
|
-
const {color, title, symbol
|
|
48
|
-
const results = testResultsArr.reduce((acc, testResults) => {
|
|
67
|
+
function testResultsToString(testResultsArr: any, category: 'Passed' | 'Failed' | 'Unresolved') {
|
|
68
|
+
const {color, title, symbol} = formatByStatus[category]
|
|
69
|
+
const results = testResultsArr.reduce((acc: any, testResults: any) => {
|
|
49
70
|
if (!testResults.isEmpty) {
|
|
50
71
|
const error = hasError(testResults) ? stringifyError(testResults) : undefined
|
|
51
72
|
acc.push(`${colorify(symbol, color)} ${colorify(error || stringifyTestResults(testResults))}`)
|
|
@@ -53,36 +74,11 @@ function errorDigest({passed, failed, diffs, logger, isInteractive}) {
|
|
|
53
74
|
return acc
|
|
54
75
|
}, [])
|
|
55
76
|
|
|
56
|
-
const coloredTitle = results.length ? colorify(title(results.length), color
|
|
77
|
+
const coloredTitle = results.length ? colorify(title(results.length), color) : ''
|
|
57
78
|
return testResultsSection(coloredTitle, results)
|
|
58
79
|
}
|
|
59
80
|
|
|
60
|
-
function colorify(msg, color = 'reset') {
|
|
81
|
+
function colorify(msg: any, color: Color = 'reset') {
|
|
61
82
|
return isInteractive ? msg : `${colors[color]}${msg}${colors.reset}`
|
|
62
83
|
}
|
|
63
84
|
}
|
|
64
|
-
|
|
65
|
-
function stringifyTestResults(testResults) {
|
|
66
|
-
const hostDisplaySize = testResults.hostDisplaySize
|
|
67
|
-
const viewport = hostDisplaySize ? `[${hostDisplaySize.width}x${hostDisplaySize.height}]` : ''
|
|
68
|
-
const testName = `${testResults.name} ${viewport}`
|
|
69
|
-
return testName + (testResults.error ? ` : ${testResults.error}` : '')
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function testResultsSection(title, results) {
|
|
73
|
-
return results.length ? `${indent()}${title}${indent(3)}${results.join(indent(3))}` : ''
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function stringifyError(testResults) {
|
|
77
|
-
return testResults.error ? stringifyTestResults(testResults) : `[Eyes test not started] : ${testResults}`
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function indent(spaces = 2) {
|
|
81
|
-
return `\n ${' '.repeat(spaces)}`
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function hasError(testResult) {
|
|
85
|
-
return testResult.error || testResult instanceof Error
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
module.exports = errorDigest
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
function getErrorsAndDiffs(testResultsArr) {
|
|
1
|
+
export default function getErrorsAndDiffs(testResultsArr: any) {
|
|
3
2
|
return testResultsArr.reduce(
|
|
4
|
-
({failed, diffs, passed}, testResults) => {
|
|
3
|
+
({failed, diffs, passed}: any, testResults: any) => {
|
|
5
4
|
if (testResults instanceof Error || testResults.error) {
|
|
6
5
|
failed.push(testResults)
|
|
7
6
|
} else {
|
|
@@ -11,9 +10,7 @@ function getErrorsAndDiffs(testResultsArr) {
|
|
|
11
10
|
} else {
|
|
12
11
|
if (testStatus === 'Unresolved') {
|
|
13
12
|
if (testResults.isNew) {
|
|
14
|
-
testResults.error = new Error(
|
|
15
|
-
`${testResults.name}. Please approve the new baseline at ${testResults.url}`,
|
|
16
|
-
)
|
|
13
|
+
testResults.error = new Error(`${testResults.name}. Please approve the new baseline at ${testResults.url}`)
|
|
17
14
|
failed.push(testResults)
|
|
18
15
|
} else {
|
|
19
16
|
diffs.push(testResults)
|
|
@@ -29,5 +26,3 @@ function getErrorsAndDiffs(testResultsArr) {
|
|
|
29
26
|
{failed: [], diffs: [], passed: []},
|
|
30
27
|
)
|
|
31
28
|
}
|
|
32
|
-
|
|
33
|
-
module.exports = getErrorsAndDiffs
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const {formatters} = require('@applitools/core')
|
|
8
|
-
const {resolve} = require('path')
|
|
1
|
+
import errorDigest from './errorDigest'
|
|
2
|
+
import {makeLogger} from '@applitools/logger'
|
|
3
|
+
import getErrorsAndDiffs from './getErrorsAndDiffs'
|
|
4
|
+
import fs from 'fs'
|
|
5
|
+
import {formatters} from '@applitools/core'
|
|
6
|
+
import {resolve} from 'path'
|
|
9
7
|
|
|
10
|
-
function printTestResults(testResultsArr) {
|
|
8
|
+
function printTestResults(testResultsArr: any) {
|
|
11
9
|
const logger = makeLogger({
|
|
12
10
|
level: testResultsArr.resultConfig.showLogs ? 'info' : 'silent',
|
|
13
11
|
label: 'eyes',
|
|
@@ -26,10 +24,17 @@ function printTestResults(testResultsArr) {
|
|
|
26
24
|
)
|
|
27
25
|
}
|
|
28
26
|
}
|
|
29
|
-
function handleBatchResultsFile(results, tapFileConfig) {
|
|
27
|
+
function handleBatchResultsFile(results: any, tapFileConfig: any) {
|
|
30
28
|
const fileName = tapFileConfig.tapFileName || `${new Date().toISOString()}-eyes.tap`
|
|
31
29
|
const tapFile = resolve(tapFileConfig.tapDirPath, fileName)
|
|
32
|
-
return writeFile(
|
|
30
|
+
return fs.writeFile(
|
|
31
|
+
tapFile,
|
|
32
|
+
formatters.toHierarchicTAPString(results, {includeSubTests: false, markNewAsPassed: true}),
|
|
33
|
+
{},
|
|
34
|
+
(err: any) => {
|
|
35
|
+
if (err) throw err
|
|
36
|
+
},
|
|
37
|
+
)
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
export default {printTestResults, handleBatchResultsFile}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import handleTestResults from './handleTestResults'
|
|
2
|
+
export type EyesCypressAction = 'before:run' | 'after:run'
|
|
3
|
+
|
|
4
|
+
declare global {
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
6
|
+
namespace Cypress {
|
|
7
|
+
interface ResolvedConfigOptions {
|
|
8
|
+
appliConfFile: {
|
|
9
|
+
dontCloseBatches: boolean
|
|
10
|
+
batch: any
|
|
11
|
+
serverUrl: string
|
|
12
|
+
proxy: string
|
|
13
|
+
apiKey: string
|
|
14
|
+
batchId: string
|
|
15
|
+
tapDirPath: string
|
|
16
|
+
tapFileName: string
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default function makeGlobalRunHooks({closeManager, closeBatches, closeUniversalServer}: any): {
|
|
23
|
+
'after:run': (results: CypressCommandLine.CypressRunResult) => void | Promise<void>
|
|
24
|
+
'before:run': (runDetails: Cypress.BeforeRunDetails) => void | Promise<void>
|
|
25
|
+
} {
|
|
26
|
+
return {
|
|
27
|
+
'before:run': ({config}: Cypress.BeforeRunDetails): void => {
|
|
28
|
+
if (!(config as Cypress.Config).isTextTerminal) return
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
'after:run': async ({config}: CypressCommandLine.CypressRunResult) => {
|
|
32
|
+
try {
|
|
33
|
+
if (!(config as Cypress.Config).isTextTerminal) return
|
|
34
|
+
const summaries = await closeManager()
|
|
35
|
+
|
|
36
|
+
let testResults
|
|
37
|
+
for (const summary of summaries) {
|
|
38
|
+
testResults = summary.results.map(({testResults}: any) => testResults)
|
|
39
|
+
}
|
|
40
|
+
if (!config.appliConfFile.dontCloseBatches) {
|
|
41
|
+
await closeBatches({
|
|
42
|
+
batchIds: [config.appliConfFile.batchId || config.appliConfFile.batch.id],
|
|
43
|
+
serverUrl: config.appliConfFile.serverUrl,
|
|
44
|
+
proxy: config.appliConfFile.proxy,
|
|
45
|
+
apiKey: config.appliConfFile.apiKey,
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (config.appliConfFile.tapDirPath) {
|
|
50
|
+
await handleTestResults.handleBatchResultsFile(testResults, {
|
|
51
|
+
tapDirPath: config.appliConfFile.tapDirPath,
|
|
52
|
+
tapFileName: config.appliConfFile.tapFileName,
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
} finally {
|
|
56
|
+
await closeUniversalServer()
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
import makePluginExport from './pluginExport'
|
|
3
|
+
import makeConfig from './config'
|
|
4
|
+
import makeStartServer from './server'
|
|
5
|
+
import {makeLogger} from '@applitools/logger'
|
|
6
|
+
|
|
7
|
+
// DON'T REMOVE
|
|
8
|
+
//
|
|
9
|
+
// if remove the `ttsc` will compile the absolute path
|
|
10
|
+
//
|
|
11
|
+
// the absolute path is added because api-extractor goes over the `eyesPlugin`
|
|
12
|
+
// declaration before it goes over the `EyesConfig` definition, and this is why
|
|
13
|
+
// it's important to reverse the order
|
|
14
|
+
export type EyesPluginConfig = {
|
|
15
|
+
tapDirPath: string
|
|
16
|
+
tapFileName: string
|
|
17
|
+
eyesIsDisabled: boolean
|
|
18
|
+
eyesBrowser: any
|
|
19
|
+
eyesLayoutBreakpoints: any
|
|
20
|
+
eyesFailCypressOnDiff: boolean
|
|
21
|
+
eyesDisableBrowserFetching: boolean
|
|
22
|
+
eyesTestConcurrency: number
|
|
23
|
+
eyesWaitBeforeCapture: number
|
|
24
|
+
eyesPort?: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const {config, eyesConfig} = makeConfig()
|
|
28
|
+
const logger = makeLogger({level: config.showLogs ? 'info' : 'silent', label: 'eyes'})
|
|
29
|
+
|
|
30
|
+
const startServer = makeStartServer({logger})
|
|
31
|
+
|
|
32
|
+
const pluginExport = makePluginExport({
|
|
33
|
+
startServer,
|
|
34
|
+
eyesConfig: Object.assign({}, eyesConfig, {appliConfFile: config}),
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
export default pluginExport
|