-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨ Integrate selenium and appium session support #1239
Changes from 56 commits
51bf525
3055888
d625419
2e406ed
6d4c8a4
d306ef8
38707d0
86f5253
6035b7a
1923ede
db8b2fd
cca6bae
4a0c2c4
b2b6810
c8c2d12
0b78bf7
fa873b2
2014e5f
fb49fb1
2d34329
ca456af
e5efcd4
d377484
90c5721
c3a7063
0556687
46b0fa4
18dbc54
e34bb7d
0664df1
016ddd8
e5f26eb
e598b8c
df08c52
6ce4a33
cb87112
d9d1a63
035ace3
6a08f7e
9170a5b
2a9a116
433a98f
17c2c91
359a405
8b39ec9
f34b79e
c75cfc2
158b452
0016b82
9887349
30c929c
ae3f9a6
241f2d8
6eae220
4c0830d
b207f99
94289c1
e351591
5323de9
3f164a2
91492dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
nilshah98 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"name": "@percy/webdriver-utils", | ||
"version": "1.22.0", | ||
"license": "MIT", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/percy/cli", | ||
"directory": "packages/webdriver-utils" | ||
}, | ||
"engines": { | ||
"node": ">=14" | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"main": "./dist/index.js", | ||
"type": "module", | ||
"exports": { | ||
".": "./dist/index.js" | ||
}, | ||
"scripts": { | ||
"build": "node ../../scripts/build", | ||
"lint": "eslint --ignore-path ../../.gitignore .", | ||
"test": "node ../../scripts/test", | ||
"test:coverage": "yarn test --coverage" | ||
nilshah98 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}, | ||
"dependencies": { | ||
"@percy/sdk-utils": "1.22.0" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import utils from '@percy/sdk-utils'; | ||
import Cache from './util/cache.js'; | ||
const { request } = utils; | ||
|
||
export default class Driver { | ||
constructor(sessionId, executorUrl) { | ||
this.sessionId = sessionId; | ||
this.executorUrl = executorUrl.includes('@') ? `https://${executorUrl.split('@')[1]}` : executorUrl; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also can we add this check below this 😅 this.executorUrl = executorUrl.endsWith('/') ? this.executorUrl.slice(0, -1) : this.executorUrl; It turns out that |
||
} | ||
|
||
async getCapabilites() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use cache class from appium js sdk here. It becomes pretty expensive to fetch capabilities per screenshot [ ideally you only want to do it once per |
||
return await Cache.withCache(Cache.caps, this.sessionId, async() => { | ||
const baseUrl = `${this.executorUrl}/session/${this.sessionId}`; | ||
const caps = JSON.parse((await request(baseUrl)).body); | ||
return caps.value; | ||
}) | ||
} | ||
|
||
async getWindowSize() { | ||
const baseUrl = `${this.executorUrl}/session/${this.sessionId}/window/current/size`; | ||
const windowSize = JSON.parse((await request(baseUrl)).body); | ||
return windowSize; | ||
} | ||
|
||
// command => {script: "", args: []} | ||
async executeScript(command) { | ||
if ((!command.constructor === Object) || | ||
!(Object.keys(command).length === 2 && | ||
Object.keys(command).includes('script') && | ||
Object.keys(command).includes('args')) | ||
) { | ||
throw new Error('Please pass command as {script: "", args: []}'); | ||
} | ||
const options = { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json;charset=utf-8' | ||
}, | ||
body: JSON.stringify(command) | ||
}; | ||
const baseUrl = `${this.executorUrl}/session/${this.sessionId}/execute/sync`; | ||
const response = JSON.parse((await request(baseUrl, options)).body); | ||
return response; | ||
} | ||
|
||
async takeScreenshot() { | ||
const baseUrl = `${this.executorUrl}/session/${this.sessionId}/screenshot`; | ||
const screenShot = JSON.parse((await request(baseUrl)).body); | ||
return screenShot.value; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import ProviderResolver from './providers/providerResolver.js'; | ||
import utils from '@percy/sdk-utils'; | ||
|
||
const log = utils.logger('webdriver-utils:main'); | ||
|
||
export default async function automateScreenshot(options) { | ||
log.info('Starting automate screenshot'); | ||
const automate = ProviderResolver.resolve(options.sessionId, options.commandExecutorUrl, options.capabilities, options.sessionCapabilites); | ||
await automate.createDriver(); | ||
return await automate.screenshot(options.snapshotName); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
export default class DesktopMetaData { | ||
constructor(driver, opts) { | ||
this.driver = driver; | ||
this.capabilities = opts; | ||
} | ||
|
||
browserName() { | ||
return this.capabilities.browserName.toLowerCase(); | ||
} | ||
|
||
osName() { | ||
let osName = this.capabilities.osVersion; | ||
if (osName) return osName.toLowerCase(); | ||
|
||
osName = this.capabilities.platform; | ||
return osName; | ||
} | ||
|
||
// desktop will show this as browser version | ||
osVersion() { | ||
return this.capabilities.version.split('.')[0]; | ||
} | ||
|
||
deviceName() { | ||
return this.browserName() + '_' + this.osVersion() + '_' + this.osName(); | ||
} | ||
|
||
orientation() { | ||
return 'landscape'; | ||
} | ||
|
||
async windowSize() { | ||
const dpr = await this.devicePixelRatio(); | ||
const data = await this.driver.getWindowSize(); | ||
const width = parseInt(data.value.width * dpr), height = parseInt(data.value.height * dpr); | ||
return { width, height }; | ||
} | ||
|
||
async devicePixelRatio() { | ||
const devicePixelRatio = await this.driver.executeScript({ script: 'return window.devicePixelRatio;', args: [] }); | ||
return devicePixelRatio.value; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import DesktopMetaData from './desktopMetaData.js'; | ||
import MobileMetaData from './mobileMetaData.js'; | ||
|
||
export default class MetaDataResolver { | ||
static resolve(driver, capabilities, opts) { | ||
if (!driver) throw new Error('Please pass a Driver object'); | ||
|
||
const platform = opts.platformName || opts.platform; | ||
if (['ios', 'android'].includes(platform.toLowerCase())) { | ||
return new MobileMetaData(driver, capabilities); | ||
} else { | ||
return new DesktopMetaData(driver, capabilities); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
export default class MobileMetaData { | ||
constructor(driver, opts) { | ||
this.driver = driver; | ||
this.capabilities = opts; | ||
} | ||
|
||
browserName() { | ||
return this.capabilities.browserName.toLowerCase(); | ||
} | ||
|
||
osName() { | ||
let osName = this.capabilities.os.toLowerCase(); | ||
if (osName === 'mac' && this.browserName() === 'iphone') { | ||
osName = 'ios'; | ||
} | ||
return osName; | ||
} | ||
|
||
osVersion() { | ||
return this.capabilities.osVersion.split('.')[0]; | ||
} | ||
|
||
deviceName() { | ||
return this.capabilities.deviceName.split('-')[0]; | ||
} | ||
|
||
orientation() { | ||
return this.capabilities.orientation; | ||
} | ||
|
||
async windowSize() { | ||
const dpr = await this.devicePixelRatio(); | ||
const data = await this.driver.getWindowSize(); | ||
const width = parseInt(data.value.width * dpr), height = parseInt(data.value.height * dpr); | ||
return { width, height }; | ||
} | ||
|
||
async devicePixelRatio() { | ||
const devicePixelRatio = await this.driver.executeScript({ script: 'return window.devicePixelRatio;', args: [] }); | ||
return devicePixelRatio.value; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
automateScreenshot
should we keep it in camel case instead we can call it onscreenshot
as well just saying becauseurl's
in general don't have camel casing.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's rename it.