Test Cases
| 🕙 Start time | ⌛ Duration |
|---|---|
| 5/11/2026, 3:40:30 PM | 22.32 s |
| ✅ Passed | ❌ Failed | ⏩ Skipped | 🚧 Todo | ⚪ Total | |
|---|---|---|---|---|---|
| Test Suites | 151 | 0 | 1 | 0 | 152 |
| Tests | 476 | 0 | 6 | 0 | 482 |
✅ src/actionHashCollision.test.ts [link]
2 passed, 0 failed, 0 skipped, 0 todo, done in 5.355596000000105 s
✅ action hash collision — different actions targeting the same initial state › collisionAutomata
✅ dismiss from Prompt transitions to Closed
✅ init from Prompt also transitions to Closed (global reset via [*] action)
✅ action hash collision — different actions targeting the same initial state✅ src/automataInternals.test.ts [link]
15 passed, 0 failed, 0 skipped, 0 todo, done in 50.731009000000086 s
✅ automata internal functions tests › currentState functions test
✅ returns the initial state ID & name
✅ returns the correct state ID & name after a transition
✅ automata internal functions tests › currentAction functions test
✅ has no initial action
✅ returns the correct action ID & name after a transition
✅ automata internal functions tests › currentCycle functions test
✅ initial cycle is 1
✅ cycle is incremented after action dispatch
✅ automata internal functions tests › currentEpoch functions test
✅ initial epoch is 1
✅ epoch is incremented after action dispatch of some automata
✅ automata internal functions tests › all internals captured via diagram reducers
✅ captures correct initial stateId and stateName
✅ actionId and actionName are null initially
✅ cycle is 1 initially
✅ captures actionId, actionName after dispatch; stateId/cycle reflect pre-transition values
✅ _currentTimestamp returns a positive number
✅ _currentTime returns an ISO-8601 string
✅ automata internal functions tests
✅ automata is not null✅ src/builtinFunctions.test.ts [link]
126 passed, 0 failed, 0 skipped, 0 todo, done in 138.48423000000003 s
✅ builtin functions codegen › diff
✅ diff(5, 3) = b-a = -2
✅ diff(3, 5) = b-a = 2
✅ diff(null, 3) throws TypeError
✅ builtin functions codegen › mod
✅ mod(10, 3) = 1
✅ mod(null, 3) throws TypeError
✅ builtin functions codegen › trunc
✅ trunc(1.9) = 1
✅ trunc(-1.9) = -1
✅ builtin functions codegen › ceil
✅ ceil(1.1) = 2
✅ ceil(-1.1) = -1
✅ builtin functions codegen › dec
✅ dec(5) = 4
✅ builtin functions codegen › neg
✅ neg(5) = -5
✅ neg(-3) = 3
✅ builtin functions codegen › inv
✅ inv(4) = 0.25
✅ inv(2) = 0.5
✅ builtin functions codegen › pow
✅ pow(2, 10) = 1024
✅ pow(4, 0.5) = 2
✅ builtin functions codegen › isGreater
✅ isGreater(5, 3) = true
✅ isGreater(3, 5) = false
✅ isGreater(3, 3) = false (boundary)
✅ isGreater(null, 3) throws
✅ builtin functions codegen › isLess
✅ isLess(3, 5) = true
✅ isLess(5, 3) = false
✅ isLess(3, 3) = false (boundary)
✅ builtin functions codegen › isGreaterOrEqual
✅ isGreaterOrEqual(3, 3) = true
✅ isGreaterOrEqual(5, 3) = true
✅ isGreaterOrEqual(2, 3) = false
✅ builtin functions codegen › isLessOrEqual
✅ isLessOrEqual(3, 3) = true
✅ isLessOrEqual(2, 3) = true
✅ isLessOrEqual(5, 3) = false
✅ builtin functions codegen › isEven / isOdd
✅ isEven(4) = true
✅ isEven(3) = false
✅ isOdd(3) = true
✅ isOdd(4) = false
✅ isEven(null) throws
✅ builtin functions codegen › isInteger
✅ isInteger(3) = true
✅ isInteger(3.1) = false
✅ builtin functions codegen › isPositive / isNegative
✅ isPositive(1) = true
✅ isPositive(-1) = false
✅ isPositive(0) = false
✅ isNegative(-1) = true
✅ isNegative(1) = false
✅ builtin functions codegen › and
✅ and(true, true) = true
✅ and(true, false) = false
✅ and(false, false) = false
✅ builtin functions codegen › or
✅ or(false, true) = true
✅ or(false, false) = false
✅ builtin functions codegen › none
✅ none(false, false) = true
✅ none(true, false) = false
✅ builtin functions codegen › if
✅ if(true, y, n) = y
✅ if(false, y, n) = n
✅ builtin functions codegen › case
✅ case: first branch matches
✅ case: second branch matches
✅ case: fallback when no branch matches
✅ builtin functions codegen › choose
✅ choose(0, a, b, c) = a
✅ choose(2, a, b, c) = c
✅ builtin functions codegen › repeat
✅ repeat(ab, 3) = ababab
✅ builtin functions codegen › padLeft / padRight
✅ padLeft(x, 4, 0) = 000x
✅ padRight(x, 4, 0) = x000
✅ builtin functions codegen › substr
✅ substr(hello, 1, 3) = el
✅ builtin functions codegen › len (string)
✅ len(hello) = 5
✅ len("") = 0
✅ builtin functions codegen › sin / cos
✅ sin(0) = 0
✅ cos(0) = 1
✅ builtin functions codegen › ln / lg
✅ ln(1) = 0
✅ lg(10) = 1
✅ builtin functions codegen › null-safe functions via NullSafe state
✅ isNull(null) = true
✅ isNull(0) = false
✅ isNull("") = false
✅ has(null, k) = false
✅ has({a:1}, a) = true
✅ has({a:1}, b) = false
✅ and(null, null) = false (null is falsy)
✅ or(null, true) = true
✅ none(null, null) = true
✅ if(null, y, n) = n (null is falsy)
✅ coalesce(null, null, fallback) = fallback
✅ coalesce(null, found, other) = found
✅ len(null) = 0
✅ builtin functions codegen › collection functions › stats
✅ min([3,1,4,1,5]) = 1
✅ min([]) = null
✅ med([1,2,3,4,5]) = 3
✅ med([]) = null
✅ sumsq([1,2,3]) = 14
✅ sumsq([3,4]) = 25
✅ builtin functions codegen › collection functions › isEqual (deep)
✅ isEqual({x:1},{x:1}) = true
✅ isEqual({x:1},{x:2}) = false
✅ isEqual([1,2],[1,2]) = true
✅ builtin functions codegen › collection functions › setAttr
✅ setAttr({a:1}, b, 2) = {a:1, b:2}
✅ setAttr({a:1}, a, 99) overwrites
✅ setAttr(null, k, 1) = null (lodash _.set returns null for null input)
✅ builtin functions codegen › collection functions › omit
✅ omit({a:1, b:2}, b) = {a:1}
✅ omit(null, k) = {}
✅ builtin functions codegen › collection functions › pick
✅ pick({a:1,b:2,c:3}, a) = {a:1}
✅ pick(null, k) = {}
✅ builtin functions codegen › collection functions › merge
✅ merge({a:1}, {b:2}) = {a:1, b:2}
✅ merge({a:1,b:1}, {b:2}) patch wins
✅ builtin functions codegen › collection functions › pluck
✅ pluck([{n:1},{n:2}], n) = [1,2]
✅ pluck(null, n) = [] (not a collection)
✅ pluck([], n) = []
✅ builtin functions codegen › collection functions › filterBy
✅ filterBy([{n:1},{n:2},{n:1}], n, 1) = [{n:1},{n:1}]
✅ filterBy(items, n, 99) = [] (no match)
✅ filterBy(null, n, 1) = []
✅ builtin functions codegen › collection functions › find
✅ find([{n:1},{n:2}], n, 2) = {n:2}
✅ find(items, n, 99) = null (no match)
✅ find(null, n, 1) = null
✅ builtin functions codegen › collection functions › sample
✅ sample([1,2,3,4,5], 2) returns 2 items from source
✅ sample([], 2) = []
✅ builtin functions codegen › collection functions › sort
✅ sort([3,1,4,1,5]) = [1,1,3,4,5]
✅ sort([]) = []
✅ sort(null) = []
✅ builtin functions codegen › collection functions › left / right
✅ left([1,2,3,4,5], 2) = [1,2]
✅ left([], 2) = []
✅ left(null, 2) = []
✅ right([1,2,3,4,5], 2) = [4,5]
✅ builtin functions codegen › collection functions › indexOf
✅ indexOf([10,20,30], 20) = 1
✅ indexOf([10,20,30], 99) = -1 (not found)
✅ indexOf(null, 20) = -1
✅ builtin functions codegen › collection functions › len (array)
✅ len([1,2,3,4,5]) = 5
✅ len([]) = 0
✅ len(null) = 0
✅ builtin functions codegen › collection functions › reverse
✅ reverse([1,2,3]) = [3,2,1]
✅ reverse([]) = []
✅ builtin functions codegen › collection functions › keys / values
✅ keys({a:1,b:2}) = [a,b]
✅ keys(null) = []
✅ values({a:1,b:2}) = [1,2]
✅ values(null) = []
✅ builtin functions codegen › collection functions
✅ builtin functions codegen✅ src/codegenAutomata.test.ts [link]
13 passed, 0 failed, 0 skipped, 0 todo, done in 21.00817200000006 s
✅ codegen output › gamePhaseAutomata
✅ initial state
✅ the context and state do not change with the wrong action.
✅ automata must have id
✅ automata must have actions
✅ automata must have states
✅ automata.getState must return numeric state
✅ [{"action":77866287,"payload":{}}] -- > 2252048
✅ [{"action":77866287,"payload":{}},{"action":81515,"payload":{}}] -- > 69824076
✅ [{"action":77866287,"payload":{}},{"action":81515,"payload":{}},{"action":407301981,"payload":{}}] -- > 1730055131
✅ [{"action":77866287,"payload":{}},{"action":81515,"payload":{}},{"action":407301981,"payload":{}},{"action":1973300761,"payload":{}}] -- > 1929949911
✅ [{"action":77866287,"payload":{}},{"action":81515,"payload":{}},{"action":407301981,"payload":{}},{"action":1973300761,"payload":{}},{"action":1058895409,"payload":{}},{"action":1626434024,"payload":{}}] -- > 1608719668
✅ [{"action":77866287,"payload":{}},{"action":81515,"payload":{}},{"action":407301981,"payload":{}},{"action":1973300761,"payload":{}},{"action":1058895409,"payload":{}},{"action":1626434024,"payload":{}},{"action":1757631242,"payload":{}}] -- > 1985829159
✅ [{"action":77866287,"payload":{}},{"action":81515,"payload":{}},{"action":407301981,"payload":{}},{"action":1973300761,"payload":{}},{"action":1058895409,"payload":{}},{"action":1626434024,"payload":{}},{"action":1757631242,"payload":{}}] -- > 1985829159
✅ codegen output✅ src/codegenNotes.test.ts [link]
38 passed, 0 failed, 0 skipped, 0 todo, done in 2129.0909759999995 s
✅ byPass state
✅ should throw an error if the ByPass state has more than 1 transition
✅ should throw an error if the ByPass state has no transition
✅ should throw an error if the ByPass state has no action [-]
✅ payload is not propagated through ByPass
✅ the finite automaton must go to the next state after the byPasses state
✅ default assign
✅ left assign #{a=string | constant | number | list | emptyPayload = {} | emptypreviousContext = {} }
✅ left assign with previous context and payload #{ a=$payload, $b=#prevContext } prevContext - all expressions
✅ right assign with #a,#b = (list, constant, integer, string, payload = {}, prevContext = {})
✅ right assign payload $a,$b = (list, constant, integer, string, payload = {}, prevContext = {}
✅ in the function call #{a} <= add($a=10, $b=5)
✅ reducers
✅ #{a,b} from previous to shortcut, prev:{a:3,b:"str"}
✅ #{a,b} shortcut, with missing previus context, "a" and "b" should be null
✅ #{a,b} <= #a, #b, with previous context
✅ #{a,b} <= #a, #b, previous context is missing
✅ #{a,b,c,d} <= payload(integer), payload(string)...
✅ #{} <= $payload, without passed payload
✅ #{a} <= expressions(string,number,arr)
✅ #{a} <= add($a,$b)
✅ constants reference
✅ constant reference should be replaced by value in dictionary
✅ constant value should be number or string
✅ codegen should throw an error if there is no key found in the dictionary.
✅ codgen should throw an error if the dictionary is missing
✅ initial
✅ the +INIT state must be the initial state for the automata
✅ by default start state should be first state in note
✅ default context
✅ reducer from [*] shared between states
✅ by default, the context should be empty object
✅ functions
✅ nested call, mult(avg($list),$count)
✅ function calls with mixed argument types (payload, constant, literal)
✅ chained function calls
✅ function calls with array operations
✅ user defined functions
✅ simple function returning a constant value, define/fn () => 3
✅ codegen should catch cyclic dependencies and throw an error
define/lol1 () => kek1()
define/kek1 () => kek2()
define/kek2 () => kek3()
define/kek3 () => kek4()
define/kek4 () => kek5()
define/kek5 () => kek6()
define/kek6 () => lol1()
✅ the order in which the function is defined has no effect
define/kek2 () => add(1,2)
define/lol2 () => kek2()
✅ without arguments in a defined function, define/lol3 () => add(1,2)
✅ with arguments in a defined function, define/lol4 (a,b) => add(a,b)
✅ with arguments and value, define/lol5 (a) => add(a,3)
✅ complex function with constants, define/complexFunc (x, y) => add(mult(%%BASE, x), mult(%%MULTIPLIER, y), %%OFFSET)
✅ function with passed previous context and payload✅ src/coreLoop_integration.test.ts [link]
9 passed, 0 failed, 0 skipped, 0 todo, done in 58.58941300000015 s
✅ coreLoop with generated WeatherReportAutomata
✅ runs Event -> Action -> State and emits Events from State (Pending -> FETCH_WEATHER)
✅ resolves to Success on WEATHER_RESOLVED, preserving city/coords and setting result
✅ resolves to Error on WEATHER_REJECTED, preserving city/coords and setting error
✅ registers destination and unsubscribes correctly
✅ registers source; start/stop lifecycle works
✅ multiple sources and destinations; stop() stops sources and unbinds destinations
✅ idempotent start/stop
✅ throws on duplicate ids (automata/source/destination)
✅ unregister methods are safe to call twice✅ src/defineDirective.test.ts [link]
13 passed, 0 failed, 0 skipped, 0 todo, done in 34.000552999999854 s
✅ define directive codegen › defineExtended
✅ define/constVal () => 42 returns 42
✅ define/constVal is stable across dispatches
✅ 3-level chain step3(3) = 7
✅ 3-level chain step3(0) = 1
✅ 3-level chain step3(5) = 11
✅ step3(null) throws TypeError (mult rejects null)
✅ define directive codegen › defineForkPredicate
✅ amount > 0 -> Valid state
✅ amount < 0 -> Invalid state
✅ amount = 0 -> Invalid state (boundary: 0 is not > 0)
✅ define directive codegen › defineMultiState
✅ state A: double($input=3) -> val=6
✅ state B: double(#val) where #val=6 from A -> val=12
✅ double($input=10) in A -> val=20, B doubles again -> val=40
✅ double(null) in A throws TypeError (mult rejects null)
✅ define directive codegen✅ src/events.test.ts [link]
11 passed, 0 failed, 0 skipped, 0 todo, done in 485.0477599999999 s
✅ automata Events › event Adapter
✅ automata has an Event Adapter
✅ event Adapter is pre-loaded with events from diagram
✅ can add new Event Emitters to Adapter
✅ can add new Event Listeners to Adapter
✅ can set new Event Adapter
✅ automata Events › event interactions
✅ automata can listen to events dispatched by event bus
✅ subscribe/emit in 1 automata
✅ state of automata#1 changes after emit from automata#2
✅ state of automata#1 does not change on emitting wrong events from automata#2
✅ action payload can be filled from incoming event meta information
✅ event meta information can be filled from context of the automata
✅ automata Events✅ src/forks.test.ts [link]
16 passed, 0 failed, 0 skipped, 0 todo, done in 42.50260299999991 s
✅ forks › default
✅ init
✅ automata is in working state
✅ transition into END state if condition is TRUE
✅ transition back into WORKING state if condition is FALSE
✅ state reducer is invoked when transitioning to the same state after the fork
✅ forks › fork with no default path
✅ init
✅ automata is in working state
✅ transition into State1 state if isGreater is TRUE
✅ transition into State2 state if isZero is TRUE
✅ staying in WORKING state if no condition is TRUE
✅ state reducer is NOT invoked when staying on the same state
✅ forks › fork that leads into another fork
✅ init
✅ automata is in working state
✅ transition into State1 state if isGreater is TRUE
✅ transition into State2 state if isGreater is FALSE, and isPositive is TRUE
✅ transition back into WORKING state as a default path for the second fork, if isGreater and isPositive are FALSE
✅ forks › fork with duplicate default paths is not generated
✅ forks✅ src/functionDictionary.test.ts [link]
10 passed, 0 failed, 0 skipped, 0 todo, done in 95.45054399999981 s
✅ jS/TS Function Dictionary › can get functions from a dictionary
✅ built-in functions
✅ custom functions
✅ jS/TS Function Dictionary › cannot register a function under an already existing key
✅ built-in keys
✅ custom key
✅ jS/TS Function Dictionary
✅ dictionary is not empty
✅ cannot get a function under a non-existing key
✅ can register custom functions inside of a dictionary
✅ custom functions return the same result before and after being added to a dictionary
✅ cannot register a function with incorrect key length
✅ cannot register a function with incorrect key format✅ src/injectAdvanced.test.ts [link]
14 passed, 0 failed, 0 skipped, 0 todo, done in 53.8030289999997 s
✅ inject advanced codegen › injectWithDefine
✅ sumRange(1, 5) = sum([1,2,3,4]) = 10
✅ sumRange(0, 4) = sum([0,1,2,3]) = 6
✅ sumRange(5, 5) = sum([]) = 0
✅ functionDictionary has range registered
✅ functionDictionary has sumRange registered
✅ functionDictionary has sumArr registered
✅ inject advanced codegen › injectComplexReturn
✅ range(0, 4) stored as [0,1,2,3]
✅ makePoint(3, 7) stored as {x:3, y:7}
✅ funcA() = A, funcB() = B
✅ makePoint(null, null) = {x:null, y:null}
✅ range result reused in next dispatch: len([0,1,2,3]) via context is still 4
✅ inject advanced codegen › injectForkPredicate
✅ val=5 -> Positive state
✅ val=0 -> NonPositive state (boundary: 0 is not > 0)
✅ val=-3 -> NonPositive state
✅ inject advanced codegen✅ src/injectFunctions.test.ts [link]
8 passed, 0 failed, 0 skipped, 0 todo, done in 452.9971780000001 s
✅ inject functions codegen
✅ should successfully inject functions into function dictionary
✅ should successfully inject functions from export default dictionary
✅ should correctly execute injected functions during state machine transitions
✅ should successfully inject default exported function
✅ should validate exported function types and reject invalid exports
✅ should reject function names that conflict with built-in identifiers
✅ should throw error when inject directive is used without function path
✅ should throw error when referenced inject function does not exist✅ src/injectFunctionsTypeScript.test.ts [link]
3 passed, 0 failed, 0 skipped, 0 todo, done in 230.10282200000006 s
✅ inject functions codegen (TypeScript)
✅ emits namespace import for userFunctions when functionFilePath is set
✅ registers injected function via userFunctionsDict resolved from namespace import
✅ omits namespace import when functionFilePath is not provided✅ src/internalsEventBus.test.ts [link]
12 passed, 0 failed, 0 skipped, 0 todo, done in 33.976252999999815 s
✅ automata internals via EventBus › timestamp monotonicity
✅ _currentTimestamp is non-decreasing across sequential dispatches
✅ _currentTimestamp is a positive number on every dispatch
✅ automata internals via EventBus › eventBus-driven epoch and cycle
✅ first bus dispatch captures same epoch as construction (pre-increment semantics)
✅ second bus dispatch captures epoch incremented by one vs first
✅ cycle increments by one on each EventBus dispatch
✅ automata internals via EventBus › two instances subscribed to same event
✅ both instances process when the same event is dispatched
✅ first-registered instance captures lower epoch than second (insertion order)
✅ cycle counters are independent per instance
✅ automata internals via EventBus › chain reaction: A emits -> B reacts
✅ chain completes: B dispatches after A emits CHAIN
✅ b.epoch === A.epoch + 1 (A dispatches first, B second)
✅ each instance dispatches exactly once: A.cycle === B.cycle
✅ second chain: epoch increments by 2 per chain and ordering is preserved
✅ automata internals via EventBus✅ src/pureJavaScript.test.ts [link]
58 passed, 0 failed, 0 skipped, 0 todo, done in 61.80705900000066 s
✅ pure-javascript codegen - state transitions and context › pause / resume
✅ paused machine queues dispatches
✅ resume flushes queued dispatches
✅ pure-javascript codegen - state transitions and context › disable / enable
✅ disabled machine ignores dispatches
✅ enabled machine resumes accepting dispatches
✅ pure-javascript codegen - state transitions and context
✅ factory returns a non-null instance
✅ initial state is Off
✅ initial lastAction is null
✅ initial currentCycle is 0
✅ initial context has counter = null
✅ dispatch transitions state from Off to Red
✅ dispatch updates lastAction
✅ dispatch increments currentCycle
✅ counter increments on each dispatch
✅ getContext returns state and context snapshot
✅ multiple dispatches cycle through states
✅ unknown action does not change state
✅ destroy clears queue without throwing
✅ pure-javascript codegen - module-level exports
✅ exports statesDictionary
✅ exports actionsDictionary
✅ exports eventDictionary
✅ exports actionsMap
✅ exports statesMap
✅ exports functionDictionary
✅ exports getState helper
✅ exports getAction helper
✅ exports createAction helper
✅ exports hasState helper
✅ exports createEventBus function
✅ factory function is default export
✅ pure-javascript codegen - built-in functions
✅ mult built-in: doubled = val * 2
✅ if+isGreater built-in: clamps value at 100
✅ if+isGreater: passes value through when <= 100
✅ pure-javascript codegen - define directive
✅ user-defined function is applied
✅ pure-javascript codegen - inject functions
✅ functionDictionary has injected function
✅ injected function is callable
✅ pure-javascript codegen - eventAdapter on instance
✅ factory instance exposes eventAdapter
✅ eventAdapter has addEventEmitter
✅ eventAdapter has addEventListener
✅ createEventBus is exported
✅ pure-javascript codegen - forks
✅ score > 50 routes to High
✅ score <= 50 routes to Low
✅ score exactly 50 routes to Low
✅ pure-javascript codegen - subscribe via EventBus
✅ createEventBus returns [EventBus, automatas, cleanup] tuple
✅ subscribe transitions FSM on EventBus.dispatch
✅ getEventStack records dispatched events
✅ pure-javascript codegen - emit via EventBus
✅ emitter transitions to EMIT_TRIGGER on subscribed event
✅ emit dispatches specialEvent back to EventBus
✅ pure-javascript codegen - epoch tracking
✅ exports getEpoch function
✅ epoch increments on each successful dispatch
✅ epoch is shared across instances from same module
✅ unknown action does not increment epoch
✅ pure-javascript codegen - internals in context
✅ context.cycle reflects pre-dispatch cycle (currentCycle - 1)
✅ context.cycle increments on each successful dispatch
✅ context.cycle does not change on impossible action
✅ pure-javascript codegen - builtin tree-shaking
✅ includes used builtin 'add'
✅ excludes unused builtin 'mult'
✅ excludes unused builtin 'diff'
✅ excludes unused builtin 'isOdd'✅ src/pureTypeScript.test.ts [link]
49 passed, 0 failed, 0 skipped, 0 todo, done in 60.72674300000017 s
✅ pure-typescript codegen - state transitions and context › pause / resume
✅ paused machine queues dispatches
✅ resume flushes queued dispatches
✅ pure-typescript codegen - state transitions and context › disable / enable
✅ disabled machine ignores dispatches
✅ enabled machine resumes accepting dispatches
✅ pure-typescript codegen - state transitions and context
✅ factory returns a non-null instance
✅ initial state is Off
✅ initial lastAction is null
✅ initial currentCycle is 0
✅ initial context has counter = null
✅ dispatch transitions state from Off to Red
✅ dispatch updates lastAction
✅ dispatch increments currentCycle
✅ counter increments on each dispatch
✅ getContext returns state and context snapshot
✅ multiple dispatches cycle through states
✅ unknown action does not change state
✅ destroy clears queue without throwing
✅ pure-typescript codegen - .d.ts declarations
✅ generates a .d.ts file
✅ .d.ts exports statesDictionary
✅ .d.ts exports actionsDictionary
✅ .d.ts exports factory function
✅ .d.ts exports instance type
✅ .d.ts has default export
✅ .d.ts exports helper functions
✅ .d.ts exports createEventBus
✅ pure-typescript codegen - module-level exports
✅ exports statesDictionary
✅ exports actionsDictionary
✅ exports eventDictionary
✅ exports getState helper
✅ exports getAction helper
✅ exports createAction helper
✅ exports hasState helper
✅ exports createEventBus function
✅ factory function is default export
✅ pure-typescript codegen - forks
✅ score > 50 routes to High
✅ score <= 50 routes to Low
✅ score exactly 50 routes to Low
✅ pure-typescript codegen - subscribe via EventBus
✅ createEventBus returns [EventBus, automatas, cleanup] tuple
✅ subscribe transitions FSM on EventBus.dispatch
✅ getEventStack records dispatched events
✅ pure-typescript codegen - emit via EventBus
✅ emitter transitions to EMIT_TRIGGER on subscribed event
✅ emit dispatches specialEvent back to EventBus
✅ pure-typescript codegen - epoch tracking
✅ exports getEpoch function
✅ epoch increments on each successful dispatch
✅ epoch is shared across instances from same module
✅ unknown action does not increment epoch
✅ pure-typescript codegen - internals in context
✅ context.cycle reflects pre-dispatch cycle (currentCycle - 1)
✅ context.cycle increments on each successful dispatch
✅ context.cycle does not change on impossible action✅ src/python.test.ts [link]
63 passed, 0 failed, 0 skipped, 0 todo, done in 2585.5041440000005 s
✅ python codegen - structural validation
✅ generates states_dictionary
✅ generates actions_dictionary
✅ generates action_to_state_from_state_dict
✅ generates Off state hash
✅ generates Red state hash
✅ generates reducer functions
✅ generates _get_default_context
✅ generates factory function
✅ factory returns dict with state key
✅ generates helper functions
✅ generates function_dictionary
✅ context uses coalesce in default context
✅ context uses inc builtin
✅ python codegen - no pydash, selective functions
✅ no pydash import in output
✅ mult is present in function_dictionary
✅ unused functions not emitted (sort not used)
✅ event_dictionary is emitted
✅ _EventBus class is emitted
✅ _EventAdapter class is emitted
✅ create_event_bus function is emitted
✅ factory returns event_adapter key
✅ no pydash in traffic input either
✅ python codegen - builtin functions structural
✅ generates mult call in reducer
✅ generates is_greater call in reducer
✅ generates _if call in reducer
✅ python codegen - define directive structural
✅ registers user-defined double function
✅ double calls mult
✅ python codegen - inject functions
✅ includes injected function assignment
✅ injected function body references mult
✅ python codegen - event adapter structural
✅ emits event_adapter = _EventAdapter()
✅ wires add_event_listener for subscribe
✅ wires add_event_emitter for emit
✅ event_adapter in factory return dict
✅ create_event_bus function is emitted
✅ _EventBus class is emitted
✅ _EventAdapter class is emitted
✅ busReady event in event_dictionary
✅ fsmDone event in event_dictionary
✅ python codegen - inject functions execution
✅ generated inject file exists
✅ injected triple function triples a value
✅ python codegen - execution
✅ generated file exists
✅ factory creates instance with correct initial state
✅ dispatch transitions state from Off to Red
✅ dispatch increments current_cycle
✅ counter increments on each dispatch via coalesce/inc
✅ unknown action does not change state
✅ paused machine queues dispatches
✅ resume flushes queued dispatches
✅ disabled machine ignores dispatches
✅ python codegen - builtin functions execution
✅ mult builtin computes correctly
✅ isGreater + if builtins clamp correctly
✅ python codegen - define directive execution
✅ user-defined double function computes correctly
✅ python codegen - helper functions execution
✅ get_state returns correct state value
✅ get_action returns correct action value
✅ create_action returns correct action packet
✅ has_state returns True for current state
✅ has_state returns False for non-current state
✅ python codegen - event bus execution: subscribe triggers transition
✅ create_event_bus wires two automatas
✅ dispatching FsmSignal event triggers Receiver Trigger action
✅ cleanup unsubscribes all handlers - dispatch after cleanup has no effect
✅ python codegen - event bus execution: emit propagates to second FSM
✅ dispatching Send action on Sender emits FsmSignal which transitions Receiver
✅ python codegen - event dispatch sequence
✅ cascading: Sender dispatch -> emit -> Receiver transition in one bus.dispatch call
✅ no infinite loop: single dispatch causes exactly one transition, no cascade✅ src/shared.test.ts [link]
16 passed, 0 failed, 6 skipped, 0 todo, done in 38.016267999999855 s
✅ shared behavior - JavaScript
✅ starts in initial state
✅ after 1 dispatch(STEP): state is B
✅ after 2 dispatch(STEP): state is C
✅ after 3 dispatch(STEP): state is A
✅ shared behavior - TypeScript
✅ starts in initial state
✅ after 1 dispatch(STEP): state is B
✅ after 2 dispatch(STEP): state is C
✅ after 3 dispatch(STEP): state is A
✅ shared behavior - PureJavaScript
✅ starts in initial state
✅ after 1 dispatch(STEP): state is B
✅ after 2 dispatch(STEP): state is C
✅ after 3 dispatch(STEP): state is A
✅ shared behavior - PureTypeScript
✅ starts in initial state
✅ after 1 dispatch(STEP): state is B
✅ after 2 dispatch(STEP): state is C
✅ after 3 dispatch(STEP): state is A
⏩ shared behavior - Python
⏩ starts in initial state A after dispatching GO
⏩ after GO + STEP: state is B
⏩ after GO + STEP + STEP: state is C
⏩ after GO + STEP x3: state is back to A
⏩ get_epoch increments with each dispatch
⏩ has_state accepts string key