@statekit/core
v0.5.0-alpha
Published
Check out `@statekit/react`!
Downloads
4
Readme
statekit PoC WIP
Check out @statekit/react
!
import { anAsyncFn, testLog } from "../../__test__/utils"
import { createDfaConfig, createDfa } from "./dfa"
const initialData = { count: 0, foo: "bar" }
type Data = typeof initialData
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: Data) =>
data.count === payload.count && data.foo == payload.foo,
},
transitionRules: {
only: {
paused: ["running"],
},
deny: {
running: ["paused"],
},
},
})
/* TS Tests below */
const _tsEmptyConfig = createDfaConfig({})
const _tsConfig = createDfaConfig({ states: ["asd", "qwe"] })
const _ts1 = createDfa(_tsEmptyConfig)
const _ts2 = createDfa(_tsConfig)
const _ts3 = createDfa(config)
const _ts4 = createDfa({
states: ["idle", "running", "paused"],
data: initialData,
events: {
noop: () => {},
data: ({ draft }) => {
console.log(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
},
}),
},
transitionRules: {
only: {
paused: ["running"],
},
deny: {
running: ["paused"],
},
},
})
// just using
_ts1
_ts2
_ts3
_ts4
/* */
beforeAll(() => jest.useFakeTimers())
afterAll(() => jest.useRealTimers())
describe("DFA", () => {
it("should create a machine", () => {
const m = createDfa(config)
// also checks TS type inference
const initialState: 0 = m.STATE[config.states[0]]
expect(m.state).toEqual(initialState)
expect(m.STATE).toEqual({ idle: 0, running: 1, paused: 2 })
expect(m.data).toEqual(config.data)
})
it("should emit a state", () => {
const m = createDfa(config)
const prevState = m.setState(m.STATE.running)
expect(prevState).toEqual(m.STATE.idle)
expect(m.state).toEqual(m.STATE.running)
const prevState2 = m.setState(m.state)
expect(prevState2).toEqual(false)
expect(m.state).toEqual(m.STATE.running)
})
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())
})
it("async events work", async () => {
const m = createDfa(config)
const { event, STATE } = m
expect(m.state).toBe(STATE.idle)
expect(m.data.foo).toBe(initialData.foo)
const promise = event.async()
expect(m.state).toBe(STATE.idle)
expect(m.data.foo).toBe("loading") // consider
jest.advanceTimersToNextTimer()
await promise
expect(m.state).toBe(STATE.running)
expect(m.data.foo).toBe("success")
})
it("helpers work", async () => {
const m = createDfa(config)
const { helper } = m
expect(helper.isCountZero()).toBe(true)
m.setData((draft) => {
draft.count = 1
})
expect(helper.isCountZero()).toBe(false)
})
it("helpers with params work", async () => {
const m = createDfa(config)
const { helper } = m
// single arg
expect(helper.isCountEqualTo(1)).toBe(false)
expect(helper.isCountEqualTo(0)).toBe(true)
// multiple args
expect(helper.isDataSameAs({ count: 0, foo: "qwe" })).toBe(false)
expect(helper.isDataSameAs({ count: 0, foo: "bar" })).toBe(true)
})
})