mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
111 lines
5.2 KiB
JavaScript
111 lines
5.2 KiB
JavaScript
const { test, expect } = require("@playwright/test");
|
|
const { resolveTimeout } = require("./timeouts");
|
|
|
|
const { decodeDotenvQuotedValue, normalizeBaseUrl, runAdminFlow, runBiberFlow, runGuestFlow , expectHstsWhenTls, gotoOnion, webmailSsoLogin, waitForEmailInMailbox, safeIsEnabled } = require("./personas");
|
|
test.use({ ignoreHTTPSErrors: true });
|
|
|
|
const appBaseUrl = normalizeBaseUrl(process.env.APP_BASE_URL || "");
|
|
const canonicalDomain = decodeDotenvQuotedValue(process.env.CANONICAL_DOMAIN || "");
|
|
const webmailBaseUrl = normalizeBaseUrl(decodeDotenvQuotedValue(process.env.WEBMAIL_BASE_URL || ""));
|
|
const adminEmail = decodeDotenvQuotedValue(process.env.ADMIN_EMAIL || "");
|
|
const adminUsername = decodeDotenvQuotedValue(process.env.ADMIN_USERNAME || "");
|
|
const adminPassword = decodeDotenvQuotedValue(process.env.ADMIN_PASSWORD || "");
|
|
const ssoEnabled = (process.env.SSO_SERVICE_ENABLED || "").toLowerCase() === "true";
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
expect(appBaseUrl, "APP_BASE_URL must be set").toBeTruthy();
|
|
expect(canonicalDomain, "CANONICAL_DOMAIN must be set").toBeTruthy();
|
|
await page.context().clearCookies();
|
|
});
|
|
|
|
test("GitLab front page is served under canonical domain with TLS", async ({ page }) => {
|
|
const response = await gotoOnion(page, `${appBaseUrl}/`);
|
|
expect(response, "Expected GitLab response").toBeTruthy();
|
|
expect(response.status(), "Expected GitLab front page status < 400").toBeLessThan(400);
|
|
expect(
|
|
response.url().includes(canonicalDomain),
|
|
`Expected canonical domain "${canonicalDomain}" to back the GitLab URL`
|
|
).toBe(true);
|
|
const headers = response.headers();
|
|
expectHstsWhenTls(headers, appBaseUrl, "GitLab");
|
|
});
|
|
|
|
test("GitLab returns HTML content under canonical domain", async ({ request }) => {
|
|
const response = await request.get(`${appBaseUrl}/`, { timeout: resolveTimeout(30_000) });
|
|
expect(response.status(), "Expected GitLab front page status < 400").toBeLessThan(400);
|
|
const contentType = response.headers()["content-type"] || "";
|
|
expect(
|
|
contentType.includes("text/html"),
|
|
`Expected HTML content-type, got "${contentType}"`
|
|
).toBe(true);
|
|
});
|
|
|
|
require("./test-mcp-guest");
|
|
|
|
// Outbound mail. `templates/config/smtp_settings.rb.j2` derives ActionMailer's
|
|
// `tls:` from the provider's own declaration, and tls/starttls are mutually
|
|
// exclusive there: implicit TLS on 465, or STARTTLS on the relay port, never
|
|
// both. Getting it wrong does not fail the send — GitLab queues the mail and
|
|
// reports success — so the only proof is reading the message back out of the
|
|
// recipient's mailbox. GitLab only mails an address it knows, and the OmniAuth
|
|
// sign-in is what creates the account, so the persona logs in once before asking.
|
|
test("gitlab: a password-reset request is delivered to the recipient's mailbox", async ({ page }) => {
|
|
test.skip(!safeIsEnabled("email"), "no mail provider in this deploy");
|
|
test.skip(!ssoEnabled, "the administrator account is created by the first SSO login");
|
|
test.skip(!webmailBaseUrl, "the active mail provider serves no webmail vhost to read from");
|
|
expect(adminEmail, "ADMIN_EMAIL must be set").toBeTruthy();
|
|
expect(adminPassword, "ADMIN_PASSWORD must be set").toBeTruthy();
|
|
|
|
await runAdminFlow(page);
|
|
|
|
await gotoOnion(page, `${appBaseUrl}/users/password/new`);
|
|
await page.locator("input[type='email'], #user_email").first().fill(adminEmail);
|
|
await page.locator("input[type='submit'], button[type='submit']").first().click();
|
|
await expect(
|
|
page.locator("body"),
|
|
"GitLab must confirm it accepted the reset request"
|
|
).toContainText(/recovery link|password recovery|reset|instructions|receive/i, {
|
|
timeout: resolveTimeout(30_000),
|
|
});
|
|
|
|
const mailbox = await page.context().newPage();
|
|
try {
|
|
await webmailSsoLogin(mailbox, adminUsername, adminPassword, webmailBaseUrl);
|
|
const row = await waitForEmailInMailbox(mailbox, webmailBaseUrl, "password", resolveTimeout(120_000));
|
|
await expect(row, "the reset mail must reach the mailbox").toBeVisible();
|
|
} finally {
|
|
await mailbox.close().catch(() => {});
|
|
}
|
|
});
|
|
|
|
// Persona scenarios.
|
|
// Bodies live in the shared helper roles/test-e2e-playwright/files/personas
|
|
// so every role's persona flow stays consistent.
|
|
|
|
test("guest: public-landing → auth chain → never authenticated", async ({ page }) => {
|
|
await runGuestFlow(page);
|
|
});
|
|
|
|
test("biber: app → universal logout", async ({ page }) => {
|
|
await runBiberFlow(page);
|
|
});
|
|
|
|
test("administrator: app → universal logout", async ({ page }) => {
|
|
await runAdminFlow(page, {
|
|
adminInteraction: async (interactivePage) => {
|
|
// web-app-gitlab admin-only interaction: open a management surface.
|
|
const link = interactivePage
|
|
.getByRole("link", { name: /^(projects|groups|admin|settings)$/i })
|
|
.first();
|
|
if (await link.isVisible().catch(() => false)) {
|
|
await link.click({ timeout: resolveTimeout(30_000) }).catch(() => {});
|
|
await interactivePage.waitForLoadState("domcontentloaded", { timeout: resolveTimeout(30_000) }).catch(() => {});
|
|
await expect(interactivePage.locator("body")).toContainText(
|
|
/project|group|merge request|issue|admin area|gitlab/i,
|
|
{ timeout: resolveTimeout(30_000) },
|
|
);
|
|
}
|
|
},
|
|
});
|
|
});
|