You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jest测试Next.js+Typesense应用时如何Mock搜索请求返回自定义数据

Jest/RTL 环境下Mock Typesense搜索请求方案

你可以根据测试场景选以下两种实现,都能完全拦截发往Typesense的请求、自定义返回内容,不会触发真实后端调用。


方案1:模块级Mock Typesense适配器(推荐,灵活度最高)

你的代码里是通过TypesenseInstantSearchAdapter生成searchClient传给InstantSearch,直接Mock整个适配器模块是侵入性最低、控制粒度最细的方案,不需要处理网络层逻辑。

  1. 在测试文件开头,或者Jest全局setup文件中添加模块Mock:
// Mock typesense-instantsearch-adapter模块
jest.mock('typesense-instantsearch-adapter', () => {
  const originalModule = jest.requireActual('typesense-instantsearch-adapter');
  return {
    ...originalModule,
    // 重写适配器构造函数
    default: jest.fn().mockImplementation(() => ({
      searchClient: {
        // 所有搜索请求都会走这个mock的search方法
        search: jest.fn((requests) => {
          // 可根据传入的requests参数(索引名、查询词、过滤条件等)返回不同数据
          return Promise.resolve({
            results: requests.map(req => ({
              hits: [], // 这里替换成你需要的测试返回数据
              nbHits: 0,
              page: 0,
              nbPages: 1,
              hitsPerPage: req.params.hitsPerPage || 20,
              processingTimeMS: 1,
              query: req.params.query || '',
              index: req.indexName
            }))
          })
        })
      }
    }))
  }
})
  1. 单测中可动态修改返回值,覆盖不同场景:
test('搜索无结果时展示空状态', async () => {
  // 取出mock的search方法
  const Adapter = require('typesense-instantsearch-adapter').default;
  const mockSearch = Adapter.mock.results[0].value.searchClient.search;
  // 临时修改本次调用的返回为空结果
  mockSearch.mockResolvedValueOnce({
    results: [{
      hits: [],
      nbHits: 0,
      nbPages: 0,
      page: 0,
      hitsPerPage: 20
    }]
  })

  render(<Home />);
  expect(await screen.findByText('暂无搜索结果')).toBeInTheDocument();
})
  1. 可直接断言请求参数是否符合预期:
expect(mockSearch).toHaveBeenCalledWith(
  expect.arrayContaining([
    expect.objectContaining({
      indexName: SEARCH_INDEX.ITEMS,
      params: expect.objectContaining({
        hitsPerPage: 20
      })
    })
  ])
)

方案2:网络层拦截请求(适合需要监听出站请求的场景)

如果需要校验真实的请求格式、请求头,可以用网络拦截工具直接拦截发往Typesense服务的HTTP请求,最常用的是MSW(Mock Service Worker),和React Testing Library适配无侵入。

  1. 配置MSW拦截规则:
import { rest } from 'msw';
import { setupServer } from 'msw/node';

const testServer = setupServer(
  // 拦截所有域名下符合Typesense搜索规则的POST请求
  rest.post('*/collections/*/documents/search', (req, res, ctx) => {
    // 可从req中读取请求参数、请求头、索引名做分支判断
    return res(
      ctx.status(200),
      ctx.json({
        hits: [], // 替换为自定义测试数据
        found: 0,
        out_of: 0,
        page: 1,
        search_time_ms: 1
      })
    )
  })
)

// 测试生命周期管理
beforeAll(() => testServer.listen());
afterEach(() => testServer.resetHandlers());
afterAll(() => testServer.close());
  1. 单测中可临时修改拦截返回,也可断言请求属性:
test('搜索请求携带正确的API Key', async () => {
  let capturedReq;
  testServer.use(
    rest.post('*/collections/*/documents/search', (req, res, ctx) => {
      capturedReq = req;
      return res(ctx.status(200), ctx.json({ hits: [], found: 0 }))
    })
  )

  render(<Home />);
  await screen.findByText('搜索组件加载完成');
  expect(capturedReq.headers.get('X-TYPESENSE-API-KEY')).toBe('test-user-search-key');
})

注意事项

  • Mock返回的结构需要和Typesense真实返回/InstantSearch要求的字段对齐,至少包含hits、nbHits/found、nbPages、page、hitsPerPage字段,否则组件会渲染报错。
  • 如果项目里用的是axios/fetch发起自定义Typesense请求,也可以直接用jest.mock('axios')或者全局fetch mock拦截,逻辑和MSW一致。

内容的提问来源于stack exchange,提问作者Henrik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 15:39:15