在测试之间清除 Apollo 缓存

Posted

技术标签:

【中文标题】在测试之间清除 Apollo 缓存【英文标题】:Clear Apollo cache between tests 【发布时间】:2021-12-01 09:07:05 【问题描述】:

我有一个要测试的组件,但似乎 Apollo 的缓存在测试之间没有被清除。我正在使用 React 测试库和 Jest。

以下是我测试相反情况的几个测试:

it('shows a "show more" button when there is `hasNextPage` is true', async () => 
  render(
    <MemoryRouter initialEntries=['/media/1']>
      <MockedProvider mocks=[getCharacterMock, getMediaMock] cache=cache>
        <Route path='/media/:id'>
          <Media />
        </Route>
      </MockedProvider>
    </MemoryRouter>
  );

  await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
  userEvent.click(screen.getByRole('button',  name: /characters/i ));
  await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
  expect(screen.getByRole('button',  name: /show more/i )).toBeInTheDocument();
);

it("doesn't show a 'show more' button when `hasNextPage` is false", async () => 
  render(
    <MemoryRouter initialEntries=['/media/1']>
      <MockedProvider mocks=[getCharacterMockNextPageFalse, getMediaMock] cache=cache>
        <Route path='/media/:id'>
          <Media />
        </Route>
      </MockedProvider>
    </MemoryRouter>
  );

  await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
  userEvent.click(screen.getByRole('button',  name: /characters/i ));
  await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
  expect(screen.queryByText(/show more/i)).toBeNull();
);

第一个测试通过,但第二个测试失败,因为屏幕上根本没有“加载”。记录到控制台的 DOM 显示该组件已经使用它应该从模拟 getMediaMock 获取的数据进行了渲染。如果我注释掉到 waitForElementToBeRemoved 行,那么测试就会失败,因为实际上呈现了“显示更多”,即使模拟 getCharacterMockNextPageFalsehasNextPage 设置为 false(这将表示不应呈现“显示更多”按钮)。我能想到发生这种情况的唯一原因是因为测试使用了之前测试中的模拟数据,其中hasNextPage 设置为true

有没有办法在测试之间清除缓存?还是有其他原因导致了这种行为?

【问题讨论】:

【参考方案1】:

所以,据我所知,如果测试使用相同的 Apollo 缓存,那么每次测试都将使用完全相同的缓存(即不会在测试之间清除它)。在这种情况下我修复它的方法只是从第二个测试的MockedProvider 中删除缓存(因为我在这个测试中并不真正需要它),但是创建一个具有相同设置的新inMemoryCache 测试会也起作用了。

第二个测试现在看起来像这样:

it("doesn't show a 'show more' button when `hasNextPage` is false", async () => 
  render(
    <MemoryRouter initialEntries=['/media/1']>
      <MockedProvider mocks=[getCharacterMockNextPageFalse, getMediaMock]>
        <Route path='/media/:id'>
          <Media />
        </Route>
      </MockedProvider>
    </MemoryRouter>
  );
  await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
  userEvent.click(screen.getByRole('button',  name: /characters/i ));
  await waitForElementToBeRemoved(() => screen.getByText(/loading/i));
  expect(screen.queryByText(/show more/i)).toBeNull();
);

【讨论】:

您是否尝试过在查询中使用绕过标志?请参阅:apollographql.com/docs/react/caching/advanced-topics/… 否则,您还可以使用 beforeEach 在测试之间重置缓存 请参阅:apollographql.com/docs/react/caching/advanced-topics/… beforeEach:jestjs.io/docs/setup-teardown

以上是关于在测试之间清除 Apollo 缓存的主要内容,如果未能解决你的问题,请参考以下文章

使用 apollo 缓存调用一次存储的 fetch API?

Apollo 客户端:在清除或重置存储时保留/重置默认值

为啥我的 Apollo 缓存更新没有反映在我的查询中?

刷新页面时,apollo-state-link 不在缓存中保存状态

有没有办法在 Apollo Gateway 和联合服务之间添加缓存?

watchQuery (Angular-Apollo) 的缓存管理