react-testing-library配合MSW测试时await后仍处于加载状态的解决方案
已解决
唉!折腾了5小时终于找到问题根源:GraphQL fragments 和 MSW 存在兼容性问题。
问题背景
我使用MSW搭建了Mock GraphQL服务,基础配置如下,我会将其导入测试文件中使用:
// Setup requests interception using the given handlers. export const server = setupServer(...handlers); export function setup() { beforeAll(() => { // Enable the mocking in tests. server.listen(); }); beforeEach(() => { // Ensure Apollo cache is cleared between tests. return client.clearStore(); }); afterEach(() => { // Reset any runtime handlers tests may use. server.resetHandlers(); }); afterAll(() => { // Clean up once the tests are done. server.close(); }); }
我可以确认我的查询请求确实被MSW成功拦截,且响应也正确返回:
graphql.query('getAgenda', (req, res, ctx) => { console.debug('in handlers') const { id } = req.variables; if (id === '1') { console.debug('returning res') return res( ctx.data({ agenda, }) ); } }),
运行时的日志输出如下:
console.debug undefined at Component (src/pages/Agenda/ViewAgenda.js:70:10) console.debug undefined at Component (src/pages/Agenda/ViewAgenda.js:71:10) console.debug in handlers at resolver (src/__tests__/__mocks__/handlers.js:8:11) console.debug returning res at resolver (src/__tests__/__mocks__/handlers.js:12:11) console.debug undefined at Component (src/pages/Agenda/ViewAgenda.js:70:10) console.debug undefined at Component (src/pages/Agenda/ViewAgenda.js:71:10) console.debug in handlers at resolver (src/__tests__/__mocks__/handlers.js:8:11) console.debug returning res at resolver (src/__tests__/__mocks__/handlers.js:12:11) console.debug undefined at Component (src/pages/Agenda/ViewAgenda.js:70:10) console.debug undefined at Component (src/pages/Agenda/ViewAgenda.js:71:10) console.debug in handlers at resolver (src/__tests__/__mocks__/handlers.js:8:11) console.debug returning res at resolver (src/__tests__/__mocks__/handlers.js:12:11) console.debug undefined at Component (src/pages/Agenda/ViewAgenda.js:70:10) console.debug undefined at Component (src/pages/Agenda/ViewAgenda.js:71:10) console.debug in handlers at resolver (src/__tests__/__mocks__/handlers.js:8:11) console.debug returning res at resolver (src/__tests__/__mocks__/handlers.js:12:11)
日志中的undefined是我在组件中打印data的输出,我在debugger中也确认data始终没有被成功解析赋值。
我的测试用例代码如下:
it('matches its returned data snapshot', async () => { const history = createMemoryHistory(); history.push('/agenda/1'); const { asFragment } = render(<ViewAgenda />, { wrapperProps: { history }}); await screen.findByText('Planerat mötesdatum'); expect(asFragment(<ViewAgenda />)).toMatchSnapshot(); });
我已经使用了await screen等待元素渲染,也确认问题和路由无关:对应路由的handler被正确触发,组件内的打印日志也正常输出。
问题根因
出现该问题的核心原因是Apollo Client的规范化缓存依赖__typename字段匹配GraphQL fragment的定义类型,而MSW返回的Mock数据默认不会自动注入__typename属性,导致Apollo认为返回的数据和fragment定义不匹配,直接将解析后的data赋值为undefined。
解决方案
- 手动给Mock数据添加对应类型的
__typename属性,比如你的fragment定义在Agenda类型上,就给返回的agenda对象添加__typename: 'Agenda',如果有嵌套子对象也用到了fragment,对应层级也要添加对应类型的__typename。示例修改后的handler代码如下:
graphql.query('getAgenda', (req, res, ctx) => { console.debug('in handlers') const { id } = req.variables; // 给agenda加__typename const agendaWithTypename = { ...agenda, __typename: 'Agenda' } if (id === '1') { console.debug('returning res') return res( ctx.data({ agenda: agendaWithTypename, }) ); } }),
- 如果你使用的是MSW v2以上版本,可以开启GraphQL自动注入typename的配置,无需手动给每个返回对象加字段。
- 临时验证可以先去掉查询语句中的fragment,直接写全所有请求字段,如果此时data可以正常返回,即可确认是fragment匹配导致的问题。
内容的提问来源于stack exchange,提问作者Cookie
相关产品推荐
相关产品推荐

