/** * Seeds a passenger IAM user + session directly (no OTP flow) and mints an access token the portal * accepts. The API JwtGuard verifies the JWT signature (JWT_ACCESS_TOKEN_SECRET) and looks up the * session by its `id` claim; the portal then calls /auth/profile which needs a Passenger row linked * by iamUserId. Returns { token, profile } for the Playwright passenger storageState. * * Run standalone to validate: `npx ts-node test/fixtures/seed-passenger-session.ts` (prints the * token and the /auth/profile status via the running API on :4000). */ import { PrismaClient } from "@prisma/client"; import { SignJWT } from "jose"; import { UI_IDS } from "./seed-ui"; export const PASSENGER_USER_ID = "11111111-0000-4000-8000-000000000001"; export const PASSENGER_SESSION_ID = "11111111-0000-4000-8000-000000000002"; const EMAIL = "test.passenger@edr.local"; const USERNAME = "test_passenger"; export async function seedPassengerSession(prisma: PrismaClient): Promise<{ token: string }> { const secret = process.env.JWT_ACCESS_TOKEN_SECRET; if (!secret) throw new Error("JWT_ACCESS_TOKEN_SECRET is required to mint the passenger token"); const userInfo = { id: PASSENGER_USER_ID, name: { en: "Test Passenger" }, email: EMAIL, roles: [] as unknown[], status: "accepted", employee: [] as unknown[], userType: "individual", username: USERNAME, permissions: [] as unknown[], }; const expiry = new Date(Date.now() + 7 * 86400_000); // iam.users (delete-then-insert so re-seeding is idempotent). await prisma.$executeRawUnsafe(`DELETE FROM iam.sessions WHERE id = $1::uuid`, PASSENGER_SESSION_ID); await prisma.$executeRawUnsafe(`DELETE FROM iam.users WHERE id = $1::uuid`, PASSENGER_USER_ID); await prisma.$executeRawUnsafe( `INSERT INTO iam.users (created_at, id, name, username, email, user_type, status, is_active, has_set_password, is_phone_number_verified, verified_by) VALUES (now(), $1::uuid, $2::jsonb, $3, $4, 'individual', 'accepted', true, true, true, 'SYSTEM')`, PASSENGER_USER_ID, JSON.stringify(userInfo.name), USERNAME, EMAIL, ); await prisma.$executeRawUnsafe( `INSERT INTO iam.sessions (created_at, id, email, device, "userInfo", expiry_time, refresh_count, status, user_id) VALUES (now(), $1::uuid, $2, 'e2e', $3::jsonb, $4, 0, 'ACTIVE', $5::uuid)`, PASSENGER_SESSION_ID, EMAIL, JSON.stringify(userInfo), expiry, PASSENGER_USER_ID, ); // Link the seeded Passenger row to this IAM user so /auth/profile resolves. await prisma.passenger.update({ where: { id: UI_IDS.passenger }, data: { iamUserId: PASSENGER_USER_ID }, }); const token = await new SignJWT({ id: PASSENGER_SESSION_ID }) .setProtectedHeader({ alg: "HS256", typ: "JWT" }) .setIssuedAt() .setExpirationTime("7d") .sign(new TextEncoder().encode(secret)); return { token }; } if (require.main === module) { (async () => { const prisma = new PrismaClient(); try { const { token } = await seedPassengerSession(prisma); const api = process.env.API_URL ?? "http://localhost:4000"; const res = await fetch(`${api}/auth/profile`, { headers: { Authorization: `Bearer ${token}` }, }); // eslint-disable-next-line no-console console.log(`[passenger-session] /auth/profile -> HTTP ${res.status}`); // eslint-disable-next-line no-console console.log((await res.text()).slice(0, 400)); } finally { await prisma.$disconnect(); } })(); }