@applitools/screenshoter 3.2.8 → 3.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bongo/dry-run/package-lock.json +49 -6
- package/.bongo/dry-run/package.json +5 -0
- package/.bongo/dry-run.tgz +0 -0
- package/CHANGELOG.md +19 -0
- package/index.js +2 -1
- package/package.json +7 -4
- package/src/find-image-pattern.js +11 -38
- package/src/image.js +107 -64
- package/src/take-screenshot.js +136 -160
- package/src/take-simple-screenshot.js +25 -0
- package/src/take-stitched-screenshot.js +34 -40
- package/src/take-viewport-screenshot.js +179 -16
- package/test/e2e/android.spec.js +120 -13
- package/test/e2e/external.spec.js +155 -0
- package/test/e2e/ios.spec.js +142 -12
- package/test/e2e/web-ios.spec.js +19 -6
- package/test/e2e/web.spec.js +33 -21
- 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/external/agl.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/ios/webview-fully.png +0 -0
- package/test/fixtures/ios/webview.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/frame-fully.png +0 -0
- package/test/fixtures/web/frame.png +0 -0
- package/test/fixtures/web/inner-element-fully.png +0 -0
- package/test/fixtures/web/inner-element.png +0 -0
- package/test/fixtures/web/inner-region-fully.png +0 -0
- package/test/fixtures/web/inner-region.png +0 -0
- package/test/fixtures/web/page-fully.png +0 -0
- package/test/fixtures/web/page.png +0 -0
- package/test/fixtures/web/region-fully.png +0 -0
- package/test/fixtures/web/region.png +0 -0
- package/test/fixtures/web-ios/page-fully.png +0 -0
- package/test/it/find-pattern.spec.js +16 -11
- package/test/it/image.spec.js +42 -15
- package/docker-compose.yaml +0 -29
- package/src/calculate-screenshot-regions.js +0 -31
- package/src/screenshoter.js +0 -158
- 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
- package/test/util/spec-driver.js +0 -288
|
@@ -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.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
|
+
const calculateScaleRatio = makeCalculateScaleRatio({driver})
|
|
31
|
+
return async function takeScreenshot({name} = {}) {
|
|
32
|
+
logger.verbose('Taking screenshot...')
|
|
33
|
+
const image = makeImage(await driver.takeScreenshot())
|
|
34
|
+
await image.debug({...debug, name, suffix: 'original'})
|
|
35
|
+
|
|
36
|
+
if (stabilization.scale) image.scale(stabilization.scale)
|
|
37
|
+
else image.scale(await calculateScaleRatio(image.width))
|
|
38
|
+
|
|
39
|
+
if (stabilization.rotate) image.crop(stabilization.rotate)
|
|
40
|
+
|
|
41
|
+
if (stabilization.crop) image.crop(stabilization.crop)
|
|
42
|
+
|
|
43
|
+
return image
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function makeTakeMainContextScreenshot({driver, stabilization = {}, debug, logger}) {
|
|
48
|
+
const calculateScaleRatio = makeCalculateScaleRatio({driver})
|
|
49
|
+
return async function takeScreenshot({name} = {}) {
|
|
50
|
+
logger.verbose('Taking screenshot...')
|
|
51
|
+
const originalContext = driver.currentContext
|
|
52
|
+
await driver.mainContext.focus()
|
|
53
|
+
const image = makeImage(await driver.takeScreenshot())
|
|
54
|
+
await originalContext.focus()
|
|
55
|
+
await image.debug({...debug, name, suffix: 'original'})
|
|
56
|
+
|
|
57
|
+
if (stabilization.scale) image.scale(stabilization.scale)
|
|
58
|
+
else image.scale(await calculateScaleRatio(image.width))
|
|
59
|
+
|
|
60
|
+
if (stabilization.rotate) image.rotate(stabilization.rotate)
|
|
61
|
+
|
|
62
|
+
if (stabilization.crop) image.crop(stabilization.crop)
|
|
63
|
+
|
|
64
|
+
return image
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function makeTakeSafari11Screenshot({driver, stabilization = {}, debug, logger}) {
|
|
69
|
+
const calculateScaleRatio = makeCalculateScaleRatio({driver})
|
|
70
|
+
let viewportSize
|
|
71
|
+
|
|
72
|
+
return async function takeScreenshot({name} = {}) {
|
|
73
|
+
logger.verbose('Taking safari 11 driver screenshot...')
|
|
74
|
+
const image = makeImage(await driver.takeScreenshot())
|
|
75
|
+
await image.debug({...debug, name, suffix: 'original'})
|
|
76
|
+
|
|
77
|
+
if (stabilization.scale) image.scale(stabilization.scale)
|
|
78
|
+
else image.scale(await calculateScaleRatio(image.width))
|
|
79
|
+
|
|
80
|
+
if (stabilization.rotate) image.rotate(stabilization.rotate)
|
|
81
|
+
|
|
82
|
+
if (stabilization.crop) image.crop(stabilization.crop)
|
|
83
|
+
else {
|
|
84
|
+
if (!viewportSize) viewportSize = await driver.getViewportSize()
|
|
85
|
+
const viewportLocation = await driver.mainContext.execute(snippets.getElementScrollOffset, [])
|
|
86
|
+
image.crop(utils.geometry.region(viewportLocation, viewportSize))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return image
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function makeTakeMarkedScreenshot({driver, stabilization = {}, debug, logger}) {
|
|
94
|
+
const calculateScaleRatio = makeCalculateScaleRatio({driver})
|
|
95
|
+
let viewportRegion
|
|
96
|
+
|
|
97
|
+
return async function takeScreenshot({name} = {}) {
|
|
98
|
+
logger.verbose('Taking viewport screenshot (using markers)...')
|
|
99
|
+
const image = makeImage(await driver.takeScreenshot())
|
|
100
|
+
await image.debug({...debug, name, suffix: 'original'})
|
|
101
|
+
|
|
102
|
+
if (stabilization.scale) image.scale(stabilization.scale)
|
|
103
|
+
else image.scale(await calculateScaleRatio(image.width))
|
|
104
|
+
|
|
105
|
+
if (stabilization.rotate) image.rotate(stabilization.rotate)
|
|
106
|
+
|
|
107
|
+
if (stabilization.crop) image.crop(stabilization.crop)
|
|
108
|
+
else {
|
|
109
|
+
if (!viewportRegion) viewportRegion = await getViewportRegion()
|
|
110
|
+
if (viewportRegion) image.crop(viewportRegion)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
await image.debug({...debug, name, suffix: 'viewport'})
|
|
114
|
+
|
|
115
|
+
return image
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function getViewportRegion() {
|
|
119
|
+
const marker = await driver.mainContext.execute(snippets.addPageMarker)
|
|
120
|
+
await utils.general.sleep(100)
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
const image = makeImage(await driver.takeScreenshot())
|
|
124
|
+
|
|
125
|
+
if (stabilization.rotate) await image.rotate(stabilization.rotate)
|
|
6
126
|
|
|
7
|
-
|
|
8
|
-
const takeScreenshot = makeTakeScreenshot({logger, driver, stabilization, debug})
|
|
127
|
+
await image.debug({...debug, name: 'marker'})
|
|
9
128
|
|
|
10
|
-
|
|
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
|
@@ -1,9 +1,63 @@
|
|
|
1
1
|
const assert = require('assert')
|
|
2
2
|
const pixelmatch = require('pixelmatch')
|
|
3
3
|
const {Driver} = require('@applitools/driver')
|
|
4
|
-
const spec = require('
|
|
4
|
+
const spec = require('@applitools/spec-driver-webdriverio')
|
|
5
5
|
const makeImage = require('../../src/image')
|
|
6
|
-
const
|
|
6
|
+
const takeScreenshot = require('../../index')
|
|
7
|
+
|
|
8
|
+
const env = {
|
|
9
|
+
android: {
|
|
10
|
+
url: 'https://ondemand.saucelabs.com/wd/hub',
|
|
11
|
+
capabilities: {
|
|
12
|
+
name: 'Android Screenshoter Test',
|
|
13
|
+
browserName: '',
|
|
14
|
+
platformName: 'Android',
|
|
15
|
+
platformVersion: '7.0',
|
|
16
|
+
appiumVersion: '1.20.2',
|
|
17
|
+
deviceName: 'Samsung Galaxy S8 FHD GoogleAPI Emulator',
|
|
18
|
+
automationName: 'uiautomator2',
|
|
19
|
+
app: 'https://applitools.jfrog.io/artifactory/Examples/android/1.3/app-debug.apk',
|
|
20
|
+
username: process.env.SAUCE_USERNAME,
|
|
21
|
+
accessKey: process.env.SAUCE_ACCESS_KEY,
|
|
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
|
+
// },
|
|
34
|
+
},
|
|
35
|
+
androidx: {
|
|
36
|
+
url: 'https://ondemand.saucelabs.com/wd/hub',
|
|
37
|
+
capabilities: {
|
|
38
|
+
name: 'AndroidX Screenshoter Test',
|
|
39
|
+
browserName: '',
|
|
40
|
+
platformName: 'Android',
|
|
41
|
+
platformVersion: '10.0',
|
|
42
|
+
appiumVersion: '1.20.2',
|
|
43
|
+
deviceName: 'Google Pixel 3a XL GoogleAPI Emulator',
|
|
44
|
+
automationName: 'uiautomator2',
|
|
45
|
+
app: 'https://applitools.jfrog.io/artifactory/Examples/androidx/1.3.1/app_androidx.apk',
|
|
46
|
+
username: process.env.SAUCE_USERNAME,
|
|
47
|
+
accessKey: process.env.SAUCE_ACCESS_KEY,
|
|
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
|
+
// },
|
|
59
|
+
},
|
|
60
|
+
}
|
|
7
61
|
|
|
8
62
|
describe('screenshoter', () => {
|
|
9
63
|
const logger = {log: () => {}, warn: () => {}, error: () => {}, verbose: () => {}}
|
|
@@ -20,7 +74,7 @@ describe('screenshoter', () => {
|
|
|
20
74
|
|
|
21
75
|
describe('android app', () => {
|
|
22
76
|
before(async () => {
|
|
23
|
-
;[browser, destroyBrowser] = await spec.build(
|
|
77
|
+
;[browser, destroyBrowser] = await spec.build(env.android)
|
|
24
78
|
})
|
|
25
79
|
|
|
26
80
|
after(async () => {
|
|
@@ -57,6 +111,10 @@ describe('screenshoter', () => {
|
|
|
57
111
|
return fullApp({type: 'non-scrollable'})
|
|
58
112
|
})
|
|
59
113
|
|
|
114
|
+
it.skip('take webview screenshot', () => {
|
|
115
|
+
return webview()
|
|
116
|
+
})
|
|
117
|
+
|
|
60
118
|
it('take region screenshot', () => {
|
|
61
119
|
return region()
|
|
62
120
|
})
|
|
@@ -72,7 +130,7 @@ describe('screenshoter', () => {
|
|
|
72
130
|
|
|
73
131
|
describe('androidx app', () => {
|
|
74
132
|
before(async () => {
|
|
75
|
-
;[browser, destroyBrowser] = await spec.build(
|
|
133
|
+
;[browser, destroyBrowser] = await spec.build(env.androidx)
|
|
76
134
|
})
|
|
77
135
|
|
|
78
136
|
after(async () => {
|
|
@@ -89,6 +147,18 @@ describe('screenshoter', () => {
|
|
|
89
147
|
return fullApp({type: 'recycler', x: true})
|
|
90
148
|
})
|
|
91
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
|
+
|
|
92
162
|
it('take full element screenshot', () => {
|
|
93
163
|
return fullElement()
|
|
94
164
|
})
|
|
@@ -97,7 +167,7 @@ describe('screenshoter', () => {
|
|
|
97
167
|
async function app(options = {}) {
|
|
98
168
|
const expectedPath = `./test/fixtures/android/app${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
99
169
|
|
|
100
|
-
const screenshot = await
|
|
170
|
+
const screenshot = await takeScreenshot({logger, driver, wait: 1500, ...options})
|
|
101
171
|
try {
|
|
102
172
|
if (options.withStatusBar) await sanitizeStatusBar(screenshot.image)
|
|
103
173
|
const actual = await screenshot.image.toObject()
|
|
@@ -109,8 +179,18 @@ describe('screenshoter', () => {
|
|
|
109
179
|
}
|
|
110
180
|
}
|
|
111
181
|
async function fullApp({type, x, ...options} = {}) {
|
|
112
|
-
let buttonSelector, expectedPath
|
|
113
|
-
if (type === '
|
|
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') {
|
|
114
194
|
if (x) {
|
|
115
195
|
buttonSelector = {type: 'id', selector: 'btn_recycler_view_activity'}
|
|
116
196
|
expectedPath = `./test/fixtures/android/x-app-fully-recycler${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
@@ -119,7 +199,7 @@ describe('screenshoter', () => {
|
|
|
119
199
|
expectedPath = `./test/fixtures/android/app-fully-recycler${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
120
200
|
}
|
|
121
201
|
} else if (type === 'non-scrollable') {
|
|
122
|
-
buttonSelector = {type: 'id', selector: '
|
|
202
|
+
buttonSelector = {type: 'id', selector: 'btn_activity_as_dialog'}
|
|
123
203
|
expectedPath = `./test/fixtures/android/app-fully-non-scrollable${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
124
204
|
} else {
|
|
125
205
|
buttonSelector = {type: 'id', selector: 'btn_scroll_view_footer_header'}
|
|
@@ -129,7 +209,13 @@ describe('screenshoter', () => {
|
|
|
129
209
|
const button = await driver.element(buttonSelector)
|
|
130
210
|
await button.click()
|
|
131
211
|
|
|
132
|
-
|
|
212
|
+
await driver.init()
|
|
213
|
+
|
|
214
|
+
if (scrollingElementSelector) {
|
|
215
|
+
await driver.currentContext.setScrollingElement(scrollingElementSelector)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const screenshot = await takeScreenshot({
|
|
133
219
|
logger,
|
|
134
220
|
driver,
|
|
135
221
|
fully: true,
|
|
@@ -148,8 +234,29 @@ describe('screenshoter', () => {
|
|
|
148
234
|
throw err
|
|
149
235
|
}
|
|
150
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
|
+
console.log(await driver.target.getContexts())
|
|
244
|
+
await driver.target.switchContext('WEBVIEW')
|
|
245
|
+
|
|
246
|
+
await driver.init()
|
|
247
|
+
|
|
248
|
+
const screenshot = await takeScreenshot({logger, driver, wait: 1500, ...options})
|
|
249
|
+
try {
|
|
250
|
+
const actual = await screenshot.image.toObject()
|
|
251
|
+
const expected = await makeImage(expectedPath).toObject()
|
|
252
|
+
assert.strictEqual(pixelmatch(actual.data, expected.data, null, expected.width, expected.height), 0)
|
|
253
|
+
} catch (err) {
|
|
254
|
+
await screenshot.image.debug({path: './logs', name: 'webview_failed', suffix: Date.now()})
|
|
255
|
+
throw err
|
|
256
|
+
}
|
|
257
|
+
}
|
|
151
258
|
async function region(options) {
|
|
152
|
-
const screenshot = await
|
|
259
|
+
const screenshot = await takeScreenshot({
|
|
153
260
|
logger,
|
|
154
261
|
driver,
|
|
155
262
|
region: {x: 30, y: 500, height: 100, width: 200},
|
|
@@ -166,7 +273,7 @@ describe('screenshoter', () => {
|
|
|
166
273
|
}
|
|
167
274
|
}
|
|
168
275
|
async function fullRegion(options) {
|
|
169
|
-
const screenshot = await
|
|
276
|
+
const screenshot = await takeScreenshot({
|
|
170
277
|
logger,
|
|
171
278
|
driver,
|
|
172
279
|
region: {x: 30, y: 10, height: 700, width: 200},
|
|
@@ -184,7 +291,7 @@ describe('screenshoter', () => {
|
|
|
184
291
|
}
|
|
185
292
|
}
|
|
186
293
|
async function element(options) {
|
|
187
|
-
const screenshot = await
|
|
294
|
+
const screenshot = await takeScreenshot({
|
|
188
295
|
logger,
|
|
189
296
|
driver,
|
|
190
297
|
region: {type: 'id', selector: 'btn_recycler_view'},
|
|
@@ -207,7 +314,7 @@ describe('screenshoter', () => {
|
|
|
207
314
|
})
|
|
208
315
|
await button.click()
|
|
209
316
|
|
|
210
|
-
const screenshot = await
|
|
317
|
+
const screenshot = await takeScreenshot({
|
|
211
318
|
logger,
|
|
212
319
|
driver,
|
|
213
320
|
region: {type: 'id', selector: 'recyclerView'},
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
const assert = require('assert')
|
|
2
|
+
const pixelmatch = require('pixelmatch')
|
|
3
|
+
const {Driver} = require('@applitools/driver')
|
|
4
|
+
const utils = require('@applitools/utils')
|
|
5
|
+
const spec = require('@applitools/spec-driver-webdriverio')
|
|
6
|
+
const makeImage = require('../../src/image')
|
|
7
|
+
const takeScreenshot = require('../../index')
|
|
8
|
+
|
|
9
|
+
describe.skip('external tests', () => {
|
|
10
|
+
const logger = {log: () => {}, warn: () => {}, error: () => {}, verbose: () => {}}
|
|
11
|
+
let browser, destroyBrowser
|
|
12
|
+
|
|
13
|
+
afterEach(async () => {
|
|
14
|
+
await destroyBrowser()
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('AGL Android - full app screenshot of the view with animated scroll', async () => {
|
|
18
|
+
const expectedPath = `./test/fixtures/external/agl.png`
|
|
19
|
+
|
|
20
|
+
;[browser, destroyBrowser] = await spec.build({
|
|
21
|
+
url: 'https://hub.browserstack.com/wd/hub',
|
|
22
|
+
capabilities: {
|
|
23
|
+
platformName: 'android',
|
|
24
|
+
'appium:platformVersion': '11.0',
|
|
25
|
+
'appium:deviceName': 'Google Pixel 5',
|
|
26
|
+
'appium:app': 'agl_app_android',
|
|
27
|
+
'bstack:options': {
|
|
28
|
+
userName: process.env.BROWSERSTACK_USERNAME,
|
|
29
|
+
accessKey: process.env.BROWSERSTACK_ACCESS_KEY,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
await browser.closeApp()
|
|
35
|
+
await browser.launchApp()
|
|
36
|
+
const driver = await new Driver({driver: browser, spec, logger}).init()
|
|
37
|
+
|
|
38
|
+
const saveBtn = await browser.$('//android.widget.Button')
|
|
39
|
+
await saveBtn.click()
|
|
40
|
+
|
|
41
|
+
await utils.general.sleep(8000)
|
|
42
|
+
const signinBtn = await browser.$('//android.widget.Button[@text="SIGN IN"]')
|
|
43
|
+
await signinBtn.click()
|
|
44
|
+
await utils.general.sleep(10000)
|
|
45
|
+
const emailInput = await browser.$('//android.widget.EditText')
|
|
46
|
+
await emailInput.setValue('daniel.martin@toro.com')
|
|
47
|
+
const nxtBtn = await browser.$('//android.widget.Button[@text="NEXT"]')
|
|
48
|
+
await nxtBtn.click()
|
|
49
|
+
await utils.general.sleep(10000)
|
|
50
|
+
const passwordInput = await browser.$('//android.widget.EditText[@password="true"]')
|
|
51
|
+
await passwordInput.setValue('Welcome@1')
|
|
52
|
+
const loginBtn = await browser.$('//android.widget.Button[@text="LOGIN"]')
|
|
53
|
+
await loginBtn.click()
|
|
54
|
+
await utils.general.sleep(18000)
|
|
55
|
+
const skipBtn = await browser.$('//android.widget.Button[@text="SKIP"]')
|
|
56
|
+
await skipBtn.click()
|
|
57
|
+
await utils.general.sleep(5000)
|
|
58
|
+
const finishBtn = await browser.$('//android.widget.Button[@text="FINISH"]')
|
|
59
|
+
await finishBtn.click()
|
|
60
|
+
await utils.general.sleep(15000)
|
|
61
|
+
|
|
62
|
+
await driver.init()
|
|
63
|
+
|
|
64
|
+
const screenshot = await takeScreenshot({
|
|
65
|
+
logger,
|
|
66
|
+
driver,
|
|
67
|
+
fully: true,
|
|
68
|
+
framed: true,
|
|
69
|
+
stabilization: {crop: {top: 53, bottom: 16, left: 0, right: 0}},
|
|
70
|
+
debug: {path: './'},
|
|
71
|
+
})
|
|
72
|
+
try {
|
|
73
|
+
const actual = await screenshot.image.toObject()
|
|
74
|
+
const expected = await makeImage(expectedPath).toObject()
|
|
75
|
+
assert.strictEqual(pixelmatch(actual.data, expected.data, null, expected.width, expected.height), 0)
|
|
76
|
+
} catch (err) {
|
|
77
|
+
await screenshot.image.debug({path: './logs', name: 'viewport_failed', suffix: Date.now()})
|
|
78
|
+
throw err
|
|
79
|
+
}
|
|
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
|
+
})
|
|
155
|
+
})
|