@percy/webdriver-utils
Advanced tools
Comparing version 1.28.8-beta.1 to 1.28.8-beta.2
import ProviderResolver from './providers/providerResolver.js'; | ||
import utils from '@percy/sdk-utils'; | ||
import PlaywrightProvider from './providers/playwrightProvider.js'; | ||
export default class WebdriverUtils { | ||
static async automateScreenshot({ | ||
static async captureScreenshot({ | ||
sessionId, | ||
commandExecutorUrl, | ||
capabilities, | ||
sessionCapabilites, | ||
sessionCapabilities, | ||
frameGuid, | ||
pageGuid, | ||
framework, | ||
snapshotName, | ||
@@ -15,11 +19,17 @@ clientInfo, | ||
}) { | ||
const log = utils.logger('webdriver-utils:automateScreenshot'); | ||
const log = utils.logger('webdriver-utils:captureScreenshot'); | ||
try { | ||
const startTime = Date.now(); | ||
log.info(`[${snapshotName}] : Starting automate screenshot ...`); | ||
const automate = ProviderResolver.resolve(sessionId, commandExecutorUrl, capabilities, sessionCapabilites, clientInfo, environmentInfo, options, buildInfo); | ||
log.debug(`[${snapshotName}] : Resolved provider ...`); | ||
await automate.createDriver(); | ||
log.info(`[${snapshotName}] : Starting automate screenshot capture ...`); | ||
let provider; | ||
switch (framework ? framework.toLowerCase() : null) { | ||
case 'playwright': | ||
provider = new PlaywrightProvider(sessionId, frameGuid, pageGuid, clientInfo, environmentInfo, options, buildInfo); | ||
break; | ||
default: | ||
provider = ProviderResolver.resolve(sessionId, commandExecutorUrl, capabilities, sessionCapabilities, clientInfo, environmentInfo, options, buildInfo); | ||
} | ||
await provider.createDriver(); | ||
log.debug(`[${snapshotName}] : Created driver ...`); | ||
const comparisonData = await automate.screenshot(snapshotName, options); | ||
const comparisonData = await provider.screenshot(snapshotName, options); | ||
comparisonData.metadata.cliScreenshotStartTime = startTime; | ||
@@ -35,4 +45,5 @@ comparisonData.metadata.cliScreenshotEndTime = Date.now(); | ||
log.error(`[${snapshotName}] : Error Log - ${e.toString()}`); | ||
throw e; // Re-throw the error to maintain consistency in error handling | ||
} | ||
} | ||
} |
@@ -5,14 +5,17 @@ import utils from '@percy/sdk-utils'; | ||
import Tile from '../util/tile.js'; | ||
import NormalizeData from '../metadata/normalizeData.js'; | ||
import TimeIt from '../util/timing.js'; | ||
import MetaDataResolver from '../metadata/metaDataResolver.js'; | ||
import Driver from '../driver.js'; | ||
const log = utils.logger('webdriver-utils:automateProvider'); | ||
export default class AutomateProvider extends GenericProvider { | ||
constructor(sessionId, commandExecutorUrl, capabilities, sessionCapabilites, clientInfo, environmentInfo, options, buildInfo) { | ||
super(sessionId, commandExecutorUrl, capabilities, sessionCapabilites, clientInfo, environmentInfo, options, buildInfo); | ||
this._markedPercy = false; | ||
this.automateResults = null; | ||
} | ||
static supports(commandExecutorUrl) { | ||
return commandExecutorUrl.includes(process.env.AA_DOMAIN || 'browserstack'); | ||
} | ||
async createDriver() { | ||
this.driver = new Driver(this.sessionId, this.commandExecutorUrl, this.capabilities); | ||
log.debug(`Passed capabilities -> ${JSON.stringify(this.capabilities)}`); | ||
const caps = await this.driver.getCapabilites(); | ||
log.debug(`Fetched capabilities -> ${JSON.stringify(caps)}`); | ||
this.metaData = MetaDataResolver.resolve(this.driver, caps, this.capabilities); | ||
} | ||
async screenshot(name, { | ||
@@ -55,58 +58,8 @@ ignoreRegionXpaths = [], | ||
} | ||
async percyScreenshotBegin(name) { | ||
return await TimeIt.run('percyScreenshotBegin', async () => { | ||
try { | ||
let result = await this.browserstackExecutor('percyScreenshot', { | ||
name, | ||
percyBuildId: this.buildInfo.id, | ||
percyBuildUrl: this.buildInfo.url, | ||
state: 'begin' | ||
}); | ||
// Selenium Hub, set status error Code to 13 if an error is thrown | ||
// Handling error with Selenium dialect is != W3C | ||
if ((result === null || result === void 0 ? void 0 : result.status) === 13) throw new Error((result === null || result === void 0 ? void 0 : result.value) || 'Got invalid error response'); | ||
this._markedPercy = result.success; | ||
return result; | ||
} catch (e) { | ||
var _e$response, _JSON$parse, _e$response2; | ||
log.debug(`[${name}] : Could not mark Automate session as percy`); | ||
log.error(`[${name}] : error: ${e.toString()}`); | ||
/** | ||
* - Handling Error when dialect is W3C | ||
* ERROR response format from SeleniumHUB `{ | ||
* sessionId: ..., | ||
* status: 13, | ||
* value: { error: '', message: ''} | ||
* } | ||
*/ | ||
const errResponse = (e === null || e === void 0 ? void 0 : (_e$response = e.response) === null || _e$response === void 0 ? void 0 : _e$response.body) && ((_JSON$parse = JSON.parse(e === null || e === void 0 ? void 0 : (_e$response2 = e.response) === null || _e$response2 === void 0 ? void 0 : _e$response2.body)) === null || _JSON$parse === void 0 ? void 0 : _JSON$parse.value) || {}; | ||
const errMessage = (errResponse === null || errResponse === void 0 ? void 0 : errResponse.message) || (errResponse === null || errResponse === void 0 ? void 0 : errResponse.error) || (e === null || e === void 0 ? void 0 : e.message) || (e === null || e === void 0 ? void 0 : e.error) || (e === null || e === void 0 ? void 0 : e.value) || e.toString(); | ||
throw new Error(errMessage); | ||
} | ||
}); | ||
} | ||
async percyScreenshotEnd(name, error) { | ||
return await TimeIt.run('percyScreenshotEnd', async () => { | ||
try { | ||
var _this$buildInfo, _this$options; | ||
await this.browserstackExecutor('percyScreenshot', { | ||
name, | ||
percyScreenshotUrl: (_this$buildInfo = this.buildInfo) === null || _this$buildInfo === void 0 ? void 0 : _this$buildInfo.url, | ||
status: error ? 'failure' : 'success', | ||
statusMessage: error ? `${error}` : '', | ||
state: 'end', | ||
sync: (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.sync | ||
}); | ||
} catch (e) { | ||
log.debug(`[${name}] : Could not execute percyScreenshot command for Automate`); | ||
log.error(e); | ||
} | ||
}); | ||
} | ||
async getTiles(fullscreen) { | ||
var _this$options2; | ||
var _this$options; | ||
if (!this.driver) throw new Error('Driver is null, please initialize driver with createDriver().'); | ||
log.debug('Starting actual screenshotting phase'); | ||
const dpr = await this.metaData.devicePixelRatio(); | ||
const screenshotType = (_this$options2 = this.options) !== null && _this$options2 !== void 0 && _this$options2.fullPage ? 'fullpage' : 'singlepage'; | ||
const screenshotType = (_this$options = this.options) !== null && _this$options !== void 0 && _this$options.fullPage ? 'fullpage' : 'singlepage'; | ||
const response = await TimeIt.run('percyScreenshot:screenshot', async () => { | ||
@@ -148,16 +101,2 @@ return await this.browserstackExecutor('percyScreenshot', { | ||
} | ||
async browserstackExecutor(action, args) { | ||
if (!this.driver) throw new Error('Driver is null, please initialize driver with createDriver().'); | ||
let options = args ? { | ||
action, | ||
arguments: args | ||
} : { | ||
action | ||
}; | ||
let res = await this.driver.executeScript({ | ||
script: `browserstack_executor: ${JSON.stringify(options)}`, | ||
args: [] | ||
}); | ||
return res; | ||
} | ||
async setDebugUrl() { | ||
@@ -170,15 +109,4 @@ if (!this.driver) throw new Error('Driver is null, please initialize driver with createDriver().'); | ||
async getTag() { | ||
var _automateCaps$os_vers, _ref; | ||
var _this$metaData$orient; | ||
if (!this.driver) throw new Error('Driver is null, please initialize driver with createDriver().'); | ||
if (!this.automateResults) throw new Error('Comparison tag details not available'); | ||
const automateCaps = this.automateResults.capabilities; | ||
const normalizeTags = new NormalizeData(); | ||
let deviceName = this.automateResults.deviceName; | ||
const osName = normalizeTags.osRollUp(automateCaps.os); | ||
const osVersion = (_automateCaps$os_vers = automateCaps.os_version) === null || _automateCaps$os_vers === void 0 ? void 0 : _automateCaps$os_vers.split('.')[0]; | ||
const browserName = normalizeTags.browserRollUp(automateCaps.browserName, this.metaData.device()); | ||
const browserVersion = normalizeTags.browserVersionOrDeviceNameRollup(automateCaps.browserVersion, deviceName, this.metaData.device()); | ||
if (!this.metaData.device()) { | ||
deviceName = `${osName}_${osVersion}_${browserName}_${browserVersion}`; | ||
} | ||
let { | ||
@@ -189,15 +117,13 @@ width, | ||
const resolution = await this.metaData.screenResolution(); | ||
const orientation = (_ref = this.metaData.orientation() || automateCaps.deviceOrientation) === null || _ref === void 0 ? void 0 : _ref.toLowerCase(); | ||
return { | ||
name: deviceName, | ||
osName, | ||
osVersion, | ||
const orientation = (_this$metaData$orient = this.metaData.orientation()) === null || _this$metaData$orient === void 0 ? void 0 : _this$metaData$orient.toLowerCase(); | ||
const device = this.metaData.device(); | ||
const tagData = { | ||
width, | ||
height, | ||
resolution, | ||
orientation, | ||
browserName, | ||
browserVersion, | ||
resolution | ||
device | ||
}; | ||
return await super.getTag(tagData); | ||
} | ||
} |
import utils from '@percy/sdk-utils'; | ||
import TimeIt from '../util/timing.js'; | ||
import Tile from '../util/tile.js'; | ||
import Driver from '../../src/driver.js'; | ||
import MetaDataResolver from '../metadata/metaDataResolver.js'; | ||
import Tile from '../util/tile.js'; | ||
import Driver from '../driver.js'; | ||
import NormalizeData from '../metadata/normalizeData.js'; | ||
const log = utils.logger('webdriver-utils:genericProvider'); | ||
export default class GenericProvider { | ||
clientInfo = new Set(); | ||
environmentInfo = new Set(); | ||
options = {}; | ||
constructor(sessionId, commandExecutorUrl, capabilities, sessionCapabilites, clientInfo, environmentInfo, options, buildInfo) { | ||
this.sessionId = sessionId; | ||
this.commandExecutorUrl = commandExecutorUrl; | ||
this.capabilities = capabilities; | ||
this.sessionCapabilites = sessionCapabilites; | ||
this.addClientInfo(clientInfo); | ||
this.addEnvironmentInfo(environmentInfo); | ||
this.options = options; | ||
this.buildInfo = buildInfo; | ||
this.driver = null; | ||
clientInfoDetails = new Set(); | ||
environmentInfoDetails = new Set(); | ||
constructor(args) { | ||
Object.assign(this, args); | ||
this.addClientInfo(this.clientInfo); | ||
this.addEnvironmentInfo(this.environmentInfo); | ||
this._markedPercy = false; | ||
this.metaData = null; | ||
this.debugUrl = null; | ||
this.driver = null; | ||
this.header = 0; | ||
@@ -39,3 +36,3 @@ this.footer = 0; | ||
log.debug(`Fetched capabilities -> ${JSON.stringify(caps)}`); | ||
this.metaData = await MetaDataResolver.resolve(this.driver, caps, this.capabilities); | ||
this.metaData = MetaDataResolver.resolve(this.driver, caps, this.capabilities); | ||
} | ||
@@ -47,3 +44,3 @@ static supports(_commandExecutorUrl) { | ||
for (let i of [].concat(info)) { | ||
if (i) this.clientInfo.add(i); | ||
if (i) this.clientInfoDetails.add(i); | ||
} | ||
@@ -53,3 +50,3 @@ } | ||
for (let i of [].concat(info)) { | ||
if (i) this.environmentInfo.add(i); | ||
if (i) this.environmentInfoDetails.add(i); | ||
} | ||
@@ -80,2 +77,68 @@ } | ||
} | ||
async browserstackExecutor(action, args) { | ||
if (!this.driver) throw new Error('Driver is null, please initialize driver with createDriver().'); | ||
let options = args ? { | ||
action, | ||
arguments: args | ||
} : { | ||
action | ||
}; | ||
let res = await this.driver.executeScript({ | ||
script: `browserstack_executor: ${JSON.stringify(options)}`, | ||
args: [] | ||
}); | ||
return res; | ||
} | ||
async percyScreenshotBegin(name) { | ||
return await TimeIt.run('percyScreenshotBegin', async () => { | ||
try { | ||
let result = await this.browserstackExecutor('percyScreenshot', { | ||
name, | ||
percyBuildId: this.buildInfo.id, | ||
percyBuildUrl: this.buildInfo.url, | ||
state: 'begin' | ||
}); | ||
// Selenium Hub, set status error Code to 13 if an error is thrown | ||
// Handling error with Selenium dialect is != W3C | ||
if ((result === null || result === void 0 ? void 0 : result.status) === 13) { | ||
throw new Error((result === null || result === void 0 ? void 0 : result.value) || 'Got invalid error response'); | ||
} | ||
this._markedPercy = result.success; | ||
return result; | ||
} catch (e) { | ||
var _e$response, _JSON$parse, _e$response2; | ||
log.debug(`[${name}] : Could not mark Automate session as percy`); | ||
log.error(`[${name}] : error: ${e.toString()}`); | ||
/** | ||
* - Handling Error when dialect is W3C | ||
* ERROR response format from SeleniumHUB `{ | ||
* sessionId: ..., | ||
* status: 13, | ||
* value: { error: '', message: ''} | ||
* } | ||
*/ | ||
const errResponse = (e === null || e === void 0 ? void 0 : (_e$response = e.response) === null || _e$response === void 0 ? void 0 : _e$response.body) && ((_JSON$parse = JSON.parse(e === null || e === void 0 ? void 0 : (_e$response2 = e.response) === null || _e$response2 === void 0 ? void 0 : _e$response2.body)) === null || _JSON$parse === void 0 ? void 0 : _JSON$parse.value) || {}; | ||
const errMessage = (errResponse === null || errResponse === void 0 ? void 0 : errResponse.message) || (errResponse === null || errResponse === void 0 ? void 0 : errResponse.error) || (e === null || e === void 0 ? void 0 : e.message) || (e === null || e === void 0 ? void 0 : e.error) || (e === null || e === void 0 ? void 0 : e.value) || e.toString(); | ||
throw new Error(errMessage); | ||
} | ||
}); | ||
} | ||
async percyScreenshotEnd(name, error) { | ||
return await TimeIt.run('percyScreenshotEnd', async () => { | ||
try { | ||
var _this$buildInfo, _this$options; | ||
await this.browserstackExecutor('percyScreenshot', { | ||
name, | ||
percyScreenshotUrl: (_this$buildInfo = this.buildInfo) === null || _this$buildInfo === void 0 ? void 0 : _this$buildInfo.url, | ||
status: error ? 'failure' : 'success', | ||
statusMessage: error ? `${error}` : '', | ||
state: 'end', | ||
sync: (_this$options = this.options) === null || _this$options === void 0 ? void 0 : _this$options.sync | ||
}); | ||
} catch (e) { | ||
log.debug(`[${name}] : Could not execute percyScreenshot command for Automate`); | ||
log.error(e); | ||
} | ||
}); | ||
} | ||
async screenshot(name, { | ||
@@ -117,4 +180,4 @@ ignoreRegionXpaths = [], | ||
}, | ||
environmentInfo: [...this.environmentInfo].join('; '), | ||
clientInfo: [...this.clientInfo].join(' '), | ||
environmentInfo: this.getUserAgentString(this.environmentInfoDetails), | ||
clientInfo: this.getUserAgentString(this.clientInfoDetails), | ||
domInfoSha: tiles.domInfoSha, | ||
@@ -124,2 +187,11 @@ metadata: tiles.metadata || null | ||
} | ||
getUserAgentString(data) { | ||
let result = ''; | ||
if (data instanceof Set) { | ||
result = [...data].join('; '); | ||
} else if (typeof data === 'string') { | ||
result = data; | ||
} | ||
return result; | ||
} | ||
@@ -159,22 +231,2 @@ // TODO: get dom sha for non-automate | ||
} | ||
async getTag() { | ||
if (!this.driver) throw new Error('Driver is null, please initialize driver with createDriver().'); | ||
let { | ||
width, | ||
height | ||
} = await this.metaData.windowSize(); | ||
const resolution = await this.metaData.screenResolution(); | ||
const orientation = this.metaData.orientation(); | ||
return { | ||
name: this.metaData.deviceName(), | ||
osName: this.metaData.osName(), | ||
osVersion: this.metaData.osVersion(), | ||
width, | ||
height, | ||
orientation: orientation, | ||
browserName: this.metaData.browserName(), | ||
browserVersion: this.metaData.browserVersion(), | ||
resolution: resolution | ||
}; | ||
} | ||
@@ -186,3 +238,3 @@ // TODO: Add Debugging Url for non-automate | ||
async doTransformations() { | ||
var _this$options; | ||
var _this$options2; | ||
const hideScrollbarStyle = ` | ||
@@ -208,3 +260,3 @@ /* Hide scrollbar for Chrome, Safari and Opera */ | ||
}); | ||
if ((_this$options = this.options) !== null && _this$options !== void 0 && _this$options.fullPage || this.isIOS()) { | ||
if ((_this$options2 = this.options) !== null && _this$options2 !== void 0 && _this$options2.fullPage || this.isIOS()) { | ||
await this.getInitialScrollLocation(); | ||
@@ -237,7 +289,7 @@ } | ||
async getRegionObjectFromBoundingBox(selector, element) { | ||
var _this$options2; | ||
var _this$options3; | ||
const scaleFactor = await this.metaData.devicePixelRatio(); | ||
let scrollX = 0, | ||
scrollY = 0; | ||
if ((_this$options2 = this.options) !== null && _this$options2 !== void 0 && _this$options2.fullPage) { | ||
if ((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.fullPage) { | ||
scrollX = this.initialScrollLocation.value[0]; | ||
@@ -278,3 +330,3 @@ scrollY = this.initialScrollLocation.value[1]; | ||
async updatePageShiftFactor(location, scaleFactor, scrollFactors) { | ||
var _this$options3; | ||
var _this$options4; | ||
if (this.isIOS() || this.currentTag.osName === 'OS X' && parseInt(this.currentTag.browserVersion) > 13 && this.currentTag.browserName.toLowerCase() === 'safari') { | ||
@@ -286,3 +338,3 @@ this.pageYShiftFactor = this.statusBarHeight; | ||
this.pageXShiftFactor = this.isIOS() ? 0 : -(scrollFactors.value[0] * scaleFactor); | ||
if (this.isIOS() && !((_this$options3 = this.options) !== null && _this$options3 !== void 0 && _this$options3.fullPage)) { | ||
if (this.isIOS() && !((_this$options4 = this.options) !== null && _this$options4 !== void 0 && _this$options4.fullPage)) { | ||
if (scrollFactors.value[0] !== this.initialScrollLocation.value[0] || scrollFactors.value[1] !== this.initialScrollLocation.value[1]) { | ||
@@ -297,3 +349,3 @@ this.pageXShiftFactor = -1 * this.removeElementShiftFactor; | ||
async getRegionObject(selector, elementId) { | ||
var _this$options4; | ||
var _this$options5; | ||
const scaleFactor = await this.metaData.devicePixelRatio(); | ||
@@ -312,3 +364,3 @@ const rect = await this.driver.rect(elementId); | ||
const scrollFactors = await this.getScrollDetails(); | ||
if ((_this$options4 = this.options) !== null && _this$options4 !== void 0 && _this$options4.fullPage) { | ||
if ((_this$options5 = this.options) !== null && _this$options5 !== void 0 && _this$options5.fullPage) { | ||
scrollX = scrollFactors.value[0]; | ||
@@ -379,2 +431,36 @@ scrollY = scrollFactors.value[1]; | ||
} | ||
async getTag(tagData) { | ||
var _automateCaps$os_vers; | ||
if (!this.automateResults) throw new Error('Comparison tag details not available'); | ||
const automateCaps = this.automateResults.capabilities; | ||
const normalizeTags = new NormalizeData(); | ||
let deviceName = this.automateResults.deviceName; | ||
const osName = normalizeTags.osRollUp(automateCaps.os); | ||
const osVersion = (_automateCaps$os_vers = automateCaps.os_version) === null || _automateCaps$os_vers === void 0 ? void 0 : _automateCaps$os_vers.split('.')[0]; | ||
const browserName = normalizeTags.browserRollUp(automateCaps.browserName, tagData.device); | ||
const browserVersion = normalizeTags.browserVersionOrDeviceNameRollup(automateCaps.browserVersion, deviceName, tagData.device); | ||
if (!tagData.device) { | ||
deviceName = `${osName}_${osVersion}_${browserName}_${browserVersion}`; | ||
} | ||
let { | ||
width, | ||
height | ||
} = { | ||
width: tagData.width, | ||
height: tagData.height | ||
}; | ||
const resolution = tagData.resolution; | ||
const orientation = tagData.orientation || automateCaps.deviceOrientation || 'landscape'; | ||
return { | ||
name: deviceName, | ||
osName, | ||
osVersion, | ||
width, | ||
height, | ||
orientation, | ||
browserName, | ||
browserVersion, | ||
resolution | ||
}; | ||
} | ||
} |
@@ -6,5 +6,15 @@ import GenericProvider from './genericProvider.js'; | ||
// We can safely do [0] because GenericProvider is catch all | ||
const Klass = [AutomateProvider, GenericProvider].filter(x => x.supports(commandExecutorUrl))[0]; | ||
return new Klass(sessionId, commandExecutorUrl, capabilities, sessionCapabilities, clientInfo, environmentInfo, options, buildInfo); | ||
const Klass = [AutomateProvider, GenericProvider].filter(provider => provider.supports(commandExecutorUrl))[0]; | ||
const args = { | ||
sessionId, | ||
commandExecutorUrl, | ||
capabilities, | ||
sessionCapabilities, | ||
clientInfo, | ||
environmentInfo, | ||
options, | ||
buildInfo | ||
}; | ||
return new Klass(args); | ||
} | ||
} |
{ | ||
"name": "@percy/webdriver-utils", | ||
"version": "1.28.8-beta.1", | ||
"version": "1.28.8-beta.2", | ||
"license": "MIT", | ||
@@ -32,6 +32,6 @@ "repository": { | ||
"dependencies": { | ||
"@percy/config": "1.28.8-beta.1", | ||
"@percy/sdk-utils": "1.28.8-beta.1" | ||
"@percy/config": "1.28.8-beta.2", | ||
"@percy/sdk-utils": "1.28.8-beta.2" | ||
}, | ||
"gitHead": "d31a9746c7be6d74db284b8f30c3248d2bba916e" | ||
"gitHead": "6c954bcd0fa6a825ad636167f0a07251f124b710" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
48361
16
1202
+ Added@percy/config@1.28.8-beta.2(transitive)
+ Added@percy/logger@1.28.8-beta.2(transitive)
+ Added@percy/sdk-utils@1.28.8-beta.2(transitive)
- Removed@percy/config@1.28.8-beta.1(transitive)
- Removed@percy/logger@1.28.8-beta.1(transitive)
- Removed@percy/sdk-utils@1.28.8-beta.1(transitive)
Updated@percy/config@1.28.8-beta.2