Ctrl K
ComunidadGuías…

e2e/project-creator-deletion.spec.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { test, expect } from "@playwright/test";
import { TestApiClient } from "./fixtures";

test("members can delete their own shared project while keeping its issues", async ({ page }, testInfo) => {
  const owner = new TestApiClient();
  const member = new TestApiClient();
  const suffix = `${Date.now()}-${testInfo.workerIndex}`;
  const memberEmail = `project-member-${suffix}@multica.ai`;
  const apiBase = process.env.NEXT_PUBLIC_API_URL || `http://localhost:${process.env.PORT || "8080"}`;

  await owner.login(`project-owner-${suffix}@multica.ai`, "Project owner");
  const workspace = await owner.ensureWorkspace("Project permissions", `project-permissions-${suffix}`);
  try {
    await member.login(memberEmail, "Project member");
    await owner.addMemberByEmail(memberEmail);
    member.setWorkspaceId(workspace.id);
    member.setWorkspaceSlug(workspace.slug);
    await member.markUserOnboarded();

    const ownProject = await member.createProject("My temporary project");
    const otherProject = await owner.createProject("A teammate's project");
    const issue = await owner.createIssue("Keep this team's issue", { project_id: ownProject.id });
    const token = member.getToken();
    expect(token).toBeTruthy();
    await page.addInitScript((value) => {
      localStorage.setItem("multica_token", value!);
      localStorage.setItem("multica:chat:isOpen", "false");
    }, token);

    await page.goto(`/${workspace.slug}/projects/${otherProject.id}`, { waitUntil: "domcontentloaded" });
    await page.getByRole("button", { name: otherProject.title, exact: true }).click({ timeout: 30000 });
    await expect(page.getByRole("menuitem", { name: "Copy link", exact: true })).toBeVisible();
    await expect(page.getByRole("menuitem", { name: "Delete project", exact: true })).toHaveCount(0);

    const headers = { Authorization: `Bearer ${token}`, "X-Workspace-ID": workspace.id };
    const denied = await page.request.delete(`${apiBase}/api/projects/${otherProject.id}`, { headers });
    expect(denied.status()).toBe(403);

    await page.goto(`/${workspace.slug}/projects/${ownProject.id}`, { waitUntil: "domcontentloaded" });
    await page.getByRole("button", { name: ownProject.title, exact: true }).click();
    await expect(page.getByRole("menuitem", { name: "Delete project", exact: true })).toBeVisible();
    const screenshot = testInfo.outputPath("creator-delete-menu.png");
    await page.screenshot({ path: screenshot });
    await testInfo.attach("Creator can delete their project", { path: screenshot, contentType: "image/png" });
    await page.getByRole("menuitem", { name: "Delete project", exact: true }).click();
    const confirmation = page.getByRole("alertdialog", { name: "Delete project", exact: true });
    await expect(confirmation).toBeVisible();
    const deleted = page.waitForResponse((response) =>
      response.url().endsWith(`/api/projects/${ownProject.id}`) && response.request().method() === "DELETE",
    );
    await confirmation.getByRole("button", { name: "Delete", exact: true }).click();
    expect((await deleted).status()).toBe(204);
    await expect(page).toHaveURL(new RegExp(`/${workspace.slug}/projects$`));

    const retainedIssue = await page.request.get(`${apiBase}/api/issues/${issue.id}`, { headers });
    expect(retainedIssue.status()).toBe(200);
    expect(await retainedIssue.json()).toMatchObject({ id: issue.id, project_id: null });
  } finally {
    await member.cleanup();
    await owner.cleanup();
    await owner.deleteWorkspace();
  }
});