@applitools/screenshoter 3.2.8 → 3.2.9
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 +45 -2
- package/.bongo/dry-run/package.json +5 -0
- package/.bongo/dry-run.tgz +0 -0
- package/CHANGELOG.md +4 -0
- 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/package.json +6 -3
- package/src/image.js +4 -1
- package/src/screenshoter.js +1 -0
- package/src/take-screenshot.js +1 -1
- package/src/take-stitched-screenshot.js +20 -6
- package/test/e2e/android.spec.js +36 -3
- package/test/e2e/external.spec.js +84 -0
- package/test/e2e/ios.spec.js +17 -2
- package/test/e2e/web-ios.spec.js +17 -2
- package/test/e2e/web.spec.js +13 -6
- package/test/fixtures/external/agl.png +0 -0
- package/test/fixtures/ios/app-fully-table.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/docker-compose.yaml +0 -29
- package/test/util/spec-driver.js +0 -288
|
@@ -1,10 +1,53 @@
|
|
|
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.8",
|
|
13
|
+
"resolved": "file:../dry-run.tgz",
|
|
14
|
+
"integrity": "sha512-GjN+h/vj5/lKFjJPm302jD0xSFIOoSG7gPU/ogEUcCS9l5FDcMW27PRMA/xGlolKrabmCgDHJqVbAXE1WCgjyQ==",
|
|
15
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@applitools/snippets": "2.1.7",
|
|
18
|
+
"@applitools/utils": "1.2.4",
|
|
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.4",
|
|
35
|
+
"resolved": "https://registry.npmjs.org/@applitools/utils/-/utils-1.2.4.tgz",
|
|
36
|
+
"integrity": "sha512-w7ma6FFGyqhdP6LEcuHFWOcH7EzBjnoAX3UfbFWcTHA3QXnXPX37Y2ENYRodfwkorP1cUKyUHwNXJB/BMIj/hg==",
|
|
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-GjN+h/vj5/lKFjJPm302jD0xSFIOoSG7gPU/ogEUcCS9l5FDcMW27PRMA/xGlolKrabmCgDHJqVbAXE1WCgjyQ==",
|
|
8
51
|
"requires": {
|
|
9
52
|
"@applitools/snippets": "2.1.7",
|
|
10
53
|
"@applitools/utils": "1.2.4",
|
package/.bongo/dry-run.tgz
CHANGED
|
Binary file
|
package/CHANGELOG.md
CHANGED
|
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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
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.9",
|
|
4
4
|
"description": "Applitools universal screenshoter for web and native applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"applitools",
|
|
@@ -54,8 +54,11 @@
|
|
|
54
54
|
"png-async": "0.9.4"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@applitools/driver": "1.2
|
|
57
|
+
"@applitools/driver": "1.3.2",
|
|
58
58
|
"@applitools/sdk-release-kit": "0.13.4",
|
|
59
|
+
"@applitools/spec-driver-webdriverio": "1.2.0",
|
|
60
|
+
"@applitools/test-utils": "1.0.9",
|
|
61
|
+
"chromedriver": "^95.0.0",
|
|
59
62
|
"eslint": "^7.9.0",
|
|
60
63
|
"eslint-plugin-mocha-no-only": "^1.1.1",
|
|
61
64
|
"eslint-plugin-node": "^11.1.0",
|
|
@@ -64,7 +67,7 @@
|
|
|
64
67
|
"mocha": "^8.2.1",
|
|
65
68
|
"pixelmatch": "^5.2.1",
|
|
66
69
|
"prettier": "1.19.0",
|
|
67
|
-
"webdriverio": "^
|
|
70
|
+
"webdriverio": "^7.16.7"
|
|
68
71
|
},
|
|
69
72
|
"engines": {
|
|
70
73
|
"node": ">= 8.9.0"
|
package/src/image.js
CHANGED
|
@@ -289,7 +289,10 @@ async function copy(dstImage, srcImage, offset) {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
async function combine(firstImage, lastImage, srcImage, region) {
|
|
292
|
-
region = utils.geometry.intersect(
|
|
292
|
+
region = utils.geometry.intersect(
|
|
293
|
+
{x: 0, y: 0, width: firstImage.width, height: firstImage.height},
|
|
294
|
+
utils.geometry.round(region),
|
|
295
|
+
)
|
|
293
296
|
|
|
294
297
|
if (region.x === 0 && region.y === 0 && region.width >= firstImage.width && region.height >= firstImage.height) {
|
|
295
298
|
return srcImage
|
package/src/screenshoter.js
CHANGED
|
@@ -27,6 +27,7 @@ async function screenshoter({
|
|
|
27
27
|
framed = framed && fully && window
|
|
28
28
|
// screenshots with status bar could be taken only when screenshot of app or framed app fully was requested
|
|
29
29
|
withStatusBar = withStatusBar && driver.isNative && window && (!fully || framed)
|
|
30
|
+
scrollingMode = driver.isNative ? 'scroll' : scrollingMode
|
|
30
31
|
|
|
31
32
|
const activeContext = driver.currentContext
|
|
32
33
|
const context =
|
package/src/take-screenshot.js
CHANGED
|
@@ -150,7 +150,7 @@ function makeTakeNativeScreenshot({driver, stabilization = {}, debug, logger}) {
|
|
|
150
150
|
const viewportSize = await driver.getViewportSize()
|
|
151
151
|
const cropRegion = withStatusBar
|
|
152
152
|
? {x: 0, y: 0, width: viewportSize.width, height: viewportSize.height + driver.statusBarHeight}
|
|
153
|
-
: {
|
|
153
|
+
: {top: driver.statusBarHeight, bottom: driver.navigationBarHeight, left: 0, right: 0}
|
|
154
154
|
image.crop(cropRegion)
|
|
155
155
|
await image.debug({...debug, name, suffix: `viewport${withStatusBar ? '-with-statusbar' : ''}`})
|
|
156
156
|
}
|
|
@@ -26,6 +26,8 @@ async function takeStitchedScreenshot({
|
|
|
26
26
|
|
|
27
27
|
await utils.general.sleep(wait)
|
|
28
28
|
|
|
29
|
+
const contentSize = await scroller.getContentSize()
|
|
30
|
+
|
|
29
31
|
logger.verbose('Getting initial image...')
|
|
30
32
|
let image = await takeScreenshot({name: 'initial', withStatusBar})
|
|
31
33
|
const firstImage = framed ? makeImage(image) : null
|
|
@@ -39,13 +41,13 @@ async function takeStitchedScreenshot({
|
|
|
39
41
|
|
|
40
42
|
// TODO the solution should not check driver specifics,
|
|
41
43
|
// in this case target region coordinate should be already related to the scrolling element of the context
|
|
42
|
-
|
|
44
|
+
let cropRegion = driver.isNative ? targetRegion : await driver.getRegionInViewport(context, targetRegion)
|
|
43
45
|
|
|
44
46
|
logger.verbose('cropping...')
|
|
45
47
|
image.crop(withStatusBar ? utils.geometry.offset(cropRegion, {x: 0, y: driver.statusBarHeight}) : cropRegion)
|
|
46
48
|
await image.debug({...debug, name: 'initial', suffix: 'region'})
|
|
47
49
|
|
|
48
|
-
const contentRegion = utils.geometry.region({x: 0, y: 0},
|
|
50
|
+
const contentRegion = utils.geometry.region({x: 0, y: 0}, contentSize)
|
|
49
51
|
logger.verbose(`Scroller size: ${contentRegion}`)
|
|
50
52
|
|
|
51
53
|
if (region) region = utils.geometry.intersect(region, contentRegion)
|
|
@@ -84,11 +86,21 @@ async function takeStitchedScreenshot({
|
|
|
84
86
|
),
|
|
85
87
|
compensateOffset,
|
|
86
88
|
)
|
|
89
|
+
|
|
90
|
+
// TODO come up with generic solution
|
|
91
|
+
// The problem is that web default scrolling element treated differently than normal scrollable elements on the web and native
|
|
92
|
+
const cropRegionOffset = driver.isNative
|
|
93
|
+
? utils.geometry.offsetNegative(
|
|
94
|
+
utils.geometry.location(await scroller.getClientRegion()),
|
|
95
|
+
utils.geometry.location(cropRegion),
|
|
96
|
+
)
|
|
97
|
+
: {x: 0, y: 0}
|
|
98
|
+
|
|
87
99
|
const cropPartRegion = {
|
|
88
|
-
x: cropRegion.x + remainingOffset.x,
|
|
89
|
-
y: cropRegion.y + remainingOffset.y,
|
|
90
|
-
width: partRegion.width,
|
|
91
|
-
height: partRegion.height,
|
|
100
|
+
x: cropRegion.x + remainingOffset.x + cropRegionOffset.x,
|
|
101
|
+
y: cropRegion.y + remainingOffset.y + cropRegionOffset.y,
|
|
102
|
+
width: partRegion.width - cropRegionOffset.x,
|
|
103
|
+
height: partRegion.height - cropRegionOffset.y,
|
|
92
104
|
}
|
|
93
105
|
logger.verbose(`Actual offset is ${actualOffset}, remaining offset is ${remainingOffset}`)
|
|
94
106
|
|
|
@@ -105,6 +117,8 @@ async function takeStitchedScreenshot({
|
|
|
105
117
|
await image.debug({...debug, name: partName, suffix: 'region'})
|
|
106
118
|
|
|
107
119
|
const pasteOffset = utils.geometry.offsetNegative(utils.geometry.location(partRegion), initialOffset)
|
|
120
|
+
pasteOffset.y += cropRegionOffset.y
|
|
121
|
+
pasteOffset.x += cropRegionOffset.x
|
|
108
122
|
await stitchedImage.copy(image, pasteOffset)
|
|
109
123
|
|
|
110
124
|
stitchedSize = {width: pasteOffset.x + image.width, height: pasteOffset.y + image.height}
|
package/test/e2e/android.spec.js
CHANGED
|
@@ -1,10 +1,43 @@
|
|
|
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
6
|
const screenshoter = require('../../index')
|
|
7
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
|
+
androidx: {
|
|
25
|
+
url: 'https://ondemand.saucelabs.com/wd/hub',
|
|
26
|
+
capabilities: {
|
|
27
|
+
name: 'AndroidX Screenshoter Test',
|
|
28
|
+
browserName: '',
|
|
29
|
+
platformName: 'Android',
|
|
30
|
+
platformVersion: '10.0',
|
|
31
|
+
appiumVersion: '1.20.2',
|
|
32
|
+
deviceName: 'Google Pixel 3a XL GoogleAPI Emulator',
|
|
33
|
+
automationName: 'uiautomator2',
|
|
34
|
+
app: 'https://applitools.jfrog.io/artifactory/Examples/androidx/1.2.0/app_androidx.apk',
|
|
35
|
+
username: process.env.SAUCE_USERNAME,
|
|
36
|
+
accessKey: process.env.SAUCE_ACCESS_KEY,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
|
|
8
41
|
describe('screenshoter', () => {
|
|
9
42
|
const logger = {log: () => {}, warn: () => {}, error: () => {}, verbose: () => {}}
|
|
10
43
|
let driver, browser, destroyBrowser
|
|
@@ -20,7 +53,7 @@ describe('screenshoter', () => {
|
|
|
20
53
|
|
|
21
54
|
describe('android app', () => {
|
|
22
55
|
before(async () => {
|
|
23
|
-
;[browser, destroyBrowser] = await spec.build(
|
|
56
|
+
;[browser, destroyBrowser] = await spec.build(env.android)
|
|
24
57
|
})
|
|
25
58
|
|
|
26
59
|
after(async () => {
|
|
@@ -72,7 +105,7 @@ describe('screenshoter', () => {
|
|
|
72
105
|
|
|
73
106
|
describe('androidx app', () => {
|
|
74
107
|
before(async () => {
|
|
75
|
-
;[browser, destroyBrowser] = await spec.build(
|
|
108
|
+
;[browser, destroyBrowser] = await spec.build(env.androidx)
|
|
76
109
|
})
|
|
77
110
|
|
|
78
111
|
after(async () => {
|
|
@@ -0,0 +1,84 @@
|
|
|
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 screenshoter = 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 - 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': 'android_agl_app',
|
|
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(8000)
|
|
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(8000)
|
|
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
|
+
|
|
56
|
+
const skipBtn = await browser.$('//android.widget.Button[@text="SKIP"]')
|
|
57
|
+
await skipBtn.click()
|
|
58
|
+
await utils.general.sleep(5000)
|
|
59
|
+
const finishBtn = await browser.$('//android.widget.Button[@text="FINISH"]')
|
|
60
|
+
await finishBtn.click()
|
|
61
|
+
await utils.general.sleep(15000)
|
|
62
|
+
|
|
63
|
+
// const billingBtn = await browser.$('//android.widget.FrameLayout[@content-desc="Billing"]')
|
|
64
|
+
// await billingBtn.click()
|
|
65
|
+
// await utils.general.sleep(25000)
|
|
66
|
+
|
|
67
|
+
const screenshot = await screenshoter({
|
|
68
|
+
logger,
|
|
69
|
+
driver,
|
|
70
|
+
fully: true,
|
|
71
|
+
framed: true,
|
|
72
|
+
stabilization: {crop: {top: 53, bottom: 16, left: 0, right: 0}},
|
|
73
|
+
debug: {path: './'},
|
|
74
|
+
})
|
|
75
|
+
try {
|
|
76
|
+
const actual = await screenshot.image.toObject()
|
|
77
|
+
const expected = await makeImage(expectedPath).toObject()
|
|
78
|
+
assert.strictEqual(pixelmatch(actual.data, expected.data, null, expected.width, expected.height), 0)
|
|
79
|
+
} catch (err) {
|
|
80
|
+
await screenshot.image.debug({path: './logs', name: 'viewport_failed', suffix: Date.now()})
|
|
81
|
+
throw err
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
})
|
package/test/e2e/ios.spec.js
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
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
6
|
const screenshoter = require('../../index')
|
|
7
7
|
|
|
8
|
+
const env = {
|
|
9
|
+
url: 'https://ondemand.saucelabs.com/wd/hub',
|
|
10
|
+
capabilities: {
|
|
11
|
+
name: 'iOS Screenshoter Test',
|
|
12
|
+
deviceName: 'iPhone 11 Pro Simulator',
|
|
13
|
+
platformName: 'iOS',
|
|
14
|
+
platformVersion: '13.4',
|
|
15
|
+
appiumVersion: '1.19.2',
|
|
16
|
+
automationName: 'XCUITest',
|
|
17
|
+
app: 'https://applitools.jfrog.io/artifactory/Examples/IOSTestApp/1.5/app/IOSTestApp-1.5.zip',
|
|
18
|
+
username: process.env.SAUCE_USERNAME,
|
|
19
|
+
accessKey: process.env.SAUCE_ACCESS_KEY,
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
|
|
8
23
|
describe('screenshoter ios', () => {
|
|
9
24
|
const logger = {log: () => {}, warn: () => {}, error: () => {}, verbose: () => {}}
|
|
10
25
|
let driver, browser, destroyBrowser
|
|
@@ -25,7 +40,7 @@ describe('screenshoter ios', () => {
|
|
|
25
40
|
}
|
|
26
41
|
|
|
27
42
|
before(async () => {
|
|
28
|
-
;[browser, destroyBrowser] = await spec.build(
|
|
43
|
+
;[browser, destroyBrowser] = await spec.build(env)
|
|
29
44
|
})
|
|
30
45
|
|
|
31
46
|
after(async () => {
|
package/test/e2e/web-ios.spec.js
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
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 screenshoter = require('../../index')
|
|
6
6
|
const makeImage = require('../../src/image')
|
|
7
7
|
|
|
8
|
+
const env = {
|
|
9
|
+
url: 'https://ondemand.saucelabs.com/wd/hub',
|
|
10
|
+
capabilities: {
|
|
11
|
+
name: 'iOS Web Screenshoter Test',
|
|
12
|
+
deviceName: 'iPhone 11 Pro Simulator',
|
|
13
|
+
browserName: 'safari',
|
|
14
|
+
platformName: 'iOS',
|
|
15
|
+
platformVersion: '14.5',
|
|
16
|
+
appiumVersion: '1.20.1',
|
|
17
|
+
automationName: 'XCUITest',
|
|
18
|
+
username: process.env.SAUCE_USERNAME,
|
|
19
|
+
accessKey: process.env.SAUCE_ACCESS_KEY,
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
|
|
8
23
|
// TODO add tests for page without viewport meta tag
|
|
9
24
|
|
|
10
25
|
describe('screenshoter web ios', () => {
|
|
@@ -12,7 +27,7 @@ describe('screenshoter web ios', () => {
|
|
|
12
27
|
let driver, browser, destroyBrowser
|
|
13
28
|
|
|
14
29
|
before(async () => {
|
|
15
|
-
;[browser, destroyBrowser] = await spec.build(
|
|
30
|
+
;[browser, destroyBrowser] = await spec.build(env)
|
|
16
31
|
})
|
|
17
32
|
|
|
18
33
|
after(async () => {
|
package/test/e2e/web.spec.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
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 screenshoter = require('../../index')
|
|
6
6
|
const makeImage = require('../../src/image')
|
|
7
7
|
|
|
8
|
+
const env = {
|
|
9
|
+
url: 'http://localhost:4444/wd/hub',
|
|
10
|
+
capabilities: {
|
|
11
|
+
browserName: 'chrome',
|
|
12
|
+
},
|
|
13
|
+
}
|
|
14
|
+
|
|
8
15
|
// TODO add overflowed regions tests
|
|
9
16
|
|
|
10
17
|
describe('screenshoter web', () => {
|
|
@@ -12,7 +19,7 @@ describe('screenshoter web', () => {
|
|
|
12
19
|
let driver, browser, destroyBrowser
|
|
13
20
|
|
|
14
21
|
before(async () => {
|
|
15
|
-
;[browser, destroyBrowser] = await spec.build(
|
|
22
|
+
;[browser, destroyBrowser] = await spec.build(env)
|
|
16
23
|
})
|
|
17
24
|
|
|
18
25
|
after(async () => {
|
|
@@ -37,10 +44,10 @@ describe('screenshoter web', () => {
|
|
|
37
44
|
})
|
|
38
45
|
|
|
39
46
|
it('take frame screenshot with "scroll" scrolling', () => {
|
|
40
|
-
frame({scrollingMode: 'scroll'})
|
|
47
|
+
return frame({scrollingMode: 'scroll'})
|
|
41
48
|
})
|
|
42
49
|
it('take frame screenshot with "css" scrolling', () => {
|
|
43
|
-
frame({scrollingMode: 'css'})
|
|
50
|
+
return frame({scrollingMode: 'css'})
|
|
44
51
|
})
|
|
45
52
|
|
|
46
53
|
it('take full frame screenshot with "scroll" scrolling', () => {
|
|
@@ -51,10 +58,10 @@ describe('screenshoter web', () => {
|
|
|
51
58
|
})
|
|
52
59
|
|
|
53
60
|
it('take region screenshot with "scroll" scrolling', () => {
|
|
54
|
-
region({scrollingMode: 'scroll'})
|
|
61
|
+
return region({scrollingMode: 'scroll'})
|
|
55
62
|
})
|
|
56
63
|
it('take region screenshot with "css" scrolling', () => {
|
|
57
|
-
region({scrollingMode: 'css'})
|
|
64
|
+
return region({scrollingMode: 'css'})
|
|
58
65
|
})
|
|
59
66
|
|
|
60
67
|
it('take full region screenshot with "scroll" scrolling', () => {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docker-compose.yaml
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "3.4",
|
|
3
|
-
"services": {
|
|
4
|
-
"chrome": {
|
|
5
|
-
"image": "selenium/standalone-chrome",
|
|
6
|
-
"environment": [
|
|
7
|
-
"SE_NODE_OVERRIDE_MAX_SESSIONS=true",
|
|
8
|
-
"SE_NODE_MAX_SESSIONS=15"
|
|
9
|
-
],
|
|
10
|
-
"volumes": [
|
|
11
|
-
"/dev/shm:/dev/shm"
|
|
12
|
-
],
|
|
13
|
-
"network_mode": "host"
|
|
14
|
-
},
|
|
15
|
-
"firefox": {
|
|
16
|
-
"image": "selenium/standalone-firefox",
|
|
17
|
-
"environment": [
|
|
18
|
-
"SE_NODE_OVERRIDE_MAX_SESSIONS=true",
|
|
19
|
-
"SE_NODE_MAX_SESSIONS=15"
|
|
20
|
-
],
|
|
21
|
-
"volumes": [
|
|
22
|
-
"/dev/shm:/dev/shm"
|
|
23
|
-
],
|
|
24
|
-
"ports": [
|
|
25
|
-
"4445:4444"
|
|
26
|
-
]
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
package/test/util/spec-driver.js
DELETED
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
const webdriverio = require('webdriverio')
|
|
2
|
-
const utils = require('@applitools/utils')
|
|
3
|
-
|
|
4
|
-
// #region HELPERS
|
|
5
|
-
|
|
6
|
-
const LEGACY_ELEMENT_ID = 'ELEMENT'
|
|
7
|
-
const ELEMENT_ID = 'element-6066-11e4-a52e-4f735466cecf'
|
|
8
|
-
|
|
9
|
-
function extractElementId(element) {
|
|
10
|
-
return element.elementId || element[ELEMENT_ID] || element[LEGACY_ELEMENT_ID]
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
// #endregion
|
|
14
|
-
|
|
15
|
-
// #region UTILITY
|
|
16
|
-
|
|
17
|
-
function isDriver(browser) {
|
|
18
|
-
if (!browser) return false
|
|
19
|
-
return browser.constructor.name === 'Browser'
|
|
20
|
-
}
|
|
21
|
-
function isElement(element) {
|
|
22
|
-
if (!element) return false
|
|
23
|
-
return Boolean(element.elementId || element[ELEMENT_ID] || element[LEGACY_ELEMENT_ID])
|
|
24
|
-
}
|
|
25
|
-
function isSelector(selector) {
|
|
26
|
-
return utils.types.isString(selector) || utils.types.isFunction(selector)
|
|
27
|
-
}
|
|
28
|
-
function transformElement(element) {
|
|
29
|
-
const elementId = extractElementId(element)
|
|
30
|
-
return {[ELEMENT_ID]: elementId, [LEGACY_ELEMENT_ID]: elementId}
|
|
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
|
-
}
|
|
40
|
-
function extractSelector(element) {
|
|
41
|
-
return element.selector
|
|
42
|
-
}
|
|
43
|
-
async function isEqualElements(browser, element1, element2) {
|
|
44
|
-
// NOTE: wdio wraps puppeteer and generate ids by itself just incrementing a counter
|
|
45
|
-
// NOTE: appium for ios could return different ids for same element
|
|
46
|
-
if (browser.isDevTools || browser.isIOS) {
|
|
47
|
-
return browser.execute((element1, element2) => element1 === element2, element1, element2).catch(() => false)
|
|
48
|
-
}
|
|
49
|
-
if (!element1 || !element2) return false
|
|
50
|
-
const elementId1 = extractElementId(element1)
|
|
51
|
-
const elementId2 = extractElementId(element2)
|
|
52
|
-
return elementId1 === elementId2
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// #endregion
|
|
56
|
-
|
|
57
|
-
// #region COMMANDS
|
|
58
|
-
|
|
59
|
-
async function executeScript(browser, script, ...args) {
|
|
60
|
-
return browser.execute(script, ...args)
|
|
61
|
-
}
|
|
62
|
-
async function mainContext(browser) {
|
|
63
|
-
await browser.switchToFrame(null)
|
|
64
|
-
return browser
|
|
65
|
-
}
|
|
66
|
-
async function parentContext(browser) {
|
|
67
|
-
await browser.switchToParentFrame()
|
|
68
|
-
return browser
|
|
69
|
-
}
|
|
70
|
-
async function childContext(browser, element) {
|
|
71
|
-
await browser.switchToFrame(element)
|
|
72
|
-
return browser
|
|
73
|
-
}
|
|
74
|
-
async function findElement(browser, selector) {
|
|
75
|
-
const element = await browser.$(selector)
|
|
76
|
-
return !element.error ? element : null
|
|
77
|
-
}
|
|
78
|
-
async function findElements(browser, selector) {
|
|
79
|
-
const elements = await browser.$$(selector)
|
|
80
|
-
return Array.from(elements)
|
|
81
|
-
}
|
|
82
|
-
async function getElementRegion(browser, element) {
|
|
83
|
-
const extendedElement = await browser.$(element)
|
|
84
|
-
if (utils.types.isFunction(extendedElement, 'getRect')) {
|
|
85
|
-
return extendedElement.getRect()
|
|
86
|
-
} else {
|
|
87
|
-
const size = await extendedElement.getSize()
|
|
88
|
-
const location = utils.types.has(size, ['x', 'y']) ? size : await extendedElement.getLocation()
|
|
89
|
-
return {x: location.x, y: location.y, width: size.width, height: size.height}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
async function getElementAttribute(browser, element, name) {
|
|
93
|
-
return browser.getElementAttribute(extractElementId(element), name)
|
|
94
|
-
}
|
|
95
|
-
async function getWindowSize(browser) {
|
|
96
|
-
if (utils.types.isFunction(browser.getWindowRect)) {
|
|
97
|
-
return browser.getWindowRect()
|
|
98
|
-
} else if (utils.types.isFunction(browser.getWindowSize)) {
|
|
99
|
-
return await browser.getWindowSize()
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
async function setWindowSize(browser, {width, height} = {}) {
|
|
103
|
-
if (utils.types.isFunction(browser.setWindowRect)) {
|
|
104
|
-
await browser.setWindowRect(0, 0, width, height)
|
|
105
|
-
} else {
|
|
106
|
-
await browser.setWindowPosition(0, 0)
|
|
107
|
-
await browser.setWindowSize(width, height)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
async function getOrientation(browser) {
|
|
111
|
-
const orientation = await browser.getOrientation()
|
|
112
|
-
return orientation.toLowerCase()
|
|
113
|
-
}
|
|
114
|
-
async function getDriverInfo(browser) {
|
|
115
|
-
const driverInfo = {
|
|
116
|
-
sessionId: browser.sessionId,
|
|
117
|
-
isMobile: browser.isMobile,
|
|
118
|
-
isNative: browser.isMobile && !browser.capabilities.browserName,
|
|
119
|
-
deviceName: browser.capabilities.desired
|
|
120
|
-
? browser.capabilities.desired.deviceName
|
|
121
|
-
: browser.capabilities.deviceName,
|
|
122
|
-
platformName: browser.capabilities.platformName || browser.capabilities.platform,
|
|
123
|
-
platformVersion: browser.capabilities.platformVersion,
|
|
124
|
-
browserName: browser.capabilities.browserName,
|
|
125
|
-
browserVersion: browser.capabilities.browserVersion,
|
|
126
|
-
pixelRatio: browser.capabilities.pixelRatio,
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (driverInfo.isNative) {
|
|
130
|
-
const capabilities = utils.types.has(browser.capabilities, ['pixelRatio', 'viewportRect', 'statBarHeight'])
|
|
131
|
-
? browser.capabilities
|
|
132
|
-
: await browser.getSession()
|
|
133
|
-
|
|
134
|
-
driverInfo.pixelRatio = capabilities.pixelRatio
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
const {statusBar, navigationBar} = await browser.getSystemBars()
|
|
138
|
-
driverInfo.statusBarHeight = statusBar.visible ? statusBar.height : 0
|
|
139
|
-
driverInfo.navigationBarHeight = navigationBar.visible ? navigationBar.height : 0
|
|
140
|
-
} catch (err) {
|
|
141
|
-
driverInfo.statusBarHeight = capabilities.statBarHeight || (capabilities.viewportRect || {}).top || 0
|
|
142
|
-
driverInfo.navigationBarHeight = 0
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return driverInfo
|
|
147
|
-
}
|
|
148
|
-
async function takeScreenshot(driver) {
|
|
149
|
-
return driver.takeScreenshot()
|
|
150
|
-
}
|
|
151
|
-
async function visit(browser, url) {
|
|
152
|
-
return browser.url(url)
|
|
153
|
-
}
|
|
154
|
-
async function click(browser, element) {
|
|
155
|
-
if (isSelector(element)) element = await findElement(browser, element)
|
|
156
|
-
const extendedElement = await browser.$(element)
|
|
157
|
-
await extendedElement.click()
|
|
158
|
-
}
|
|
159
|
-
async function performAction(browser, actions) {
|
|
160
|
-
return browser.touchAction(actions)
|
|
161
|
-
}
|
|
162
|
-
async function getElementText(browser, element) {
|
|
163
|
-
return browser.getElementText(extractElementId(element))
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// #endregion
|
|
167
|
-
|
|
168
|
-
async function build({type = 'web'} = {}) {
|
|
169
|
-
const capabilities = {
|
|
170
|
-
web: {
|
|
171
|
-
protocol: 'http',
|
|
172
|
-
hostname: 'localhost',
|
|
173
|
-
path: '/wd/hub',
|
|
174
|
-
port: 4444,
|
|
175
|
-
logLevel: 'silent',
|
|
176
|
-
capabilities: {
|
|
177
|
-
browserName: 'chrome',
|
|
178
|
-
},
|
|
179
|
-
},
|
|
180
|
-
android: {
|
|
181
|
-
protocol: 'https',
|
|
182
|
-
hostname: 'ondemand.saucelabs.com',
|
|
183
|
-
path: '/wd/hub',
|
|
184
|
-
port: 443,
|
|
185
|
-
logLevel: 'silent',
|
|
186
|
-
capabilities: {
|
|
187
|
-
name: 'Android Screenshoter Test',
|
|
188
|
-
browserName: '',
|
|
189
|
-
platformName: 'Android',
|
|
190
|
-
platformVersion: '7.0',
|
|
191
|
-
appiumVersion: '1.20.2',
|
|
192
|
-
deviceName: 'Samsung Galaxy S8 FHD GoogleAPI Emulator',
|
|
193
|
-
automationName: 'uiautomator2',
|
|
194
|
-
app: 'https://applitools.jfrog.io/artifactory/Examples/android/1.3/app-debug.apk',
|
|
195
|
-
username: process.env.SAUCE_USERNAME,
|
|
196
|
-
accessKey: process.env.SAUCE_ACCESS_KEY,
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
androidx: {
|
|
200
|
-
protocol: 'https',
|
|
201
|
-
hostname: 'ondemand.saucelabs.com',
|
|
202
|
-
path: '/wd/hub',
|
|
203
|
-
port: 443,
|
|
204
|
-
logLevel: 'silent',
|
|
205
|
-
capabilities: {
|
|
206
|
-
name: 'AndroidX Screenshoter Test',
|
|
207
|
-
browserName: '',
|
|
208
|
-
platformName: 'Android',
|
|
209
|
-
platformVersion: '10.0',
|
|
210
|
-
appiumVersion: '1.20.2',
|
|
211
|
-
deviceName: 'Google Pixel 3a XL GoogleAPI Emulator',
|
|
212
|
-
automationName: 'uiautomator2',
|
|
213
|
-
app: 'https://applitools.jfrog.io/artifactory/Examples/androidx/1.2.0/app_androidx.apk',
|
|
214
|
-
username: process.env.SAUCE_USERNAME,
|
|
215
|
-
accessKey: process.env.SAUCE_ACCESS_KEY,
|
|
216
|
-
},
|
|
217
|
-
},
|
|
218
|
-
ios: {
|
|
219
|
-
protocol: 'https',
|
|
220
|
-
hostname: 'ondemand.saucelabs.com',
|
|
221
|
-
path: '/wd/hub',
|
|
222
|
-
port: 443,
|
|
223
|
-
logLevel: 'silent',
|
|
224
|
-
capabilities: {
|
|
225
|
-
name: 'iOS Screenshoter Test',
|
|
226
|
-
deviceName: 'iPhone 11 Pro Simulator',
|
|
227
|
-
platformName: 'iOS',
|
|
228
|
-
platformVersion: '13.4',
|
|
229
|
-
appiumVersion: '1.19.2',
|
|
230
|
-
automationName: 'XCUITest',
|
|
231
|
-
app: 'https://applitools.jfrog.io/artifactory/Examples/IOSTestApp/1.5/app/IOSTestApp-1.5.zip',
|
|
232
|
-
username: process.env.SAUCE_USERNAME,
|
|
233
|
-
accessKey: process.env.SAUCE_ACCESS_KEY,
|
|
234
|
-
},
|
|
235
|
-
},
|
|
236
|
-
'web-ios': {
|
|
237
|
-
protocol: 'https',
|
|
238
|
-
hostname: 'ondemand.saucelabs.com',
|
|
239
|
-
path: '/wd/hub',
|
|
240
|
-
port: 443,
|
|
241
|
-
logLevel: 'silent',
|
|
242
|
-
capabilities: {
|
|
243
|
-
name: 'iOS Web Screenshoter Test',
|
|
244
|
-
deviceName: 'iPhone 11 Pro Simulator',
|
|
245
|
-
browserName: 'safari',
|
|
246
|
-
platformName: 'iOS',
|
|
247
|
-
platformVersion: '14.5',
|
|
248
|
-
appiumVersion: '1.20.1',
|
|
249
|
-
automationName: 'XCUITest',
|
|
250
|
-
username: process.env.SAUCE_USERNAME,
|
|
251
|
-
accessKey: process.env.SAUCE_ACCESS_KEY,
|
|
252
|
-
},
|
|
253
|
-
},
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const browser = await webdriverio.remote(capabilities[type])
|
|
257
|
-
|
|
258
|
-
return [browser, () => browser.deleteSession()]
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
module.exports = {
|
|
262
|
-
isDriver,
|
|
263
|
-
isElement,
|
|
264
|
-
isSelector,
|
|
265
|
-
transformElement,
|
|
266
|
-
transformSelector,
|
|
267
|
-
extractSelector,
|
|
268
|
-
isEqualElements,
|
|
269
|
-
executeScript,
|
|
270
|
-
mainContext,
|
|
271
|
-
parentContext,
|
|
272
|
-
childContext,
|
|
273
|
-
findElement,
|
|
274
|
-
findElements,
|
|
275
|
-
getElementRegion,
|
|
276
|
-
getElementAttribute,
|
|
277
|
-
getWindowSize,
|
|
278
|
-
setWindowSize,
|
|
279
|
-
getOrientation,
|
|
280
|
-
getDriverInfo,
|
|
281
|
-
takeScreenshot,
|
|
282
|
-
visit,
|
|
283
|
-
click,
|
|
284
|
-
performAction,
|
|
285
|
-
getElementText,
|
|
286
|
-
|
|
287
|
-
build,
|
|
288
|
-
}
|