Skip to content

Commit

Permalink
Added support for capturing asset in multiple dpr and width combinati…
Browse files Browse the repository at this point in the history
…on (#1536)

* Intial implementation

* Capture for passed widths

* Added support for image srcset capturing

* Added tests + addressed comments

* Fix breaking tests

* Capture responsive dom

* Fix logic

* Remove new flag and use existing + enableJS

* Added endpoint for deviceDetails + deprecate deviceScaleFactor

* Fix sdk-utils testcases

* Fix breaking test

* Add test for getDeviceDetails

* Added tests for captureResponsiveDom

* Fix edge case

* Add warning remove tests

* Fix tests

* Fix tests

* addressed comments

* Added new testcase

* handle for snapshot command
  • Loading branch information
chinmay-browserstack committed Mar 6, 2024
1 parent 0519aa0 commit 9009452
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 68 deletions.
3 changes: 2 additions & 1 deletion packages/cli-snapshot/src/snapshot.js
Expand Up @@ -48,7 +48,8 @@ export const snapshot = command('snapshot', {
],

percy: {
delayUploads: true
delayUploads: true,
projectType: 'web'
},

config: {
Expand Down
12 changes: 12 additions & 0 deletions packages/client/src/client.js
Expand Up @@ -217,6 +217,18 @@ export class PercyClient {
return this.get(`job_status?sync=true&type=${type}&id=${ids.join()}`);
}

// Returns device details enabled on project associated with given token
async getDeviceDetails(buildId) {
try {
let url = 'discovery/device-details';
if (buildId) url += `?build_id=${buildId}`;
const { data } = await this.get(url);
return data;
} catch (e) {
return [];
}
}

// Retrieves project builds optionally filtered. Requires a read access token.
async getBuilds(project, filters = {}) {
validateProjectPath(project);
Expand Down
14 changes: 14 additions & 0 deletions packages/client/test/client.test.js
Expand Up @@ -353,6 +353,20 @@ describe('PercyClient', () => {
});
});

describe('#getDeviceDetails()', () => {
it('in case of error return []', async () => {
api.reply('/discovery/device-details', () => [500]);
await expectAsync(client.getDeviceDetails()).toBeResolvedTo([]);
});

it('gets device details', async () => {
api.reply('/discovery/device-details', () => [200, { data: ['<<device-data-without-build-id>>'] }]);
api.reply('/discovery/device-details?build_id=123', () => [200, { data: ['<<device-data-with-build-id>>'] }]);
await expectAsync(client.getDeviceDetails()).toBeResolvedTo(['<<device-data-without-build-id>>']);
await expectAsync(client.getDeviceDetails(123)).toBeResolvedTo(['<<device-data-with-build-id>>']);
});
});

describe('#getBuilds()', () => {
it('throws when missing a project path', async () => {
await expectAsync(client.getBuilds())
Expand Down
6 changes: 6 additions & 0 deletions packages/client/test/helpers.js
Expand Up @@ -139,6 +139,12 @@ export const api = {
'/snapshots/4567?sync=true&response_format=sync-cli': () => [201, {
name: 'test snapshot',
diff_ratio: 0
}],
'/discovery/device-details?build_id=123': () => [201, {
data: []
}],
'/discovery/device-details': () => [201, {
data: []
}]
},

Expand Down
27 changes: 18 additions & 9 deletions packages/core/src/discovery.js
Expand Up @@ -141,8 +141,9 @@ function processSnapshotResources({ domSnapshot, resources, ...snapshot }) {
// Triggers the capture of resource requests for a page by iterating over snapshot widths to resize
// the page and calling any provided execute options.
async function* captureSnapshotResources(page, snapshot, options) {
const log = logger('core:discovery');
let { discovery, additionalSnapshots = [], ...baseSnapshot } = snapshot;
let { capture, captureWidths, deviceScaleFactor, mobile } = options;
let { capture, captureWidths, deviceScaleFactor, mobile, captureForDevices } = options;

// used to take snapshots and remove any discovered root resource
let takeSnapshot = async (options, width) => {
Expand Down Expand Up @@ -187,6 +188,18 @@ async function* captureSnapshotResources(page, snapshot, options) {
let { widths, execute } = snap;
let [width] = widths;

// iterate over device to trigger reqeusts and capture other dpr width
if (captureForDevices) {
for (const device of captureForDevices) {
yield waitForDiscoveryNetworkIdle(page, discovery);
// We are not adding these widths and pixels ratios in loop below because we want to explicitly reload the page after resize which we dont do below
yield* captureSnapshotResources(page, { ...snapshot, widths: [device.width] }, {
deviceScaleFactor: device.deviceScaleFactor,
mobile: true
});
}
}

// iterate over widths to trigger reqeusts and capture other widths
if (isBaseSnapshot || captureWidths) {
for (let i = 0; i < widths.length - 1; i++) {
Expand All @@ -212,13 +225,8 @@ async function* captureSnapshotResources(page, snapshot, options) {
}

// recursively trigger resource requests for any alternate device pixel ratio
if (deviceScaleFactor !== discovery.devicePixelRatio) {
yield waitForDiscoveryNetworkIdle(page, discovery);

yield* captureSnapshotResources(page, snapshot, {
deviceScaleFactor: discovery.devicePixelRatio,
mobile: true
});
if (discovery.devicePixelRatio) {
log.deprecated('discovery.devicePixelRatio is deprecated percy will now auto capture resource in all devicePixelRatio, Ignoring configuration');
}

// wait for final network idle when not capturing DOM
Expand Down Expand Up @@ -317,7 +325,8 @@ export function createDiscoveryQueue(percy) {
try {
yield* captureSnapshotResources(page, snapshot, {
captureWidths: !snapshot.domSnapshot && percy.deferUploads,
capture: callback
capture: callback,
captureForDevices: percy.deviceDetails || []
});
} finally {
// always close the page when done
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/percy.js
Expand Up @@ -157,6 +157,7 @@ export class Percy {
if (!this.skipDiscovery) yield this.#discovery.start();
// start a local API server for SDK communication
if (this.server) yield this.server.listen();
if (this.projectType === 'web') this.deviceDetails = yield this.client.getDeviceDetails(this.build?.id);
const snapshotType = this.projectType === 'web' ? 'snapshot' : 'comparison';
this.syncQueue = new WaitForJob(snapshotType, this);
// log and mark this instance as started
Expand Down

0 comments on commit 9009452

Please sign in to comment.