mirror of
https://github.com/feathersjs/feathers.git
synced 2026-01-25 15:23:13 +00:00
400 lines
11 KiB
TypeScript
400 lines
11 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function */
|
|
import { strict as assert } from 'assert'
|
|
import express, { Request, Response, NextFunction } from 'express'
|
|
import axios from 'axios'
|
|
import fs from 'fs'
|
|
import { join } from 'path'
|
|
import { BadRequest, NotAcceptable, NotAuthenticated, NotFound, PaymentError } from '@feathersjs/errors'
|
|
|
|
import { errorHandler } from '../src'
|
|
|
|
const content = '<html><head></head><body>Error</body></html>'
|
|
|
|
const htmlHandler = function (_error: Error, _req: Request, res: Response, _next: NextFunction) {
|
|
res.send(content)
|
|
}
|
|
|
|
const jsonHandler = function (error: Error, _req: Request, res: Response, _next: NextFunction) {
|
|
res.json(error)
|
|
}
|
|
|
|
describe('error-handler', () => {
|
|
describe('supports catch-all custom handlers', function () {
|
|
before(function () {
|
|
this.app = express()
|
|
.get('/error', function (_req: Request, _res: Response, next: NextFunction) {
|
|
next(new Error('Something went wrong'))
|
|
})
|
|
.use(
|
|
errorHandler({
|
|
html: htmlHandler,
|
|
json: jsonHandler
|
|
})
|
|
)
|
|
|
|
this.server = this.app.listen(5050)
|
|
})
|
|
|
|
after(function (done) {
|
|
this.server.close(done)
|
|
})
|
|
|
|
describe('JSON handler', () => {
|
|
const options = {
|
|
url: 'http://localhost:5050/error',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json'
|
|
}
|
|
}
|
|
|
|
it('can send a custom response', async () => {
|
|
try {
|
|
await axios(options)
|
|
assert.fail('Should never get here')
|
|
} catch (error: any) {
|
|
assert.deepEqual(error.response.data, {
|
|
name: 'GeneralError',
|
|
message: 'Something went wrong',
|
|
code: 500,
|
|
className: 'general-error'
|
|
})
|
|
}
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('supports error-code specific custom handlers', () => {
|
|
describe('HTML handler', () => {
|
|
const req = {
|
|
headers: { 'content-type': 'text/html' }
|
|
}
|
|
const makeRes = (errCode: number, props?: any) => {
|
|
return Object.assign(
|
|
{
|
|
set() {},
|
|
status(code: number) {
|
|
assert.equal(code, errCode)
|
|
}
|
|
},
|
|
props
|
|
)
|
|
}
|
|
|
|
it('if the value is a string, calls res.sendFile', (done) => {
|
|
const err = new NotAuthenticated()
|
|
const middleware = errorHandler({
|
|
logger: null,
|
|
html: { 401: 'path/to/401.html' }
|
|
})
|
|
const res = makeRes(401, {
|
|
sendFile(f: any) {
|
|
assert.equal(f, 'path/to/401.html')
|
|
done()
|
|
}
|
|
})
|
|
;(middleware as any)(err, req, res)
|
|
})
|
|
|
|
it('if the value is a function, calls as middleware ', (done) => {
|
|
const err = new PaymentError()
|
|
const res = makeRes(402)
|
|
const middleware = errorHandler({
|
|
logger: null,
|
|
html: {
|
|
402: (_err: any, _req: any, _res: any) => {
|
|
assert.equal(_err, err)
|
|
assert.equal(_req, req)
|
|
assert.equal(_res, res)
|
|
done()
|
|
}
|
|
}
|
|
})
|
|
;(middleware as any)(err, req, res)
|
|
})
|
|
|
|
it('falls back to default if error code config is available', (done) => {
|
|
const err = new NotAcceptable()
|
|
const res = makeRes(406)
|
|
const middleware = errorHandler({
|
|
logger: null,
|
|
html: {
|
|
default: (_err: any, _req: any, _res: any) => {
|
|
assert.equal(_err, err)
|
|
assert.equal(_req, req)
|
|
assert.equal(_res, res)
|
|
done()
|
|
}
|
|
}
|
|
})
|
|
;(middleware as any)(err, req, res)
|
|
})
|
|
})
|
|
|
|
describe('JSON handler', () => {
|
|
const req = {
|
|
headers: { 'content-type': 'application/json' }
|
|
}
|
|
const makeRes = (errCode: number, props?: any) => {
|
|
return Object.assign(
|
|
{
|
|
set() {},
|
|
status(code: number) {
|
|
assert.equal(code, errCode)
|
|
}
|
|
},
|
|
props
|
|
)
|
|
}
|
|
|
|
it('calls res.json by default', (done) => {
|
|
const err = new NotAuthenticated()
|
|
const middleware = errorHandler({
|
|
logger: null,
|
|
json: {}
|
|
})
|
|
const res = makeRes(401, {
|
|
json(obj: any) {
|
|
assert.deepEqual(obj, err.toJSON())
|
|
done()
|
|
}
|
|
})
|
|
;(middleware as any)(err, req, res)
|
|
})
|
|
|
|
it('if the value is a function, calls as middleware ', (done) => {
|
|
const err = new PaymentError()
|
|
const res = makeRes(402)
|
|
const middleware = errorHandler({
|
|
logger: null,
|
|
json: {
|
|
402: (_err: any, _req: any, _res: any) => {
|
|
assert.equal(_err, err)
|
|
assert.equal(_req, req)
|
|
assert.equal(_res, res)
|
|
done()
|
|
}
|
|
}
|
|
})
|
|
;(middleware as any)(err, req, res)
|
|
})
|
|
|
|
it('falls back to default if error code config is available', (done) => {
|
|
const err = new NotAcceptable()
|
|
const res = makeRes(406)
|
|
const middleware = errorHandler({
|
|
logger: null,
|
|
json: {
|
|
default: (_err: any, _req: any, _res: any) => {
|
|
assert.equal(_err, err)
|
|
assert.equal(_req, req)
|
|
assert.equal(_res, res)
|
|
done()
|
|
}
|
|
}
|
|
})
|
|
;(middleware as any)(err, req, res)
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('use as app error handler', function () {
|
|
before(function () {
|
|
this.app = express()
|
|
.get('/error', function (_req: Request, _res: Response, next: NextFunction) {
|
|
next(new Error('Something went wrong'))
|
|
})
|
|
.get('/string-error', function (_req: Request, _res: Response, next: NextFunction) {
|
|
const e: any = new Error('Something was not found')
|
|
e.code = '404'
|
|
|
|
next(e)
|
|
})
|
|
.get('/bad-request', function (_req: Request, _res: Response, next: NextFunction) {
|
|
next(
|
|
new BadRequest({
|
|
message: 'Invalid Password',
|
|
errors: [
|
|
{
|
|
path: 'password',
|
|
value: null,
|
|
message: "'password' cannot be 'null'"
|
|
}
|
|
]
|
|
})
|
|
)
|
|
})
|
|
.use(function (_req: Request, _res: Response, next: NextFunction) {
|
|
next(new NotFound('File not found'))
|
|
})
|
|
.use(
|
|
errorHandler({
|
|
logger: null
|
|
})
|
|
)
|
|
|
|
this.server = this.app.listen(5050)
|
|
})
|
|
|
|
after(function (done) {
|
|
this.server.close(done)
|
|
})
|
|
|
|
describe('converts an non-feathers error', () => {
|
|
it('is an instance of GeneralError', async () => {
|
|
try {
|
|
await axios({
|
|
url: 'http://localhost:5050/error',
|
|
responseType: 'json'
|
|
})
|
|
assert.fail('Should never get here')
|
|
} catch (error: any) {
|
|
assert.equal(error.response.status, 500)
|
|
assert.deepEqual(error.response.data, {
|
|
name: 'GeneralError',
|
|
message: 'Something went wrong',
|
|
code: 500,
|
|
className: 'general-error'
|
|
})
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('text/html format', () => {
|
|
it('serves a 404.html', (done) => {
|
|
fs.readFile(join(__dirname, '..', 'public', '404.html'), async function (_err, html) {
|
|
try {
|
|
await axios({
|
|
url: 'http://localhost:5050/path/to/nowhere',
|
|
headers: {
|
|
'Content-Type': 'text/html',
|
|
Accept: 'text/html'
|
|
}
|
|
})
|
|
assert.fail('Should never get here')
|
|
} catch (error: any) {
|
|
assert.equal(error.response.status, 404)
|
|
assert.equal(error.response.data, html.toString())
|
|
done()
|
|
}
|
|
})
|
|
})
|
|
|
|
it('serves a 500.html', (done) => {
|
|
fs.readFile(join(__dirname, '..', 'public', 'default.html'), async function (_err, html) {
|
|
try {
|
|
await axios({
|
|
url: 'http://localhost:5050/error',
|
|
headers: {
|
|
'Content-Type': 'text/html',
|
|
Accept: 'text/html'
|
|
}
|
|
})
|
|
assert.fail('Should never get here')
|
|
} catch (error: any) {
|
|
assert.equal(error.response.status, 500)
|
|
assert.equal(error.response.data, html.toString())
|
|
done()
|
|
}
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('application/json format', () => {
|
|
it('500', async () => {
|
|
try {
|
|
await axios({
|
|
url: 'http://localhost:5050/error',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json'
|
|
}
|
|
})
|
|
assert.fail('Should never get here')
|
|
} catch (error: any) {
|
|
assert.equal(error.response.status, 500)
|
|
assert.deepEqual(error.response.data, {
|
|
name: 'GeneralError',
|
|
message: 'Something went wrong',
|
|
code: 500,
|
|
className: 'general-error'
|
|
})
|
|
}
|
|
})
|
|
|
|
it('404', async () => {
|
|
try {
|
|
await axios({
|
|
url: 'http://localhost:5050/path/to/nowhere',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json'
|
|
}
|
|
})
|
|
assert.fail('Should never get here')
|
|
} catch (error: any) {
|
|
assert.equal(error.response.status, 404)
|
|
assert.deepEqual(error.response.data, {
|
|
name: 'NotFound',
|
|
message: 'File not found',
|
|
code: 404,
|
|
className: 'not-found'
|
|
})
|
|
}
|
|
})
|
|
|
|
it('400', async () => {
|
|
try {
|
|
await axios({
|
|
url: 'http://localhost:5050/bad-request',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Accept: 'application/json'
|
|
}
|
|
})
|
|
assert.fail('Should never get here')
|
|
} catch (error: any) {
|
|
assert.equal(error.response.status, 400)
|
|
assert.deepEqual(error.response.data, {
|
|
name: 'BadRequest',
|
|
message: 'Invalid Password',
|
|
code: 400,
|
|
className: 'bad-request',
|
|
data: {},
|
|
errors: [
|
|
{
|
|
path: 'password',
|
|
value: null,
|
|
message: "'password' cannot be 'null'"
|
|
}
|
|
]
|
|
})
|
|
}
|
|
})
|
|
})
|
|
|
|
it('returns JSON by default', async () => {
|
|
try {
|
|
await axios('http://localhost:5050/bad-request')
|
|
assert.fail('Should never get here')
|
|
} catch (error: any) {
|
|
assert.equal(error.response.status, 400)
|
|
assert.deepEqual(error.response.data, {
|
|
name: 'BadRequest',
|
|
message: 'Invalid Password',
|
|
code: 400,
|
|
className: 'bad-request',
|
|
data: {},
|
|
errors: [
|
|
{
|
|
path: 'password',
|
|
value: null,
|
|
message: "'password' cannot be 'null'"
|
|
}
|
|
]
|
|
})
|
|
}
|
|
})
|
|
})
|
|
})
|