| 1 | import type { EntityAdapter } from '../index'
|
|---|
| 2 | import { createEntityAdapter } from '../index'
|
|---|
| 3 | import type { PayloadAction } from '../../createAction'
|
|---|
| 4 | import { configureStore } from '../../configureStore'
|
|---|
| 5 | import { createSlice } from '../../createSlice'
|
|---|
| 6 | import type { BookModel } from './fixtures/book'
|
|---|
| 7 |
|
|---|
| 8 | describe('createStateOperator', () => {
|
|---|
| 9 | let adapter: EntityAdapter<BookModel, string>
|
|---|
| 10 |
|
|---|
| 11 | beforeEach(() => {
|
|---|
| 12 | adapter = createEntityAdapter({
|
|---|
| 13 | selectId: (book: BookModel) => book.id,
|
|---|
| 14 | })
|
|---|
| 15 | })
|
|---|
| 16 | it('Correctly mutates a draft state when inside `createNextState', () => {
|
|---|
| 17 | const booksSlice = createSlice({
|
|---|
| 18 | name: 'books',
|
|---|
| 19 | initialState: adapter.getInitialState(),
|
|---|
| 20 | reducers: {
|
|---|
| 21 | // We should be able to call an adapter method as a mutating helper in a larger reducer
|
|---|
| 22 | addOne(state, action: PayloadAction<BookModel>) {
|
|---|
| 23 | // Originally, having nested `produce` calls don't mutate `state` here as I would have expected.
|
|---|
| 24 | // (note that `state` here is actually an Immer Draft<S>, from `createReducer`)
|
|---|
| 25 | // One woarkound was to return the new plain result value instead
|
|---|
| 26 | // See https://github.com/immerjs/immer/issues/533
|
|---|
| 27 | // However, after tweaking `createStateOperator` to check if the argument is a draft,
|
|---|
| 28 | // we can just treat the operator as strictly mutating, without returning a result,
|
|---|
| 29 | // and the result should be correct.
|
|---|
| 30 | const result = adapter.addOne(state, action)
|
|---|
| 31 | expect(result.ids.length).toBe(1)
|
|---|
| 32 | //Deliberately _don't_ return result
|
|---|
| 33 | },
|
|---|
| 34 | // We should also be able to pass them individually as case reducers
|
|---|
| 35 | addAnother: adapter.addOne,
|
|---|
| 36 | },
|
|---|
| 37 | })
|
|---|
| 38 |
|
|---|
| 39 | const { addOne, addAnother } = booksSlice.actions
|
|---|
| 40 |
|
|---|
| 41 | const store = configureStore({
|
|---|
| 42 | reducer: {
|
|---|
| 43 | books: booksSlice.reducer,
|
|---|
| 44 | },
|
|---|
| 45 | })
|
|---|
| 46 |
|
|---|
| 47 | const book1: BookModel = { id: 'a', title: 'First' }
|
|---|
| 48 | store.dispatch(addOne(book1))
|
|---|
| 49 |
|
|---|
| 50 | const state1 = store.getState()
|
|---|
| 51 | expect(state1.books.ids.length).toBe(1)
|
|---|
| 52 | expect(state1.books.entities['a']).toBe(book1)
|
|---|
| 53 |
|
|---|
| 54 | const book2: BookModel = { id: 'b', title: 'Second' }
|
|---|
| 55 | store.dispatch(addAnother(book2))
|
|---|
| 56 |
|
|---|
| 57 | const state2 = store.getState()
|
|---|
| 58 | expect(state2.books.ids.length).toBe(2)
|
|---|
| 59 | expect(state2.books.entities['b']).toBe(book2)
|
|---|
| 60 | })
|
|---|
| 61 | })
|
|---|