Skip to content

Commit

Permalink
Fix shortcuts not throwing ParseErrors
Browse files Browse the repository at this point in the history
  • Loading branch information
szmarczak committed Apr 15, 2020
1 parent 5d69522 commit 4fd1006
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 20 deletions.
32 changes: 19 additions & 13 deletions source/as-promise/core.ts
Expand Up @@ -4,7 +4,9 @@ import {
Options,
NormalizedOptions,
Defaults,
ResponseType
ResponseType,
ParseError,
Response
} from './types';
import Request, {knownHookEvents, RequestError, Method} from '../core';

Expand All @@ -15,21 +17,25 @@ if (!knownHookEvents.includes('beforeRetry' as any)) {
export const knownBodyTypes = ['json', 'buffer', 'text'];

// @ts-ignore The error is: Not all code paths return a value.
export const parseBody = (body: Buffer, responseType: ResponseType, encoding?: string): unknown => {
if (responseType === 'text') {
return body.toString(encoding);
}
export const parseBody = (body: Buffer, response: Response, responseType: ResponseType, encoding?: string): unknown => {
try {
if (responseType === 'text') {
return body.toString(encoding);
}

if (responseType === 'json') {
return body.length === 0 ? '' : JSON.parse(body.toString()) as unknown;
}
if (responseType === 'json') {
return body.length === 0 ? '' : JSON.parse(body.toString()) as unknown;
}

if (responseType === 'buffer') {
return Buffer.from(body);
}
if (responseType === 'buffer') {
return Buffer.from(body);
}

if (!knownBodyTypes.includes(responseType)) {
throw new TypeError(`Unknown body type '${responseType as string}'`);
if (!knownBodyTypes.includes(responseType)) {
throw new TypeError(`Unknown body type '${responseType as string}'`);
}
} catch (error) {
throw new ParseError(error, response);
}
};

Expand Down
15 changes: 9 additions & 6 deletions source/as-promise/index.ts
Expand Up @@ -8,8 +8,7 @@ import {
Response,
RequestError,
HTTPError,
ReadError,
ParseError
ReadError
} from './types';
import PromisableRequest, {parseBody} from './core';
import proxyEvents from '../core/utils/proxy-events';
Expand All @@ -25,6 +24,7 @@ const proxiedRequestEvents = [
export default function asPromise<T>(options: NormalizedOptions): CancelableRequest<T> {
let retryCount = 0;
let body: Buffer;
let currentResponse: Response;
const emitter = new EventEmitter();

const promise = new PCancelable<T>((resolve, reject, onCancel) => {
Expand All @@ -49,6 +49,8 @@ export default function asPromise<T>(options: NormalizedOptions): CancelableRequ
onCancel(() => request.destroy());

request.once('response', async (response: Response) => {
currentResponse = response;

response.retryCount = retryCount;

if (response.request.aborted) {
Expand All @@ -73,14 +75,13 @@ export default function asPromise<T>(options: NormalizedOptions): CancelableRequ

// Parse body
try {
response.body = parseBody(body, options.responseType, options.encoding);
response.body = parseBody(body, response, options.responseType, options.encoding);
} catch (error) {
// Fallback to `utf8`
response.body = body.toString('utf8');

if (isOk()) {
const parseError = new ParseError(error, response, options);
request._beforeError(parseError);
request._beforeError(error);
return;
}
}
Expand Down Expand Up @@ -221,8 +222,10 @@ export default function asPromise<T>(options: NormalizedOptions): CancelableRequ

const shortcut = <T>(responseType: NormalizedOptions['responseType']): CancelableRequest<T> => {
const newPromise = (async () => {
// Wait until downloading has ended
await promise;
return parseBody(body, responseType);

return parseBody(body, currentResponse, responseType);
})();

Object.defineProperties(newPromise, Object.getOwnPropertyDescriptors(promise));
Expand Down
4 changes: 3 additions & 1 deletion source/as-promise/types.ts
Expand Up @@ -109,7 +109,9 @@ export interface Defaults extends RequestDefaults {
export class ParseError extends RequestError {
declare readonly response: Response;

constructor(error: Error, response: Response, options: NormalizedOptions) {
constructor(error: Error, response: Response) {
const {options} = response.request;

super(`${error.message} in "${options.url.toString()}"`, error, options);
this.name = 'ParseError';

Expand Down
11 changes: 11 additions & 0 deletions test/response-parse.ts
Expand Up @@ -171,3 +171,14 @@ test('.buffer() returns binary content', withServer, async (t, server, got) => {
const buffer = await got('').buffer();
t.is(Buffer.compare(buffer, body), 0);
});

test('shortcuts throw ParseErrors', withServer, async (t, server, got) => {
server.get('/', (_request, response) => {
response.end('not a json');
});

await t.throwsAsync(got('').json(), {
instanceOf: ParseError,
message: /^Unexpected token o in JSON at position 1 in/
});
});

0 comments on commit 4fd1006

Please sign in to comment.