如何使用redux-toolkit的slice来测试thunk?

huangapple go评论73阅读模式
英文:

How to test thunk with redux-toolkit slice?

问题

这是您的代码片段的翻译:

我有一个简单的THUNK

import { AppDispatch } from "../store";
import { Api } from "../../shared/api/index";
import { registrationFormSlice } from "../registration";

export const logIn =
  (email: string, password: string) =>
  async (dispatch: AppDispatch) => {
    try {         
      const { status } = await Api.auth.logIn({ email, password });
      if (status === 200) {
        dispatch(registrationFormSlice.actions.reset());
      }          
    } catch (error: any) {
      console.error(error);
    }
  };

请问还有其他需要翻译的内容吗?

英文:

I have a simple THUNK:

import { AppDispatch } from "../store";
import { Api } from "../../shared/api/index";
import { registrationFormSlice } from "../registration";

export const logIn =
  (email: string, password: string) =>
  async (dispatch: AppDispatch) => {
    try {         
      const { status } = await Api.auth.logIn({ email, password });
      if (status === 200) {
        dispatch(registrationFormSlice.actions.reset());
      }          
    } catch (error: any) {
      console.error(error);
    }
  };

How can I test it?

I tried to find the answer on my own, but everything I could find did not give an answer or was very difficult to understand. I can't even write how I'm testing this THUNK as I can't figure out where to start.

答案1

得分: 0

如果你只想测试与操作相关的逻辑,可以使用 redux-mock-store 包。

> 用于测试 Redux 异步 action creators 和 middleware 的模拟 store。模拟 store 会创建一个包含已分发的 actions 的数组,用作测试的 action 记录。

> 请注意,该库旨在测试与 action 相关的逻辑,而不是 reducer 相关的逻辑。

例如:

api.ts:

const Api = {
  auth: {
    async logIn(payload) {
      return fetch('http://localhost:3000/api/login')
    }
  }
}

export { Api }

registration.ts:

import { createSlice } from '@reduxjs/toolkit';

const registrationFormSlice = createSlice({
  name: 'registration',
  initialState: {},
  reducers: {
    reset() { }
  }
})

export { registrationFormSlice }

thunk.ts:

import { Api } from "./api";
import { registrationFormSlice } from "./registration";

type AppDispatch = any;

export const logIn =
  (email: string, password: string) =>
    async (dispatch: AppDispatch) => {
      try {
        const { status } = await Api.auth.logIn({ email, password });
        if (status === 200) {
          dispatch(registrationFormSlice.actions.reset());
        }
      } catch (error: any) {
        console.error(error);
      }
    };

thunk.test.ts:

import { AnyAction } from 'redux';
import configureStore, { MockStoreCreator } from 'redux-mock-store'
import thunk, { ThunkDispatch } from 'redux-thunk'
import { logIn } from './thunk';
import { Api } from "./api";
import { registrationFormSlice } from './registration';

type RootState = any;

const middlewares = [thunk]
type DispatchExts = ThunkDispatch<RootState, undefined, AnyAction>
const mockStoreCreator: MockStoreCreator<RootState, DispatchExts> =
  configureStore<RootState, DispatchExts>(middlewares)


describe('thunk', () => {
  afterEach(() => {
    jest.restoreAllMocks();
  })
  test('should pass', () => {
    jest.spyOn(Api.auth, 'logIn').mockResolvedValue({ status: 200 } as unknown as Response)
    const store = mockStoreCreator();
    return store.dispatch(logIn('example@gmail.com', '123')).then(() => {
      const actions = store.getActions();
      expect(actions).toEqual([registrationFormSlice.actions.reset()])
    })
  })
})

测试结果:

 PASS  stackoverflow/76302702/thunk.test.ts (19.876 s)
  thunk
    ✓ should pass (7 ms)

-----------------|---------|----------|---------|---------|-------------------
File             | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------------|---------|----------|---------|---------|-------------------
All files        |   88.24 |       50 |      60 |    87.5 |                   
 api.ts          |   66.67 |      100 |       0 |   66.67 | 4                 
 registration.ts |     100 |      100 |       0 |     100 |                   
 thunk.ts        |   90.91 |       50 |     100 |      90 | 15                
-----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        21.879 s
英文:

If you only want to test the action-related logic, you can use redux-mock-store package.

> A mock store for testing Redux async action creators and middleware. The mock store will create an array of dispatched actions which serve as an action log for tests.

> Please note that this library is designed to test the action-related logic, not the reducer-related one.

E.g.

api.ts:

const Api = {
  auth: {
    async logIn(payload) {
      return fetch(&#39;http://localhost:3000/api/login&#39;)
    }
  }
}

export { Api }

registration.ts:

import { createSlice } from &#39;@reduxjs/toolkit&#39;;

const registrationFormSlice = createSlice({
  name: &#39;registration&#39;,
  initialState: {},
  reducers: {
    reset() { }
  }
})

export { registrationFormSlice }

thunk.ts:

import { Api } from &quot;./api&quot;;
import { registrationFormSlice } from &quot;./registration&quot;;

type AppDispatch = any;

export const logIn =
  (email: string, password: string) =&gt;
    async (dispatch: AppDispatch) =&gt; {
      try {
        const { status } = await Api.auth.logIn({ email, password });
        if (status === 200) {
          dispatch(registrationFormSlice.actions.reset());
        }
      } catch (error: any) {
        console.error(error);
      }
    };

thunk.test.ts:

import { AnyAction } from &#39;redux&#39;;
import configureStore, { MockStoreCreator } from &#39;redux-mock-store&#39;
import thunk, { ThunkDispatch } from &#39;redux-thunk&#39;
import { logIn } from &#39;./thunk&#39;;
import { Api } from &quot;./api&quot;;
import { registrationFormSlice } from &#39;./registration&#39;;

type RootState = any;

const middlewares = [thunk]
type DispatchExts = ThunkDispatch&lt;RootState, undefined, AnyAction&gt;
const mockStoreCreator: MockStoreCreator&lt;RootState, DispatchExts&gt; =
  configureStore&lt;RootState, DispatchExts&gt;(middlewares)


describe(&#39;thunk&#39;, () =&gt; {
  afterEach(() =&gt; {
    jest.restoreAllMocks();
  })
  test(&#39;should pass&#39;, () =&gt; {
    jest.spyOn(Api.auth, &#39;logIn&#39;).mockResolvedValue({ status: 200 } as unknown as Response)
    const store = mockStoreCreator();
    return store.dispatch(logIn(&#39;example@gmail.com&#39;, &#39;123&#39;)).then(() =&gt; {
      const actions = store.getActions();
      expect(actions).toEqual([registrationFormSlice.actions.reset()])
    })
  })
})

Test result:

 PASS  stackoverflow/76302702/thunk.test.ts (19.876 s)
  thunk
    ✓ should pass (7 ms)

-----------------|---------|----------|---------|---------|-------------------
File             | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------------|---------|----------|---------|---------|-------------------
All files        |   88.24 |       50 |      60 |    87.5 |                   
 api.ts          |   66.67 |      100 |       0 |   66.67 | 4                 
 registration.ts |     100 |      100 |       0 |     100 |                   
 thunk.ts        |   90.91 |       50 |     100 |      90 | 15                
-----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        21.879 s

huangapple
  • 本文由 发表于 2023年5月22日 10:20:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76302702.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定