我有以下简单的示例 React 应用程序,其前端在端口 5000 上运行,后端 Express 服务器在端口 5001 上运行。两者之间的关系是通过 "proxy"建立的:"http://localhost :5001",
在 package.json 中。
在前端,如果单击“提交”,则会向后端的 /sample
路由发送 POST 请求,并将状态 (200) 打印到屏幕上。这一切都运行良好。
我现在想使用react-testing-library(或任何其他类似的包)来测试此行为。我已经设置了以下测试文件;但是,当它运行时,我收到Error: connect ECONNREFUSED 127.0.0.1:80
。几乎是测试库没有在正确的位置寻找后端?有没有办法在配置中指定它?
我看到其他一些帖子出现此错误,他们建议在 URL 前面包含一个前导“/”,但我的例子中已经有这个(即/sample/)。 Jest test passed but get Error: connect ECONNREFUSED 127.0.0.1:80 at the end
前端
function App() {
const [responseStatus, setResponseStatus] = useState<number>();
const { handleSubmit, register } = useForm();
const onSubmit = (data: any) => {
console.log(data);
fetch('/sample/', {
method: 'POST',
body: data,
}).then((resp) => setResponseStatus(resp.status));
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<p>Welcome</p>
<p>{responseStatus}</p>
<input {...register('fieldNo1')} />
<button type="submit" data-testid="submit-button">
Submit
</button>
</form>
);
}
Express 后端
var router = express.Router();
router.post('/', function (req, res, next) {
res.sendStatus(200);
});
测试文件
test('sample test', async () => {
render(<App />);
const welcomeText = screen.getByText('Welcome');
expect(welcomeText).toBeInTheDocument();
const submitButton = screen.getByTestId('submit-button');
fireEvent.click(submitButton);
const responseText = await screen.findByText('200');
expect(responseText).toBeInTheDocument();
});
package.json
{
"name": "sample",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:5001",
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.1.1",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.4.1",
"@types/node": "^16.11.27",
"@types/react": "^18.0.6",
"@types/react-dom": "^18.0.2",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-hook-form": "^7.33.1",
"react-scripts": "5.0.1",
"supertest": "^6.2.3",
"typescript": "^4.6.3",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "set PORT=5000 && react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/supertest": "^2.0.12"
}
}
最佳答案
我也有和你类似的需求;我的解决方案与 @jonrsharpe 在评论中建议的差不多 - 我使用 msw 代理到我的 API(本地或真实)
我更进一步,通过 msw 创建了一个代理处理程序,它既代理并将响应保存到文件中,然后又创建了一个模拟处理程序,它基本上只是在需要时重放记录的响应。
我倾向于在它们之间交换:
- 根据需要更新模拟负载(和/或针对真实 API 进行测试)
- 当需要速度和可重复性时(例如在 CI 管道中),请使用模拟版本
这是我的 typescript 代码:
import { rest, setupServer } from 'msw';
import { headersToObject } from 'headers-utils';
import fs from 'fs/promises';
// This proxies everthing to real APIs - useful to update mock-responses
export const proxyAllHandlers = [
rest.all('/*', async (req, res, ctx) => {
const proxyUrl = new URL(req.url.pathname, 'https://<my-real-url>')
const proxy = await ctx.fetch(proxyUrl.href, {
headers: { authorization: "<auth token if required>" }
});
let text = await proxy.text();
console.log(`${req.method} ${req.url.pathname}`, text);
try {
// also save to file
let filename = `./src/tests/mock-responses/${req.method.toUpperCase()}${req.url.pathname.replaceAll("/", "-")}.json`;
console.log(`Saving ${filename}...`);
await fs.writeFile(filename, JSON.stringify(JSON.parse(text), null, '\t'), 'utf-8');
}
catch(err) {
console.error("Error saving!", err);
}
return res(
ctx.status(proxy.status),
ctx.set(headersToObject(proxy.headers)),
ctx.body(text)
)
}),
];
// This mocks all responses from the apis by replaying previous recorded payloads
export const mockHandlers = [
rest.all("/*", async (req, res, ctx) => {
let filename = `./src/tests/mock-responses/${req.method.toUpperCase()}${req.url.pathname.replaceAll("/", "-")}.json`;
let data = await fs.readFile(filename, 'utf-8');
return res(ctx.json(JSON.parse(data)));
})
]
// Use proxyAllHandlers to record all expected requests as mocks and use mockHandlers to mock them
export const server = setupServer(...proxyAllHandlers);
beforeAll(() => {
// Establish requests interception layer before all tests.
server.listen()
});
afterAll(() => {
// Clean up after all tests are done, preventing this
// interception layer from affecting irrelevant tests.
server.close()
});
归功于此 github 线程,该线程具有使用 msw 的代理代码:https://github.com/mswjs/msw/discussions/887
关于jestjs - 测试通过代理向后端发送请求的 react 应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72945148/