Add Playwright E2E test setup (#3169)

* docs: design e2e test setup

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>

* docs: plan e2e test implementation

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>

* test: add playwright e2e scripts

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>

* test: configure playwright

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>

* test: add core e2e fixtures and specs

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>

* ci: run e2e tests on pull requests

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>

* [autofix.ci] apply automated fixes

* test: stabilize e2e suite

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>

* test: ignore playwright artifacts

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>

* Update .github/workflows/e2e.yml

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* test: address e2e review feedback

Co-authored-by: Amruth Pillai <im.amruth@gmail.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
Amruth Pillai
2026-06-20 07:39:06 +02:00
committed by GitHub
parent 56c90947e4
commit dfd2c77bc9
18 changed files with 1474 additions and 33 deletions
+13
View File
@@ -0,0 +1,13 @@
import { loginViaUi, logoutViaUi, registerViaUi } from "../fixtures/auth";
import { expect, test } from "../fixtures/test";
test("registers and logs in with email credentials", async ({ page, account }) => {
await registerViaUi(page, account);
await expect(page.getByRole("heading", { name: "Resumes" })).toBeVisible();
await logoutViaUi(page, account);
await expect(page.getByRole("heading", { name: "Sign in to your account" })).toBeVisible();
await loginViaUi(page, account);
await expect(page.getByRole("heading", { name: "Resumes" })).toBeVisible();
});
@@ -0,0 +1,30 @@
import { readFile } from "node:fs/promises";
import { createSampleResumeFromDashboard, openSidebarSection } from "../fixtures/resume";
import { expect, test } from "../fixtures/test";
test("exports and imports a resume JSON backup", async ({ authPage: page }, testInfo) => {
await createSampleResumeFromDashboard(page, testInfo);
await openSidebarSection(page, "Export");
const downloadPromise = page.waitForEvent("download");
await page.getByRole("button", { name: /^JSON/ }).click();
const download = await downloadPromise;
expect(download.suggestedFilename()).toMatch(/\.json$/);
const downloadPath = testInfo.outputPath(download.suggestedFilename());
await download.saveAs(downloadPath);
const exportedData = JSON.parse(await readFile(downloadPath, "utf-8")) as { basics: { name: string } };
await page.goto("/dashboard/resumes");
await page.getByText("Import an existing resume").click();
const dialog = page.getByRole("dialog", { name: "Import an existing resume" });
await dialog.getByRole("combobox").click();
await page.getByRole("option", { name: "Reactive Resume (JSON)" }).click();
await dialog.locator('input[type="file"]').setInputFiles(downloadPath);
await dialog.getByRole("button", { name: "Import", exact: true }).click();
await page.waitForURL(/\/builder\/.+/);
await openSidebarSection(page, "Basics");
await expect(page.getByLabel("Name")).toHaveValue(exportedData.basics.name);
});
+21
View File
@@ -0,0 +1,21 @@
import { createSampleResumeFromDashboard, openSidebarSection } from "../fixtures/resume";
import { expect, test } from "../fixtures/test";
test("publishes a resume and renders it for an anonymous visitor", async ({ browser, authPage: page }, testInfo) => {
await createSampleResumeFromDashboard(page, testInfo);
await openSidebarSection(page, "Sharing");
await page.getByRole("switch", { name: /Allow Public Access/ }).click();
const sharingUrl = page.locator("#sharing-url");
await expect(sharingUrl).toHaveValue(/\/e2e_/);
const publicUrl = await sharingUrl.inputValue();
expect(publicUrl).toMatch(/\/e2e_/);
const anonymous = await browser.newPage();
try {
await anonymous.goto(publicUrl);
await expect(anonymous.getByRole("button", { name: "Download PDF" })).toBeVisible();
} finally {
await anonymous.close();
}
});
+23
View File
@@ -0,0 +1,23 @@
import { createSampleResumeFromDashboard, openSidebarSection } from "../fixtures/resume";
import { expect, test } from "../fixtures/test";
test("creates a sample resume and persists a basics edit", async ({ authPage: page }, testInfo) => {
await createSampleResumeFromDashboard(page, testInfo);
const updatedName = `E2E Edited ${Date.now()}`;
await openSidebarSection(page, "Basics");
const savePromise = page.waitForResponse((response) => {
if (!response.url().includes("/api/rpc")) return false;
if (response.request().method() !== "POST") return false;
if (!response.ok()) return false;
const body = response.request().postData() ?? "";
return body.includes(updatedName);
});
await page.getByLabel("Name").fill(updatedName);
await savePromise;
await page.reload();
await openSidebarSection(page, "Basics");
await expect(page.getByLabel("Name")).toHaveValue(updatedName);
});