Skip to content

Commit

Permalink
fix reduxjs#541: invoke removeAll mutably within produce (reduxjs#544)
Browse files Browse the repository at this point in the history
add tests
  • Loading branch information
phryneas authored May 9, 2020
1 parent b835eae commit 9a37bd7
Showing 4 changed files with 542 additions and 5 deletions.
260 changes: 260 additions & 0 deletions src/entities/sorted_state_adapter.test.ts
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import {
AClockworkOrange,
AnimalFarm
} from './fixtures/book'
import { createNextState } from '..'

describe('Sorted State Adapter', () => {
let adapter: EntityStateAdapter<BookModel>
@@ -436,4 +437,263 @@ describe('Sorted State Adapter', () => {
}
})
})

describe('can be used mutably when wrapped in createNextState', () => {
test('removeAll', () => {
const withTwo = adapter.addMany(state, [TheGreatGatsby, AnimalFarm])
const result = createNextState(withTwo, draft => {
adapter.removeAll(draft)
})
expect(result).toMatchInlineSnapshot(`
Object {
"entities": Object {},
"ids": Array [],
}
`)
})

test('addOne', () => {
const result = createNextState(state, draft => {
adapter.addOne(draft, TheGreatGatsby)
})

expect(result).toMatchInlineSnapshot(`
Object {
"entities": Object {
"tgg": Object {
"id": "tgg",
"title": "The Great Gatsby",
},
},
"ids": Array [
"tgg",
],
}
`)
})

test('addMany', () => {
const result = createNextState(state, draft => {
adapter.addMany(draft, [TheGreatGatsby, AnimalFarm])
})

expect(result).toMatchInlineSnapshot(`
Object {
"entities": Object {
"af": Object {
"id": "af",
"title": "Animal Farm",
},
"tgg": Object {
"id": "tgg",
"title": "The Great Gatsby",
},
},
"ids": Array [
"af",
"tgg",
],
}
`)
})

test('setAll', () => {
const result = createNextState(state, draft => {
adapter.setAll(draft, [TheGreatGatsby, AnimalFarm])
})

expect(result).toMatchInlineSnapshot(`
Object {
"entities": Object {
"af": Object {
"id": "af",
"title": "Animal Farm",
},
"tgg": Object {
"id": "tgg",
"title": "The Great Gatsby",
},
},
"ids": Array [
"af",
"tgg",
],
}
`)
})

test('updateOne', () => {
const withOne = adapter.addOne(state, TheGreatGatsby)
const changes = { title: 'A New Hope' }
const result = createNextState(withOne, draft => {
adapter.updateOne(draft, {
id: TheGreatGatsby.id,
changes
})
})

expect(result).toMatchInlineSnapshot(`
Object {
"entities": Object {
"tgg": Object {
"id": "tgg",
"title": "A New Hope",
},
},
"ids": Array [
"tgg",
],
}
`)
})

test('updateMany', () => {
const firstChange = { title: 'First Change' }
const secondChange = { title: 'Second Change' }
const withMany = adapter.setAll(state, [TheGreatGatsby, AClockworkOrange])

const result = createNextState(withMany, draft => {
adapter.updateMany(draft, [
{ id: TheGreatGatsby.id, changes: firstChange },
{ id: AClockworkOrange.id, changes: secondChange }
])
})

expect(result).toMatchInlineSnapshot(`
Object {
"entities": Object {
"aco": Object {
"id": "aco",
"title": "Second Change",
},
"tgg": Object {
"id": "tgg",
"title": "First Change",
},
},
"ids": Array [
"tgg",
"aco",
],
}
`)
})

test('upsertOne (insert)', () => {
const result = createNextState(state, draft => {
adapter.upsertOne(draft, TheGreatGatsby)
})
expect(result).toMatchInlineSnapshot(`
Object {
"entities": Object {
"tgg": Object {
"id": "tgg",
"title": "The Great Gatsby",
},
},
"ids": Array [
"tgg",
],
}
`)
})

test('upsertOne (update)', () => {
const withOne = adapter.upsertOne(state, TheGreatGatsby)
const result = createNextState(withOne, draft => {
adapter.upsertOne(draft, {
id: TheGreatGatsby.id,
title: 'A New Hope'
})
})
expect(result).toMatchInlineSnapshot(`
Object {
"entities": Object {
"tgg": Object {
"id": "tgg",
"title": "A New Hope",
},
},
"ids": Array [
"tgg",
],
}
`)
})

test('upsertMany', () => {
const withOne = adapter.upsertOne(state, TheGreatGatsby)
const result = createNextState(withOne, draft => {
adapter.upsertMany(draft, [
{
id: TheGreatGatsby.id,
title: 'A New Hope'
},
AnimalFarm
])
})
expect(result).toMatchInlineSnapshot(`
Object {
"entities": Object {
"af": Object {
"id": "af",
"title": "Animal Farm",
},
"tgg": Object {
"id": "tgg",
"title": "A New Hope",
},
},
"ids": Array [
"tgg",
"af",
],
}
`)
})

test('removeOne', () => {
const withTwo = adapter.addMany(state, [TheGreatGatsby, AnimalFarm])
const result = createNextState(withTwo, draft => {
adapter.removeOne(draft, TheGreatGatsby.id)
})
expect(result).toMatchInlineSnapshot(`
Object {
"entities": Object {
"af": Object {
"id": "af",
"title": "Animal Farm",
},
},
"ids": Array [
"af",
],
}
`)
})

test('removeMany', () => {
const withThree = adapter.addMany(state, [
TheGreatGatsby,
AnimalFarm,
AClockworkOrange
])
const result = createNextState(withThree, draft => {
adapter.removeMany(draft, [TheGreatGatsby.id, AnimalFarm.id])
})
expect(result).toMatchInlineSnapshot(`
Object {
"entities": Object {
"aco": Object {
"id": "aco",
"title": "A Clockwork Orange",
},
},
"ids": Array [
"aco",
],
}
`)
})
})
})
16 changes: 15 additions & 1 deletion src/entities/state_adapter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import createNextState, { isDraft } from 'immer'
import { EntityState } from './models'
import { EntityState, PreventAny } from './models'
import { PayloadAction, isFSA } from '../createAction'

export function createSingleArgumentStateOperator<V>(
mutator: (state: EntityState<V>) => void
) {
const operator = createStateOperator((_: undefined, state: EntityState<V>) =>
mutator(state)
)

return function operation<S extends EntityState<V>>(
state: PreventAny<S, V>
): S {
return operator(state as S, undefined)
}
}

export function createStateOperator<V, R>(
mutator: (arg: R, state: EntityState<V>) => void
) {
Loading

0 comments on commit 9a37bd7

Please sign in to comment.