MAI CALL - step 4
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* AC verification for Passo 4:
|
||||
* requireRole('ADMIN') returns FORBIDDEN for OPERATOR, passes for ADMIN.
|
||||
*
|
||||
* Uses createCallerFactory with in-memory contexts — no DB or HTTP required.
|
||||
*/
|
||||
import { TRPCError } from '@trpc/server';
|
||||
import { router, createCallerFactory, requireRole } from '../packages/api/src/trpc.js';
|
||||
import type { Context } from '../packages/api/src/context.js';
|
||||
|
||||
function makeCtx(role: 'ADMIN' | 'OPERATOR'): Context {
|
||||
return {
|
||||
user: { id: 'u1', email: `${role.toLowerCase()}@demo.local`, role, tenantId: 't1' },
|
||||
// db / prisma / logger are not touched by the role check, use minimal stubs
|
||||
db: {} as Context['db'],
|
||||
prisma: {} as Context['prisma'],
|
||||
tenantId: 't1',
|
||||
headers: new Headers(),
|
||||
logger: console as unknown as Context['logger'],
|
||||
};
|
||||
}
|
||||
|
||||
const testRouter = router({
|
||||
adminOnly: requireRole('ADMIN').query(() => ({ ok: true })),
|
||||
});
|
||||
|
||||
const createCaller = createCallerFactory(testRouter);
|
||||
|
||||
async function main() {
|
||||
// OPERATOR must be rejected with FORBIDDEN
|
||||
try {
|
||||
await createCaller(makeCtx('OPERATOR')).adminOnly();
|
||||
throw new Error('Expected FORBIDDEN but call succeeded');
|
||||
} catch (err) {
|
||||
if (err instanceof TRPCError && err.code === 'FORBIDDEN') {
|
||||
console.log('OPERATOR → FORBIDDEN ✓');
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// ADMIN must succeed
|
||||
const result = await createCaller(makeCtx('ADMIN')).adminOnly();
|
||||
if (!result.ok) throw new Error('ADMIN call returned unexpected result');
|
||||
console.log('ADMIN → ok ✓');
|
||||
|
||||
console.log('\nRole middleware AC PASSED');
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('Role middleware AC FAILED:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user