From 481ea82205f50a484928b0c4ae29323dc909b0d5 Mon Sep 17 00:00:00 2001 From: Reece Dunham Date: Thu, 25 Jul 2024 12:10:48 -0400 Subject: [PATCH] fix: really weird bug with tests --- package.json | 5 +-- src/handleEvent.ts | 66 +++++++++++++++++++++------------------ src/index.ts | 55 +++++++++++++++++--------------- src/utils.ts | 11 ++++--- tests/handleEvent.spec.ts | 22 ++++++++----- tests/timers.spec.ts | 3 +- 6 files changed, 91 insertions(+), 71 deletions(-) diff --git a/package.json b/package.json index f2079f5..a2012e4 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "typescript": "^5.5.2" }, "scripts": { - "prettier": "prettier --write \"**/*.{ts,md,json,js,cjs}\"", + "prettier": "prettier --write \"**/*.{ts,json,js,cjs}\"", "build": "tsc && node build.mjs", "prepack": "yarn build", "test": "mocha --require esbuild-register --extension js,ts,cjs,mjs tests", @@ -61,7 +61,8 @@ }, "prettier": { "semi": false, - "tabWidth": 4 + "tabWidth": 4, + "trailingComma": "es5" }, "publishConfig": { "access": "public" diff --git a/src/handleEvent.ts b/src/handleEvent.ts index 0ef421f..8684346 100644 --- a/src/handleEvent.ts +++ b/src/handleEvent.ts @@ -27,7 +27,7 @@ function runCAT( definition: StateMachineLike>, newContext: Partial, event: Event, - options: HandleEventOptions + options: HandleEventOptions, ): HandleEventReturn> { const log = getLogger() // do we need to check conditions? @@ -37,7 +37,7 @@ function runCAT( // IOI sometimes puts the actions along-side keys like Transition and Condition, // yet both still apply const irregularEventKeys = Object.keys(handler).filter((k) => - k.includes("$") + k.includes("$"), ) const hasIrregularEventKeys = irregularEventKeys.length > 0 @@ -57,22 +57,22 @@ function runCAT( { ...(newContext || {}), ...(options.contractId && { - ContractId: options.contractId + ContractId: options.contractId, }), ...(definition.Constants || {}), - Value: event + Value: event, }, { pushUniqueAction(reference, item) { const referenceArray = findNamedChild( reference, newContext, - true + true, ) item = findNamedChild(item, newContext, false) - getLogger()( + log( "action", - `Running pushUniqueAction on ${reference} with ${item}` + `Running pushUniqueAction on ${reference} with ${item}`, ) if (!Array.isArray(referenceArray)) { @@ -90,8 +90,8 @@ function runCAT( return true }, timers: options.timers, - eventTimestamp: options.timestamp - } + eventTimestamp: options.timestamp, + }, ) } @@ -106,7 +106,7 @@ function runCAT( ;(Actions).push( ...irregularEventKeys.map((key) => { return { [key]: handler[key] } - }) + }), ) } @@ -114,31 +114,31 @@ function runCAT( for (const action of Object.keys(actionSet)) { newContext = handleActions( { - [action]: actionSet[action] + [action]: actionSet[action], }, { ...newContext, ...(definition.Constants || {}), ...(options.contractId && { - ContractId: options.contractId + ContractId: options.contractId, }), - Value: event + Value: event, }, { - originalContext: definition.Context ?? {} - } + originalContext: definition.Context ?? {}, + }, ) } } // drop this specific event's value - if (newContext.hasOwnProperty("Value")) { + if (newContext["Value"]) { // @ts-expect-error delete newContext.Value } // drop this specific event's ContractId - if (newContext.hasOwnProperty("ContractId")) { + if (newContext["ContractId"]) { // @ts-expect-error delete newContext.ContractId } @@ -156,7 +156,7 @@ function runCAT( log( "transition", - `${options.currentState} is performing a transition to ${state} - running its "-" event` + `${options.currentState} is performing a transition to ${state} - running its "-" event`, ) // When transitioning, we have to reset all timers. @@ -176,14 +176,14 @@ function runCAT( currentState: state, timers: options.timers, timestamp: options.timestamp, - contractId: options.contractId - } + contractId: options.contractId, + }, ) } return { context: newContext, - state + state, } } @@ -201,7 +201,7 @@ export function handleEvent( definition: StateMachineLike>, context: Partial, event: Event, - options: HandleEventOptions + options: HandleEventOptions, ): HandleEventReturn> { const log = getLogger() const { eventName, currentState = "Start" } = options @@ -209,20 +209,22 @@ export function handleEvent( // (current state object - reduces code duplication) let eventToCatsMap = definition.States?.[currentState] - const hasPreExecState = !!Object.keys(eventToCatsMap || {}).find(key => key.startsWith("$")) + const hasPreExecState = !!Object.keys(eventToCatsMap || {}).find((key) => + key.startsWith("$"), + ) const hasEventState = !!eventToCatsMap?.[eventName] if (!eventToCatsMap || (!hasEventState && !hasPreExecState)) { log( "disregard-event", - `SM in state ${currentState} disregarding ${eventName}` + `SM in state ${currentState} disregarding ${eventName}`, ) // we are here because either: // - we have no handler for the current state // - in this particular state, the state machine doesn't care about the current event return { context: context, - state: currentState + state: currentState, } } @@ -231,7 +233,9 @@ export function handleEvent( type CATList = CATObject[] - function runCATsUntilCompletionOrTransition(eventHandlers: CATList): HandleEventReturn> | undefined { + function runCATsUntilCompletionOrTransition( + eventHandlers: CATList, + ): HandleEventReturn> | undefined { for (const handler of eventHandlers) { const out = runCAT(handler, definition, newContext, event, options) @@ -241,7 +245,7 @@ export function handleEvent( // we swapped states while in a handler, so our work here is done return { context: newContext, - state: out.state + state: out.state, } } } @@ -257,7 +261,9 @@ export function handleEvent( } // Handle timers/anything that starts with $ because they need to run first. - for (const preExecStateName of Object.keys(eventToCatsMap).filter(k => k.startsWith("$"))) { + for (const preExecStateName of Object.keys(eventToCatsMap).filter((k) => + k.startsWith("$"), + )) { const preExecState = eventToCatsMap[preExecStateName] const preExecHandlers: CATList = [] @@ -277,7 +283,7 @@ export function handleEvent( if (timerResult) { log( "timer", - "Timer caused a state transition, replaying current event with new state." + "Timer caused a state transition, replaying current event with new state.", ) options.currentState = timerResult.state @@ -294,6 +300,6 @@ export function handleEvent( return { state: currentState, - context: newContext + context: newContext, } } diff --git a/src/index.ts b/src/index.ts index c30c9e2..d142063 100644 --- a/src/index.ts +++ b/src/index.ts @@ -35,7 +35,7 @@ import { getLogger, setLogger } from "./logging" export function test>( input: any, context: Context, - options?: Partial + options?: Partial, ): boolean | any { if (!input) { throw new Error("State machine is falsy!") @@ -51,7 +51,7 @@ export function test>( findNamedChild: opts.findNamedChild || findNamedChild, ...opts, _path: opts._path || "Root", - _currentLoopDepth: 0 + _currentLoopDepth: 0, }) } @@ -60,17 +60,22 @@ export function test>( * The benefit of using this is that it's a single, inline call, instead of 4 * lines per call. */ -function testWithPath(input: any, context: Context, options: TestOptions, name: string): boolean | Context { +function testWithPath( + input: any, + context: Context, + options: TestOptions, + name: string, +): boolean | Context { return realTest(input, context, { ...options, - _path: `${options._path}.${name}` + _path: `${options._path}.${name}`, }) } function realTest( input: any, variables: Variables, - options: TestOptions + options: TestOptions, ): Variables | boolean { const log = getLogger() @@ -92,7 +97,7 @@ function realTest( if (Array.isArray(input)) { // @ts-expect-error Type mismatch thing. return input.map((val, index) => - testWithPath(val, variables, options, `[${index}]`) + testWithPath(val, variables, options, `[${index}]`), ) } @@ -115,8 +120,8 @@ function realTest( val, variables, options, - `$eq[${index}]` - ) === res + `$eq[${index}]`, + ) === res, ) ) } @@ -127,13 +132,13 @@ function realTest( if (input.$and) { return input.$and.every((val, index) => - testWithPath(val, variables, options, `$and[${index}]`) + testWithPath(val, variables, options, `$and[${index}]`), ) } if (input.$or) { return input.$or.some((val, index) => - testWithPath(val, variables, options, `$or[${index}]`) + testWithPath(val, variables, options, `$or[${index}]`), ) } @@ -171,7 +176,7 @@ function realTest( input, variables, "$inarray", - options + options, ) } @@ -201,7 +206,7 @@ function realTest( if (!options.eventTimestamp && options.eventTimestamp !== 0) { log( "validation", - "No event timestamp found when timer is supposed to be active" + "No event timestamp found when timer is supposed to be active", ) return false } @@ -209,7 +214,7 @@ function realTest( timer = { startTime: options.eventTimestamp, endTime: options.eventTimestamp + seconds, - path + path, } options.timers.push(timer) @@ -222,7 +227,7 @@ function realTest( // The timer is up. Delete it from the timers array // so that a new timer can be created if this state is visited again. const index = options.timers.findIndex( - (timer) => timer.path === path + (timer) => timer.path === path, ) if (index !== -1) { @@ -242,8 +247,8 @@ function realTest( input.$pushunique[1], variables, options, - "$pushunique[1]" - ) + "$pushunique[1]", + ), ) } @@ -252,13 +257,13 @@ function realTest( input.$contains[0], variables, options, - "$contains[0]" + "$contains[0]", ) const second = testWithPath( input.$contains[1], variables, options, - "$contains[1]" + "$contains[1]", ) as string if (typeof first === "string") { @@ -299,7 +304,7 @@ export type RealTestFunc = typeof realTest export function handleActions( input: any, context: Context, - options?: HandleActionsOptions + options?: HandleActionsOptions, ): Context { if (!input || typeof input !== "object") { return context @@ -318,7 +323,7 @@ export function handleActions( set( context, reference, - op === "$inc" ? variableValue + 1 : variableValue - 1 + op === "$inc" ? variableValue + 1 : variableValue - 1, ) } else { let reference = input[op][0] @@ -335,7 +340,7 @@ export function handleActions( reference, op === "$inc" ? variableValue + incrementBy - : variableValue - incrementBy + : variableValue - incrementBy, ) } } @@ -389,12 +394,12 @@ export function handleActions( const variableValue1 = findNamedChild( input["$mul"][0], context, - true + true, ) const variableValue2 = findNamedChild( input["$mul"][1], context, - false + false, ) if ( @@ -434,7 +439,7 @@ export function handleActions( // clone the thing let array: unknown[] = deepClone( - findNamedChild(reference, context, true) + findNamedChild(reference, context, true), ) if (!Array.isArray(array)) { @@ -451,7 +456,7 @@ export function handleActions( const value = findNamedChild( reference, options.originalContext, - true + true, ) set(context, reference, value) diff --git a/src/utils.ts b/src/utils.ts index 081ad7b..8eb3828 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -103,14 +103,13 @@ export function set(obj: any, keys: string | string[], val: any): void { * @param reference The reference to the target as a string. * @param variables The object that may contain the target. * @param forWriting true if this reference is being written to. - * @returns The value if found, or the reference if it wasn't / - * something went wrong. + * @returns The value if found, or the reference if it wasn't / something went wrong. */ export function findNamedChild( reference: string, variables: any, - forWriting = false, -): any { + forWriting = false +): boolean | string | number | any { if (typeof reference !== "string") { return reference } @@ -141,7 +140,9 @@ export function findNamedChild( let obj = variables // if we have a global matching the exact name of the reference, this is probably what we want - if (obj[reference]) { + // note: not sure why exactly but if we don't do this proto check, + // `handleEvent api > supports actions with constants` fails + if (Object.prototype.hasOwnProperty.call(reference)) { return obj[reference] } diff --git a/tests/handleEvent.spec.ts b/tests/handleEvent.spec.ts index a77fee8..b1d5480 100644 --- a/tests/handleEvent.spec.ts +++ b/tests/handleEvent.spec.ts @@ -209,14 +209,22 @@ describe("handleEvent api", () => { it("supports $.ContractId", () => { const { Definition, Input } = suites.withContractId - const result = handleEvent(Definition, Definition.Context, Input.Value, { - currentState: "Start", - eventName: Input.Name, - timestamp: 0, - contractId: "abc123", - }) + const result = handleEvent( + Definition, + Definition.Context, + Input.Value, + { + currentState: "Start", + eventName: Input.Name, + timestamp: 0, + contractId: "abc123", + }, + ) - assert.ok(!result.context["ContractId"], "ContractId should not be in the context after the event") + assert.ok( + !result.context["ContractId"], + "ContractId should not be in the context after the event", + ) assert.strictEqual(result.state, "Success") }) }) diff --git a/tests/timers.spec.ts b/tests/timers.spec.ts index 93985a3..d243877 100644 --- a/tests/timers.spec.ts +++ b/tests/timers.spec.ts @@ -14,10 +14,9 @@ * limitations under the License. */ -import { test, Timer } from "../src" +import { setLogger, test, Timer } from "../src" import assert from "assert" import callSpy from "call-spy" -import { setLogger } from "../src/logging" const data = { After1: [