Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@percy/webdriver-utils

Package Overview
Dependencies
Maintainers
6
Versions
89
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@percy/webdriver-utils - npm Package Compare versions

Comparing version 1.27.0-beta.0 to 1.27.0-beta.1

dist/metadata/normalizeData.js

20

dist/driver.js

@@ -6,12 +6,19 @@ import utils from '@percy/sdk-utils';

} = utils;
const log = utils.logger('webdriver-utils:driver');
export default class Driver {
constructor(sessionId, executorUrl) {
constructor(sessionId, executorUrl, passedCapabilities) {
this.sessionId = sessionId;
this.executorUrl = executorUrl.includes('@') ? `https://${executorUrl.split('@')[1]}` : executorUrl;
this.passedCapabilities = passedCapabilities;
}
async getCapabilites() {
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;
try {
const baseUrl = `${this.executorUrl}/session/${this.sessionId}`;
const caps = JSON.parse((await request(baseUrl)).body);
return caps.value;
} catch (err) {
log.warn(`Falling back to legacy protocol, Error: ${err.message}`);
return this.passedCapabilities;
}
});

@@ -30,2 +37,7 @@ }

}
// browser_executor is custom BS executor script, if there is anything extra it breaks
// percy_automate_script is an anchor comment to identify percy automate scripts
if (!command.script.includes('browserstack_executor')) {
command.script = `/* percy_automate_script */ \n ${command.script}`;
}
const options = {

@@ -32,0 +44,0 @@ method: 'POST',

17

dist/index.js

@@ -33,9 +33,14 @@ import ProviderResolver from './providers/providerResolver.js';

async automateScreenshot() {
this.log.info('Starting automate screenshot ...');
const automate = ProviderResolver.resolve(this.sessionId, this.commandExecutorUrl, this.capabilities, this.sessionCapabilites, this.clientInfo, this.environmentInfo, this.options, this.buildInfo);
this.log.debug('Resolved provider ...');
await automate.createDriver();
this.log.debug('Created driver ...');
return await automate.screenshot(this.snapshotName, this.options);
try {
this.log.info(`[${this.snapshotName}] : Starting automate screenshot ...`);
const automate = ProviderResolver.resolve(this.sessionId, this.commandExecutorUrl, this.capabilities, this.sessionCapabilites, this.clientInfo, this.environmentInfo, this.options, this.buildInfo);
this.log.debug(`[${this.snapshotName}] : Resolved provider ...`);
await automate.createDriver();
this.log.debug(`[${this.snapshotName}] : Created driver ...`);
return await automate.screenshot(this.snapshotName, this.options);
} catch (e) {
this.log.error(`[${this.snapshotName}] : Error - ${e.message}`);
this.log.error(`[${this.snapshotName}] : Error Log - ${e.toString()}`);
}
}
}

@@ -0,1 +1,2 @@

import Cache from '../util/cache.js';
export default class DesktopMetaData {

@@ -6,12 +7,18 @@ constructor(driver, opts) {

}
device() {
return false;
}
browserName() {
return this.capabilities.browserName.toLowerCase();
var _this$capabilities, _this$capabilities$br;
return (_this$capabilities = this.capabilities) === null || _this$capabilities === void 0 ? void 0 : (_this$capabilities$br = _this$capabilities.browserName) === null || _this$capabilities$br === void 0 ? void 0 : _this$capabilities$br.toLowerCase();
}
browserVersion() {
return this.capabilities.browserVersion.split('.')[0];
var _this$capabilities2, _this$capabilities2$b;
return (_this$capabilities2 = this.capabilities) === null || _this$capabilities2 === void 0 ? void 0 : (_this$capabilities2$b = _this$capabilities2.browserVersion) === null || _this$capabilities2$b === void 0 ? void 0 : _this$capabilities2$b.split('.')[0];
}
osName() {
let osName = this.capabilities.os;
if (osName) return osName.toLowerCase();
osName = this.capabilities.platform;
var _this$capabilities3, _osName, _this$capabilities4;
let osName = (_this$capabilities3 = this.capabilities) === null || _this$capabilities3 === void 0 ? void 0 : _this$capabilities3.os;
if (osName) return (_osName = osName) === null || _osName === void 0 ? void 0 : _osName.toLowerCase();
osName = (_this$capabilities4 = this.capabilities) === null || _this$capabilities4 === void 0 ? void 0 : _this$capabilities4.platform;
return osName;

@@ -22,3 +29,4 @@ }

osVersion() {
return this.capabilities.osVersion.toLowerCase();
var _this$capabilities5, _this$capabilities5$o;
return (_this$capabilities5 = this.capabilities) === null || _this$capabilities5 === void 0 ? void 0 : (_this$capabilities5$o = _this$capabilities5.osVersion) === null || _this$capabilities5$o === void 0 ? void 0 : _this$capabilities5$o.toLowerCase();
}

@@ -44,16 +52,20 @@

async screenResolution() {
const data = await this.driver.executeScript({
script: 'return [(window.screen.width * window.devicePixelRatio).toString(), (window.screen.height * window.devicePixelRatio).toString()];',
args: []
return await Cache.withCache(Cache.resolution, this.driver.sessionId, async () => {
const data = await this.driver.executeScript({
script: 'return [(window.screen.width * window.devicePixelRatio).toString(), (window.screen.height * window.devicePixelRatio).toString()];',
args: []
});
const screenInfo = data.value;
return `${screenInfo[0]} x ${screenInfo[1]}`;
});
const screenInfo = data.value;
return `${screenInfo[0]} x ${screenInfo[1]}`;
}
async devicePixelRatio() {
const devicePixelRatio = await this.driver.executeScript({
script: 'return window.devicePixelRatio;',
args: []
return await Cache.withCache(Cache.dpr, this.driver.sessionId, async () => {
const devicePixelRatio = await this.driver.executeScript({
script: 'return window.devicePixelRatio;',
args: []
});
return devicePixelRatio.value;
});
return devicePixelRatio.value;
}
}

@@ -5,5 +5,6 @@ import DesktopMetaData from './desktopMetaData.js';

static resolve(driver, capabilities, opts) {
var _capabilities$platfor, _capabilities$device, _capabilities$device$;
if (!driver) throw new Error('Please pass a Driver object');
const platform = opts.platformName || opts.platform;
if (['ios', 'android'].includes(platform.toLowerCase())) {
if (['ios', 'android'].includes(platform.toLowerCase()) || ['ios', 'android'].includes(capabilities === null || capabilities === void 0 ? void 0 : (_capabilities$platfor = capabilities.platformName) === null || _capabilities$platfor === void 0 ? void 0 : _capabilities$platfor.toLowerCase()) || ['ipad', 'iphone'].includes(capabilities === null || capabilities === void 0 ? void 0 : (_capabilities$device = capabilities.device) === null || _capabilities$device === void 0 ? void 0 : (_capabilities$device$ = _capabilities$device.toString()) === null || _capabilities$device$ === void 0 ? void 0 : _capabilities$device$.toLowerCase())) {
return new MobileMetaData(driver, capabilities);

@@ -10,0 +11,0 @@ } else {

@@ -0,1 +1,3 @@

import Cache from '../util/cache.js';
// Todo: Implement a base metadata for the common functions.
export default class MobileMetaData {

@@ -6,15 +8,20 @@ constructor(driver, opts) {

}
device() {
return true;
}
browserName() {
return this.capabilities.browserName.toLowerCase();
var _this$capabilities, _this$capabilities$br;
return (_this$capabilities = this.capabilities) === null || _this$capabilities === void 0 ? void 0 : (_this$capabilities$br = _this$capabilities.browserName) === null || _this$capabilities$br === void 0 ? void 0 : _this$capabilities$br.toLowerCase();
}
browserVersion() {
var _this$capabilities$br;
const bsVersion = (_this$capabilities$br = this.capabilities.browserVersion) === null || _this$capabilities$br === void 0 ? void 0 : _this$capabilities$br.split('.');
var _this$capabilities$br2, _this$capabilities2, _this$capabilities2$v;
const bsVersion = (_this$capabilities$br2 = this.capabilities.browserVersion) === null || _this$capabilities$br2 === void 0 ? void 0 : _this$capabilities$br2.split('.');
if ((bsVersion === null || bsVersion === void 0 ? void 0 : bsVersion.length) > 0) {
return bsVersion[0];
}
return this.capabilities.version.split('.')[0];
return (_this$capabilities2 = this.capabilities) === null || _this$capabilities2 === void 0 ? void 0 : (_this$capabilities2$v = _this$capabilities2.version) === null || _this$capabilities2$v === void 0 ? void 0 : _this$capabilities2$v.split('.')[0];
}
osName() {
let osName = this.capabilities.os.toLowerCase();
var _this$capabilities3, _this$capabilities3$o;
let osName = (_this$capabilities3 = this.capabilities) === null || _this$capabilities3 === void 0 ? void 0 : (_this$capabilities3$o = _this$capabilities3.os) === null || _this$capabilities3$o === void 0 ? void 0 : _this$capabilities3$o.toLowerCase();
if (osName === 'mac' && this.browserName() === 'iphone') {

@@ -26,9 +33,12 @@ osName = 'ios';

osVersion() {
return this.capabilities.osVersion.split('.')[0];
var _this$capabilities4, _this$capabilities4$o;
return (_this$capabilities4 = this.capabilities) === null || _this$capabilities4 === void 0 ? void 0 : (_this$capabilities4$o = _this$capabilities4.osVersion) === null || _this$capabilities4$o === void 0 ? void 0 : _this$capabilities4$o.split('.')[0];
}
deviceName() {
return this.capabilities.deviceName.split('-')[0];
var _this$capabilities5, _this$capabilities5$d;
return (_this$capabilities5 = this.capabilities) === null || _this$capabilities5 === void 0 ? void 0 : (_this$capabilities5$d = _this$capabilities5.deviceName) === null || _this$capabilities5$d === void 0 ? void 0 : _this$capabilities5$d.split('-')[0];
}
orientation() {
return this.capabilities.orientation;
var _this$capabilities6;
return (_this$capabilities6 = this.capabilities) === null || _this$capabilities6 === void 0 ? void 0 : _this$capabilities6.orientation;
}

@@ -46,16 +56,20 @@ async windowSize() {

async screenResolution() {
const data = await this.driver.executeScript({
script: 'return [(window.screen.width * window.devicePixelRatio).toString(), (window.screen.height * window.devicePixelRatio).toString()];',
args: []
return await Cache.withCache(Cache.resolution, this.driver.sessionId, async () => {
const data = await this.driver.executeScript({
script: 'return [parseInt(window.screen.width * window.devicePixelRatio).toString(), parseInt(window.screen.height * window.devicePixelRatio).toString()];',
args: []
});
const screenInfo = data.value;
return `${screenInfo[0]} x ${screenInfo[1]}`;
});
const screenInfo = data.value;
return `${screenInfo[0]} x ${screenInfo[1]}`;
}
async devicePixelRatio() {
const devicePixelRatio = await this.driver.executeScript({
script: 'return window.devicePixelRatio;',
args: []
return await Cache.withCache(Cache.dpr, this.driver.sessionId, async () => {
const devicePixelRatio = await this.driver.executeScript({
script: 'return window.devicePixelRatio;',
args: []
});
return devicePixelRatio.value;
});
return devicePixelRatio.value;
}
}

@@ -5,2 +5,3 @@ import utils from '@percy/sdk-utils';

import Tile from '../util/tile.js';
import NormalizeData from '../metadata/normalizeData.js';
const log = utils.logger('webdriver-utils:automateProvider');

@@ -14,2 +15,3 @@ const {

this._markedPercy = false;
this.automateResults = null;
}

@@ -23,12 +25,17 @@ static supports(commandExecutorUrl) {

ignoreRegionElements = [],
customIgnoreRegions = []
customIgnoreRegions = [],
considerRegionXpaths = [],
considerRegionSelectors = [],
considerRegionElements = [],
customConsiderRegions = []
}) {
let response = null;
let error;
log.info('Preparing to capture screenshots on automate ...');
log.debug(`[${name}] : Preparing to capture screenshots on automate ...`);
try {
log.debug('Marking automate session as percy ...');
let result = await this.percyScreenshotBegin(name);
log.debug('Fetching the debug url ...');
this.setDebugUrl(result);
log.debug(`[${name}] : Marking automate session as percy ...`);
const result = await this.percyScreenshotBegin(name);
this.automateResults = JSON.parse(result.value);
log.debug(`[${name}] : Fetching the debug url ...`);
this.setDebugUrl();
response = await super.screenshot(name, {

@@ -38,3 +45,7 @@ ignoreRegionXpaths,

ignoreRegionElements,
customIgnoreRegions
customIgnoreRegions,
considerRegionXpaths,
considerRegionSelectors,
considerRegionElements,
customConsiderRegions
});

@@ -62,4 +73,4 @@ } catch (e) {

} catch (e) {
log.debug(`[${name}] Could not mark Automate session as percy`);
log.error(`[${name}] error: ${e.toString()}`);
log.debug(`[${name}] : Could not mark Automate session as percy`);
log.error(`[${name}] : error: ${e.toString()}`);
return null;

@@ -80,3 +91,3 @@ }

} catch (e) {
log.debug(`[${name}] Could not execute percyScreenshot command for Automate`);
log.debug(`[${name}] : Could not execute percyScreenshot command for Automate`);
log.error(e);

@@ -88,3 +99,3 @@ }

if (!this.driver) throw new Error('Driver is null, please initialize driver with createDriver().');
log.info('Starting actual screenshotting phase');
log.debug('Starting actual screenshotting phase');
const response = await TimeIt.run('percyScreenshot:screenshot', async () => {

@@ -95,6 +106,3 @@ return await this.browserstackExecutor('percyScreenshot', {

screenshotType: 'singlepage',
scaleFactor: await this.driver.executeScript({
script: 'return window.devicePixelRatio;',
args: []
}),
scaleFactor: await this.metaData.devicePixelRatio(),
options: this.options

@@ -143,6 +151,41 @@ });

this.debugUrl = await Cache.withCache(Cache.bstackSessionDetails, this.driver.sessionId, async () => {
const sessionDetails = await this.browserstackExecutor('getSessionDetails');
return JSON.parse(sessionDetails.value).browser_url;
return `https://automate.browserstack.com/builds/${this.automateResults.buildHash}/sessions/${this.automateResults.sessionHash}`;
});
}
async getTag() {
var _automateCaps$os_vers, _ref;
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 {
width,
height
} = await this.metaData.windowSize();
const resolution = await this.metaData.screenResolution();
const orientation = (_ref = this.metaData.orientation() || automateCaps.deviceOrientation) === null || _ref === void 0 ? void 0 : _ref.toLowerCase();
// for android window size only constitutes of browser viewport, hence adding nav / status / url bar heights
[this.header, this.footer] = await this.getHeaderFooter(deviceName, osVersion, browserName);
height = this.metaData.device() && (osName === null || osName === void 0 ? void 0 : osName.toLowerCase()) === 'android' ? height + this.header + this.footer : height;
return {
name: deviceName,
osName,
osVersion,
width,
height,
orientation,
browserName,
browserVersion,
resolution
};
}
}

@@ -59,3 +59,3 @@ import utils from '@percy/sdk-utils';

async createDriver() {
this.driver = new Driver(this.sessionId, this.commandExecutorUrl);
this.driver = new Driver(this.sessionId, this.commandExecutorUrl, this.capabilities);
log.debug(`Passed capabilities -> ${JSON.stringify(this.capabilities)}`);

@@ -101,3 +101,7 @@ const caps = await this.driver.getCapabilites();

ignoreRegionElements = [],
customIgnoreRegions = []
customIgnoreRegions = [],
considerRegionXpaths = [],
considerRegionSelectors = [],
considerRegionElements = [],
customConsiderRegions = []
}) {

@@ -107,12 +111,13 @@ let fullscreen = false;

const percyCSS = (this.defaultPercyCSS() + (this.options.percyCSS || '')).split('\n').join('');
log.debug(`Applying the percyCSS - ${this.options.percyCSS}`);
log.debug(`[${name}] : Applying the percyCSS - ${this.options.percyCSS}`);
await this.addPercyCSS(percyCSS);
log.debug('Fetching comparisong tag ...');
const tag = await this.getTag();
log.debug(`${name} : Tag ${JSON.stringify(tag)}`);
log.debug(`[${name}] : Tag ${JSON.stringify(tag)}`);
const tiles = await this.getTiles(this.header, this.footer, fullscreen);
log.debug(`${name} : Tiles ${JSON.stringify(tiles)}`);
const ignoreRegions = await this.findIgnoredRegions(ignoreRegionXpaths, ignoreRegionSelectors, ignoreRegionElements, customIgnoreRegions);
log.debug(`[${name}] : Tiles ${JSON.stringify(tiles)}`);
const ignoreRegions = await this.findRegions(ignoreRegionXpaths, ignoreRegionSelectors, ignoreRegionElements, customIgnoreRegions);
const considerRegions = await this.findRegions(considerRegionXpaths, considerRegionSelectors, considerRegionElements, customConsiderRegions);
await this.setDebugUrl();
log.debug(`${name} : Debug url ${this.debugUrl}`);
log.debug(`[${name}] : Debug url ${this.debugUrl}`);
await this.removePercyCSS();

@@ -125,3 +130,8 @@ return {

externalDebugUrl: this.debugUrl,
ignoredElementsData: ignoreRegions,
ignoredElementsData: {
ignoreElementsData: ignoreRegions
},
consideredElementsData: {
considerElementsData: considerRegions
},
environmentInfo: [...this.environmentInfo].join('; '),

@@ -183,12 +193,10 @@ clientInfo: [...this.clientInfo].join(' '),

}
async findIgnoredRegions(ignoreRegionXpaths, ignoreRegionSelectors, ignoreRegionElements, customIgnoreRegions) {
const ignoreElementXpaths = await this.getIgnoreRegionsBy('xpath', ignoreRegionXpaths);
const ignoreElementSelectors = await this.getIgnoreRegionsBy('css selector', ignoreRegionSelectors);
const ignoreElements = await this.getIgnoreRegionsByElement(ignoreRegionElements);
const ignoreElementCustom = await this.getCustomIgnoreRegions(customIgnoreRegions);
return {
ignoreElementsData: [...ignoreElementXpaths, ...ignoreElementSelectors, ...ignoreElements, ...ignoreElementCustom]
};
async findRegions(xpaths, selectors, elements, customLocations) {
const xpathRegions = await this.getSeleniumRegionsBy('xpath', xpaths);
const selectorRegions = await this.getSeleniumRegionsBy('css selector', selectors);
const elementRegions = await this.getSeleniumRegionsByElement(elements);
const customRegions = await this.getSeleniumRegionsByLocation(customLocations);
return [...xpathRegions, ...selectorRegions, ...elementRegions, ...customRegions];
}
async ignoreElementObject(selector, elementId) {
async getRegionObject(selector, elementId) {
const scaleFactor = parseInt(await this.metaData.devicePixelRatio());

@@ -216,4 +224,4 @@ const rect = await this.driver.rect(elementId);

}
async getIgnoreRegionsBy(findBy, elements) {
const ignoredElementsArray = [];
async getSeleniumRegionsBy(findBy, elements) {
const regionsArray = [];
for (const idx in elements) {

@@ -223,4 +231,4 @@ try {

const selector = `${findBy}: ${elements[idx]}`;
const ignoredRegion = await this.ignoreElementObject(selector, element[Object.keys(element)[0]]);
ignoredElementsArray.push(ignoredRegion);
const region = await this.getRegionObject(selector, element[Object.keys(element)[0]]);
regionsArray.push(region);
} catch (e) {

@@ -231,11 +239,11 @@ log.warn(`Selenium Element with ${findBy}: ${elements[idx]} not found. Ignoring this ${findBy}.`);

}
return ignoredElementsArray;
return regionsArray;
}
async getIgnoreRegionsByElement(elements) {
const ignoredElementsArray = [];
async getSeleniumRegionsByElement(elements) {
const regionsArray = [];
for (let index = 0; index < elements.length; index++) {
try {
const selector = `element: ${index}`;
const ignoredRegion = await this.ignoreElementObject(selector, elements[index]);
ignoredElementsArray.push(ignoredRegion);
const region = await this.getRegionObject(selector, elements[index]);
regionsArray.push(region);
} catch (e) {

@@ -246,6 +254,6 @@ log.warn(`Correct Web Element not passed at index ${index}.`);

}
return ignoredElementsArray;
return regionsArray;
}
async getCustomIgnoreRegions(customLocations) {
const ignoredElementsArray = [];
async getSeleniumRegionsByLocation(customLocations) {
const elementsArray = [];
const {

@@ -259,4 +267,4 @@ width,

if (!invalid) {
const selector = `custom ignore region ${index}`;
const ignoredRegion = {
const selector = `custom region ${index}`;
const region = {
selector,

@@ -270,3 +278,3 @@ coOrdinates: {

};
ignoredElementsArray.push(ignoredRegion);
elementsArray.push(region);
} else {

@@ -276,5 +284,5 @@ log.warn(`Values passed in custom ignored region at index: ${index} is not valid`);

}
return ignoredElementsArray;
return elementsArray;
}
async getHeaderFooter() {
async getHeaderFooter(deviceName, osVersion, browserName) {
// passing 0 as key, since across different pages and tests, this config will remain same

@@ -284,6 +292,5 @@ const devicesConfig = await Cache.withCache(Cache.devicesConfig, 0, async () => {

});
let deviceKey = `${this.metaData.deviceName()}-${this.metaData.osVersion()}`;
let browserName = this.capabilities.browserName;
let deviceKey = `${deviceName}-${osVersion}`;
return devicesConfig[deviceKey] ? devicesConfig[deviceKey][browserName] ? [devicesConfig[deviceKey][browserName].header, devicesConfig[deviceKey][browserName].footer] : [0, 0] : [0, 0];
}
}

@@ -13,2 +13,4 @@ import utils from '@percy/sdk-utils';

static devicesConfig = 'devicesConfig';
static dpr = 'dpr';
static resolution = 'resolution';

@@ -15,0 +17,0 @@ // maintainance

{
"name": "@percy/webdriver-utils",
"version": "1.27.0-beta.0",
"version": "1.27.0-beta.1",
"license": "MIT",

@@ -32,6 +32,6 @@ "repository": {

"dependencies": {
"@percy/config": "1.27.0-beta.0",
"@percy/sdk-utils": "1.27.0-beta.0"
"@percy/config": "1.27.0-beta.1",
"@percy/sdk-utils": "1.27.0-beta.1"
},
"gitHead": "2bc16314f51dddcc1cda459e7aa4b7b2db85f00a"
"gitHead": "40cdf9c38613ccaf5e3707cd2cd2d2778ffbd5dd"
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc