|
6 | 6 | } from "../../../toolbox/colors/palette-workspace-repository.js"; |
7 | 7 | import { startRepoServer } from "../../helpers/playwrightRepoServer.mjs"; |
8 | 8 | import { clearPlaywrightStorage, installPlaywrightStorageIsolation } from "../../helpers/playwrightStorageIsolation.mjs"; |
| 9 | +import { expectCompactToolFormControls } from "../../helpers/toolFormControlAssertions.mjs"; |
9 | 10 | import { workspaceV2CoverageReporter } from "../../helpers/workspaceV2CoverageReporter.mjs"; |
10 | 11 |
|
11 | 12 | const sourcePaletteRows = [ |
@@ -341,6 +342,13 @@ test("Palette repository owns active project swatches without mutating invalid p |
341 | 342 | expect(repeatPinAllResult.message).toContain("0 pinned, 2 already pinned"); |
342 | 343 | expect(repository.listSwatches().filter((swatch) => swatch.source === "reference")).toHaveLength(sourceCountAfterPinAll); |
343 | 344 | expect(repository.getSnapshot().selectedSwatch).toMatchObject({ name: "Reference Green", symbol: "G" }); |
| 345 | + const batchTagResult = repository.addTagToSwatches(["J", "R"], "batch"); |
| 346 | + expect(batchTagResult.ok).toBe(true); |
| 347 | + expect(batchTagResult.message).toBe("Added tag batch to 2 checked swatches."); |
| 348 | + expect(repository.findSwatch("J")).toMatchObject({ name: "Hero Updated", tags: ["primary", "batch"] }); |
| 349 | + expect(repository.findSwatch("R")).toMatchObject({ name: "Reference Red", tags: ["batch"] }); |
| 350 | + expect(repository.findSwatch("G")).toMatchObject({ name: "Reference Green", tags: [] }); |
| 351 | + expect(repository.getSnapshot().selectedSwatch).toMatchObject({ name: "Reference Green", symbol: "G" }); |
344 | 352 |
|
345 | 353 | const bulkPinRepository = createProjectWorkspacePaletteRepository({ sourcePaletteRows }); |
346 | 354 | const bulkSourceSwatches = bulkPinRepository.listSourceSwatches({ sourceId: "reference", sortKey: "hue" }); |
@@ -477,6 +485,20 @@ test("Palette Tool adds, updates, pins, validates, and shows project-owned detai |
477 | 485 | await expect(page.locator("[data-palette-tags]")).toBeDisabled(); |
478 | 486 | await expect(page.locator("[data-palette-tags]")).toHaveValue(""); |
479 | 487 | await expect(page.locator("[data-palette-editor-form] input[placeholder], [data-palette-user-swatch-form] input[placeholder]")).toHaveCount(0); |
| 488 | + await expectCompactToolFormControls(page, [ |
| 489 | + "[data-palette-selected-symbol]", |
| 490 | + "[data-palette-selected-hex]", |
| 491 | + "[data-palette-selected-name]", |
| 492 | + "[data-palette-tags]", |
| 493 | + "[data-palette-symbol]", |
| 494 | + "[data-palette-hex]", |
| 495 | + "[data-palette-name]", |
| 496 | + "[data-palette-source-select]", |
| 497 | + "[data-palette-source-search]", |
| 498 | + "[data-palette-harmony-match]", |
| 499 | + "[data-palette-harmony-scheme]" |
| 500 | + ]); |
| 501 | + await expect(page.locator("[data-palette-user-hex-preview]")).not.toHaveClass(/tool-form-control/); |
480 | 502 | await expect(page.locator("[data-palette-editor-tags-input-row] th")).toHaveAttribute("rowspan", "2"); |
481 | 503 | const tagInputRowBox = await page.locator("[data-palette-editor-tags-input-row]").boundingBox(); |
482 | 504 | const tagListRowBox = await page.locator("[data-palette-editor-tags-list-row]").boundingBox(); |
@@ -849,6 +871,75 @@ test("Palette Tool adds, updates, pins, validates, and shows project-owned detai |
849 | 871 | } |
850 | 872 | }); |
851 | 873 |
|
| 874 | +test("Palette Tool batch tags checked project palette swatches", async ({ page }) => { |
| 875 | + const failures = await openRepoPage(page, "/toolbox/colors/index.html"); |
| 876 | + |
| 877 | + try { |
| 878 | + await expect(page.getByText("Project Palette Tags")).toBeVisible(); |
| 879 | + await expect(page.getByText("Swatch Editor")).toHaveCount(0); |
| 880 | + await expect(page.locator("[data-palette-clear-checked]")).toBeDisabled(); |
| 881 | + |
| 882 | + await page.locator("[data-palette-source-select]").selectOption("palette-colors008"); |
| 883 | + await page.locator("[data-palette-source-pin-all]").click(); |
| 884 | + await expect(page.locator("[data-palette-count]")).toHaveText("8"); |
| 885 | + await expect(page.locator("[data-palette-swatch-check]")).toHaveCount(8); |
| 886 | + |
| 887 | + const blackItem = page.locator("[data-palette-swatch-item]", { |
| 888 | + has: page.locator("[data-palette-swatch-name='Black']") |
| 889 | + }); |
| 890 | + const brownItem = page.locator("[data-palette-swatch-item]", { |
| 891 | + has: page.locator("[data-palette-swatch-name='Brown']") |
| 892 | + }); |
| 893 | + const blueItem = page.locator("[data-palette-swatch-item]", { |
| 894 | + has: page.locator("[data-palette-swatch-name='Blue']") |
| 895 | + }); |
| 896 | + const blackTile = blackItem.locator("[data-palette-swatch-row]"); |
| 897 | + const brownTile = brownItem.locator("[data-palette-swatch-row]"); |
| 898 | + const blueTile = blueItem.locator("[data-palette-swatch-row]"); |
| 899 | + const blackCheck = blackItem.locator("[data-palette-swatch-check]"); |
| 900 | + const brownCheck = brownItem.locator("[data-palette-swatch-check]"); |
| 901 | + |
| 902 | + await blackTile.click(); |
| 903 | + await expect(page.locator("[data-palette-selected-summary]")).toHaveText("Black"); |
| 904 | + const checkBox = await blackCheck.boundingBox(); |
| 905 | + const tileBox = await blackTile.boundingBox(); |
| 906 | + expect((checkBox?.x || 0) - (tileBox?.x || 0)).toBeLessThan(10); |
| 907 | + expect((checkBox?.y || 0) - (tileBox?.y || 0)).toBeLessThan(10); |
| 908 | + |
| 909 | + await page.locator("[data-palette-tags]").fill("solo"); |
| 910 | + await expect(blackTile).toHaveAttribute("data-palette-swatch-tags", ""); |
| 911 | + await page.locator("[data-palette-tags]").press("Enter"); |
| 912 | + await expect(blackTile).toHaveAttribute("data-palette-swatch-tags", "solo"); |
| 913 | + await expect(brownTile).toHaveAttribute("data-palette-swatch-tags", ""); |
| 914 | + await expect(blueTile).toHaveAttribute("data-palette-swatch-tags", ""); |
| 915 | + |
| 916 | + await blackCheck.check(); |
| 917 | + await brownCheck.check(); |
| 918 | + await expect(page.locator("[data-palette-clear-checked]")).toBeEnabled(); |
| 919 | + await page.locator("[data-palette-tags]").fill("batch"); |
| 920 | + await page.locator("[data-palette-tags]").press("Enter"); |
| 921 | + await expect(blackTile).toHaveAttribute("data-palette-swatch-tags", "solo, batch"); |
| 922 | + await expect(brownTile).toHaveAttribute("data-palette-swatch-tags", "batch"); |
| 923 | + await expect(blueTile).toHaveAttribute("data-palette-swatch-tags", ""); |
| 924 | + |
| 925 | + await page.locator("[data-palette-clear-checked]").click(); |
| 926 | + await expect(blackCheck).not.toBeChecked(); |
| 927 | + await expect(brownCheck).not.toBeChecked(); |
| 928 | + await expect(page.locator("[data-palette-clear-checked]")).toBeDisabled(); |
| 929 | + |
| 930 | + await page.locator("[data-palette-tags]").fill("afterclear"); |
| 931 | + await page.locator("[data-palette-tags]").press("Enter"); |
| 932 | + await expect(blackTile).toHaveAttribute("data-palette-swatch-tags", "solo, batch, afterclear"); |
| 933 | + await expect(brownTile).toHaveAttribute("data-palette-swatch-tags", "batch"); |
| 934 | + await expect(blueTile).toHaveAttribute("data-palette-swatch-tags", ""); |
| 935 | + |
| 936 | + expectNoPageFailures(failures); |
| 937 | + } finally { |
| 938 | + await workspaceV2CoverageReporter.stop(page); |
| 939 | + await failures.server.close(); |
| 940 | + } |
| 941 | +}); |
| 942 | + |
852 | 943 | test("Palette Tool rejects invalid payloads before render and blocks editing without an active project", async ({ page }) => { |
853 | 944 | const invalidFailures = await openRepoPage(page, "/toolbox/colors/index.html?palette=invalid"); |
854 | 945 |
|
|
0 commit comments