import * as net from '@/scripts/net' import { on } from '@/scripts/event' import { t } from '@/scripts/i18n' import { showModal } from '@/scripts/notify' jest.mock('@/scripts/notify') test('the GET method', async () => { const json = jest.fn().mockResolvedValue({}) window.fetch = jest.fn().mockResolvedValue({ ok: true, json, headers: new Map([['Content-Type', 'application/json']]), clone: () => ({}), }) const stub = jest.fn() on('beforeFetch', stub) await net.get('/abc', { a: 'b' }) expect(stub).toBeCalledWith({ method: 'GET', url: '/abc', data: { a: 'b' }, }) expect(window.fetch.mock.calls[0][0].url).toBe('/abc?a=b') expect(json).toBeCalled() await net.get('/abc') expect(window.fetch.mock.calls[1][0].url).toBe('/abc?') }) test('the POST method', async () => { window.fetch = jest.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({}), headers: new Map([['Content-Type', 'application/json']]), clone: () => ({}), }) const meta = document.createElement('meta') meta.name = 'csrf-token' meta.content = 'token' document.head.appendChild(meta) const stub = jest.fn() on('beforeFetch', stub) const formData = new FormData() await net.post('/abc', formData) expect(stub).toBeCalledWith({ method: 'POST', url: '/abc', data: formData, }) await net.post('/abc', { a: 'b' }) expect(stub).toBeCalledWith({ method: 'POST', url: '/abc', data: { a: 'b' }, }) // eslint-disable-next-line prefer-destructuring const request = window.fetch.mock.calls[1][0] expect(request.url).toBe('/abc') expect(request.method).toBe('POST') expect(request.body).toBe(JSON.stringify({ a: 'b' })) expect(request.headers.get('X-CSRF-TOKEN')).toBe('token') expect(request.headers.get('Content-Type')).toBe('application/json') await net.post('/abc') expect(window.fetch.mock.calls[2][0].body).toBeUndefined() }) test('the PUT method', () => { const fetch = jest.fn() window.fetch = fetch const stub = jest.fn() on('beforeFetch', stub) net.put('/abc') expect(fetch).toBeCalled() // eslint-disable-next-line prefer-destructuring const request = fetch.mock.calls[0][0] expect(request.method).toBe('PUT') expect(stub).toBeCalledWith({ method: 'PUT', url: '/abc', data: undefined, }) }) test('the DELETE method', () => { const fetch = jest.fn() window.fetch = fetch const stub = jest.fn() on('beforeFetch', stub) net.del('/abc') expect(fetch).toBeCalled() // eslint-disable-next-line prefer-destructuring const request = fetch.mock.calls[0][0] expect(request.method).toBe('DELETE') expect(stub).toBeCalledWith({ method: 'DELETE', url: '/abc', data: undefined, }) }) test('low level fetch', async () => { const json = jest.fn().mockResolvedValue({}) window.fetch = jest .fn() .mockRejectedValueOnce(new Error('network')) .mockResolvedValueOnce({ ok: false, headers: new Map(), text: () => Promise.resolve('404'), clone: () => ({}), }) .mockResolvedValueOnce({ ok: false, json: () => Promise.resolve({ message: 'error' }), headers: new Map([['Content-Type', 'application/json']]), clone: () => ({}), }) .mockResolvedValueOnce({ ok: true, json, headers: new Map([['Content-Type', 'application/json']]), clone: () => ({}), }) .mockResolvedValueOnce({ ok: true, headers: new Map(), text: () => Promise.resolve('text'), clone: () => ({}), }) const request: RequestInit = { headers: new Headers() } const stub = jest.fn() on('fetchError', stub) await net.walkFetch(request as Request) expect(showModal).toBeCalledWith({ mode: 'alert', title: t('general.fatalError'), dangerousHTML: 'network', type: 'danger', okButtonType: 'outline-light', }) expect(stub).toBeCalledWith(expect.any(Error)) await net.walkFetch(request as Request) expect(showModal).toBeCalledWith({ mode: 'alert', title: t('general.fatalError'), dangerousHTML: '404', type: 'danger', okButtonType: 'outline-light', }) expect(stub.mock.calls[1][0]).toHaveProperty('message', '404') expect(stub.mock.calls[1][0]).toHaveProperty('response') await net.walkFetch(request as Request) expect(showModal).toBeCalledWith({ mode: 'alert', title: t('general.fatalError'), dangerousHTML: 'error', type: 'danger', okButtonType: 'outline-light', }) expect(stub.mock.calls[2][0]).toHaveProperty('message', 'error') expect(stub.mock.calls[2][0]).toHaveProperty('response') await net.walkFetch(request as Request) expect(json).toBeCalled() expect(await net.walkFetch(request as Request)).toBe('text') }) test('process backend errors', async () => { window.fetch = jest .fn() .mockResolvedValueOnce({ status: 422, headers: new Map([['Content-Type', 'application/json']]), json() { return Promise.resolve({ errors: { name: ['required'] }, }) }, clone: () => ({}), }) .mockResolvedValueOnce({ status: 419, headers: new Map([['Content-Type', 'application/json']]), json() { return Promise.resolve({ message: 'CSRF token mismatched.', }) }, clone: () => ({}), }) .mockResolvedValueOnce({ status: 403, headers: new Map([['Content-Type', 'application/json']]), json() { return Promise.resolve({ message: 'forbidden' }) }, clone: () => ({}), }) .mockResolvedValueOnce({ status: 500, headers: new Map([['Content-Type', 'application/json']]), json() { return Promise.resolve({ message: 'fake exception', exception: true, trace: [ { file: 'k.php', line: 2 }, { file: 'v.php', line: 3 }, ], }) }, clone: () => ({}), }) const result: { code: number message: string } = await net.walkFetch({ headers: new Headers() } as Request) expect(result.code).toBe(1) expect(result.message).toBe('required') await net.walkFetch({ headers: new Headers() } as Request) expect(showModal).toBeCalledWith({ mode: 'alert', text: t('general.csrf'), }) await net.walkFetch({ headers: new Headers() } as Request) expect(showModal).toBeCalledWith({ mode: 'alert', text: 'forbidden', type: 'warning', }) await net.walkFetch({ headers: new Headers() } as Request) expect(showModal).toBeCalledWith({ mode: 'alert', title: t('general.fatalError'), dangerousHTML: 'fake exception
[1] k.php#L2
[2] v.php#L3
', type: 'danger', okButtonType: 'outline-light', }) })