forked from webdriverio/webdriverio
-
Notifications
You must be signed in to change notification settings - Fork 0
Wdio Percy support v8 #1
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
Open
amaanbs
wants to merge
44
commits into
main
Choose a base branch
from
wdio_percy_support_v8
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
933fcae
Add support for Percy
amaanbs a007216
es-lint fixes
amaanbs c85e2b1
binary download fix
amaanbs d1cba84
Merge branch 'main' of github.com:amaanbs/webdriverio into wdio_percy…
amaanbs 02a7706
resolve merge conflicts
amaanbs f165eaf
add error handling
amaanbs 4f6d8ca
best platform for caps as objects
amaanbs ffca74b
minor fix
amaanbs f7a9ca1
minor fixes
amaanbs abd6493
added unit tests
amaanbs 3047eb2
ts-lint fixes
amaanbs b29658a
PR review fixes
amaanbs 497c10f
add package-lock.json
amaanbs f6ee31b
minor fixes
amaanbs f067682
Screenshot stabilization + default mode = auto
amaanbs dafa563
PR review fixes
amaanbs a7a9397
Merge branch 'main' of github.com:amaanbs/webdriverio into wdio_percy…
amaanbs 42b9e06
Fix test failure import
amaanbs b8e8755
update tests
amaanbs 7c7b1ab
PR review fixes
amaanbs 6819cf2
Merge branch 'main' of github.com:amaanbs/webdriverio into wdio_percy…
amaanbs 907de46
Merge branch 'main' of github.com:amaanbs/webdriverio into wdio_percy…
rev-doshi 1315406
Merge branch 'main' of github.com:amaanbs/webdriverio into wdio_percy…
rev-doshi e8d6b94
review changes
rev-doshi 4ab0126
linting fix
rev-doshi e9279bb
import fix
rev-doshi 7811083
import fix
rev-doshi 08c222d
test fixes and using # prefix for private fields
rev-doshi 52b38d9
Revert "test fixes and using # prefix for private fields"
rev-doshi a0b80e5
test fix
rev-doshi b438b1f
review comments fix
rev-doshi 425e941
percy packages changes
rev-doshi 7b07fa3
Merge pull request #3 from rev-doshi/wdio_percy_support_v8
rev-doshi 5d5d033
conflict resolution
rev-doshi 436e132
package-lock fix
rev-doshi 463e3b4
review changes
rev-doshi 7b4503c
review changes
rev-doshi 68e13ce
review changes
rev-doshi fdfcf82
Merge branch 'main' of github.com:amaanbs/webdriverio into wdio_percy…
rev-doshi 77bc0fe
minor fix
rev-doshi 250ed1d
review changes
rev-doshi 0f01b16
master merge and UT fix
rev-doshi a84203b
master merge
rev-doshi d39f702
minor fix
rev-doshi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 4 additions & 2 deletions
6
packages/wdio-browserstack-service/src/@types/bstack-service-types.d.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,13 @@ | ||
| declare namespace WebdriverIO { | ||
| interface Browser { | ||
| getAccessibilityResultsSummary: () => Promise<{ [key: string]: any; }>, | ||
| getAccessibilityResults: () => Promise<Array<{ [key: string]: any; }>> | ||
| getAccessibilityResults: () => Promise<Array<{ [key: string]: any; }>>, | ||
| percyCaptureMap: any | ||
| } | ||
|
|
||
| interface MultiRemoteBrowser { | ||
| getAccessibilityResultsSummary: () => Promise<{ [key: string]: any; }>, | ||
| getAccessibilityResults: () => Promise<Array<{ [key: string]: any; }>> | ||
| getAccessibilityResults: () => Promise<Array<{ [key: string]: any; }>>, | ||
| percyCaptureMap: any | ||
| } | ||
| } |
88 changes: 88 additions & 0 deletions
88
packages/wdio-browserstack-service/src/Percy/Percy-Handler.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| import type { Capabilities } from '@wdio/types' | ||
| import type { BeforeCommandArgs, AfterCommandArgs } from '@wdio/reporter' | ||
|
|
||
| import { | ||
| o11yClassErrorHandler | ||
| } from '../util.js' | ||
| import PercyCaptureMap from './PercyCaptureMap.js' | ||
|
|
||
| import * as PercySDK from './PercySDK.js' | ||
|
|
||
| class _PercyHandler { | ||
| private _testMetadata: { [key: string]: any } = {} | ||
| private sessionName?: string | ||
| private _isAppAutomate?: boolean | ||
| public _percyScreenshotCounter: any = 0 | ||
|
|
||
| constructor ( | ||
| private _percyAutoCaptureMode: string | undefined, | ||
| private _browser: WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser, | ||
| private _capabilities: Capabilities.RemoteCapability, | ||
| isAppAutomate?: boolean, | ||
| private _framework?: string | ||
| ) { | ||
| this._isAppAutomate = isAppAutomate | ||
| } | ||
|
|
||
| _setSessionName(name: string) { | ||
| this.sessionName = name | ||
| } | ||
|
|
||
| async teardown () { | ||
| await new Promise<void>((resolve) => { | ||
| setInterval(() => { | ||
| if (this._percyScreenshotCounter === 0) { | ||
| resolve() | ||
| } | ||
| }, 1000) | ||
| }) | ||
| } | ||
|
|
||
| async percyAutoCapture(eventName: string | null) { | ||
| if (eventName) { | ||
| this._percyScreenshotCounter += 1 | ||
amaanbs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| this._isAppAutomate ? await PercySDK.screenshotApp(this._browser, (this._browser.percyCaptureMap as PercyCaptureMap).getName((this.sessionName as string), eventName)) : await PercySDK.screenshot(this._browser, (this._browser.percyCaptureMap as PercyCaptureMap).getName((this.sessionName as string), eventName)); | ||
| (this._browser.percyCaptureMap as PercyCaptureMap).increment((this.sessionName as string), eventName) | ||
| this._percyScreenshotCounter -= 1 | ||
| } | ||
| } | ||
|
|
||
| async before () { | ||
| this._browser.percyCaptureMap = new PercyCaptureMap() | ||
| } | ||
|
|
||
| async browserCommand (args: BeforeCommandArgs & AfterCommandArgs) { | ||
| if (args.endpoint && this._percyAutoCaptureMode) { | ||
| let eventName = null | ||
| if ((args.endpoint as string).includes('click') && ['click', 'auto'].includes(this._percyAutoCaptureMode as string)) { | ||
| eventName = 'click' | ||
| } else if ((args.endpoint as string).includes('screenshot') && ['screenshot', 'auto'].includes(this._percyAutoCaptureMode as string)) { | ||
| eventName = 'screenshot' | ||
| } else if ((args.endpoint as string).includes('actions') && ['auto'].includes(this._percyAutoCaptureMode as string)) { | ||
| if (args.body && args.body.actions && Array.isArray(args.body.actions) && args.body.actions.length && args.body.actions[0].type === 'key') { | ||
| eventName = 'keys' | ||
| } | ||
| } | ||
| await this.percyAutoCapture(eventName) | ||
| } | ||
| } | ||
|
|
||
| async afterTest () { | ||
| if (this._percyAutoCaptureMode && this._percyAutoCaptureMode === 'testcase') { | ||
| await this.percyAutoCapture('testcase') | ||
| } | ||
| } | ||
|
|
||
| async afterScenario () { | ||
| if (this._percyAutoCaptureMode && this._percyAutoCaptureMode === 'testcase') { | ||
| await this.percyAutoCapture('testcase') | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // https://github.com/microsoft/TypeScript/issues/6543 | ||
| const PercyHandler: typeof _PercyHandler = o11yClassErrorHandler(_PercyHandler) | ||
| type PercyHandler = _PercyHandler | ||
|
|
||
| export default PercyHandler | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| import fs from 'node:fs' | ||
| import path from 'node:path' | ||
| import os from 'node:os' | ||
|
|
||
| import { createRequire } from 'node:module' | ||
| const require = createRequire(import.meta.url) | ||
| const { spawn } = require('node:child_process') | ||
|
|
||
| import { nodeRequest, getBrowserStackUser, getBrowserStackKey } from '../util.js' | ||
| import { PercyLogger } from './PercyLogger.js' | ||
|
|
||
| import PercyBinary from './PercyBinary.js' | ||
|
|
||
| import type { BrowserstackConfig, UserConfig } from '../types.js' | ||
| import type { Options } from '@wdio/types' | ||
|
|
||
| const logDir = 'logs' | ||
|
|
||
| class Percy { | ||
| #logfile: string = path.join(logDir, 'percy.log') | ||
| #address: string = process.env.PERCY_SERVER_ADDRESS || 'http://localhost:5338' | ||
|
|
||
| #binaryPath: string | any = null | ||
| #options: BrowserstackConfig & Options.Testrunner | ||
| #config: Options.Testrunner | ||
| #proc: any = null | ||
| #isApp: boolean = false | ||
| #projectName: string | undefined = undefined | ||
|
|
||
| isProcessRunning = false | ||
|
|
||
| constructor(options: BrowserstackConfig & Options.Testrunner, config: Options.Testrunner, bsConfig: UserConfig) { | ||
| this.#options = options | ||
| this.#config = config | ||
| if (options.app) { | ||
| this.#isApp = true | ||
| } | ||
| this.#projectName = bsConfig.projectName | ||
| } | ||
|
|
||
| async #getBinaryPath(): Promise<string> { | ||
| if (!this.#binaryPath) { | ||
| const pb = new PercyBinary() | ||
| this.#binaryPath = await pb.getBinaryPath(this.#config) | ||
| } | ||
| return this.#binaryPath | ||
| } | ||
|
|
||
| async #sleep(ms: number) { | ||
| return new Promise(resolve => setTimeout(resolve, ms)) | ||
| } | ||
|
|
||
| async healthcheck() { | ||
| try { | ||
| const resp = await nodeRequest('GET', 'percy/healthcheck', null, this.#address) | ||
| if (resp) { | ||
| return true | ||
| } | ||
| } catch (err) { | ||
| return false | ||
| } | ||
| } | ||
|
|
||
| async start() { | ||
| const binaryPath: string = await this.#getBinaryPath() | ||
| const logStream = fs.createWriteStream(this.#logfile, { flags: 'a' }) | ||
| const token = await this.fetchPercyToken() | ||
| const configPath = await this.createPercyConfig() | ||
|
|
||
| if (!token) { | ||
| return false | ||
| } | ||
|
|
||
| const commandArgs = [`${this.#isApp ? 'app:exec' : 'exec'}:start`] | ||
|
|
||
| if (configPath) { | ||
| commandArgs.push('-c', configPath as string) | ||
| } | ||
|
|
||
| this.#proc = spawn( | ||
| binaryPath, | ||
| commandArgs, | ||
| { env: Object.assign(process.env, { PERCY_TOKEN: token }) } | ||
| ) | ||
|
|
||
| this.#proc.stdout.pipe(logStream) | ||
| this.#proc.stderr.pipe(logStream) | ||
| this.isProcessRunning = true | ||
| const that = this | ||
|
|
||
| /* eslint-disable @typescript-eslint/no-unused-vars */ | ||
| this.#proc.on('close', function (code: any) { | ||
| that.isProcessRunning = false | ||
| }) | ||
|
|
||
| do { | ||
| const healthcheck = await this.healthcheck() | ||
| if (healthcheck) { | ||
| PercyLogger.debug('Percy healthcheck successful') | ||
| return true | ||
| } | ||
|
|
||
| await this.#sleep(1000) | ||
| } while (this.isProcessRunning) | ||
|
|
||
| return false | ||
| } | ||
|
|
||
| async stop() { | ||
| const binaryPath = await this.#getBinaryPath() | ||
| return new Promise( (resolve) => { | ||
| const proc = spawn(binaryPath, ['exec:stop']) | ||
| proc.on('close', (code: any) => { | ||
| this.isProcessRunning = false | ||
| resolve(code) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| isRunning() { | ||
| return this.isProcessRunning | ||
| } | ||
|
|
||
| async fetchPercyToken() { | ||
| const projectName = this.#projectName | ||
|
|
||
| try { | ||
| const type = this.#isApp ? 'app' : 'automate' | ||
| const response = await nodeRequest( | ||
| 'GET', | ||
| `api/app_percy/get_project_token?name=${projectName}&type=${type}`, | ||
| { | ||
| username: getBrowserStackUser(this.#config), | ||
| password: getBrowserStackKey(this.#config) | ||
| }, | ||
| 'https://api.browserstack.com' | ||
| ) | ||
| PercyLogger.debug('Percy fetch token success : ' + response.token) | ||
| return response.token | ||
| } catch (err) { | ||
| PercyLogger.error(`Percy unable to fetch project token: ${err}`) | ||
| return null | ||
| } | ||
| } | ||
|
|
||
| async createPercyConfig() { | ||
| if (!this.#options.percyOptions) { | ||
| return null | ||
| } | ||
|
|
||
| const configPath = path.join(os.tmpdir(), 'percy.json') | ||
| const percyOptions = this.#options.percyOptions | ||
|
|
||
| if (!percyOptions.version) { | ||
| percyOptions.version = '2' | ||
| } | ||
|
|
||
| return new Promise((resolve) => { | ||
| fs.writeFile( | ||
| configPath, | ||
| JSON.stringify( | ||
| percyOptions | ||
| ), | ||
| (err: any) => { | ||
| if (err) { | ||
| PercyLogger.error(`Error creating percy config: ${err}`) | ||
| resolve(null) | ||
| } | ||
|
|
||
| PercyLogger.debug('Percy config created at ' + configPath) | ||
| resolve(configPath) | ||
| } | ||
| ) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| export default Percy |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.