Skip to content

Commit

Permalink
Fix unhandled errors if throwing in an async handler
Browse files Browse the repository at this point in the history
  • Loading branch information
szmarczak committed Feb 8, 2020
1 parent 4f8c555 commit 518d95a
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 8 deletions.
2 changes: 1 addition & 1 deletion documentation/examples/gh-got.js
Expand Up @@ -2,7 +2,7 @@
const got = require('../..');
const package = require('../../package');

const getRateLimit = ({headers}) => ({
const getRateLimit = (headers) => ({
limit: parseInt(headers['x-ratelimit-limit'], 10),
remaining: parseInt(headers['x-ratelimit-remaining'], 10),
reset: new Date(parseInt(headers['x-ratelimit-reset'], 10) * 1000)
Expand Down
4 changes: 2 additions & 2 deletions documentation/lets-make-a-plugin.md
Expand Up @@ -161,7 +161,7 @@ Umm... `response.headers['x-ratelimit-remaining']` doesn't look good. What about
Yeah, definitely. Since `response.headers` is an object, we can easily parse these:

```js
const getRateLimit = ({headers}) => ({
const getRateLimit = (headers) => ({
limit: parseInt(headers['x-ratelimit-limit'], 10),
remaining: parseInt(headers['x-ratelimit-remaining'], 10),
reset: new Date(parseInt(headers['x-ratelimit-reset'], 10) * 1000)
Expand All @@ -182,7 +182,7 @@ getRateLimit({
Let's integrate it:

```js
const getRateLimit = ({headers}) => ({
const getRateLimit = (headers) => ({
limit: parseInt(headers['x-ratelimit-limit'], 10),
remaining: parseInt(headers['x-ratelimit-remaining'], 10),
reset: new Date(parseInt(headers['x-ratelimit-reset'], 10) * 1000)
Expand Down
15 changes: 12 additions & 3 deletions source/create.ts
Expand Up @@ -113,9 +113,18 @@ const create = (defaults: Defaults): Got => {
return root;
});

if (result !== root && !options.isStream) {
Object.setPrototypeOf(result, Object.getPrototypeOf(root));
Object.defineProperties(result, Object.getOwnPropertyDescriptors(root));
if (result !== root && !options.isStream && root) {
const typedResult = result as Promise<unknown>;

const {then: promiseThen, catch: promiseCatch, finally: promiseFianlly} = typedResult;
Object.setPrototypeOf(typedResult, Object.getPrototypeOf(root));
Object.defineProperties(typedResult, Object.getOwnPropertyDescriptors(root));

// These should point to the new promise
// eslint-disable-next-line promise/prefer-await-to-then
typedResult.then = promiseThen;
typedResult.catch = promiseCatch;
typedResult.finally = promiseFianlly;
}

return result;
Expand Down
4 changes: 2 additions & 2 deletions source/types.ts
Expand Up @@ -8,7 +8,7 @@ import {URL} from 'url';
import {Readable as ReadableStream} from 'stream';
import {Timings, IncomingMessageWithTimings} from '@szmarczak/http-timer';
import CacheableLookup from 'cacheable-lookup';
import {Except, Merge, Promisable} from 'type-fest';
import {Except, Merge} from 'type-fest';
import {GotReturn} from './create';
import {GotError, HTTPError, MaxRedirectsError, ParseError, TimeoutError, RequestError} from './errors';
import {Hooks} from './known-hook-events';
Expand Down Expand Up @@ -77,7 +77,7 @@ export interface RetryObject {

export type RetryFunction = (retryObject: RetryObject) => number;

export type HandlerFunction = <T extends GotReturn>(options: NormalizedOptions, next: (options: NormalizedOptions) => T) => Promisable<T>;
export type HandlerFunction = <T extends GotReturn>(options: NormalizedOptions, next: (options: NormalizedOptions) => T) => T | Promise<T>;

export interface DefaultRetryOptions {
limit: number;
Expand Down
14 changes: 14 additions & 0 deletions test/create.ts
Expand Up @@ -296,3 +296,17 @@ test('async handlers', withServer, async (t, server, got) => {
// @ts-ignore Manual tests
t.true((await promise).modified);
});

test('async handlers can throw', async t => {
const message = 'meh';

const instance = got.extend({
handlers: [
async () => {
throw new Error(message);
}
]
});

await t.throwsAsync(instance('https://example.com'), {message});
});

0 comments on commit 518d95a

Please sign in to comment.