@statekit/react
TypeScript icon, indicating that this package has built-in type declarations

0.1.1-alpha • Public • Published

statekit PoC WIP

Check out @statekit/core!

There it explains the latest version but here is a summary:

const config = createDfaConfig({
   states: ["idle", "running", "paused"],
   data: initialData,
   events: {
      noop: () => {},
      data: ({ draft }) => {
         //console.log(draft)
         draft
      },
      payload: ({ draft }, p: Partial<Data>) => {
         Object.assign(draft, p)
      },
      meta: (meta) => {
         meta.draft.foo = meta.state.toString()
      },
      return: ({ isStateOneOf, S }) => {
         if (isStateOneOf([S.idle, S.paused])) return
      },
      cases: ({ cases, S, draft }) =>
         cases({
            [S.idle]: () => S.running,
            [S.paused]: () => {
               draft.count = 123
            },
         }),
      async: async ({ draft, S }) => {
         draft.foo = "loading"

         draft.foo = await anAsyncFn("success")

         return S.running
      },
   },
   helpers: {
      isCountZero: ({ data }) => data.count === 0,
      isCountEqualTo: ({ data }, to: number) => data.count === to,
      isDataSameAs: ({ data }, payload: { count: number; foo: string }) =>
         data.count === payload.count && data.foo == payload.foo,
   },
   transitionRules: {
      only: {
         paused: ["running"],
      },
      deny: {
         running: ["paused"],
      },
   },
})

//...

it("should emit events", () => {
   const m = createDfa(config)
   const { event } = m

   event.noop()
   expect(m.data).toEqual(initialData)

   event.data()
   expect(m.data).toEqual(initialData)

   event.payload({ count: 1 })
   expect(m.data).toEqual({ ...initialData, count: 1 })

   event.meta()
   expect(m.data.foo).toEqual(m.state.toString())
})

And in React tests:

import * as React from "react"
import { StatekitProvider } from "../feat/statekit"
import { createMachineContext } from "../feat/machine/createMachineContext"
import { machineConfigFactory } from "./mock-factories/machineConfig"
import { createMachine } from "@statekit/core"
import { act, render, screen, fireEvent, cleanup } from "@testing-library/react"

const firstRootSiblingCfg = machineConfigFactory()
const secondRootSiblingCfg = machineConfigFactory({
   count: -100,
   foo: "second sibling",
})

const firstRootSiblingMachine = createMachine(firstRootSiblingCfg)
const secondRootSiblingMachine = createMachine(secondRootSiblingCfg)

const [FirstRootSiblingMachineProvider, useFirstRootSiblingMachine] =
   createMachineContext(firstRootSiblingMachine)
const [SecondRootSiblingMachineProvider, useSecondRootSiblingMachine] =
   createMachineContext(secondRootSiblingMachine)

const dataTestId = {
   FirstRootSibling: "first-root-sibling",
   SecondRootSibling: "second-root-sibling",
   FirstRootSiblingFirstChild: "first-root-sibling-first-child",
   FirstRootSiblingSecondChild: "first-root-sibling-second-child",
} as const

const Root = () => (
   <StatekitProvider>
      <FirstRootSibling>
         <FirstRootSiblingFirstChild />
         <FirstRootSiblingSecondChild />
      </FirstRootSibling>
      <SecondRootSibling />
   </StatekitProvider>
)

const FirstRootSibling = ({ children }: { children?: React.ReactNode }) => {
   const m = useFirstRootSiblingMachine()

   return (
      <FirstRootSiblingMachineProvider>
         <span data-testid={dataTestId.FirstRootSibling}>{m.data.count}</span>
         {children}
      </FirstRootSiblingMachineProvider>
   )
}

const SecondRootSibling = ({ children }: { children?: React.ReactNode }) => {
   const m = useSecondRootSiblingMachine()

   return (
      <SecondRootSiblingMachineProvider>
         <span data-testid={dataTestId.SecondRootSibling}>{m.data.count}</span>
         {children}
      </SecondRootSiblingMachineProvider>
   )
}

const FirstRootSiblingFirstChild = () => {
   const m = useFirstRootSiblingMachine()

   return (
      <span data-testid={dataTestId.FirstRootSiblingFirstChild}>{m.data.count}</span>
   )
}

const FirstRootSiblingSecondChild = () => {
   const m = useFirstRootSiblingMachine()

   return (
      <>
         <span data-testid={dataTestId.FirstRootSiblingSecondChild}>
            {m.data.count}
         </span>
         <button onClick={() => m.event.mutate({ count: 123 })}>
            FirstRootSiblingSecondChild button
         </button>
      </>
   )
}

const setup = () => {
   const view = render(<Root />)

   return { view }
}

afterEach(() => cleanup)

describe("Machine", () => {
   it("SecondRootSibling initial data", () => {
      setup()

      const el = screen.getByTestId(dataTestId.SecondRootSibling)

      expect(el.textContent).toBe(secondRootSiblingCfg.data.count.toString())
   })

   it("FirstRootSiblingFirstChild initial data from First machine", () => {
      setup()

      const el = screen.getByTestId(dataTestId.FirstRootSiblingFirstChild)

      expect(el.textContent).toBe(firstRootSiblingCfg.data.count.toString())
   })

   it("events trigger re-render", () => {
      setup()

      const buttonEl = screen.getByText("FirstRootSiblingSecondChild button")

      act(() => fireEvent.click(buttonEl))

      const countEl = screen.getByTestId(dataTestId.FirstRootSiblingSecondChild)

      expect(countEl.textContent).toBe("123")
   })

   it("events can be received by a sibling", () => {
      setup()

      const buttonEl = screen.getByText("FirstRootSiblingSecondChild button")

      act(() => fireEvent.click(buttonEl))

      const siblingCountEl = screen.getByTestId(
         dataTestId.FirstRootSiblingFirstChild
      )

      expect(siblingCountEl.textContent).toBe("123")
   })
})

Readme

Keywords

none

Package Sidebar

Install

npm i @statekit/react

Weekly Downloads

83

Version

0.1.1-alpha

License

ISC

Unpacked Size

33.7 kB

Total Files

28

Last publish

Collaborators

  • berkekaragoz