Skip to content

Commit

Permalink
Adding waitForTimeout/waitForSelector for assets discovery browser wh…
Browse files Browse the repository at this point in the history
…en JS is enabled (#1715)
  • Loading branch information
amandeepsingh333 committed Sep 16, 2024
1 parent 4f97ecb commit 676420e
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 3 deletions.
10 changes: 10 additions & 0 deletions packages/core/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,14 @@ export const configSchema = {
maximum: 750,
minimum: 1
},
waitForSelector: {
type: 'string'
},
waitForTimeout: {
type: 'integer',
minimum: 1,
maximum: 30000
},
disableCache: {
type: 'boolean'
},
Expand Down Expand Up @@ -295,6 +303,8 @@ export const snapshotSchema = {
allowedHostnames: { $ref: '/config/discovery#/properties/allowedHostnames' },
disallowedHostnames: { $ref: '/config/discovery#/properties/disallowedHostnames' },
requestHeaders: { $ref: '/config/discovery#/properties/requestHeaders' },
waitForSelector: { $ref: '/config/discovery#/properties/waitForSelector' },
waitForTimeout: { $ref: '/config/discovery#/properties/waitForTimeout' },
authorization: { $ref: '/config/discovery#/properties/authorization' },
disableCache: { $ref: '/config/discovery#/properties/disableCache' },
captureMockedServiceWorker: { $ref: '/config/discovery#/properties/captureMockedServiceWorker' },
Expand Down
17 changes: 16 additions & 1 deletion packages/core/src/discovery.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logger from '@percy/logger';
import Queue from './queue.js';
import Page from './page.js';
import {
normalizeURL,
hostnameMatches,
Expand All @@ -9,7 +10,9 @@ import {
createLogResource,
yieldAll,
snapshotLogName,
withRetries
waitForTimeout,
withRetries,
waitForSelectorInsideBrowser
} from './utils.js';
import {
sha256hash
Expand Down Expand Up @@ -203,6 +206,18 @@ async function* captureSnapshotResources(page, snapshot, options) {
yield resizePage(snapshot.widths[0]);
yield page.goto(snapshot.url, { cookies });

// wait for any specified timeout
if (snapshot.discovery.waitForTimeout && page.enableJavaScript) {
log.debug(`Wait for ${snapshot.discovery.waitForTimeout}ms timeout`);
await waitForTimeout(snapshot.discovery.waitForTimeout);
}

// wait for any specified selector
if (snapshot.discovery.waitForSelector && page.enableJavaScript) {
log.debug(`Wait for selector: ${snapshot.discovery.waitForSelector}`);
await waitForSelectorInsideBrowser(page, snapshot.discovery.waitForSelector, Page.TIMEOUT);
}

if (snapshot.execute) {
// when any execute options are provided, inject snapshot options
/* istanbul ignore next: cannot detect coverage of injected code */
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ function getSnapshotOptions(options, { config, meta }) {
allowedHostnames: config.discovery.allowedHostnames,
disallowedHostnames: config.discovery.disallowedHostnames,
networkIdleTimeout: config.discovery.networkIdleTimeout,
waitForTimeout: config.discovery.waitForTimeout,
waitForSelector: config.discovery.waitForSelector,
devicePixelRatio: config.discovery.devicePixelRatio,
requestHeaders: config.discovery.requestHeaders,
authorization: config.discovery.authorization,
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,15 @@ async function waitForSelector(selector, timeout) {
}
}

// wait for a query selector to exist within an optional timeout inside browser
export async function waitForSelectorInsideBrowser(page, selector, timeout) {
try {
return page.eval(`await waitForSelector(${JSON.stringify(selector)}, ${timeout})`);
} catch {
throw new Error(`Unable to find: ${selector}`);
}
}

// Browser-specific util to wait for an xpath selector to exist within an optional timeout.
/* istanbul ignore next: tested, but coverage is stripped */
async function waitForXPath(selector, timeout) {
Expand Down
71 changes: 71 additions & 0 deletions packages/core/test/discovery.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2430,6 +2430,77 @@ describe('Discovery', () => {
});
});

describe('waitForSelector/waitForTimeout at the time of discovery when Js is enabled =>', () => {
it('calls waitForTimeout, waitForSelector and page.eval when their respective arguments are given', async () => {
const page = await percy.browser.page();
spyOn(percy.browser, 'page').and.returnValue(page);
spyOn(page, 'eval').and.callThrough();
percy.loglevel('debug');

await percy.snapshot({
name: 'test discovery',
url: 'http://localhost:8000',
enableJavaScript: true,
discovery: {
waitForTimeout: 100,
waitForSelector: 'body'
}
});
await percy.idle();

expect(page.eval).toHaveBeenCalledWith('await waitForSelector("body", 30000)');
expect(logger.stderr).toEqual(jasmine.arrayContaining([
'[percy:core:discovery] Wait for selector: body',
'[percy:core:discovery] Wait for 100ms timeout'
]));
});
});
describe('waitForSelector/waitForTimeout at the time of discovery when Js is disabled =>', () => {
it('donot calls waitForTimeout, waitForSelector and page.eval', async () => {
const page2 = await percy.browser.page();
spyOn(page2, 'eval').and.callThrough();
percy.loglevel('debug');

await percy.snapshot({
name: 'test discovery 2',
url: 'http://localhost:8000',
cliEnableJavaScript: false,
discovery: {
waitForTimeout: 100,
waitForSelector: 'flex'
}
});

await percy.idle();

expect(page2.eval).not.toHaveBeenCalledWith('await waitForSelector("flex", 30000)');
expect(logger.stderr).not.toEqual(jasmine.arrayContaining([
'[percy:core:discovery] Wait for 100ms timeout',
'[percy:core:discovery] Wait for selector: flex'
]));
});
it('when domSnapshot is present with default parameters waitForSelector/waitForTimeout are not called', async () => {
percy.loglevel('debug');

await percy.snapshot({
name: 'test discovery 3',
url: 'http://localhost:8000',
domSnapshot: testDOM,
discovery: {
waitForTimeout: 100,
waitForSelector: 'body'
}
});

await percy.idle();

expect(logger.stderr).not.toEqual(jasmine.arrayContaining([
'[percy:core:discovery] Wait for 100ms timeout',
'[percy:core:discovery] Wait for selector: body'
]));
});
});

describe('Capture image srcset =>', () => {
it('make request call to capture resource', async () => {
let responsiveDOM = dedent`
Expand Down
32 changes: 30 additions & 2 deletions packages/core/test/utils.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { decodeAndEncodeURLWithLogging } from '../src/utils.js';
import { logger } from './helpers/index.js';
import { decodeAndEncodeURLWithLogging, waitForSelectorInsideBrowser } from '../src/utils.js';
import { logger, setupTest } from './helpers/index.js';
import percyLogger from '@percy/logger';
import Percy from '@percy/core';

describe('utils', () => {
let log;
Expand Down Expand Up @@ -45,4 +46,31 @@ describe('utils', () => {
expect(logger.stderr).toEqual(['[percy] some Warning Message']);
});
});
describe('waitForSelectorInsideBrowser', () => {
it('waitForSelectorInsideBrowser should work when called with correct parameters', async () => {
await setupTest();
let percy = await Percy.start({
token: 'PERCY_TOKEN',
snapshot: { widths: [1000] },
discovery: { concurrency: 1 }
});
const page = await percy.browser.page();
spyOn(page, 'eval').and.callThrough();
waitForSelectorInsideBrowser(page, 'body', 30000);

expect(page.eval).toHaveBeenCalledWith('await waitForSelector("body", 30000)');
});
it('should handle errors when waitForSelectorInsideBrowser fails', async () => {
let error = null;
const expectedError = new Error('Unable to find: body');

try {
await waitForSelectorInsideBrowser(null, 'body', 30000);
} catch (e) {
error = e;
}

expect(error).toEqual(expectedError);
});
});
});

0 comments on commit 676420e

Please sign in to comment.