// Unit test for `profiles.create` — driven through `@voltro/testing`. // // The governance features (field encryption, retention TTL sweep, GDPR // export/erase) are wired by governancePlugin at boot — store middleware + // scheduled sweeps that the unit harness does NOT run. So this test targets the // executor's OWN observable behavior: a plain audited insert that echoes back // { id, name, email } (never the ssn). `makeTestContext` hands the handler the // SAME mixin-wrapped `ctx.store` it gets in production, so the audit() mixin // auto-fills createdAt/createdBy exactly as at runtime. // Run with `voltro test` (vitest). import { afterAll, beforeAll, describe, it, expect } from 'vitest' import { makeFieldCipher, setFieldCipher } from '@voltro/runtime' import { makeTestContext, mockStore, invoke } from '@voltro/testing' import { database } from '../database/schema' // registers actors / tenants / profiles import { createProfile } from '../mutations/profiles.create.mutation' import createProfileHandler from '../mutations/profiles.create.mutation.server' const subject = { type: 'user', id: 'admin_1', tenantId: 'acme' } as const // `profiles.ssn` is an `.encrypted()` column, so the store middleware refuses to // write it unless a field cipher is registered — normally `governancePlugin({ // fieldEncryption: true })` does that at boot from VOLTRO_FIELD_ENCRYPTION_KEY, // a step the unit harness doesn't run. We register the SAME AES-256-GCM cipher // process-globally here so the encrypted insert exercises the real write path // (plaintext in, ciphertext at rest), then clear it so the global doesn't leak. beforeAll(() => setFieldCipher(makeFieldCipher('unit-test-field-encryption-key'))) afterAll(() => setFieldCipher(undefined)) describe('profiles.create', () => { it('inserts a profile + echoes back { id, name, email } with a prof_ TypeID', async () => { const ctx = makeTestContext({ subject, store: mockStore({ profiles: [] }) }) const row = (await invoke( createProfile, createProfileHandler, { name: 'Ada Lovelace', email: 'ada@example.com', ssn: '123-45-6789' }, ctx, )) as { id: string; name: string; email: string } expect(row.name).toBe('Ada Lovelace') expect(row.email).toBe('ada@example.com') expect(row.id).toMatch(/^prof_/) // The handler deliberately does NOT echo the ssn — only id/name/email. expect(row).not.toHaveProperty('ssn') // The row is really persisted — the live query sees it. const rows = await ctx.store.query(database.profiles.descriptor) expect(rows).toHaveLength(1) }) it('rejects an empty name at the input-schema decode (NonEmptyString)', async () => { const ctx = makeTestContext({ subject, store: mockStore({ profiles: [] }) }) await expect( invoke(createProfile, createProfileHandler, { name: '', email: 'x@y.z', ssn: '000' }, ctx), ).rejects.toThrow() }) })