Skip to content
GitHubXDiscord

mockAction

Stable · since 0.1.0

A method on the TestRuntime returned by createTestRuntime. Registers an action handler for a trigger. The test-time equivalent of useAction — same registration mechanism, no React.

The handler is typically a vi.fn() or jest.fn() so you can assert call counts and arguments directly.

import { createTestRuntime } from '@triggery/testing';

const rt = createTestRuntime();
rt.mockAction(/* ... */);
mockAction<S extends TriggerSchema, K extends ActionKey<S>>(
  trigger: Trigger<S>,
  name: K,
  handler: ActionFn<ActionMap<S>[K]>,
): RegistrationToken;

type ActionFn<P> = [P] extends [void] ? () => void : (payload: P) => void;
ParamTypeDescription
triggerTrigger<S>The trigger whose action you’re stubbing.
nameK extends ActionKey<S>An action declared in the trigger’s schema.
handlerActionFn<P>The mock implementation. Void-payload actions take () => void.

A RegistrationToken with { unregister(): void }.

import { createTriggerfunction createTrigger<S extends TriggerSchema>(config: CreateTriggerConfig<S>, runtime?: Runtime): Trigger<S>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
} from '@triggery/core';
import { createTestRuntimefunction createTestRuntime(options?: TestRuntimeOptions): TestRuntime } from '@triggery/testing'; import { expectconst expect: ExpectStatic, itconst it: TestAPI
Defines a test case with a given name and test function. The test function can optionally be configured with test options.
@paramname - The name of the test or a function that will be used as a test name.@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.@throws{Error} If called inside another test function.@example```ts // Define a simple test it('adds two numbers', () => { expect(add(1, 2)).toBe(3); }); ```@example```ts // Define a test with options it('subtracts two numbers', { retry: 3 }, () => { expect(subtract(5, 2)).toBe(3); }); ```
, viconst vi: VitestUtils } from 'vitest';
itit<object>(name: string | Function, fn?: TestFunction<object> | undefined, options?: number): void (+1 overload)
Defines a test case with a given name and test function. The test function can optionally be configured with test options.
@paramname - The name of the test or a function that will be used as a test name.@paramoptionsOrFn - Optional. The test options or the test function if no explicit name is provided.@paramoptionsOrTest - Optional. The test function or options, depending on the previous parameters.@throws{Error} If called inside another test function.@example```ts // Define a simple test it('adds two numbers', () => { expect(add(1, 2)).toBe(3); }); ```@example```ts // Define a test with options it('subtracts two numbers', { retry: 3 }, () => { expect(subtract(5, 2)).toBe(3); }); ```
('calls showToast with the right payload', () => {
const rtconst rt: TestRuntime = createTestRuntimefunction createTestRuntime(options?: TestRuntimeOptions): TestRuntime(); const t
const t: Trigger<{
    events: {
        "new-message": {
            author: string;
            text: string;
        };
    };
    actions: {
        showToast: {
            title: string;
        };
    };
}>
= createTrigger
createTrigger<{
    events: {
        "new-message": {
            author: string;
            text: string;
        };
    };
    actions: {
        showToast: {
            title: string;
        };
    };
}>(config: CreateTriggerConfig<{
    events: {
        "new-message": {
            author: string;
            text: string;
        };
    };
    actions: {
        showToast: {
            title: string;
        };
    };
}>, runtime?: Runtime): Trigger<{
    events: {
        "new-message": {
            author: string;
            text: string;
        };
    };
    actions: {
        showToast: {
            title: string;
        };
    };
}>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
<{
events
events: {
    'new-message': {
        author: string;
        text: string;
    };
}
: { 'new-message': { authorauthor: string: string; texttext: string: string } };
actions
actions: {
    showToast: {
        title: string;
    };
}
: { showToast
showToast: {
    title: string;
}
: { titletitle: string: string } };
}>( { idid: string: 'demo', eventsevents: readonly "new-message"[]: ['new-message'], handler
handler: TriggerHandler<{
    events: {
        "new-message": {
            author: string;
            text: string;
        };
    };
    actions: {
        showToast: {
            title: string;
        };
    };
}, never>
({ event
event: {
    readonly name: "new-message";
    readonly payload: {
        author: string;
        text: string;
    };
}
, actions
actions: ActionsCtx<{
    showToast: {
        title: string;
    };
}>
}) {
actions
actions: ActionsCtx<{
    showToast: {
        title: string;
    };
}>
.showToast
showToast?: ((payload: {
    title: string;
}) => void) | undefined
?.({ titletitle: string: event
event: {
    readonly name: "new-message";
    readonly payload: {
        author: string;
        text: string;
    };
}
.payload
payload: {
    author: string;
    text: string;
}
.authorauthor: string });
}, }, rtconst rt: TestRuntime, ); const showToastconst showToast: Mock<Procedure> = viconst vi: VitestUtils.fnVitestUtils.fn: <Procedure>(originalImplementation?: Procedure | undefined) => Mock<Procedure>
Creates a spy on a function, though can be initiated without one. Every time a function is invoked, it stores its call arguments, returns, and instances. Also, you can manipulate its behavior with [methods](https://vitest.dev/api/mock). If no function is given, mock will return `undefined`, when invoked.
@example```ts const getApples = vi.fn(() => 0) getApples() expect(getApples).toHaveBeenCalled() expect(getApples).toHaveReturnedWith(0) getApples.mockReturnValueOnce(5) expect(getApples()).toBe(5) expect(getApples).toHaveNthReturnedWith(2, 5) ```
();
rtconst rt: TestRuntime.mockAction
mockAction<{
    events: {
        "new-message": {
            author: string;
            text: string;
        };
    };
    actions: {
        showToast: {
            title: string;
        };
    };
}, "showToast">(trigger: Trigger<{
    events: {
        "new-message": {
            author: string;
            text: string;
        };
    };
    actions: {
        showToast: {
            title: string;
        };
    };
}>, name: "showToast", handler: (payload: {
    title: string;
}) => void): RegistrationToken
Register an action handler — typically a `vi.fn()`.
(t
const t: Trigger<{
    events: {
        "new-message": {
            author: string;
            text: string;
        };
    };
    actions: {
        showToast: {
            title: string;
        };
    };
}>
, 'showToast', showToastconst showToast: Mock<Procedure>);
rtconst rt: TestRuntime.fireSyncfunction fireSync(eventName: string, payload?: unknown): void
Run dispatch synchronously (for tests and benchmarks).
('new-message', { authorauthor: string: 'Alice', texttext: string: 'hi' });
expectexpect<Mock<Procedure>>(actual: Mock<Procedure>, message?: string): Assertion<Mock<Procedure>> (+1 overload)(showToastconst showToast: Mock<Procedure>).toHaveBeenCalledExactlyOnceWith
Assertion<Mock<Procedure>>.toHaveBeenCalledExactlyOnceWith: <[{
    title: string;
}]>(args_0: {
    title: string;
}) => void
Ensure that a mock function is called with specific arguments and called exactly once.
@exampleexpect(mockFunc).toHaveBeenCalledExactlyOnceWith('arg1', 42);
({ titletitle: string: 'Alice' });
});
import { createTriggerfunction createTrigger<S extends TriggerSchema>(config: CreateTriggerConfig<S>, runtime?: Runtime): Trigger<S>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
} from '@triggery/core';
import { createTestRuntimefunction createTestRuntime(options?: TestRuntimeOptions): TestRuntime } from '@triggery/testing'; import { viconst vi: VitestUtils } from 'vitest'; const rtconst rt: TestRuntime = createTestRuntimefunction createTestRuntime(options?: TestRuntimeOptions): TestRuntime(); const t
const t: Trigger<{
    events: {
        close: void;
    };
    actions: {
        onClose: void;
    };
}>
= createTrigger
createTrigger<{
    events: {
        close: void;
    };
    actions: {
        onClose: void;
    };
}>(config: CreateTriggerConfig<{
    events: {
        close: void;
    };
    actions: {
        onClose: void;
    };
}>, runtime?: Runtime): Trigger<{
    events: {
        close: void;
    };
    actions: {
        onClose: void;
    };
}>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
<{
events
events: {
    close: void;
}
: { closeclose: void: void };
actions
actions: {
    onClose: void;
}
: { onCloseonClose: void: void };
}>( { idid: string: 'demo', eventsevents: readonly "close"[]: ['close'], handler
handler: TriggerHandler<{
    events: {
        close: void;
    };
    actions: {
        onClose: void;
    };
}, never>
({ actions
actions: ActionsCtx<{
    onClose: void;
}>
}) {
actions
actions: ActionsCtx<{
    onClose: void;
}>
.onCloseonClose?: (() => void) | undefined?.();
}, }, rtconst rt: TestRuntime, ); const onCloseconst onClose: Mock<Procedure> = viconst vi: VitestUtils.fnVitestUtils.fn: <Procedure>(originalImplementation?: Procedure | undefined) => Mock<Procedure>
Creates a spy on a function, though can be initiated without one. Every time a function is invoked, it stores its call arguments, returns, and instances. Also, you can manipulate its behavior with [methods](https://vitest.dev/api/mock). If no function is given, mock will return `undefined`, when invoked.
@example```ts const getApples = vi.fn(() => 0) getApples() expect(getApples).toHaveBeenCalled() expect(getApples).toHaveReturnedWith(0) getApples.mockReturnValueOnce(5) expect(getApples()).toBe(5) expect(getApples).toHaveNthReturnedWith(2, 5) ```
();
rtconst rt: TestRuntime.mockAction
mockAction<{
    events: {
        close: void;
    };
    actions: {
        onClose: void;
    };
}, "onClose">(trigger: Trigger<{
    events: {
        close: void;
    };
    actions: {
        onClose: void;
    };
}>, name: "onClose", handler: () => void): RegistrationToken
Register an action handler — typically a `vi.fn()`.
(t
const t: Trigger<{
    events: {
        close: void;
    };
    actions: {
        onClose: void;
    };
}>
, 'onClose', onCloseconst onClose: Mock<Procedure>);
rtconst rt: TestRuntime.fireSyncfunction fireSync(eventName: string, payload?: unknown): void
Run dispatch synchronously (for tests and benchmarks).
('close');
import { createTriggerfunction createTrigger<S extends TriggerSchema>(config: CreateTriggerConfig<S>, runtime?: Runtime): Trigger<S>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
} from '@triggery/core';
import { createTestRuntimefunction createTestRuntime(options?: TestRuntimeOptions): TestRuntime } from '@triggery/testing'; import { viconst vi: VitestUtils } from 'vitest'; const rtconst rt: TestRuntime = createTestRuntimefunction createTestRuntime(options?: TestRuntimeOptions): TestRuntime(); const t
const t: Trigger<{
    events: {
        save: {
            id: string;
        };
    };
    actions: {
        persist: {
            id: string;
        };
    };
}>
= createTrigger
createTrigger<{
    events: {
        save: {
            id: string;
        };
    };
    actions: {
        persist: {
            id: string;
        };
    };
}>(config: CreateTriggerConfig<{
    events: {
        save: {
            id: string;
        };
    };
    actions: {
        persist: {
            id: string;
        };
    };
}>, runtime?: Runtime): Trigger<{
    events: {
        save: {
            id: string;
        };
    };
    actions: {
        persist: {
            id: string;
        };
    };
}>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
<{
events
events: {
    save: {
        id: string;
    };
}
: { save
save: {
    id: string;
}
: { idid: string: string } };
actions
actions: {
    persist: {
        id: string;
    };
}
: { persist
persist: {
    id: string;
}
: { idid: string: string } };
}>( { idid: string: 'demo', eventsevents: readonly "save"[]: ['save'], async handler
handler: TriggerHandler<{
    events: {
        save: {
            id: string;
        };
    };
    actions: {
        persist: {
            id: string;
        };
    };
}, never>
({ event
event: {
    readonly name: "save";
    readonly payload: {
        id: string;
    };
}
, actions
actions: ActionsCtx<{
    persist: {
        id: string;
    };
}>
}) {
await actions
actions: ActionsCtx<{
    persist: {
        id: string;
    };
}>
.persist
persist?: ((payload: {
    id: string;
}) => void) | undefined
?.(event
event: {
    readonly name: "save";
    readonly payload: {
        id: string;
    };
}
.payload
payload: {
    id: string;
}
);
}, }, rtconst rt: TestRuntime, ); const persist
const persist: Mock<(_payload: {
    id: string;
}) => Promise<void>>
= viconst vi: VitestUtils.fn
VitestUtils.fn: <(_payload: {
    id: string;
}) => Promise<void>>(originalImplementation?: ((_payload: {
    id: string;
}) => Promise<void>) | undefined) => Mock<(_payload: {
    id: string;
}) => Promise<void>>
Creates a spy on a function, though can be initiated without one. Every time a function is invoked, it stores its call arguments, returns, and instances. Also, you can manipulate its behavior with [methods](https://vitest.dev/api/mock). If no function is given, mock will return `undefined`, when invoked.
@example```ts const getApples = vi.fn(() => 0) getApples() expect(getApples).toHaveBeenCalled() expect(getApples).toHaveReturnedWith(0) getApples.mockReturnValueOnce(5) expect(getApples()).toBe(5) expect(getApples).toHaveNthReturnedWith(2, 5) ```
(async (_payload
_payload: {
    id: string;
}
: { idid: string: string }) => {
await Promisevar Promise: PromiseConstructor
Represents the completion of an asynchronous operation
.resolvePromiseConstructor.resolve(): Promise<void> (+2 overloads)
Creates a new resolved promise.
@returnsA resolved promise.
();
}); rtconst rt: TestRuntime.mockAction
mockAction<{
    events: {
        save: {
            id: string;
        };
    };
    actions: {
        persist: {
            id: string;
        };
    };
}, "persist">(trigger: Trigger<{
    events: {
        save: {
            id: string;
        };
    };
    actions: {
        persist: {
            id: string;
        };
    };
}>, name: "persist", handler: (payload: {
    id: string;
}) => void): RegistrationToken
Register an action handler — typically a `vi.fn()`.
(t
const t: Trigger<{
    events: {
        save: {
            id: string;
        };
    };
    actions: {
        persist: {
            id: string;
        };
    };
}>
, 'persist', persist
const persist: Mock<(_payload: {
    id: string;
}) => Promise<void>>
);
import { createTriggerfunction createTrigger<S extends TriggerSchema>(config: CreateTriggerConfig<S>, runtime?: Runtime): Trigger<S>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
} from '@triggery/core';
import { createTestRuntimefunction createTestRuntime(options?: TestRuntimeOptions): TestRuntime } from '@triggery/testing'; const rtconst rt: TestRuntime = createTestRuntimefunction createTestRuntime(options?: TestRuntimeOptions): TestRuntime(); const t
const t: Trigger<{
    events: {
        ping: void;
    };
    actions: {
        log: void;
    };
}>
= createTrigger
createTrigger<{
    events: {
        ping: void;
    };
    actions: {
        log: void;
    };
}>(config: CreateTriggerConfig<{
    events: {
        ping: void;
    };
    actions: {
        log: void;
    };
}>, runtime?: Runtime): Trigger<{
    events: {
        ping: void;
    };
    actions: {
        log: void;
    };
}>
Create a trigger and register it in a runtime (the default runtime if none is passed).
@example```ts const messageTrigger = createTrigger<{ events: { 'new-message': { author: string; text: string } }; conditions: { user: { id: string }; settings: { sound: boolean } }; actions: { showToast: { title: string }; playSound: void }; }>({ id: 'message-received', events: ['new-message'], required: ['user', 'settings'], handler({ event, conditions, actions, check }) { if (!conditions.user || !conditions.settings) return; // V1: manual narrowing if (check.is('settings', (s) => s.sound)) actions.playSound?.(); actions.showToast?.({ title: event.payload.author }); }, }); ```
<{
events
events: {
    ping: void;
}
: { pingping: void: void };
actions
actions: {
    log: void;
}
: { loglog: void: void };
}>( { idid: string: 'demo', eventsevents: readonly "ping"[]: ['ping'], handler
handler: TriggerHandler<{
    events: {
        ping: void;
    };
    actions: {
        log: void;
    };
}, never>
({ actions
actions: ActionsCtx<{
    log: void;
}>
}) { actions
actions: ActionsCtx<{
    log: void;
}>
.loglog?: (() => void) | undefined?.(); } },
rtconst rt: TestRuntime, ); const firstconst first: RegistrationToken = rtconst rt: TestRuntime.mockAction
mockAction<{
    events: {
        ping: void;
    };
    actions: {
        log: void;
    };
}, "log">(trigger: Trigger<{
    events: {
        ping: void;
    };
    actions: {
        log: void;
    };
}>, name: "log", handler: () => void): RegistrationToken
Register an action handler — typically a `vi.fn()`.
(t
const t: Trigger<{
    events: {
        ping: void;
    };
    actions: {
        log: void;
    };
}>
, 'log', () => consolevar console: Console.logConsole.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
('first'));
rtconst rt: TestRuntime.fireSyncfunction fireSync(eventName: string, payload?: unknown): void
Run dispatch synchronously (for tests and benchmarks).
('ping'); // "first"
firstconst first: RegistrationToken.unregisterfunction unregister(): void
Idempotent unregister.
();
rtconst rt: TestRuntime.mockAction
mockAction<{
    events: {
        ping: void;
    };
    actions: {
        log: void;
    };
}, "log">(trigger: Trigger<{
    events: {
        ping: void;
    };
    actions: {
        log: void;
    };
}>, name: "log", handler: () => void): RegistrationToken
Register an action handler — typically a `vi.fn()`.
(t
const t: Trigger<{
    events: {
        ping: void;
    };
    actions: {
        log: void;
    };
}>
, 'log', () => consolevar console: Console.logConsole.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
('second'));
rtconst rt: TestRuntime.fireSyncfunction fireSync(eventName: string, payload?: unknown): void
Run dispatch synchronously (for tests and benchmarks).
('ping'); // "second"