@applitools/core 4.62.0 → 4.63.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +225 -0
- package/dist/automation/get-nml-client.js +21 -15
- package/dist/check.js +16 -7
- package/dist/classic/utils/extract-default-environments.js +2 -2
- package/dist/open-eyes.js +1 -1
- package/dist/ufg/check.js +1 -0
- package/dist/ufg/create-render-target-from-snapshot.js +1 -0
- package/dist/ufg/utils/media-playback-guard.js +382 -0
- package/dist/ufg/utils/take-dom-snapshots.js +7 -0
- package/package.json +26 -20
- package/types/automation/get-nml-client.d.ts +1 -1
- package/types/automation/types.d.ts +1 -1
- package/types/ufg/utils/media-playback-guard.d.ts +67 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,230 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [4.63.1](https://github.com/Applitools-Dev/sdk/compare/js/core@4.63.0...js/core@4.63.1) (2026-05-26)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* prevent BrightCove/video.js player corruption during layoutBreakpoints snapshots ([#3828](https://github.com/Applitools-Dev/sdk/issues/3828)) ([380fbae](https://github.com/Applitools-Dev/sdk/commit/380fbaeb1c6a964c640975f1a109417db51f691c))
|
|
9
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
10
|
+
* truly disable NML broker URL cache between checks | FLD-4283 ([#3837](https://github.com/Applitools-Dev/sdk/issues/3837)) ([da76dd3](https://github.com/Applitools-Dev/sdk/commit/da76dd3227c3297320be0d19558a7437b5733999))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Dependencies
|
|
14
|
+
|
|
15
|
+
* @applitools/utils bumped to 1.14.5
|
|
16
|
+
#### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
19
|
+
* @applitools/logger bumped to 2.2.12
|
|
20
|
+
#### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
* @applitools/dom-shared bumped to 1.2.1
|
|
27
|
+
#### Bug Fixes
|
|
28
|
+
|
|
29
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
30
|
+
* @applitools/dom-snapshot bumped to 4.17.2
|
|
31
|
+
#### Bug Fixes
|
|
32
|
+
|
|
33
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
* @applitools/socket bumped to 1.3.13
|
|
38
|
+
#### Bug Fixes
|
|
39
|
+
|
|
40
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
* @applitools/req bumped to 1.10.2
|
|
45
|
+
#### Bug Fixes
|
|
46
|
+
|
|
47
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
* @applitools/image bumped to 1.2.11
|
|
52
|
+
#### Bug Fixes
|
|
53
|
+
|
|
54
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
* @applitools/snippets bumped to 2.9.2
|
|
59
|
+
#### Bug Fixes
|
|
60
|
+
|
|
61
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
* @applitools/dom-capture bumped to 11.8.1
|
|
66
|
+
#### Bug Fixes
|
|
67
|
+
|
|
68
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
* @applitools/driver bumped to 1.26.2
|
|
73
|
+
#### Bug Fixes
|
|
74
|
+
|
|
75
|
+
* redact cookie values from logs to prevent sensitive data exposure | AD-12834 ([#3835](https://github.com/Applitools-Dev/sdk/issues/3835)) ([d883647](https://github.com/Applitools-Dev/sdk/commit/d883647d8e007467bd2770ddb79f89be057067b9))
|
|
76
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
* @applitools/spec-driver-webdriver bumped to 1.6.2
|
|
81
|
+
#### Bug Fixes
|
|
82
|
+
|
|
83
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
* @applitools/spec-driver-selenium bumped to 1.8.2
|
|
88
|
+
#### Bug Fixes
|
|
89
|
+
|
|
90
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
* @applitools/spec-driver-playwright bumped to 1.9.2
|
|
95
|
+
#### Bug Fixes
|
|
96
|
+
|
|
97
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
* @applitools/spec-driver-puppeteer bumped to 1.8.2
|
|
102
|
+
#### Bug Fixes
|
|
103
|
+
|
|
104
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
* @applitools/screenshoter bumped to 3.12.21
|
|
109
|
+
#### Bug Fixes
|
|
110
|
+
|
|
111
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
* @applitools/nml-client bumped to 1.11.28
|
|
116
|
+
#### Bug Fixes
|
|
117
|
+
|
|
118
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
* @applitools/tunnel-client bumped to 1.11.14
|
|
123
|
+
#### Bug Fixes
|
|
124
|
+
|
|
125
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
* @applitools/ufg-client bumped to 1.22.2
|
|
130
|
+
#### Bug Fixes
|
|
131
|
+
|
|
132
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
133
|
+
* strip extra fields from checkResources log output ([#3836](https://github.com/Applitools-Dev/sdk/issues/3836)) ([6d75209](https://github.com/Applitools-Dev/sdk/commit/6d752094abb6fcc0e998cf95e1f266964dbfd6f3))
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
* @applitools/core-base bumped to 1.34.1
|
|
138
|
+
#### Bug Fixes
|
|
139
|
+
|
|
140
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
* @applitools/ec-client bumped to 1.12.30
|
|
145
|
+
#### Bug Fixes
|
|
146
|
+
|
|
147
|
+
* strip .d.ts extension from import() type specifiers | FLD-4429 ([#3830](https://github.com/Applitools-Dev/sdk/issues/3830)) ([37aac45](https://github.com/Applitools-Dev/sdk/commit/37aac45958b713702bea87c144623dd3e65fce79))
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
* @applitools/test-server bumped to 1.4.4
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
## [4.63.0](https://github.com/Applitools-Dev/sdk/compare/js/core@4.62.0...js/core@4.63.0) (2026-05-19)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
### Features
|
|
158
|
+
|
|
159
|
+
* soft-deprecate CheckSettings.timeout() with telemetry [[#3705](https://github.com/Applitools-Dev/sdk/issues/3705)] ([#3805](https://github.com/Applitools-Dev/sdk/issues/3805)) ([a5d6390](https://github.com/Applitools-Dev/sdk/commit/a5d6390f17fc0380736b88cbe05dd147e66a86cf))
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
### Bug Fixes
|
|
163
|
+
|
|
164
|
+
* avoid double-scaling environment viewport in classic mode | FLD-4359 ([#3793](https://github.com/Applitools-Dev/sdk/issues/3793)) ([246050b](https://github.com/Applitools-Dev/sdk/commit/246050b8a7984b869c068262162a69191c834947))
|
|
165
|
+
* http2 support via settings AD 13119 ([#3804](https://github.com/Applitools-Dev/sdk/issues/3804)) ([759d451](https://github.com/Applitools-Dev/sdk/commit/759d4518254828140aa50e2c5de14e80af0b997c))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
### Dependencies
|
|
169
|
+
|
|
170
|
+
* @applitools/snippets bumped to 2.9.1
|
|
171
|
+
#### Bug Fixes
|
|
172
|
+
|
|
173
|
+
* declare @babel/preset-typescript dep for sandbox build ([#3815](https://github.com/Applitools-Dev/sdk/issues/3815)) ([10c44c6](https://github.com/Applitools-Dev/sdk/commit/10c44c66635f1ed4e0361f22ecebf2221c2cc912))
|
|
174
|
+
* @applitools/dom-snapshot bumped to 4.17.1
|
|
175
|
+
|
|
176
|
+
* @applitools/req bumped to 1.10.1
|
|
177
|
+
#### Bug Fixes
|
|
178
|
+
|
|
179
|
+
* http2 support via settings AD 13119 ([#3804](https://github.com/Applitools-Dev/sdk/issues/3804)) ([759d451](https://github.com/Applitools-Dev/sdk/commit/759d4518254828140aa50e2c5de14e80af0b997c))
|
|
180
|
+
* @applitools/driver bumped to 1.26.1
|
|
181
|
+
#### Bug Fixes
|
|
182
|
+
|
|
183
|
+
* address CI regressions from executeBrowserCommands and Chromium 140+ service worker ([#3848](https://github.com/Applitools-Dev/sdk/issues/3848)) ([099ada5](https://github.com/Applitools-Dev/sdk/commit/099ada5e52d4153157b98c2203df428579527e49))
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
* @applitools/spec-driver-playwright bumped to 1.9.1
|
|
188
|
+
#### Bug Fixes
|
|
189
|
+
|
|
190
|
+
* address CI regressions from executeBrowserCommands and Chromium 140+ service worker ([#3848](https://github.com/Applitools-Dev/sdk/issues/3848)) ([099ada5](https://github.com/Applitools-Dev/sdk/commit/099ada5e52d4153157b98c2203df428579527e49))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
* @applitools/ufg-client bumped to 1.22.1
|
|
195
|
+
#### Bug Fixes
|
|
196
|
+
|
|
197
|
+
* http2 support via settings AD 13119 ([#3804](https://github.com/Applitools-Dev/sdk/issues/3804)) ([759d451](https://github.com/Applitools-Dev/sdk/commit/759d4518254828140aa50e2c5de14e80af0b997c))
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
* @applitools/spec-driver-webdriver bumped to 1.6.1
|
|
202
|
+
|
|
203
|
+
* @applitools/spec-driver-selenium bumped to 1.8.1
|
|
204
|
+
|
|
205
|
+
* @applitools/spec-driver-puppeteer bumped to 1.8.1
|
|
206
|
+
|
|
207
|
+
* @applitools/screenshoter bumped to 3.12.20
|
|
208
|
+
|
|
209
|
+
* @applitools/nml-client bumped to 1.11.27
|
|
210
|
+
|
|
211
|
+
* @applitools/tunnel-client bumped to 1.11.13
|
|
212
|
+
|
|
213
|
+
* @applitools/core-base bumped to 1.34.0
|
|
214
|
+
#### Features
|
|
215
|
+
|
|
216
|
+
* soft-deprecate CheckSettings.timeout() with telemetry [[#3705](https://github.com/Applitools-Dev/sdk/issues/3705)] ([#3805](https://github.com/Applitools-Dev/sdk/issues/3805)) ([a5d6390](https://github.com/Applitools-Dev/sdk/commit/a5d6390f17fc0380736b88cbe05dd147e66a86cf))
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
#### Bug Fixes
|
|
220
|
+
|
|
221
|
+
* http2 support via settings AD 13119 ([#3804](https://github.com/Applitools-Dev/sdk/issues/3804)) ([759d451](https://github.com/Applitools-Dev/sdk/commit/759d4518254828140aa50e2c5de14e80af0b997c))
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
* @applitools/ec-client bumped to 1.12.29
|
|
226
|
+
|
|
227
|
+
|
|
3
228
|
## [4.62.0](https://github.com/Applitools-Dev/sdk/compare/js/core@4.61.1...js/core@4.62.0) (2026-05-05)
|
|
4
229
|
|
|
5
230
|
|
|
@@ -4,15 +4,17 @@ exports.makeGetNMLClient = exports.clearNMLClients = void 0;
|
|
|
4
4
|
const nml_client_1 = require("@applitools/nml-client");
|
|
5
5
|
const utils_1 = require("@applitools/utils");
|
|
6
6
|
const clients = new Map();
|
|
7
|
+
const cacheDisabled = new Set();
|
|
7
8
|
// for tests
|
|
8
9
|
function clearNMLClients() {
|
|
9
10
|
clients.clear();
|
|
11
|
+
cacheDisabled.clear();
|
|
10
12
|
}
|
|
11
13
|
exports.clearNMLClients = clearNMLClients;
|
|
12
14
|
function makeGetNMLClient({ client, logger: mainLogger }) {
|
|
13
15
|
return {
|
|
14
16
|
getNMLClient,
|
|
15
|
-
|
|
17
|
+
disableNMLClientCache,
|
|
16
18
|
};
|
|
17
19
|
async function getNMLClient({ driver, settings, logger, }) {
|
|
18
20
|
if (client)
|
|
@@ -20,26 +22,30 @@ function makeGetNMLClient({ client, logger: mainLogger }) {
|
|
|
20
22
|
logger = logger.extend(mainLogger);
|
|
21
23
|
const { sessionId } = await driver.getDriverInfo();
|
|
22
24
|
const cacheKey = sessionId !== null && sessionId !== void 0 ? sessionId : driver.guid;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return clientFromCache;
|
|
25
|
+
if (cacheDisabled.has(cacheKey)) {
|
|
26
|
+
logger.log('NML broker url cache is disabled for this session — re-extracting broker url');
|
|
26
27
|
}
|
|
27
28
|
else {
|
|
28
|
-
const
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
const clientFromCache = clients.get(cacheKey);
|
|
30
|
+
if (clientFromCache)
|
|
31
|
+
return clientFromCache;
|
|
32
|
+
}
|
|
33
|
+
const brokerUrl = await driver.extractBrokerUrl();
|
|
34
|
+
if (!brokerUrl)
|
|
35
|
+
throw new Error('Unable to extract broker url from the device');
|
|
36
|
+
if (utils_1.types.has(brokerUrl, 'error')) {
|
|
37
|
+
logger.error('Broker url extraction has failed with error', brokerUrl.error);
|
|
38
|
+
throw new Error(brokerUrl.error);
|
|
38
39
|
}
|
|
40
|
+
const nmlClient = (0, nml_client_1.makeNMLClient)({ settings: { brokerUrl, ...settings }, logger });
|
|
41
|
+
if (!cacheDisabled.has(cacheKey))
|
|
42
|
+
clients.set(cacheKey, nmlClient);
|
|
43
|
+
return nmlClient;
|
|
39
44
|
}
|
|
40
|
-
async function
|
|
45
|
+
async function disableNMLClientCache(driver) {
|
|
41
46
|
const { sessionId } = await driver.getDriverInfo();
|
|
42
47
|
const cacheKey = sessionId !== null && sessionId !== void 0 ? sessionId : driver.guid;
|
|
48
|
+
cacheDisabled.add(cacheKey);
|
|
43
49
|
clients.delete(cacheKey);
|
|
44
50
|
}
|
|
45
51
|
}
|
package/dist/check.js
CHANGED
|
@@ -35,8 +35,8 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
35
35
|
function makeCheck({ type: defaultType = 'classic', eyes, target: defaultTarget, spec, logger: mainLogger, }) {
|
|
36
36
|
let stepIndex = 0;
|
|
37
37
|
return async function check({ type = defaultType, target = defaultTarget, settings, config, logger = mainLogger, } = {}) {
|
|
38
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
39
|
-
var
|
|
38
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
39
|
+
var _s, _t, _u, _v, _w;
|
|
40
40
|
logger = logger.extend(mainLogger, { tags: [`check-${type}-${utils.general.shortid()}`] });
|
|
41
41
|
settings = { ...config === null || config === void 0 ? void 0 : config.screenshot, ...config === null || config === void 0 ? void 0 : config.check, ...settings };
|
|
42
42
|
(_a = settings.fully) !== null && _a !== void 0 ? _a : (settings.fully = !settings.region && (!settings.frames || settings.frames.length === 0));
|
|
@@ -56,23 +56,32 @@ function makeCheck({ type: defaultType = 'classic', eyes, target: defaultTarget,
|
|
|
56
56
|
!utils.types.isEmpty(settings.accessibilitySettings));
|
|
57
57
|
(_h = settings.autProxy) !== null && _h !== void 0 ? _h : (settings.autProxy = eyes.test.eyesServer.proxy);
|
|
58
58
|
(_j = settings.useDom) !== null && _j !== void 0 ? _j : (settings.useDom = false);
|
|
59
|
-
(_k = (
|
|
59
|
+
(_k = (_s = settings).matchTimeout) !== null && _k !== void 0 ? _k : (_s.matchTimeout = 0);
|
|
60
60
|
settings.lazyLoad = settings.lazyLoad === true ? {} : settings.lazyLoad;
|
|
61
61
|
if (settings.lazyLoad) {
|
|
62
|
-
(_l = (
|
|
63
|
-
(_m = (
|
|
64
|
-
(_o = (
|
|
62
|
+
(_l = (_t = settings.lazyLoad).scrollLength) !== null && _l !== void 0 ? _l : (_t.scrollLength = defaults_1.DEFAULT_LAZY_LOAD.scrollLength);
|
|
63
|
+
(_m = (_u = settings.lazyLoad).waitingTime) !== null && _m !== void 0 ? _m : (_u.waitingTime = defaults_1.DEFAULT_LAZY_LOAD.waitingTime);
|
|
64
|
+
(_o = (_v = settings.lazyLoad).maxAmountToScroll) !== null && _o !== void 0 ? _o : (_v.maxAmountToScroll = defaults_1.DEFAULT_LAZY_LOAD.maxAmountToScroll);
|
|
65
65
|
}
|
|
66
66
|
settings.stepIndex = stepIndex++;
|
|
67
67
|
(_p = settings.waitBetweenStitches) !== null && _p !== void 0 ? _p : (settings.waitBetweenStitches = utils.types.isObject(settings.lazyLoad)
|
|
68
68
|
? settings.lazyLoad.waitingTime
|
|
69
69
|
: defaults_1.DEFAULT_WAIT_BEFORE_CAPTURE);
|
|
70
70
|
if (settings.mobileOptions) {
|
|
71
|
-
(_q = (
|
|
71
|
+
(_q = (_w = settings.mobileOptions).keepNavigationBar) !== null && _q !== void 0 ? _q : (_w.keepNavigationBar = false);
|
|
72
72
|
}
|
|
73
73
|
if (settings.matchLevel === 'Content') {
|
|
74
74
|
logger.console.log(chalk_1.default.yellow(lang.matchLevelContentDeprecatedWarning));
|
|
75
75
|
}
|
|
76
|
+
if ((_r = settings.usedDeprecations) === null || _r === void 0 ? void 0 : _r.length) {
|
|
77
|
+
void eyes.core.logEvent({
|
|
78
|
+
settings: {
|
|
79
|
+
...eyes.test.eyesServer,
|
|
80
|
+
level: 'Notice',
|
|
81
|
+
event: { type: 'SDK.deprecation', deprecations: settings.usedDeprecations },
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
76
85
|
const driver = (0, driver_1.isDriver)(target, spec)
|
|
77
86
|
? await (0, driver_1.makeDriver)({ spec, driver: target, reset: target === defaultTarget, logger })
|
|
78
87
|
: null;
|
|
@@ -34,8 +34,8 @@ async function extractDefaultEnvironments({ driver, settings, }) {
|
|
|
34
34
|
try {
|
|
35
35
|
const driverEnvironment = await driver.getEnvironment();
|
|
36
36
|
const viewport = await driver.getViewport();
|
|
37
|
-
|
|
38
|
-
environment.viewportSize = utils.geometry.scale(
|
|
37
|
+
// scale layout viewport by visualViewport.scale to get visible CSS viewport (avoids double-scaling spec drivers that already return CSS pixels)
|
|
38
|
+
environment.viewportSize = utils.geometry.scale(viewport.viewportSize, viewport.viewportScale);
|
|
39
39
|
environment.environmentId = utils.general.guid();
|
|
40
40
|
if (driverEnvironment.isEC)
|
|
41
41
|
environment.ecSessionId = (_a = (await driver.getSessionId())) !== null && _a !== void 0 ? _a : undefined;
|
package/dist/open-eyes.js
CHANGED
|
@@ -145,7 +145,7 @@ function makeOpenEyes({ type: defaultType = 'classic', clients, batch, removeDup
|
|
|
145
145
|
logger,
|
|
146
146
|
});
|
|
147
147
|
if (settings.disableBrokerUrlCache && driver) {
|
|
148
|
-
await core.
|
|
148
|
+
await core.disableNMLClientCache(driver);
|
|
149
149
|
}
|
|
150
150
|
const getTypedEyes = (0, get_typed_eyes_1.makeGetTypedEyes)({
|
|
151
151
|
type,
|
package/dist/ufg/check.js
CHANGED
|
@@ -52,6 +52,7 @@ function makeCheck({ eyes, target: defaultTarget, environments: defaultEnvironme
|
|
|
52
52
|
...eyes.test.ufgServer,
|
|
53
53
|
eyesServerUrl: eyes.test.eyesServer.eyesServerUrl,
|
|
54
54
|
apiKey: eyes.test.eyesServer.apiKey,
|
|
55
|
+
httpVersion: eyes.test.eyesServer.httpVersion,
|
|
55
56
|
},
|
|
56
57
|
logger,
|
|
57
58
|
});
|
|
@@ -16,6 +16,7 @@ async function createRenderTargetFromSnapshot({ ufgClient, snapshot, logger, url
|
|
|
16
16
|
proxy: snapshot.account.eyesServer.proxy,
|
|
17
17
|
autProxy: snapshot.settings.autProxy,
|
|
18
18
|
skipRootHtmlResource: snapshot.settings.skipRootHtmlResource,
|
|
19
|
+
httpVersion: snapshot.settings.httpVersion,
|
|
19
20
|
},
|
|
20
21
|
logger,
|
|
21
22
|
});
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pagePayload = exports.makeMediaPlaybackGuard = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Prevents media playback side-effects during the layoutBreakpoints snapshot loop.
|
|
6
|
+
*
|
|
7
|
+
* dom-snapshot calls video.play() per breakpoint to capture a video frame. For
|
|
8
|
+
* BrightCove / video.js players this triggers CSS class changes (has-started, is-playing)
|
|
9
|
+
* and subtitle text injection that outlast the corresponding pause() call. With multiple
|
|
10
|
+
* breakpoints the mutations accumulate and corrupt visual snapshots.
|
|
11
|
+
*
|
|
12
|
+
* Lifecycle:
|
|
13
|
+
* const guard = makeMediaPlaybackGuard({context, logger})
|
|
14
|
+
* await guard.setup() // once, before the loop
|
|
15
|
+
* for (const entry of entries) {
|
|
16
|
+
* await guard.beforeResize() // before setViewportSize
|
|
17
|
+
* // setViewportSize / reload / lazyLoad
|
|
18
|
+
* await guard.beforeSnapshot() // after resize, before takeDomSnapshot
|
|
19
|
+
* // takeDomSnapshot
|
|
20
|
+
* await guard.afterSnapshot() // after takeDomSnapshot
|
|
21
|
+
* }
|
|
22
|
+
* // setViewportSize (restore)
|
|
23
|
+
* await guard.teardown() // once, after final viewport restore
|
|
24
|
+
*
|
|
25
|
+
* Implementation notes:
|
|
26
|
+
*
|
|
27
|
+
* The TypeScript layer is just orchestration — `setup` / `beforeResize` / etc. each
|
|
28
|
+
* dispatch a phase name to a single self-contained page-side payload (`pagePayload`
|
|
29
|
+
* below) via `context.execute`. The first call installs a library at `window[ns]`
|
|
30
|
+
* with one handler per lifecycle method; subsequent calls just look up and run
|
|
31
|
+
* `window[ns][phase]()`. Teardown deletes `window[ns]` so a fresh guard starts clean.
|
|
32
|
+
*
|
|
33
|
+
* - `ns` is randomised per guard instance so concurrent guards on the same page
|
|
34
|
+
* (e.g. nested checks) do not collide.
|
|
35
|
+
* - Per-element state lives in a `WeakMap`, not on the elements themselves — no
|
|
36
|
+
* marker properties leak onto the page's DOM.
|
|
37
|
+
* - A single `walkAll(root, fn)` helper handles every Document/ShadowRoot traversal.
|
|
38
|
+
* - A `MutationObserver` covers the gap between phase calls (e.g. videos that
|
|
39
|
+
* BrightCove creates during setViewportSize). The synchronous walks in
|
|
40
|
+
* `beforeSnapshot` remain because the observer fires on a microtask and would
|
|
41
|
+
* otherwise lose the race against dom-snapshot's serialization.
|
|
42
|
+
*/
|
|
43
|
+
function makeMediaPlaybackGuard({ context, logger, }) {
|
|
44
|
+
const ns = '__applitools_mpg_' + Math.random().toString(36).slice(2) + '__';
|
|
45
|
+
return {
|
|
46
|
+
setup: () => runPhase('setup'),
|
|
47
|
+
beforeResize: () => runPhase('beforeResize'),
|
|
48
|
+
beforeSnapshot: () => runPhase('beforeSnapshot'),
|
|
49
|
+
afterSnapshot: () => runPhase('afterSnapshot'),
|
|
50
|
+
teardown: () => runPhase('teardown'),
|
|
51
|
+
};
|
|
52
|
+
function runPhase(phase) {
|
|
53
|
+
return context
|
|
54
|
+
.execute(pagePayload, { ns, phase })
|
|
55
|
+
.catch((err) => logger.warn(`media guard: ${phase} failed`, err));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.makeMediaPlaybackGuard = makeMediaPlaybackGuard;
|
|
59
|
+
/**
|
|
60
|
+
* The entire page-side library — a single self-contained function shipped to the
|
|
61
|
+
* browser by `context.execute`. No closure variables from the TypeScript side are
|
|
62
|
+
* visible inside this body.
|
|
63
|
+
*
|
|
64
|
+
* Contract: on first invocation, installs `window[ns]` with `{setup, beforeResize,
|
|
65
|
+
* beforeSnapshot, afterSnapshot, teardown}` handlers; on every invocation, calls
|
|
66
|
+
* `window[ns][phase]()` if present. The handlers all close over the same set of
|
|
67
|
+
* private helpers and a `WeakMap`-backed per-element state.
|
|
68
|
+
*/
|
|
69
|
+
/* istanbul ignore next — runs only inside the browser, not in node */
|
|
70
|
+
function pagePayload(arg) {
|
|
71
|
+
const w = window;
|
|
72
|
+
const ns = arg.ns;
|
|
73
|
+
if (!w[ns])
|
|
74
|
+
install();
|
|
75
|
+
const state = w[ns];
|
|
76
|
+
if (state && typeof state[arg.phase] === 'function')
|
|
77
|
+
state[arg.phase]();
|
|
78
|
+
function install() {
|
|
79
|
+
// ----- private state -----
|
|
80
|
+
const videoUndos = new WeakMap();
|
|
81
|
+
const captionUndos = new WeakMap();
|
|
82
|
+
const playerSnapshots = [];
|
|
83
|
+
const originalProtoPlay = HTMLMediaElement.prototype.play;
|
|
84
|
+
const originalCreateElement = document.createElement.bind(document);
|
|
85
|
+
const originalCreateElementNS = document.createElementNS.bind(document);
|
|
86
|
+
let observer = null;
|
|
87
|
+
// ----- helpers -----
|
|
88
|
+
/** Single DOM traversal helper. Visits every element under `root`, recursing into shadow roots. */
|
|
89
|
+
function walkAll(root, fn) {
|
|
90
|
+
const els = root.querySelectorAll('*');
|
|
91
|
+
for (let i = 0; i < els.length; i++) {
|
|
92
|
+
const el = els[i];
|
|
93
|
+
fn(el);
|
|
94
|
+
const sr = el.shadowRoot;
|
|
95
|
+
if (sr)
|
|
96
|
+
walkAll(sr, fn);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function walkVideos(root, fn) {
|
|
100
|
+
walkAll(root, el => {
|
|
101
|
+
if (el.tagName === 'VIDEO')
|
|
102
|
+
fn(el);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function walkCaptions(root, fn) {
|
|
106
|
+
walkAll(root, el => {
|
|
107
|
+
const cl = el.classList;
|
|
108
|
+
if (cl && cl.contains('vjs-text-track-display'))
|
|
109
|
+
fn(el);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Replace an own-property on `obj` with `replacement` and return a closure that
|
|
114
|
+
* puts the original back. Restores correctly whether the original lived on the
|
|
115
|
+
* instance or only on the prototype.
|
|
116
|
+
*/
|
|
117
|
+
function overrideOwn(obj, key, replacement) {
|
|
118
|
+
const wasOwn = Object.prototype.hasOwnProperty.call(obj, key);
|
|
119
|
+
const original = wasOwn ? obj[key] : undefined;
|
|
120
|
+
obj[key] = replacement;
|
|
121
|
+
return function restore() {
|
|
122
|
+
if (wasOwn)
|
|
123
|
+
obj[key] = original;
|
|
124
|
+
else
|
|
125
|
+
delete obj[key];
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function runUndos(undos) {
|
|
129
|
+
for (let i = undos.length - 1; i >= 0; i--) {
|
|
130
|
+
try {
|
|
131
|
+
undos[i]();
|
|
132
|
+
}
|
|
133
|
+
catch (_) {
|
|
134
|
+
// best-effort restore: a failure here must not block the rest
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// ----- locking primitives -----
|
|
139
|
+
function lockVideo(video) {
|
|
140
|
+
if (videoUndos.has(video))
|
|
141
|
+
return;
|
|
142
|
+
const undos = [];
|
|
143
|
+
// 1. Mask the `autoplay` IDL attribute so reads return false and writes are dropped.
|
|
144
|
+
const hadAutoplay = video.hasAttribute('autoplay');
|
|
145
|
+
if (hadAutoplay)
|
|
146
|
+
video.removeAttribute('autoplay');
|
|
147
|
+
try {
|
|
148
|
+
Object.defineProperty(video, 'autoplay', {
|
|
149
|
+
configurable: true,
|
|
150
|
+
get: () => false,
|
|
151
|
+
set: () => { },
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
catch (_) { }
|
|
155
|
+
undos.push(() => {
|
|
156
|
+
try {
|
|
157
|
+
delete video.autoplay;
|
|
158
|
+
}
|
|
159
|
+
catch (_) { }
|
|
160
|
+
if (hadAutoplay)
|
|
161
|
+
video.setAttribute('autoplay', '');
|
|
162
|
+
});
|
|
163
|
+
// 2. setAttribute('autoplay', ...) — BrightCove uses this directly, bypassing the IDL setter.
|
|
164
|
+
undos.push(overrideOwn(video, 'setAttribute', function (name, value) {
|
|
165
|
+
if (name === 'autoplay')
|
|
166
|
+
return;
|
|
167
|
+
return Element.prototype.setAttribute.call(this, name, value);
|
|
168
|
+
}));
|
|
169
|
+
// 3. Make captureStream() return zero video tracks so dom-snapshot's buildBlobVideos
|
|
170
|
+
// skips its play()/record/pause cycle entirely.
|
|
171
|
+
if (video.captureStream) {
|
|
172
|
+
undos.push(overrideOwn(video, 'captureStream', function () {
|
|
173
|
+
return { getVideoTracks: () => [] };
|
|
174
|
+
}));
|
|
175
|
+
}
|
|
176
|
+
// 4. Disable text tracks (caption rendering source).
|
|
177
|
+
const tracks = video.textTracks;
|
|
178
|
+
const savedModes = [];
|
|
179
|
+
for (let i = 0; i < tracks.length; i++) {
|
|
180
|
+
savedModes.push(tracks[i].mode);
|
|
181
|
+
tracks[i].mode = 'disabled';
|
|
182
|
+
}
|
|
183
|
+
undos.push(() => {
|
|
184
|
+
const t = video.textTracks;
|
|
185
|
+
for (let i = 0; i < t.length && i < savedModes.length; i++)
|
|
186
|
+
t[i].mode = savedModes[i];
|
|
187
|
+
});
|
|
188
|
+
videoUndos.set(video, undos);
|
|
189
|
+
}
|
|
190
|
+
function unlockVideo(video) {
|
|
191
|
+
const undos = videoUndos.get(video);
|
|
192
|
+
if (!undos)
|
|
193
|
+
return;
|
|
194
|
+
videoUndos.delete(video);
|
|
195
|
+
runUndos(undos);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Lock a .vjs-text-track-display caption container. Instance-level overrides because
|
|
199
|
+
* BrightCove's event handlers re-inject cue elements in microtasks between our
|
|
200
|
+
* phase call returning and dom-snapshot serializing the DOM — synchronous, persistent
|
|
201
|
+
* overrides intercept every insertion path regardless of timing.
|
|
202
|
+
*/
|
|
203
|
+
function lockCaption(c) {
|
|
204
|
+
if (captionUndos.has(c))
|
|
205
|
+
return;
|
|
206
|
+
const undos = [];
|
|
207
|
+
while (c.firstChild)
|
|
208
|
+
c.removeChild(c.firstChild);
|
|
209
|
+
undos.push(overrideOwn(c, 'appendChild', (n) => n));
|
|
210
|
+
undos.push(overrideOwn(c, 'insertBefore', (n) => n));
|
|
211
|
+
undos.push(overrideOwn(c, 'insertAdjacentHTML', () => { }));
|
|
212
|
+
undos.push(overrideOwn(c, 'insertAdjacentElement', (_pos, n) => n));
|
|
213
|
+
try {
|
|
214
|
+
Object.defineProperty(c, 'innerHTML', {
|
|
215
|
+
configurable: true,
|
|
216
|
+
get: () => '',
|
|
217
|
+
set: () => { },
|
|
218
|
+
});
|
|
219
|
+
undos.push(() => {
|
|
220
|
+
try {
|
|
221
|
+
delete c.innerHTML;
|
|
222
|
+
}
|
|
223
|
+
catch (_) { }
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
catch (_) { }
|
|
227
|
+
captionUndos.set(c, undos);
|
|
228
|
+
}
|
|
229
|
+
function unlockCaption(c) {
|
|
230
|
+
const undos = captionUndos.get(c);
|
|
231
|
+
if (!undos)
|
|
232
|
+
return;
|
|
233
|
+
captionUndos.delete(c);
|
|
234
|
+
runUndos(undos);
|
|
235
|
+
}
|
|
236
|
+
// ----- player container snapshot / restore -----
|
|
237
|
+
function snapshotPlayers() {
|
|
238
|
+
walkVideos(document, video => {
|
|
239
|
+
const playerEl = video.closest('video-js, [data-vjs-player], .video-js');
|
|
240
|
+
playerSnapshots.push({
|
|
241
|
+
video,
|
|
242
|
+
paused: video.paused,
|
|
243
|
+
currentTime: video.currentTime,
|
|
244
|
+
playerEl,
|
|
245
|
+
playerClasses: playerEl ? Array.from(playerEl.classList) : [],
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
function restorePlayers() {
|
|
250
|
+
for (let i = 0; i < playerSnapshots.length; i++) {
|
|
251
|
+
const s = playerSnapshots[i];
|
|
252
|
+
if (s.paused && !s.video.paused) {
|
|
253
|
+
s.video.pause();
|
|
254
|
+
try {
|
|
255
|
+
s.video.currentTime = s.currentTime;
|
|
256
|
+
}
|
|
257
|
+
catch (_) { } // MSE may reject seeks
|
|
258
|
+
}
|
|
259
|
+
if (s.playerEl) {
|
|
260
|
+
const current = Array.from(s.playerEl.classList);
|
|
261
|
+
for (let j = 0; j < current.length; j++) {
|
|
262
|
+
if (s.playerClasses.indexOf(current[j]) === -1)
|
|
263
|
+
s.playerEl.classList.remove(current[j]);
|
|
264
|
+
}
|
|
265
|
+
for (let j = 0; j < s.playerClasses.length; j++)
|
|
266
|
+
s.playerEl.classList.add(s.playerClasses[j]);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// ----- global patches (live for the entire loop) -----
|
|
271
|
+
function patchGlobals() {
|
|
272
|
+
// video.js calls HTMLMediaElement.prototype.play.call(el) directly — prototype patch is mandatory.
|
|
273
|
+
// Stays alive through teardown's restorePlayers() so BrightCove's pause-event handler
|
|
274
|
+
// cannot call the (now-live) native play() and restart playback.
|
|
275
|
+
;
|
|
276
|
+
HTMLMediaElement.prototype.play = function () {
|
|
277
|
+
return Promise.resolve();
|
|
278
|
+
};
|
|
279
|
+
document.createElement = function (tag) {
|
|
280
|
+
const el = originalCreateElement(tag);
|
|
281
|
+
if (typeof tag === 'string' && tag.toLowerCase() === 'video') {
|
|
282
|
+
lockVideo(el);
|
|
283
|
+
}
|
|
284
|
+
return el;
|
|
285
|
+
};
|
|
286
|
+
document.createElementNS = function (nsArg, tag) {
|
|
287
|
+
const el = originalCreateElementNS(nsArg, tag);
|
|
288
|
+
if (typeof tag === 'string' && tag.toLowerCase() === 'video') {
|
|
289
|
+
lockVideo(el);
|
|
290
|
+
}
|
|
291
|
+
return el;
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function unpatchGlobals() {
|
|
295
|
+
;
|
|
296
|
+
HTMLMediaElement.prototype.play = originalProtoPlay;
|
|
297
|
+
document.createElement = originalCreateElement;
|
|
298
|
+
document.createElementNS = originalCreateElementNS;
|
|
299
|
+
}
|
|
300
|
+
// ----- mutation observer (belt-and-suspenders for late-arriving nodes) -----
|
|
301
|
+
function startObserver() {
|
|
302
|
+
observer = new MutationObserver(mutations => {
|
|
303
|
+
for (let i = 0; i < mutations.length; i++) {
|
|
304
|
+
const added = mutations[i].addedNodes;
|
|
305
|
+
for (let j = 0; j < added.length; j++) {
|
|
306
|
+
const node = added[j];
|
|
307
|
+
if (!(node instanceof Element))
|
|
308
|
+
continue;
|
|
309
|
+
if (node.tagName === 'VIDEO')
|
|
310
|
+
lockVideo(node);
|
|
311
|
+
else if (node.classList && node.classList.contains('vjs-text-track-display'))
|
|
312
|
+
lockCaption(node);
|
|
313
|
+
walkVideos(node, lockVideo);
|
|
314
|
+
walkCaptions(node, lockCaption);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
observer.observe(document, { childList: true, subtree: true });
|
|
319
|
+
}
|
|
320
|
+
function stopObserver() {
|
|
321
|
+
if (observer) {
|
|
322
|
+
observer.disconnect();
|
|
323
|
+
observer = null;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// ----- bootstrap -----
|
|
327
|
+
// Player state is NOT snapshotted here. It is captured fresh in `beforeSnapshot`
|
|
328
|
+
// so that responsive classes (vjs-layout-small, vjs-fluid, orientation classes)
|
|
329
|
+
// applied during setViewportSize are preserved across afterSnapshot's restore.
|
|
330
|
+
// This also automatically covers videos BrightCove injects mid-loop, since the
|
|
331
|
+
// walk re-runs each iteration.
|
|
332
|
+
patchGlobals();
|
|
333
|
+
walkCaptions(document, lockCaption);
|
|
334
|
+
startObserver();
|
|
335
|
+
// ----- phase handlers (called from TS via runPhase) -----
|
|
336
|
+
w[ns] = {
|
|
337
|
+
// `setup` is already complete by the time we get here; the no-op handler keeps the dispatch shape uniform.
|
|
338
|
+
setup() { },
|
|
339
|
+
beforeResize() {
|
|
340
|
+
walkVideos(document, lockVideo);
|
|
341
|
+
walkCaptions(document, lockCaption);
|
|
342
|
+
},
|
|
343
|
+
beforeSnapshot() {
|
|
344
|
+
// Safety net first — pause videos and disable tracks before snapshotting state,
|
|
345
|
+
// so playback classes (vjs-playing) settle to a consistent paused-state.
|
|
346
|
+
walkVideos(document, video => {
|
|
347
|
+
if (!video.paused)
|
|
348
|
+
video.pause();
|
|
349
|
+
const t = video.textTracks;
|
|
350
|
+
for (let i = 0; i < t.length; i++)
|
|
351
|
+
t[i].mode = 'disabled';
|
|
352
|
+
});
|
|
353
|
+
// Capture fresh per-player state — runs after resize so responsive classes
|
|
354
|
+
// reflect the current breakpoint, and so videos BrightCove injected during
|
|
355
|
+
// the resize are included.
|
|
356
|
+
playerSnapshots.length = 0;
|
|
357
|
+
snapshotPlayers();
|
|
358
|
+
// MutationObserver is async; lock new caption containers synchronously before
|
|
359
|
+
// dom-snapshot's next-macrotask serialization runs.
|
|
360
|
+
walkCaptions(document, lockCaption);
|
|
361
|
+
},
|
|
362
|
+
afterSnapshot() {
|
|
363
|
+
walkVideos(document, unlockVideo);
|
|
364
|
+
restorePlayers();
|
|
365
|
+
// Clear after consume — the captured state is breakpoint-specific and must not
|
|
366
|
+
// leak into the next iteration or teardown, where the viewport differs.
|
|
367
|
+
playerSnapshots.length = 0;
|
|
368
|
+
},
|
|
369
|
+
teardown() {
|
|
370
|
+
// Restore players BEFORE unpatching globals: BrightCove's pause-event handler can call
|
|
371
|
+
// play() during pause(), and we need that call to still hit the no-op prototype patch.
|
|
372
|
+
restorePlayers();
|
|
373
|
+
stopObserver();
|
|
374
|
+
unpatchGlobals();
|
|
375
|
+
walkVideos(document, unlockVideo);
|
|
376
|
+
walkCaptions(document, unlockCaption);
|
|
377
|
+
delete w[ns];
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
exports.pagePayload = pagePayload;
|
|
@@ -34,6 +34,7 @@ const take_dom_snapshot_1 = require("./take-dom-snapshot");
|
|
|
34
34
|
const generate_safe_selectors_1 = require("./generate-safe-selectors");
|
|
35
35
|
const wait_for_lazy_load_1 = require("../../automation/utils/wait-for-lazy-load");
|
|
36
36
|
const calculate_required_sizes_1 = require("../../automation/utils/calculate-required-sizes");
|
|
37
|
+
const media_playback_guard_1 = require("./media-playback-guard");
|
|
37
38
|
const chalk_1 = __importDefault(require("chalk"));
|
|
38
39
|
const utils = __importStar(require("@applitools/utils"));
|
|
39
40
|
const lang = __importStar(require("../../lang"));
|
|
@@ -85,9 +86,12 @@ async function takeDomSnapshots({ driver, settings, hooks, provides, logger, })
|
|
|
85
86
|
context: currentContext,
|
|
86
87
|
elementReferences: settings.elementReferences,
|
|
87
88
|
});
|
|
89
|
+
const mediaGuard = (0, media_playback_guard_1.makeMediaPlaybackGuard)({ context: currentContext, logger });
|
|
90
|
+
await mediaGuard.setup();
|
|
88
91
|
const snapshots = Array(settings.environments.length);
|
|
89
92
|
for (const [index, { viewportSize, browsers }] of entries.entries()) {
|
|
90
93
|
logger.log(`Taking dom snapshot for viewport size ${viewportSize}`);
|
|
94
|
+
await mediaGuard.beforeResize();
|
|
91
95
|
if (viewportSize) {
|
|
92
96
|
try {
|
|
93
97
|
await driver.setViewportSize(viewportSize);
|
|
@@ -121,10 +125,13 @@ async function takeDomSnapshots({ driver, settings, hooks, provides, logger, })
|
|
|
121
125
|
await (0, wait_for_lazy_load_1.waitForLazyLoad)({ context: currentContext, settings: settings.lazyLoad, logger });
|
|
122
126
|
}
|
|
123
127
|
await beforeEachSnapshot();
|
|
128
|
+
await mediaGuard.beforeSnapshot();
|
|
124
129
|
const snapshot = await (0, take_dom_snapshot_1.takeDomSnapshot)({ context: currentContext, settings, logger });
|
|
125
130
|
browsers.forEach(({ index }) => (snapshots[index] = snapshot));
|
|
131
|
+
await mediaGuard.afterSnapshot();
|
|
126
132
|
}
|
|
127
133
|
await driver.setViewportSize(initialViewportSize);
|
|
134
|
+
await mediaGuard.teardown();
|
|
128
135
|
if (settings.layoutBreakpoints.reload) {
|
|
129
136
|
await driver.reloadPage();
|
|
130
137
|
await beforeEachSnapshot();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applitools/core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.63.1",
|
|
4
4
|
"homepage": "https://applitools.com",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/applitools/eyes.sdk.javascript1/issues"
|
|
@@ -61,19 +61,19 @@
|
|
|
61
61
|
"setup:standalone": "sh -c 'yarn chromedriver --port=4444 --verbose &'"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@applitools/core-base": "1.
|
|
65
|
-
"@applitools/dom-capture": "11.8.
|
|
66
|
-
"@applitools/dom-snapshot": "4.17.
|
|
67
|
-
"@applitools/driver": "1.26.
|
|
68
|
-
"@applitools/ec-client": "1.12.
|
|
69
|
-
"@applitools/logger": "2.2.
|
|
70
|
-
"@applitools/nml-client": "1.11.
|
|
71
|
-
"@applitools/req": "1.10.
|
|
72
|
-
"@applitools/screenshoter": "3.12.
|
|
73
|
-
"@applitools/snippets": "2.9.
|
|
74
|
-
"@applitools/socket": "1.3.
|
|
75
|
-
"@applitools/ufg-client": "1.22.
|
|
76
|
-
"@applitools/utils": "1.14.
|
|
64
|
+
"@applitools/core-base": "1.34.1",
|
|
65
|
+
"@applitools/dom-capture": "11.8.1",
|
|
66
|
+
"@applitools/dom-snapshot": "4.17.2",
|
|
67
|
+
"@applitools/driver": "1.26.2",
|
|
68
|
+
"@applitools/ec-client": "1.12.30",
|
|
69
|
+
"@applitools/logger": "2.2.12",
|
|
70
|
+
"@applitools/nml-client": "1.11.28",
|
|
71
|
+
"@applitools/req": "1.10.2",
|
|
72
|
+
"@applitools/screenshoter": "3.12.21",
|
|
73
|
+
"@applitools/snippets": "2.9.2",
|
|
74
|
+
"@applitools/socket": "1.3.13",
|
|
75
|
+
"@applitools/ufg-client": "1.22.2",
|
|
76
|
+
"@applitools/utils": "1.14.5",
|
|
77
77
|
"abort-controller": "3.0.0",
|
|
78
78
|
"chalk": "4.1.2",
|
|
79
79
|
"node-fetch": "2.6.7",
|
|
@@ -82,23 +82,28 @@
|
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@applitools/bongo": "^5.10.0",
|
|
85
|
-
"@applitools/spec-driver-playwright": "^1.9.
|
|
86
|
-
"@applitools/spec-driver-puppeteer": "^1.8.
|
|
87
|
-
"@applitools/spec-driver-selenium": "^1.8.
|
|
88
|
-
"@applitools/test-server": "^1.4.
|
|
85
|
+
"@applitools/spec-driver-playwright": "^1.9.2",
|
|
86
|
+
"@applitools/spec-driver-puppeteer": "^1.8.2",
|
|
87
|
+
"@applitools/spec-driver-selenium": "^1.8.2",
|
|
88
|
+
"@applitools/test-server": "^1.4.4",
|
|
89
89
|
"@applitools/test-utils": "^1.5.17",
|
|
90
|
-
"@applitools/tunnel-client": "^1.11.
|
|
90
|
+
"@applitools/tunnel-client": "^1.11.14",
|
|
91
|
+
"@swc-node/register": "^1.6.8",
|
|
91
92
|
"@types/mocha": "^10.0.7",
|
|
92
93
|
"@types/node": "^12.20.55",
|
|
93
94
|
"@types/selenium-webdriver": "^4.1.2",
|
|
94
95
|
"@types/semver": "^7.5.8",
|
|
96
|
+
"chai": "^4.2.0",
|
|
95
97
|
"chromedriver": "^131.0.5",
|
|
96
98
|
"crypto": "^1.0.1",
|
|
99
|
+
"express": "^4.10.6",
|
|
100
|
+
"mocha": "^11.7.5",
|
|
97
101
|
"nock": "^13.3.2",
|
|
98
102
|
"playwright": "1.47.0",
|
|
99
103
|
"png-async": "^0.9.4",
|
|
100
104
|
"puppeteer": "^24.11.1",
|
|
101
|
-
"selenium-webdriver": "^4.15.0"
|
|
105
|
+
"selenium-webdriver": "^4.15.0",
|
|
106
|
+
"webdriver": "^5.23.0"
|
|
102
107
|
},
|
|
103
108
|
"engines": {
|
|
104
109
|
"node": ">=12.13.0"
|
|
@@ -113,6 +118,7 @@
|
|
|
113
118
|
"ws>bufferutil": false,
|
|
114
119
|
"ws>utf-8-validate": false,
|
|
115
120
|
"@applitools/core-base>@applitools/image>sharp": false,
|
|
121
|
+
"@swc-node/register>@swc/core": false,
|
|
116
122
|
"selenium-webdriver>ws>bufferutil": false,
|
|
117
123
|
"selenium-webdriver>ws>utf-8-validate": false
|
|
118
124
|
}
|
|
@@ -12,6 +12,6 @@ export declare function makeGetNMLClient({ client, logger: mainLogger }: Options
|
|
|
12
12
|
settings: Omit<NMLClientSettings, 'brokerUrl'>;
|
|
13
13
|
logger: Logger;
|
|
14
14
|
}) => Promise<NMLClient>;
|
|
15
|
-
|
|
15
|
+
disableNMLClientCache: (driver: Driver<SpecType>) => Promise<void>;
|
|
16
16
|
};
|
|
17
17
|
export {};
|
|
@@ -67,7 +67,7 @@ export interface Core<TSpec extends SpecType> extends Omit<BaseCore.Core, 'openE
|
|
|
67
67
|
driver: Driver<TSpec>;
|
|
68
68
|
logger: Logger;
|
|
69
69
|
}): Promise<NMLClient>;
|
|
70
|
-
|
|
70
|
+
disableNMLClientCache(driver: Driver<TSpec>): Promise<void>;
|
|
71
71
|
openEyes(options: {
|
|
72
72
|
target?: DriverTarget<TSpec>;
|
|
73
73
|
settings: BaseCore.OpenSettings;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type SpecType, type Context } from '@applitools/driver';
|
|
2
|
+
import { type Logger } from '@applitools/logger';
|
|
3
|
+
/**
|
|
4
|
+
* Prevents media playback side-effects during the layoutBreakpoints snapshot loop.
|
|
5
|
+
*
|
|
6
|
+
* dom-snapshot calls video.play() per breakpoint to capture a video frame. For
|
|
7
|
+
* BrightCove / video.js players this triggers CSS class changes (has-started, is-playing)
|
|
8
|
+
* and subtitle text injection that outlast the corresponding pause() call. With multiple
|
|
9
|
+
* breakpoints the mutations accumulate and corrupt visual snapshots.
|
|
10
|
+
*
|
|
11
|
+
* Lifecycle:
|
|
12
|
+
* const guard = makeMediaPlaybackGuard({context, logger})
|
|
13
|
+
* await guard.setup() // once, before the loop
|
|
14
|
+
* for (const entry of entries) {
|
|
15
|
+
* await guard.beforeResize() // before setViewportSize
|
|
16
|
+
* // setViewportSize / reload / lazyLoad
|
|
17
|
+
* await guard.beforeSnapshot() // after resize, before takeDomSnapshot
|
|
18
|
+
* // takeDomSnapshot
|
|
19
|
+
* await guard.afterSnapshot() // after takeDomSnapshot
|
|
20
|
+
* }
|
|
21
|
+
* // setViewportSize (restore)
|
|
22
|
+
* await guard.teardown() // once, after final viewport restore
|
|
23
|
+
*
|
|
24
|
+
* Implementation notes:
|
|
25
|
+
*
|
|
26
|
+
* The TypeScript layer is just orchestration — `setup` / `beforeResize` / etc. each
|
|
27
|
+
* dispatch a phase name to a single self-contained page-side payload (`pagePayload`
|
|
28
|
+
* below) via `context.execute`. The first call installs a library at `window[ns]`
|
|
29
|
+
* with one handler per lifecycle method; subsequent calls just look up and run
|
|
30
|
+
* `window[ns][phase]()`. Teardown deletes `window[ns]` so a fresh guard starts clean.
|
|
31
|
+
*
|
|
32
|
+
* - `ns` is randomised per guard instance so concurrent guards on the same page
|
|
33
|
+
* (e.g. nested checks) do not collide.
|
|
34
|
+
* - Per-element state lives in a `WeakMap`, not on the elements themselves — no
|
|
35
|
+
* marker properties leak onto the page's DOM.
|
|
36
|
+
* - A single `walkAll(root, fn)` helper handles every Document/ShadowRoot traversal.
|
|
37
|
+
* - A `MutationObserver` covers the gap between phase calls (e.g. videos that
|
|
38
|
+
* BrightCove creates during setViewportSize). The synchronous walks in
|
|
39
|
+
* `beforeSnapshot` remain because the observer fires on a microtask and would
|
|
40
|
+
* otherwise lose the race against dom-snapshot's serialization.
|
|
41
|
+
*/
|
|
42
|
+
export declare function makeMediaPlaybackGuard<TSpec extends SpecType>({ context, logger, }: {
|
|
43
|
+
context: Context<TSpec>;
|
|
44
|
+
logger: Logger;
|
|
45
|
+
}): {
|
|
46
|
+
setup: () => Promise<void>;
|
|
47
|
+
beforeResize: () => Promise<void>;
|
|
48
|
+
beforeSnapshot: () => Promise<void>;
|
|
49
|
+
afterSnapshot: () => Promise<void>;
|
|
50
|
+
teardown: () => Promise<void>;
|
|
51
|
+
};
|
|
52
|
+
type Phase = 'setup' | 'beforeResize' | 'beforeSnapshot' | 'afterSnapshot' | 'teardown';
|
|
53
|
+
/**
|
|
54
|
+
* The entire page-side library — a single self-contained function shipped to the
|
|
55
|
+
* browser by `context.execute`. No closure variables from the TypeScript side are
|
|
56
|
+
* visible inside this body.
|
|
57
|
+
*
|
|
58
|
+
* Contract: on first invocation, installs `window[ns]` with `{setup, beforeResize,
|
|
59
|
+
* beforeSnapshot, afterSnapshot, teardown}` handlers; on every invocation, calls
|
|
60
|
+
* `window[ns][phase]()` if present. The handlers all close over the same set of
|
|
61
|
+
* private helpers and a `WeakMap`-backed per-element state.
|
|
62
|
+
*/
|
|
63
|
+
export declare function pagePayload(arg: {
|
|
64
|
+
ns: string;
|
|
65
|
+
phase: Phase;
|
|
66
|
+
}): void;
|
|
67
|
+
export {};
|