diff --git a/packages/core/src/config.js b/packages/core/src/config.js index 4590b65dd..ed7a3bf67 100644 --- a/packages/core/src/config.js +++ b/packages/core/src/config.js @@ -285,7 +285,8 @@ export const snapshotSchema = { captureMockedServiceWorker: { $ref: '/config/discovery#/properties/captureMockedServiceWorker' }, captureSrcset: { $ref: '/config/discovery#/properties/captureSrcset' }, userAgent: { $ref: '/config/discovery#/properties/userAgent' }, - devicePixelRatio: { $ref: '/config/discovery#/properties/devicePixelRatio' } + devicePixelRatio: { $ref: '/config/discovery#/properties/devicePixelRatio' }, + retry: { $ref: '/config/discovery#/properties/retry' } } } }, diff --git a/packages/core/src/discovery.js b/packages/core/src/discovery.js index 73b7fa9bd..fab06ea6f 100644 --- a/packages/core/src/discovery.js +++ b/packages/core/src/discovery.js @@ -267,7 +267,7 @@ export const RESOURCE_CACHE_KEY = Symbol('resource-cache'); // Creates an asset discovery queue that uses the percy browser instance to create a page for each // snapshot which is used to intercept and capture snapshot resource requests. export function createDiscoveryQueue(percy) { - let { concurrency, retry } = percy.config.discovery; + let { concurrency } = percy.config.discovery; let queue = new Queue('discovery'); let cache; @@ -336,7 +336,7 @@ export function createDiscoveryQueue(percy) { await page.close(); } }, { - count: retry ? 3 : 1, + count: snapshot.discovery.retry ? 3 : 1, onRetry: () => { percy.log.info(`Retrying snapshot: ${snapshotLogName(snapshot.name, snapshot.meta)}`, snapshot.meta); }, diff --git a/packages/core/src/snapshot.js b/packages/core/src/snapshot.js index 1f6ffecd8..49e1ea6f2 100644 --- a/packages/core/src/snapshot.js +++ b/packages/core/src/snapshot.js @@ -118,7 +118,8 @@ function getSnapshotOptions(options, { config, meta }) { disableCache: config.discovery.disableCache, captureMockedServiceWorker: config.discovery.captureMockedServiceWorker, captureSrcset: config.discovery.captureSrcset, - userAgent: config.discovery.userAgent + userAgent: config.discovery.userAgent, + retry: config.discovery.retry } }, options], (path, prev, next) => { switch (path.map(k => k.toString()).join('.')) { diff --git a/packages/core/test/discovery.test.js b/packages/core/test/discovery.test.js index d6c9be137..6c7b2304a 100644 --- a/packages/core/test/discovery.test.js +++ b/packages/core/test/discovery.test.js @@ -912,6 +912,74 @@ describe('Discovery', () => { }); }); + describe('discovery retry', () => { + let Page; + let fastCount; + + beforeEach(async () => { + // reset page timeout so that it gets read from env again + ({ Page } = await import('../src/page.js')); + Page.TIMEOUT = undefined; + process.env.PERCY_PAGE_LOAD_TIMEOUT = 500; + + // some async request that takes a while and only resolves 4th time + let counter = 0; + server.reply('/', () => new Promise(r => ( + (counter += 1) && + setTimeout(r, counter === fastCount ? 0 : 2000, [200, 'text/html', ''])))); + }); + + afterAll(() => { + delete process.env.PERCY_PAGE_LOAD_TIMEOUT; + }); + + it('should retry the snapshot discovery upto 3 times', async () => { + // 3rd request will resolve instantly + fastCount = 3; + + await percy.snapshot({ + name: 'test navigation timeout', + url: 'http://localhost:8000', + discovery: { retry: true }, + widths: [400, 800] + }); + + await percy.idle(); + + expect(logger.stdout).toEqual([ + '[percy] Percy has started!', + '[percy] Retrying snapshot: test navigation timeout', + '[percy] Retrying snapshot: test navigation timeout', + '[percy] Snapshot taken: test navigation timeout' + ]); + }); + + it('throws exception after last retry', async () => { + // 3rd request will also resolve in delayed fashion + fastCount = 4; + + await percy.snapshot({ + name: 'test navigation timeout', + url: 'http://localhost:8000', + discovery: { retry: true }, + widths: [400, 800] + }); + + await percy.idle(); + + expect(logger.stdout).toEqual([ + '[percy] Percy has started!', + '[percy] Retrying snapshot: test navigation timeout', + '[percy] Retrying snapshot: test navigation timeout' + ]); + + expect(logger.stderr).toEqual([ + '[percy] Encountered an error taking snapshot: test navigation timeout', + '[percy] Error: Navigation failed: Timed out waiting for the page load event' + ]); + }); + }); + describe('navigation timeout', () => { let Page;