Test code-native integration flows end-to-end using invokeFlow() and createMockContextComponents().
invokeFlow() lets you unit test an entire code-native integration Flow by running both its trigger (onTrigger) and execution (onExecution) functions in sequence. You can provide config var values, context overrides, and partial trigger payloads.
Config var values keyed by config var name. String values are passed through directly. ConnectionValue objects (from createConnection() or connectionValue()) are recognized by the presence of a fields key.
A flow with no custom trigger uses the default webhook trigger. The body data from the trigger payload is available at params.onTrigger.results.body.data:
connectionValue() reads process.env.PRISMATIC_CONNECTION_VALUE by default. You can pass a custom environment variable name: connectionValue("MY_CONN_VAR").
Mocking component actions with createMockContextComponents()
When a flow invokes other components via context.components, use createMockContextComponents() to inject mock implementations. By default it returns each action’s examplePayload; pass explicit overrides for actions that need custom behavior.
registry — an object mapping component keys to their ComponentManifest-shaped actions map. This is typically the componentRegistry object from your CNI.
mocks.actions — an optional nested object keyed as { [componentKey]: { [actionKey]: () => Promise<any> } }. Actions listed here override the default examplePayload response.
mock-context-components.test.ts
import { describe, expect, it } from "vitest";import { flow } from "@prismatic-io/spectral";import { invokeFlow, createMockContextComponents,} from "@prismatic-io/spectral/dist/testing";import { componentRegistry } from "./src/componentRegistry";const myFlow = flow({ name: "My Flow", stableKey: "my-flow", description: "Calls another component action", onExecution: async (context, params) => { // context.components.myComponent.fetchData is mocked below const response = await context.components.myComponent.fetchData({ endpoint: "https://api.example.com/data", }); return { data: response.data }; },});describe("myFlow", () => { it("uses mocked component action", async () => { const components = createMockContextComponents(componentRegistry, { actions: { myComponent: { fetchData: () => Promise.resolve({ data: "mocked response" }), }, }, }); const { result } = await invokeFlow(myFlow, { context: { components }, }); expect(result).toMatchObject({ data: "mocked response" }); }); it("falls back to examplePayload for unmocked actions", async () => { // No overrides — every action returns its examplePayload const components = createMockContextComponents(componentRegistry); const { result } = await invokeFlow(myFlow, { context: { components }, }); // result.data matches the examplePayload defined in the manifest expect(result.data).toBeDefined(); });});
When testing a flow in isolation, override only the component actions that produce values your flow’s logic branches on. Let other actions fall back to their examplePayload to keep tests focused.