Ctrl K
ComunidadGuías…

e2e/b6-b9.spec.ts

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

Archivo original ↗Preguntar a KiBot
import { navigateWorkspace, openProjectSection, openProject } from "./workspace-controls";
import { expect, test, type Page } from "@playwright/test";

const demoPassword = "demo-password-please-change";

async function signIn(page: Page): Promise<void> {
  await page.goto("/");
  await page.getByLabel("Workspace password").fill(demoPassword);
  await page.getByRole("button", { name: "Sign in" }).click();
  await expect(page.getByRole("heading", { name: "Projects", exact: true })).toBeVisible();
}

async function openInventory(page: Page): Promise<void> {
  await navigateWorkspace(page, "Inventory");
  await expect(page.getByRole("heading", { name: "Inventory" })).toBeVisible();
}

function inventoryRecord(id: string, name: string) {
  return {
    id,
    name,
    kind: "tool",
    quantity: 1,
    availableQuantity: 1,
    unit: "each",
    tags: [],
    links: [],
    evidence: { state: "physically_counted" },
    createdAt: "2026-08-30T10:00:00.000Z",
    updatedAt: "2026-08-30T10:00:00.000Z",
    version: 1,
  };
}

test("launches inventory before sequential typing from the topbar", async ({ page }) => {
  await signIn(page);
  const topbarSearch = page.getByRole("button", { name: "Open workspace commands" });
  await expect(topbarSearch).toBeVisible();
  await topbarSearch.focus();
  await expect(topbarSearch).toBeFocused();
  await topbarSearch.click();
  await page.getByRole("dialog", { name: "Workspace commands", exact: true }).getByRole("option", { name: /^Inventory Open inventory/u }).click();
  const inventorySearch = page.getByRole("textbox", { name: "Search inventory" });
  await expect(inventorySearch).toBeFocused();

  await inventorySearch.pressSequentially("ESP32");
  await expect(inventorySearch).toHaveValue("ESP32");
  await expect(inventorySearch).toBeFocused();
  await expect(page).toHaveURL(/q=ESP32/u);
  await expect(page.getByRole("button", { name: "Open ESP32 development board" })).toBeVisible();
});

test("Cmd/Ctrl+K launches inventory and focuses its single search field", async ({ page }) => {
  await signIn(page);
  const topbarSearch = page.getByRole("button", { name: "Open workspace commands" });
  await expect(topbarSearch).toBeVisible();
  await topbarSearch.evaluate((element) => {
    element.addEventListener("focus", () => { document.body.dataset.topbarSearchFocused = "true"; }, { once: true });
  });
  await page.keyboard.press("Control+K");
  await expect(page.locator("body")).toHaveAttribute("data-topbar-search-focused", "true");
  const inventorySearch = page.getByRole("textbox", { name: "Search inventory" });
  await expect(inventorySearch).toBeFocused();
});

test("keeps one local inventory search and lets the shared shortcut focus it", async ({ page }) => {
  await signIn(page);
  await openInventory(page);

  const search = page.getByRole("textbox", { name: "Search inventory" });
  await expect(search).toBeVisible();
  await expect(page.getByRole("textbox", { name: "Search inventory", exact: true })).toHaveCount(1);
  await expect(page.getByRole("button", { name: "Open workspace commands", exact: true })).toBeVisible();
  await page.keyboard.press("Control+K");
  await expect(search).toBeFocused();

  await search.fill("ESP32");
  await expect(page).toHaveURL(/q=ESP32/u);
});

test("keeps the newest result and URL after rapid inventory queries", async ({ page }) => {
  await signIn(page);
  const slow = inventoryRecord("slow-result", "Slow result");
  const fast = inventoryRecord("fast-result", "Fast result");
  await page.route("**/api/v1/inventory**", async (route) => {
    const requestUrl = new URL(route.request().url());
    if (route.request().method() !== "GET" || requestUrl.pathname !== "/api/v1/inventory") return route.continue();
    const query = requestUrl.searchParams.get("q") ?? "";
    if (query === "slow") await new Promise((resolve) => setTimeout(resolve, 450));
    const data = query === "slow" ? [slow] : query === "fast" ? [fast] : [];
    await route.fulfill({
      status: 200,
      contentType: "application/json",
      body: JSON.stringify({ data, limit: 25, total: data.length }),
    });
  });

  await openInventory(page);
  const search = page.getByRole("textbox", { name: "Search inventory" });
  await search.fill("slow");
  await page.waitForTimeout(320);
  await search.fill("fast");

  await expect(page.getByRole("button", { name: "Open Fast result" })).toBeVisible();
  await expect(page.getByRole("button", { name: "Open Slow result" })).toHaveCount(0);
  await expect(page).toHaveURL(/q=fast/u);
});

test("only reports a cleared selection when a selection existed before filtering", async ({ page }) => {
  await signIn(page);
  const rows = [inventoryRecord("tool-00", "Tool 00"), inventoryRecord("tool-01", "Tool 01")];
  await page.route("**/api/v1/inventory**", async (route) => {
    const requestUrl = new URL(route.request().url());
    if (route.request().method() !== "GET" || requestUrl.pathname !== "/api/v1/inventory") return route.continue();
    const query = requestUrl.searchParams.get("q")?.toLocaleLowerCase() ?? "";
    const data = query ? rows.filter((row) => row.name.toLocaleLowerCase().includes(query)) : rows;
    await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ data, limit: 25, total: data.length }) });
  });

  await openInventory(page);
  const notice = page.locator(".inventory-selection-notice");
  const search = page.getByRole("textbox", { name: "Search inventory" });
  await search.fill("Tool 00");
  await expect(page.getByRole("button", { name: "Open Tool 00" })).toBeVisible();
  await expect(notice).toHaveCount(0);

  await page.getByLabel("Select Tool 00").check();
  await search.fill("Tool 01");
  await expect(page.getByRole("button", { name: "Open Tool 01" })).toBeVisible();
  await expect(notice).toContainText("Selection cleared");
});

test("keeps inventory and shopping actions usable at 390px without horizontal overflow", async ({ page }) => {
  await page.setViewportSize({ width: 390, height: 844 });
  await signIn(page);
  const launcher = page.getByRole("button", { name: "Open workspace commands" });
  await expect(launcher).toBeVisible();
  const restingLauncherBox = await launcher.boundingBox();
  expect(restingLauncherBox?.width ?? 0).toBeGreaterThanOrEqual(44);
  expect(restingLauncherBox?.height ?? 0).toBeGreaterThanOrEqual(44);
  await launcher.focus();
  const focusedLauncherBox = await launcher.boundingBox();
  expect(focusedLauncherBox?.width ?? 0).toBeGreaterThanOrEqual(44);
  expect(focusedLauncherBox?.height ?? 0).toBeGreaterThanOrEqual(44);
  await openInventory(page);

  await expect(page.getByRole("textbox", { name: "Search inventory", exact: true })).toHaveCount(1);
  await expect(page.getByRole("button", { name: "Open workspace commands", exact: true })).toBeVisible();
  await page.getByRole("button", { name: "Filters", exact: true }).click();
  const inventoryControls = page.locator(".inventory-toolbar .field-search, .inventory-toolbar .category-control:visible");
  for (const control of await inventoryControls.all()) {
    const box = await control.boundingBox();
    expect(box?.width ?? 0).toBeGreaterThanOrEqual(44);
    expect(box?.height ?? 0).toBeGreaterThanOrEqual(44);
  }
  await page.getByLabel("Select all loaded inventory items").check();
  const selectionButton = page.getByRole("button", { name: "Bulk edit", exact: true });
  await expect(selectionButton).toBeVisible();
  const selectionBox = await selectionButton.boundingBox();
  expect(selectionBox?.width ?? 0).toBeGreaterThanOrEqual(44);
  expect(selectionBox?.height ?? 0).toBeGreaterThanOrEqual(44);
  expect(await page.evaluate(() => document.documentElement.scrollWidth <= document.documentElement.clientWidth)).toBe(true);

  await openProject(page, "Synthetic H2D desk lamp");
  await openProjectSection(page, "To source");
  await page.getByText("Inventory-linked supplier records", { exact: true }).click(); await expect(page.locator(".shopping-section")).toBeVisible();
  const shoppingControls = page.locator(".shopping-actions .button, .shopping-section .offer-row, .shopping-section .expert-detail > [data-disclosure='trigger']");
  for (const control of await shoppingControls.all()) {
    const box = await control.boundingBox();
    if (box) {
      expect(box.width).toBeGreaterThanOrEqual(44);
      expect(box.height).toBeGreaterThanOrEqual(44);
    }
  }
  expect(await page.evaluate(() => document.documentElement.scrollWidth <= document.documentElement.clientWidth)).toBe(true);
});