@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.
- package/.bongo/dry-run/package-lock.json +11 -11
- package/.bongo/dry-run.tgz +0 -0
- package/CHANGELOG.md +6 -0
- package/index.js +2 -1
- package/logs/screenshot_2021_12_16_19_06_06_332Z_full_app_failed_1639681566332.png +0 -0
- package/logs/screenshot_2021_12_16_19_15_59_935Z_full_app_failed_1639682159935.png +0 -0
- package/logs/screenshot_2021_12_16_19_33_20_679Z_full_app_failed_1639683200679.png +0 -0
- package/logs/screenshot_2021_12_16_19_37_22_120Z_ios_viewport_failed.png +0 -0
- package/logs/screenshot_2021_12_16_19_38_09_461Z_ios_full_page_failed.png +0 -0
- package/logs/screenshot_2021_12_16_19_59_45_182Z_ios_viewport_failed.png +0 -0
- package/package.json +5 -5
- package/src/find-image-pattern.js +10 -38
- package/src/image.js +104 -64
- package/src/take-screenshot.js +136 -160
- package/src/take-simple-screenshot.js +25 -0
- package/src/take-stitched-screenshot.js +32 -52
- package/src/take-viewport-screenshot.js +179 -16
- package/test/e2e/android.spec.js +42 -11
- package/test/e2e/external.spec.js +81 -10
- package/test/e2e/ios.spec.js +48 -10
- package/test/e2e/web-ios.spec.js +3 -5
- package/test/e2e/web.spec.js +20 -15
- package/test/fixtures/android/app-fully-non-scrollable.png +0 -0
- package/test/fixtures/android/app-fully-recycler.png +0 -0
- package/test/fixtures/android/app-fully-scroll-statusbar.png +0 -0
- package/test/fixtures/android/app-fully-scroll.png +0 -0
- package/test/fixtures/android/app-statusbar.png +0 -0
- package/test/fixtures/android/x-app-fully-collapsing.png +0 -0
- package/test/fixtures/android/x-app-fully-recycler.png +0 -0
- package/test/fixtures/android/x-element-fully.png +0 -0
- package/test/fixtures/image/{house.combined-higher-wider.png → house.framed-higher-wider.png} +0 -0
- package/test/fixtures/image/{house.combined-higher.png → house.framed-higher.png} +0 -0
- package/test/fixtures/image/house.framed-shorter-thinner.png +0 -0
- package/test/fixtures/image/{house.combined-wider.png → house.framed-wider.png} +0 -0
- package/test/fixtures/ios/app-fully-collapsing.png +0 -0
- package/test/fixtures/ios/app-fully-collection.png +0 -0
- package/test/fixtures/ios/app-fully-overlapped-statusbar.png +0 -0
- package/test/fixtures/ios/app-fully-overlapped.png +0 -0
- package/test/fixtures/ios/app-fully-scroll-statusbar.png +0 -0
- package/test/fixtures/ios/app-fully-scroll.png +0 -0
- package/test/fixtures/ios/app-fully-superview.png +0 -0
- package/test/fixtures/ios/app-fully-table.png +0 -0
- package/test/fixtures/ios/app-statusbar.png +0 -0
- package/test/fixtures/ios/app.png +0 -0
- package/test/fixtures/ios/element-fully.png +0 -0
- package/test/fixtures/ios/element.png +0 -0
- package/test/fixtures/ios/region.png +0 -0
- package/test/fixtures/pattern/iPad_5th_landscape.png +0 -0
- package/test/fixtures/pattern/iPad_5th_portrait.png +0 -0
- package/test/fixtures/pattern/iPad_9th_landscape.png +0 -0
- package/test/fixtures/pattern/iPad_9th_portrait.png +0 -0
- package/test/fixtures/pattern/iPhone_11_landscape.png +0 -0
- package/test/fixtures/pattern/iPhone_11_portrait.png +0 -0
- package/test/fixtures/pattern/iPhone_13_landscape.png +0 -0
- package/test/fixtures/pattern/iPhone_13_portrait.png +0 -0
- package/test/fixtures/pattern/iPhone_SE_landscape.png +0 -0
- package/test/fixtures/pattern/iPhone_SE_portrait.png +0 -0
- package/test/fixtures/pattern/iPhone_XS_portrait_noviewport.png +0 -0
- package/test/fixtures/web-ios/page-fully.png +0 -0
- package/test/fixtures/web-ios/page.png +0 -0
- package/test/it/find-pattern.spec.js +16 -11
- package/test/it/image.spec.js +42 -15
- package/logs/screenshot_2021_11_14_12_35_00_342Z_full_frame_failed.png +0 -0
- package/logs/screenshot_2021_11_14_12_38_00_715Z_frame_failed.png +0 -0
- package/logs/screenshot_2021_11_14_12_38_03_866Z_frame_failed.png +0 -0
- package/logs/screenshot_2021_11_14_13_02_56_464Z_full_app_failed_1636894976464.png +0 -0
- package/logs/screenshot_2021_11_14_13_04_27_904Z_full_app_failed_1636895067904.png +0 -0
- package/logs/screenshot_2021_11_14_13_06_13_662Z_full_app_failed_1636895173662.png +0 -0
- package/logs/screenshot_2021_11_14_13_06_23_745Z_full_app_failed_1636895183745.png +0 -0
- package/logs/screenshot_2021_11_14_13_18_31_571Z_full_app_failed_1636895911571.png +0 -0
- package/logs/screenshot_2021_11_14_13_25_54_557Z_viewport_failed_1636896354557.png +0 -0
- package/logs/screenshot_2021_11_14_13_29_32_326Z_viewport_failed_1636896572326.png +0 -0
- package/logs/screenshot_2021_11_14_13_34_22_483Z_viewport_failed_1636896862483.png +0 -0
- package/logs/screenshot_2021_11_14_13_37_25_734Z_viewport_failed_1636897045734.png +0 -0
- package/logs/screenshot_2021_11_14_13_42_25_024Z_viewport_failed_1636897345024.png +0 -0
- package/logs/screenshot_2021_11_14_13_57_24_366Z_full_app_failed_1636898244366.png +0 -0
- package/logs/screenshot_2021_11_14_14_20_42_951Z_full_app_failed_1636899642951.png +0 -0
- package/logs/screenshot_2021_11_14_14_31_07_853Z_full_app_failed_1636900267853.png +0 -0
- package/logs/screenshot_2021_11_14_14_32_07_195Z_full_app_failed_1636900327195.png +0 -0
- package/logs/screenshot_2021_11_14_14_42_16_716Z_full_app_failed_1636900936716.png +0 -0
- package/logs/screenshot_2021_11_14_14_47_37_646Z_full_app_failed_1636901257646.png +0 -0
- package/logs/screenshot_2021_11_14_14_54_18_522Z_full_app_failed_1636901658522.png +0 -0
- package/logs/screenshot_2021_11_14_14_55_36_756Z_full_app_failed_1636901736756.png +0 -0
- package/logs/screenshot_2021_11_14_15_00_26_000Z_full_app_failed_1636902026000.png +0 -0
- package/logs/screenshot_2021_11_14_15_04_13_598Z_full_app_failed_1636902253598.png +0 -0
- package/logs/screenshot_2021_11_14_15_07_37_914Z_full_app_failed_1636902457914.png +0 -0
- package/logs/screenshot_2021_11_14_15_12_20_039Z_full_app_failed_1636902740039.png +0 -0
- package/logs/screenshot_2021_11_14_15_15_44_401Z_full_app_failed_1636902944401.png +0 -0
- package/logs/screenshot_2021_11_14_15_26_23_318Z_viewport_failed_1636903583318.png +0 -0
- package/src/calculate-screenshot-regions.js +0 -31
- package/src/screenshoter.js +0 -159
- package/test/fixtures/pattern/iPad_Air_portrait.png +0 -0
- package/test/fixtures/pattern/iPhone_5S_landscape.png +0 -0
- package/test/fixtures/pattern/iPhone_XR_perfecto_landscape.png +0 -0
- package/test/fixtures/pattern/iPhone_XS_Max_perfecto_landscape.png +0 -0
- package/test/fixtures/pattern/iPhone_XS_landscape.png +0 -0
- package/test/fixtures/pattern/iPhone_XS_portrait.png +0 -0
- package/test/fixtures/pattern/iPhone_X_perfecto_portrait.png +0 -0
|
@@ -1,25 +1,188 @@
|
|
|
1
1
|
const utils = require('@applitools/utils')
|
|
2
|
-
const
|
|
2
|
+
const snippets = require('@applitools/snippets')
|
|
3
|
+
const findImagePattern = require('./find-image-pattern')
|
|
4
|
+
const makeImage = require('./image')
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
function makeTakeViewportScreenshot(options) {
|
|
7
|
+
const {driver} = options
|
|
8
|
+
if (driver.isNative) {
|
|
9
|
+
return makeTakeNativeScreenshot(options)
|
|
10
|
+
} else if (driver.browserName === 'Firefox') {
|
|
11
|
+
try {
|
|
12
|
+
const browserVersion = Number.parseInt(driver.browserVersion, 10)
|
|
13
|
+
if (browserVersion >= 48 && browserVersion <= 72) {
|
|
14
|
+
// firefox between versions 48 and 72 takes current frame screenshot only
|
|
15
|
+
return makeTakeMainContextScreenshot(options)
|
|
16
|
+
}
|
|
17
|
+
} catch (ignored) {}
|
|
18
|
+
} else if (driver.browserName === 'Safari') {
|
|
19
|
+
if (driver.isIOS) {
|
|
20
|
+
// safari on ios takes screenshot with browser and os interfaces
|
|
21
|
+
return makeTakeMarkedScreenshot(options)
|
|
22
|
+
} else if (driver.browserVersion === '11') {
|
|
23
|
+
// safari 11 on macs takes full page screenshot
|
|
24
|
+
return makeTakeSafari11Screenshot(options)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return makeTakeDefaultScreenshot(options)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function makeTakeDefaultScreenshot({driver, stabilization = {}, debug, logger}) {
|
|
32
|
+
const calculateScaleRatio = makeCalculateScaleRatio({driver})
|
|
33
|
+
return async function takeScreenshot({name} = {}) {
|
|
34
|
+
logger.verbose('Taking screenshot...')
|
|
35
|
+
const image = makeImage(await driver.takeScreenshot())
|
|
36
|
+
await image.debug({...debug, name, suffix: 'original'})
|
|
37
|
+
|
|
38
|
+
if (stabilization.scale) image.scale(stabilization.scale)
|
|
39
|
+
else image.scale(await calculateScaleRatio(image.width))
|
|
40
|
+
|
|
41
|
+
if (stabilization.rotate) image.crop(stabilization.rotate)
|
|
42
|
+
|
|
43
|
+
if (stabilization.crop) image.crop(stabilization.crop)
|
|
44
|
+
|
|
45
|
+
return image
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function makeTakeMainContextScreenshot({driver, stabilization = {}, debug, logger}) {
|
|
50
|
+
const calculateScaleRatio = makeCalculateScaleRatio({driver})
|
|
51
|
+
return async function takeScreenshot({name} = {}) {
|
|
52
|
+
logger.verbose('Taking screenshot...')
|
|
53
|
+
const originalContext = driver.currentContext
|
|
54
|
+
await driver.mainContext.focus()
|
|
55
|
+
const image = makeImage(await driver.takeScreenshot())
|
|
56
|
+
await originalContext.focus()
|
|
57
|
+
await image.debug({...debug, name, suffix: 'original'})
|
|
58
|
+
|
|
59
|
+
if (stabilization.scale) image.scale(stabilization.scale)
|
|
60
|
+
else image.scale(await calculateScaleRatio(image.width))
|
|
6
61
|
|
|
7
|
-
|
|
8
|
-
|
|
62
|
+
if (stabilization.rotate) image.rotate(stabilization.rotate)
|
|
63
|
+
|
|
64
|
+
if (stabilization.crop) image.crop(stabilization.crop)
|
|
65
|
+
|
|
66
|
+
return image
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function makeTakeSafari11Screenshot({driver, stabilization = {}, debug, logger}) {
|
|
71
|
+
const calculateScaleRatio = makeCalculateScaleRatio({driver})
|
|
72
|
+
let viewportSize
|
|
73
|
+
|
|
74
|
+
return async function takeScreenshot({name} = {}) {
|
|
75
|
+
logger.verbose('Taking safari 11 driver screenshot...')
|
|
76
|
+
const image = makeImage(await driver.takeScreenshot())
|
|
77
|
+
await image.debug({...debug, name, suffix: 'original'})
|
|
78
|
+
|
|
79
|
+
if (stabilization.scale) image.scale(stabilization.scale)
|
|
80
|
+
else image.scale(await calculateScaleRatio(image.width))
|
|
81
|
+
|
|
82
|
+
if (stabilization.rotate) image.rotate(stabilization.rotate)
|
|
83
|
+
|
|
84
|
+
if (stabilization.crop) image.crop(stabilization.crop)
|
|
85
|
+
else {
|
|
86
|
+
if (!viewportSize) viewportSize = await driver.getViewportSize()
|
|
87
|
+
const viewportLocation = await driver.mainContext.execute(snippets.getElementScrollOffset, [])
|
|
88
|
+
image.crop(utils.geometry.region(viewportLocation, viewportSize))
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return image
|
|
92
|
+
}
|
|
93
|
+
}
|
|
9
94
|
|
|
10
|
-
|
|
95
|
+
function makeTakeMarkedScreenshot({driver, stabilization = {}, debug, logger}) {
|
|
96
|
+
const calculateScaleRatio = makeCalculateScaleRatio({driver})
|
|
97
|
+
let viewportRegion
|
|
98
|
+
|
|
99
|
+
return async function takeScreenshot({name} = {}) {
|
|
100
|
+
logger.verbose('Taking viewport screenshot (using markers)...')
|
|
101
|
+
const image = makeImage(await driver.takeScreenshot())
|
|
102
|
+
await image.debug({...debug, name, suffix: 'original'})
|
|
103
|
+
|
|
104
|
+
if (stabilization.scale) image.scale(stabilization.scale)
|
|
105
|
+
else image.scale(await calculateScaleRatio(image.width))
|
|
106
|
+
|
|
107
|
+
if (stabilization.rotate) image.rotate(stabilization.rotate)
|
|
108
|
+
|
|
109
|
+
if (stabilization.crop) image.crop(stabilization.crop)
|
|
110
|
+
else {
|
|
111
|
+
if (!viewportRegion) viewportRegion = await getViewportRegion()
|
|
112
|
+
if (viewportRegion) image.crop(viewportRegion)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await image.debug({...debug, name, suffix: 'viewport'})
|
|
116
|
+
|
|
117
|
+
return image
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function getViewportRegion() {
|
|
121
|
+
const marker = await driver.mainContext.execute(snippets.addPageMarker)
|
|
122
|
+
try {
|
|
123
|
+
const image = makeImage(await driver.takeScreenshot())
|
|
124
|
+
|
|
125
|
+
if (stabilization.rotate) await image.rotate(stabilization.rotate)
|
|
126
|
+
|
|
127
|
+
await image.debug({...debug, name: 'marker'})
|
|
128
|
+
|
|
129
|
+
const markerLocation = findImagePattern(await image.toObject(), {...marker, pixelRatio: driver.pixelRatio})
|
|
130
|
+
if (!markerLocation) return null
|
|
131
|
+
|
|
132
|
+
const viewportSize = await driver.getViewportSize()
|
|
133
|
+
|
|
134
|
+
return utils.geometry.region(utils.geometry.scale(markerLocation, 1 / driver.pixelRatio), viewportSize)
|
|
135
|
+
} finally {
|
|
136
|
+
await driver.mainContext.execute(snippets.cleanupPageMarker)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function makeTakeNativeScreenshot({driver, stabilization = {}, debug, logger}) {
|
|
142
|
+
return async function takeScreenshot({name, withStatusBar} = {}) {
|
|
143
|
+
logger.verbose('Taking native driver screenshot...')
|
|
144
|
+
const image = makeImage(await driver.takeScreenshot())
|
|
145
|
+
await image.debug({...debug, name, suffix: 'original'})
|
|
146
|
+
|
|
147
|
+
if (stabilization.scale) image.scale(stabilization.scale)
|
|
148
|
+
else image.scale(1 / driver.pixelRatio)
|
|
149
|
+
|
|
150
|
+
if (stabilization.rotate) image.rotate(stabilization.rotate)
|
|
151
|
+
|
|
152
|
+
if (stabilization.crop) image.crop(stabilization.crop)
|
|
153
|
+
else {
|
|
154
|
+
const viewportSize = await driver.getViewportSize()
|
|
155
|
+
const cropRegion = withStatusBar
|
|
156
|
+
? {x: 0, y: 0, width: viewportSize.width, height: viewportSize.height + driver.statusBarHeight}
|
|
157
|
+
: {top: driver.statusBarHeight, bottom: driver.navigationBarHeight, left: 0, right: 0}
|
|
158
|
+
image.crop(cropRegion)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
await image.debug({...debug, name, suffix: `viewport${withStatusBar ? '-with-statusbar' : ''}`})
|
|
162
|
+
|
|
163
|
+
return image
|
|
164
|
+
}
|
|
165
|
+
}
|
|
11
166
|
|
|
12
|
-
|
|
167
|
+
function makeCalculateScaleRatio({driver}) {
|
|
168
|
+
let viewportWidth, contentWidth
|
|
169
|
+
const VIEWPORT_THRESHOLD = 1
|
|
170
|
+
const CONTENT_THRESHOLD = 10
|
|
171
|
+
return async function calculateScaleRatio(imageWidth) {
|
|
172
|
+
if (!viewportWidth) viewportWidth = await driver.getViewportSize().then(size => size.width)
|
|
173
|
+
if (!contentWidth) contentWidth = await driver.mainContext.getContentSize().then(size => size.width)
|
|
174
|
+
// If the image's width is the same as the viewport's width or the
|
|
175
|
+
// top level context's width, no scaling is necessary.
|
|
176
|
+
if (
|
|
177
|
+
(imageWidth >= viewportWidth - VIEWPORT_THRESHOLD && imageWidth <= viewportWidth + VIEWPORT_THRESHOLD) ||
|
|
178
|
+
(imageWidth >= contentWidth - CONTENT_THRESHOLD && imageWidth <= contentWidth + CONTENT_THRESHOLD)
|
|
179
|
+
) {
|
|
180
|
+
return 1
|
|
181
|
+
}
|
|
13
182
|
|
|
14
|
-
|
|
15
|
-
|
|
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)}
|
|
183
|
+
const scaledImageWidth = Math.round(imageWidth / driver.pixelRatio)
|
|
184
|
+
return viewportWidth / scaledImageWidth / driver.pixelRatio
|
|
22
185
|
}
|
|
23
186
|
}
|
|
24
187
|
|
|
25
|
-
module.exports =
|
|
188
|
+
module.exports = makeTakeViewportScreenshot
|
package/test/e2e/android.spec.js
CHANGED
|
@@ -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
|
|
6
|
+
const takeScreenshot = require('../../index')
|
|
7
7
|
|
|
8
8
|
const env = {
|
|
9
9
|
android: {
|
|
@@ -31,10 +31,20 @@ const env = {
|
|
|
31
31
|
appiumVersion: '1.20.2',
|
|
32
32
|
deviceName: 'Google Pixel 3a XL GoogleAPI Emulator',
|
|
33
33
|
automationName: 'uiautomator2',
|
|
34
|
-
app: 'https://applitools.jfrog.io/artifactory/Examples/androidx/1.
|
|
34
|
+
app: 'https://applitools.jfrog.io/artifactory/Examples/androidx/1.3.1/app_androidx.apk',
|
|
35
35
|
username: process.env.SAUCE_USERNAME,
|
|
36
36
|
accessKey: process.env.SAUCE_ACCESS_KEY,
|
|
37
37
|
},
|
|
38
|
+
|
|
39
|
+
// url: 'http://0.0.0.0:4723/wd/hub',
|
|
40
|
+
// capabilities: {
|
|
41
|
+
// deviceName: 'Google Pixel 3a XL',
|
|
42
|
+
// platformName: 'Android',
|
|
43
|
+
// platformVersion: '10.0',
|
|
44
|
+
// automationName: 'uiautomator2',
|
|
45
|
+
// avd: 'Pixel_3a_XL',
|
|
46
|
+
// app: 'https://applitools.jfrog.io/artifactory/Examples/androidx/1.3.3/app_androidx.apk',
|
|
47
|
+
// },
|
|
38
48
|
},
|
|
39
49
|
}
|
|
40
50
|
|
|
@@ -122,6 +132,14 @@ describe('screenshoter', () => {
|
|
|
122
132
|
return fullApp({type: 'recycler', x: true})
|
|
123
133
|
})
|
|
124
134
|
|
|
135
|
+
it('take full app screenshot (collapsing layout)', () => {
|
|
136
|
+
return fullApp({type: 'collapsing', x: true})
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it.skip('take full app screenshot (overlapped status bar)', () => {
|
|
140
|
+
return fullApp({type: 'overlapped', x: true})
|
|
141
|
+
})
|
|
142
|
+
|
|
125
143
|
it('take full element screenshot', () => {
|
|
126
144
|
return fullElement()
|
|
127
145
|
})
|
|
@@ -130,7 +148,7 @@ describe('screenshoter', () => {
|
|
|
130
148
|
async function app(options = {}) {
|
|
131
149
|
const expectedPath = `./test/fixtures/android/app${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
132
150
|
|
|
133
|
-
const screenshot = await
|
|
151
|
+
const screenshot = await takeScreenshot({logger, driver, wait: 1500, ...options})
|
|
134
152
|
try {
|
|
135
153
|
if (options.withStatusBar) await sanitizeStatusBar(screenshot.image)
|
|
136
154
|
const actual = await screenshot.image.toObject()
|
|
@@ -142,8 +160,15 @@ describe('screenshoter', () => {
|
|
|
142
160
|
}
|
|
143
161
|
}
|
|
144
162
|
async function fullApp({type, x, ...options} = {}) {
|
|
145
|
-
let buttonSelector, expectedPath
|
|
146
|
-
if (type === '
|
|
163
|
+
let buttonSelector, expectedPath, scrollingElementSelector
|
|
164
|
+
if (type === 'overlapped') {
|
|
165
|
+
buttonSelector = {type: 'id', selector: 'btn_recycler_view_under_status_bar_activity'}
|
|
166
|
+
expectedPath = `./test/fixtures/android/x-app-fully-overlapped${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
167
|
+
} else if (type === 'collapsing') {
|
|
168
|
+
buttonSelector = {type: 'id', selector: 'btn_recycler_view_nested_collapsing'}
|
|
169
|
+
scrollingElementSelector = {type: 'id', selector: 'recyclerView'}
|
|
170
|
+
expectedPath = `./test/fixtures/android/x-app-fully-collapsing${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
171
|
+
} else if (type === 'recycler') {
|
|
147
172
|
if (x) {
|
|
148
173
|
buttonSelector = {type: 'id', selector: 'btn_recycler_view_activity'}
|
|
149
174
|
expectedPath = `./test/fixtures/android/x-app-fully-recycler${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
@@ -152,7 +177,7 @@ describe('screenshoter', () => {
|
|
|
152
177
|
expectedPath = `./test/fixtures/android/app-fully-recycler${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
153
178
|
}
|
|
154
179
|
} else if (type === 'non-scrollable') {
|
|
155
|
-
buttonSelector = {type: 'id', selector: '
|
|
180
|
+
buttonSelector = {type: 'id', selector: 'btn_activity_as_dialog'}
|
|
156
181
|
expectedPath = `./test/fixtures/android/app-fully-non-scrollable${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
157
182
|
} else {
|
|
158
183
|
buttonSelector = {type: 'id', selector: 'btn_scroll_view_footer_header'}
|
|
@@ -162,7 +187,13 @@ describe('screenshoter', () => {
|
|
|
162
187
|
const button = await driver.element(buttonSelector)
|
|
163
188
|
await button.click()
|
|
164
189
|
|
|
165
|
-
|
|
190
|
+
await driver.init()
|
|
191
|
+
|
|
192
|
+
if (scrollingElementSelector) {
|
|
193
|
+
await driver.currentContext.setScrollingElement(scrollingElementSelector)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const screenshot = await takeScreenshot({
|
|
166
197
|
logger,
|
|
167
198
|
driver,
|
|
168
199
|
fully: true,
|
|
@@ -182,7 +213,7 @@ describe('screenshoter', () => {
|
|
|
182
213
|
}
|
|
183
214
|
}
|
|
184
215
|
async function region(options) {
|
|
185
|
-
const screenshot = await
|
|
216
|
+
const screenshot = await takeScreenshot({
|
|
186
217
|
logger,
|
|
187
218
|
driver,
|
|
188
219
|
region: {x: 30, y: 500, height: 100, width: 200},
|
|
@@ -199,7 +230,7 @@ describe('screenshoter', () => {
|
|
|
199
230
|
}
|
|
200
231
|
}
|
|
201
232
|
async function fullRegion(options) {
|
|
202
|
-
const screenshot = await
|
|
233
|
+
const screenshot = await takeScreenshot({
|
|
203
234
|
logger,
|
|
204
235
|
driver,
|
|
205
236
|
region: {x: 30, y: 10, height: 700, width: 200},
|
|
@@ -217,7 +248,7 @@ describe('screenshoter', () => {
|
|
|
217
248
|
}
|
|
218
249
|
}
|
|
219
250
|
async function element(options) {
|
|
220
|
-
const screenshot = await
|
|
251
|
+
const screenshot = await takeScreenshot({
|
|
221
252
|
logger,
|
|
222
253
|
driver,
|
|
223
254
|
region: {type: 'id', selector: 'btn_recycler_view'},
|
|
@@ -240,7 +271,7 @@ describe('screenshoter', () => {
|
|
|
240
271
|
})
|
|
241
272
|
await button.click()
|
|
242
273
|
|
|
243
|
-
const screenshot = await
|
|
274
|
+
const screenshot = await takeScreenshot({
|
|
244
275
|
logger,
|
|
245
276
|
driver,
|
|
246
277
|
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
|
|
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': '
|
|
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(
|
|
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(
|
|
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
|
-
|
|
64
|
-
// await billingBtn.click()
|
|
65
|
-
// await utils.general.sleep(25000)
|
|
62
|
+
await driver.init()
|
|
66
63
|
|
|
67
|
-
const screenshot = await
|
|
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
|
})
|
package/test/e2e/ios.spec.js
CHANGED
|
@@ -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
|
|
6
|
+
const takeScreenshot = require('../../index')
|
|
7
7
|
|
|
8
8
|
const env = {
|
|
9
9
|
url: 'https://ondemand.saucelabs.com/wd/hub',
|
|
@@ -14,10 +14,18 @@ const env = {
|
|
|
14
14
|
platformVersion: '13.4',
|
|
15
15
|
appiumVersion: '1.19.2',
|
|
16
16
|
automationName: 'XCUITest',
|
|
17
|
-
app: 'https://applitools.jfrog.io/artifactory/Examples/IOSTestApp/1.
|
|
17
|
+
app: 'https://applitools.jfrog.io/artifactory/Examples/IOSTestApp/1.8/app/IOSTestApp.zip',
|
|
18
18
|
username: process.env.SAUCE_USERNAME,
|
|
19
19
|
accessKey: process.env.SAUCE_ACCESS_KEY,
|
|
20
20
|
},
|
|
21
|
+
|
|
22
|
+
// url: 'http://0.0.0.0:4723/wd/hub',
|
|
23
|
+
// capabilities: {
|
|
24
|
+
// deviceName: 'iPhone 11 Pro',
|
|
25
|
+
// platformName: 'iOS',
|
|
26
|
+
// platformVersion: '14.5',
|
|
27
|
+
// app: '/Users/kyrylo/Downloads/IOSTestApp.zip',
|
|
28
|
+
// },
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
describe('screenshoter ios', () => {
|
|
@@ -77,6 +85,22 @@ describe('screenshoter ios', () => {
|
|
|
77
85
|
return fullApp({type: 'collection'})
|
|
78
86
|
})
|
|
79
87
|
|
|
88
|
+
it('take full app screenshot (table view with collapsing header)', () => {
|
|
89
|
+
return fullApp({type: 'collapsing'})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
it('take full app screenshot (collection view with overlapped status bar)', () => {
|
|
93
|
+
return fullApp({type: 'overlapped'})
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('take full app screenshot with status bar (collection view with overlapped status bar)', () => {
|
|
97
|
+
return fullApp({type: 'overlapped', withStatusBar: true})
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('take full app screenshot (collection view with superview)', () => {
|
|
101
|
+
return fullApp({type: 'superview'})
|
|
102
|
+
})
|
|
103
|
+
|
|
80
104
|
it('take region screenshot', () => {
|
|
81
105
|
return region()
|
|
82
106
|
})
|
|
@@ -96,7 +120,7 @@ describe('screenshoter ios', () => {
|
|
|
96
120
|
async function app(options = {}) {
|
|
97
121
|
const expectedPath = `./test/fixtures/ios/app${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
98
122
|
|
|
99
|
-
const screenshot = await
|
|
123
|
+
const screenshot = await takeScreenshot({logger, driver, ...options})
|
|
100
124
|
try {
|
|
101
125
|
if (options.withStatusBar) await sanitizeStatusBar(screenshot.image)
|
|
102
126
|
const actual = await screenshot.image.toObject()
|
|
@@ -108,8 +132,19 @@ describe('screenshoter ios', () => {
|
|
|
108
132
|
}
|
|
109
133
|
}
|
|
110
134
|
async function fullApp({type, ...options} = {}) {
|
|
111
|
-
let buttonSelector, expectedPath
|
|
112
|
-
if (type === '
|
|
135
|
+
let buttonSelector, expectedPath, overlap
|
|
136
|
+
if (type === 'superview') {
|
|
137
|
+
overlap = {top: 200}
|
|
138
|
+
buttonSelector = {type: 'accessibility id', selector: 'Bottom to superview'}
|
|
139
|
+
expectedPath = `./test/fixtures/ios/app-fully-superview${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
140
|
+
} else if (type === 'overlapped') {
|
|
141
|
+
overlap = {top: 200}
|
|
142
|
+
buttonSelector = {type: 'accessibility id', selector: 'Bottom to safe area'}
|
|
143
|
+
expectedPath = `./test/fixtures/ios/app-fully-overlapped${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
144
|
+
} else if (type === 'collapsing') {
|
|
145
|
+
buttonSelector = {type: 'accessibility id', selector: 'Table view with stretchable header'}
|
|
146
|
+
expectedPath = `./test/fixtures/ios/app-fully-collapsing${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
147
|
+
} else if (type === 'collection') {
|
|
113
148
|
buttonSelector = {type: 'accessibility id', selector: 'Collection view'}
|
|
114
149
|
expectedPath = `./test/fixtures/ios/app-fully-collection${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
115
150
|
} else if (type === 'table') {
|
|
@@ -123,13 +158,16 @@ describe('screenshoter ios', () => {
|
|
|
123
158
|
const button = await driver.element(buttonSelector)
|
|
124
159
|
await button.click()
|
|
125
160
|
|
|
126
|
-
|
|
161
|
+
await driver.init()
|
|
162
|
+
|
|
163
|
+
const screenshot = await takeScreenshot({
|
|
127
164
|
logger,
|
|
128
165
|
driver,
|
|
129
166
|
fully: true,
|
|
130
167
|
framed: true,
|
|
131
168
|
scrollingMode: 'scroll',
|
|
132
169
|
wait: 1500,
|
|
170
|
+
overlap: {top: 10, bottom: 50, ...overlap},
|
|
133
171
|
...options,
|
|
134
172
|
})
|
|
135
173
|
try {
|
|
@@ -143,7 +181,7 @@ describe('screenshoter ios', () => {
|
|
|
143
181
|
}
|
|
144
182
|
}
|
|
145
183
|
async function region(options) {
|
|
146
|
-
const screenshot = await
|
|
184
|
+
const screenshot = await takeScreenshot({
|
|
147
185
|
logger,
|
|
148
186
|
driver,
|
|
149
187
|
region: {x: 30, y: 500, height: 100, width: 200},
|
|
@@ -161,7 +199,7 @@ describe('screenshoter ios', () => {
|
|
|
161
199
|
}
|
|
162
200
|
}
|
|
163
201
|
async function fullRegion(options) {
|
|
164
|
-
const screenshot = await
|
|
202
|
+
const screenshot = await takeScreenshot({
|
|
165
203
|
logger,
|
|
166
204
|
driver,
|
|
167
205
|
region: {x: 30, y: 10, height: 700, width: 200},
|
|
@@ -179,7 +217,7 @@ describe('screenshoter ios', () => {
|
|
|
179
217
|
}
|
|
180
218
|
}
|
|
181
219
|
async function element(options) {
|
|
182
|
-
const screenshot = await
|
|
220
|
+
const screenshot = await takeScreenshot({
|
|
183
221
|
logger,
|
|
184
222
|
driver,
|
|
185
223
|
region: {type: 'accessibility id', selector: 'Table view'},
|
|
@@ -202,7 +240,7 @@ describe('screenshoter ios', () => {
|
|
|
202
240
|
})
|
|
203
241
|
await button.click()
|
|
204
242
|
|
|
205
|
-
const screenshot = await
|
|
243
|
+
const screenshot = await takeScreenshot({
|
|
206
244
|
logger,
|
|
207
245
|
driver,
|
|
208
246
|
region: {type: 'xpath', selector: '//XCUIElementTypeTable[1]'},
|
package/test/e2e/web-ios.spec.js
CHANGED
|
@@ -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
|
|
5
|
+
const takeScreenshot = require('../../index')
|
|
6
6
|
const makeImage = require('../../src/image')
|
|
7
7
|
|
|
8
8
|
const env = {
|
|
@@ -20,8 +20,6 @@ const env = {
|
|
|
20
20
|
},
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// TODO add tests for page without viewport meta tag
|
|
24
|
-
|
|
25
23
|
describe('screenshoter web ios', () => {
|
|
26
24
|
const logger = {log: () => {}, warn: () => {}, error: () => {}, verbose: () => {}}
|
|
27
25
|
let driver, browser, destroyBrowser
|
|
@@ -49,7 +47,7 @@ describe('screenshoter web ios', () => {
|
|
|
49
47
|
})
|
|
50
48
|
|
|
51
49
|
async function viewport(options) {
|
|
52
|
-
const screenshot = await
|
|
50
|
+
const screenshot = await takeScreenshot({logger, driver, ...options})
|
|
53
51
|
try {
|
|
54
52
|
const actual = await screenshot.image.toObject()
|
|
55
53
|
const expected = await makeImage('./test/fixtures/web-ios/page.png').toObject()
|
|
@@ -61,7 +59,7 @@ describe('screenshoter web ios', () => {
|
|
|
61
59
|
}
|
|
62
60
|
|
|
63
61
|
async function fullPage(options) {
|
|
64
|
-
const screenshot = await
|
|
62
|
+
const screenshot = await takeScreenshot({logger, driver, fully: true, ...options})
|
|
65
63
|
try {
|
|
66
64
|
const actual = await screenshot.image.toObject()
|
|
67
65
|
const expected = await makeImage('./test/fixtures/web-ios/page-fully.png').toObject()
|