MSW在单个测试中第二次无法与更新的数据匹配相同的请求

发布于 2025-01-25 09:45:10 字数 3363 浏览 5 评论 0原文

我有一个简单的用RTK查询挂钩生成的房屋列表,其中可以标记为喜欢的项目,并根据标签无效自动进行数据倒置。当我在测试中运行项目时,一切都可以匹配MSW中的第二次匹配,在突变成功后通过标签无效触发了该请求。

服务:

export const homesApi = createApi({
reducerPath: 'homesApi',
baseQuery: fetchBaseQuery({
  baseUrl: API_URL,
  prepareHeaders: (headers, { getState }) => {
    headers.set('Accept', `application/json`);
    return headers;
  },
}),
tagTypes: [
  'Homes',
],
endpoints: (builder) => ({
  getHomes: builder.query({
    query: (params) => {
      
      const url = qs.stringifyUrl(
        { url: '/homes', query: params },
        { skipEmptyString: true, skipNull: true }
      );

      return url

    },
    providesTags: (result) =>
      result?.data
        ? [
            ...result.data.map(({ id }) => ({ type: 'Homes', id })),
            { type: 'Homes', id: 'LIST' },
          ]
        : [{ type: 'Homes', id: 'LIST' }],
  }),
  homeFavorite: builder.mutation({
    query(payload) {

      const {id} = payload;
      const url = `/homes/${id}/favorite`;

      return {
        url,
        method: 'POST'
      };

    },
    invalidatesTags: () => [{ type: 'Homes', id: 'LIST' }],
  }),
}),
});

export const {
  useGetHomesQuery,
  useHomeFavoriteMutation
} = homesApi;

测试:

const store = configureStore({
  reducer: {
    [homesApi.reducerPath]: homesApi.reducer,
  },
  middleware: (getDefaultMiddleware) =>
   getDefaultMiddleware({
      serializableCheck: false,
      immutableCheck: false,
   }).concat(
      homesApi.middleware
   ),
});

setupListeners(store.dispatch);

let cleanupListeners;

describe('Homes component', () => {
    beforeEach(() => {
        cleanupListeners = setupListeners(store.dispatch)
    })

    afterEach(() => {
        cleanupListeners();
        store.dispatch(homesApi.util.resetApiState())
    });

    it('should mark item favorite', async() => {
     
       server.use(
          rest.get(`${API_URL}/homes`, (req, res, ctx) => {
            return res(
              ctx.json(MOCK_SUCCESS)
            );
          }), 
          rest.post(`${API_URL}/homes/1/favorite`, (req, res, ctx) => {
            return res(
              ctx.json({})
            );
          }),
        );

      render(
        <Provider store={store}>
            <BrowserRouter>
                <Routes>
                    <Route path={'/'} element={<Homes/>}/>
                </Routes>
            </BrowserRouter>
        </Provider>
      );

      const user = userEvent.setup();
      const items = await screen.findAllByTestId('homeItem');

      expect(items.length).toBe(5);

      const icon = within(items[0]).getByTestId('fIcon');

      expect(icon).not.toHaveClass('fav');
    
      await user.click(icon);

     //here I try to match the request for the second time with new data
      server.use(
        rest.get(`${API_URL}/homes`, (req, res, ctx) => {
            return res(
              ctx.json(MOCK_SUCCESS_UPDATED)
            );
        }), 
      )

      const itemsNew = await screen.findAllByTestId('homeItem');

      expect(within(itemsNew[0]).getByTestId('fIcon')).toHaveClass('fav');
      
    })
});

任何想法我在做什么错,因为无论我尝试什么,我都无法第二次匹配相同的获取请求。以下是我遇到的错误

[MSW]警告:捕获了无匹配请求处理程序的请求:

I have a simple list of homes generated with RTK query hooks where item can be marked favorite and data refetched automatically based on tags invalidation. While everything works when I run the project within the test msw is not able to match the same GET request called second time after mutation success triggers it via tags invalidation.

service:

export const homesApi = createApi({
reducerPath: 'homesApi',
baseQuery: fetchBaseQuery({
  baseUrl: API_URL,
  prepareHeaders: (headers, { getState }) => {
    headers.set('Accept', `application/json`);
    return headers;
  },
}),
tagTypes: [
  'Homes',
],
endpoints: (builder) => ({
  getHomes: builder.query({
    query: (params) => {
      
      const url = qs.stringifyUrl(
        { url: '/homes', query: params },
        { skipEmptyString: true, skipNull: true }
      );

      return url

    },
    providesTags: (result) =>
      result?.data
        ? [
            ...result.data.map(({ id }) => ({ type: 'Homes', id })),
            { type: 'Homes', id: 'LIST' },
          ]
        : [{ type: 'Homes', id: 'LIST' }],
  }),
  homeFavorite: builder.mutation({
    query(payload) {

      const {id} = payload;
      const url = `/homes/${id}/favorite`;

      return {
        url,
        method: 'POST'
      };

    },
    invalidatesTags: () => [{ type: 'Homes', id: 'LIST' }],
  }),
}),
});

export const {
  useGetHomesQuery,
  useHomeFavoriteMutation
} = homesApi;

test:

const store = configureStore({
  reducer: {
    [homesApi.reducerPath]: homesApi.reducer,
  },
  middleware: (getDefaultMiddleware) =>
   getDefaultMiddleware({
      serializableCheck: false,
      immutableCheck: false,
   }).concat(
      homesApi.middleware
   ),
});

setupListeners(store.dispatch);

let cleanupListeners;

describe('Homes component', () => {
    beforeEach(() => {
        cleanupListeners = setupListeners(store.dispatch)
    })

    afterEach(() => {
        cleanupListeners();
        store.dispatch(homesApi.util.resetApiState())
    });

    it('should mark item favorite', async() => {
     
       server.use(
          rest.get(`${API_URL}/homes`, (req, res, ctx) => {
            return res(
              ctx.json(MOCK_SUCCESS)
            );
          }), 
          rest.post(`${API_URL}/homes/1/favorite`, (req, res, ctx) => {
            return res(
              ctx.json({})
            );
          }),
        );

      render(
        <Provider store={store}>
            <BrowserRouter>
                <Routes>
                    <Route path={'/'} element={<Homes/>}/>
                </Routes>
            </BrowserRouter>
        </Provider>
      );

      const user = userEvent.setup();
      const items = await screen.findAllByTestId('homeItem');

      expect(items.length).toBe(5);

      const icon = within(items[0]).getByTestId('fIcon');

      expect(icon).not.toHaveClass('fav');
    
      await user.click(icon);

     //here I try to match the request for the second time with new data
      server.use(
        rest.get(`${API_URL}/homes`, (req, res, ctx) => {
            return res(
              ctx.json(MOCK_SUCCESS_UPDATED)
            );
        }), 
      )

      const itemsNew = await screen.findAllByTestId('homeItem');

      expect(within(itemsNew[0]).getByTestId('fIcon')).toHaveClass('fav');
      
    })
});

any idea what am I doing wrong since I am not able to match the same GET request for the second time no matter what I try. below is the error I am getting

[MSW] Warning: captured a request without a matching request handler:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蝶舞 2025-02-01 09:45:10

尝试使用

https://mswjs.io/docs/docs/api/api/response/once/once/once

基本思想是res.once模拟响应,完全是1个API调用

,如果您两次调用相同的端点,它只会响应一次

是我的用例删除数据,以便在UI中存在更新的数据,

请尝试使用全局处理程序,并且在您的测试中进行:

server.use(
  rest.get('your/endpoint', (req, res, ctx) => 
    res.**once**(ctx.json(replaceDataHereWithDesiredResponse))
  )
)

当然,两次,上面的代码在同一测试子句中

try out with

https://mswjs.io/docs/api/response/once

basic idea that res.once mock response for exactly 1 api call

if you call the same endpoint twice, it will only respond once

here is my use case, I fetch data, i then run a post request to add data, then i need to refetch the data so that the updated data is present in UI,

try with no global handler, and in your test, do:

server.use(
  rest.get('your/endpoint', (req, res, ctx) => 
    res.**once**(ctx.json(replaceDataHereWithDesiredResponse))
  )
)

twice, of course, above codes were in the same test clause

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文