/** * AC verification for Passo 7: * op1 creates a request → admin claims → admin resolves → queue shows correct order. * Repeat create with same clientRequestId returns the same row without error. */ import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { config as loadEnv } from 'dotenv'; const here = path.dirname(fileURLToPath(import.meta.url)); loadEnv({ path: path.resolve(here, '../.env') }); import { prisma } from '../packages/db/src/index.js'; import { appRouter, createTRPCContext } from '../packages/api/src/index.js'; import { createCallerFactory } from '../packages/api/src/trpc.js'; async function makeCaller(email: string) { const user = await prisma.user.findFirst({ where: { email } }); if (!user) throw new Error(`User ${email} not found — run pnpm db:seed`); const ctx = await createTRPCContext({ user: { id: user.id, email: user.email, role: user.role as 'ADMIN' | 'OPERATOR', tenantId: user.tenantId }, headers: new Headers(), }); return createCallerFactory(appRouter)(ctx); } async function main() { const op1 = await makeCaller('op1@demo.local'); const admin = await makeCaller('admin@demo.local'); // Find a workstation to use const workstations = await admin.workstation.list(); const ws = workstations[0]; if (!ws) throw new Error('No workstations found — run pnpm db:seed'); const clientRequestId = crypto.randomUUID(); // --- create --- console.log('1. op1 creates a maintenance request...'); const created = await op1.maintenanceRequest.create({ workstationId: ws.id, description: 'Barulho anormal no posto CTR04 — teste smoke', clientRequestId, }); if (created.status !== 'OPEN') throw new Error(`Expected OPEN, got ${created.status}`); console.log(` Created id=${created.id} status=${created.status} ✓`); // --- idempotent duplicate --- console.log('2. Repeating create with same clientRequestId...'); const duplicate = await op1.maintenanceRequest.create({ workstationId: ws.id, description: 'Duplicado — deve devolver a row existente', clientRequestId, }); if (duplicate.id !== created.id) { throw new Error(`Idempotency failed: got id=${duplicate.id}, expected ${created.id}`); } console.log(` Same id returned (${duplicate.id}) ✓`); // --- getById --- console.log('3. getById...'); const fetched = await op1.maintenanceRequest.getById({ id: created.id }); if (fetched.workstation.code !== ws.code) throw new Error('workstation relation missing'); console.log(` workstation=${fetched.workstation.code}, reportedBy=${fetched.reportedBy.email} ✓`); // --- claim --- console.log('4. admin claims the request...'); const claimed = await admin.maintenanceRequest.claim({ id: created.id }); if (claimed.status !== 'CLAIMED') throw new Error(`Expected CLAIMED, got ${claimed.status}`); console.log(` status=${claimed.status} claimedBy=${claimed.claimedBy?.email} ✓`); // --- cannot claim again --- console.log('5. Claiming again should return CONFLICT...'); try { await admin.maintenanceRequest.claim({ id: created.id }); throw new Error('Expected CONFLICT but succeeded'); } catch (err: unknown) { const trpcErr = err as { code?: string }; if (trpcErr.code !== 'CONFLICT') throw err; console.log(' CONFLICT returned ✓'); } // --- resolve --- console.log('6. admin resolves the request...'); const resolved = await admin.maintenanceRequest.resolve({ id: created.id, resolutionNote: 'Peça trocada', }); if (resolved.status !== 'RESOLVED') throw new Error(`Expected RESOLVED, got ${resolved.status}`); console.log(` status=${resolved.status} resolvedBy=${resolved.resolvedBy?.email} ✓`); // --- queue order --- console.log('7. Creating two more requests to verify queue order...'); const r2 = await op1.maintenanceRequest.create({ workstationId: ws.id, description: 'Segundo pedido smoke test ABC', clientRequestId: crypto.randomUUID(), }); const r3 = await op1.maintenanceRequest.create({ workstationId: ws.id, description: 'Terceiro pedido smoke test XYZ', clientRequestId: crypto.randomUUID(), }); const queue = await admin.maintenanceRequest.queue({ statuses: ['OPEN'], limit: 10 }); const ids = queue.items.map((i) => i.id); const r3Index = ids.indexOf(r3.id); const r2Index = ids.indexOf(r2.id); if (r3Index === -1 || r2Index === -1) throw new Error('Requests not in queue'); if (r3Index > r2Index) throw new Error('Queue not ordered by createdAt DESC'); console.log(` Queue order DESC: r3 at pos ${r3Index}, r2 at pos ${r2Index} ✓`); // --- DomainEvents --- console.log('8. Verifying DomainEvents were emitted...'); const events = await prisma.domainEvent.findMany({ where: { aggregateId: created.id }, orderBy: { occurredAt: 'asc' }, }); const types = events.map((e) => e.eventType); if (JSON.stringify(types) !== JSON.stringify(['created', 'claimed', 'resolved'])) { throw new Error(`Unexpected event types: ${JSON.stringify(types)}`); } console.log(` Events: ${types.join(' → ')} ✓`); await prisma.$disconnect(); console.log('\nMaintenanceRequest router AC PASSED'); } main().catch(async (err) => { console.error('MaintenanceRequest router AC FAILED:', err); await prisma.$disconnect(); process.exit(1); });