@pikku/core 0.12.52 → 0.12.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/services/index.d.ts +3 -0
- package/dist/services/index.js +3 -0
- package/dist/services/istanbul-coverage-service.d.ts +12 -0
- package/dist/services/istanbul-coverage-service.js +41 -0
- package/dist/services/scenario-actors-service.d.ts +3 -21
- package/dist/services/stub-tracker.d.ts +43 -0
- package/dist/services/stub-tracker.js +146 -0
- package/dist/services/v8-coverage-service.d.ts +41 -0
- package/dist/services/v8-coverage-service.js +63 -0
- package/dist/types/core.types.d.ts +9 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +16 -0
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +0 -6
- package/dist/wirings/workflow/pikku-workflow-service.js +56 -6
- package/dist/wirings/workflow/workflow.types.d.ts +1 -1
- package/package.json +1 -1
- package/src/services/index.ts +19 -0
- package/src/services/istanbul-coverage-service.test.ts +66 -0
- package/src/services/istanbul-coverage-service.ts +65 -0
- package/src/services/scenario-actors-service.ts +3 -21
- package/src/services/stub-tracker.test.ts +104 -0
- package/src/services/stub-tracker.ts +185 -0
- package/src/services/v8-coverage-service.test.ts +69 -0
- package/src/services/v8-coverage-service.ts +121 -0
- package/src/types/core.types.ts +9 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +29 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +100 -6
- package/src/wirings/workflow/workflow.types.ts +2 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -37,6 +37,20 @@ export interface WorkflowExpectEventuallyOptions extends WorkflowStepOptions {
|
|
|
37
37
|
interval?: string | number
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/** Options for workflow.expectError() */
|
|
41
|
+
export interface WorkflowExpectErrorOptions extends WorkflowStepOptions {
|
|
42
|
+
/** Assert the error message matches (string = substring match). */
|
|
43
|
+
matches?: string | RegExp
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Options for workflow.expectService() */
|
|
47
|
+
export interface WorkflowExpectServiceOptions extends WorkflowStepOptions {
|
|
48
|
+
/** Assert a recorded call's first argument deep-equals this value. */
|
|
49
|
+
calledWith?: unknown
|
|
50
|
+
/** Assert the exact number of matching calls. Default: at least one. */
|
|
51
|
+
times?: number
|
|
52
|
+
}
|
|
53
|
+
|
|
40
54
|
/**
|
|
41
55
|
* Type signature for workflow.do() RPC form - used by inspector
|
|
42
56
|
*/
|
|
@@ -381,6 +395,21 @@ export interface PikkuWorkflowWire {
|
|
|
381
395
|
options?: WorkflowExpectEventuallyOptions
|
|
382
396
|
) => Promise<TOutput>
|
|
383
397
|
|
|
398
|
+
/** Error-path step (scenarios): succeeds only when the RPC throws; returns the message */
|
|
399
|
+
expectError: <TInput = any>(
|
|
400
|
+
stepName: string,
|
|
401
|
+
rpcName: string,
|
|
402
|
+
data: TInput,
|
|
403
|
+
options?: WorkflowExpectErrorOptions
|
|
404
|
+
) => Promise<string>
|
|
405
|
+
|
|
406
|
+
/** Stub-assertion step (scenarios): asserts `service.method` was called on the target server */
|
|
407
|
+
expectService: (
|
|
408
|
+
stepName: string,
|
|
409
|
+
serviceMethod: string,
|
|
410
|
+
options?: WorkflowExpectServiceOptions
|
|
411
|
+
) => Promise<void>
|
|
412
|
+
|
|
384
413
|
/** Sleep for a duration */
|
|
385
414
|
sleep: WorkflowWireSleep
|
|
386
415
|
|
|
@@ -60,6 +60,8 @@ import type {
|
|
|
60
60
|
WorkflowServiceConfig,
|
|
61
61
|
WorkflowStepOptions,
|
|
62
62
|
WorkflowExpectEventuallyOptions,
|
|
63
|
+
WorkflowExpectErrorOptions,
|
|
64
|
+
WorkflowExpectServiceOptions,
|
|
63
65
|
} from './workflow.types.js'
|
|
64
66
|
import {
|
|
65
67
|
continueGraph,
|
|
@@ -1099,12 +1101,6 @@ export abstract class PikkuWorkflowService implements WorkflowService {
|
|
|
1099
1101
|
})
|
|
1100
1102
|
}
|
|
1101
1103
|
|
|
1102
|
-
/**
|
|
1103
|
-
* Start a new workflow run
|
|
1104
|
-
* Automatically detects workflow type (DSL or graph) from meta and executes accordingly
|
|
1105
|
-
* @param options.inline - If true, execute workflow directly without queue service
|
|
1106
|
-
* @param options.startNode - Starting node ID for graph workflows (from wire config)
|
|
1107
|
-
*/
|
|
1108
1104
|
/**
|
|
1109
1105
|
* Start a new workflow run
|
|
1110
1106
|
* Automatically detects workflow type (DSL or graph) from meta and executes accordingly
|
|
@@ -2229,6 +2225,104 @@ export abstract class PikkuWorkflowService implements WorkflowService {
|
|
|
2229
2225
|
)
|
|
2230
2226
|
},
|
|
2231
2227
|
|
|
2228
|
+
expectError: async (
|
|
2229
|
+
stepName: string,
|
|
2230
|
+
rpcName: string,
|
|
2231
|
+
data: any,
|
|
2232
|
+
options?: WorkflowExpectErrorOptions
|
|
2233
|
+
) => {
|
|
2234
|
+
this.verifyStepName(stepName)
|
|
2235
|
+
const resolvedRpcName =
|
|
2236
|
+
addonNamespace && !rpcName.includes(':')
|
|
2237
|
+
? `${addonNamespace}:${rpcName}`
|
|
2238
|
+
: rpcName
|
|
2239
|
+
return await this.inlineStep(
|
|
2240
|
+
runId,
|
|
2241
|
+
stepName,
|
|
2242
|
+
async () => {
|
|
2243
|
+
let result: any
|
|
2244
|
+
try {
|
|
2245
|
+
result = options?.actor
|
|
2246
|
+
? await options.actor.invoke(resolvedRpcName, data)
|
|
2247
|
+
: await rpcService.rpcWithWire(resolvedRpcName, data, {})
|
|
2248
|
+
} catch (e: any) {
|
|
2249
|
+
const message = e?.message ?? String(e)
|
|
2250
|
+
if (options?.matches) {
|
|
2251
|
+
const matched =
|
|
2252
|
+
typeof options.matches === 'string'
|
|
2253
|
+
? message.includes(options.matches)
|
|
2254
|
+
: options.matches.test(message)
|
|
2255
|
+
if (!matched) {
|
|
2256
|
+
throw new Error(
|
|
2257
|
+
`[workflow] expectError '${stepName}' ('${resolvedRpcName}') threw, but the message did not match ${options.matches}: ${message}`
|
|
2258
|
+
)
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
return message
|
|
2262
|
+
}
|
|
2263
|
+
throw new Error(
|
|
2264
|
+
`[workflow] expectError '${stepName}' ('${resolvedRpcName}') expected an error but the call succeeded: ${JSON.stringify(result)?.slice(0, 300)}`
|
|
2265
|
+
)
|
|
2266
|
+
},
|
|
2267
|
+
options
|
|
2268
|
+
)
|
|
2269
|
+
},
|
|
2270
|
+
|
|
2271
|
+
expectService: async (
|
|
2272
|
+
stepName: string,
|
|
2273
|
+
serviceMethod: string,
|
|
2274
|
+
options?: WorkflowExpectServiceOptions
|
|
2275
|
+
) => {
|
|
2276
|
+
this.verifyStepName(stepName)
|
|
2277
|
+
const [service, method] = serviceMethod.split('.')
|
|
2278
|
+
if (!service || !method) {
|
|
2279
|
+
throw new Error(
|
|
2280
|
+
`[workflow] expectService '${stepName}' needs 'service.method', got '${serviceMethod}'`
|
|
2281
|
+
)
|
|
2282
|
+
}
|
|
2283
|
+
await this.inlineStep(
|
|
2284
|
+
runId,
|
|
2285
|
+
stepName,
|
|
2286
|
+
async () => {
|
|
2287
|
+
const rpcName = 'console:getStubCalls'
|
|
2288
|
+
const calls: Array<{
|
|
2289
|
+
service: string
|
|
2290
|
+
method: string
|
|
2291
|
+
args: unknown[]
|
|
2292
|
+
}> = options?.actor
|
|
2293
|
+
? await options.actor.invoke(rpcName, { service })
|
|
2294
|
+
: await rpcService.rpcWithWire(rpcName, { service }, {})
|
|
2295
|
+
const matching = (calls ?? []).filter(
|
|
2296
|
+
(c) =>
|
|
2297
|
+
c.service === service &&
|
|
2298
|
+
c.method === method &&
|
|
2299
|
+
(options?.calledWith === undefined ||
|
|
2300
|
+
JSON.stringify(c.args?.[0]) ===
|
|
2301
|
+
JSON.stringify(options.calledWith))
|
|
2302
|
+
)
|
|
2303
|
+
const expected = options?.times
|
|
2304
|
+
const ok =
|
|
2305
|
+
expected === undefined
|
|
2306
|
+
? matching.length > 0
|
|
2307
|
+
: matching.length === expected
|
|
2308
|
+
if (!ok) {
|
|
2309
|
+
const seen =
|
|
2310
|
+
(calls ?? [])
|
|
2311
|
+
.map(
|
|
2312
|
+
(c) =>
|
|
2313
|
+
`${c.service}.${c.method}(${JSON.stringify(c.args?.[0])?.slice(0, 120) ?? ''})`
|
|
2314
|
+
)
|
|
2315
|
+
.join('\n ') || '(none)'
|
|
2316
|
+
throw new Error(
|
|
2317
|
+
`[workflow] expectService '${stepName}' expected ${expected ?? 'at least one'} call(s) to '${serviceMethod}'` +
|
|
2318
|
+
`${options?.calledWith !== undefined ? ` with ${JSON.stringify(options.calledWith)}` : ''}, found ${matching.length}. Recorded:\n ${seen}`
|
|
2319
|
+
)
|
|
2320
|
+
}
|
|
2321
|
+
},
|
|
2322
|
+
options
|
|
2323
|
+
)
|
|
2324
|
+
},
|
|
2325
|
+
|
|
2232
2326
|
// Implement workflow.sleep()
|
|
2233
2327
|
sleep: async (stepName: string, duration: string | number) => {
|
|
2234
2328
|
this.verifyStepName(stepName)
|
|
@@ -8,6 +8,8 @@ export type { WorkflowService } from '../../services/workflow-service.js'
|
|
|
8
8
|
export type {
|
|
9
9
|
WorkflowStepOptions,
|
|
10
10
|
WorkflowExpectEventuallyOptions,
|
|
11
|
+
WorkflowExpectErrorOptions,
|
|
12
|
+
WorkflowExpectServiceOptions,
|
|
11
13
|
WorkflowWireDoRPC,
|
|
12
14
|
WorkflowWireDoInline,
|
|
13
15
|
WorkflowWireSleep,
|