@applitools/screenshoter 3.2.9 → 3.3.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 (98) hide show
  1. package/.bongo/dry-run/package-lock.json +11 -11
  2. package/.bongo/dry-run.tgz +0 -0
  3. package/CHANGELOG.md +6 -0
  4. package/index.js +2 -1
  5. package/logs/screenshot_2021_12_16_19_06_06_332Z_full_app_failed_1639681566332.png +0 -0
  6. package/logs/screenshot_2021_12_16_19_15_59_935Z_full_app_failed_1639682159935.png +0 -0
  7. package/logs/screenshot_2021_12_16_19_33_20_679Z_full_app_failed_1639683200679.png +0 -0
  8. package/logs/screenshot_2021_12_16_19_37_22_120Z_ios_viewport_failed.png +0 -0
  9. package/logs/screenshot_2021_12_16_19_38_09_461Z_ios_full_page_failed.png +0 -0
  10. package/logs/screenshot_2021_12_16_19_59_45_182Z_ios_viewport_failed.png +0 -0
  11. package/package.json +5 -5
  12. package/src/find-image-pattern.js +10 -38
  13. package/src/image.js +104 -64
  14. package/src/take-screenshot.js +136 -160
  15. package/src/take-simple-screenshot.js +25 -0
  16. package/src/take-stitched-screenshot.js +32 -52
  17. package/src/take-viewport-screenshot.js +179 -16
  18. package/test/e2e/android.spec.js +42 -11
  19. package/test/e2e/external.spec.js +81 -10
  20. package/test/e2e/ios.spec.js +48 -10
  21. package/test/e2e/web-ios.spec.js +3 -5
  22. package/test/e2e/web.spec.js +20 -15
  23. package/test/fixtures/android/app-fully-non-scrollable.png +0 -0
  24. package/test/fixtures/android/app-fully-recycler.png +0 -0
  25. package/test/fixtures/android/app-fully-scroll-statusbar.png +0 -0
  26. package/test/fixtures/android/app-fully-scroll.png +0 -0
  27. package/test/fixtures/android/app-statusbar.png +0 -0
  28. package/test/fixtures/android/x-app-fully-collapsing.png +0 -0
  29. package/test/fixtures/android/x-app-fully-recycler.png +0 -0
  30. package/test/fixtures/android/x-element-fully.png +0 -0
  31. package/test/fixtures/image/{house.combined-higher-wider.png → house.framed-higher-wider.png} +0 -0
  32. package/test/fixtures/image/{house.combined-higher.png → house.framed-higher.png} +0 -0
  33. package/test/fixtures/image/house.framed-shorter-thinner.png +0 -0
  34. package/test/fixtures/image/{house.combined-wider.png → house.framed-wider.png} +0 -0
  35. package/test/fixtures/ios/app-fully-collapsing.png +0 -0
  36. package/test/fixtures/ios/app-fully-collection.png +0 -0
  37. package/test/fixtures/ios/app-fully-overlapped-statusbar.png +0 -0
  38. package/test/fixtures/ios/app-fully-overlapped.png +0 -0
  39. package/test/fixtures/ios/app-fully-scroll-statusbar.png +0 -0
  40. package/test/fixtures/ios/app-fully-scroll.png +0 -0
  41. package/test/fixtures/ios/app-fully-superview.png +0 -0
  42. package/test/fixtures/ios/app-fully-table.png +0 -0
  43. package/test/fixtures/ios/app-statusbar.png +0 -0
  44. package/test/fixtures/ios/app.png +0 -0
  45. package/test/fixtures/ios/element-fully.png +0 -0
  46. package/test/fixtures/ios/element.png +0 -0
  47. package/test/fixtures/ios/region.png +0 -0
  48. package/test/fixtures/pattern/iPad_5th_landscape.png +0 -0
  49. package/test/fixtures/pattern/iPad_5th_portrait.png +0 -0
  50. package/test/fixtures/pattern/iPad_9th_landscape.png +0 -0
  51. package/test/fixtures/pattern/iPad_9th_portrait.png +0 -0
  52. package/test/fixtures/pattern/iPhone_11_landscape.png +0 -0
  53. package/test/fixtures/pattern/iPhone_11_portrait.png +0 -0
  54. package/test/fixtures/pattern/iPhone_13_landscape.png +0 -0
  55. package/test/fixtures/pattern/iPhone_13_portrait.png +0 -0
  56. package/test/fixtures/pattern/iPhone_SE_landscape.png +0 -0
  57. package/test/fixtures/pattern/iPhone_SE_portrait.png +0 -0
  58. package/test/fixtures/pattern/iPhone_XS_portrait_noviewport.png +0 -0
  59. package/test/fixtures/web-ios/page-fully.png +0 -0
  60. package/test/fixtures/web-ios/page.png +0 -0
  61. package/test/it/find-pattern.spec.js +16 -11
  62. package/test/it/image.spec.js +42 -15
  63. package/logs/screenshot_2021_11_14_12_35_00_342Z_full_frame_failed.png +0 -0
  64. package/logs/screenshot_2021_11_14_12_38_00_715Z_frame_failed.png +0 -0
  65. package/logs/screenshot_2021_11_14_12_38_03_866Z_frame_failed.png +0 -0
  66. package/logs/screenshot_2021_11_14_13_02_56_464Z_full_app_failed_1636894976464.png +0 -0
  67. package/logs/screenshot_2021_11_14_13_04_27_904Z_full_app_failed_1636895067904.png +0 -0
  68. package/logs/screenshot_2021_11_14_13_06_13_662Z_full_app_failed_1636895173662.png +0 -0
  69. package/logs/screenshot_2021_11_14_13_06_23_745Z_full_app_failed_1636895183745.png +0 -0
  70. package/logs/screenshot_2021_11_14_13_18_31_571Z_full_app_failed_1636895911571.png +0 -0
  71. package/logs/screenshot_2021_11_14_13_25_54_557Z_viewport_failed_1636896354557.png +0 -0
  72. package/logs/screenshot_2021_11_14_13_29_32_326Z_viewport_failed_1636896572326.png +0 -0
  73. package/logs/screenshot_2021_11_14_13_34_22_483Z_viewport_failed_1636896862483.png +0 -0
  74. package/logs/screenshot_2021_11_14_13_37_25_734Z_viewport_failed_1636897045734.png +0 -0
  75. package/logs/screenshot_2021_11_14_13_42_25_024Z_viewport_failed_1636897345024.png +0 -0
  76. package/logs/screenshot_2021_11_14_13_57_24_366Z_full_app_failed_1636898244366.png +0 -0
  77. package/logs/screenshot_2021_11_14_14_20_42_951Z_full_app_failed_1636899642951.png +0 -0
  78. package/logs/screenshot_2021_11_14_14_31_07_853Z_full_app_failed_1636900267853.png +0 -0
  79. package/logs/screenshot_2021_11_14_14_32_07_195Z_full_app_failed_1636900327195.png +0 -0
  80. package/logs/screenshot_2021_11_14_14_42_16_716Z_full_app_failed_1636900936716.png +0 -0
  81. package/logs/screenshot_2021_11_14_14_47_37_646Z_full_app_failed_1636901257646.png +0 -0
  82. package/logs/screenshot_2021_11_14_14_54_18_522Z_full_app_failed_1636901658522.png +0 -0
  83. package/logs/screenshot_2021_11_14_14_55_36_756Z_full_app_failed_1636901736756.png +0 -0
  84. package/logs/screenshot_2021_11_14_15_00_26_000Z_full_app_failed_1636902026000.png +0 -0
  85. package/logs/screenshot_2021_11_14_15_04_13_598Z_full_app_failed_1636902253598.png +0 -0
  86. package/logs/screenshot_2021_11_14_15_07_37_914Z_full_app_failed_1636902457914.png +0 -0
  87. package/logs/screenshot_2021_11_14_15_12_20_039Z_full_app_failed_1636902740039.png +0 -0
  88. package/logs/screenshot_2021_11_14_15_15_44_401Z_full_app_failed_1636902944401.png +0 -0
  89. package/logs/screenshot_2021_11_14_15_26_23_318Z_viewport_failed_1636903583318.png +0 -0
  90. package/src/calculate-screenshot-regions.js +0 -31
  91. package/src/screenshoter.js +0 -159
  92. package/test/fixtures/pattern/iPad_Air_portrait.png +0 -0
  93. package/test/fixtures/pattern/iPhone_5S_landscape.png +0 -0
  94. package/test/fixtures/pattern/iPhone_XR_perfecto_landscape.png +0 -0
  95. package/test/fixtures/pattern/iPhone_XS_Max_perfecto_landscape.png +0 -0
  96. package/test/fixtures/pattern/iPhone_XS_landscape.png +0 -0
  97. package/test/fixtures/pattern/iPhone_XS_portrait.png +0 -0
  98. package/test/fixtures/pattern/iPhone_X_perfecto_portrait.png +0 -0
@@ -2,7 +2,7 @@ const assert = require('assert')
2
2
  const pixelmatch = require('pixelmatch')
3
3
  const {Driver} = require('@applitools/driver')
4
4
  const spec = require('@applitools/spec-driver-webdriverio')
5
- const screenshoter = require('../../index')
5
+ const takeScreenshot = require('../../index')
6
6
  const makeImage = require('../../src/image')
7
7
 
8
8
  const env = {
@@ -128,7 +128,7 @@ describe('screenshoter web', () => {
128
128
  })
129
129
 
130
130
  async function viewport(options) {
131
- const screenshot = await screenshoter({logger, driver, ...options})
131
+ const screenshot = await takeScreenshot({logger, driver, ...options})
132
132
  try {
133
133
  const actual = await screenshot.image.toObject()
134
134
  const expected = await makeImage('./test/fixtures/web/page.png').toObject()
@@ -139,7 +139,7 @@ describe('screenshoter web', () => {
139
139
  }
140
140
  }
141
141
  async function fullPage(options) {
142
- const screenshot = await screenshoter({logger, driver, fully: true, ...options})
142
+ const screenshot = await takeScreenshot({logger, driver, fully: true, ...options})
143
143
  try {
144
144
  const actual = await screenshot.image.toObject()
145
145
  const expected = await makeImage('./test/fixtures/web/page-fully.png').toObject()
@@ -150,7 +150,12 @@ describe('screenshoter web', () => {
150
150
  }
151
151
  }
152
152
  async function frame(options) {
153
- const screenshot = await screenshoter({logger, driver, frames: [{reference: 'iframe[name="frame1"]'}], ...options})
153
+ const screenshot = await takeScreenshot({
154
+ logger,
155
+ driver,
156
+ frames: [{reference: 'iframe[name="frame1"]'}],
157
+ ...options,
158
+ })
154
159
  try {
155
160
  const actual = await screenshot.image.toObject()
156
161
  const expected = await makeImage('./test/fixtures/web/frame.png').toObject()
@@ -161,7 +166,7 @@ describe('screenshoter web', () => {
161
166
  }
162
167
  }
163
168
  async function fullFrame(options) {
164
- const screenshot = await screenshoter({
169
+ const screenshot = await takeScreenshot({
165
170
  logger,
166
171
  driver,
167
172
  frames: [{reference: 'iframe[name="frame1"]'}],
@@ -179,7 +184,7 @@ describe('screenshoter web', () => {
179
184
  }
180
185
  async function region(options) {
181
186
  const region = {x: 30, y: 500, height: 100, width: 200}
182
- const screenshot = await screenshoter({logger, driver, region, ...options})
187
+ const screenshot = await takeScreenshot({logger, driver, region, ...options})
183
188
  try {
184
189
  const actual = await screenshot.image.toObject()
185
190
  const expected = await makeImage('./test/fixtures/web/region.png').toObject()
@@ -191,7 +196,7 @@ describe('screenshoter web', () => {
191
196
  }
192
197
  async function fullRegion(options) {
193
198
  const region = {x: 30, y: 500, height: 700, width: 200}
194
- const screenshot = await screenshoter({logger, driver, region, fully: true, ...options})
199
+ const screenshot = await takeScreenshot({logger, driver, region, fully: true, ...options})
195
200
  try {
196
201
  const actual = await screenshot.image.toObject()
197
202
  const expected = await makeImage('./test/fixtures/web/region-fully.png').toObject()
@@ -202,7 +207,7 @@ describe('screenshoter web', () => {
202
207
  }
203
208
  }
204
209
  async function element(options) {
205
- const screenshot = await screenshoter({logger, driver, region: '#overflowing-div-image', ...options})
210
+ const screenshot = await takeScreenshot({logger, driver, region: '#overflowing-div-image', ...options})
206
211
  try {
207
212
  const actual = await screenshot.image.toObject()
208
213
  const expected = await makeImage('./test/fixtures/web/element.png').toObject()
@@ -213,7 +218,7 @@ describe('screenshoter web', () => {
213
218
  }
214
219
  }
215
220
  async function fullElement(options) {
216
- const screenshot = await screenshoter({logger, driver, region: '#overflowing-div-image', fully: true, ...options})
221
+ const screenshot = await takeScreenshot({logger, driver, region: '#overflowing-div-image', fully: true, ...options})
217
222
  try {
218
223
  const actual = await screenshot.image.toObject()
219
224
  const expected = await makeImage('./test/fixtures/web/element-fully.png').toObject()
@@ -224,7 +229,7 @@ describe('screenshoter web', () => {
224
229
  }
225
230
  }
226
231
  async function regionInFrame(options) {
227
- const screenshot = await screenshoter({
232
+ const screenshot = await takeScreenshot({
228
233
  logger,
229
234
  driver,
230
235
  frames: [{reference: 'iframe[name="frame1"]'}],
@@ -241,7 +246,7 @@ describe('screenshoter web', () => {
241
246
  }
242
247
  }
243
248
  async function fullRegionInFrame(options) {
244
- const screenshot = await screenshoter({
249
+ const screenshot = await takeScreenshot({
245
250
  logger,
246
251
  driver,
247
252
  frames: [{reference: 'iframe[name="frame1"]'}],
@@ -259,7 +264,7 @@ describe('screenshoter web', () => {
259
264
  }
260
265
  }
261
266
  async function elementInFrame(options) {
262
- const screenshot = await screenshoter({
267
+ const screenshot = await takeScreenshot({
263
268
  logger,
264
269
  driver,
265
270
  frames: [{reference: 'iframe[name="frame1"]'}],
@@ -276,7 +281,7 @@ describe('screenshoter web', () => {
276
281
  }
277
282
  }
278
283
  async function fullElementInFrame(options) {
279
- const screenshot = await screenshoter({
284
+ const screenshot = await takeScreenshot({
280
285
  logger,
281
286
  driver,
282
287
  frames: [{reference: 'iframe[name="frame1"]'}],
@@ -294,7 +299,7 @@ describe('screenshoter web', () => {
294
299
  }
295
300
  }
296
301
  async function frameInFrame(options) {
297
- const screenshot = await screenshoter({
302
+ const screenshot = await takeScreenshot({
298
303
  logger,
299
304
  driver,
300
305
  frames: [{reference: 'iframe[name="frame1"]'}, {reference: 'iframe[name="frame1-1"]'}],
@@ -310,7 +315,7 @@ describe('screenshoter web', () => {
310
315
  }
311
316
  }
312
317
  async function fullFrameInFrame(options) {
313
- const screenshot = await screenshoter({
318
+ const screenshot = await takeScreenshot({
314
319
  logger,
315
320
  driver,
316
321
  frames: [{reference: 'iframe[name="frame1"]'}, {reference: 'iframe[name="frame1-1"]'}],
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -4,23 +4,28 @@ const findPattern = require('../../src/find-image-pattern')
4
4
 
5
5
  describe('pattern', () => {
6
6
  const fixtures = [
7
- {name: 'iPhone_5S_landscape', position: {x: 0, y: 100}, pixelRatio: 2},
8
- {name: 'iPhone_X_perfecto_portrait', position: {x: 0, y: 297}, pixelRatio: 3},
9
- {name: 'iPhone_XR_perfecto_landscape', position: {x: 88, y: 100}, pixelRatio: 2},
10
- {name: 'iPhone_XS_Max_perfecto_landscape', position: {x: 132, y: 150}, pixelRatio: 3},
11
- {name: 'iPhone_XS_landscape', position: {x: 132, y: 150}, pixelRatio: 3},
12
- {name: 'iPhone_XS_portrait', position: {x: 0, y: 282}, pixelRatio: 3},
13
- {name: 'iPad_Air_portrait', position: {x: 0, y: 140}, pixelRatio: 2},
7
+ {name: 'iPhone_SE_portrait', position: {x: 0, y: 140}, offset: 0, pixelRatio: 2},
8
+ {name: 'iPhone_SE_landscape', position: {x: 0, y: 100}, offset: 0, pixelRatio: 2},
9
+ {name: 'iPhone_11_portrait', position: {x: 0, y: 282}, offset: 0, pixelRatio: 3},
10
+ {name: 'iPhone_11_landscape', position: {x: 132, y: 150}, offset: 0, pixelRatio: 3},
11
+ {name: 'iPhone_13_portrait', position: {x: 0, y: 141}, offset: 0, pixelRatio: 3},
12
+ {name: 'iPhone_13_landscape', position: {x: 141, y: 144}, offset: 0, pixelRatio: 3},
13
+ {name: 'iPad_5th_portrait', position: {x: 0, y: 140}, offset: 0, pixelRatio: 2},
14
+ {name: 'iPad_5th_landscape', position: {x: 0, y: 140}, offset: 0, pixelRatio: 2},
15
+ {name: 'iPad_9th_portrait', position: {x: 0, y: 136}, offset: 0, pixelRatio: 2},
16
+ {name: 'iPad_9th_landscape', position: {x: 641, y: 137}, offset: 1, pixelRatio: 2},
17
+ {name: 'iPhone_XS_portrait_noviewport', position: {x: 0, y: 282}, offset: 0, pixelRatio: 3},
14
18
  {name: 'iPhone_XS_portrait_nomarker', position: null, pixelRatio: 3},
15
19
  ]
16
20
 
17
- fixtures.forEach(({name, position, pixelRatio}) => {
21
+ fixtures.forEach(({name, position, offset, pixelRatio}) => {
18
22
  it(name, async () => {
19
23
  const image = await makeImage(`./test/fixtures/pattern/${name}.png`)
20
24
  const result = findPattern(await image.toObject(), {
21
- offset: 1 * pixelRatio,
22
- size: 3 * pixelRatio,
23
- mask: [0, 1, 0],
25
+ pixelRatio,
26
+ mask: [1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1],
27
+ offset,
28
+ size: 1,
24
29
  })
25
30
  assert.deepStrictEqual(result, position)
26
31
  })
@@ -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,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,159 +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
- scrollingMode = driver.isNative ? 'scroll' : scrollingMode
31
-
32
- const activeContext = driver.currentContext
33
- const context =
34
- frames.length > 0
35
- ? await activeContext.context(frames.reduce((parent, frame) => ({...frame, parent}), null))
36
- : activeContext
37
-
38
- // traverse from main context to target context to hide scrollbars and preserve context state (scroll/translate position)
39
- for (const nextContext of context.path) {
40
- const scrollingElement = await nextContext.getScrollingElement()
41
- // unlike web apps, native apps do not always have scrolling element
42
- if (scrollingElement) {
43
- if (driver.isWeb && hideScrollbars) await scrollingElement.hideScrollbars()
44
- await scrollingElement.preserveState()
45
- }
46
- }
47
-
48
- // blur active element in target context
49
- const activeElement = driver.isWeb && hideCaret ? await context.blurElement() : null
50
-
51
- const target = await getTarget({window, context, region, fully, scrollingMode, logger})
52
-
53
- if (driver.isWeb && hideScrollbars) await target.scroller.hideScrollbars()
54
-
55
- try {
56
- if (!window) await scrollIntoViewport({...target, logger})
57
-
58
- const screenshot =
59
- fully && target.scroller
60
- ? await takeStitchedScreenshot({...target, withStatusBar, overlap, framed, wait, stabilization, debug, logger})
61
- : await takeViewportScreenshot({...target, withStatusBar, wait, stabilization, debug, logger})
62
-
63
- if (hooks && hooks.afterScreenshot) {
64
- // imitate image-like state for the hook
65
- if (window && fully && target.scroller) {
66
- await target.scroller.moveTo({x: 0, y: 0}, await driver.mainContext.getScrollingElement())
67
- }
68
- await hooks.afterScreenshot({driver, scroller: target.scroller, screenshot})
69
- }
70
-
71
- return screenshot
72
- } finally {
73
- if (target.scroller) {
74
- await target.scroller.restoreScrollbars()
75
- }
76
-
77
- // if there was active element and we have blurred it, then restore focus
78
- if (activeElement) await context.focusElement(activeElement)
79
-
80
- // traverse from target context to the main context to restore scrollbars and context states
81
- for (const prevContext of context.path.reverse()) {
82
- const scrollingElement = await prevContext.getScrollingElement()
83
- if (scrollingElement) {
84
- if (driver.isWeb && hideScrollbars) await scrollingElement.restoreScrollbars()
85
- await scrollingElement.restoreState()
86
- }
87
- }
88
-
89
- // restore focus on original active context
90
- await activeContext.focus()
91
- }
92
- }
93
-
94
- async function getTarget({window, context, region, fully, scrollingMode, logger}) {
95
- if (window) {
96
- // window/app
97
- const scrollingElement = await context.main.getScrollingElement()
98
- return {
99
- context: context.main,
100
- scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
101
- }
102
- } else if (region) {
103
- if (utils.types.has(region, ['x', 'y', 'width', 'height'])) {
104
- // region by coordinates
105
- const scrollingElement = await context.getScrollingElement()
106
- return {
107
- context,
108
- region,
109
- scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
110
- }
111
- } else {
112
- // region by element or selector
113
- const element = await context.element(region)
114
- if (!element) throw new Error('Element not found!')
115
-
116
- const elementContext = element.context
117
-
118
- if (fully) {
119
- const isScrollable = await element.isScrollable()
120
- // if element is scrollable, then take screenshot of the full element content, otherwise take screenshot of full element
121
- const region = isScrollable ? null : await element.getRegion()
122
- const scrollingElement = isScrollable ? element : await elementContext.getScrollingElement()
123
- // css stitching could be applied only to root element of its context
124
- scrollingMode = scrollingMode === 'css' && !(await scrollingElement.isRoot()) ? 'mixed' : scrollingMode
125
- return {
126
- context: elementContext,
127
- region,
128
- scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
129
- }
130
- } else {
131
- const scrollingElement = await context.getScrollingElement()
132
- return {
133
- context: elementContext,
134
- region: await element.getRegion(),
135
- scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
136
- }
137
- }
138
- }
139
- } else if (!context.isMain) {
140
- // context
141
- if (fully) {
142
- const scrollingElement = await context.getScrollingElement()
143
- return {
144
- context,
145
- scroller: scrollingElement ? makeScroller({logger, element: scrollingElement, scrollingMode}) : null,
146
- }
147
- } else {
148
- const scrollingElement = await context.parent.getScrollingElement()
149
- const element = await context.getContextElement()
150
- return {
151
- context: context.parent,
152
- region: await element.getRegion(), // IMHO we should use CLIENT (without borders) region here
153
- scroller: scrollingElement ? makeScroller({logger, element: scrollingElement, scrollingMode}) : null,
154
- }
155
- }
156
- }
157
- }
158
-
159
- module.exports = screenshoter