Add Playwright fixtures with 5 test user types for e2e tests
Creates test infrastructure to enable previously skipped e2e tests: - Onboarding user (no period data) for setup flow tests - Established user (period 14 days ago) for normal usage tests - Calendar user (with calendarToken) for ICS feed tests - Garmin user (valid tokens) for connected state tests - Garmin expired user (expired tokens) for expiry warning tests Also fixes ICS feed route to strip .ics suffix from Next.js dynamic route param, adds calendarToken to /api/user response, and sets viewRule on users collection for unauthenticated ICS access. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,11 +14,13 @@ interface RouteParams {
|
||||
}
|
||||
|
||||
export async function GET(_request: NextRequest, { params }: RouteParams) {
|
||||
const { userId, token } = await params;
|
||||
const { userId, token: rawToken } = await params;
|
||||
// Strip .ics suffix if present (Next.js may include it in the param)
|
||||
const token = rawToken.endsWith(".ics") ? rawToken.slice(0, -4) : rawToken;
|
||||
const pb = createPocketBaseClient();
|
||||
|
||||
try {
|
||||
// Fetch user from database
|
||||
const pb = createPocketBaseClient();
|
||||
const user = await pb.collection("users").getOne(userId);
|
||||
|
||||
// Check if user has a calendar token set
|
||||
|
||||
@@ -26,6 +26,7 @@ const mockPbGetOne = vi.fn().mockImplementation(() => {
|
||||
notificationTime: currentMockUser.notificationTime,
|
||||
timezone: currentMockUser.timezone,
|
||||
activeOverrides: currentMockUser.activeOverrides,
|
||||
calendarToken: currentMockUser.calendarToken,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -96,17 +97,27 @@ describe("GET /api/user", () => {
|
||||
expect(body.timezone).toBe("America/New_York");
|
||||
});
|
||||
|
||||
it("does not expose sensitive token fields", async () => {
|
||||
it("does not expose sensitive Garmin token fields", async () => {
|
||||
currentMockUser = mockUser;
|
||||
|
||||
const mockRequest = {} as NextRequest;
|
||||
const response = await GET(mockRequest);
|
||||
const body = await response.json();
|
||||
|
||||
// Should NOT include encrypted tokens
|
||||
// Should NOT include encrypted Garmin tokens
|
||||
expect(body.garminOauth1Token).toBeUndefined();
|
||||
expect(body.garminOauth2Token).toBeUndefined();
|
||||
expect(body.calendarToken).toBeUndefined();
|
||||
});
|
||||
|
||||
it("includes calendarToken for calendar subscription URL", async () => {
|
||||
currentMockUser = mockUser;
|
||||
|
||||
const mockRequest = {} as NextRequest;
|
||||
const response = await GET(mockRequest);
|
||||
const body = await response.json();
|
||||
|
||||
// calendarToken is needed by the calendar page to display the subscription URL
|
||||
expect(body.calendarToken).toBe("cal-secret-token");
|
||||
});
|
||||
|
||||
it("includes activeOverrides array", async () => {
|
||||
@@ -392,9 +403,8 @@ describe("PATCH /api/user", () => {
|
||||
expect(body.cycleLength).toBe(32);
|
||||
expect(body.notificationTime).toBe("07:30");
|
||||
expect(body.timezone).toBe("America/New_York");
|
||||
// Should not expose sensitive fields
|
||||
// Should not expose sensitive Garmin token fields
|
||||
expect(body.garminOauth1Token).toBeUndefined();
|
||||
expect(body.garminOauth2Token).toBeUndefined();
|
||||
expect(body.calendarToken).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -36,6 +36,7 @@ export const GET = withAuth(async (_request, user, pb) => {
|
||||
notificationTime: freshUser.notificationTime,
|
||||
timezone: freshUser.timezone,
|
||||
activeOverrides: freshUser.activeOverrides ?? [],
|
||||
calendarToken: (freshUser.calendarToken as string) || null,
|
||||
},
|
||||
{
|
||||
headers: { "Cache-Control": "no-store, no-cache, must-revalidate" },
|
||||
|
||||
Reference in New Issue
Block a user