Created
May 28, 2021 06:22
-
-
Save highgrove/2d06703c8c2f2e5e38d8b310b7da1e2e to your computer and use it in GitHub Desktop.
Simple xstate test from machine definition
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {createMachine, EventObject, StateNodeConfig, StateSchema} from "xstate"; | |
import {createModel as xCreateModel} from "@xstate/test"; | |
export type TestDefinition<TTestContext, TContext, TSchema extends StateSchema<TContext>> = { | |
test?: (context: TTestContext) => Promise<any> | void; | |
} & (TSchema['states'] extends Record<string, StateSchema<TContext>> ? { | |
states?: { | |
[key in keyof TSchema['states']]?: TestDefinition<TTestContext, TContext, TSchema['states'][key]> | |
} | |
} : Record<string, never>); | |
function createModel<TTestContext, TContext, TSchema extends StateSchema<TContext>, TEvent extends EventObject>(definition: StateNodeConfig<TContext, TSchema, TEvent>, { | |
test, | |
states | |
}: TestDefinition<TTestContext, TContext, TSchema>) { | |
const mappedStates = states ? Object.entries(definition.states).map(([key, def]) => [key, createModel(def, states[key] ?? {})]).reduce((agg, [k, d]) => ({ | |
...agg, | |
[k]: d | |
}), {}) : definition.states; | |
return { | |
...definition, | |
meta: test ? {test} : {}, | |
states: mappedStates, | |
} | |
} | |
type StateContextFrom<TStateNodeConfig> = TStateNodeConfig extends StateNodeConfig<infer TContext, infer TSchema, infer TEvent> ? TContext : never; | |
type StateSchemaFrom<TStateNodeConfig> = TStateNodeConfig extends StateNodeConfig<infer TContext, infer TSchema, infer TEvent> ? TSchema : never; | |
type StateEventFrom<TStateNodeConfig> = TStateNodeConfig extends StateNodeConfig<infer TContext, infer TSchema, infer TEvent> ? TEvent : never; | |
type StateNodeConfigFrom<TStateNodeConfig> = TStateNodeConfig extends StateNodeConfig<infer TContext, infer TSchema, infer TEvent> ? StateNodeConfig<TContext, TSchema, TEvent> : never; | |
export declare type EventExecutor<TTestContext, TEvent extends EventObject> = ( | |
testContext: TTestContext, | |
event: TEvent) => Promise<any> | void; | |
export interface TestEventConfig<TTestContext, TEvent extends EventObject> { | |
exec?: EventExecutor<TTestContext, TEvent>; | |
cases?: Omit<TEvent, 'type'>[]; | |
} | |
type Platform<T extends string> = `error.platform.${T}` | `done.invoke.${T}` | |
type PlatformEvents<TTestContext, T extends string> = { [key in Platform<T>]?: TestEventConfig<TTestContext, any> }; | |
/* | |
* Simple xstate model test definition | |
* | |
* */ | |
export function defineModel<TStateNodeConfig = any, TTestContext = any, TServices extends string = never>(definition: StateNodeConfigFrom<TStateNodeConfig>, { | |
events = {}, | |
...model | |
}: TestDefinition<TTestContext, StateContextFrom<TStateNodeConfig>, StateSchemaFrom<TStateNodeConfig>> & { | |
events?: { | |
[key in StateEventFrom<TStateNodeConfig>['type']]?: TestEventConfig<TTestContext, Extract<StateEventFrom<TStateNodeConfig>, { type: key }>>; | |
} & PlatformEvents<TTestContext, TServices> | |
}) { | |
return xCreateModel<TTestContext, StateContextFrom<TStateNodeConfig>>(createMachine(createModel(definition, model)), {events}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment