Skip to content

Commit

Permalink
Merge branch 'master' into issue-1486-breaking
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Nov 20, 2020
2 parents f2da0ee + c00fce3 commit 545a6e6
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 3 deletions.
2 changes: 1 addition & 1 deletion readme.md
Expand Up @@ -519,7 +519,7 @@ Delays between retries counts with function `1000 * Math.pow(2, retry - 1) + Mat

The `calculateDelay` property is a `function` that receives an object with `attemptCount`, `retryOptions`, `error` and `computedValue` properties for current retry count, the retry options, error and default computed value. The function must return a delay in milliseconds (or a Promise resolving with it) (`0` return value cancels retry).

**Note:** The `calculateDelay` function is responsible for the entire cache mechanism, including the `limit` property. To support it, you need to check whether `computedValue` is different than `0`.
**Note:** The `calculateDelay` function is responsible for the entire retry mechanism, including the `limit` property. To support the `limit` property, you need to check whether `computedValue` is different than `0`.

By default, it retries *only* on the specified methods, status codes, and on these network errors:
- `ETIMEDOUT`: One of the [timeout](#timeout) limits were reached.
Expand Down
8 changes: 6 additions & 2 deletions source/core/index.ts
Expand Up @@ -31,7 +31,7 @@ import normalizePromiseArguments from '../as-promise/normalize-arguments';
import {PromiseOnly} from '../as-promise/types';
import calculateRetryDelay from './calculate-retry-delay';

const globalDnsCache = new CacheableLookup();
let globalDnsCache: CacheableLookup;

type HttpRequestFunction = typeof httpRequest;
type Error = NodeJS.ErrnoException;
Expand Down Expand Up @@ -1218,7 +1218,7 @@ export class RequestError extends Error {
this.timings = this.request?.timings;

// Recover the original stacktrace
if (!is.undefined(error.stack)) {
if (is.string(error.stack) && is.string(this.stack)) {
const indexOfMessage = this.stack.indexOf(this.message) + this.message.length;
const thisStackTrace = this.stack.slice(indexOfMessage).split('\n').reverse();
const errorStackTrace = error.stack.slice(error.stack.indexOf(error.message!) + error.message!.length).split('\n').reverse();
Expand Down Expand Up @@ -1758,6 +1758,10 @@ export default class Request extends Duplex implements RequestEvents<Request> {

// `options.dnsCache`
if (options.dnsCache === true) {
if (!globalDnsCache) {
globalDnsCache = new CacheableLookup();
}

options.dnsCache = globalDnsCache;
} else if (!is.undefined(options.dnsCache) && !options.dnsCache.lookup) {
throw new TypeError(`Parameter \`dnsCache\` must be a CacheableLookup instance or a boolean, got ${is(options.dnsCache)}`);
Expand Down
69 changes: 69 additions & 0 deletions test/error.ts
Expand Up @@ -3,6 +3,8 @@ import net = require('net');
import http = require('http');
import stream = require('stream');
import test from 'ava';
import getStream = require('get-stream');
import is from '@sindresorhus/is';
import got, {RequestError, HTTPError, TimeoutError} from '../source';
import withServer from './helpers/with-server';

Expand Down Expand Up @@ -261,3 +263,70 @@ test.skip('the old stacktrace is recovered', async t => {
// the second `at get` points to the real cause.
t.not(error.stack!.indexOf('at get'), error.stack!.lastIndexOf('at get'));
});

test.serial('custom stack trace', withServer, async (t, _server, got) => {
const ErrorCaptureStackTrace = Error.captureStackTrace;

const enable = () => {
Error.captureStackTrace = (target: {stack: any}) => {
target.stack = [
'line 1',
'line 2'
];
};
};

const disable = () => {
Error.captureStackTrace = ErrorCaptureStackTrace;
};

// Node.js default behavior
{
const stream = got.stream('');
stream.destroy(new Error('oh no'));

const caught = await t.throwsAsync(getStream(stream));
t.is(is(caught.stack), 'string');
}

// Passing a custom error
{
enable();
const error = new Error('oh no');
disable();

const stream = got.stream('');
stream.destroy(error);

const caught = await t.throwsAsync(getStream(stream));
t.is(is(caught.stack), 'string');
}

// Custom global behavior
{
enable();
const error = new Error('oh no');

const stream = got.stream('');
stream.destroy(error);

const caught = await t.throwsAsync(getStream(stream));
t.is(is(caught.stack), 'Array');

disable();
}

// Passing a default error that needs some processing
{
const error = new Error('oh no');
enable();

const stream = got.stream('');
stream.destroy(error);

const caught = await t.throwsAsync(getStream(stream));
t.is(is(caught.stack), 'Array');

disable();
}
});

0 comments on commit 545a6e6

Please sign in to comment.