2026-09-16 07:46:58 +00:00
|
|
|
import PocketBase from "pocketbase";
|
|
|
|
|
|
|
|
|
|
export const PB_URL = process.env.NEXT_PUBLIC_PB_URL ?? "http://127.0.0.1:8090";
|
|
|
|
|
export const APP_URL = process.env.APP_URL ?? "http://localhost:3000";
|
|
|
|
|
|
|
|
|
|
export const DEMO = {
|
|
|
|
|
clientSlug: "wf",
|
|
|
|
|
projectSlug: "wfdash-webapp",
|
|
|
|
|
managerEmail: "manager@wf.example.com",
|
|
|
|
|
managerPassword: "manager-password-123",
|
2026-09-16 13:59:49 +00:00
|
|
|
ownerEmail: "owner@example.com",
|
|
|
|
|
ownerPassword: "owner-password-123",
|
2026-09-16 07:46:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Fail loudly rather than skipping. A permission test that silently skips is
|
|
|
|
|
* worse than no test: the suite goes green and nobody checks the boundary.
|
|
|
|
|
*/
|
|
|
|
|
export async function requireServices(): Promise<void> {
|
|
|
|
|
const pbUp = await fetch(`${PB_URL}/api/health`)
|
|
|
|
|
.then((r) => r.ok)
|
|
|
|
|
.catch(() => false);
|
|
|
|
|
|
|
|
|
|
if (!pbUp) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
`PocketBase is not reachable at ${PB_URL}. Check NEXT_PUBLIC_PB_URL.`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const appUp = await fetch(`${APP_URL}/login`)
|
|
|
|
|
.then((r) => r.ok)
|
|
|
|
|
.catch(() => false);
|
|
|
|
|
|
|
|
|
|
if (!appUp) {
|
|
|
|
|
throw new Error(
|
|
|
|
|
`The app is not reachable at ${APP_URL}. Run \`npm run dev\` first.`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function adminPb(): Promise<PocketBase> {
|
|
|
|
|
const pb = new PocketBase(PB_URL);
|
|
|
|
|
pb.autoCancellation(false);
|
|
|
|
|
await pb
|
|
|
|
|
.collection("_superusers")
|
|
|
|
|
.authWithPassword(
|
|
|
|
|
process.env.PB_SUPERUSER_EMAIL!,
|
|
|
|
|
process.env.PB_SUPERUSER_PASSWORD!
|
|
|
|
|
);
|
|
|
|
|
return pb;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Sign in through the app and return the Set-Cookie value for later requests. */
|
|
|
|
|
export async function signIn(
|
|
|
|
|
email: string,
|
|
|
|
|
password: string
|
|
|
|
|
): Promise<string> {
|
|
|
|
|
const response = await fetch(`${APP_URL}/api/auth/login`, {
|
|
|
|
|
method: "POST",
|
|
|
|
|
headers: { "content-type": "application/json" },
|
|
|
|
|
body: JSON.stringify({ email, password }),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
throw new Error(`Sign in failed for ${email}: ${response.status}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const setCookie = response.headers.get("set-cookie");
|
|
|
|
|
if (!setCookie) throw new Error("No auth cookie returned");
|
|
|
|
|
|
|
|
|
|
return setCookie.split(";")[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** A PocketBase client authenticated as a normal user, for read-rule tests. */
|
|
|
|
|
export async function userPb(
|
|
|
|
|
email: string,
|
|
|
|
|
password: string
|
|
|
|
|
): Promise<PocketBase> {
|
|
|
|
|
const pb = new PocketBase(PB_URL);
|
|
|
|
|
pb.autoCancellation(false);
|
|
|
|
|
await pb.collection("users").authWithPassword(email, password);
|
|
|
|
|
return pb;
|
|
|
|
|
}
|