Redux - Testing Slices & Thunks

Unit-test Redux logic without external tools by calling reducers and thunks directly and asserting results.

Try it: Test a slice reducer

View source
const { createSlice } = RTK;
function assert(name, cond){ const el=document.getElementById('test-out'); const li=document.createElement('li'); li.textContent=`${cond?'PASS':'FAIL'} - ${name}`; li.style.color=cond?'limegreen':'salmon'; el.appendChild(li); }
const slice = createSlice({ name:'counter', initialState:{value:0}, reducers:{ inc(s){s.value++}, addBy(s,a){s.value+=a.payload} } });
const r = slice.reducer;
let s = { value:0 };
s = r(s, slice.actions.inc());
assert('inc increments', s.value===1);
s = r(s, slice.actions.addBy(4));
assert('addBy adds payload', s.value===5);

    Try it: Test an async thunk

    View source
    const { createSlice, configureStore, createAsyncThunk } = RTK;
    const fetchData = createAsyncThunk('d/fetch', async ()=>{ await new Promise(r=>setTimeout(r,50)); return 42; });
    const slice2 = createSlice({ name:'d', initialState:{status:'idle', value:null}, reducers:{}, extraReducers:b=>{
      b.addCase(fetchData.pending,(s)=>{s.status='loading'})
       .addCase(fetchData.fulfilled,(s,a)=>{s.status='succeeded'; s.value=a.payload})
       .addCase(fetchData.rejected,(s)=>{s.status='failed'})
    }});
    const store = configureStore({ reducer:{ d:slice2.reducer } });
    (async function(){
      function assert(name, cond){ const el=document.getElementById('test-out2'); const li=document.createElement('li'); li.textContent=`${cond?'PASS':'FAIL'} - ${name}`; li.style.color=cond?'limegreen':'salmon'; el.appendChild(li); }
      let s = store.getState();
      assert('initial idle', s.d.status==='idle');
      const p = store.dispatch(fetchData());
      s = store.getState();
      assert('pending', s.d.status==='loading');
      await p; s = store.getState();
      assert('fulfilled', s.d.status==='succeeded' && s.d.value===42);
    })();