| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import { expect } from 'chai'
- import fetchMock from 'fetch-mock'
- import { Response } from 'node-fetch'
- import {
- deleteJSON,
- FetchError,
- getUserFacingMessage,
- getJSON,
- postJSON,
- putJSON,
- } from '../../../frontend/js/infrastructure/fetch-json'
- describe('fetchJSON', function () {
- before(function () {
- fetchMock.restore()
- })
- afterEach(function () {
- fetchMock.restore()
- })
- const headers = {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- }
- it('handles GET requests', function () {
- fetchMock.once(
- { method: 'GET', url: '/test', headers },
- { status: 200, body: { result: 'success' } }
- )
- return expect(getJSON('/test')).to.eventually.deep.equal({
- result: 'success',
- })
- })
- it('handles 4xx responses', function () {
- fetchMock.get('/test', {
- status: 400,
- body: { message: 'The request was invalid' },
- })
- return expect(getJSON('/test'))
- .to.eventually.be.rejectedWith('Bad Request')
- .and.be.an.instanceOf(FetchError)
- .to.nested.include({
- message: 'Bad Request',
- 'data.message': 'The request was invalid',
- 'response.status': 400,
- 'info.statusCode': 400,
- })
- })
- it('handles 5xx responses', async function () {
- fetchMock.get('/test', { status: 500 })
- return expect(getJSON('/test'))
- .to.eventually.be.rejectedWith('Internal Server Error')
- .and.be.an.instanceOf(FetchError)
- .to.nested.include({
- 'response.status': 500,
- 'info.statusCode': 500,
- })
- })
- it('handles JSON error responses', async function () {
- fetchMock.get('/test', {
- status: 500,
- headers: {
- 'Content-Type': 'application/json',
- },
- body: { message: 'lorem ipsum' },
- })
- return expect(getJSON('/test'))
- .to.eventually.be.rejectedWith('Internal Server Error')
- .and.be.an.instanceOf(FetchError)
- .to.nested.include({
- 'data.message': 'lorem ipsum',
- })
- })
- it('handles text error responses', async function () {
- fetchMock.get('/test', {
- status: 500,
- headers: {
- 'Content-Type': 'text/plain',
- },
- body: 'lorem ipsum',
- })
- return expect(getJSON('/test'))
- .to.eventually.be.rejectedWith('Internal Server Error')
- .and.be.an.instanceOf(FetchError)
- .to.nested.include({
- 'data.message': 'lorem ipsum',
- })
- })
- it('handles text error responses sent as HTML', async function () {
- fetchMock.get('/test', {
- status: 500,
- headers: {
- 'Content-Type': 'text/html',
- },
- body: 'lorem ipsum',
- })
- return expect(getJSON('/test'))
- .to.eventually.be.rejectedWith('Internal Server Error')
- .and.be.an.instanceOf(FetchError)
- .to.nested.include({
- 'data.message': 'lorem ipsum',
- })
- })
- it('handles (ignores) HTML error responses sent as HTML', async function () {
- fetchMock.get('/test', {
- status: 500,
- headers: {
- 'Content-Type': 'text/html',
- },
- body: '<!doctype html><html lang="en"><body><p>lorem ipsum</p></body></html>',
- })
- const promise = getJSON('/test')
- expect(promise)
- .to.eventually.be.rejectedWith('Internal Server Error')
- .and.be.an.instanceOf(FetchError)
- try {
- await promise
- } catch (error) {
- expect(error.data).to.eql({})
- }
- })
- it('handles 5xx responses without a status message', async function () {
- // It's hard to make a Response object with statusText=null,
- // so we need to do some monkey-work to make it happen
- const response = new Response('weird scary error', {
- ok: false,
- status: 599,
- })
- Object.defineProperty(response, 'statusText', {
- get: () => null,
- set: () => {},
- })
- fetchMock.get('/test', response)
- return expect(getJSON('/test'))
- .to.eventually.be.rejectedWith('Unexpected Error: 599')
- .and.be.an.instanceOf(FetchError)
- .to.nested.include({
- 'response.status': 599,
- 'info.statusCode': 599,
- message: 'Unexpected Error: 599',
- })
- })
- it('handles POST requests', function () {
- const body = { example: true }
- fetchMock.once(
- { method: 'POST', url: '/test', headers, body },
- { status: 200, body: { result: 'success' } }
- )
- return expect(postJSON('/test', { body })).to.eventually.deep.equal({
- result: 'success',
- })
- })
- it('handles PUT requests', function () {
- const body = { example: true }
- fetchMock.once(
- { method: 'PUT', url: '/test', headers, body },
- { status: 200, body: { result: 'success' } }
- )
- return expect(putJSON('/test', { body })).to.eventually.deep.equal({
- result: 'success',
- })
- })
- it('handles DELETE requests', function () {
- fetchMock.once({ method: 'DELETE', url: '/test', headers }, { status: 204 })
- return expect(deleteJSON('/test')).to.eventually.deep.equal({})
- })
- describe('getUserFacingMessage()', function () {
- it('returns the error facing message for FetchError instances', function () {
- const error = new FetchError(
- '403 error',
- 'http:/example.com',
- {},
- { status: 403 }
- )
- expect(getUserFacingMessage(error)).to.equal(
- 'Session error. Please check you have cookies enabled. If the problem persists, try clearing your cache and cookies.'
- )
- })
- it('returns `message` for Error instances different than FetchError', function () {
- const error = new Error('403 error')
- expect(getUserFacingMessage(error)).to.equal('403 error')
- })
- it('returns `undefined` for non-Error instances', function () {
- expect(getUserFacingMessage(undefined)).to.be.undefined
- expect(getUserFacingMessage(null)).to.be.undefined
- expect(getUserFacingMessage('error')).to.be.undefined
- })
- })
- })
|