import { describe, expect, it } from "vitest"; import { apiFetch, clearCookieJar } from "./setup.js"; import type { Website, Domain } from "../../../src/api/contracts/models.js"; describe("Tier 3 E2E - Cross-Feature Logic", () => { // --- 1. Session Expiration vs CRUD --- describe("Session Expiration vs CRUD", () => { it("should prevent CRUD operations once the session has expired or was cleared", async () => { const sessionId = "tier3_expiration"; clearCookieJar(sessionId); // Log in await apiFetch("/api/auth/login", { method: "POST", sessionId, body: JSON.stringify({ email: "owner@example.com", password: "correct-password" }), }); // Verify CRUD works while logged in const listBefore = await apiFetch("/api/websites", { method: "GET", sessionId }); expect(listBefore.$status).toBe(200); // Simulate session expiration by clearing the cookies clearCookieJar(sessionId); // Attempt GET should fail const listAfter = await apiFetch("/api/websites", { method: "GET", sessionId }); expect(listAfter.$status).toBe(401); expect(listAfter.error?.code).toBe("PERMISSION_DENIED"); // Attempt POST should fail const createAfter = await apiFetch("/api/websites", { method: "POST", sessionId, body: JSON.stringify({ name: "ExpiredSite", domain: "expired.com" }), }); expect(createAfter.$status).toBe(401); // Attempt DELETE should fail const deleteAfter = await apiFetch("/api/websites/site-1", { method: "DELETE", sessionId, }); expect(deleteAfter.$status).toBe(401); }); }); // --- 2. Role Scope Comparisons --- describe("Role Scope Comparisons", () => { it("should allow Owner full read/write privileges", async () => { const sessionId = "tier3_role_owner"; clearCookieJar(sessionId); await apiFetch("/api/auth/login", { method: "POST", sessionId, body: JSON.stringify({ email: "owner@example.com", password: "correct-password" }), }); // Owner creates website const createRes = await apiFetch("/api/websites", { method: "POST", sessionId, body: JSON.stringify({ name: "OwnerSite", domain: "owner.com" }), }); expect(createRes.$status).toBe(201); // Owner deletes website const deleteRes = await apiFetch(`/api/websites/${createRes.data!.id}`, { method: "DELETE", sessionId, }); expect(deleteRes.$status).toBe(200); }); it("should restrict Auditor role to read-only actions and block mutations", async () => { const sessionId = "tier3_role_auditor"; clearCookieJar(sessionId); await apiFetch("/api/auth/login", { method: "POST", sessionId, body: JSON.stringify({ email: "auditor@example.com", password: "correct-password" }), }); // Read actions should pass const listRes = await apiFetch("/api/websites", { method: "GET", sessionId }); expect(listRes.$status).toBe(200); // Write action (Create) should fail with 403 Forbidden/Permission Denied const createRes = await apiFetch("/api/websites", { method: "POST", sessionId, body: JSON.stringify({ name: "AuditorSite", domain: "auditor.com" }), }); expect(createRes.$status).toBe(403); expect(createRes.error?.code).toBe("PERMISSION_DENIED"); // Mutation action (Delete) should fail with 403 const deleteRes = await apiFetch("/api/websites/site-1", { method: "DELETE", sessionId, }); expect(deleteRes.$status).toBe(403); expect(deleteRes.error?.code).toBe("PERMISSION_DENIED"); }); it("should allow Developer to create/update websites but restrict them from deleting websites", async () => { const sessionId = "tier3_role_developer"; clearCookieJar(sessionId); await apiFetch("/api/auth/login", { method: "POST", sessionId, body: JSON.stringify({ email: "developer@example.com", password: "correct-password" }), }); // Developer can create website const createRes = await apiFetch("/api/websites", { method: "POST", sessionId, body: JSON.stringify({ name: "DevSite", domain: "dev.com" }), }); expect(createRes.$status).toBe(201); // Developer cannot delete website (returns 403) const deleteRes = await apiFetch(`/api/websites/${createRes.data!.id}`, { method: "DELETE", sessionId, }); expect(deleteRes.$status).toBe(403); expect(deleteRes.error?.code).toBe("PERMISSION_DENIED"); }); }); // --- 3. Domain Mapping to Website CRUD --- describe("Domain Mapping to Website CRUD", () => { it("should update dependent website state when its mapped domain is deleted", async () => { const sessionId = "tier3_mapping"; clearCookieJar(sessionId); await apiFetch("/api/auth/login", { method: "POST", sessionId, body: JSON.stringify({ email: "owner@example.com", password: "correct-password" }), }); // 1. Create a domain const domainRes = await apiFetch("/api/domains", { method: "POST", sessionId, body: JSON.stringify({ name: "mapped-domain.com", type: "primary" }), }); expect(domainRes.$status).toBe(201); // 2. Create a website mapped to that domain const siteRes = await apiFetch("/api/websites", { method: "POST", sessionId, body: JSON.stringify({ name: "MappedSite", domain: "mapped-domain.com" }), }); expect(siteRes.$status).toBe(201); expect(siteRes.data?.status).toBe("healthy"); // 3. Delete the domain const deleteDomRes = await apiFetch(`/api/domains/${domainRes.data!.id}`, { method: "DELETE", sessionId, }); expect(deleteDomRes.$status).toBe(200); // 4. Retrieve website details and check if status degraded/warning due to severed domain const siteDetailRes = await apiFetch(`/api/websites/${siteRes.data!.id}`, { method: "GET", sessionId, }); expect(siteDetailRes.$status).toBe(200); expect(siteDetailRes.data?.status).toBe("warning"); }); }); });