fix: gate captureException on user consent and fix HEIC PII scrubbing

captureException now checks isRequestOptedIn before forwarding errors
to Sentry, closing a gap where server errors leaked to an external
service even when no user had consented. The PII scrubbing regex is
also fixed: he[ic]f? failed to match .heic due to word-boundary
behavior and is replaced with hei[cf]? which correctly covers .heic,
.heif, and .hei.

Adds 88 new analytics tests across unit, integration, and e2e layers
proving PostHog/Sentry are never invoked when analytics is disabled or
users have not consented, plus full 7-day reminder lifecycle coverage.
This commit is contained in:
SnapOtter
2026-04-29 23:47:19 +08:00
parent 53343a0836
commit fc8b549d78
17 changed files with 1446 additions and 5 deletions
+37
View File
@@ -0,0 +1,37 @@
import { test as base, expect, type Page } from "@playwright/test";
export async function login(page: Page, username = "admin", password = "admin") {
await page.goto("/login");
await page.getByLabel("Username").fill(username);
await page.getByLabel("Password").fill(password);
await page.getByRole("button", { name: /login/i }).click();
}
export async function getSessionViaApi(page: Page) {
const token = await page.evaluate(() => localStorage.getItem("snapotter-token") ?? "");
const res = await page.request.get("/api/auth/session", {
headers: { Authorization: `Bearer ${token}` },
});
return res.json();
}
export async function setConsentViaApi(
page: Page,
data: { enabled?: boolean; remindLater?: boolean },
) {
const token = await page.evaluate(() => localStorage.getItem("snapotter-token") ?? "");
const apiBase = process.env.API_URL || "http://localhost:13491";
await page.request.put(`${apiBase}/api/v1/user/analytics`, {
headers: { Authorization: `Bearer ${token}` },
data,
});
}
export const test = base.extend<{ loggedInPage: Page }>({
loggedInPage: async ({ page }, use) => {
await page.goto("/");
await use(page);
},
});
export { expect };