import { E2E_OWNER_ROLE_ID, E2E_PROJECT_ID, E2E_UID, E2E_WORKSPACE_ID, openDb } from "../helpers"; // Flips onboarding flags on the seeded user so specs can exercise the wizards through the real UI; the wizards restore the flags on completion, this exists only as a safety net for cleanup when a test fails midway. export function updateUser(fields: { first_login_done?: number }): void { const db = openDb(); const sets: string[] = []; const values: number[] = []; if (fields.first_login_done !== undefined) { sets.push("first_login_done = ?"); values.push(fields.first_login_done); } if (sets.length === 0) { db.close(); return; } db.prepare(`UPDATE users SET ${sets.join(", ")} WHERE id = ?`).run(...values, E2E_UID); db.close(); } // Removes the seeded Owner role/membership so the owner-wizard spec can exercise the real tenancy.Service.BindDefaultWorkspaceOwner flow, which always INSERTs a fresh singleton Owner role rather than reusing the one global.ts seeds for every other spec's benefit; leaving that row in place makes CompleteOwnerWizard 409 with a role conflict on a genuinely fresh onboarding run. export function clearDefaultWorkspaceOwnership(): void { const db = openDb(); db.prepare(`DELETE FROM member_roles WHERE user_id = ? AND workspace_id = ?`).run(E2E_UID, E2E_WORKSPACE_ID); db.prepare(`DELETE FROM workspace_members WHERE user_id = ? AND workspace_id = ?`).run(E2E_UID, E2E_WORKSPACE_ID); db.prepare(`DELETE FROM roles WHERE workspace_id = ? AND is_owner_role = 1`).run(E2E_WORKSPACE_ID); db.close(); } // Re-seeds what clearDefaultWorkspaceOwnership removed, as a safety net for afterAll so a mid-test failure can't leave every other spec file without a workspace owner; idempotent like global.ts's seed, a no-op once the wizard has already recreated them. export function restoreDefaultWorkspaceOwnership(): void { const db = openDb(); const now = Math.floor(Date.now() / 1000); db.prepare( `INSERT INTO roles (id, workspace_id, name, is_owner_role, created_at, updated_at) SELECT ?, ?, 'Owner', 1, ?, ? WHERE NOT EXISTS (SELECT 1 FROM roles WHERE workspace_id = ? AND is_owner_role = 1)`, ).run(E2E_OWNER_ROLE_ID, E2E_WORKSPACE_ID, now, now, E2E_WORKSPACE_ID); db.prepare( `INSERT INTO workspace_members (user_id, workspace_id, created_at) VALUES (?, ?, ?) ON CONFLICT(user_id, workspace_id) DO NOTHING`, ).run(E2E_UID, E2E_WORKSPACE_ID, now); db.prepare(`DELETE FROM member_roles WHERE user_id = ? AND workspace_id = ?`).run(E2E_UID, E2E_WORKSPACE_ID); db.prepare( `INSERT INTO member_roles (user_id, workspace_id, role_id, created_at) SELECT ?, ?, id, ? FROM roles WHERE workspace_id = ? AND is_owner_role = 1`, ).run(E2E_UID, E2E_WORKSPACE_ID, now, E2E_WORKSPACE_ID); db.close(); } // Docs are project-scoped (internal/docs/usecase.go rejects a missing project_id), so this always creates the doc under the seeded e2e project. export async function createDocWith(token: string, title: string): Promise { const res = await fetch(`${process.env.NEXUL_BASE_URL ?? "http://web"}/api/docs`, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" }, body: JSON.stringify({ title, project_id: E2E_PROJECT_ID }), }); const body = (await res.json()) as { id: string }; return body.id; }