0

I am trying to write my first async thunk with the provided function from Redux Toolkit: createAsyncThunk.

But after hours reading the docs and online instructions, it seems I am missing something as I can't import the action rollDice.

GenerateRandomDice.spec.ts

import { beforeEach, describe, expect, it } from 'vitest'
import { ReduxStore } from '../../../react-view/main'
import { configureStoreWith } from '../../../app/store'
import { Dependencies } from '../../../app/dependencies'
import { InMemoryIdProvider } from '../../../infrastructure/idProvider/InMemoryIdProvider'
import { InMemoryRandomDiceProvider } from '../../../infrastructure/randomDiceProvider/InMemoryRandomDiceProvider'

describe('Generate Random Dice', () => {
  let store: ReduxStore
  let dependencies: Dependencies

  beforeEach(() => {
    dependencies = {
      idProvider: new InMemoryIdProvider(),
      randomDiceProvider: new InMemoryRandomDiceProvider(),
    }
    store = configureStoreWith(dependencies)
  })

  it('should generate 10 random dice', () => {
    store.dispatch(rollDice())
    const state = store.getState()

    expect(state).toBe('something') // I don't expect this to pass, it's not the point
  })
})

diceSlice.ts

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { Dependencies } from '../../app/dependencies'

type ExtraDependencies = {
  extra: Dependencies
}

const rollDice = createAsyncThunk<number, any, ExtraDependencies>(
  `dice/rollDice`,
  async (thunkAPI, { extra: { randomDiceProvider } }) => {
    return randomDiceProvider.generateRandomDieValue()
  },
)

export const initialState = {
  dice: [] as number[],
  loading: false,
  error: null,
}

export const diceSlice = createSlice({
  name: 'dice',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder.addCase(rollDice.fulfilled, (state, action) => {
      state.dice.push(action.payload)
    })
  },
})

export const diceReducer = diceSlice.reducer

As far as I understand it, the createSlice functions should somehow create the action for me, but it's not the case.

Webstorm screenshot

What am I missing?

A Mehmeto
  • 1,594
  • 3
  • 22
  • 37

1 Answers1

0

It seems I found the issue with the help of a forum, so I am posting here for reference.

So first I needed to export the rollDice generated by createAsyncThunk.

That has triggered a first error: createAsyncThunk.d.ts(108, 118): An argument for 'arg' was not provided. So I needed to change the ThunkArg type from any to void.

Second, I had a big no overlap that was resolve by digging in configureStoreWith.

import {
  combineReducers,
  configureStore,
  ThunkMiddleware,
} from '@reduxjs/toolkit'
import { diceSlice } from '../core/dice/diceSlice'
import { Dependencies } from './dependencies'

const rootReducer = combineReducers({
  dice: diceSlice.reducer,
})

export const configureStoreWith = (dependencies: Partial<Dependencies>) =>
  configureStore({
    reducer: rootReducer,
    middleware: (getDefaultMiddleware) =>
      getDefaultMiddleware({
        serializableCheck: false,
        thunk: {
          extraArgument: dependencies,
        },
      }),
  })

I had to remove the Partial to make it work. I'd like to keep it partial so as not to have to instantiate all my dependencies for all the tests, but instead "cherry-instanciate" for the need of the test only.

I am not sure how I could achieve that though.

A Mehmeto
  • 1,594
  • 3
  • 22
  • 37