thenavisapp
Version:
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
1,394 lines (1,201 loc) • 28 kB
text/typescript
import {Buffer} from 'node:buffer';
import {Agent as HttpAgent} from 'node:http';
import test from 'ava';
import nock from 'nock';
import getStream from 'get-stream';
import FormData from 'form-data';
import sinon from 'sinon';
import delay from 'delay';
import type {Handler} from 'express';
import Responselike from 'responselike';
import type {Constructor} from 'type-fest';
import got, {RequestError, HTTPError, type Response, type OptionsInit} from '../source/index.js';
import withServer from './helpers/with-server.js';
const errorString = 'oops';
const error = new Error(errorString);
const echoHeaders: Handler = (request, response) => {
response.end(JSON.stringify(request.headers));
};
const echoBody: Handler = async (request, response) => {
response.end(await getStream(request));
};
const echoUrl: Handler = (request, response) => {
response.end(request.url);
};
const retryEndpoint: Handler = (request, response) => {
if (request.headers.foo) {
response.statusCode = 302;
response.setHeader('location', '/');
response.end();
}
response.statusCode = 500;
response.end();
};
const redirectEndpoint: Handler = (_request, response) => {
response.statusCode = 302;
response.setHeader('location', '/');
response.end();
};
const createAgentSpy = <T extends HttpAgent>(AgentClass: Constructor<any>): {agent: T; spy: sinon.SinonSpy} => {
const agent: T = new AgentClass({keepAlive: true});
// eslint-disable-next-line import/no-named-as-default-member
const spy = sinon.spy(agent, 'addRequest' as any);
return {agent, spy};
};
test('async hooks', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
const {body} = await got<Record<string, string>>({
responseType: 'json',
hooks: {
beforeRequest: [
async options => {
await delay(100);
options.headers.foo = 'bar';
},
],
},
});
t.is(body.foo, 'bar');
});
test('catches init thrown errors', async t => {
await t.throwsAsync(got('https://example.com', {
hooks: {
init: [() => {
throw error;
}],
},
}), {
instanceOf: RequestError,
message: errorString,
});
});
test('passes init thrown errors to beforeError hooks (promise-only)', async t => {
t.plan(1);
await t.throwsAsync(got('https://example.com', {
hooks: {
init: [() => {
throw error;
}],
beforeError: [error => {
t.is(error.message, errorString);
return error;
}],
},
}), {
instanceOf: RequestError,
message: errorString,
});
});
test('catches beforeRequest thrown errors', async t => {
await t.throwsAsync(got('https://example.com', {
hooks: {
beforeRequest: [() => {
throw error;
}],
},
}), {
instanceOf: RequestError,
message: errorString,
});
});
test('catches beforeRedirect thrown errors', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
server.get('/redirect', redirectEndpoint);
await t.throwsAsync(got('redirect', {
hooks: {
beforeRedirect: [() => {
throw error;
}],
},
}), {
instanceOf: RequestError,
message: errorString,
});
});
test('catches beforeRetry thrown errors', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
server.get('/retry', retryEndpoint);
await t.throwsAsync(got('retry', {
hooks: {
beforeRetry: [() => {
throw error;
}],
},
}), {
instanceOf: RequestError,
message: errorString,
});
});
test('throws if afterResponse returns an invalid value', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
await t.throwsAsync(got('', {
hooks: {
afterResponse: [
// @ts-expect-error Testing purposes
() => {},
],
},
}), {
message: 'The `afterResponse` hook returned an invalid value',
});
});
test('catches afterResponse thrown errors', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
await t.throwsAsync(got({
hooks: {
afterResponse: [() => {
throw error;
}],
},
}), {
instanceOf: RequestError,
message: errorString,
});
});
test('accepts an async function as init hook', async t => {
await got('https://example.com', {
hooks: {
init: [
async () => {
t.pass();
},
],
},
});
});
test('catches beforeRequest promise rejections', async t => {
await t.throwsAsync(got('https://example.com', {
hooks: {
beforeRequest: [
async () => {
throw error;
},
],
},
}), {
instanceOf: RequestError,
message: errorString,
});
});
test('catches beforeRedirect promise rejections', withServer, async (t, server, got) => {
server.get('/', redirectEndpoint);
await t.throwsAsync(got({
hooks: {
beforeRedirect: [
async () => {
throw error;
},
],
},
}), {
instanceOf: RequestError,
message: errorString,
});
});
test('catches beforeRetry promise rejections', withServer, async (t, server, got) => {
server.get('/retry', retryEndpoint);
await t.throwsAsync(got('retry', {
hooks: {
beforeRetry: [
async () => {
throw error;
},
],
},
}), {
instanceOf: RequestError,
message: errorString,
});
});
test('catches afterResponse promise rejections', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
await t.throwsAsync(got({
hooks: {
afterResponse: [
async () => {
throw error;
},
],
},
}), {message: errorString});
});
test('catches beforeError errors', async t => {
await t.throwsAsync(got('https://example.com', {
request() {
throw new Error('No way');
},
hooks: {
beforeError: [
async () => {
throw error;
},
],
},
}), {message: errorString});
});
test('init is called with options', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
const context = {};
await got({
hooks: {
init: [
options => {
t.deepEqual(options.context, context);
},
],
},
context,
});
});
test('init from defaults is called with options', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
const context = {};
let count = 0;
const instance = got.extend({
hooks: {
init: [
options => {
count += options.context ? 1 : 0;
},
],
},
});
await instance({context});
t.is(count, 1);
});
test('init allows modifications', withServer, async (t, server, got) => {
server.get('/', (request, response) => {
response.end(request.headers.foo);
});
const options = {
headers: {},
hooks: {
init: [
(options: OptionsInit) => {
options.headers = {
foo: 'bar',
};
},
],
},
};
const {body} = await got('', options);
t.deepEqual(options.headers, {});
t.is(body, 'bar');
});
test('beforeRequest is called with options', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
await got({
responseType: 'json',
hooks: {
beforeRequest: [
options => {
const url = options.url as URL;
t.is(url.pathname, '/');
t.is(url.hostname, 'localhost');
},
],
},
});
});
test('beforeRequest allows modifications', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
const {body} = await got<Record<string, string>>({
responseType: 'json',
hooks: {
beforeRequest: [
options => {
options.headers.foo = 'bar';
},
],
},
});
t.is(body.foo, 'bar');
});
test('returning HTTP response from a beforeRequest hook', withServer, async (t, server, got) => {
server.get('/', echoUrl);
const {statusCode, headers, body} = await got({
hooks: {
beforeRequest: [
() => new Responselike({
statusCode: 200,
headers: {
foo: 'bar',
},
body: Buffer.from('Hi!'),
url: '',
}),
],
},
});
t.is(statusCode, 200);
t.is(headers.foo, 'bar');
t.is(body, 'Hi!');
});
test('beforeRedirect is called with options and response', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
server.get('/redirect', redirectEndpoint);
await got('redirect', {
responseType: 'json',
hooks: {
beforeRedirect: [
(options, response) => {
const url = options.url as URL;
t.is(url.pathname, '/');
t.is(url.hostname, 'localhost');
t.is(response.statusCode, 302);
t.is(new URL(response.url).pathname, '/redirect');
t.is(response.redirectUrls.length, 1);
},
],
},
});
});
test('beforeRedirect allows modifications', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
server.get('/redirect', redirectEndpoint);
const {body} = await got<Record<string, string>>('redirect', {
responseType: 'json',
hooks: {
beforeRedirect: [
options => {
options.headers.foo = 'bar';
},
],
},
});
t.is(body.foo, 'bar');
});
test('beforeRetry is called with options', withServer, async (t, server) => {
server.get('/', echoHeaders);
server.get('/retry', retryEndpoint);
const context = {};
await got('retry', {
prefixUrl: server.url,
responseType: 'json',
retry: {
limit: 1,
},
throwHttpErrors: false,
context,
hooks: {
beforeRetry: [
(error, retryCount) => {
const {options} = error;
const {retryCount: requestRetryCount} = error.request!;
t.is((options.url as URL).hostname, 'localhost');
t.deepEqual(options.context, context);
t.truthy(error);
t.is(requestRetryCount, 0);
t.is(retryCount, 1);
},
],
},
});
});
test('beforeRetry allows modifications', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
server.get('/retry', retryEndpoint);
const {body} = await got<Record<string, string>>('retry', {
responseType: 'json',
hooks: {
beforeRetry: [
({options}) => {
options.headers.foo = 'bar';
},
],
},
});
t.is(body.foo, 'bar');
});
test('beforeRetry allows stream body if different from original', withServer, async (t, server, got) => {
server.post('/retry', async (request, response) => {
if (request.headers.foo) {
response.send('test');
} else {
response.statusCode = 500;
}
response.end();
});
const generateBody = () => {
const form = new FormData();
form.append('A', 'B');
return form;
};
const {body} = await got.post('retry', {
body: generateBody(),
retry: {
methods: ['POST'],
},
hooks: {
beforeRetry: [
({options}) => {
const form = generateBody();
options.body = form;
options.headers['content-type'] = `multipart/form-data; boundary=${form.getBoundary()}`;
options.headers.foo = 'bar';
},
],
},
});
t.is(body, 'test');
});
test('afterResponse is called with response', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
await got({
responseType: 'json',
hooks: {
afterResponse: [
response => {
t.is(typeof response.body, 'object');
return response;
},
],
},
});
});
test('afterResponse allows modifications', withServer, async (t, server, got) => {
server.get('/', echoHeaders);
const {body} = await got<Record<string, string>>({
responseType: 'json',
hooks: {
afterResponse: [
response => {
response.body = {hello: 'world'};
return response;
},
],
},
});
t.is(body.hello, 'world');
});
test('afterResponse allows to retry', withServer, async (t, server, got) => {
server.get('/', (request, response) => {
if (request.headers.token !== 'unicorn') {
response.statusCode = 401;
}
response.end();
});
const {statusCode} = await got({
hooks: {
afterResponse: [
(response, retryWithMergedOptions) => {
if (response.statusCode === 401) {
return retryWithMergedOptions({
headers: {
token: 'unicorn',
},
});
}
return response;
},
],
},
});
t.is(statusCode, 200);
});
test('afterResponse allows to retry without losing the port', withServer, async (t, server) => {
server.get('/', (request, response) => {
if (request.headers.token !== 'unicorn') {
response.statusCode = 401;
}
response.end();
});
const {statusCode} = await got({
url: server.url,
hooks: {
afterResponse: [
(response, retryWithMergedOptions) => {
if (response.statusCode === 401) {
return retryWithMergedOptions({
headers: {
token: 'unicorn',
},
});
}
return response;
},
],
},
});
t.is(statusCode, 200);
});
test('cancelling the request after retrying in a afterResponse hook', withServer, async (t, server, got) => {
let requests = 0;
server.get('/', (_request, response) => {
requests++;
response.end();
});
const gotPromise = got({
hooks: {
afterResponse: [
(_response, retryWithMergedOptions) => {
const promise = retryWithMergedOptions({
headers: {
token: 'unicorn',
},
});
gotPromise.cancel();
return promise;
},
],
},
retry: {
calculateDelay: () => 1,
},
});
await t.throwsAsync(gotPromise);
await delay(100);
t.is(requests, 1);
});
test('afterResponse allows to retry - `beforeRetry` hook', withServer, async (t, server, got) => {
server.get('/', (request, response) => {
if (request.headers.token !== 'unicorn') {
response.statusCode = 401;
}
response.end();
});
let isCalled = false;
const {statusCode} = await got({
hooks: {
afterResponse: [
(response, retryWithMergedOptions) => {
if (response.statusCode === 401) {
return retryWithMergedOptions({
headers: {
token: 'unicorn',
},
});
}
return response;
},
],
beforeRetry: [
options => {
t.truthy(options);
isCalled = true;
},
],
},
});
t.is(statusCode, 200);
t.true(isCalled);
});
test('no infinity loop when retrying on afterResponse', withServer, async (t, server, got) => {
server.get('/', (request, response) => {
if (request.headers.token !== 'unicorn') {
response.statusCode = 401;
}
response.end();
});
await t.throwsAsync(got({
retry: {
limit: 0,
},
hooks: {
afterResponse: [
(_response, retryWithMergedOptions) => retryWithMergedOptions({
headers: {
token: 'invalid',
},
}),
],
},
}), {instanceOf: HTTPError, message: 'Response code 401 (Unauthorized)'});
});
test('throws on afterResponse retry failure', withServer, async (t, server, got) => {
let didVisit401then500: boolean;
server.get('/', (_request, response) => {
if (didVisit401then500) {
response.statusCode = 500;
} else {
didVisit401then500 = true;
response.statusCode = 401;
}
response.end();
});
await t.throwsAsync(got({
retry: {
limit: 1,
},
hooks: {
afterResponse: [
(response, retryWithMergedOptions) => {
if (response.statusCode === 401) {
return retryWithMergedOptions({
headers: {
token: 'unicorn',
},
});
}
return response;
},
],
},
}), {instanceOf: HTTPError, message: 'Response code 500 (Internal Server Error)'});
});
test('does not throw on afterResponse retry HTTP failure if throwHttpErrors is false', withServer, async (t, server, got) => {
let didVisit401then500: boolean;
server.get('/', (_request, response) => {
if (didVisit401then500) {
response.statusCode = 500;
} else {
didVisit401then500 = true;
response.statusCode = 401;
}
response.end();
});
const {statusCode} = await got({
throwHttpErrors: false,
retry: {
limit: 1,
},
hooks: {
afterResponse: [
(response, retryWithMergedOptions) => {
if (response.statusCode === 401) {
return retryWithMergedOptions({
headers: {
token: 'unicorn',
},
});
}
return response;
},
],
},
});
t.is(statusCode, 500);
});
test('throwing in a beforeError hook - promise', withServer, async (t, server, got) => {
server.get('/', (_request, response) => {
response.end('ok');
});
await t.throwsAsync(got({
hooks: {
afterResponse: [
() => {
throw error;
},
],
beforeError: [
(): never => {
throw new Error('foobar');
},
() => {
throw new Error('This shouldn\'t be called at all');
},
],
},
}), {message: 'foobar'});
});
test('throwing in a beforeError hook - stream', withServer, async (t, _server, got) => {
await t.throwsAsync(getStream(got.stream({
hooks: {
beforeError: [
() => {
throw new Error('foobar');
},
() => {
throw new Error('This shouldn\'t be called at all');
},
],
},
})), {message: 'foobar'});
});
test('beforeError is called with an error - promise', withServer, async (t, server, got) => {
server.get('/', (_request, response) => {
response.end('ok');
});
await t.throwsAsync(got({
hooks: {
afterResponse: [
() => {
throw error;
},
],
beforeError: [error2 => {
t.true(error2 instanceof Error);
return error2;
}],
},
}), {message: errorString});
});
test('beforeError is called with an error - stream', withServer, async (t, _server, got) => {
await t.throwsAsync(getStream(got.stream({
hooks: {
beforeError: [error2 => {
t.true(error2 instanceof Error);
return error2;
}],
},
})), {message: 'Response code 404 (Not Found)'});
});
test('beforeError allows modifications', async t => {
const errorString2 = 'foobar';
await t.throwsAsync(got('https://example.com', {
request() {
throw error;
},
hooks: {
beforeError: [
error => {
const newError = new Error(errorString2);
return new RequestError(newError.message, newError, error.options);
},
],
},
}), {message: errorString2});
});
test('does not break on `afterResponse` hook with JSON mode', withServer, async (t, server, got) => {
server.get('/foobar', echoHeaders);
await t.notThrowsAsync(got('', {
hooks: {
afterResponse: [
(response, retryWithMergedOptions) => {
if (response.statusCode === 404) {
return retryWithMergedOptions({
url: new URL('/foobar', response.url),
});
}
return response;
},
],
},
responseType: 'json',
}));
});
test('catches HTTPErrors', withServer, async (t, _server, got) => {
t.plan(2);
await t.throwsAsync(got({
hooks: {
beforeError: [
error => {
t.true(error instanceof HTTPError);
return error;
},
],
},
}));
});
test('timeout can be modified using a hook', withServer, async (t, server, got) => {
server.get('/', () => {});
await t.throwsAsync(got({
timeout: {
request: 1000,
},
hooks: {
beforeRequest: [
options => {
options.timeout.request = 500;
},
],
},
retry: {
limit: 1,
},
}), {message: 'Timeout awaiting \'request\' for 500ms'});
});
test('beforeRequest hook is called before each request', withServer, async (t, server, got) => {
server.post('/', echoUrl);
server.post('/redirect', redirectEndpoint);
const buffer = Buffer.from('Hello, Got!');
let counts = 0;
await got.post('redirect', {
body: buffer,
hooks: {
beforeRequest: [
options => {
counts++;
t.is(options.headers['content-length'], String(buffer.length));
},
],
},
});
t.is(counts, 2);
});
test('beforeError emits valid promise `HTTPError`s', async t => {
t.plan(3);
nock('https://ValidHTTPErrors.com').get('/').reply(() => [422, 'no']);
const instance = got.extend({
hooks: {
beforeError: [
error => {
t.true(error instanceof HTTPError);
t.truthy(error.response!.body);
return error;
},
],
},
retry: {
limit: 0,
},
});
await t.throwsAsync(instance('https://ValidHTTPErrors.com'));
});
test('hooks are not duplicated', withServer, async (t, _server, got) => {
let calls = 0;
await t.throwsAsync(got({
hooks: {
beforeError: [
error => {
calls++;
return error;
},
],
},
retry: {
limit: 0,
},
}), {message: 'Response code 404 (Not Found)'});
t.is(calls, 1);
});
test('async afterResponse allows to retry with allowGetBody and json payload', withServer, async (t, server, got) => {
server.get('/', (request, response) => {
if (request.headers.token !== 'unicorn') {
response.statusCode = 401;
}
response.end();
});
const {statusCode} = await got({
allowGetBody: true,
json: {hello: 'world'},
hooks: {
afterResponse: [
(response, retryWithMergedOptions) => {
if (response.statusCode === 401) {
return retryWithMergedOptions({headers: {token: 'unicorn'}});
}
return response;
},
],
},
retry: {
limit: 0,
},
throwHttpErrors: false,
});
t.is(statusCode, 200);
});
test('beforeRequest hook respect `agent` option', withServer, async (t, server, got) => {
server.get('/', (_request, response) => {
response.end('ok');
});
const {agent, spy} = createAgentSpy(HttpAgent);
t.truthy((await got({
hooks: {
beforeRequest: [
options => {
options.agent = {
http: agent,
};
},
],
},
})).body);
t.true(spy.calledOnce);
// Make sure to close all open sockets
agent.destroy();
});
test('beforeRequest hook respect `url` option', withServer, async (t, server, got) => {
server.get('/', (_request, response) => {
response.end('ko');
});
server.get('/changed', (_request, response) => {
response.end('ok');
});
t.is((await got(server.hostname, {
hooks: {
beforeRequest: [
options => {
options.url = new URL(`${server.url}/changed`);
},
],
},
})).body, 'ok');
});
test('no duplicate hook calls in single-page paginated requests', withServer, async (t, server, got) => {
server.get('/get', (_request, response) => {
response.end('i <3 koalas');
});
let beforeHookCount = 0;
let beforeHookCountAdditional = 0;
let afterHookCount = 0;
let afterHookCountAdditional = 0;
const hooks = {
beforeRequest: [
() => {
beforeHookCount++;
},
],
afterResponse: [
(response: any) => {
afterHookCount++;
return response;
},
],
};
// Test only one request
const instance = got.extend({
hooks,
pagination: {
paginate: () => false,
countLimit: 2009,
transform: response => [response],
},
});
await instance.paginate.all('get');
t.is(beforeHookCount, 1);
t.is(afterHookCount, 1);
await instance.paginate.all('get', {
hooks: {
beforeRequest: [
() => {
beforeHookCountAdditional++;
},
],
afterResponse: [
(response: any) => {
afterHookCountAdditional++;
return response;
},
],
},
});
t.is(beforeHookCount, 2);
t.is(afterHookCount, 2);
t.is(beforeHookCountAdditional, 1);
t.is(afterHookCountAdditional, 1);
await got.paginate.all('get', {
hooks,
pagination: {
paginate: () => false,
transform: response => [response],
},
});
t.is(beforeHookCount, 3);
t.is(afterHookCount, 3);
});
test('no duplicate hook calls in sequential paginated requests', withServer, async (t, server, got) => {
server.get('/get', (_request, response) => {
response.end('i <3 unicorns');
});
let requestNumber = 0;
let beforeHookCount = 0;
let afterHookCount = 0;
const hooks = {
beforeRequest: [
() => {
beforeHookCount++;
},
],
afterResponse: [
(response: any) => {
afterHookCount++;
return response;
},
],
};
// Test only two requests, one after another
const paginate = () => requestNumber++ === 0 ? {} : false;
const instance = got.extend({
hooks,
pagination: {
paginate,
countLimit: 2009,
transform: response => [response],
},
});
await instance.paginate.all('get');
t.is(beforeHookCount, 2);
t.is(afterHookCount, 2);
requestNumber = 0;
await got.paginate.all('get', {
hooks,
pagination: {
paginate,
transform: response => [response],
},
});
t.is(beforeHookCount, 4);
t.is(afterHookCount, 4);
});
test('intentional duplicate hooks in pagination with extended instance', withServer, async (t, server, got) => {
server.get('/get', (_request, response) => {
response.end('<3');
});
let beforeCount = 0; // Number of times the hooks from `extend` are called
let afterCount = 0;
let beforeCountAdditional = 0; // Number of times the added hooks are called
let afterCountAdditional = 0;
const beforeHook = () => {
beforeCount++;
};
const afterHook = (response: any) => {
afterCount++;
return response;
};
const instance = got.extend({
hooks: {
beforeRequest: [
beforeHook,
beforeHook,
],
afterResponse: [
afterHook,
afterHook,
],
},
pagination: {
paginate: () => false,
countLimit: 2009,
transform: response => [response],
},
});
// Add duplicate hooks when calling paginate
const beforeHookAdditional = () => {
beforeCountAdditional++;
};
const afterHookAdditional = (response: any) => {
afterCountAdditional++;
return response;
};
await instance.paginate.all('get', {
hooks: {
beforeRequest: [
beforeHook,
beforeHookAdditional,
beforeHookAdditional,
],
afterResponse: [
afterHook,
afterHookAdditional,
afterHookAdditional,
],
},
});
t.is(beforeCount, 3);
t.is(afterCount, 3);
t.is(beforeCountAdditional, 2);
t.is(afterCountAdditional, 2);
});
test('no duplicate hook calls when returning original request options', withServer, async (t, server, got) => {
server.get('/get', (_request, response) => {
response.end('i <3 unicorns');
});
let requestNumber = 0;
let beforeHookCount = 0;
let afterHookCount = 0;
const hooks = {
beforeRequest: [
() => {
beforeHookCount++;
},
],
afterResponse: [
(response: any) => {
afterHookCount++;
return response;
},
],
};
// Test only two requests, one after another
const paginate = ({response}: {response: Response}) => requestNumber++ === 0 ? response.request.options : false;
const instance = got.extend({
hooks,
pagination: {
paginate,
countLimit: 2009,
transform: response => [response],
},
});
await instance.paginate.all('get');
t.is(beforeHookCount, 2);
t.is(afterHookCount, 2);
requestNumber = 0;
await got.paginate.all('get', {
hooks,
pagination: {
paginate,
transform: response => [response],
},
});
t.is(beforeHookCount, 4);
t.is(afterHookCount, 4);
});
test('`beforeRequest` change body', withServer, async (t, server, got) => {
server.post('/', echoBody);
const response = await got.post({
json: {payload: 'old'},
hooks: {
beforeRequest: [
options => {
options.body = JSON.stringify({payload: 'new'});
options.headers['content-length'] = options.body.length.toString();
},
],
},
});
t.is(JSON.parse(response.body).payload, 'new');
});
test('can retry without an agent', withServer, async (t, server, got) => {
server.get('/', (_request, response) => {
response.statusCode = 408;
response.end();
});
let counter = 0;
class MyAgent extends HttpAgent {
createConnection(port: any, options: any, callback: any) {
counter++;
return (HttpAgent as any).prototype.createConnection.call(this, port, options, callback);
}
}
const {response} = (await t.throwsAsync<HTTPError>(got({
agent: {
http: new MyAgent(),
},
hooks: {
beforeRetry: [
error => {
error.options.agent.http = undefined;
},
],
},
retry: {
calculateDelay: ({computedValue}) => computedValue ? 1 : 0,
},
})))!;
t.is(response.retryCount, 2);
t.is(counter, 1);
});
test('does not throw on empty body when running afterResponse hooks', withServer, async (t, server, got) => {
server.get('/', (_request, response) => {
response.end();
});
await t.notThrowsAsync(got('', {
hooks: {
afterResponse: [
response => response,
],
},
}));
});
test('does not call beforeError hooks on falsy throwHttpErrors', withServer, async (t, server, got) => {
server.get('/', (_request, response) => {
response.statusCode = 404;
response.end();
});
let called = false;
await got('', {
throwHttpErrors: false,
hooks: {
beforeError: [
error => {
called = true;
return error;
},
],
},
});
t.false(called);
});