@percy/webdriver-utils 1.27.5-alpha.0 → 1.27.6-alpha.0

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/dist/driver.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import utils from '@percy/sdk-utils';
2
2
  import Cache from './util/cache.js';
3
- import httpsAgent from './util/utils.js';
4
3
  const {
5
4
  request
6
5
  } = utils;
@@ -11,14 +10,20 @@ export default class Driver {
11
10
  this.executorUrl = executorUrl.includes('@') ? `https://${executorUrl.split('@')[1]}` : executorUrl;
12
11
  this.passedCapabilities = passedCapabilities;
13
12
  }
13
+ static requestPostOptions(command) {
14
+ return {
15
+ method: 'POST',
16
+ headers: {
17
+ 'Content-Type': 'application/json;charset=utf-8'
18
+ },
19
+ body: JSON.stringify(command)
20
+ };
21
+ }
14
22
  async getCapabilites() {
15
23
  return await Cache.withCache(Cache.caps, this.sessionId, async () => {
16
24
  try {
17
- const options = {
18
- agent: httpsAgent()
19
- };
20
25
  const baseUrl = `${this.executorUrl}/session/${this.sessionId}`;
21
- const caps = JSON.parse((await request(baseUrl, options)).body);
26
+ const caps = JSON.parse((await request(baseUrl)).body);
22
27
  return caps.value;
23
28
  } catch (err) {
24
29
  log.warn(`Falling back to legacy protocol, Error: ${err.message}`);
@@ -27,11 +32,8 @@ export default class Driver {
27
32
  });
28
33
  }
29
34
  async getWindowSize() {
30
- const options = {
31
- agent: httpsAgent()
32
- };
33
35
  const baseUrl = `${this.executorUrl}/session/${this.sessionId}/window/current/size`;
34
- const windowSize = JSON.parse((await request(baseUrl, options)).body);
36
+ const windowSize = JSON.parse((await request(baseUrl)).body);
35
37
  return windowSize;
36
38
  }
37
39
 
@@ -45,46 +47,26 @@ export default class Driver {
45
47
  if (!command.script.includes('browserstack_executor')) {
46
48
  command.script = `/* percy_automate_script */ \n ${command.script}`;
47
49
  }
48
- const options = {
49
- method: 'POST',
50
- headers: {
51
- 'Content-Type': 'application/json;charset=utf-8'
52
- },
53
- agent: httpsAgent(),
54
- body: JSON.stringify(command)
55
- };
50
+ const options = Driver.requestPostOptions(command);
56
51
  const baseUrl = `${this.executorUrl}/session/${this.sessionId}/execute/sync`;
57
52
  const response = JSON.parse((await request(baseUrl, options)).body);
58
53
  return response;
59
54
  }
60
55
  async takeScreenshot() {
61
- const options = {
62
- agent: httpsAgent()
63
- };
64
56
  const baseUrl = `${this.executorUrl}/session/${this.sessionId}/screenshot`;
65
- const screenShot = JSON.parse((await request(baseUrl, options)).body);
57
+ const screenShot = JSON.parse((await request(baseUrl)).body);
66
58
  return screenShot.value;
67
59
  }
68
60
  async rect(elementId) {
69
- const options = {
70
- agent: httpsAgent()
71
- };
72
61
  const baseUrl = `${this.executorUrl}/session/${this.sessionId}/element/${elementId}/rect`;
73
- const response = JSON.parse((await request(baseUrl, options)).body);
62
+ const response = JSON.parse((await request(baseUrl)).body);
74
63
  return response.value;
75
64
  }
76
65
  async findElement(using, value) {
77
- const options = {
78
- method: 'POST',
79
- headers: {
80
- 'Content-Type': 'application/json;charset=utf-8'
81
- },
82
- agent: httpsAgent(),
83
- body: JSON.stringify({
84
- using,
85
- value
86
- })
87
- };
66
+ const options = Driver.requestPostOptions({
67
+ using,
68
+ value
69
+ });
88
70
  const baseUrl = `${this.executorUrl}/session/${this.sessionId}/element`;
89
71
  const response = JSON.parse((await request(baseUrl, options)).body);
90
72
  return response.value;
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ export default class WebdriverUtils {
23
23
  const comparisonData = await automate.screenshot(snapshotName, options);
24
24
  comparisonData.metadata.cliScreenshotStartTime = startTime;
25
25
  comparisonData.metadata.cliScreenshotEndTime = Date.now();
26
+ log.debug(`[${snapshotName}] : Comparison Data: ${JSON.stringify(comparisonData)}`);
26
27
  return comparisonData;
27
28
  } catch (e) {
28
29
  log.error(`[${snapshotName}] : Error - ${e.message}`);
@@ -49,7 +49,7 @@ export default class DesktopMetaData {
49
49
  async screenResolution() {
50
50
  return await Cache.withCache(Cache.resolution, this.driver.sessionId, async () => {
51
51
  const data = await this.driver.executeScript({
52
- script: 'return [(window.screen.width * window.devicePixelRatio).toString(), (window.screen.height * window.devicePixelRatio).toString()];',
52
+ script: 'return [parseInt(window.screen.width * window.devicePixelRatio).toString(), parseInt(window.screen.height * window.devicePixelRatio).toString()];',
53
53
  args: []
54
54
  });
55
55
  const screenInfo = data.value;
@@ -47,8 +47,7 @@ export default class AutomateProvider extends GenericProvider {
47
47
  error = e;
48
48
  throw e;
49
49
  } finally {
50
- var _response, _response$body;
51
- await this.percyScreenshotEnd(name, (_response = response) === null || _response === void 0 ? void 0 : (_response$body = _response.body) === null || _response$body === void 0 ? void 0 : _response$body.link, `${error}`);
50
+ await this.percyScreenshotEnd(name, error);
52
51
  }
53
52
  return response;
54
53
  }
@@ -61,23 +60,38 @@ export default class AutomateProvider extends GenericProvider {
61
60
  percyBuildUrl: this.buildInfo.url,
62
61
  state: 'begin'
63
62
  });
63
+ // Selenium Hub, set status error Code to 13 if an error is thrown
64
+ // Handling error with Selenium dialect is != W3C
65
+ 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');
64
66
  this._markedPercy = result.success;
65
67
  return result;
66
68
  } catch (e) {
69
+ var _e$response, _JSON$parse, _e$response2;
67
70
  log.debug(`[${name}] : Could not mark Automate session as percy`);
68
71
  log.error(`[${name}] : error: ${e.toString()}`);
69
- return null;
72
+ /**
73
+ * - Handling Error when dialect is W3C
74
+ * ERROR response format from SeleniumHUB `{
75
+ * sessionId: ...,
76
+ * status: 13,
77
+ * value: { error: '', message: ''}
78
+ * }
79
+ */
80
+ 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) || {};
81
+ 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();
82
+ throw new Error(errMessage);
70
83
  }
71
84
  });
72
85
  }
73
- async percyScreenshotEnd(name, percyScreenshotUrl, statusMessage = null) {
86
+ async percyScreenshotEnd(name, error) {
74
87
  return await TimeIt.run('percyScreenshotEnd', async () => {
75
88
  try {
89
+ var _this$buildInfo;
76
90
  await this.browserstackExecutor('percyScreenshot', {
77
91
  name,
78
- percyScreenshotUrl,
79
- status: percyScreenshotUrl ? 'success' : 'failure',
80
- statusMessage,
92
+ percyScreenshotUrl: (_this$buildInfo = this.buildInfo) === null || _this$buildInfo === void 0 ? void 0 : _this$buildInfo.url,
93
+ status: error ? 'failure' : 'success',
94
+ statusMessage: error ? `${error}` : '',
81
95
  state: 'end'
82
96
  });
83
97
  } catch (e) {
@@ -168,10 +182,6 @@ export default class AutomateProvider extends GenericProvider {
168
182
  } = await this.metaData.windowSize();
169
183
  const resolution = await this.metaData.screenResolution();
170
184
  const orientation = (_ref = this.metaData.orientation() || automateCaps.deviceOrientation) === null || _ref === void 0 ? void 0 : _ref.toLowerCase();
171
-
172
- // for android window size only constitutes of browser viewport, hence adding nav / status / url bar heights
173
- [this.header, this.footer] = await this.getHeaderFooter(deviceName, osVersion, browserName);
174
- height = this.metaData.device() && (osName === null || osName === void 0 ? void 0 : osName.toLowerCase()) === 'android' ? height + this.header + this.footer : height;
175
185
  return {
176
186
  name: deviceName,
177
187
  osName,
@@ -0,0 +1,5 @@
1
+ export default class CapabilitiesManager {
2
+ constructor(capabilities) {
3
+ this.capabilities = capabilities;
4
+ }
5
+ }
@@ -2,12 +2,6 @@ import utils from '@percy/sdk-utils';
2
2
  import MetaDataResolver from '../metadata/metaDataResolver.js';
3
3
  import Tile from '../util/tile.js';
4
4
  import Driver from '../driver.js';
5
- import Cache from '../util/cache.js';
6
- import httpsAgent from '../util/utils.js';
7
- const {
8
- request
9
- } = utils;
10
- const DEVICES_CONFIG_URL = 'https://storage.googleapis.com/percy-utils/devices.json';
11
5
  const log = utils.logger('webdriver-utils:genericProvider');
12
6
  export default class GenericProvider {
13
7
  clientInfo = new Set();
@@ -133,9 +127,6 @@ export default class GenericProvider {
133
127
  } = await this.metaData.windowSize();
134
128
  const resolution = await this.metaData.screenResolution();
135
129
  const orientation = this.metaData.orientation();
136
- [this.header, this.footer] = await this.getHeaderFooter();
137
- // for android window size only constitutes of browser viewport, hence adding nav / status / url bar heights
138
- height = this.metaData.osName() === 'android' ? height + this.header + this.footer : height;
139
130
  return {
140
131
  name: this.metaData.deviceName(),
141
132
  osName: this.metaData.osName(),
@@ -239,12 +230,4 @@ export default class GenericProvider {
239
230
  }
240
231
  return elementsArray;
241
232
  }
242
- async getHeaderFooter(deviceName, osVersion, browserName) {
243
- // passing 0 as key, since across different pages and tests, this config will remain same
244
- const devicesConfig = await Cache.withCache(Cache.devicesConfig, 0, async () => {
245
- return (await request(DEVICES_CONFIG_URL, httpsAgent())).body;
246
- });
247
- let deviceKey = `${deviceName}-${osVersion}`;
248
- return devicesConfig[deviceKey] ? devicesConfig[deviceKey][browserName] ? [devicesConfig[deviceKey][browserName].header, devicesConfig[deviceKey][browserName].footer] : [0, 0] : [0, 0];
249
- }
250
233
  }
@@ -0,0 +1,72 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { colors } from '@percy/logger/utils';
4
+ import semver from 'semver';
5
+ export default class CapabilitiesValidator {
6
+ constructor(automateCapabilities, sessionCapabilities) {
7
+ this.automateCapabilities = automateCapabilities;
8
+ this.sessionCapabilities = sessionCapabilities;
9
+ }
10
+ WARN_LOG_LEVEL = 'WARN';
11
+ ERROR_LOG_LEVEL = 'ERROR';
12
+ log(message, errorLevel = this.ERROR_LOG_LEVEL) {
13
+ if (errorLevel === this.WARN_LOG_LEVEL) {
14
+ console.warn(colors.yellow(message));
15
+ } else if (errorLevel === this.ERROR_LOG_LEVEL) {
16
+ console.error(colors.red(message));
17
+ }
18
+ }
19
+ existsInArray(array, value) {
20
+ if (!array || array.length === 0) return false;
21
+ return array.some(element => {
22
+ return element === value;
23
+ });
24
+ }
25
+ validateBrowserOSVersions() {
26
+ var _this$sessionCapabili, _this$sessionCapabili2;
27
+ const cwd = process.cwd();
28
+ const excludeBrowserData = JSON.parse(fs.readFileSync(path.join(cwd, 'packages/webdriver-utils/src/util/exclude_browsers.json')));
29
+ let {
30
+ os,
31
+ osVersion,
32
+ browserName,
33
+ browserVersion,
34
+ deviceName
35
+ } = this.automateCapabilities;
36
+ const platform = (_this$sessionCapabili = this.sessionCapabilities) === null || _this$sessionCapabili === void 0 ? void 0 : (_this$sessionCapabili2 = _this$sessionCapabili.platformName) === null || _this$sessionCapabili2 === void 0 ? void 0 : _this$sessionCapabili2.toLowerCase();
37
+ if (!os || !osVersion || !browserName || !browserVersion) {
38
+ this.log('OS/Browser Combination is not supported on Percy');
39
+ throw new Error('OS/Browser Combination is not supported on Percy');
40
+ }
41
+ const isMobile = ['ios', 'android'].includes(platform);
42
+ if (isMobile && !deviceName) {
43
+ this.log('Device capabilities are incorrect or not supported on Percy');
44
+ throw new Error('Device capabilities are incorrect or not supported on Percy');
45
+ }
46
+ if (excludeBrowserData !== null && excludeBrowserData !== void 0 && excludeBrowserData.os[os]) {
47
+ const osData = excludeBrowserData === null || excludeBrowserData === void 0 ? void 0 : excludeBrowserData.os[os];
48
+ if (osData !== null && osData !== void 0 && osData.os_versions) {
49
+ if (this.existsInArray(osData.os_versions, osVersion)) {
50
+ this.log(`${os} ${osVersion} is not supported on Percy`);
51
+ throw new Error(`${os} ${osVersion} is not supported on Percy`);
52
+ }
53
+ }
54
+ if (osData !== null && osData !== void 0 && osData.browsers) {
55
+ const browserData = osData === null || osData === void 0 ? void 0 : osData.browsers[browserName.toLowerCase()];
56
+ if (browserData && browserData.min_version === 'all') {
57
+ this.log(`${browserName} is not supported on Percy`);
58
+ throw new Error(`${browserName} is not supported on Percy`);
59
+ } else if (browserData && parseInt(browserVersion, 10) < parseInt(browserData.min_version, 10)) {
60
+ this.log(`${browserName}: ${browserVersion} is not supported on Percy`);
61
+ throw new Error(`${browserName}: ${browserVersion} is not supported on Percy`);
62
+ }
63
+ }
64
+ if (osData !== null && osData !== void 0 && osData.device_names) {
65
+ if (this.existsInArray(osData === null || osData === void 0 ? void 0 : osData.device_names, deviceName)) {
66
+ this.log(`${deviceName} is not supported on Percy`);
67
+ throw new Error(`${deviceName} is not supported in Percy`);
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,7 @@
1
+ export const SELENIUM_TO_API_OS_MAPPING = {
2
+ MAC: 'OS X',
3
+ WIN8: 'Windows',
4
+ XP: 'Windows',
5
+ WINDOWS: 'Windows',
6
+ ANY: 'OS X'
7
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percy/webdriver-utils",
3
- "version": "1.27.5-alpha.0",
3
+ "version": "1.27.6-alpha.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,8 +29,8 @@
29
29
  "test:coverage": "yarn test --coverage"
30
30
  },
31
31
  "dependencies": {
32
- "@percy/config": "1.27.5-alpha.0",
33
- "@percy/sdk-utils": "1.27.5-alpha.0"
32
+ "@percy/config": "1.27.6-alpha.0",
33
+ "@percy/sdk-utils": "1.27.6-alpha.0"
34
34
  },
35
- "gitHead": "8ecc32db25f708a01192b8454d0fdf9c051f48a0"
35
+ "gitHead": "415a083dc13e9453990b042a41d6676f6618df0c"
36
36
  }
@@ -1,8 +0,0 @@
1
- import https from 'https';
2
- export function httpsAgent() {
3
- return new https.Agent({
4
- minVersion: 'TLSv1.2',
5
- maxVersion: 'TLSv1.2'
6
- });
7
- }
8
- export default httpsAgent;