// Unit tests with `@voltro/testing` — no database, no running server. Two // things get covered: // // 1. `orders.place` — the runnable primitive. `makeTestContext` hands the // handler the SAME mixin-wrapped `ctx.store` it gets in production, so // tenant auto-scoping + the `order_…` id injection behave exactly as at // runtime. // 2. `orders.fulfill` — the workflow is descriptor-pinned. A real run PARKS // on `awaitSignal('approval')` (a human-approval gate), so a plain // `start()` never resolves in a unit test; a full run needs a signal // (integration). Here we assert the wire contract (name / payload / // success decode) and that the executor factory is wired. // // Run with `voltro test` (vitest). import { describe, it, expect } from 'vitest' import { Schema } from 'effect' import { invoke, makeTestContext, mockStore } from '@voltro/testing' import { database } from '../database/schema' // registers orders / actors / tenants import { placeOrder } from '../mutations/orders.place.mutation' import placeOrderExecutor from '../mutations/orders.place.mutation.server' import { FulfillOrder } from '../workflows/order.fulfill.workflow' import buildExecute from '../workflows/order.fulfill.workflow.server' describe('orders.place', () => { it('inserts an order, auto-stamped to the caller tenant', async () => { const ctx = makeTestContext({ subject: { type: 'user', id: 'user_1', tenantId: 'acme' }, store: mockStore({ orders: [] }), }) // `invoke`, NOT `await placeOrderExecutor(...)`. An executor written in the // Effect style RETURNS an Effect, and awaiting a non-thenable hands the // Effect object straight back — unrun. `row.status` then reads `undefined` // and the test fails pointing at the assertion rather than at the call. // // `invoke` is what production does: it decodes the input against the // descriptor's schema, runs the guards, and runs an Effect handler through // the same path the dispatcher uses (so a typed error stays typed instead of // arriving as a FiberFailure). Passing the DESCRIPTOR is what makes those // hops possible. const row = await invoke( placeOrder, placeOrderExecutor, { tenantId: 'acme', customerName: 'Ada Lovelace', amountCents: 4200 }, ctx, ) expect(row.status).toBe('placed') expect(row.customerName).toBe('Ada Lovelace') expect(row.amountCents).toBe(4200) expect(row.tenantId).toBe('acme') // tenant() stamped it from the subject expect(row.id).toMatch(/^order_/) // TypeID auto-injected }) it('isolates tenants — t2 never sees t1 rows (REAL tenant scoping)', async () => { const ctx = makeTestContext({ subject: { type: 'user', id: 'u1', tenantId: 't1' }, store: mockStore({ orders: [] }), }) await invoke(placeOrder, placeOrderExecutor, { tenantId: 't1', customerName: 'Grace', amountCents: 100 }, ctx) // Re-scope the SAME store to a different tenant — the real WHERE filter // hides t1's row from t2. const seenByT2 = await ctx.withTenant('t2', (c) => c.store.query(database.orders.descriptor)) expect(seenByT2).toHaveLength(0) }) }) describe('orders.fulfill (workflow descriptor)', () => { it('declares the expected wire name', () => { expect(FulfillOrder.name).toBe('orders.fulfill') }) it('accepts a valid { orderId, tenantId } payload and rejects a malformed one', () => { const decode = Schema.decodeUnknownSync(FulfillOrder.payloadSchema) expect(decode({ orderId: 'order_1', tenantId: 'acme' })).toMatchObject({ orderId: 'order_1', tenantId: 'acme', }) expect(() => decode({ orderId: 'order_1' })).toThrow() // missing tenantId }) it('declares a { orderId, outcome } success schema with a literal outcome', () => { const decode = Schema.decodeUnknownSync(FulfillOrder.successSchema) expect(decode({ orderId: 'order_1', outcome: 'shipped' })).toEqual({ orderId: 'order_1', outcome: 'shipped', }) expect(decode({ orderId: 'order_1', outcome: 'rejected' })).toEqual({ orderId: 'order_1', outcome: 'rejected', }) expect(() => decode({ orderId: 'order_1', outcome: 'delivered' })).toThrow() // not in the literal union }) it('exposes an executor factory (ctx) => run — a real run needs an approval signal (integration)', () => { const ctx = makeTestContext({ subject: { type: 'user', id: 'user_1', tenantId: 't1' }, store: mockStore({ orders: [] }), }) expect(typeof buildExecute).toBe('function') expect(typeof buildExecute(ctx)).toBe('function') }) })