Skip to content

Latest commit

 

History

History
 
 

__tests__

"use strict"
import produce, {applyPatches} from "../src/index"

describe("readme example", () => {
    it("works", () => {
        const baseState = [
            {
                todo: "Learn typescript",
                done: true
            },
            {
                todo: "Try immer",
                done: false
            }
        ]

        const nextState = produce(baseState, draft => {
            draft.push({todo: "Tweet about it"})
            draft[1].done = true
        })

        // the new item is only added to the next state,
        // base state is unmodified
        expect(baseState.length).toBe(2)
        expect(nextState.length).toBe(3)

        // same for the changed 'done' prop
        expect(baseState[1].done).toBe(false)
        expect(nextState[1].done).toBe(true)

        // unchanged data is structurally shared
        expect(nextState[0]).toBe(baseState[0])
        // changed data not (dûh)
        expect(nextState[1]).not.toBe(baseState[1])
    })

    it("it can use this", () => {
        const base = {counter: 0}

        const next = produce(base, function() {
            this.counter++
        })
        expect(next.counter).toBe(1)

        // OR
        const increment = produce(function() {
            this.counter++
        })
        expect(increment(base).counter).toBe(1)
    })

    it("patches", () => {
        let state = {
            name: "Micheal",
            age: 32
        }

        // Let's assume the user is in a wizard, and we don't know whether
        // his changes should be updated
        let fork = state
        // all the changes the user made in the wizard
        let changes = []
        // all the inverse patches
        let inverseChanges = []

        fork = produce(
            fork,
            draft => {
                draft.age = 33
            },
            // The third argument to produce is a callback to which the patches will be fed
            (patches, inversePatches) => {
                changes.push(...patches)
                inverseChanges.push(...inversePatches)
            }
        )

        // In the mean time, our original state is updated as well, as changes come in from the server
        state = produce(state, draft => {
            draft.name = "Michel"
        })

        // When the wizard finishes (successfully) we can replay the changes made in the fork onto the *new* state!
        state = applyPatches(state, changes)

        // state now contains the changes from both code paths!
        expect(state).toEqual({
            name: "Michel",
            age: 33
        })

        // Even after finishing the wizard, the user might change his mind...
        state = applyPatches(state, inverseChanges)
        expect(state).toEqual({
            name: "Michel",
            age: 32
        })
    })

    it("can update set", () => {
        const state = {
            title: "hello",
            tokenSet: new Set()
        }

        const nextState = produce(state, draft => {
            draft.title = draft.title.toUpperCase() // let immer do it's job
            // don't use the operations onSet, as that mutates the instance!
            // draft.tokenSet.add("c1342")

            // instead: clone the set (once!)
            const newSet = new Set(draft.tokenSet)
            // mutate it once
            newSet.add("c1342")
            // update the draft with the new set
            draft.tokenSet = newSet
        })

        expect(state).toEqual({title: "hello", tokenSet: new Set()})
        expect(nextState).toEqual({
            title: "HELLO",
            tokenSet: new Set(["c1342"])
        })
    })

    it("can deep udpate map", () => {
        const state = {
            users: new Map([["michel", {name: "miche"}]])
        }

        const nextState = produce(state, draft => {
            const newUsers = new Map(draft.users)
            // mutate the new map and set a _new_ user object
            // but leverage produce again to deeply update it's contents
            newUsers.set(
                "michel",
                produce(draft.users.get("michel"), draft => {
                    draft.name = "michel"
                })
            )
            draft.users = newUsers
        })

        expect(state).toEqual({users: new Map([["michel", {name: "miche"}]])})
        expect(nextState).toEqual({
            users: new Map([["michel", {name: "michel"}]])
        })
    })
})