Skip to content

Commit

Permalink
test(web): api/index.jsx
Browse files Browse the repository at this point in the history
  • Loading branch information
paularmstrong authored and blakeblackshear committed Feb 20, 2021
1 parent 53288d3 commit 6d133ef
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 7 deletions.
8 changes: 8 additions & 0 deletions web/config/setupTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,11 @@ Object.defineProperty(window, 'matchMedia', {
dispatchEvent: jest.fn(),
}),
});

window.fetch = () => Promise.resolve();

beforeEach(() => {
jest.spyOn(window, 'fetch').mockImplementation(async (url, opts = {}) => {
throw new Error(`Unexpected fetch to ${url}, ${JSON.stringify(opts)}`);
});
});
1 change: 1 addition & 0 deletions web/src/api/__mocks__/baseUrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const baseUrl = 'http:https://base-url.local:5000';
116 changes: 116 additions & 0 deletions web/src/api/__tests__/index.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { h } from 'preact';
import { ApiProvider, useFetch, useApiHost } from '..';
import { render, screen } from '@testing-library/preact';

jest.mock('../baseUrl');

describe('useApiHost', () => {
test('is set from the baseUrl', async () => {
function Test() {
const apiHost = useApiHost();
return <div>{apiHost}</div>;
}
render(
<ApiProvider>
<Test />
</ApiProvider>
);
expect(screen.queryByText('http:https://base-url.local:5000')).toBeInTheDocument();
});
});

describe('useFetch', () => {
function Test() {
const { data, status } = useFetch('/api/tacos');
return (
<div>
<span>{data ? data.returnData : ''}</span>
<span>{status}</span>
</div>
);
}
test('loads data', async () => {
const fetchSpy = jest.spyOn(window, 'fetch').mockImplementation(
(url) =>
new Promise((resolve) => {
setTimeout(() => {
resolve({ ok: true, json: () => Promise.resolve({ returnData: 'yep' }) });
}, 1);
})
);

render(
<ApiProvider>
<Test />
</ApiProvider>
);

expect(screen.queryByText('loading')).toBeInTheDocument();
expect(screen.queryByText('yep')).not.toBeInTheDocument();

jest.runAllTimers();
await screen.findByText('loaded');
expect(fetchSpy).toHaveBeenCalledWith('http:https://base-url.local:5000/api/tacos');

expect(screen.queryByText('loaded')).toBeInTheDocument();
expect(screen.queryByText('yep')).toBeInTheDocument();
});

test('sets error if response is not okay', async () => {
jest.spyOn(window, 'fetch').mockImplementation(
(url) =>
new Promise((resolve) => {
setTimeout(() => {
resolve({ ok: false });
}, 1);
})
);

render(
<ApiProvider>
<Test />
</ApiProvider>
);

expect(screen.queryByText('loading')).toBeInTheDocument();
jest.runAllTimers();
await screen.findByText('error');
});

test('does not re-fetch if the query has already been made', async () => {
const fetchSpy = jest.spyOn(window, 'fetch').mockImplementation(
(url) =>
new Promise((resolve) => {
setTimeout(() => {
resolve({ ok: true, json: () => Promise.resolve({ returnData: 'yep' }) });
}, 1);
})
);

const { rerender } = render(
<ApiProvider>
<Test key={0} />
</ApiProvider>
);

expect(screen.queryByText('loading')).toBeInTheDocument();
expect(screen.queryByText('yep')).not.toBeInTheDocument();

jest.runAllTimers();
await screen.findByText('loaded');
expect(fetchSpy).toHaveBeenCalledWith('http:https://base-url.local:5000/api/tacos');

rerender(
<ApiProvider>
<Test key={1} />
</ApiProvider>
);

expect(screen.queryByText('loaded')).toBeInTheDocument();
expect(screen.queryByText('yep')).toBeInTheDocument();

jest.runAllTimers();

expect(fetchSpy).toHaveBeenCalledTimes(1);
});
});
1 change: 1 addition & 0 deletions web/src/api/baseUrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const baseUrl = import.meta.env.SNOWPACK_PUBLIC_API_HOST || window.baseUrl || '';
17 changes: 10 additions & 7 deletions web/src/api/index.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { baseUrl } from './baseUrl';
import { h, createContext } from 'preact';
import produce from 'immer';
import { useContext, useEffect, useReducer } from 'preact/hooks';

export const ApiHost = createContext(import.meta.env.SNOWPACK_PUBLIC_API_HOST || window.baseUrl || '');

export const FetchStatus = {
NONE: 'none',
LOADING: 'loading',
Expand All @@ -12,11 +11,11 @@ export const FetchStatus = {
};

const initialState = Object.freeze({
host: import.meta.env.SNOWPACK_PUBLIC_API_HOST || window.baseUrl || '',
host: baseUrl,
queries: {},
});
export const Api = createContext(initialState);
export default Api;

const Api = createContext(initialState);

function reducer(state, { type, payload, meta }) {
switch (type) {
Expand Down Expand Up @@ -65,8 +64,12 @@ export function useFetch(url, fetchId) {
async function fetchData() {
await dispatch({ type: 'REQUEST', payload: { url, fetchId } });
const response = await fetch(`${state.host}${url}`);
const data = await response.json();
await dispatch({ type: 'RESPONSE', payload: { url, ok: response.ok, data, fetchId } });
try {
const data = await response.json();
await dispatch({ type: 'RESPONSE', payload: { url, ok: response.ok, data, fetchId } });
} catch (e) {
await dispatch({ type: 'RESPONSE', payload: { url, ok: false, data: null, fetchId } });
}
}

fetchData();
Expand Down

0 comments on commit 6d133ef

Please sign in to comment.