penpot/frontend/playwright/ui/specs/dashboard.spec.js
Andrey Antukh b660ea9d53 Route the app by query string with screen key
Move SPA routing out of the URL fragment into the normal query
string. The screen travels in a reserved `screen` key holding
the route name (`?screen=workspace&team-id=…`); every other
param keeps its name. `rt/nav` and `rt/resolve` keep their
signatures.

This deletes the fragment-mirroring URL surgery, simplifies
link-preview (the server sees everything) and nginx (single
path, no SPA fallback rules needed), and migrates OIDC
redirects, email links, e2e helpers and plugin test utils to
the new format.

Legacy `#/…` URLs translate client-side for one Penpot version
(`legacy-routes`, marked TODO(next-version)); non-SPA paths
are untouched.

AI-assisted-by: muse-spark-1.3-contributor
2026-09-15 17:10:54 +02:00

184 lines
5.9 KiB
JavaScript

import { test, expect } from "@playwright/test";
import DashboardPage from "../pages/DashboardPage";
test.beforeEach(async ({ page }) => {
await DashboardPage.init(page);
});
test("Dashboard page has title ", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await expect(dashboardPage.page).toHaveURL(/screen=dashboard/);
await expect(dashboardPage.mainHeading).toBeVisible();
});
test("User can create a new project", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupNewProject();
await dashboardPage.goToDashboard();
await dashboardPage.addProjectButton.click();
await expect(dashboardPage.projectName).toBeVisible();
});
test("User goes to draft page", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDraftsEmpty();
await dashboardPage.goToDashboard();
await dashboardPage.draftsLink.click();
await expect(dashboardPage.mainHeading).toHaveText("Drafts");
});
test("Lists files in the drafts page", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDrafts();
await dashboardPage.goToDrafts();
await expect(
dashboardPage.page.getByRole("button", { name: /New File 1/ }),
).toBeVisible();
await expect(
dashboardPage.page.getByRole("button", { name: /New File 2/ }),
).toBeVisible();
});
test("User hasn't an empty placeholder", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToDashboard();
await expect(
dashboardPage.page.getByTestId("empty-placeholder"),
).toBeHidden();
});
test("User has context menu options for edit file", async ({ page }) => {
await DashboardPage.mockRPC(
page,
"get-all-projects",
"dashboard/get-all-projects.json",
);
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDrafts();
await dashboardPage.goToDrafts();
const button = dashboardPage.page.getByRole("button", { name: /New File 2/ });
await button.click();
await button.click({ button: "right" });
await expect(dashboardPage.page.getByText("rename")).toBeVisible();
await expect(dashboardPage.page.getByText("duplicate")).toBeVisible();
await expect(
dashboardPage.page.getByText("add as shared library"),
).toBeVisible();
await expect(dashboardPage.page.getByText("delete")).toBeVisible();
});
test("Multiple elements in context", async ({ page }) => {
await DashboardPage.mockRPC(
page,
"get-all-projects",
"dashboard/get-all-projects.json",
);
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDrafts();
await dashboardPage.goToDrafts();
const button = dashboardPage.page.getByRole("button", { name: /New File 1/ });
await button.click();
const button2 = dashboardPage.page.getByRole("button", {
name: /New File 2/,
});
await button2.click({ modifiers: ["Shift"] });
await button.click({ button: "right" });
await expect(page.getByTestId("duplicate-multi")).toBeVisible();
await expect(page.getByTestId("file-move-multi")).toBeVisible();
await expect(page.getByTestId("file-binary-export-multi")).toBeVisible();
await expect(page.getByTestId("file-delete-multi")).toBeVisible();
});
test("User has create file button", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDrafts();
await dashboardPage.goToDrafts();
await expect(dashboardPage.page.getByText("+ New File")).toBeVisible();
});
test("User has add font button", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.goToFonts();
await expect(dashboardPage.page.getByText("add custom font")).toBeVisible();
});
test("Bug 9443, Admin can not demote owner", async ({ page }) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await DashboardPage.mockRPC(
page,
"get-team-members?team-id=*",
"dashboard/get-team-members-admin.json",
);
await dashboardPage.goToSecondTeamMembersSection();
await expect(page.getByRole("heading", { name: "Members" })).toBeVisible();
await expect(page.getByRole("combobox", { name: "Admin" })).toBeVisible();
await expect(page.getByText("Owner")).toBeVisible();
await expect(page.getByRole("combobox", { name: "Owner" })).toHaveCount(0);
});
test("Bug 9927, Don't show the banner to invite team members if the user has dismissed it", async ({
page,
}) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await DashboardPage.mockRPC(
page,
"get-projects?team-id=*",
"dashboard/get-projects-second-team.json",
);
await dashboardPage.goToSecondTeamDashboard();
await expect(page.getByText("Team Up")).toBeVisible();
await page.getByRole("button", { name: "Close" }).click();
await page.reload();
await expect(page.getByText("Second team")).toBeVisible();
await expect(page.getByText("Team Up")).not.toBeVisible();
});
test("Bug 10141, The team does not disappear from the team list after deletion", async ({
page,
}) => {
const dashboardPage = new DashboardPage(page);
await dashboardPage.setupDashboardFull();
await DashboardPage.mockRPC(
page,
"get-teams",
"logged-in-user/get-teams-complete-owner.json",
);
await dashboardPage.goToDashboard();
await dashboardPage.teamDropdown.click();
await expect(page.getByText("Second Team")).toBeVisible();
await page.getByText("Second Team").click();
await page.getByRole("button", { name: "team-management" }).click();
await page.getByTestId("delete-team").click();
await DashboardPage.mockRPC(
page,
"get-teams",
"logged-in-user/get-teams-default.json",
);
await page.getByRole("button", { name: "Delete team" }).click();
await dashboardPage.teamDropdown.click();
await expect(page.getByText("Second Team")).not.toBeVisible();
});