@applitools/screenshoter 3.2.8 → 3.3.2

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 (80) hide show
  1. package/.bongo/dry-run/package-lock.json +49 -6
  2. package/.bongo/dry-run/package.json +5 -0
  3. package/.bongo/dry-run.tgz +0 -0
  4. package/CHANGELOG.md +19 -0
  5. package/index.js +2 -1
  6. package/package.json +7 -4
  7. package/src/find-image-pattern.js +11 -38
  8. package/src/image.js +107 -64
  9. package/src/take-screenshot.js +136 -160
  10. package/src/take-simple-screenshot.js +25 -0
  11. package/src/take-stitched-screenshot.js +34 -40
  12. package/src/take-viewport-screenshot.js +179 -16
  13. package/test/e2e/android.spec.js +120 -13
  14. package/test/e2e/external.spec.js +155 -0
  15. package/test/e2e/ios.spec.js +142 -12
  16. package/test/e2e/web-ios.spec.js +19 -6
  17. package/test/e2e/web.spec.js +33 -21
  18. package/test/fixtures/android/app-fully-non-scrollable.png +0 -0
  19. package/test/fixtures/android/app-fully-recycler.png +0 -0
  20. package/test/fixtures/android/app-fully-scroll-statusbar.png +0 -0
  21. package/test/fixtures/android/app-fully-scroll.png +0 -0
  22. package/test/fixtures/android/app-statusbar.png +0 -0
  23. package/test/fixtures/android/x-app-fully-collapsing.png +0 -0
  24. package/test/fixtures/android/x-app-fully-recycler.png +0 -0
  25. package/test/fixtures/android/x-element-fully.png +0 -0
  26. package/test/fixtures/external/agl.png +0 -0
  27. package/test/fixtures/image/{house.combined-higher-wider.png → house.framed-higher-wider.png} +0 -0
  28. package/test/fixtures/image/{house.combined-higher.png → house.framed-higher.png} +0 -0
  29. package/test/fixtures/image/house.framed-shorter-thinner.png +0 -0
  30. package/test/fixtures/image/{house.combined-wider.png → house.framed-wider.png} +0 -0
  31. package/test/fixtures/ios/app-fully-collapsing.png +0 -0
  32. package/test/fixtures/ios/app-fully-collection.png +0 -0
  33. package/test/fixtures/ios/app-fully-overlapped-statusbar.png +0 -0
  34. package/test/fixtures/ios/app-fully-overlapped.png +0 -0
  35. package/test/fixtures/ios/app-fully-scroll-statusbar.png +0 -0
  36. package/test/fixtures/ios/app-fully-scroll.png +0 -0
  37. package/test/fixtures/ios/app-fully-superview.png +0 -0
  38. package/test/fixtures/ios/app-fully-table.png +0 -0
  39. package/test/fixtures/ios/app-statusbar.png +0 -0
  40. package/test/fixtures/ios/app.png +0 -0
  41. package/test/fixtures/ios/element-fully.png +0 -0
  42. package/test/fixtures/ios/element.png +0 -0
  43. package/test/fixtures/ios/region.png +0 -0
  44. package/test/fixtures/ios/webview-fully.png +0 -0
  45. package/test/fixtures/ios/webview.png +0 -0
  46. package/test/fixtures/pattern/iPad_5th_landscape.png +0 -0
  47. package/test/fixtures/pattern/iPad_5th_portrait.png +0 -0
  48. package/test/fixtures/pattern/iPad_9th_landscape.png +0 -0
  49. package/test/fixtures/pattern/iPad_9th_portrait.png +0 -0
  50. package/test/fixtures/pattern/iPhone_11_landscape.png +0 -0
  51. package/test/fixtures/pattern/iPhone_11_portrait.png +0 -0
  52. package/test/fixtures/pattern/iPhone_13_landscape.png +0 -0
  53. package/test/fixtures/pattern/iPhone_13_portrait.png +0 -0
  54. package/test/fixtures/pattern/iPhone_SE_landscape.png +0 -0
  55. package/test/fixtures/pattern/iPhone_SE_portrait.png +0 -0
  56. package/test/fixtures/pattern/iPhone_XS_portrait_noviewport.png +0 -0
  57. package/test/fixtures/web/frame-fully.png +0 -0
  58. package/test/fixtures/web/frame.png +0 -0
  59. package/test/fixtures/web/inner-element-fully.png +0 -0
  60. package/test/fixtures/web/inner-element.png +0 -0
  61. package/test/fixtures/web/inner-region-fully.png +0 -0
  62. package/test/fixtures/web/inner-region.png +0 -0
  63. package/test/fixtures/web/page-fully.png +0 -0
  64. package/test/fixtures/web/page.png +0 -0
  65. package/test/fixtures/web/region-fully.png +0 -0
  66. package/test/fixtures/web/region.png +0 -0
  67. package/test/fixtures/web-ios/page-fully.png +0 -0
  68. package/test/it/find-pattern.spec.js +16 -11
  69. package/test/it/image.spec.js +42 -15
  70. package/docker-compose.yaml +0 -29
  71. package/src/calculate-screenshot-regions.js +0 -31
  72. package/src/screenshoter.js +0 -158
  73. package/test/fixtures/pattern/iPad_Air_portrait.png +0 -0
  74. package/test/fixtures/pattern/iPhone_5S_landscape.png +0 -0
  75. package/test/fixtures/pattern/iPhone_XR_perfecto_landscape.png +0 -0
  76. package/test/fixtures/pattern/iPhone_XS_Max_perfecto_landscape.png +0 -0
  77. package/test/fixtures/pattern/iPhone_XS_landscape.png +0 -0
  78. package/test/fixtures/pattern/iPhone_XS_portrait.png +0 -0
  79. package/test/fixtures/pattern/iPhone_X_perfecto_portrait.png +0 -0
  80. package/test/util/spec-driver.js +0 -288
@@ -78,42 +78,69 @@ describe('image', () => {
78
78
  assert.strictEqual(actual.height, 50000)
79
79
  })
80
80
 
81
- it('should replace region in image with a higher and wider image', async () => {
81
+ it('should frame image in a higher and wider region', async () => {
82
82
  const image = makeImage('./test/fixtures/image/house.png')
83
83
  const srcImage = makeImage({
84
84
  width: 200,
85
85
  height: 200,
86
86
  data: Buffer.alloc(200 * 200 * 4, Buffer.from([0xff, 0, 0, 0xff])),
87
87
  })
88
- const combinedImage = await srcImage.combine(image, image, {x: 200, y: 200, width: 100, height: 100})
88
+ const combinedImage = await srcImage.frame(image, image, {x: 200, y: 200, width: 100, height: 100})
89
89
  const actual = await combinedImage.toObject()
90
- const expected = await makeImage('./test/fixtures/image/house.combined-higher-wider.png').toObject()
90
+ const expected = await makeImage('./test/fixtures/image/house.framed-higher-wider.png').toObject()
91
91
  assert.ok(pixelmatch(actual.data, expected.data, null, expected.width, expected.height) === 0)
92
92
  })
93
93
 
94
- it('should replace region in image with a higher image', async () => {
94
+ it('should frame image in a higher region', async () => {
95
95
  const image = await makeImage('./test/fixtures/image/house.png')
96
96
  const srcImage = makeImage({
97
97
  width: 200,
98
98
  height: 200,
99
99
  data: Buffer.alloc(200 * 200 * 4, Buffer.from([0, 0xff, 0, 0xff])),
100
100
  })
101
- const combinedImage = await srcImage.combine(image, image, {x: 200, y: 200, width: 200, height: 100})
101
+ const combinedImage = await srcImage.frame(image, image, {x: 200, y: 200, width: 200, height: 100})
102
102
  const actual = await combinedImage.toObject()
103
- const expected = await makeImage('./test/fixtures/image/house.combined-higher.png').toObject()
103
+ const expected = await makeImage('./test/fixtures/image/house.framed-higher.png').toObject()
104
104
  assert.ok(pixelmatch(actual.data, expected.data, null, expected.width, expected.height) === 0)
105
105
  })
106
106
 
107
- it('should replace region in image with a higher image', async () => {
107
+ it('should frame image in a wider region', async () => {
108
108
  const image = await makeImage('./test/fixtures/image/house.png')
109
- const srcImage = makeImage({
110
- width: 200,
111
- height: 200,
112
- data: Buffer.alloc(200 * 200 * 4, Buffer.from([0, 0, 0xff, 0xff])),
113
- })
114
- const combinedImage = await srcImage.combine(image, image, {x: 200, y: 200, width: 100, height: 200})
115
- const actual = await combinedImage.toObject()
116
- const expected = await makeImage('./test/fixtures/image/house.combined-wider.png').toObject()
109
+ const data = Buffer.alloc(200 * 200 * 4, Buffer.from([0, 0, 0xff, 0xff]))
110
+ const actual = await makeImage({width: 200, height: 200, data})
111
+ .frame(image, image, {x: 200, y: 200, width: 100, height: 200})
112
+ .toObject()
113
+ const expected = await makeImage('./test/fixtures/image/house.framed-wider.png').toObject()
114
+ assert.ok(pixelmatch(actual.data, expected.data, null, expected.width, expected.height) === 0)
115
+ })
116
+
117
+ it('should frame image in a shorter and thinner region', async () => {
118
+ const image = await makeImage('./test/fixtures/image/house.png')
119
+ const data = Buffer.alloc(200 * 200 * 4, Buffer.from([0xff, 0, 0xff, 0xff]))
120
+ const actual = await makeImage({width: 200, height: 200, data})
121
+ .frame(image, image, {x: 100, y: 100, width: 250, height: 250})
122
+ .toObject()
123
+ const expected = await makeImage('./test/fixtures/image/house.framed-shorter-thinner.png').toObject()
124
+ assert.ok(pixelmatch(actual.data, expected.data, null, expected.width, expected.height) === 0)
125
+ })
126
+
127
+ it('should frame image in a shorter region', async () => {
128
+ const image = await makeImage('./test/fixtures/image/house.png')
129
+ const data = Buffer.alloc(200 * 200 * 4, Buffer.from([0xff, 0, 0xff, 0xff]))
130
+ const actual = await makeImage({width: 200, height: 200, data})
131
+ .frame(image, image, {x: 100, y: 100, width: 200, height: 250})
132
+ .toObject()
133
+ const expected = await makeImage('./test/fixtures/image/house.framed-shorter-thinner.png').toObject()
134
+ assert.ok(pixelmatch(actual.data, expected.data, null, expected.width, expected.height) === 0)
135
+ })
136
+
137
+ it('should frame image in a thinner region', async () => {
138
+ const image = await makeImage('./test/fixtures/image/house.png')
139
+ const data = Buffer.alloc(200 * 200 * 4, Buffer.from([0xff, 0, 0xff, 0xff]))
140
+ const actual = await makeImage({width: 200, height: 200, data})
141
+ .frame(image, image, {x: 100, y: 100, width: 250, height: 200})
142
+ .toObject()
143
+ const expected = await makeImage('./test/fixtures/image/house.framed-shorter-thinner.png').toObject()
117
144
  assert.ok(pixelmatch(actual.data, expected.data, null, expected.width, expected.height) === 0)
118
145
  })
119
146
  })
@@ -1,29 +0,0 @@
1
- {
2
- "version": "3.4",
3
- "services": {
4
- "chrome": {
5
- "image": "selenium/standalone-chrome",
6
- "environment": [
7
- "SE_NODE_OVERRIDE_MAX_SESSIONS=true",
8
- "SE_NODE_MAX_SESSIONS=15"
9
- ],
10
- "volumes": [
11
- "/dev/shm:/dev/shm"
12
- ],
13
- "network_mode": "host"
14
- },
15
- "firefox": {
16
- "image": "selenium/standalone-firefox",
17
- "environment": [
18
- "SE_NODE_OVERRIDE_MAX_SESSIONS=true",
19
- "SE_NODE_MAX_SESSIONS=15"
20
- ],
21
- "volumes": [
22
- "/dev/shm:/dev/shm"
23
- ],
24
- "ports": [
25
- "4445:4444"
26
- ]
27
- }
28
- }
29
- }
@@ -1,31 +0,0 @@
1
- const utils = require('@applitools/utils')
2
-
3
- async function calculateScreenshotRegions({context, screenshotRegion, regions}) {
4
- const screenshotRegions = []
5
- for (const region of regions) {
6
- screenshotRegions.push(await transformRegion(region))
7
- }
8
-
9
- return screenshotRegions
10
-
11
- async function transformRegion(region) {
12
- if (utils.types.has(region, ['x', 'y', 'width', 'height'])) {
13
- // if someday different coordinate systems will be supported (context or app based), the conversion will happen here
14
- return [regions]
15
- }
16
- const elements = await context.elements(region)
17
- return elements.reduce(async (regions, element) => {
18
- regions = await regions
19
- const region = await element.getRegion()
20
- regions.push({
21
- x: Math.max(0, region.x - screenshotRegion.x),
22
- y: Math.max(0, region.y - screenshotRegion.y),
23
- width: region.width,
24
- height: region.height,
25
- })
26
- return regions
27
- }, [])
28
- }
29
- }
30
-
31
- module.exports = calculateScreenshotRegions
@@ -1,158 +0,0 @@
1
- const utils = require('@applitools/utils')
2
- const makeScroller = require('./scroller')
3
- const scrollIntoViewport = require('./scroll-into-viewport')
4
- const takeStitchedScreenshot = require('./take-stitched-screenshot')
5
- const takeViewportScreenshot = require('./take-viewport-screenshot')
6
-
7
- async function screenshoter({
8
- driver,
9
- frames = [],
10
- region,
11
- fully,
12
- scrollingMode,
13
- hideScrollbars,
14
- hideCaret,
15
- withStatusBar,
16
- overlap,
17
- framed,
18
- wait,
19
- stabilization,
20
- hooks,
21
- debug,
22
- logger,
23
- }) {
24
- // screenshot of a window/app was requested (fully or viewport)
25
- const window = !region && (!frames || frames.length === 0)
26
- // framed screenshots could be taken only when screenshot of window/app fully was requested
27
- framed = framed && fully && window
28
- // screenshots with status bar could be taken only when screenshot of app or framed app fully was requested
29
- withStatusBar = withStatusBar && driver.isNative && window && (!fully || framed)
30
-
31
- const activeContext = driver.currentContext
32
- const context =
33
- frames.length > 0
34
- ? await activeContext.context(frames.reduce((parent, frame) => ({...frame, parent}), null))
35
- : activeContext
36
-
37
- // traverse from main context to target context to hide scrollbars and preserve context state (scroll/translate position)
38
- for (const nextContext of context.path) {
39
- const scrollingElement = await nextContext.getScrollingElement()
40
- // unlike web apps, native apps do not always have scrolling element
41
- if (scrollingElement) {
42
- if (driver.isWeb && hideScrollbars) await scrollingElement.hideScrollbars()
43
- await scrollingElement.preserveState()
44
- }
45
- }
46
-
47
- // blur active element in target context
48
- const activeElement = driver.isWeb && hideCaret ? await context.blurElement() : null
49
-
50
- const target = await getTarget({window, context, region, fully, scrollingMode, logger})
51
-
52
- if (driver.isWeb && hideScrollbars) await target.scroller.hideScrollbars()
53
-
54
- try {
55
- if (!window) await scrollIntoViewport({...target, logger})
56
-
57
- const screenshot =
58
- fully && target.scroller
59
- ? await takeStitchedScreenshot({...target, withStatusBar, overlap, framed, wait, stabilization, debug, logger})
60
- : await takeViewportScreenshot({...target, withStatusBar, wait, stabilization, debug, logger})
61
-
62
- if (hooks && hooks.afterScreenshot) {
63
- // imitate image-like state for the hook
64
- if (window && fully && target.scroller) {
65
- await target.scroller.moveTo({x: 0, y: 0}, await driver.mainContext.getScrollingElement())
66
- }
67
- await hooks.afterScreenshot({driver, scroller: target.scroller, screenshot})
68
- }
69
-
70
- return screenshot
71
- } finally {
72
- if (target.scroller) {
73
- await target.scroller.restoreScrollbars()
74
- }
75
-
76
- // if there was active element and we have blurred it, then restore focus
77
- if (activeElement) await context.focusElement(activeElement)
78
-
79
- // traverse from target context to the main context to restore scrollbars and context states
80
- for (const prevContext of context.path.reverse()) {
81
- const scrollingElement = await prevContext.getScrollingElement()
82
- if (scrollingElement) {
83
- if (driver.isWeb && hideScrollbars) await scrollingElement.restoreScrollbars()
84
- await scrollingElement.restoreState()
85
- }
86
- }
87
-
88
- // restore focus on original active context
89
- await activeContext.focus()
90
- }
91
- }
92
-
93
- async function getTarget({window, context, region, fully, scrollingMode, logger}) {
94
- if (window) {
95
- // window/app
96
- const scrollingElement = await context.main.getScrollingElement()
97
- return {
98
- context: context.main,
99
- scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
100
- }
101
- } else if (region) {
102
- if (utils.types.has(region, ['x', 'y', 'width', 'height'])) {
103
- // region by coordinates
104
- const scrollingElement = await context.getScrollingElement()
105
- return {
106
- context,
107
- region,
108
- scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
109
- }
110
- } else {
111
- // region by element or selector
112
- const element = await context.element(region)
113
- if (!element) throw new Error('Element not found!')
114
-
115
- const elementContext = element.context
116
-
117
- if (fully) {
118
- const isScrollable = await element.isScrollable()
119
- // if element is scrollable, then take screenshot of the full element content, otherwise take screenshot of full element
120
- const region = isScrollable ? null : await element.getRegion()
121
- const scrollingElement = isScrollable ? element : await elementContext.getScrollingElement()
122
- // css stitching could be applied only to root element of its context
123
- scrollingMode = scrollingMode === 'css' && !(await scrollingElement.isRoot()) ? 'mixed' : scrollingMode
124
- return {
125
- context: elementContext,
126
- region,
127
- scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
128
- }
129
- } else {
130
- const scrollingElement = await context.getScrollingElement()
131
- return {
132
- context: elementContext,
133
- region: await element.getRegion(),
134
- scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
135
- }
136
- }
137
- }
138
- } else if (!context.isMain) {
139
- // context
140
- if (fully) {
141
- const scrollingElement = await context.getScrollingElement()
142
- return {
143
- context,
144
- scroller: scrollingElement ? makeScroller({logger, element: scrollingElement, scrollingMode}) : null,
145
- }
146
- } else {
147
- const scrollingElement = await context.parent.getScrollingElement()
148
- const element = await context.getContextElement()
149
- return {
150
- context: context.parent,
151
- region: await element.getRegion(), // IMHO we should use CLIENT (without borders) region here
152
- scroller: scrollingElement ? makeScroller({logger, element: scrollingElement, scrollingMode}) : null,
153
- }
154
- }
155
- }
156
- }
157
-
158
- module.exports = screenshoter
@@ -1,288 +0,0 @@
1
- const webdriverio = require('webdriverio')
2
- const utils = require('@applitools/utils')
3
-
4
- // #region HELPERS
5
-
6
- const LEGACY_ELEMENT_ID = 'ELEMENT'
7
- const ELEMENT_ID = 'element-6066-11e4-a52e-4f735466cecf'
8
-
9
- function extractElementId(element) {
10
- return element.elementId || element[ELEMENT_ID] || element[LEGACY_ELEMENT_ID]
11
- }
12
-
13
- // #endregion
14
-
15
- // #region UTILITY
16
-
17
- function isDriver(browser) {
18
- if (!browser) return false
19
- return browser.constructor.name === 'Browser'
20
- }
21
- function isElement(element) {
22
- if (!element) return false
23
- return Boolean(element.elementId || element[ELEMENT_ID] || element[LEGACY_ELEMENT_ID])
24
- }
25
- function isSelector(selector) {
26
- return utils.types.isString(selector) || utils.types.isFunction(selector)
27
- }
28
- function transformElement(element) {
29
- const elementId = extractElementId(element)
30
- return {[ELEMENT_ID]: elementId, [LEGACY_ELEMENT_ID]: elementId}
31
- }
32
- function transformSelector(selector) {
33
- if (utils.types.has(selector, 'selector')) {
34
- if (!utils.types.has(selector, 'type')) return selector.selector
35
- if (selector.type === 'css') return `css selector:${selector.selector}`
36
- else return `${selector.type}:${selector.selector}`
37
- }
38
- return selector
39
- }
40
- function extractSelector(element) {
41
- return element.selector
42
- }
43
- async function isEqualElements(browser, element1, element2) {
44
- // NOTE: wdio wraps puppeteer and generate ids by itself just incrementing a counter
45
- // NOTE: appium for ios could return different ids for same element
46
- if (browser.isDevTools || browser.isIOS) {
47
- return browser.execute((element1, element2) => element1 === element2, element1, element2).catch(() => false)
48
- }
49
- if (!element1 || !element2) return false
50
- const elementId1 = extractElementId(element1)
51
- const elementId2 = extractElementId(element2)
52
- return elementId1 === elementId2
53
- }
54
-
55
- // #endregion
56
-
57
- // #region COMMANDS
58
-
59
- async function executeScript(browser, script, ...args) {
60
- return browser.execute(script, ...args)
61
- }
62
- async function mainContext(browser) {
63
- await browser.switchToFrame(null)
64
- return browser
65
- }
66
- async function parentContext(browser) {
67
- await browser.switchToParentFrame()
68
- return browser
69
- }
70
- async function childContext(browser, element) {
71
- await browser.switchToFrame(element)
72
- return browser
73
- }
74
- async function findElement(browser, selector) {
75
- const element = await browser.$(selector)
76
- return !element.error ? element : null
77
- }
78
- async function findElements(browser, selector) {
79
- const elements = await browser.$$(selector)
80
- return Array.from(elements)
81
- }
82
- async function getElementRegion(browser, element) {
83
- const extendedElement = await browser.$(element)
84
- if (utils.types.isFunction(extendedElement, 'getRect')) {
85
- return extendedElement.getRect()
86
- } else {
87
- const size = await extendedElement.getSize()
88
- const location = utils.types.has(size, ['x', 'y']) ? size : await extendedElement.getLocation()
89
- return {x: location.x, y: location.y, width: size.width, height: size.height}
90
- }
91
- }
92
- async function getElementAttribute(browser, element, name) {
93
- return browser.getElementAttribute(extractElementId(element), name)
94
- }
95
- async function getWindowSize(browser) {
96
- if (utils.types.isFunction(browser.getWindowRect)) {
97
- return browser.getWindowRect()
98
- } else if (utils.types.isFunction(browser.getWindowSize)) {
99
- return await browser.getWindowSize()
100
- }
101
- }
102
- async function setWindowSize(browser, {width, height} = {}) {
103
- if (utils.types.isFunction(browser.setWindowRect)) {
104
- await browser.setWindowRect(0, 0, width, height)
105
- } else {
106
- await browser.setWindowPosition(0, 0)
107
- await browser.setWindowSize(width, height)
108
- }
109
- }
110
- async function getOrientation(browser) {
111
- const orientation = await browser.getOrientation()
112
- return orientation.toLowerCase()
113
- }
114
- async function getDriverInfo(browser) {
115
- const driverInfo = {
116
- sessionId: browser.sessionId,
117
- isMobile: browser.isMobile,
118
- isNative: browser.isMobile && !browser.capabilities.browserName,
119
- deviceName: browser.capabilities.desired
120
- ? browser.capabilities.desired.deviceName
121
- : browser.capabilities.deviceName,
122
- platformName: browser.capabilities.platformName || browser.capabilities.platform,
123
- platformVersion: browser.capabilities.platformVersion,
124
- browserName: browser.capabilities.browserName,
125
- browserVersion: browser.capabilities.browserVersion,
126
- pixelRatio: browser.capabilities.pixelRatio,
127
- }
128
-
129
- if (driverInfo.isNative) {
130
- const capabilities = utils.types.has(browser.capabilities, ['pixelRatio', 'viewportRect', 'statBarHeight'])
131
- ? browser.capabilities
132
- : await browser.getSession()
133
-
134
- driverInfo.pixelRatio = capabilities.pixelRatio
135
-
136
- try {
137
- const {statusBar, navigationBar} = await browser.getSystemBars()
138
- driverInfo.statusBarHeight = statusBar.visible ? statusBar.height : 0
139
- driverInfo.navigationBarHeight = navigationBar.visible ? navigationBar.height : 0
140
- } catch (err) {
141
- driverInfo.statusBarHeight = capabilities.statBarHeight || (capabilities.viewportRect || {}).top || 0
142
- driverInfo.navigationBarHeight = 0
143
- }
144
- }
145
-
146
- return driverInfo
147
- }
148
- async function takeScreenshot(driver) {
149
- return driver.takeScreenshot()
150
- }
151
- async function visit(browser, url) {
152
- return browser.url(url)
153
- }
154
- async function click(browser, element) {
155
- if (isSelector(element)) element = await findElement(browser, element)
156
- const extendedElement = await browser.$(element)
157
- await extendedElement.click()
158
- }
159
- async function performAction(browser, actions) {
160
- return browser.touchAction(actions)
161
- }
162
- async function getElementText(browser, element) {
163
- return browser.getElementText(extractElementId(element))
164
- }
165
-
166
- // #endregion
167
-
168
- async function build({type = 'web'} = {}) {
169
- const capabilities = {
170
- web: {
171
- protocol: 'http',
172
- hostname: 'localhost',
173
- path: '/wd/hub',
174
- port: 4444,
175
- logLevel: 'silent',
176
- capabilities: {
177
- browserName: 'chrome',
178
- },
179
- },
180
- android: {
181
- protocol: 'https',
182
- hostname: 'ondemand.saucelabs.com',
183
- path: '/wd/hub',
184
- port: 443,
185
- logLevel: 'silent',
186
- capabilities: {
187
- name: 'Android Screenshoter Test',
188
- browserName: '',
189
- platformName: 'Android',
190
- platformVersion: '7.0',
191
- appiumVersion: '1.20.2',
192
- deviceName: 'Samsung Galaxy S8 FHD GoogleAPI Emulator',
193
- automationName: 'uiautomator2',
194
- app: 'https://applitools.jfrog.io/artifactory/Examples/android/1.3/app-debug.apk',
195
- username: process.env.SAUCE_USERNAME,
196
- accessKey: process.env.SAUCE_ACCESS_KEY,
197
- },
198
- },
199
- androidx: {
200
- protocol: 'https',
201
- hostname: 'ondemand.saucelabs.com',
202
- path: '/wd/hub',
203
- port: 443,
204
- logLevel: 'silent',
205
- capabilities: {
206
- name: 'AndroidX Screenshoter Test',
207
- browserName: '',
208
- platformName: 'Android',
209
- platformVersion: '10.0',
210
- appiumVersion: '1.20.2',
211
- deviceName: 'Google Pixel 3a XL GoogleAPI Emulator',
212
- automationName: 'uiautomator2',
213
- app: 'https://applitools.jfrog.io/artifactory/Examples/androidx/1.2.0/app_androidx.apk',
214
- username: process.env.SAUCE_USERNAME,
215
- accessKey: process.env.SAUCE_ACCESS_KEY,
216
- },
217
- },
218
- ios: {
219
- protocol: 'https',
220
- hostname: 'ondemand.saucelabs.com',
221
- path: '/wd/hub',
222
- port: 443,
223
- logLevel: 'silent',
224
- capabilities: {
225
- name: 'iOS Screenshoter Test',
226
- deviceName: 'iPhone 11 Pro Simulator',
227
- platformName: 'iOS',
228
- platformVersion: '13.4',
229
- appiumVersion: '1.19.2',
230
- automationName: 'XCUITest',
231
- app: 'https://applitools.jfrog.io/artifactory/Examples/IOSTestApp/1.5/app/IOSTestApp-1.5.zip',
232
- username: process.env.SAUCE_USERNAME,
233
- accessKey: process.env.SAUCE_ACCESS_KEY,
234
- },
235
- },
236
- 'web-ios': {
237
- protocol: 'https',
238
- hostname: 'ondemand.saucelabs.com',
239
- path: '/wd/hub',
240
- port: 443,
241
- logLevel: 'silent',
242
- capabilities: {
243
- name: 'iOS Web Screenshoter Test',
244
- deviceName: 'iPhone 11 Pro Simulator',
245
- browserName: 'safari',
246
- platformName: 'iOS',
247
- platformVersion: '14.5',
248
- appiumVersion: '1.20.1',
249
- automationName: 'XCUITest',
250
- username: process.env.SAUCE_USERNAME,
251
- accessKey: process.env.SAUCE_ACCESS_KEY,
252
- },
253
- },
254
- }
255
-
256
- const browser = await webdriverio.remote(capabilities[type])
257
-
258
- return [browser, () => browser.deleteSession()]
259
- }
260
-
261
- module.exports = {
262
- isDriver,
263
- isElement,
264
- isSelector,
265
- transformElement,
266
- transformSelector,
267
- extractSelector,
268
- isEqualElements,
269
- executeScript,
270
- mainContext,
271
- parentContext,
272
- childContext,
273
- findElement,
274
- findElements,
275
- getElementRegion,
276
- getElementAttribute,
277
- getWindowSize,
278
- setWindowSize,
279
- getOrientation,
280
- getDriverInfo,
281
- takeScreenshot,
282
- visit,
283
- click,
284
- performAction,
285
- getElementText,
286
-
287
- build,
288
- }