在 express 应用程序中测试默认错误处理程序会导致超时
Testing default error handler in an express application results in a timeout
测试快速应用程序的默认错误处理程序时,会导致超时。该函数如下所示:
const createApp = (underlyingFunction) => {
const app = express()
app.get('/my-endpoint', async (req, res) => {
await underlyingFunction()
res.send({ success: true })
})
const errorHandler: ErrorRequestHandler = (error, req, res, next) => {
console.error('Unhandled exception');
console.error(error);
console.error(error.stack);
res.status(500).send({
message: 'Oh dear',
});
// next()
}
app.use(errorHandler)
return app;
}
测试如下所示:
test('error should be handled and return 500', async () => {
underlyingFunction.mockImplementation(() => {
throw new Error('Something went wrong')
})
const app = createApp(underlyingFunction)
const response = await request(app).get('/my-endpoint')
expect(response.status).toBe(500)
})
当运行测试时,出现如下错误:
thrown: "Exceeded timeout of 5000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
可能是什么原因造成的?
对于 express
V4,从 Error Handling#Catching Errors 文档中,我们知道:
For errors returned from asynchronous functions invoked by route handlers and middleware, you must pass them to the next()
function, where Express will catch and process them.
虽然测试用例中mock的underlyingFunction
是同步的,但是在路由中,async/await
语法将这个路由handler转为异步代码
因此,您需要使用 try...catch
语句来捕获 underlyingFunction
函数引发的错误。并将 error
传递给 next
函数。 express
将使用 error
.
将请求路由到错误处理程序中间件
例如
app.ts
:
import express from 'express';
import { ErrorRequestHandler } from 'express-serve-static-core';
export const createApp = (underlyingFunction) => {
const app = express();
app.get('/my-endpoint', async (req, res, next) => {
try {
await underlyingFunction();
res.send({ success: true });
} catch (error) {
next(error);
}
});
const errorHandler: ErrorRequestHandler = (error, req, res, next) => {
console.error('Unhandled exception');
res.status(500).send({ message: 'Oh dear' });
};
app.use(errorHandler);
return app;
};
app.test.ts
:
import request from 'supertest';
import { createApp } from './app';
describe('68923821', () => {
test('error should be handled and return 500', async () => {
const underlyingFunction = jest.fn().mockImplementation(() => {
throw new Error('Something went wrong');
});
const app = createApp(underlyingFunction);
const res = await request(app).get('/my-endpoint');
expect(res.status).toEqual(500);
});
});
测试结果:
PASS examples/68923821/app.test.ts (9.128 s)
68923821
✓ error should be handled and return 500 (49 ms)
console.error
Unhandled exception
15 |
16 | const errorHandler: ErrorRequestHandler = (error, req, res, next) => {
> 17 | console.error('Unhandled exception');
| ^
18 | res.status(500).send({ message: 'Oh dear' });
19 | };
20 |
at errorHandler (examples/68923821/app.ts:17:13)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.661 s
测试快速应用程序的默认错误处理程序时,会导致超时。该函数如下所示:
const createApp = (underlyingFunction) => {
const app = express()
app.get('/my-endpoint', async (req, res) => {
await underlyingFunction()
res.send({ success: true })
})
const errorHandler: ErrorRequestHandler = (error, req, res, next) => {
console.error('Unhandled exception');
console.error(error);
console.error(error.stack);
res.status(500).send({
message: 'Oh dear',
});
// next()
}
app.use(errorHandler)
return app;
}
测试如下所示:
test('error should be handled and return 500', async () => {
underlyingFunction.mockImplementation(() => {
throw new Error('Something went wrong')
})
const app = createApp(underlyingFunction)
const response = await request(app).get('/my-endpoint')
expect(response.status).toBe(500)
})
当运行测试时,出现如下错误:
thrown: "Exceeded timeout of 5000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
可能是什么原因造成的?
对于 express
V4,从 Error Handling#Catching Errors 文档中,我们知道:
For errors returned from asynchronous functions invoked by route handlers and middleware, you must pass them to the
next()
function, where Express will catch and process them.
虽然测试用例中mock的underlyingFunction
是同步的,但是在路由中,async/await
语法将这个路由handler转为异步代码
因此,您需要使用 try...catch
语句来捕获 underlyingFunction
函数引发的错误。并将 error
传递给 next
函数。 express
将使用 error
.
例如
app.ts
:
import express from 'express';
import { ErrorRequestHandler } from 'express-serve-static-core';
export const createApp = (underlyingFunction) => {
const app = express();
app.get('/my-endpoint', async (req, res, next) => {
try {
await underlyingFunction();
res.send({ success: true });
} catch (error) {
next(error);
}
});
const errorHandler: ErrorRequestHandler = (error, req, res, next) => {
console.error('Unhandled exception');
res.status(500).send({ message: 'Oh dear' });
};
app.use(errorHandler);
return app;
};
app.test.ts
:
import request from 'supertest';
import { createApp } from './app';
describe('68923821', () => {
test('error should be handled and return 500', async () => {
const underlyingFunction = jest.fn().mockImplementation(() => {
throw new Error('Something went wrong');
});
const app = createApp(underlyingFunction);
const res = await request(app).get('/my-endpoint');
expect(res.status).toEqual(500);
});
});
测试结果:
PASS examples/68923821/app.test.ts (9.128 s)
68923821
✓ error should be handled and return 500 (49 ms)
console.error
Unhandled exception
15 |
16 | const errorHandler: ErrorRequestHandler = (error, req, res, next) => {
> 17 | console.error('Unhandled exception');
| ^
18 | res.status(500).send({ message: 'Oh dear' });
19 | };
20 |
at errorHandler (examples/68923821/app.ts:17:13)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.661 s