@applitools/screenshoter 3.2.3 → 3.2.7
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 +53 -10
- package/.bongo/dry-run/package.json +5 -0
- package/.bongo/dry-run.tgz +0 -0
- package/CHANGELOG.md +18 -0
- package/logs/screenshot_2021_10_13_05_50_49_159Z_full_app_failed_1634104249159.png +0 -0
- package/package.json +5 -5
- package/src/image.js +1 -1
- package/src/screenshoter.js +19 -14
- package/src/take-screenshot.js +1 -0
- package/src/take-stitched-screenshot.js +1 -1
- package/test/e2e/android.spec.js +8 -1
- package/test/fixtures/android/app-fully-non-scrollable.png +0 -0
- package/test/fixtures/android/region.png +0 -0
- package/test/util/spec-driver.js +12 -13
- package/logs/screenshot_2021_08_12_10_21_06_033Z_full_app_failed_1628763666033.png +0 -0
- package/logs/screenshot_2021_08_12_10_34_27_290Z_ios_viewport_failed.png +0 -0
- package/logs/screenshot_2021_08_12_10_34_28_434Z_ios_full_page_failed.png +0 -0
- package/logs/screenshot_2021_08_12_10_43_02_793Z_full_app_failed_1628764982793.png +0 -0
- package/logs/screenshot_2021_08_12_11_03_20_837Z_region_failed_1628766200837.png +0 -0
- package/logs/screenshot_2021_08_12_11_11_33_054Z_full_app_failed_1628766693054.png +0 -0
- package/logs/screenshot_2021_08_12_12_46_06_592Z_viewport_failed_1628772366592.png +0 -0
- package/logs/screenshot_2021_08_12_12_46_15_832Z_viewport_failed_1628772375832.png +0 -0
- package/logs/screenshot_2021_08_12_12_49_45_671Z_viewport_failed_1628772585671.png +0 -0
- package/logs/screenshot_2021_08_12_12_49_56_939Z_viewport_failed_1628772596939.png +0 -0
- package/logs/screenshot_2021_08_12_12_51_32_701Z_full_app_failed_1628772692701.png +0 -0
- package/logs/screenshot_2021_08_12_12_58_47_681Z_region_failed_1628773127681.png +0 -0
- package/logs/screenshot_2021_08_12_13_11_30_839Z_viewport_failed_1628773890839.png +0 -0
- package/logs/screenshot_2021_08_12_13_11_54_642Z_viewport_failed_1628773914642.png +0 -0
- package/logs/screenshot_2021_08_12_13_16_08_255Z_element_failed.png +0 -0
- package/logs/screenshot_2021_08_12_13_38_10_302Z_region_failed_1628775490302.png +0 -0
|
@@ -1,25 +1,68 @@
|
|
|
1
1
|
{
|
|
2
|
+
"name": "dry-run",
|
|
3
|
+
"lockfileVersion": 2,
|
|
2
4
|
"requires": true,
|
|
3
|
-
"
|
|
5
|
+
"packages": {
|
|
6
|
+
"": {
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@applitools/screenshoter": "file:../dry-run.tgz"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"node_modules/@applitools/screenshoter": {
|
|
12
|
+
"version": "3.2.6",
|
|
13
|
+
"resolved": "file:../dry-run.tgz",
|
|
14
|
+
"integrity": "sha512-WzfjtYPRtHz35A5qzYaJbVWkyB17lnzu1JHun6I8U6NvBIOIoxKRiT3H/9YSZqr/WR+eGAXRLV7gYi53/nsmKw==",
|
|
15
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@applitools/snippets": "2.1.7",
|
|
18
|
+
"@applitools/utils": "1.2.3",
|
|
19
|
+
"png-async": "0.9.4"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">= 8.9.0"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"node_modules/@applitools/snippets": {
|
|
26
|
+
"version": "2.1.7",
|
|
27
|
+
"resolved": "https://registry.npmjs.org/@applitools/snippets/-/snippets-2.1.7.tgz",
|
|
28
|
+
"integrity": "sha512-Tr4Gj7Qov/oPy+8WI4oVmmubxqpOzr8P3Wjzpl6rA57xKLg6/TiIg5oZNb4+jEmO2ShjNYLaEwRWHl7kPgb4fw==",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=8.9.0"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"node_modules/@applitools/utils": {
|
|
34
|
+
"version": "1.2.3",
|
|
35
|
+
"resolved": "https://registry.npmjs.org/@applitools/utils/-/utils-1.2.3.tgz",
|
|
36
|
+
"integrity": "sha512-MZXsrzeHTvjFLzpfyKRDUmZWzNxH3gWd3reqYf+1kYimALKB3CO82VDNmkaGJykrRbxEP03Yqha7fHJj9eKslQ==",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">= 8.9.0"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"node_modules/png-async": {
|
|
42
|
+
"version": "0.9.4",
|
|
43
|
+
"resolved": "https://registry.npmjs.org/png-async/-/png-async-0.9.4.tgz",
|
|
44
|
+
"integrity": "sha512-B//AXX9TkneKfgtOpT1mdUnnhk2BImGD+a98vImsMU8uo1dBeHyW/kM2erWZ/CsYteTPU/xKG+t6T62heHkC3A=="
|
|
45
|
+
}
|
|
46
|
+
},
|
|
4
47
|
"dependencies": {
|
|
5
48
|
"@applitools/screenshoter": {
|
|
6
49
|
"version": "file:../dry-run.tgz",
|
|
7
|
-
"integrity": "sha512-
|
|
50
|
+
"integrity": "sha512-WzfjtYPRtHz35A5qzYaJbVWkyB17lnzu1JHun6I8U6NvBIOIoxKRiT3H/9YSZqr/WR+eGAXRLV7gYi53/nsmKw==",
|
|
8
51
|
"requires": {
|
|
9
|
-
"@applitools/snippets": "2.1.
|
|
10
|
-
"@applitools/utils": "1.2.
|
|
52
|
+
"@applitools/snippets": "2.1.7",
|
|
53
|
+
"@applitools/utils": "1.2.3",
|
|
11
54
|
"png-async": "0.9.4"
|
|
12
55
|
}
|
|
13
56
|
},
|
|
14
57
|
"@applitools/snippets": {
|
|
15
|
-
"version": "2.1.
|
|
16
|
-
"resolved": "https://registry.npmjs.org/@applitools/snippets/-/snippets-2.1.
|
|
17
|
-
"integrity": "sha512-
|
|
58
|
+
"version": "2.1.7",
|
|
59
|
+
"resolved": "https://registry.npmjs.org/@applitools/snippets/-/snippets-2.1.7.tgz",
|
|
60
|
+
"integrity": "sha512-Tr4Gj7Qov/oPy+8WI4oVmmubxqpOzr8P3Wjzpl6rA57xKLg6/TiIg5oZNb4+jEmO2ShjNYLaEwRWHl7kPgb4fw=="
|
|
18
61
|
},
|
|
19
62
|
"@applitools/utils": {
|
|
20
|
-
"version": "1.2.
|
|
21
|
-
"resolved": "https://registry.npmjs.org/@applitools/utils/-/utils-1.2.
|
|
22
|
-
"integrity": "sha512-
|
|
63
|
+
"version": "1.2.3",
|
|
64
|
+
"resolved": "https://registry.npmjs.org/@applitools/utils/-/utils-1.2.3.tgz",
|
|
65
|
+
"integrity": "sha512-MZXsrzeHTvjFLzpfyKRDUmZWzNxH3gWd3reqYf+1kYimALKB3CO82VDNmkaGJykrRbxEP03Yqha7fHJj9eKslQ=="
|
|
23
66
|
},
|
|
24
67
|
"png-async": {
|
|
25
68
|
"version": "0.9.4",
|
package/.bongo/dry-run.tgz
CHANGED
|
Binary file
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@
|
|
|
4
4
|
## Unreleased
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
## 3.2.7 - 2021/10/13
|
|
8
|
+
|
|
9
|
+
- handle a case when scrolling element does not exist
|
|
10
|
+
|
|
11
|
+
## 3.2.6 - 2021/10/12
|
|
12
|
+
|
|
13
|
+
- handle a case when scrolling element does not exist
|
|
14
|
+
|
|
15
|
+
## 3.2.5 - 2021/10/5
|
|
16
|
+
|
|
17
|
+
- fix issue with fractional image size after scaling
|
|
18
|
+
|
|
19
|
+
## 3.2.4 - 2021/9/9
|
|
20
|
+
|
|
21
|
+
- handle selectors that evaluate to elements from a different context
|
|
22
|
+
- updated to @applitools/snippets@2.1.7 (from 2.1.4)
|
|
23
|
+
- updated to @applitools/utils@1.2.3 (from 1.2.2)
|
|
24
|
+
|
|
7
25
|
## 3.2.3 - 2021/8/13
|
|
8
26
|
|
|
9
27
|
- remove base64 sanitizing
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applitools/screenshoter",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.7",
|
|
4
4
|
"description": "Applitools universal screenshoter for web and native applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"applitools",
|
|
@@ -48,13 +48,13 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@applitools/snippets": "2.1.
|
|
52
|
-
"@applitools/utils": "1.2.
|
|
51
|
+
"@applitools/snippets": "2.1.7",
|
|
52
|
+
"@applitools/utils": "1.2.3",
|
|
53
53
|
"png-async": "0.9.4"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@applitools/driver": "1.
|
|
57
|
-
"@applitools/sdk-release-kit": "0.13.
|
|
56
|
+
"@applitools/driver": "1.2.6",
|
|
57
|
+
"@applitools/sdk-release-kit": "0.13.3",
|
|
58
58
|
"eslint": "^7.9.0",
|
|
59
59
|
"eslint-plugin-mocha-no-only": "^1.1.1",
|
|
60
60
|
"eslint-plugin-node": "^11.1.0",
|
package/src/image.js
CHANGED
package/src/screenshoter.js
CHANGED
|
@@ -54,13 +54,14 @@ async function screenshoter({
|
|
|
54
54
|
try {
|
|
55
55
|
if (!window) await scrollIntoViewport({...target, logger})
|
|
56
56
|
|
|
57
|
-
const screenshot =
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
const screenshot =
|
|
58
|
+
fully && target.scroller
|
|
59
|
+
? await takeStitchedScreenshot({...target, withStatusBar, overlap, framed, wait, stabilization, debug, logger})
|
|
60
|
+
: await takeViewportScreenshot({...target, withStatusBar, wait, stabilization, debug, logger})
|
|
60
61
|
|
|
61
62
|
if (hooks && hooks.afterScreenshot) {
|
|
62
63
|
// imitate image-like state for the hook
|
|
63
|
-
if (window && fully) {
|
|
64
|
+
if (window && fully && target.scroller) {
|
|
64
65
|
await target.scroller.moveTo({x: 0, y: 0}, await driver.mainContext.getScrollingElement())
|
|
65
66
|
}
|
|
66
67
|
await hooks.afterScreenshot({driver, scroller: target.scroller, screenshot})
|
|
@@ -68,7 +69,9 @@ async function screenshoter({
|
|
|
68
69
|
|
|
69
70
|
return screenshot
|
|
70
71
|
} finally {
|
|
71
|
-
|
|
72
|
+
if (target.scroller) {
|
|
73
|
+
await target.scroller.restoreScrollbars()
|
|
74
|
+
}
|
|
72
75
|
|
|
73
76
|
// if there was active element and we have blurred it, then restore focus
|
|
74
77
|
if (activeElement) await context.focusElement(activeElement)
|
|
@@ -93,7 +96,7 @@ async function getTarget({window, context, region, fully, scrollingMode, logger}
|
|
|
93
96
|
const scrollingElement = await context.main.getScrollingElement()
|
|
94
97
|
return {
|
|
95
98
|
context: context.main,
|
|
96
|
-
scroller: makeScroller({element: scrollingElement, scrollingMode, logger}),
|
|
99
|
+
scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
|
|
97
100
|
}
|
|
98
101
|
} else if (region) {
|
|
99
102
|
if (utils.types.has(region, ['x', 'y', 'width', 'height'])) {
|
|
@@ -102,31 +105,33 @@ async function getTarget({window, context, region, fully, scrollingMode, logger}
|
|
|
102
105
|
return {
|
|
103
106
|
context,
|
|
104
107
|
region,
|
|
105
|
-
scroller: makeScroller({element: scrollingElement, scrollingMode, logger}),
|
|
108
|
+
scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
|
|
106
109
|
}
|
|
107
110
|
} else {
|
|
108
111
|
// region by element or selector
|
|
109
112
|
const element = await context.element(region)
|
|
110
113
|
if (!element) throw new Error('Element not found!')
|
|
111
114
|
|
|
115
|
+
const elementContext = element.context
|
|
116
|
+
|
|
112
117
|
if (fully) {
|
|
113
118
|
const isScrollable = await element.isScrollable()
|
|
114
119
|
// if element is scrollable, then take screenshot of the full element content, otherwise take screenshot of full element
|
|
115
120
|
const region = isScrollable ? null : await element.getRegion()
|
|
116
|
-
const scrollingElement = isScrollable ? element : await
|
|
121
|
+
const scrollingElement = isScrollable ? element : await elementContext.getScrollingElement()
|
|
117
122
|
// css stitching could be applied only to root element of its context
|
|
118
123
|
scrollingMode = scrollingMode === 'css' && !(await scrollingElement.isRoot()) ? 'mixed' : scrollingMode
|
|
119
124
|
return {
|
|
120
|
-
context,
|
|
125
|
+
context: elementContext,
|
|
121
126
|
region,
|
|
122
|
-
scroller: makeScroller({element: scrollingElement, scrollingMode, logger}),
|
|
127
|
+
scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
|
|
123
128
|
}
|
|
124
129
|
} else {
|
|
125
130
|
const scrollingElement = await context.getScrollingElement()
|
|
126
131
|
return {
|
|
127
|
-
context,
|
|
132
|
+
context: elementContext,
|
|
128
133
|
region: await element.getRegion(),
|
|
129
|
-
scroller: makeScroller({element: scrollingElement, scrollingMode, logger}),
|
|
134
|
+
scroller: scrollingElement ? makeScroller({element: scrollingElement, scrollingMode, logger}) : null,
|
|
130
135
|
}
|
|
131
136
|
}
|
|
132
137
|
}
|
|
@@ -136,7 +141,7 @@ async function getTarget({window, context, region, fully, scrollingMode, logger}
|
|
|
136
141
|
const scrollingElement = await context.getScrollingElement()
|
|
137
142
|
return {
|
|
138
143
|
context,
|
|
139
|
-
scroller: makeScroller({logger, element: scrollingElement, scrollingMode}),
|
|
144
|
+
scroller: scrollingElement ? makeScroller({logger, element: scrollingElement, scrollingMode}) : null,
|
|
140
145
|
}
|
|
141
146
|
} else {
|
|
142
147
|
const scrollingElement = await context.parent.getScrollingElement()
|
|
@@ -144,7 +149,7 @@ async function getTarget({window, context, region, fully, scrollingMode, logger}
|
|
|
144
149
|
return {
|
|
145
150
|
context: context.parent,
|
|
146
151
|
region: await element.getRegion(), // IMHO we should use CLIENT (without borders) region here
|
|
147
|
-
scroller: makeScroller({logger, element: scrollingElement, scrollingMode}),
|
|
152
|
+
scroller: scrollingElement ? makeScroller({logger, element: scrollingElement, scrollingMode}) : null,
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
}
|
package/src/take-screenshot.js
CHANGED
|
@@ -107,6 +107,7 @@ function makeTakeMarkedScreenshot({driver, stabilization = {}, debug, logger}) {
|
|
|
107
107
|
else {
|
|
108
108
|
if (!viewportRegion) viewportRegion = await getViewportRegion()
|
|
109
109
|
image.crop(viewportRegion)
|
|
110
|
+
await image.debug({...debug, name, suffix: 'viewport'})
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
return image
|
|
@@ -55,7 +55,7 @@ async function takeStitchedScreenshot({
|
|
|
55
55
|
|
|
56
56
|
// TODO padding should be provided from args instead of overlap
|
|
57
57
|
const padding = {top: overlap, bottom: overlap}
|
|
58
|
-
const [initialRegion, ...partRegions] = utils.geometry.divide(region, image.size, padding)
|
|
58
|
+
const [initialRegion, ...partRegions] = utils.geometry.divide(region, utils.geometry.round(image.size), padding)
|
|
59
59
|
logger.verbose('Part regions', partRegions)
|
|
60
60
|
|
|
61
61
|
logger.verbose('Creating stitched image composition container')
|
package/test/e2e/android.spec.js
CHANGED
|
@@ -53,8 +53,12 @@ describe('screenshoter', () => {
|
|
|
53
53
|
return fullApp({type: 'recycler'})
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
+
it('take full app screenshot (non-scrollable)', () => {
|
|
57
|
+
return fullApp({type: 'non-scrollable'})
|
|
58
|
+
})
|
|
59
|
+
|
|
56
60
|
it('take region screenshot', () => {
|
|
57
|
-
region()
|
|
61
|
+
return region()
|
|
58
62
|
})
|
|
59
63
|
|
|
60
64
|
it.skip('take full region screenshot', () => {
|
|
@@ -114,6 +118,9 @@ describe('screenshoter', () => {
|
|
|
114
118
|
buttonSelector = {type: 'id', selector: 'btn_recycler_view'}
|
|
115
119
|
expectedPath = `./test/fixtures/android/app-fully-recycler${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
116
120
|
}
|
|
121
|
+
} else if (type === 'non-scrollable') {
|
|
122
|
+
buttonSelector = {type: 'id', selector: 'btn_edit_text'}
|
|
123
|
+
expectedPath = `./test/fixtures/android/app-fully-non-scrollable${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
117
124
|
} else {
|
|
118
125
|
buttonSelector = {type: 'id', selector: 'btn_scroll_view_footer_header'}
|
|
119
126
|
expectedPath = `./test/fixtures/android/app-fully-scroll${options.withStatusBar ? '-statusbar' : ''}.png`
|
|
Binary file
|
|
Binary file
|
package/test/util/spec-driver.js
CHANGED
|
@@ -10,12 +10,6 @@ function extractElementId(element) {
|
|
|
10
10
|
return element.elementId || element[ELEMENT_ID] || element[LEGACY_ELEMENT_ID]
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
function transformSelector(selector) {
|
|
14
|
-
if (!utils.types.has(selector, ['type', 'selector'])) return selector
|
|
15
|
-
else if (selector.type === 'css') return `css selector:${selector.selector}`
|
|
16
|
-
else return `${selector.type}:${selector.selector}`
|
|
17
|
-
}
|
|
18
|
-
|
|
19
13
|
// #endregion
|
|
20
14
|
|
|
21
15
|
// #region UTILITY
|
|
@@ -29,16 +23,20 @@ function isElement(element) {
|
|
|
29
23
|
return Boolean(element.elementId || element[ELEMENT_ID] || element[LEGACY_ELEMENT_ID])
|
|
30
24
|
}
|
|
31
25
|
function isSelector(selector) {
|
|
32
|
-
return (
|
|
33
|
-
utils.types.isString(selector) ||
|
|
34
|
-
utils.types.isFunction(selector) ||
|
|
35
|
-
utils.types.has(selector, ['type', 'selector'])
|
|
36
|
-
)
|
|
26
|
+
return utils.types.isString(selector) || utils.types.isFunction(selector)
|
|
37
27
|
}
|
|
38
28
|
function transformElement(element) {
|
|
39
29
|
const elementId = extractElementId(element)
|
|
40
30
|
return {[ELEMENT_ID]: elementId, [LEGACY_ELEMENT_ID]: elementId}
|
|
41
31
|
}
|
|
32
|
+
function transformSelector(selector) {
|
|
33
|
+
if (utils.types.has(selector, 'selector')) {
|
|
34
|
+
if (!utils.types.has(selector, 'type')) return selector.selector
|
|
35
|
+
if (selector.type === 'css') return `css selector:${selector.selector}`
|
|
36
|
+
else return `${selector.type}:${selector.selector}`
|
|
37
|
+
}
|
|
38
|
+
return selector
|
|
39
|
+
}
|
|
42
40
|
function extractSelector(element) {
|
|
43
41
|
return element.selector
|
|
44
42
|
}
|
|
@@ -74,11 +72,11 @@ async function childContext(browser, element) {
|
|
|
74
72
|
return browser
|
|
75
73
|
}
|
|
76
74
|
async function findElement(browser, selector) {
|
|
77
|
-
const element = await browser.$(
|
|
75
|
+
const element = await browser.$(selector)
|
|
78
76
|
return !element.error ? element : null
|
|
79
77
|
}
|
|
80
78
|
async function findElements(browser, selector) {
|
|
81
|
-
const elements = await browser.$$(
|
|
79
|
+
const elements = await browser.$$(selector)
|
|
82
80
|
return Array.from(elements)
|
|
83
81
|
}
|
|
84
82
|
async function getElementRegion(browser, element) {
|
|
@@ -265,6 +263,7 @@ module.exports = {
|
|
|
265
263
|
isElement,
|
|
266
264
|
isSelector,
|
|
267
265
|
transformElement,
|
|
266
|
+
transformSelector,
|
|
268
267
|
extractSelector,
|
|
269
268
|
isEqualElements,
|
|
270
269
|
executeScript,
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|