diff --git a/packages/playwright-core/src/server/fetch.ts b/packages/playwright-core/src/server/fetch.ts index af37d5a3fc..76054b33cc 100644 --- a/packages/playwright-core/src/server/fetch.ts +++ b/packages/playwright-core/src/server/fetch.ts @@ -201,7 +201,7 @@ export abstract class APIRequestContext extends SdkObject { setHeader(headers, 'content-length', String(postData.byteLength)); const controller = new ProgressController(metadata, this); const fetchResponse = await controller.run(progress => { - return this._sendRequestWithRetries(progress, requestUrl, options, postData); + return this._sendRequestWithRetries(progress, requestUrl, options, postData, params.maxRetries); }); const fetchUid = this._storeResponseBody(fetchResponse.body); this.fetchLog.set(fetchUid, controller.metadata.log); @@ -247,14 +247,16 @@ export abstract class APIRequestContext extends SdkObject { } } - private async _sendRequestWithRetries(progress: Progress, url: URL, options: SendRequestOptions, postData?: Buffer): Promise & { body: Buffer }>{ - const maxRetries = 5; + private async _sendRequestWithRetries(progress: Progress, url: URL, options: SendRequestOptions, postData?: Buffer, maxRetries?: number): Promise & { body: Buffer }>{ + maxRetries ??= 5; let backoff = 250; for (let i = 0; i <= maxRetries; i++) { try { return await this._sendRequest(progress, url, options, postData); } catch (e) { - if (i === maxRetries - 1 || (options.deadline && monotonicTime() + backoff > options.deadline)) + if (maxRetries === 0) + throw e; + if (i === maxRetries || (options.deadline && monotonicTime() + backoff > options.deadline)) throw new Error(`Failed after ${i + 1} attempt(s): ${e}`); // Retry on connection reset only. if (e.code !== 'ECONNRESET') diff --git a/tests/library/browsercontext-fetch.spec.ts b/tests/library/browsercontext-fetch.spec.ts index a8aaeb389f..2551c4fc21 100644 --- a/tests/library/browsercontext-fetch.spec.ts +++ b/tests/library/browsercontext-fetch.spec.ts @@ -59,7 +59,7 @@ it('should throw on network error', async ({ context, server }) => { server.setRoute('/test', (req, res) => { req.socket.destroy(); }); - const error = await context.request.get(server.PREFIX + '/test').catch(e => e); + const error = await context.request.get(server.PREFIX + '/test', { maxRetries: 0 }).catch(e => e); expect(error.message).toContain('apiRequestContext.get: socket hang up'); }); @@ -68,7 +68,7 @@ it('should throw on network error after redirect', async ({ context, server }) = server.setRoute('/test', (req, res) => { req.socket.destroy(); }); - const error = await context.request.get(server.PREFIX + '/redirect').catch(e => e); + const error = await context.request.get(server.PREFIX + '/redirect', { maxRetries: 0 }).catch(e => e); expect(error.message).toContain('apiRequestContext.get: socket hang up'); }); diff --git a/tests/library/global-fetch.spec.ts b/tests/library/global-fetch.spec.ts index e17f94b49d..b405f4d2b1 100644 --- a/tests/library/global-fetch.spec.ts +++ b/tests/library/global-fetch.spec.ts @@ -436,7 +436,7 @@ it('should throw an error when maxRedirects is less than 0', async ({ playwright const request = await playwright.request.newContext(); for (const method of ['GET', 'PUT', 'POST', 'OPTIONS', 'HEAD', 'PATCH']) - await expect(async () => request.fetch(`${server.PREFIX}/a/redirect1`, { method, maxRedirects: -1 })).rejects.toThrow(`'maxRedirects' should be greater than or equal to '0'`); + await expect(async () => request.fetch(`${server.PREFIX}/a/redirect1`, { method, maxRedirects: -1 })).rejects.toThrow(`'maxRedirects' must be greater than or equal to '0'`); await request.dispose(); });