diff --git a/backend/tests/e2e/tier4.spec.ts b/backend/tests/e2e/tier4.spec.ts new file mode 100644 index 0000000..2c86e33 --- /dev/null +++ b/backend/tests/e2e/tier4.spec.ts @@ -0,0 +1,184 @@ +import { describe, expect, it } from "vitest"; +import { apiFetch, clearCookieJar } from "./setup.js"; +import type { User, Website, Domain, DnsRecord } from "../../../src/api/contracts/models.js"; + +describe("Tier 4 E2E - Workload Application Scenarios", () => { + it("should successfully execute a complete real-world lifecycle workload scenario", async () => { + const sessionId = "tier4_lifecycle_scenario"; + clearCookieJar(sessionId); + + // 1. LOGIN + const loginRes = await apiFetch<{ user: User }>( + "/api/auth/login", + { + method: "POST", + sessionId, + body: JSON.stringify({ + email: "owner@example.com", + password: "correct-password", + }), + } + ); + expect(loginRes.$status).toBe(200); + expect(loginRes.data?.user.role).toBe("owner"); + + // 2. CONFIRM USER CONTEXT + const meRes = await apiFetch("/api/auth/me", { + method: "GET", + sessionId, + }); + expect(meRes.$status).toBe(200); + expect(meRes.data?.email).toBe("owner@example.com"); + + // 3. CREATE DOMAIN + const domainName = "workload-lifecycle.com"; + const createDomRes = await apiFetch("/api/domains", { + method: "POST", + sessionId, + body: JSON.stringify({ + name: domainName, + type: "primary", + documentRoot: `/home/coaxys/${domainName}`, + }), + }); + expect(createDomRes.$status).toBe(201); + const domainId = createDomRes.data!.id; + expect(domainId).toBeDefined(); + + // 4. CONFIRM DOMAIN IN LIST + const listDomRes = await apiFetch("/api/domains", { + method: "GET", + sessionId, + }); + expect(listDomRes.$status).toBe(200); + const foundDom = listDomRes.data!.find((d) => d.id === domainId); + expect(foundDom).toBeDefined(); + expect(foundDom?.name).toBe(domainName); + + // 5. CREATE WEBSITE MAPPED TO DOMAIN + const siteName = "Workload Production App"; + const createSiteRes = await apiFetch("/api/websites", { + method: "POST", + sessionId, + body: JSON.stringify({ + name: siteName, + domain: domainName, + runtime: "Node.js", + environment: "production", + }), + }); + expect(createSiteRes.$status).toBe(201); + const siteId = createSiteRes.data!.id; + expect(siteId).toBeDefined(); + + // 6. CONFIRM WEBSITE IN LIST + const listSiteRes = await apiFetch("/api/websites", { + method: "GET", + sessionId, + }); + expect(listSiteRes.$status).toBe(200); + const foundSite = listSiteRes.data!.find((w) => w.id === siteId); + expect(foundSite).toBeDefined(); + expect(foundSite?.name).toBe(siteName); + expect(foundSite?.domain).toBe(domainName); + + // 7. GET WEBSITE DETAILS + const detailSiteRes = await apiFetch(`/api/websites/${siteId}`, { + method: "GET", + sessionId, + }); + expect(detailSiteRes.$status).toBe(200); + expect(detailSiteRes.data?.name).toBe(siteName); + + // 8. UPDATE WEBSITE CONFIGS + const updateSiteRes = await apiFetch(`/api/websites/${siteId}`, { + method: "PUT", + sessionId, + body: JSON.stringify({ + runtime: "Docker", + environment: "staging", + }), + }); + expect(updateSiteRes.$status).toBe(200); + expect(updateSiteRes.data?.runtime).toBe("Docker"); + expect(updateSiteRes.data?.environment).toBe("staging"); + + // 9. ADD DNS RECORD TO DOMAIN + const createDnsRes = await apiFetch(`/api/domains/${domainId}/dns`, { + method: "POST", + sessionId, + body: JSON.stringify({ + name: "api", + ttl: 14400, + type: "A", + record: "192.0.2.99", + }), + }); + expect(createDnsRes.$status).toBe(201); + const recordId = createDnsRes.data!.id; + expect(recordId).toBeDefined(); + + // 10. LIST AND VERIFY DNS RECORD + const listDnsRes = await apiFetch(`/api/domains/${domainId}/dns`, { + method: "GET", + sessionId, + }); + expect(listDnsRes.$status).toBe(200); + const foundRecord = listDnsRes.data!.find((r) => r.id === recordId); + expect(foundRecord).toBeDefined(); + expect(foundRecord?.record).toBe("192.0.2.99"); + + // 11. DELETE DNS RECORD + const deleteDnsRes = await apiFetch<{ deleted: string }>( + `/api/domains/${domainId}/dns/${recordId}`, + { + method: "DELETE", + sessionId, + } + ); + expect(deleteDnsRes.$status).toBe(200); + + // 12. DELETE WEBSITE + const deleteSiteRes = await apiFetch<{ deleted: string }>(`/api/websites/${siteId}`, { + method: "DELETE", + sessionId, + }); + expect(deleteSiteRes.$status).toBe(200); + + // 13. CONFIRM WEBSITE DELETED + const confirmSiteDeleted = await apiFetch(`/api/websites/${siteId}`, { + method: "GET", + sessionId, + }); + expect(confirmSiteDeleted.$status).toBe(404); + + // 14. DELETE DOMAIN + const deleteDomRes = await apiFetch<{ deleted: string }>(`/api/domains/${domainId}`, { + method: "DELETE", + sessionId, + }); + expect(deleteDomRes.$status).toBe(200); + + // 15. CONFIRM DOMAIN DELETED + const confirmDomDeleted = await apiFetch(`/api/domains/${domainId}`, { + method: "GET", + sessionId, + }); + expect(confirmDomDeleted.$status).toBe(404); + + // 16. LOGOUT + const logoutRes = await apiFetch<{ ok: boolean }>("/api/auth/logout", { + method: "POST", + sessionId, + }); + expect(logoutRes.$status).toBe(200); + expect(logoutRes.data?.ok).toBe(true); + + // 17. CONFIRM LOGGED OUT + const confirmMeLoggedOut = await apiFetch("/api/auth/me", { + method: "GET", + sessionId, + }); + expect(confirmMeLoggedOut.$status).toBe(401); + }); +});