222 lines
5.9 KiB
TypeScript
222 lines
5.9 KiB
TypeScript
jest.mock('./settings', () => ({
|
|
siteId: 'remark',
|
|
}));
|
|
|
|
import { RequestError } from 'utils/errorUtils';
|
|
import { API_BASE, BASE_URL } from './constants.config';
|
|
import { apiFetcher, authFetcher, adminFetcher, JWT_HEADER, XSRF_HEADER } from './fetcher';
|
|
|
|
type FetchImplementaitonProps = {
|
|
status?: number;
|
|
headers?: Record<string, string>;
|
|
json?: () => Promise<unknown>;
|
|
text?: () => Promise<unknown>;
|
|
data?: unknown;
|
|
};
|
|
|
|
function mockFetch({ headers = {}, data = {}, ...props }: FetchImplementaitonProps = {}) {
|
|
window.fetch = jest.fn().mockImplementation(() => {
|
|
return {
|
|
status: 200,
|
|
headers: new Headers(headers),
|
|
async json() {
|
|
return data;
|
|
},
|
|
async text() {
|
|
return JSON.stringify(data);
|
|
},
|
|
...props,
|
|
};
|
|
});
|
|
}
|
|
|
|
describe('fetcher', () => {
|
|
const headers = { [XSRF_HEADER]: '' };
|
|
const apiUri = '/anything';
|
|
const apiUrl = `${BASE_URL}${API_BASE}/anything?site=remark`;
|
|
|
|
describe('methods', () => {
|
|
it('should send GET request', async () => {
|
|
expect.assertions(1);
|
|
|
|
mockFetch();
|
|
await apiFetcher.get(apiUri);
|
|
|
|
expect(window.fetch).toHaveBeenCalledWith(apiUrl, { method: 'get', headers });
|
|
});
|
|
it('should send POST request', async () => {
|
|
expect.assertions(1);
|
|
|
|
mockFetch();
|
|
await apiFetcher.post(apiUri);
|
|
|
|
expect(window.fetch).toHaveBeenCalledWith(apiUrl, { method: 'post', headers });
|
|
});
|
|
it('should send PUT request', async () => {
|
|
expect.assertions(1);
|
|
|
|
mockFetch();
|
|
await apiFetcher.put(apiUri);
|
|
|
|
expect(window.fetch).toHaveBeenCalledWith(apiUrl, { method: 'put', headers });
|
|
});
|
|
it('should send DELETE request', async () => {
|
|
expect.assertions(1);
|
|
|
|
mockFetch();
|
|
await apiFetcher.delete(apiUri);
|
|
|
|
expect(window.fetch).toHaveBeenCalledWith(apiUrl, { method: 'delete', headers });
|
|
});
|
|
});
|
|
|
|
describe('auth fetcher', () => {
|
|
it('should use other base url for auth fetcher', async () => {
|
|
expect.assertions(1);
|
|
|
|
mockFetch();
|
|
await authFetcher.post(apiUri);
|
|
|
|
expect(window.fetch).toHaveBeenCalledWith(`${BASE_URL}/auth/anything?site=remark`, { method: 'post', headers });
|
|
});
|
|
});
|
|
|
|
describe('admin fetcher', () => {
|
|
it('should use other base url for auth fetcher', async () => {
|
|
expect.assertions(1);
|
|
|
|
mockFetch();
|
|
await adminFetcher.post(apiUri);
|
|
|
|
expect(window.fetch).toHaveBeenCalledWith(`${BASE_URL}${API_BASE}/admin/anything?site=remark`, {
|
|
method: 'post',
|
|
headers,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('headers', () => {
|
|
it('should set active token and than clean it on unauthorized respose', async () => {
|
|
expect.assertions(4);
|
|
|
|
const headersWithJwt = { [JWT_HEADER]: 'token', ...headers };
|
|
// Set token to `activeJwtToken`
|
|
mockFetch({ headers: headersWithJwt });
|
|
await apiFetcher.get(apiUri);
|
|
|
|
expect(window.fetch).toHaveBeenCalled();
|
|
|
|
// Check if `activeJwtToken` saved and clean
|
|
mockFetch({ headers, status: 401 });
|
|
await expect(
|
|
apiFetcher.get(apiUri).then(() => {
|
|
throw Error('apiFether shoud throw error on 401 responce');
|
|
})
|
|
).rejects.toEqual(new Error('Not authorized.'));
|
|
|
|
expect(window.fetch).toHaveBeenCalledWith(apiUrl, {
|
|
method: 'get',
|
|
headers: headersWithJwt,
|
|
});
|
|
|
|
// Check if `activeJwtToken` was cleaned
|
|
mockFetch({ headers });
|
|
await apiFetcher.get(apiUri);
|
|
|
|
expect(window.fetch).toHaveBeenCalledWith(apiUrl, { method: 'get', headers });
|
|
});
|
|
});
|
|
|
|
describe('send data', () => {
|
|
it('should send JSON', async () => {
|
|
expect.assertions(1);
|
|
|
|
const data = { text: 'text' };
|
|
const headersWithContentType = { ...headers, 'Content-Type': 'application/json' };
|
|
|
|
mockFetch();
|
|
await apiFetcher.post(apiUri, {}, data);
|
|
|
|
expect(window.fetch).toBeCalledWith(apiUrl, {
|
|
method: 'post',
|
|
headers: headersWithContentType,
|
|
body: JSON.stringify(data),
|
|
});
|
|
});
|
|
|
|
it("shouldn't send content-type with form data", async () => {
|
|
expect.assertions(1);
|
|
|
|
const body = new FormData();
|
|
|
|
mockFetch();
|
|
await apiFetcher.post(apiUri, {}, body);
|
|
|
|
expect(window.fetch).toHaveBeenCalledWith(apiUrl, {
|
|
method: 'post',
|
|
body,
|
|
headers,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('request errors', () => {
|
|
it('should throw json on api json response with >= 400 status code', async () => {
|
|
expect.assertions(1);
|
|
|
|
const data = {
|
|
code: 2,
|
|
error: 'you just cant',
|
|
details: 'you just cant at all',
|
|
};
|
|
|
|
mockFetch({ status: 400, data });
|
|
|
|
await expect(apiFetcher.get(apiUri)).rejects.toEqual(data);
|
|
});
|
|
|
|
it('should throw error on api json response with >= 400 status code and bad json from server', async () => {
|
|
expect.assertions(1);
|
|
|
|
const data = ']{{"code: 2';
|
|
|
|
mockFetch({ status: 400, data });
|
|
|
|
await expect(apiFetcher.get(apiUri)).rejects.toEqual(data);
|
|
});
|
|
|
|
it('should throw special error object on 401 status', async () => {
|
|
expect.assertions(1);
|
|
|
|
const response = '<html>unauthorized nginx response</html>';
|
|
|
|
mockFetch({
|
|
status: 401,
|
|
json() {
|
|
throw new Error('json parse error');
|
|
},
|
|
async text() {
|
|
return response;
|
|
},
|
|
});
|
|
|
|
await expect(apiFetcher.get(apiUri)).rejects.toEqual(new RequestError('Not authorized.', 401));
|
|
});
|
|
it('should throw "Something went wrong." object on unknown status', async () => {
|
|
expect.assertions(1);
|
|
|
|
mockFetch({
|
|
status: 400,
|
|
json() {
|
|
throw new Error('json parse error');
|
|
},
|
|
async text() {
|
|
return 'you given me something wrong';
|
|
},
|
|
});
|
|
|
|
await expect(apiFetcher.get(apiUri)).rejects.toEqual(new RequestError('Something went wrong.', 0));
|
|
});
|
|
});
|
|
});
|