Jestjs 创建React应用程序';t从_mock__目录正确模拟模块

Jestjs 创建React应用程序';t从_mock__目录正确模拟模块,jestjs,mocking,create-react-app,Jestjs,Mocking,Create React App,我有一个来自\uuuuumocks\uuuuu目录的Jest和mocks的工作示例,它可以工作: 使用简单的笑话设置 //package.json { “姓名”:“a”, “版本”:“1.0.0”, “main”:“index.js”, “脚本”:{ “测试”:“开玩笑” }, ... “依赖性”:{ “笑话”:“^26.6.3” }, “依赖项”:{ @octokit/rest:“^18.0.12” } } 然后/index.js: const{Octokit}=require(@Octok

我有一个来自
\uuuuumocks\uuuuu
目录的Jest和mocks的工作示例,它可以工作:

使用简单的笑话设置
//package.json
{
“姓名”:“a”,
“版本”:“1.0.0”,
“main”:“index.js”,
“脚本”:{
“测试”:“开玩笑”
},
...
“依赖性”:{
“笑话”:“^26.6.3”
},
“依赖项”:{
@octokit/rest:“^18.0.12”
}
}
然后
/index.js

const{Octokit}=require(@Octokit/rest”);
const octokit=新的octokit();
module.exports.foo=函数(){
返回octokit.repos.listForOrg({org:“octokit”,键入:“public”})
}
通过它的测试(
/index.test.js
):

const{foo}=require(“./index.js”);
测试(“foo应该为true”,async()=>{
expect(wait foo()).toEqual([1,2]);
});
和mock(
/\uuuuuumocks\uuuuu/@octokit/rest/index.js
):

module.exports.Octokit=jest.fn().mockImplementation(()=>({
回购协议:{
listForOrg:jest.fn().mockResolvedValue([1,2])
}
}) );
这工作得很好,测试通过了

使用CreateReact应用程序 然而,对Create-React应用程序执行同样的操作似乎给了我一个奇怪的结果:

//package.json
{
“名称”:“b”,
“版本”:“0.1.0”,
“依赖项”:{
“@octokit/rest”:“^18.0.12”,
“@测试库/jest dom”:“^5.11.4”,
“@testing library/react”:“^11.1.0”,
“@测试库/用户事件”:“^12.1.10”,
“反应”:“^17.0.1”,
“react dom”:“^17.0.1”,
“反应脚本”:“4.0.1”,
“web重要信息”:“^0.2.4”
},
“脚本”:{
“开始”:“反应脚本开始”,
“构建”:“反应脚本构建”,
“测试”:“反应脚本测试”,
“弹出”:“反应脚本弹出”
},
...
}
然后
/src/foo.js

从“@Octokit/rest”导入{Octokit};
const octokit=新的octokit();
module.exports.foo=函数(){
返回octokit.repos.listForOrg({org:“octokit”,键入:“public”})
}
通过它的测试(
/src/foo.test.js
):

const{foo}=require(“./foo.js”);
测试(“foo应该为true”,async()=>{
expect(wait foo()).toEqual([1,2]);
});
和同一个mock(在
/src/\uuuuuu mocks\uuuuuu/@octokit/rest/index.js
下):

export const Octokit=jest.fn().mockImplementation(()=>({
回购协议:{
listForOrg:jest.fn().mockResolvedValue([1,2])
}
}) );
这会导致测试失败:

 FAIL  src/foo.test.js
  ✕ foo should be true (2 ms)

  ● foo should be true

    expect(received).toEqual(expected) // deep equality

    Expected: [1, 2]
    Received: undefined

      2 |
      3 | test("foo should be true", async () => {
    > 4 |     expect(await foo()).toEqual([1,2]);
        |                         ^
      5 | });
      6 |
      7 |

      at Object.<anonymous> (src/foo.test.js:4:25)
FAIL src/foo.test.js
✕ foo应为真(2毫秒)
● 福应该是真的
expect(received).toEqual(expected)//深度相等
预期:[1,2]
收到:未定义
2 |
3 |测试(“foo应该为true”,async()=>{
>4 | expect(wait foo()).toEqual([1,2]);
|                         ^
5 | });
6 |
7 |
反对。(src/foo.test.js:4:25)

在阅读了很多之后,我似乎无法在CreateReact应用程序中使用
\uuuu mocks\uuuuu
。问题是什么?

问题是CRA的默认Jest设置会自动重置模拟,从而删除您设置的
mockResolvedValue


解决此问题的一种方法是从模块中公开mock函数,这也为您提供了更多的控制,使您可以在不同的测试中使用不同的值(例如,测试错误处理)并断言调用的内容:

export const mockListForOrg=jest.fn(); export const Octokit=jest.fn().mockImplementation(()=>({ 回购协议:{ listForOrg:mockListForOrg, }, })); 然后,在Jest将其重置后,在测试中配置所需的值:

从“@octokit/rest”导入{mockListForOrg};
从“/foo”导入{foo};
测试(“foo应该为true”,async()=>{
mockListForOrg.mockResolvedValueOnce([1,2]);
expect(wait foo()).toEqual([1,2]);
});

另一个选项是将以下内容添加到您的
包.json
中以覆盖该配置,根据:

{
...
“笑话”:{
“重置模拟”:错误
}
}
但是,这可能会导致在测试之间保留模拟状态(接收到的调用)的问题,因此您需要确保它们在某个地方被清除和/或重置


请注意,您通常不应该嘲笑您没有的东西,但是-如果
@octokit/rest
的接口更改,您的测试将继续通过,但您的代码将无法工作。为了避免这一问题,我建议采用以下两种方法之一:

  • 将断言移动到传输层,例如使用以检查是否发出了正确的请求;或
  • 编写一个简单的外观,包装
    @octokit/rest
    ,将您的代码与您不拥有的接口分离,并模仿它
以及更高级别(端到端)的测试,以确保一切都能与真正的GitHub API一起正常工作

事实上,删除模拟并使用MSW编写此类测试:

从“msw”导入{rest};
从“msw/node”导入{setupServer};
从“/foo”导入{foo};
const server=setupServer(rest.get(“https://api.github.com/orgs/octokit/repos“,(请求、res、ctx)=>{
返回res(ctx.status(200),ctx.json([1,2]);
}));
之前(()=>server.listen());
毕竟(()=>server.close());
测试(“foo应该为true”,async()=>{
expect(wait foo()).toEqual([1,2]);
});
暴露出当前关于
octokit.repos.listForOrg
将返回什么的假设是不准确的,因为此测试失败:

● 福应该是真的
expect(received).toEqual(expected)//深度相等
预期:[1,2]
收到:{“数据”:[1,2],“标题”:{“内容类型”:“应用程序/json”,“x-powered-by”:“msw”},“状态”:200,“url”:https://api.github.com/orgs/octokit/repos?type=public"}
13 | 
14 |测试(“foo应该为true”,async()=>{
>15 | expect(wait foo()).toEqual([1,2]);
|