Files
arsam 8f135b8a89 Import tests: backend/tests/e2e/tier3
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
2026-09-18 23:09:40 +03:30

182 lines
6.3 KiB
TypeScript

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<Website[]>("/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<Website>("/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<Website[]>("/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<Website>("/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<Domain>("/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<Website>("/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<Website>(`/api/websites/${siteRes.data!.id}`, {
method: "GET",
sessionId,
});
expect(siteDetailRes.$status).toBe(200);
expect(siteDetailRes.data?.status).toBe("warning");
});
});
});