@applitools/eyes-testcafe 2.0.0-beta.8 → 2.0.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +467 -0
  2. package/LICENSE +1 -1
  3. package/README.md +7 -531
  4. package/dist/api.js +51 -0
  5. package/dist/extract-environment.js +15 -0
  6. package/dist/index-legacy.js +5 -0
  7. package/dist/index.js +19 -0
  8. package/dist/legacy.js +225 -0
  9. package/dist/spec-driver.js +245 -0
  10. package/package.json +73 -76
  11. package/types/index-legacy.d.ts +2 -0
  12. package/types/index.d.ts +1833 -0
  13. package/dist/captureFrameAndPoll.js +0 -1468
  14. package/dist/captureFrameAndPollForIE.js +0 -12569
  15. package/index.js +0 -29
  16. package/lib/BordersAwareElementContentLocationProvider.js +0 -79
  17. package/lib/Eyes.js +0 -927
  18. package/lib/EyesFactory.js +0 -73
  19. package/lib/EyesTestCafe.js +0 -1270
  20. package/lib/EyesTestcafeUtils.js +0 -440
  21. package/lib/EyesVisualGrid.js +0 -345
  22. package/lib/ImageOrientationHandler.js +0 -31
  23. package/lib/JavascriptHandler.js +0 -20
  24. package/lib/TestCafeExecutor.js +0 -57
  25. package/lib/capture/EyesWebDriverScreenshot.js +0 -650
  26. package/lib/capture/EyesWebDriverScreenshotFactory.js +0 -32
  27. package/lib/capture/FirefoxScreenshotImageProvider.js +0 -63
  28. package/lib/capture/ImageProviderFactory.js +0 -38
  29. package/lib/capture/SafariScreenshotImageProvider.js +0 -254
  30. package/lib/capture/TakesScreenshotImageProvider.js +0 -35
  31. package/lib/errors/EyesDriverOperationError.js +0 -10
  32. package/lib/errors/NoFramesError.js +0 -7
  33. package/lib/fluent/AccessibilityRegionByElement.js +0 -46
  34. package/lib/fluent/AccessibilityRegionBySelector.js +0 -58
  35. package/lib/fluent/FloatingRegionByElement.js +0 -56
  36. package/lib/fluent/FloatingRegionBySelector.js +0 -63
  37. package/lib/fluent/FrameLocator.js +0 -110
  38. package/lib/fluent/IgnoreRegionByElement.js +0 -51
  39. package/lib/fluent/IgnoreRegionBySelector.js +0 -57
  40. package/lib/fluent/SelectorByElement.js +0 -37
  41. package/lib/fluent/SelectorByLocator.js +0 -47
  42. package/lib/fluent/Target.js +0 -17
  43. package/lib/fluent/TestcafeCheckSettings.js +0 -352
  44. package/lib/frames/Frame.js +0 -149
  45. package/lib/frames/FrameChain.js +0 -175
  46. package/lib/getCaptureDomScript.js +0 -14
  47. package/lib/hash.js +0 -15
  48. package/lib/isTestcafeSelector.js +0 -7
  49. package/lib/makeClientFunctionWrapper.js +0 -61
  50. package/lib/positioning/CssTranslatePositionMemento.js +0 -39
  51. package/lib/positioning/CssTranslatePositionProvider.js +0 -130
  52. package/lib/positioning/ElementPositionMemento.js +0 -36
  53. package/lib/positioning/ElementPositionProvider.js +0 -88
  54. package/lib/positioning/FirefoxRegionPositionCompensation.js +0 -45
  55. package/lib/positioning/ImageRotation.js +0 -22
  56. package/lib/positioning/OverflowAwareCssTranslatePositionProvider.js +0 -17
  57. package/lib/positioning/OverflowAwareScrollPositionProvider.js +0 -17
  58. package/lib/positioning/RegionPositionCompensationFactory.js +0 -37
  59. package/lib/positioning/SafariRegionPositionCompensation.js +0 -26
  60. package/lib/positioning/ScrollPositionMemento.js +0 -36
  61. package/lib/positioning/ScrollPositionProvider.js +0 -118
  62. package/lib/positioning/fixImageMarkPosition.js +0 -36
  63. package/lib/regionVisibility/MoveToRegionVisibilityStrategy.js +0 -55
  64. package/lib/regionVisibility/NopRegionVisibilityStrategy.js +0 -35
  65. package/lib/regionVisibility/RegionVisibilityStrategy.js +0 -30
  66. package/lib/runner/ClassicRunner.js +0 -31
  67. package/lib/runner/EyesRunner.js +0 -41
  68. package/lib/runner/TestResultContainer.js +0 -38
  69. package/lib/runner/TestResultsSummary.js +0 -112
  70. package/lib/runner/VisualGridRunner.js +0 -57
  71. package/lib/safeExecuteFunction.js +0 -28
  72. package/lib/wrappers/EyesTargetLocator.js +0 -329
  73. package/lib/wrappers/EyesWebDriver.js +0 -560
  74. package/lib/wrappers/EyesWebElement.js +0 -383
  75. package/lib/wrappers/EyesWebElementPromise.js +0 -68
@@ -1,560 +0,0 @@
1
- 'use strict'
2
-
3
- const {Selector} = require('testcafe')
4
- const {ArgumentGuard, /* MutableImage, */ GeneralUtils} = require('@applitools/eyes-common')
5
-
6
- const fs = require('fs')
7
- const path = require('path')
8
- const rmrf = require('rimraf')
9
-
10
- const {ClientFunction} = require('testcafe')
11
- const {FrameChain} = require('../frames/FrameChain')
12
- const {EyesTestcafeUtils} = require('../EyesTestcafeUtils')
13
- const {EyesWebElement} = require('./EyesWebElement')
14
- // const {EyesWebElementPromise} = require('./EyesWebElementPromise')
15
- const {EyesTargetLocator} = require('./EyesTargetLocator')
16
- const {TestCafeExecutor} = require('../TestCafeExecutor')
17
-
18
- const SCREENSHOTS_PATH = '/.applitools__screenshots'
19
- const getViewport = () => ({
20
- // eslint-disable-next-line no-undef
21
- width: Math.max(document.documentElement.clientWidth, window.innerWidth || 0),
22
- // eslint-disable-next-line no-undef
23
- height: Math.max(document.documentElement.clientHeight, window.innerHeight || 0),
24
- })
25
-
26
- /**
27
- * An Eyes implementation of the interfaces implemented by {@link IWebDriver}.
28
- * Used so we'll be able to return the users an object with the same functionality as {@link WebDriver}.
29
- *
30
- * @extends {WebDriver}
31
- * @implements {EyesJsExecutor}
32
- */
33
- class EyesWebDriver {
34
- /**
35
- * @param {Logger} logger
36
- * @param {Eyes} eyes
37
- * @param {WebDriver} driver
38
- */
39
- constructor(logger, eyes, driver) {
40
- ArgumentGuard.notNull(logger, 'logger')
41
- ArgumentGuard.notNull(eyes, 'eyes')
42
- ArgumentGuard.notNull(driver, 'driver')
43
-
44
- this._logger = logger
45
- this._eyes = eyes
46
- this._driver = driver
47
-
48
- this._elementsIds = new Map()
49
- this._frameChain = new FrameChain(logger)
50
-
51
- /** @type {ImageRotation} */
52
- this._rotation = null
53
- /** @type {RectangleSize} */
54
- this._defaultContentViewportSize = null
55
-
56
- this._executor = new TestCafeExecutor(driver)
57
- this._clientFunctions = {}
58
-
59
- // this._logger.verbose("Driver session is " + this.getSessionId());
60
- }
61
-
62
- // noinspection JSUnusedGlobalSymbols
63
- /**
64
- * @return {Eyes}
65
- */
66
- getEyes() {
67
- return this._eyes
68
- }
69
-
70
- /**
71
- * @return {WebDriver}
72
- */
73
- getRemoteWebDriver() {
74
- // noinspection JSUnresolvedVariable
75
- return this._driver.driver || this._driver
76
- }
77
-
78
- /**
79
- * @inheritDoc
80
- */
81
- execute(command) {
82
- return this._driver.execute(command)
83
- }
84
-
85
- /**
86
- * @inheritDoc
87
- */
88
- setFileDetector(detector) {
89
- return this._driver.setFileDetector(detector)
90
- }
91
-
92
- /**
93
- * @inheritDoc
94
- */
95
- getExecutor() {
96
- return this._driver.getExecutor()
97
- }
98
-
99
- getDriver() {
100
- return this._driver
101
- }
102
-
103
- /**
104
- * @inheritDoc
105
- */
106
- getSession() {
107
- return this._driver.getSession()
108
- }
109
-
110
- /**
111
- * @inheritDoc
112
- */
113
- getCapabilities() {
114
- return this._driver.getCapabilities()
115
- }
116
-
117
- /**
118
- * @inheritDoc
119
- */
120
- quit() {
121
- return this._driver.quit()
122
- }
123
-
124
- /**
125
- * @inheritDoc
126
- */
127
- actions(options) {
128
- return this._driver.actions(options)
129
- }
130
-
131
- /**
132
- * @inheritDoc
133
- */
134
- touchActions() {
135
- return this._driver.touchActions()
136
- }
137
-
138
- /**
139
- * @inheritDoc
140
- */
141
-
142
- async executeScript(script, ...varArgs) {
143
- EyesTestcafeUtils.handleSpecialCommands(script, ...varArgs)
144
- return this._executor.executeScript(script, ...varArgs)
145
- }
146
-
147
- /**
148
- * @inheritDoc
149
- */
150
- executeAsyncScript(script, ...varArgs) {
151
- EyesTestcafeUtils.handleSpecialCommands(script, ...varArgs)
152
- return this._driver.executeAsyncScript(script, ...varArgs)
153
- }
154
-
155
- /**
156
- * @inheritDoc
157
- */
158
- call(fn, optScope, ...varArgs) {
159
- return this._driver.call(fn, optScope, ...varArgs)
160
- }
161
-
162
- /**
163
- * @inheritDoc
164
- */
165
- wait(condition, optTimeout, optMessage) {
166
- return this._driver.wait(condition, optTimeout, optMessage)
167
- }
168
-
169
- /**
170
- * @inheritDoc
171
- */
172
- sleep(ms) {
173
- return this._driver.sleep(ms)
174
- }
175
-
176
- /**
177
- * @inheritDoc
178
- */
179
- getWindowHandle() {
180
- return this._driver.getWindowHandle()
181
- }
182
-
183
- /**
184
- * @inheritDoc
185
- */
186
- getAllWindowHandles() {
187
- return this._driver.getAllWindowHandles()
188
- }
189
-
190
- /**
191
- * @inheritDoc
192
- */
193
- getPageSource() {
194
- return this._driver.getPageSource()
195
- }
196
-
197
- /**
198
- * @inheritDoc
199
- */
200
- close() {
201
- return this._driver.close()
202
- }
203
-
204
- /**
205
- * @inheritDoc
206
- */
207
- get(url) {
208
- this._frameChain.clear()
209
- return this._driver.get(url)
210
- }
211
-
212
- /**
213
- * @inheritDoc
214
- */
215
- getCurrentUrl() {
216
- // eslint-disable-next-line no-undef
217
- return this._evalWithDriver(() => window.location.href)
218
- }
219
-
220
- /**
221
- * @inheritDoc
222
- */
223
- async getTitle() {
224
- return Selector('title').with({boundTestRun: this._driver}).innerText
225
- }
226
-
227
- // noinspection JSCheckFunctionSignatures
228
- /**
229
- * @inheritDoc
230
- * @param {!(By|Function)} locator The locator strategy to use when searching for the element.
231
- * @return {EyesWebElementPromise} - A promise that will resolve to a EyesWebElement.
232
- */
233
- findElement(locator) {
234
- return Selector(locator).with({boundTestRun: this._driver})
235
- }
236
-
237
- // noinspection JSCheckFunctionSignatures
238
- /**
239
- * @inheritDoc
240
- * @param {!(By|Function)} locator The locator strategy to use when searching for the element.
241
- * @return {!Promise<!Array<!EyesWebElement>>} - A promise that will be resolved to an array of the located
242
- * {@link EyesWebElement}s.
243
- */
244
- async findElements(locator) {
245
- const elements = await Selector(locator).with({boundTestRun: this._driver})
246
- return elements.map(element => {
247
- element = new EyesWebElement(this._logger, this, element)
248
- // For Remote web elements, we can keep the IDs
249
- this._elementsIds.set(element.getId(), element)
250
- return element
251
- })
252
- }
253
-
254
- /**
255
- * @inheritDoc
256
- */
257
- async takeScreenshot() {
258
- this._logger.log('Getting screenshot from TestCafe')
259
- const filename = Math.random()
260
- .toString()
261
- .slice(2)
262
- const filepath = path.resolve(SCREENSHOTS_PATH, filename)
263
- const screenshotPath = await this._driver.takeScreenshot(filepath)
264
- if (!screenshotPath) {
265
- throw new Error('Failed to get Testcafe screenshot')
266
- }
267
-
268
- this._logger.log('screenshot created at', screenshotPath)
269
- try {
270
- return fs.readFileSync(screenshotPath)
271
- } finally {
272
- const screenshotFolder = path.dirname(screenshotPath)
273
- rmrf.sync(screenshotFolder)
274
- this._logger.log('screenshot folder deleted at', screenshotFolder)
275
- }
276
- }
277
-
278
- async getViewport() {
279
- return this._executor.executeScript(getViewport)
280
- }
281
-
282
- async resizeWindow(width, height) {
283
- return this._driver.resizeWindow(width, height)
284
- }
285
-
286
- /**
287
- * @inheritDoc
288
- */
289
- navigate() {
290
- return this._driver.navigate()
291
- }
292
-
293
- /**
294
- * @inheritDoc
295
- * @return {EyesTargetLocator} - The target locator interface for this instance.
296
- */
297
- switchTo() {
298
- return new EyesTargetLocator(this._logger, this)
299
- }
300
-
301
- /**
302
- * Found elements are sometimes accessed by their IDs (e.g. tapping an element in Appium).
303
- *
304
- * @return {Map<string, WebElement>} - Maps of IDs for found elements.
305
- */
306
- getElementIds() {
307
- return this._elementsIds
308
- }
309
-
310
- // noinspection JSUnusedGlobalSymbols
311
- /**
312
- * @return {ImageRotation} - The image rotation data.
313
- */
314
- getRotation() {
315
- return this._rotation
316
- }
317
-
318
- /**
319
- * @param {ImageRotation} rotation - The image rotation data.
320
- */
321
- setRotation(rotation) {
322
- this._rotation = rotation
323
- }
324
-
325
- // noinspection JSUnusedGlobalSymbols
326
- /**
327
- * @param {string} className
328
- * @return {EyesWebElementPromise} - A promise that will resolve to a EyesWebElement.
329
- */
330
- findElementByClassName(className) {
331
- // noinspection JSCheckFunctionSignatures
332
- return this.findElement(toClassName(className))
333
- }
334
-
335
- // noinspection JSUnusedGlobalSymbols
336
- /**
337
- * @param {string} className
338
- * @return {!Promise<!Array<!EyesWebElement>>} - A promise that will resolve to an array of EyesWebElements.
339
- */
340
- findElementsByClassName(className) {
341
- // noinspection JSCheckFunctionSignatures
342
- return this.findElements(toClassName(className))
343
- }
344
-
345
- // noinspection JSUnusedGlobalSymbols
346
- /**
347
- * @param {string} cssSelector
348
- * @return {EyesWebElementPromise} - A promise that will resolve to a EyesWebElement.
349
- */
350
- findElementByCssSelector(cssSelector) {
351
- // noinspection JSCheckFunctionSignatures
352
- return this.findElement(cssSelector)
353
- }
354
-
355
- // noinspection JSUnusedGlobalSymbols
356
- /**
357
- * @param {string} cssSelector
358
- * @return {!Promise<!Array<!EyesWebElement>>} - A promise that will resolve to an array of EyesWebElements.
359
- */
360
- findElementsByCssSelector(cssSelector) {
361
- // noinspection JSCheckFunctionSignatures
362
- return this.findElements(cssSelector)
363
- }
364
-
365
- // noinspection JSUnusedGlobalSymbols
366
- /**
367
- * @param {string} id
368
- * @return {EyesWebElementPromise} - A promise that will resolve to a EyesWebElement.
369
- */
370
- findElementById(id) {
371
- // noinspection JSCheckFunctionSignatures
372
- return this.findElement(`#${escapeCss(id)}`)
373
- }
374
-
375
- // noinspection JSUnusedGlobalSymbols
376
- /**
377
- * @param {string} id
378
- * @return {!Promise<!Array<!EyesWebElement>>} - A promise that will resolve to an array of EyesWebElements.
379
- */
380
- findElementsById(id) {
381
- // noinspection JSCheckFunctionSignatures
382
- return this.findElements(`#${escapeCss(id)}`)
383
- }
384
-
385
- // noinspection JSUnusedGlobalSymbols
386
- /**
387
- * @param {string} name
388
- * @return {!Promise<!Array<!EyesWebElement>>} - A promise that will resolve to an array of EyesWebElements.
389
- */
390
- findElementsByName(name) {
391
- // noinspection JSCheckFunctionSignatures
392
- return this.findElements(`*[name="${escapeCss(name)}"]`)
393
- }
394
-
395
- /**
396
- * @param {boolean} [forceQuery=true] - If true, we will perform the query even if we have a cached viewport size.
397
- * @return {Promise<RectangleSize>} - The viewport size of the default content (outer most frame).
398
- */
399
- async getDefaultContentViewportSize(forceQuery = true) {
400
- this._logger.verbose('getDefaultContentViewportSize()')
401
- if (this._defaultContentViewportSize && !forceQuery) {
402
- this._logger.verbose('Using cached viewport size: ', this._defaultContentViewportSize)
403
- return this._defaultContentViewportSize
404
- }
405
-
406
- const switchTo = this.switchTo()
407
- const currentFrames = this._frameChain.clone()
408
-
409
- // Optimization
410
- if (currentFrames.size() > 0) {
411
- await switchTo.defaultContent()
412
- }
413
-
414
- this._logger.verbose('Extracting viewport size...')
415
- this._defaultContentViewportSize = await EyesTestcafeUtils.getViewportSizeOrDisplaySize(
416
- this._logger,
417
- this._driver,
418
- )
419
- this._logger.verbose('Done! Viewport size: ', this._defaultContentViewportSize)
420
-
421
- if (currentFrames.size() > 0) {
422
- await switchTo.frames(currentFrames)
423
- }
424
-
425
- return this._defaultContentViewportSize
426
- }
427
-
428
- /**
429
- * @return {FrameChain} - The current frame chain.
430
- */
431
- getFrameChain() {
432
- return this._frameChain
433
- }
434
-
435
- /**
436
- * @return {Promise<string>}
437
- */
438
- async getUserAgent() {
439
- try {
440
- // eslint-disable-next-line no-undef
441
- const userAgent = await this._evalWithDriver(() => navigator.userAgent, 'getUserAgent')()
442
- this._logger.verbose(`user agent: ${userAgent}`)
443
- return userAgent
444
- } catch (err) {
445
- this._logger.verbose(`Failed to obtain user-agent string ${err}`)
446
- return null
447
- }
448
- }
449
-
450
- _evalWithDriver(func, functionName) {
451
- if (!this._clientFunctions[functionName]) {
452
- this._clientFunctions[functionName] = ClientFunction(func)
453
- }
454
- return this._clientFunctions[functionName].with({boundTestRun: this._driver})
455
- }
456
-
457
- // noinspection JSUnusedGlobalSymbols
458
- /**
459
- * @return {Promise<string>} - A copy of the current frame chain.
460
- */
461
- async getSessionId() {
462
- return String(Math.random()).slice(2)
463
- }
464
-
465
- /**
466
- * @override
467
- */
468
- toString() {
469
- return GeneralUtils.toString(this, ['_logger', '_eyes'])
470
- }
471
-
472
- /**
473
- * Rotates the image as necessary. The rotation is either manually forced by passing a non-null ImageRotation, or
474
- * automatically inferred.
475
- *
476
- * @param {Logger} logger - The underlying driver which produced the screenshot.
477
- * @param {IWebDriver} driver - The underlying driver which produced the screenshot.
478
- * @param {MutableImage} image - The image to normalize.
479
- * @param {ImageRotation} rotation - The degrees by which to rotate the image: positive values = clockwise rotation,
480
- * negative values = counter-clockwise, 0 = force no rotation, null = rotate automatically as needed.
481
- * @return {Promise<MutableImage>} - A normalized image.
482
- */
483
- static async normalizeRotation(logger, driver, image, rotation) {
484
- ArgumentGuard.notNull(logger, 'logger')
485
- ArgumentGuard.notNull(driver, 'driver')
486
- ArgumentGuard.notNull(image, 'image')
487
-
488
- let degrees
489
- if (rotation) {
490
- degrees = rotation.getRotation()
491
- } else {
492
- logger.verbose('Trying to automatically normalize rotation...')
493
- degrees = await EyesTestcafeUtils.tryAutomaticRotation(logger, driver, image)
494
- }
495
-
496
- return image.rotate(degrees)
497
- }
498
- }
499
-
500
- function toClassName(name) {
501
- const names = name
502
- .split(/\s+/g)
503
- .filter(s => s.length > 0)
504
- .map(s => escapeCss(s))
505
- return Selector(`.${names.join('.')}`)
506
- }
507
-
508
- /**
509
- * Escapes a CSS string.
510
- * @param {string} css the string to escape.
511
- * @return {string} the escaped string.
512
- * @throws {TypeError} if the input value is not a string.
513
- * @see https://drafts.csswg.org/cssom/#serialize-an-identifier
514
- */
515
- function escapeCss(css) {
516
- if (typeof css !== 'string') {
517
- throw new TypeError('input must be a string')
518
- }
519
- let ret = ''
520
- const n = css.length
521
- for (let i = 0; i < n; i++) {
522
- const c = css.charCodeAt(i)
523
- if (c === 0x0) {
524
- throw new Error('Invalid character when escaping css')
525
- }
526
-
527
- if (
528
- (c >= 0x0001 && c <= 0x001f) ||
529
- c === 0x007f ||
530
- (i === 0 && c >= 0x0030 && c <= 0x0039) ||
531
- (i === 1 && c >= 0x0030 && c <= 0x0039 && css.charCodeAt(0) === 0x002d)
532
- ) {
533
- ret += `\\${c.toString(16)} `
534
- continue
535
- }
536
-
537
- if (i === 0 && c === 0x002d && n === 1) {
538
- ret += `\\${css.charAt(i)}`
539
- continue
540
- }
541
-
542
- if (
543
- c >= 0x0080 ||
544
- c === 0x002d || // -
545
- c === 0x005f || // _
546
- (c >= 0x0030 && c <= 0x0039) || // [0-9]
547
- (c >= 0x0041 && c <= 0x005a) || // [A-Z]
548
- (c >= 0x0061 && c <= 0x007a)
549
- ) {
550
- // [a-z]
551
- ret += css.charAt(i)
552
- continue
553
- }
554
-
555
- ret += `\\${css.charAt(i)}`
556
- }
557
- return ret
558
- }
559
-
560
- exports.EyesWebDriver = EyesWebDriver