dri*_*hev 7 mocking jestjs create-react-app
我有一个 Jest 的工作示例和来自的模拟__mocks__有效目录的模拟:
// package.json\n{\n "name": "a",\n "version": "1.0.0",\n "main": "index.js",\n "scripts": {\n "test": "jest"\n },\n ...\n "devDependencies": {\n "jest": "^26.6.3"\n },\n "dependencies": {\n "@octokit/rest": "^18.0.12"\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n进而/index.js:
const { Octokit } = require("@octokit/rest");\n\nconst octokit = new Octokit();\n\nmodule.exports.foo = function() {\n return octokit.repos.listForOrg({ org: "octokit", type: "public" })\n}\nRun Code Online (Sandbox Code Playgroud)\n及其测试(/index.test.js ):
const { foo } = require("./index.js");\n\ntest("foo should be true", async () => {\n expect(await foo()).toEqual([1,2]);\n});\nRun Code Online (Sandbox Code Playgroud)\n和模拟(/__mocks__/@octokit/rest/index.js ):
module.exports.Octokit = jest.fn().mockImplementation( () => ({\n repos: {\n listForOrg: jest.fn().mockResolvedValue([1,2])\n }\n}) );\nRun Code Online (Sandbox Code Playgroud)\n这工作得很好并且测试通过了。
\n然而,对 Create React App 进行同样的操作似乎给了我一个奇怪的结果:
\n// package.json\n{\n "name": "b",\n "version": "0.1.0",\n "dependencies": {\n "@octokit/rest": "^18.0.12",\n "@testing-library/jest-dom": "^5.11.4",\n "@testing-library/react": "^11.1.0",\n "@testing-library/user-event": "^12.1.10",\n "react": "^17.0.1",\n "react-dom": "^17.0.1",\n "react-scripts": "4.0.1",\n "web-vitals": "^0.2.4"\n },\n "scripts": {\n "start": "react-scripts start",\n "build": "react-scripts build",\n "test": "react-scripts test",\n "eject": "react-scripts eject"\n },\n ...\n}\nRun Code Online (Sandbox Code Playgroud)\n进而/src/foo.js:
import { Octokit } from "@octokit/rest";\n\nconst octokit = new Octokit();\n\nmodule.exports.foo = function() {\n return octokit.repos.listForOrg({ org: "octokit", type: "public" })\n}\nRun Code Online (Sandbox Code Playgroud)\n及其测试(/src/foo.test.js ):
const { foo} = require("./foo.js");\n\ntest("foo should be true", async () => {\n expect(await foo()).toEqual([1,2]);\n});\nRun Code Online (Sandbox Code Playgroud)\n和完全相同的模拟(在/src/__mocks__/@octokit/rest/index.js):
export const Octokit = jest.fn().mockImplementation( () => ({\n repos: {\n listForOrg: jest.fn().mockResolvedValue([1,2])\n }\n}) );\nRun Code Online (Sandbox Code Playgroud)\n这使得测试失败:
\n FAIL src/foo.test.js\n \xe2\x9c\x95 foo should be true (2 ms)\n\n \xe2\x97\x8f foo should be true\n\n expect(received).toEqual(expected) // deep equality\n\n Expected: [1, 2]\n Received: undefined\n\n 2 |\n 3 | test("foo should be true", async () => {\n > 4 | expect(await foo()).toEqual([1,2]);\n | ^\n 5 | });\n 6 |\n 7 |\n\n at Object.<anonymous> (src/foo.test.js:4:25)\nRun Code Online (Sandbox Code Playgroud)\n读了很多书后,我似乎无法做到__mocks__在 Create React App 中工作。有什么问题?
jon*_*rpe 12
问题是 CRA 的默认 Jest 设置会自动重置模拟,从而删除mockResolvedValue您设置的模拟。
解决这个问题的一种方法是从模块中公开模拟函数,这也使您可以更好地控制在不同的测试中使用不同的值(例如测试错误处理)并断言调用的内容:
\nexport const mockListForOrg = jest.fn();\n\nexport const Octokit = jest.fn().mockImplementation(() => ({\n repos: {\n listForOrg: mockListForOrg,\n },\n}));\nRun Code Online (Sandbox Code Playgroud)\n然后,在Jest 重置它之后,您可以在测试中配置所需的值:
\nimport { mockListForOrg } from "@octokit/rest";\n\nimport { foo } from "./foo";\n\ntest("foo should be true", async () => {\n mockListForOrg.mockResolvedValueOnce([1, 2]);\n\n expect(await foo()).toEqual([1, 2]);\n});\nRun Code Online (Sandbox Code Playgroud)\n另一种选择是根据此问题将以下内容添加到您的文件中package.json以覆盖该配置:
{\n ...\n "jest": {\n "resetMocks": false\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n不过,这可能会导致测试之间保留模拟状态(收到的呼叫)的问题,因此您需要确保它们在某处被清除和/或重置。
\n请注意,尽管如此,您通常不应该模拟您不拥有的东西 - 如果@octokit/rest更改的接口您的测试将继续通过,但您的代码将无法工作。为了避免这个问题,我建议使用以下之一或两者:
@octokit/rest,将您的代码与您不拥有的接口解耦,并模拟它;以及更高级别(端到端)测试,以确保一切都能与真正的 GitHub API 正常工作。
\n事实上,删除模拟并使用 MSW编写这样的测试:
\nimport { rest } from "msw";\nimport { setupServer } from "msw/node";\n\nimport { foo } from "./foo";\n\nconst server = setupServer(rest.get("https://api.github.com/orgs/octokit/repos", (req, res, ctx) => {\n return res(ctx.status(200), ctx.json([1, 2]));\n}));\n\nbeforeAll(() => server.listen());\n\nafterAll(() => server.close());\n\ntest("foo should be true", async () => {\n expect(await foo()).toEqual([1, 2]);\n});\nRun Code Online (Sandbox Code Playgroud)\n暴露出当前关于octokit.repos.listForOrg返回内容的假设是不准确的,因为此测试失败了:
\xe2\x97\x8f foo should be true\n\n expect(received).toEqual(expected) // deep equality\n\n Expected: [1, 2]\n Received: {"data": [1, 2], "headers": {"content-type": "application/json", "x-powered-by": "msw"}, "status": 200, "url": "https://api.github.com/orgs/octokit/repos?type=public"}\n\n 13 | \n 14 | test("foo should be true", async () => {\n > 15 | expect(await foo()).toEqual([1, 2]);\n | ^\n 16 | });\n 17 | \n\n at Object.<anonymous> (src/foo.test.js:15:25)\nRun Code Online (Sandbox Code Playgroud)\n您的实现实际上应该看起来更像:
\nexport async function foo() {\n const { data } = await octokit.repos.listForOrg({ org: "octokit", type: "public" });\n return data;\n}\nRun Code Online (Sandbox Code Playgroud)\n或者:
\nexport function foo() {\n return octokit.repos.listForOrg({ org: "octokit", type: "public" }).then(({ data }) => data);\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
4786 次 |
| 最近记录: |