settings.test.ts, explore.test.ts, and social.test.ts weren't matched
by any Playwright project, so they had silently never run — which is
how they rotted. Register them (one project each) and repair the
selectors against the current UI:
- settings: the page was split into sibling sections
(/settings/{profile,security,account}); the spec assumed one page.
Navigate to the right sub-page per test, use the stable section-nav
links + #id input locators (the Vite dev server transiently
double-renders the profile form during hydration, breaking
getByLabel), and wait for hydration before interacting with
fetcher-backed forms and the avatar dropdown.
- explore: setProfileVisibility now targets /settings/profile and
waits for hydration so the visibility save uses the fetcher.
- social: already green once registered.
Also fixes an app bug the specs surfaced: deleting a passkey redirected
to /settings#security, a stale anchor that now resolves to
/settings/profile — so you'd land on the wrong section. It now
redirects to /settings/security.
Verified locally against Postgres/BRouter: green under CI-style
retries (the residual registration flake is the same cold-start class
the rest of the suite has, which is why CI runs retries=2).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
30 lines
1.1 KiB
TypeScript
30 lines
1.1 KiB
TypeScript
import { data, redirect } from "react-router";
|
|
import { eq, and } from "drizzle-orm";
|
|
import type { Route } from "./+types/api.settings.passkey.delete";
|
|
import { getSessionUser } from "~/lib/auth/session.server";
|
|
import { getDb } from "~/lib/db";
|
|
import { credentials } from "@trails-cool/db/schema/journal";
|
|
|
|
export async function action({ request }: Route.ActionArgs) {
|
|
const user = await getSessionUser(request);
|
|
if (!user) throw redirect("/auth/login");
|
|
|
|
const formData = await request.formData();
|
|
const credentialId = formData.get("credentialId") as string;
|
|
if (!credentialId) return data({ error: "Missing credential ID" }, { status: 400 });
|
|
|
|
const db = getDb();
|
|
const deleted = await db
|
|
.delete(credentials)
|
|
.where(and(eq(credentials.id, credentialId), eq(credentials.userId, user.id)))
|
|
.returning();
|
|
|
|
if (deleted.length === 0) {
|
|
return data({ error: "Passkey not found" }, { status: 404 });
|
|
}
|
|
|
|
// Settings is split into sections now; the bare /settings#security
|
|
// anchor resolves to /settings/profile. Send the user back to the
|
|
// security section they were on.
|
|
return redirect("/settings/security");
|
|
}
|