Skip to content

Commit 337a1af

Browse files
authored
feat(fetchOEmbedData): Handle non-ok responses (#104)
* fix(fetchOEmbedData): throw on non-ok response * adjust tests to use actual Response object instead of object approximation
1 parent da399e4 commit 337a1af

File tree

6 files changed

+49
-12
lines changed

6 files changed

+49
-12
lines changed

src/__tests__/transformers/GIPHY.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ import {
1111

1212
import { cache, getMarkdownASTForFile, parseASTToMarkdown } from '../helpers';
1313

14+
const { Response } = jest.requireActual('node-fetch');
1415
jest.mock('node-fetch', () => jest.fn());
1516

1617
const mockFetch = ({ height, width }) =>
17-
fetchMock.mockResolvedValue({
18-
json: () => Promise.resolve({ height, width }),
19-
});
18+
fetchMock.mockImplementation(() =>
19+
Promise.resolve(new Response(JSON.stringify({ height, width })))
20+
);
2021

2122
beforeEach(() => {
2223
fetchMock.mockClear();

src/__tests__/transformers/Instagram.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ import { getHTML, shouldTransform } from '../../transformers/Instagram';
66

77
import { cache, getMarkdownASTForFile, parseASTToMarkdown } from '../helpers';
88

9+
const { Response } = jest.requireActual('node-fetch');
910
jest.mock('node-fetch', () => jest.fn());
1011

1112
const mockFetch = html =>
12-
fetchMock.mockResolvedValue({ json: () => Promise.resolve({ html }) });
13+
fetchMock.mockImplementation(() =>
14+
Promise.resolve(new Response(JSON.stringify({ html })))
15+
);
1316

1417
beforeEach(() => {
1518
fetchMock.mockClear();

src/__tests__/transformers/Streamable.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ import {
1010

1111
import { cache, getMarkdownASTForFile, parseASTToMarkdown } from '../helpers';
1212

13+
const { Response } = jest.requireActual('node-fetch');
1314
jest.mock('node-fetch', () => jest.fn());
1415

1516
const mockFetch = html =>
16-
fetchMock.mockResolvedValue({ json: () => Promise.resolve({ html }) });
17+
fetchMock.mockImplementation(() =>
18+
Promise.resolve(new Response(JSON.stringify({ html })))
19+
);
1720

1821
beforeEach(() => {
1922
fetchMock.mockClear();

src/__tests__/transformers/Twitter.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@ import { getHTML, shouldTransform } from '../../transformers/Twitter';
66

77
import { cache, getMarkdownASTForFile, parseASTToMarkdown } from '../helpers';
88

9+
const { Response } = jest.requireActual('node-fetch');
910
jest.mock('node-fetch', () => jest.fn());
1011

1112
const mockFetch = (status, moment) =>
1213
fetchMock
13-
.mockResolvedValueOnce({ json: () => Promise.resolve({ html: status }) })
14-
.mockResolvedValueOnce({ json: () => Promise.resolve({ html: status }) })
15-
.mockResolvedValueOnce({ json: () => Promise.resolve({ html: moment }) })
16-
.mockResolvedValueOnce({ json: () => Promise.resolve({ html: moment }) })
17-
.mockResolvedValueOnce({ json: () => Promise.resolve({ html: moment }) })
18-
.mockResolvedValueOnce({ json: () => Promise.resolve({ html: moment }) });
14+
.mockResolvedValueOnce(new Response(JSON.stringify({ html: status })))
15+
.mockResolvedValueOnce(new Response(JSON.stringify({ html: status })))
16+
.mockResolvedValueOnce(new Response(JSON.stringify({ html: moment })))
17+
.mockResolvedValueOnce(new Response(JSON.stringify({ html: moment })))
18+
.mockResolvedValueOnce(new Response(JSON.stringify({ html: moment })))
19+
.mockResolvedValueOnce(new Response(JSON.stringify({ html: moment })));
1920

2021
beforeEach(() => {
2122
fetchMock.mockReset();

src/__tests__/transformers/utils/fetchOEmbedData.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,25 @@ describe(`fetchOEmbedData`, () => {
3434
});
3535
});
3636

37+
test(`throws on non-ok status`, () => {
38+
// make sure we make our result assertion
39+
expect.assertions(1);
40+
41+
fetch.mockResolvedValue(
42+
new Response(JSON.stringify(MockedResponseResult), {
43+
// non-ok status is one outside of 200-299 range
44+
// ( https://developer.mozilla.org/en-US/docs/Web/API/Response/ok )
45+
status: 403,
46+
})
47+
);
48+
49+
return fetchOEmbedData(URL).catch(err => {
50+
expect(err).toMatchInlineSnapshot(
51+
`[Error: Request to https://google.com returned non-OK status (403)]`
52+
);
53+
});
54+
});
55+
3756
describe(`network resilience`, () => {
3857
test(`retries requests if there was network error`, () => {
3958
// make sure we make our result assertion

src/transformers/utils/index.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,17 @@ export const fetchOEmbedData = url =>
66
fetchWithRetries(url, {
77
retries: 3,
88
retryDelay: attempt => 2 ** attempt * 1000,
9-
}).then(data => data.json());
9+
})
10+
.then(response => {
11+
if (!response.ok) {
12+
throw new Error(
13+
`Request to ${url} returned non-OK status (${response.status})`
14+
);
15+
}
16+
17+
return response;
18+
})
19+
.then(data => data.json());
1020

1121
export const getTrimmedPathName = pathname =>
1222
// Trim leading and trailing slashes

0 commit comments

Comments
 (0)