@applitools/screenshoter 3.2.9 → 3.3.3

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 (97) hide show
  1. package/.bongo/dry-run/package-lock.json +19 -19
  2. package/.bongo/dry-run.tgz +0 -0
  3. package/CHANGELOG.md +23 -0
  4. package/docker-compose.yaml +29 -0
  5. package/index.js +2 -1
  6. package/package.json +6 -6
  7. package/src/find-image-pattern.js +11 -38
  8. package/src/image.js +116 -73
  9. package/src/scroll-into-viewport.js +16 -7
  10. package/src/take-screenshot.js +136 -160
  11. package/src/take-simple-screenshot.js +25 -0
  12. package/src/take-stitched-screenshot.js +32 -52
  13. package/src/take-viewport-screenshot.js +157 -16
  14. package/test/e2e/android.spec.js +84 -11
  15. package/test/e2e/external.spec.js +81 -10
  16. package/test/e2e/ios.spec.js +129 -13
  17. package/test/e2e/web-ios.spec.js +44 -11
  18. package/test/e2e/web.spec.js +20 -15
  19. package/test/fixtures/android/app-fully-non-scrollable.png +0 -0
  20. package/test/fixtures/android/app-fully-recycler.png +0 -0
  21. package/test/fixtures/android/app-fully-scroll-statusbar.png +0 -0
  22. package/test/fixtures/android/app-fully-scroll.png +0 -0
  23. package/test/fixtures/android/app-statusbar.png +0 -0
  24. package/test/fixtures/android/x-app-fully-collapsing.png +0 -0
  25. package/test/fixtures/android/x-app-fully-recycler.png +0 -0
  26. package/test/fixtures/android/x-element-fully.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-ios/page-fully-landscape.png +0 -0
  58. package/test/fixtures/web-ios/page-fully.png +0 -0
  59. package/test/fixtures/web-ios/page-landscape.png +0 -0
  60. package/test/it/find-pattern.spec.js +16 -11
  61. package/test/it/image.spec.js +42 -15
  62. package/logs/screenshot_2021_11_14_12_35_00_342Z_full_frame_failed.png +0 -0
  63. package/logs/screenshot_2021_11_14_12_38_00_715Z_frame_failed.png +0 -0
  64. package/logs/screenshot_2021_11_14_12_38_03_866Z_frame_failed.png +0 -0
  65. package/logs/screenshot_2021_11_14_13_02_56_464Z_full_app_failed_1636894976464.png +0 -0
  66. package/logs/screenshot_2021_11_14_13_04_27_904Z_full_app_failed_1636895067904.png +0 -0
  67. package/logs/screenshot_2021_11_14_13_06_13_662Z_full_app_failed_1636895173662.png +0 -0
  68. package/logs/screenshot_2021_11_14_13_06_23_745Z_full_app_failed_1636895183745.png +0 -0
  69. package/logs/screenshot_2021_11_14_13_18_31_571Z_full_app_failed_1636895911571.png +0 -0
  70. package/logs/screenshot_2021_11_14_13_25_54_557Z_viewport_failed_1636896354557.png +0 -0
  71. package/logs/screenshot_2021_11_14_13_29_32_326Z_viewport_failed_1636896572326.png +0 -0
  72. package/logs/screenshot_2021_11_14_13_34_22_483Z_viewport_failed_1636896862483.png +0 -0
  73. package/logs/screenshot_2021_11_14_13_37_25_734Z_viewport_failed_1636897045734.png +0 -0
  74. package/logs/screenshot_2021_11_14_13_42_25_024Z_viewport_failed_1636897345024.png +0 -0
  75. package/logs/screenshot_2021_11_14_13_57_24_366Z_full_app_failed_1636898244366.png +0 -0
  76. package/logs/screenshot_2021_11_14_14_20_42_951Z_full_app_failed_1636899642951.png +0 -0
  77. package/logs/screenshot_2021_11_14_14_31_07_853Z_full_app_failed_1636900267853.png +0 -0
  78. package/logs/screenshot_2021_11_14_14_32_07_195Z_full_app_failed_1636900327195.png +0 -0
  79. package/logs/screenshot_2021_11_14_14_42_16_716Z_full_app_failed_1636900936716.png +0 -0
  80. package/logs/screenshot_2021_11_14_14_47_37_646Z_full_app_failed_1636901257646.png +0 -0
  81. package/logs/screenshot_2021_11_14_14_54_18_522Z_full_app_failed_1636901658522.png +0 -0
  82. package/logs/screenshot_2021_11_14_14_55_36_756Z_full_app_failed_1636901736756.png +0 -0
  83. package/logs/screenshot_2021_11_14_15_00_26_000Z_full_app_failed_1636902026000.png +0 -0
  84. package/logs/screenshot_2021_11_14_15_04_13_598Z_full_app_failed_1636902253598.png +0 -0
  85. package/logs/screenshot_2021_11_14_15_07_37_914Z_full_app_failed_1636902457914.png +0 -0
  86. package/logs/screenshot_2021_11_14_15_12_20_039Z_full_app_failed_1636902740039.png +0 -0
  87. package/logs/screenshot_2021_11_14_15_15_44_401Z_full_app_failed_1636902944401.png +0 -0
  88. package/logs/screenshot_2021_11_14_15_26_23_318Z_viewport_failed_1636903583318.png +0 -0
  89. package/src/calculate-screenshot-regions.js +0 -31
  90. package/src/screenshoter.js +0 -159
  91. package/test/fixtures/pattern/iPad_Air_portrait.png +0 -0
  92. package/test/fixtures/pattern/iPhone_5S_landscape.png +0 -0
  93. package/test/fixtures/pattern/iPhone_XR_perfecto_landscape.png +0 -0
  94. package/test/fixtures/pattern/iPhone_XS_Max_perfecto_landscape.png +0 -0
  95. package/test/fixtures/pattern/iPhone_XS_landscape.png +0 -0
  96. package/test/fixtures/pattern/iPhone_XS_portrait.png +0 -0
  97. package/test/fixtures/pattern/iPhone_X_perfecto_portrait.png +0 -0
@@ -1,25 +1,166 @@
1
1
  const utils = require('@applitools/utils')
2
- const makeTakeScreenshot = require('./take-screenshot')
2
+ const snippets = require('@applitools/snippets')
3
+ const findImagePattern = require('./find-image-pattern')
4
+ const makeImage = require('./image')
3
5
 
4
- async function takeViewportScreenshot({context, region, withStatusBar, wait, stabilization, debug = {}, logger}) {
5
- logger.verbose('Taking image of...')
6
+ function makeTakeViewportScreenshot(options) {
7
+ const {driver} = options
8
+ if (driver.isNative) {
9
+ return makeTakeNativeScreenshot(options)
10
+ } else if (driver.isIOS) {
11
+ // safari on ios takes screenshot with browser and os interfaces
12
+ return makeTakeMarkedScreenshot(options)
13
+ } else if (driver.browserName === 'Firefox') {
14
+ try {
15
+ const browserVersion = Number.parseInt(driver.browserVersion, 10)
16
+ if (browserVersion >= 48 && browserVersion <= 72) {
17
+ // firefox between versions 48 and 72 takes current frame screenshot only
18
+ return makeTakeMainContextScreenshot(options)
19
+ }
20
+ } catch (ignored) {}
21
+ } else if (driver.browserName === 'Safari' && driver.browserVersion === '11') {
22
+ // safari 11 on macs takes full page screenshot
23
+ return makeTakeSafari11Screenshot(options)
24
+ }
25
+
26
+ return makeTakeDefaultScreenshot(options)
27
+ }
28
+
29
+ function makeTakeDefaultScreenshot({driver, stabilization = {}, debug, logger}) {
30
+ return async function takeScreenshot({name} = {}) {
31
+ logger.verbose('Taking screenshot...')
32
+ const image = makeImage(await driver.takeScreenshot())
33
+ await image.debug({...debug, name, suffix: 'original'})
34
+
35
+ if (stabilization.scale) image.scale(stabilization.scale)
36
+ else image.scale(1 / driver.pixelRatio)
37
+
38
+ if (stabilization.rotate) image.crop(stabilization.rotate)
39
+
40
+ if (stabilization.crop) image.crop(stabilization.crop)
41
+
42
+ return image
43
+ }
44
+ }
45
+
46
+ function makeTakeMainContextScreenshot({driver, stabilization = {}, debug, logger}) {
47
+ return async function takeScreenshot({name} = {}) {
48
+ logger.verbose('Taking screenshot...')
49
+ const originalContext = driver.currentContext
50
+ await driver.mainContext.focus()
51
+ const image = makeImage(await driver.takeScreenshot())
52
+ await originalContext.focus()
53
+ await image.debug({...debug, name, suffix: 'original'})
54
+
55
+ if (stabilization.scale) image.scale(stabilization.scale)
56
+ else image.scale(1 / driver.pixelRatio)
57
+
58
+ if (stabilization.rotate) image.rotate(stabilization.rotate)
59
+
60
+ if (stabilization.crop) image.crop(stabilization.crop)
61
+
62
+ return image
63
+ }
64
+ }
65
+
66
+ function makeTakeSafari11Screenshot({driver, stabilization = {}, debug, logger}) {
67
+ let viewportSize
68
+
69
+ return async function takeScreenshot({name} = {}) {
70
+ logger.verbose('Taking safari 11 driver screenshot...')
71
+ const image = makeImage(await driver.takeScreenshot())
72
+ await image.debug({...debug, name, suffix: 'original'})
73
+
74
+ if (stabilization.scale) image.scale(stabilization.scale)
75
+ else image.scale(1 / driver.pixelRatio)
76
+
77
+ if (stabilization.rotate) image.rotate(stabilization.rotate)
78
+
79
+ if (stabilization.crop) image.crop(stabilization.crop)
80
+ else {
81
+ if (!viewportSize) viewportSize = await driver.getViewportSize()
82
+ const viewportLocation = await driver.mainContext.execute(snippets.getElementScrollOffset, [])
83
+ image.crop(utils.geometry.region(viewportLocation, viewportSize))
84
+ }
85
+
86
+ return image
87
+ }
88
+ }
89
+
90
+ function makeTakeMarkedScreenshot({driver, stabilization = {}, debug, logger}) {
91
+ let viewportRegion
92
+
93
+ return async function takeScreenshot({name} = {}) {
94
+ logger.verbose('Taking viewport screenshot (using markers)...')
95
+ const image = makeImage(await driver.takeScreenshot())
96
+ await image.debug({...debug, name, suffix: 'original'})
97
+
98
+ if (stabilization.scale) image.scale(stabilization.scale)
99
+ else image.scale(1 / driver.pixelRatio)
100
+
101
+ if (stabilization.rotate) image.rotate(stabilization.rotate)
102
+ else if (driver.orientation === 'landscape' && image.width < image.height) image.rotate(-90)
103
+
104
+ if (stabilization.crop) image.crop(stabilization.crop)
105
+ else {
106
+ if (!viewportRegion) viewportRegion = await getViewportRegion()
107
+ if (viewportRegion) image.crop(viewportRegion)
108
+ }
109
+
110
+ await image.debug({...debug, name, suffix: 'viewport'})
111
+
112
+ return image
113
+ }
114
+
115
+ async function getViewportRegion() {
116
+ const marker = await driver.mainContext.execute(snippets.addPageMarker)
117
+ await utils.general.sleep(100)
118
+
119
+ try {
120
+ const image = makeImage(await driver.takeScreenshot())
121
+
122
+ if (stabilization.rotate) image.rotate(stabilization.rotate)
123
+ else if (driver.orientation === 'landscape' && image.width < image.height) image.rotate(-90)
124
+
125
+ await image.debug({...debug, name: 'marker'})
126
+
127
+ const markerLocation = findImagePattern(await image.toObject(), {...marker, pixelRatio: driver.pixelRatio})
128
+ if (!markerLocation) return null
129
+
130
+ const viewportSize = await driver.getViewportSize()
131
+
132
+ return utils.geometry.region(utils.geometry.scale(markerLocation, 1 / driver.pixelRatio), viewportSize)
133
+ } finally {
134
+ await driver.mainContext.execute(snippets.cleanupPageMarker)
135
+ }
136
+ }
137
+ }
138
+
139
+ function makeTakeNativeScreenshot({driver, stabilization = {}, debug, logger}) {
140
+ return async function takeScreenshot({name, withStatusBar} = {}) {
141
+ logger.verbose('Taking native driver screenshot...')
142
+ const image = makeImage(await driver.takeScreenshot())
143
+ await image.debug({...debug, name, suffix: 'original'})
144
+
145
+ if (stabilization.scale) image.scale(stabilization.scale)
146
+ else image.scale(1 / driver.pixelRatio)
6
147
 
7
- const driver = context.driver
8
- const takeScreenshot = makeTakeScreenshot({logger, driver, stabilization, debug})
148
+ if (stabilization.rotate) image.rotate(stabilization.rotate)
149
+ else if (driver.orientation === 'landscape' && image.width < image.height) image.rotate(-90)
9
150
 
10
- await utils.general.sleep(wait)
151
+ if (stabilization.crop) image.crop(stabilization.crop)
152
+ else {
153
+ const viewportSize = await driver.getViewportSize()
154
+ const cropRegion = withStatusBar
155
+ ? {x: 0, y: 0, width: viewportSize.width, height: viewportSize.height + driver.statusBarHeight}
156
+ : {top: driver.statusBarHeight, bottom: driver.navigationBarHeight, left: 0, right: 0}
157
+ image.crop(cropRegion)
158
+ }
11
159
 
12
- const image = await takeScreenshot({withStatusBar})
160
+ await image.debug({...debug, name, suffix: `viewport${withStatusBar ? '-with-statusbar' : ''}`})
13
161
 
14
- if (region) {
15
- const cropRegion = await driver.getRegionInViewport(context, region)
16
- if (utils.geometry.isEmpty(cropRegion)) throw new Error('Screenshot region is out of viewport')
17
- image.crop(cropRegion)
18
- await image.debug({path: debug.path, suffix: 'region'})
19
- return {image, region: cropRegion}
20
- } else {
21
- return {image, region: utils.geometry.region({x: 0, y: 0}, image.size)}
162
+ return image
22
163
  }
23
164
  }
24
165
 
25
- module.exports = takeViewportScreenshot
166
+ module.exports = makeTakeViewportScreenshot
@@ -3,7 +3,7 @@ const pixelmatch = require('pixelmatch')
3
3
  const {Driver} = require('@applitools/driver')
4
4
  const spec = require('@applitools/spec-driver-webdriverio')
5
5
  const makeImage = require('../../src/image')
6
- const screenshoter = require('../../index')
6
+ const takeScreenshot = require('../../index')
7
7
 
8
8
  const env = {
9
9
  android: {
@@ -20,6 +20,17 @@ const env = {
20
20
  username: process.env.SAUCE_USERNAME,
21
21
  accessKey: process.env.SAUCE_ACCESS_KEY,
22
22
  },
23
+
24
+ // url: 'http://0.0.0.0:4723/wd/hub',
25
+ // capabilities: {
26
+ // deviceName: 'Google Pixel 3a XL',
27
+ // platformName: 'Android',
28
+ // platformVersion: '10.0',
29
+ // automationName: 'uiautomator2',
30
+ // nativeWebScreenshot: true,
31
+ // avd: 'Pixel_3a_XL',
32
+ // app: 'https://applitools.jfrog.io/artifactory/Examples/android/1.3/app-debug.apk',
33
+ // },
23
34
  },
24
35
  androidx: {
25
36
  url: 'https://ondemand.saucelabs.com/wd/hub',
@@ -31,10 +42,20 @@ const env = {
31
42
  appiumVersion: '1.20.2',
32
43
  deviceName: 'Google Pixel 3a XL GoogleAPI Emulator',
33
44
  automationName: 'uiautomator2',
34
- app: 'https://applitools.jfrog.io/artifactory/Examples/androidx/1.2.0/app_androidx.apk',
45
+ app: 'https://applitools.jfrog.io/artifactory/Examples/androidx/1.3.1/app_androidx.apk',
35
46
  username: process.env.SAUCE_USERNAME,
36
47
  accessKey: process.env.SAUCE_ACCESS_KEY,
37
48
  },
49
+
50
+ // url: 'http://0.0.0.0:4723/wd/hub',
51
+ // capabilities: {
52
+ // deviceName: 'Google Pixel 3a XL',
53
+ // platformName: 'Android',
54
+ // platformVersion: '10.0',
55
+ // automationName: 'uiautomator2',
56
+ // avd: 'Pixel_3a_XL',
57
+ // app: 'https://applitools.jfrog.io/artifactory/Examples/androidx/1.3.3/app_androidx.apk',
58
+ // },
38
59
  },
39
60
  }
40
61
 
@@ -90,6 +111,10 @@ describe('screenshoter', () => {
90
111
  return fullApp({type: 'non-scrollable'})
91
112
  })
92
113
 
114
+ it.skip('take webview screenshot', () => {
115
+ return webview()
116
+ })
117
+
93
118
  it('take region screenshot', () => {
94
119
  return region()
95
120
  })
@@ -122,6 +147,18 @@ describe('screenshoter', () => {
122
147
  return fullApp({type: 'recycler', x: true})
123
148
  })
124
149
 
150
+ it('take full app screenshot (collapsing layout)', () => {
151
+ return fullApp({type: 'collapsing', x: true})
152
+ })
153
+
154
+ it.skip('take full app screenshot (pager)', () => {
155
+ return fullApp({type: 'pager', x: true})
156
+ })
157
+
158
+ it.skip('take full app screenshot (overlapped status bar)', () => {
159
+ return fullApp({type: 'overlapped', x: true})
160
+ })
161
+
125
162
  it('take full element screenshot', () => {
126
163
  return fullElement()
127
164
  })
@@ -130,7 +167,7 @@ describe('screenshoter', () => {
130
167
  async function app(options = {}) {
131
168
  const expectedPath = `./test/fixtures/android/app${options.withStatusBar ? '-statusbar' : ''}.png`
132
169
 
133
- const screenshot = await screenshoter({logger, driver, wait: 1500, ...options})
170
+ const screenshot = await takeScreenshot({logger, driver, wait: 1500, ...options})
134
171
  try {
135
172
  if (options.withStatusBar) await sanitizeStatusBar(screenshot.image)
136
173
  const actual = await screenshot.image.toObject()
@@ -142,8 +179,18 @@ describe('screenshoter', () => {
142
179
  }
143
180
  }
144
181
  async function fullApp({type, x, ...options} = {}) {
145
- let buttonSelector, expectedPath
146
- if (type === 'recycler') {
182
+ let buttonSelector, expectedPath, scrollingElementSelector
183
+ if (type === 'pager') {
184
+ buttonSelector = {type: 'id', selector: 'btn_view_pager_2_activity'}
185
+ expectedPath = `./test/fixtures/android/x-app-fully-pager${options.withStatusBar ? '-statusbar' : ''}.png`
186
+ } else if (type === 'overlapped') {
187
+ buttonSelector = {type: 'id', selector: 'btn_recycler_view_under_status_bar_activity'}
188
+ expectedPath = `./test/fixtures/android/x-app-fully-overlapped${options.withStatusBar ? '-statusbar' : ''}.png`
189
+ } else if (type === 'collapsing') {
190
+ buttonSelector = {type: 'id', selector: 'btn_recycler_view_nested_collapsing'}
191
+ scrollingElementSelector = {type: 'id', selector: 'recyclerView'}
192
+ expectedPath = `./test/fixtures/android/x-app-fully-collapsing${options.withStatusBar ? '-statusbar' : ''}.png`
193
+ } else if (type === 'recycler') {
147
194
  if (x) {
148
195
  buttonSelector = {type: 'id', selector: 'btn_recycler_view_activity'}
149
196
  expectedPath = `./test/fixtures/android/x-app-fully-recycler${options.withStatusBar ? '-statusbar' : ''}.png`
@@ -152,7 +199,7 @@ describe('screenshoter', () => {
152
199
  expectedPath = `./test/fixtures/android/app-fully-recycler${options.withStatusBar ? '-statusbar' : ''}.png`
153
200
  }
154
201
  } else if (type === 'non-scrollable') {
155
- buttonSelector = {type: 'id', selector: 'btn_edit_text'}
202
+ buttonSelector = {type: 'id', selector: 'btn_activity_as_dialog'}
156
203
  expectedPath = `./test/fixtures/android/app-fully-non-scrollable${options.withStatusBar ? '-statusbar' : ''}.png`
157
204
  } else {
158
205
  buttonSelector = {type: 'id', selector: 'btn_scroll_view_footer_header'}
@@ -162,7 +209,13 @@ describe('screenshoter', () => {
162
209
  const button = await driver.element(buttonSelector)
163
210
  await button.click()
164
211
 
165
- const screenshot = await screenshoter({
212
+ await driver.init()
213
+
214
+ if (scrollingElementSelector) {
215
+ await driver.currentContext.setScrollingElement(scrollingElementSelector)
216
+ }
217
+
218
+ const screenshot = await takeScreenshot({
166
219
  logger,
167
220
  driver,
168
221
  fully: true,
@@ -181,8 +234,28 @@ describe('screenshoter', () => {
181
234
  throw err
182
235
  }
183
236
  }
237
+ async function webview(options) {
238
+ const expectedPath = `./test/fixtures/android/webview.png`
239
+ const buttonSelector = {type: 'id', selector: 'btn_web_view'}
240
+
241
+ const button = await driver.element(buttonSelector)
242
+ await button.click()
243
+ await driver.target.switchContext('WEBVIEW')
244
+
245
+ await driver.init()
246
+
247
+ const screenshot = await takeScreenshot({logger, driver, wait: 1500, ...options})
248
+ try {
249
+ const actual = await screenshot.image.toObject()
250
+ const expected = await makeImage(expectedPath).toObject()
251
+ assert.strictEqual(pixelmatch(actual.data, expected.data, null, expected.width, expected.height), 0)
252
+ } catch (err) {
253
+ await screenshot.image.debug({path: './logs', name: 'webview_failed', suffix: Date.now()})
254
+ throw err
255
+ }
256
+ }
184
257
  async function region(options) {
185
- const screenshot = await screenshoter({
258
+ const screenshot = await takeScreenshot({
186
259
  logger,
187
260
  driver,
188
261
  region: {x: 30, y: 500, height: 100, width: 200},
@@ -199,7 +272,7 @@ describe('screenshoter', () => {
199
272
  }
200
273
  }
201
274
  async function fullRegion(options) {
202
- const screenshot = await screenshoter({
275
+ const screenshot = await takeScreenshot({
203
276
  logger,
204
277
  driver,
205
278
  region: {x: 30, y: 10, height: 700, width: 200},
@@ -217,7 +290,7 @@ describe('screenshoter', () => {
217
290
  }
218
291
  }
219
292
  async function element(options) {
220
- const screenshot = await screenshoter({
293
+ const screenshot = await takeScreenshot({
221
294
  logger,
222
295
  driver,
223
296
  region: {type: 'id', selector: 'btn_recycler_view'},
@@ -240,7 +313,7 @@ describe('screenshoter', () => {
240
313
  })
241
314
  await button.click()
242
315
 
243
- const screenshot = await screenshoter({
316
+ const screenshot = await takeScreenshot({
244
317
  logger,
245
318
  driver,
246
319
  region: {type: 'id', selector: 'recyclerView'},
@@ -4,7 +4,7 @@ const {Driver} = require('@applitools/driver')
4
4
  const utils = require('@applitools/utils')
5
5
  const spec = require('@applitools/spec-driver-webdriverio')
6
6
  const makeImage = require('../../src/image')
7
- const screenshoter = require('../../index')
7
+ const takeScreenshot = require('../../index')
8
8
 
9
9
  describe.skip('external tests', () => {
10
10
  const logger = {log: () => {}, warn: () => {}, error: () => {}, verbose: () => {}}
@@ -14,7 +14,7 @@ describe.skip('external tests', () => {
14
14
  await destroyBrowser()
15
15
  })
16
16
 
17
- it('AGL - full app screenshot of the view with animated scroll', async () => {
17
+ it('AGL Android - full app screenshot of the view with animated scroll', async () => {
18
18
  const expectedPath = `./test/fixtures/external/agl.png`
19
19
 
20
20
  ;[browser, destroyBrowser] = await spec.build({
@@ -23,7 +23,7 @@ describe.skip('external tests', () => {
23
23
  platformName: 'android',
24
24
  'appium:platformVersion': '11.0',
25
25
  'appium:deviceName': 'Google Pixel 5',
26
- 'appium:app': 'android_agl_app',
26
+ 'appium:app': 'agl_app_android',
27
27
  'bstack:options': {
28
28
  userName: process.env.BROWSERSTACK_USERNAME,
29
29
  accessKey: process.env.BROWSERSTACK_ACCESS_KEY,
@@ -41,18 +41,17 @@ describe.skip('external tests', () => {
41
41
  await utils.general.sleep(8000)
42
42
  const signinBtn = await browser.$('//android.widget.Button[@text="SIGN IN"]')
43
43
  await signinBtn.click()
44
- await utils.general.sleep(8000)
44
+ await utils.general.sleep(10000)
45
45
  const emailInput = await browser.$('//android.widget.EditText')
46
46
  await emailInput.setValue('daniel.martin@toro.com')
47
47
  const nxtBtn = await browser.$('//android.widget.Button[@text="NEXT"]')
48
48
  await nxtBtn.click()
49
- await utils.general.sleep(8000)
49
+ await utils.general.sleep(10000)
50
50
  const passwordInput = await browser.$('//android.widget.EditText[@password="true"]')
51
51
  await passwordInput.setValue('Welcome@1')
52
52
  const loginBtn = await browser.$('//android.widget.Button[@text="LOGIN"]')
53
53
  await loginBtn.click()
54
54
  await utils.general.sleep(18000)
55
-
56
55
  const skipBtn = await browser.$('//android.widget.Button[@text="SKIP"]')
57
56
  await skipBtn.click()
58
57
  await utils.general.sleep(5000)
@@ -60,11 +59,9 @@ describe.skip('external tests', () => {
60
59
  await finishBtn.click()
61
60
  await utils.general.sleep(15000)
62
61
 
63
- // const billingBtn = await browser.$('//android.widget.FrameLayout[@content-desc="Billing"]')
64
- // await billingBtn.click()
65
- // await utils.general.sleep(25000)
62
+ await driver.init()
66
63
 
67
- const screenshot = await screenshoter({
64
+ const screenshot = await takeScreenshot({
68
65
  logger,
69
66
  driver,
70
67
  fully: true,
@@ -81,4 +78,78 @@ describe.skip('external tests', () => {
81
78
  throw err
82
79
  }
83
80
  })
81
+
82
+ it('AGL iOS - full app screenshot of the view with animated scroll', async () => {
83
+ const expectedPath = `./test/fixtures/external/agl.png`
84
+ ;[browser, destroyBrowser] = await spec.build({
85
+ url: 'https://hub.browserstack.com/wd/hub',
86
+ capabilities: {
87
+ platformName: 'ios',
88
+ 'appium:platformVersion': '14',
89
+ 'appium:deviceName': 'iPhone 12',
90
+ 'appium:app': 'agl_app',
91
+ 'appium:processArguments': `{
92
+ "args": [
93
+ "-dev.environment", "qtrtest",
94
+ "-dev.clear.keychain", "YES",
95
+ "-dev.keychain.shared", "NO",
96
+ "-user.lastQuickTourVersionCompleted", "0"
97
+ ],
98
+ "env": {
99
+ "DYLD_INSERT_LIBRARIES": "@executable_path/Frameworks/EyesiOSHelper.xcframework/ios-arm64/EyesiOSHelper.framework/EyesiOSHelper"
100
+ }
101
+ }`,
102
+ 'bstack:options': {
103
+ userName: process.env.BROWSERSTACK_USERNAME,
104
+ accessKey: process.env.BROWSERSTACK_ACCESS_KEY,
105
+ },
106
+ },
107
+ })
108
+
109
+ await browser.closeApp()
110
+ await browser.launchApp()
111
+ const driver = await new Driver({driver: browser, spec, logger}).init()
112
+
113
+ await browser.acceptAlert()
114
+
115
+ await utils.general.sleep(8000)
116
+ const signinBtn = await browser.$('//XCUIElementTypeButton[@name="SIGN IN"]')
117
+ await signinBtn.click()
118
+ await utils.general.sleep(8000)
119
+ const emailInput = await browser.$('//XCUIElementTypeTextField')
120
+ await emailInput.setValue('daniel.martin@toro.com')
121
+ const nxtBtn = await browser.$('//XCUIElementTypeButton[@name="NEXT"]')
122
+ await nxtBtn.click()
123
+ await utils.general.sleep(8000)
124
+ const passwordInput = await browser.$('//XCUIElementTypeSecureTextField')
125
+ await passwordInput.setValue('Welcome@1')
126
+ const loginBtn = await browser.$('//XCUIElementTypeButton[@name="LOGIN"]')
127
+ await loginBtn.click()
128
+ await utils.general.sleep(18000)
129
+ const skipBtn = await browser.$('//XCUIElementTypeButton[@name="Skip"]')
130
+ await skipBtn.click()
131
+ await utils.general.sleep(5000)
132
+ const finishBtn = await browser.$('//XCUIElementTypeButton[@name="Finish"]')
133
+ await finishBtn.click()
134
+ await utils.general.sleep(20000)
135
+
136
+ await driver.init()
137
+
138
+ const screenshot = await takeScreenshot({
139
+ logger,
140
+ driver,
141
+ fully: true,
142
+ framed: true,
143
+ wait: 1500,
144
+ // debug: {path: './'},
145
+ })
146
+ try {
147
+ const actual = await screenshot.image.toObject()
148
+ const expected = await makeImage(expectedPath).toObject()
149
+ assert.strictEqual(pixelmatch(actual.data, expected.data, null, expected.width, expected.height), 0)
150
+ } catch (err) {
151
+ await screenshot.image.debug({path: './logs', name: 'viewport_failed', suffix: Date.now()})
152
+ throw err
153
+ }
154
+ })
84
155
  })