feat(e2e): add freight e2e docker-compose stack with isolated services

This commit is contained in:
Nathnael
2026-07-21 11:00:02 +00:00
parent 2a35ee97fa
commit b8b8c4adf7
19 changed files with 1701 additions and 54 deletions

View File

@@ -0,0 +1,79 @@
/**
* API contract smoke — no browser, pure cy.request against freight-api.
* Verifies the containerized stack booted: migrations ran, seeders ran,
* auth issues tokens.
*/
const api = () => Cypress.env("apiUrl") as string;
describe("freight-api: health + auth contract", () => {
it("GET /api/health responds", () => {
cy.request(`${api()}/api/health`).its("status").should("eq", 200);
});
it("rejects bad credentials", () => {
cy.request({
method: "POST",
url: `${api()}/api/auth/login`,
body: { email: "nobody@edr.local", password: "wrong-password" },
failOnStatusCode: false,
})
.its("status")
.should("be.oneOf", [400, 401, 404]);
});
it("logs in every seeded staff user", () => {
cy.fixture("users.json").then((users) => {
Object.values<{ email: string }>(users.staff).forEach(({ email }) => {
cy.apiLogin(email);
});
});
});
it("staff token can read /api/me", () => {
cy.apiLogin("ceo@edr.local").then(({ token }) => {
cy.request({
url: `${api()}/api/me`,
headers: { Authorization: `Bearer ${token}` },
}).then((response) => {
expect(response.status).to.eq(200);
});
});
});
it("refresh-token rotates the session", () => {
cy.apiLogin("chief@edr.local").then(({ refreshToken }) => {
cy.request("POST", `${api()}/api/auth/refresh-token`, { refreshToken })
.its("body.token")
.should("be.a", "string");
});
});
it("demo portal users are seeded", () => {
// DemoUsersSeeder hardcodes this password (staff users use DEFAULT_PASSWORD)
cy.apiLogin("user@gmail.com", Cypress.env("demoPassword"));
cy.apiLogin("user2@gmail.com", Cypress.env("demoPassword"));
});
});
describe("freight-api: seeded database", () => {
it("migrations table is populated", () => {
cy.task<{ rowCount: number }>("db:query", {
sql: "select count(*)::int as count from migrations",
}).then(({ rows }: any) => {
expect(rows[0].count).to.be.greaterThan(100);
});
});
it("staff users exist with credentials", () => {
cy.task("db:query", {
sql: `select u.email from iam.users u
join iam.user_credentials c on c.user_id = u.id
where u.email like '%@edr.local' order by u.email`,
}).then(({ rows }: any) => {
const emails = rows.map((row: { email: string }) => row.email);
expect(emails).to.include.members(["ceo@edr.local", "linestaff@edr.local"]);
});
});
});
export {};