From 1792bac845f86fae07e75b415a961b1ceaf81afb Mon Sep 17 00:00:00 2001 From: Jigar Wala Date: Mon, 11 Sep 2023 20:18:42 +0530 Subject: [PATCH 1/9] initial commit --- packages/core/src/api.js | 2 +- packages/core/src/config.js | 47 +++++++++++++++++++++++++++ packages/core/src/utils.js | 26 ++++++++++++--- packages/webdriver-utils/src/index.js | 8 +---- 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/packages/core/src/api.js b/packages/core/src/api.js index b10c348ae..45054311f 100644 --- a/packages/core/src/api.js +++ b/packages/core/src/api.js @@ -117,7 +117,7 @@ export function createPercyServer(percy, port) { success: await percy.flush(req.body).then(() => true) })) .route('post', '/percy/automateScreenshot', async (req, res) => { - req = percyAutomateRequestHandler(req, percy.build); + req = percyAutomateRequestHandler(req, percy); res.json(200, { success: await (percy.upload(await new WebdriverUtils(req.body).automateScreenshot())).then(() => true) }); diff --git a/packages/core/src/config.js b/packages/core/src/config.js index 59e31af58..71da5dd17 100644 --- a/packages/core/src/config.js +++ b/packages/core/src/config.js @@ -49,6 +49,53 @@ export const configSchema = { }, scope: { type: 'string' + }, + freezeAnimation: { + type: 'boolean', + default: false, + onlyAutomate: true + }, + ignoreRegions: { + type: 'object', + additionalProperties: false, + onlyAutomate: true, + properties: { + ignoreRegionSelectors: { + type: 'array', + default: [], + items: { + type: 'string' + } + }, + ignoreRegionXpaths: { + type: 'array', + default: [], + items: { + type: 'string' + } + } + } + }, + considerRegions: { + type: 'object', + additionalProperties: false, + onlyAutomate: true, + properties: { + considerRegionSelectors: { + type: 'array', + default: [], + items: { + type: 'string' + } + }, + considerRegionXPaths: { + type: 'array', + default: [], + items: { + type: 'string' + } + } + } } } }, diff --git a/packages/core/src/utils.js b/packages/core/src/utils.js index 4a3f412e5..ee30d88f2 100644 --- a/packages/core/src/utils.js +++ b/packages/core/src/utils.js @@ -1,5 +1,6 @@ import EventEmitter from 'events'; import { sha256hash } from '@percy/client/utils'; +import { camelcase, merge } from '@percy/config/utils'; export { request, @@ -24,17 +25,32 @@ export function normalizeURL(url) { } // Returns the body for automateScreenshot in structure -export function percyAutomateRequestHandler(req, buildInfo) { +export function percyAutomateRequestHandler(req, percy) { if (req.body.client_info) { req.body.clientInfo = req.body.client_info; } if (req.body.environment_info) { req.body.environmentInfo = req.body.environment_info; } - if (!req.body.options) { - req.body.options = {}; - } - req.body.buildInfo = buildInfo; + + // combines array and overrides global config with per-screenshot config + let camelCasedOptions = {}; + Object.entries(req.body.options || {}).forEach(([key, value]) => { + camelCasedOptions[camelcase(key)] = value; + }); + + req.body.options = merge([{ + percyCSS: percy.config.snapshot.percyCSS, + freezeAnimation: percy.config.snapshot.freezeAnimation, + ignoreRegionSelectors: percy.config.snapshot.ignoreRegions.ignoreRegionSelectors, + ignoreRegionXpaths: percy.config.snapshot.ignoreRegions.ignoreRegionXpaths, + considerRegionSelectors: percy.config.snapshot.considerRegions.considerRegionSelectors, + considerRegionXPaths: percy.config.snapshot.considerRegions.considerRegionXPaths + }, + camelCasedOptions + ]); + + req.body.buildInfo = percy.build; return req; } diff --git a/packages/webdriver-utils/src/index.js b/packages/webdriver-utils/src/index.js index e5cabca74..f2b9d63c1 100644 --- a/packages/webdriver-utils/src/index.js +++ b/packages/webdriver-utils/src/index.js @@ -1,6 +1,5 @@ import ProviderResolver from './providers/providerResolver.js'; import utils from '@percy/sdk-utils'; -import { camelcase } from '@percy/config/utils'; export default class WebdriverUtils { log = utils.logger('webdriver-utils:main'); @@ -21,12 +20,7 @@ export default class WebdriverUtils { this.capabilities = capabilities; this.sessionCapabilites = sessionCapabilites; this.snapshotName = snapshotName; - const camelCasedOptions = {}; - Object.keys(options).forEach((key) => { - let newKey = camelcase(key); - camelCasedOptions[newKey] = options[key]; - }); - this.options = camelCasedOptions; + this.options = options; this.clientInfo = clientInfo; this.environmentInfo = environmentInfo; this.buildInfo = buildInfo; From 5a1251ee76f03b9ca3b9035dc604bbabbc724cfa Mon Sep 17 00:00:00 2001 From: Jigar Wala Date: Mon, 11 Sep 2023 21:01:02 +0530 Subject: [PATCH 2/9] combine percyCSS similar to web projects --- packages/core/src/utils.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/core/src/utils.js b/packages/core/src/utils.js index ee30d88f2..7c5ce2fad 100644 --- a/packages/core/src/utils.js +++ b/packages/core/src/utils.js @@ -48,7 +48,12 @@ export function percyAutomateRequestHandler(req, percy) { considerRegionXPaths: percy.config.snapshot.considerRegions.considerRegionXPaths }, camelCasedOptions - ]); + ], (path, prev, next) => { + switch (path.map(k => k.toString()).join('.')) { + case 'percyCSS': // concatenate percy css + return [path, [prev, next].filter(Boolean).join('\n')]; + } + }); req.body.buildInfo = percy.build; return req; From d735eae8f301819e5efb3369eb8bf976476ca8a2 Mon Sep 17 00:00:00 2001 From: Jigar Wala Date: Mon, 11 Sep 2023 21:01:28 +0530 Subject: [PATCH 3/9] raise warning when using params that are invalid with non automate projects --- packages/config/src/validate.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/config/src/validate.js b/packages/config/src/validate.js index 02e553811..2a58da0b0 100644 --- a/packages/config/src/validate.js +++ b/packages/config/src/validate.js @@ -19,6 +19,17 @@ const ajv = new AJV({ getDefaultSchema() ], keywords: [{ + keyword: 'onlyAutomate', + error: { + message: 'Only valid for Automate type projects' + }, + code: cxt => { + let isAutomateProjectToken = (process.env.PERCY_TOKEN || '').split('_')[0] === 'auto'; + if (!isAutomateProjectToken) { + cxt.error(); + } + } + }, { // custom instanceof schema validation keyword: 'instanceof', metaSchema: { From d5b6a9edbb90f2015bafb2cb033b8092a2d05b00 Mon Sep 17 00:00:00 2001 From: Jigar Wala Date: Tue, 12 Sep 2023 21:07:44 +0530 Subject: [PATCH 4/9] remove defaults, perform validation only when token passed --- packages/config/src/validate.js | 5 +++-- packages/core/src/config.js | 5 ----- packages/core/src/utils.js | 8 ++++---- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/config/src/validate.js b/packages/config/src/validate.js index 2a58da0b0..add0b2f96 100644 --- a/packages/config/src/validate.js +++ b/packages/config/src/validate.js @@ -21,11 +21,12 @@ const ajv = new AJV({ keywords: [{ keyword: 'onlyAutomate', error: { - message: 'Only valid for Automate type projects' + message: 'property only valid with Automate integration.' }, code: cxt => { let isAutomateProjectToken = (process.env.PERCY_TOKEN || '').split('_')[0] === 'auto'; - if (!isAutomateProjectToken) { + // we do validation only when token is passed + if (!!process.env.PERCY_TOKEN && !isAutomateProjectToken) { cxt.error(); } } diff --git a/packages/core/src/config.js b/packages/core/src/config.js index 71da5dd17..8b2024d4f 100644 --- a/packages/core/src/config.js +++ b/packages/core/src/config.js @@ -52,7 +52,6 @@ export const configSchema = { }, freezeAnimation: { type: 'boolean', - default: false, onlyAutomate: true }, ignoreRegions: { @@ -62,14 +61,12 @@ export const configSchema = { properties: { ignoreRegionSelectors: { type: 'array', - default: [], items: { type: 'string' } }, ignoreRegionXpaths: { type: 'array', - default: [], items: { type: 'string' } @@ -83,14 +80,12 @@ export const configSchema = { properties: { considerRegionSelectors: { type: 'array', - default: [], items: { type: 'string' } }, considerRegionXPaths: { type: 'array', - default: [], items: { type: 'string' } diff --git a/packages/core/src/utils.js b/packages/core/src/utils.js index 7c5ce2fad..647c4e3f8 100644 --- a/packages/core/src/utils.js +++ b/packages/core/src/utils.js @@ -42,10 +42,10 @@ export function percyAutomateRequestHandler(req, percy) { req.body.options = merge([{ percyCSS: percy.config.snapshot.percyCSS, freezeAnimation: percy.config.snapshot.freezeAnimation, - ignoreRegionSelectors: percy.config.snapshot.ignoreRegions.ignoreRegionSelectors, - ignoreRegionXpaths: percy.config.snapshot.ignoreRegions.ignoreRegionXpaths, - considerRegionSelectors: percy.config.snapshot.considerRegions.considerRegionSelectors, - considerRegionXPaths: percy.config.snapshot.considerRegions.considerRegionXPaths + ignoreRegionSelectors: percy.config.snapshot.ignoreRegions?.ignoreRegionSelectors, + ignoreRegionXpaths: percy.config.snapshot.ignoreRegions?.ignoreRegionXpaths, + considerRegionSelectors: percy.config.snapshot.considerRegions?.considerRegionSelectors, + considerRegionXPaths: percy.config.snapshot.considerRegions?.considerRegionXPaths, }, camelCasedOptions ], (path, prev, next) => { From 1004bfff46fbd9459d0c1232f38f758270c55672 Mon Sep 17 00:00:00 2001 From: Jigar Wala Date: Tue, 12 Sep 2023 21:10:12 +0530 Subject: [PATCH 5/9] lint fix --- packages/core/src/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/utils.js b/packages/core/src/utils.js index 647c4e3f8..f71c872dd 100644 --- a/packages/core/src/utils.js +++ b/packages/core/src/utils.js @@ -45,7 +45,7 @@ export function percyAutomateRequestHandler(req, percy) { ignoreRegionSelectors: percy.config.snapshot.ignoreRegions?.ignoreRegionSelectors, ignoreRegionXpaths: percy.config.snapshot.ignoreRegions?.ignoreRegionXpaths, considerRegionSelectors: percy.config.snapshot.considerRegions?.considerRegionSelectors, - considerRegionXPaths: percy.config.snapshot.considerRegions?.considerRegionXPaths, + considerRegionXPaths: percy.config.snapshot.considerRegions?.considerRegionXPaths }, camelCasedOptions ], (path, prev, next) => { From 40f14c9c6c69aabb174dc63746fa5962d88ee58b Mon Sep 17 00:00:00 2001 From: Jigar Wala Date: Thu, 14 Sep 2023 11:36:17 +0530 Subject: [PATCH 6/9] increase coverage --- packages/config/src/utils/normalize.js | 3 +- packages/core/src/api.js | 7 +- packages/core/src/utils.js | 3 +- packages/core/test/api.test.js | 89 ++++++++++++++++++++++---- packages/core/test/unit/utils.test.js | 42 +----------- 5 files changed, 85 insertions(+), 59 deletions(-) diff --git a/packages/config/src/utils/normalize.js b/packages/config/src/utils/normalize.js index 1b07c4c42..844fc4de3 100644 --- a/packages/config/src/utils/normalize.js +++ b/packages/config/src/utils/normalize.js @@ -5,7 +5,8 @@ import { getSchema } from '../validate.js'; const CAMELCASE_MAP = new Map([ ['css', 'CSS'], ['javascript', 'JavaScript'], - ['dom', 'DOM'] + ['dom', 'DOM'], + ['xpaths', 'XPaths'] ]); // Regular expression that matches words from boundaries or consecutive casing diff --git a/packages/core/src/api.js b/packages/core/src/api.js index 45054311f..bb45cad7e 100644 --- a/packages/core/src/api.js +++ b/packages/core/src/api.js @@ -117,10 +117,9 @@ export function createPercyServer(percy, port) { success: await percy.flush(req.body).then(() => true) })) .route('post', '/percy/automateScreenshot', async (req, res) => { - req = percyAutomateRequestHandler(req, percy); - res.json(200, { - success: await (percy.upload(await new WebdriverUtils(req.body).automateScreenshot())).then(() => true) - }); + percyAutomateRequestHandler(req, percy); + percy.upload(await new WebdriverUtils(req.body).automateScreenshot()); + res.json(200, { success: true }); }) // stops percy at the end of the current event loop .route('/percy/stop', (req, res) => { diff --git a/packages/core/src/utils.js b/packages/core/src/utils.js index f71c872dd..34a8838bf 100644 --- a/packages/core/src/utils.js +++ b/packages/core/src/utils.js @@ -24,6 +24,7 @@ export function normalizeURL(url) { return `${protocol}//${host}${pathname}${search}`; } +/* istanbul ignore next: tested, but coverage is stripped */ // Returns the body for automateScreenshot in structure export function percyAutomateRequestHandler(req, percy) { if (req.body.client_info) { @@ -54,8 +55,8 @@ export function percyAutomateRequestHandler(req, percy) { return [path, [prev, next].filter(Boolean).join('\n')]; } }); - req.body.buildInfo = percy.build; + // returning for testing purpose. return req; } diff --git a/packages/core/test/api.test.js b/packages/core/test/api.test.js index 033503739..443f1dd5e 100644 --- a/packages/core/test/api.test.js +++ b/packages/core/test/api.test.js @@ -2,7 +2,7 @@ import path from 'path'; import PercyConfig from '@percy/config'; import { logger, setupTest, fs } from './helpers/index.js'; import Percy from '@percy/core'; -import WebdriverUtils from '@percy/webdriver-utils'; // eslint-disable-line import/no-extraneous-dependencies +import WebdriverUtils from '@percy/webdriver-utils'; describe('API Server', () => { let percy; @@ -131,17 +131,6 @@ describe('API Server', () => { }); }); - it('has a /automateScreenshot endpoint that calls #upload()', async () => { - spyOn(percy, 'upload').and.resolveTo(); - spyOn(WebdriverUtils.prototype, 'automateScreenshot').and.resolveTo(true); - await percy.start(); - - await expectAsync(request('/percy/automateScreenshot', { - body: { name: 'Snapshot name' }, - method: 'post' - })).toBeResolvedTo({ success: true }); - }); - it('has a /stop endpoint that calls #stop()', async () => { spyOn(percy, 'stop').and.resolveTo(); await percy.start(); @@ -277,6 +266,82 @@ describe('API Server', () => { await expectAsync(pending).toBeResolved(); }); + // describe('percyAutomateRequestHandler', () => { + // let req; + // let percyBuildInfo; + // beforeAll(() => { + // req = { + // body: { + // name: 'abc', + // client_info: 'client', + // environment_info: 'environment' + // } + // }; + + // percyBuildInfo = { + // id: '123', + // url: 'https://percy.io/abc/123' + // }; + // }); + + // it('converts client_info to clientInfo', () => { + // const nreq = percyAutomateRequestHandler(req, percyBuildInfo); + // expect(nreq.body.clientInfo).toBe('client'); + // }); + + // it('converts environment_info to environmentInfo', () => { + // const nreq = percyAutomateRequestHandler(req, percyBuildInfo); + // expect(nreq.body.environmentInfo).toBe('environment'); + // }); + + // it('adds options', () => { + // const nreq = percyAutomateRequestHandler(req, percyBuildInfo); + // expect(nreq.body.options).toEqual({}); + // }); + + // it('adds percyBuildInfo', () => { + // const nreq = percyAutomateRequestHandler(req, percyBuildInfo); + // expect(nreq.body.buildInfo).toEqual(percyBuildInfo); + // }); + // }); + + fit('has a /automateScreenshot endpoint that calls #upload() async with provided options', async () => { + let resolve, test = new Promise(r => (resolve = r)); + spyOn(percy, 'upload').and.returnValue(test); + let mockWebdriverUtilResponse = 'TODO: mocked response'; + // let percyAutomateRequestHandlerSpy = spyOn(utils, 'percyAutomateRequestHandler').and.callThrough(); + spyOn(WebdriverUtils.prototype, 'automateScreenshot').and.resolveTo(mockWebdriverUtilResponse); + + await percy.start(); + + percy.config.snapshot.percyCSS = '.global { color: blue }'; + percy.config.snapshot.freezeAnimation = false; + percy.config.snapshot.ignoreRegions = { ignoreRegionSelectors: ['.selector-global'] }; + percy.config.snapshot.considerRegions = { considerRegionXPaths: ['/xpath-global'] }; + + await expectAsync(request('/percy/automateScreenshot', { + body: { + name: 'Snapshot name', + client_info: 'client', + environment_info: 'environment', + options: { + percyCSS: '.percy-screenshot: { color: red }', + freeze_animation: true, + ignore_region_xpaths: ['/xpath-per-screenshot'], + consider_region_xpaths: ['/xpath-per-screenshot'] + } + }, + method: 'post' + })).toBeResolvedTo({ success: true }); + + // expect(percyAutomateRequestHandlerSpy).toHaveBeenCalledOnceWith({ + + // }) + expect(percy.upload).toHaveBeenCalledOnceWith(mockWebdriverUtilResponse); + await expectAsync(test).toBePending(); + resolve(); // no hanging promises + }); + it('returns a 500 error when an endpoint throws', async () => { spyOn(percy, 'snapshot').and.rejectWith(new Error('test error')); await percy.start(); diff --git a/packages/core/test/unit/utils.test.js b/packages/core/test/unit/utils.test.js index 97929771d..354dc1bb7 100644 --- a/packages/core/test/unit/utils.test.js +++ b/packages/core/test/unit/utils.test.js @@ -2,8 +2,7 @@ import { generatePromise, AbortController, yieldTo, - yieldAll, - percyAutomateRequestHandler + yieldAll } from '../../src/utils.js'; describe('Unit / Utils', () => { @@ -166,43 +165,4 @@ describe('Unit / Utils', () => { { done: true, value: [2, 4, null, 3, 6] }); }); }); - - describe('percyAutomateRequestHandler', () => { - let req; - let percyBuildInfo; - beforeAll(() => { - req = { - body: { - name: 'abc', - client_info: 'client', - environment_info: 'environment' - } - }; - - percyBuildInfo = { - id: '123', - url: 'https://percy.io/abc/123' - }; - }); - - it('converts client_info to clientInfo', () => { - const nreq = percyAutomateRequestHandler(req, percyBuildInfo); - expect(nreq.body.clientInfo).toBe('client'); - }); - - it('converts environment_info to environmentInfo', () => { - const nreq = percyAutomateRequestHandler(req, percyBuildInfo); - expect(nreq.body.environmentInfo).toBe('environment'); - }); - - it('adds options', () => { - const nreq = percyAutomateRequestHandler(req, percyBuildInfo); - expect(nreq.body.options).toEqual({}); - }); - - it('adds percyBuildInfo', () => { - const nreq = percyAutomateRequestHandler(req, percyBuildInfo); - expect(nreq.body.buildInfo).toEqual(percyBuildInfo); - }); - }); }); From 11524f94215ba4d56efef0695073465a060b2152 Mon Sep 17 00:00:00 2001 From: Jigar Wala Date: Thu, 14 Sep 2023 17:07:40 +0530 Subject: [PATCH 7/9] improve coverage --- packages/config/test/index.test.js | 116 +++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 6 deletions(-) diff --git a/packages/config/test/index.test.js b/packages/config/test/index.test.js index 207bbf4e8..5e81e6da5 100644 --- a/packages/config/test/index.test.js +++ b/packages/config/test/index.test.js @@ -355,6 +355,104 @@ describe('PercyConfig', () => { expect(conf).toEqual({ foo: { bar: 'baz', qux: 'xyzzy' } }); }); + describe('validates automate integration specific properties', () => { + beforeEach(() => { + delete process.env.PERCY_TOKEN; + + PercyConfig.addSchema({ + test: { + type: 'object', + additionalProperties: false, + properties: { + foo: { + type: 'number', + onlyAutomate: true + }, + bar: { + type: 'number' + } + } + } + }); + }); + + it('passes when no token present', () => { + expect(PercyConfig.validate({ + test: { + foo: 1, + bar: 2 + } + })).toBeUndefined(); + }); + + it('passes when token is of automate project', () => { + process.env.PERCY_TOKEN = 'auto_PERCY_TOKEN'; + + expect(PercyConfig.validate({ + test: { + foo: 1, + bar: 2 + } + })).toBeUndefined(); + }); + + it('warns when token is of legacy web project', () => { + process.env.PERCY_TOKEN = 'PERCY_TOKEN'; + + expect(PercyConfig.validate({ + test: { + foo: 1, + bar: 2 + } + })).toEqual([{ + path: 'test.foo', + message: 'property only valid with Automate integration.' + }]); + }); + + it('warns when token is of web project', () => { + process.env.PERCY_TOKEN = 'web_PERCY_TOKEN'; + + expect(PercyConfig.validate({ + test: { + foo: 1, + bar: 2 + } + })).toEqual([{ + path: 'test.foo', + message: 'property only valid with Automate integration.' + }]); + }); + + it('warns when token is of app project', () => { + process.env.PERCY_TOKEN = 'app_PERCY_TOKEN'; + + expect(PercyConfig.validate({ + test: { + foo: 1, + bar: 2 + } + })).toEqual([{ + path: 'test.foo', + message: 'property only valid with Automate integration.' + }]); + }); + + it('warns when token is of self serve project', () => { + process.env.PERCY_TOKEN = 'ss_PERCY_TOKEN'; + + expect(PercyConfig.validate({ + test: { + foo: 1, + bar: 2 + } + })).toEqual([{ + path: 'test.foo', + message: 'property only valid with Automate integration.' + }]); + }); + }); + it('can validate functions and regular expressions', () => { PercyConfig.addSchema({ func: { instanceof: 'Function' }, @@ -1102,7 +1200,8 @@ describe('PercyConfig', () => { 'percy-css': '', 'enable-javascript': false, 'disable-shadow-dom': true, - 'cli-enable-javascript': true + 'cli-enable-javascript': true, + 'ignore-region-xpaths': [''] })).toEqual({ fooBar: 'baz', foo: { barBaz: 'qux' }, @@ -1111,7 +1210,8 @@ describe('PercyConfig', () => { percyCSS: '', enableJavaScript: false, disableShadowDOM: true, - cliEnableJavaScript: true + cliEnableJavaScript: true, + ignoreRegionXPaths: [''] }); }); @@ -1123,7 +1223,8 @@ describe('PercyConfig', () => { percyCSS: '', enableJavaScript: false, disableShadowDOM: true, - cliEnableJavaScript: true + cliEnableJavaScript: true, + ignoreRegionXPaths: [''] }, { kebab: true })).toEqual({ 'foo-bar': 'baz', foo: { 'bar-baz': 'qux' }, @@ -1131,7 +1232,8 @@ describe('PercyConfig', () => { 'percy-css': '', 'enable-javascript': false, 'disable-shadow-dom': true, - 'cli-enable-javascript': true + 'cli-enable-javascript': true, + 'ignore-region-xpaths': [''] }); }); @@ -1143,7 +1245,8 @@ describe('PercyConfig', () => { percyCSS: '', enableJavaScript: false, disableShadowDOM: true, - cliEnableJavaScript: true + cliEnableJavaScript: true, + ignoreRegionXPaths: [''] }, { snake: true })).toEqual({ foo_bar: 'baz', foo: { bar_baz: 'qux' }, @@ -1151,7 +1254,8 @@ describe('PercyConfig', () => { percy_css: '', enable_javascript: false, disable_shadow_dom: true, - cli_enable_javascript: true + cli_enable_javascript: true, + ignore_region_xpaths: [''] }); }); From 59fc5f04291546d25e8f9c9dbcdd37810dd08a1e Mon Sep 17 00:00:00 2001 From: Jigar Wala Date: Thu, 14 Sep 2023 18:03:47 +0530 Subject: [PATCH 8/9] refactor for improved coverage --- packages/core/src/api.js | 2 +- packages/core/test/api.test.js | 58 +++++++-------------------- packages/webdriver-utils/src/index.js | 51 +++++++++-------------- 3 files changed, 34 insertions(+), 77 deletions(-) diff --git a/packages/core/src/api.js b/packages/core/src/api.js index bb45cad7e..ffeb4325c 100644 --- a/packages/core/src/api.js +++ b/packages/core/src/api.js @@ -118,7 +118,7 @@ export function createPercyServer(percy, port) { })) .route('post', '/percy/automateScreenshot', async (req, res) => { percyAutomateRequestHandler(req, percy); - percy.upload(await new WebdriverUtils(req.body).automateScreenshot()); + percy.upload(await WebdriverUtils.automateScreenshot(req.body)); res.json(200, { success: true }); }) // stops percy at the end of the current event loop diff --git a/packages/core/test/api.test.js b/packages/core/test/api.test.js index 443f1dd5e..06670302f 100644 --- a/packages/core/test/api.test.js +++ b/packages/core/test/api.test.js @@ -266,51 +266,11 @@ describe('API Server', () => { await expectAsync(pending).toBeResolved(); }); - // describe('percyAutomateRequestHandler', () => { - // let req; - // let percyBuildInfo; - // beforeAll(() => { - // req = { - // body: { - // name: 'abc', - // client_info: 'client', - // environment_info: 'environment' - // } - // }; - - // percyBuildInfo = { - // id: '123', - // url: 'https://percy.io/abc/123' - // }; - // }); - - // it('converts client_info to clientInfo', () => { - // const nreq = percyAutomateRequestHandler(req, percyBuildInfo); - // expect(nreq.body.clientInfo).toBe('client'); - // }); - - // it('converts environment_info to environmentInfo', () => { - // const nreq = percyAutomateRequestHandler(req, percyBuildInfo); - // expect(nreq.body.environmentInfo).toBe('environment'); - // }); - - // it('adds options', () => { - // const nreq = percyAutomateRequestHandler(req, percyBuildInfo); - // expect(nreq.body.options).toEqual({}); - // }); - - // it('adds percyBuildInfo', () => { - // const nreq = percyAutomateRequestHandler(req, percyBuildInfo); - // expect(nreq.body.buildInfo).toEqual(percyBuildInfo); - // }); - // }); - - fit('has a /automateScreenshot endpoint that calls #upload() async with provided options', async () => { + it('has a /automateScreenshot endpoint that calls #upload() async with provided options', async () => { let resolve, test = new Promise(r => (resolve = r)); spyOn(percy, 'upload').and.returnValue(test); let mockWebdriverUtilResponse = 'TODO: mocked response'; - // let percyAutomateRequestHandlerSpy = spyOn(utils, 'percyAutomateRequestHandler').and.callThrough(); - spyOn(WebdriverUtils.prototype, 'automateScreenshot').and.resolveTo(mockWebdriverUtilResponse); + let automateScreenshotSpy = spyOn(WebdriverUtils, 'automateScreenshot').and.resolveTo(mockWebdriverUtilResponse); await percy.start(); @@ -334,9 +294,19 @@ describe('API Server', () => { method: 'post' })).toBeResolvedTo({ success: true }); - // expect(percyAutomateRequestHandlerSpy).toHaveBeenCalledOnceWith({ + expect(automateScreenshotSpy).toHaveBeenCalledOnceWith(jasmine.objectContaining({ + clientInfo: 'client', + environmentInfo: 'environment', + buildInfo: { id: '123', url: 'https://percy.io/test/test/123', number: 1 }, + options: { + freezeAnimation: true, + percyCSS: '.global { color: blue }\n.percy-screenshot: { color: red }', + ignoreRegionSelectors: ['.selector-global'], + ignoreRegionXPaths: ['/xpath-per-screenshot'], + considerRegionXPaths: ['/xpath-global', '/xpath-per-screenshot'] + } + })); - // }) expect(percy.upload).toHaveBeenCalledOnceWith(mockWebdriverUtilResponse); await expectAsync(test).toBePending(); resolve(); // no hanging promises diff --git a/packages/webdriver-utils/src/index.js b/packages/webdriver-utils/src/index.js index f2b9d63c1..7f20b2415 100644 --- a/packages/webdriver-utils/src/index.js +++ b/packages/webdriver-utils/src/index.js @@ -2,45 +2,32 @@ import ProviderResolver from './providers/providerResolver.js'; import utils from '@percy/sdk-utils'; export default class WebdriverUtils { - log = utils.logger('webdriver-utils:main'); - constructor( - { - sessionId, - commandExecutorUrl, - capabilities, - sessionCapabilites, - snapshotName, - clientInfo, - environmentInfo, - options = {}, - buildInfo = {} - }) { - this.sessionId = sessionId; - this.commandExecutorUrl = commandExecutorUrl; - this.capabilities = capabilities; - this.sessionCapabilites = sessionCapabilites; - this.snapshotName = snapshotName; - this.options = options; - this.clientInfo = clientInfo; - this.environmentInfo = environmentInfo; - this.buildInfo = buildInfo; - } - - async automateScreenshot() { + static async automateScreenshot({ + sessionId, + commandExecutorUrl, + capabilities, + sessionCapabilites, + snapshotName, + clientInfo, + environmentInfo, + options = {}, + buildInfo = {} + }) { + const log = utils.logger('webdriver-utils:automateScreenshot'); try { const startTime = Date.now(); - 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 ...`); + 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(); - this.log.debug(`[${this.snapshotName}] : Created driver ...`); - const comparisonData = await automate.screenshot(this.snapshotName, this.options); + log.debug(`[${snapshotName}] : Created driver ...`); + const comparisonData = await automate.screenshot(snapshotName, options); comparisonData.metadata.cliScreenshotStartTime = startTime; comparisonData.metadata.cliScreenshotEndTime = Date.now(); return comparisonData; } catch (e) { - this.log.error(`[${this.snapshotName}] : Error - ${e.message}`); - this.log.error(`[${this.snapshotName}] : Error Log - ${e.toString()}`); + log.error(`[${snapshotName}] : Error - ${e.message}`); + log.error(`[${snapshotName}] : Error Log - ${e.toString()}`); } } } From 06a3b7a7491e5a626c1aabcfd32b1b3a2b62caac Mon Sep 17 00:00:00 2001 From: Jigar Wala Date: Thu, 14 Sep 2023 18:06:17 +0530 Subject: [PATCH 9/9] refactor: remove return --- packages/core/src/utils.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/core/src/utils.js b/packages/core/src/utils.js index 34a8838bf..6e055a71a 100644 --- a/packages/core/src/utils.js +++ b/packages/core/src/utils.js @@ -56,8 +56,6 @@ export function percyAutomateRequestHandler(req, percy) { } }); req.body.buildInfo = percy.build; - // returning for testing purpose. - return req; } // Creates a local resource object containing the resource URL, mimetype, content, sha, and any