webui: Migrate from @open-wc/testing to Playwright
diff --git a/loop/webui/src/web-components/sketch-view-mode-select.test.ts b/loop/webui/src/web-components/sketch-view-mode-select.test.ts
index 13f5a27..6db790b 100644
--- a/loop/webui/src/web-components/sketch-view-mode-select.test.ts
+++ b/loop/webui/src/web-components/sketch-view-mode-select.test.ts
@@ -1,106 +1,119 @@
-import {
-  html,
-  fixture,
-  expect,
-  oneEvent,
-  elementUpdated,
-  fixtureCleanup,
-} from "@open-wc/testing";
-import "./sketch-view-mode-select";
-import type { SketchViewModeSelect } from "./sketch-view-mode-select";
+import { test, expect } from "@sand4rt/experimental-ct-web";
+import { SketchViewModeSelect } from "./sketch-view-mode-select";
 
-describe("SketchViewModeSelect", () => {
-  afterEach(() => {
-    fixtureCleanup();
+test("initializes with 'chat' as the default mode", async ({ mount }) => {
+  const component = await mount(SketchViewModeSelect, {});
+
+  // Check the activeMode property
+  const activeMode = await component.evaluate(
+    (el: SketchViewModeSelect) => el.activeMode,
+  );
+  expect(activeMode).toBe("chat");
+
+  // Check that the chat button has the active class
+  await expect(
+    component.locator("#showConversationButton.active"),
+  ).toBeVisible();
+});
+
+test("displays all four view mode buttons", async ({ mount }) => {
+  const component = await mount(SketchViewModeSelect, {});
+
+  // Count the number of buttons
+  const buttonCount = await component.locator(".emoji-button").count();
+  expect(buttonCount).toBe(4);
+
+  // Check that each button exists
+  await expect(component.locator("#showConversationButton")).toBeVisible();
+  await expect(component.locator("#showDiffButton")).toBeVisible();
+  await expect(component.locator("#showChartsButton")).toBeVisible();
+  await expect(component.locator("#showTerminalButton")).toBeVisible();
+
+  // Check the title attributes
+  expect(
+    await component.locator("#showConversationButton").getAttribute("title"),
+  ).toBe("Conversation View");
+  expect(await component.locator("#showDiffButton").getAttribute("title")).toBe(
+    "Diff View",
+  );
+  expect(
+    await component.locator("#showChartsButton").getAttribute("title"),
+  ).toBe("Charts View");
+  expect(
+    await component.locator("#showTerminalButton").getAttribute("title"),
+  ).toBe("Terminal View");
+});
+
+test("dispatches view-mode-select event when clicking a mode button", async ({
+  mount,
+}) => {
+  const component = await mount(SketchViewModeSelect, {});
+
+  // Set up promise to wait for the event
+  const eventPromise = component.evaluate((el) => {
+    return new Promise((resolve) => {
+      el.addEventListener(
+        "view-mode-select",
+        (event) => {
+          resolve((event as CustomEvent).detail);
+        },
+        { once: true },
+      );
+    });
   });
 
-  it("initializes with 'chat' as the default mode", async () => {
-    const el: SketchViewModeSelect = await fixture(html`
-      <sketch-view-mode-select></sketch-view-mode-select>
-    `);
+  // Click the diff button
+  await component.locator("#showDiffButton").click();
 
-    expect(el.activeMode).to.equal("chat");
-    const chatButton = el.shadowRoot!.querySelector("#showConversationButton");
-    expect(chatButton!.classList.contains("active")).to.be.true;
-  });
+  // Wait for the event and check its details
+  const detail: any = await eventPromise;
+  expect(detail.mode).toBe("diff");
+});
 
-  it("displays all four view mode buttons", async () => {
-    const el: SketchViewModeSelect = await fixture(html`
-      <sketch-view-mode-select></sketch-view-mode-select>
-    `);
+test("updates the active mode when receiving update-active-mode event", async ({
+  mount,
+}) => {
+  const component = await mount(SketchViewModeSelect, {});
 
-    const buttons = el.shadowRoot!.querySelectorAll(".emoji-button");
-    expect(buttons.length).to.equal(4);
+  // Initially should be in chat mode
+  let activeMode = await component.evaluate(
+    (el: SketchViewModeSelect) => el.activeMode,
+  );
+  expect(activeMode).toBe("chat");
 
-    const chatButton = el.shadowRoot!.querySelector("#showConversationButton");
-    const diffButton = el.shadowRoot!.querySelector("#showDiffButton");
-    const chartsButton = el.shadowRoot!.querySelector("#showChartsButton");
-    const terminalButton = el.shadowRoot!.querySelector("#showTerminalButton");
-
-    expect(chatButton).to.exist;
-    expect(diffButton).to.exist;
-    expect(chartsButton).to.exist;
-    expect(terminalButton).to.exist;
-
-    expect(chatButton!.getAttribute("title")).to.equal("Conversation View");
-    expect(diffButton!.getAttribute("title")).to.equal("Diff View");
-    expect(chartsButton!.getAttribute("title")).to.equal("Charts View");
-    expect(terminalButton!.getAttribute("title")).to.equal("Terminal View");
-  });
-
-  it("dispatches view-mode-select event when clicking a mode button", async () => {
-    const el: SketchViewModeSelect = await fixture(html`
-      <sketch-view-mode-select></sketch-view-mode-select>
-    `);
-
-    const diffButton = el.shadowRoot!.querySelector(
-      "#showDiffButton",
-    ) as HTMLButtonElement;
-
-    // Setup listener for the view-mode-select event
-    setTimeout(() => diffButton.click());
-    const { detail } = await oneEvent(el, "view-mode-select");
-
-    expect(detail.mode).to.equal("diff");
-  });
-
-  it("updates the active mode when receiving update-active-mode event", async () => {
-    const el: SketchViewModeSelect = await fixture(html`
-      <sketch-view-mode-select></sketch-view-mode-select>
-    `);
-
-    // Initially should be in chat mode
-    expect(el.activeMode).to.equal("chat");
-
-    // Dispatch the update-active-mode event to change to diff mode
+  // Dispatch the update-active-mode event
+  await component.evaluate((el) => {
     const updateEvent = new CustomEvent("update-active-mode", {
       detail: { mode: "diff" },
       bubbles: true,
     });
     el.dispatchEvent(updateEvent);
-
-    // Wait for the component to update
-    await elementUpdated(el);
-
-    expect(el.activeMode).to.equal("diff");
-    const diffButton = el.shadowRoot!.querySelector("#showDiffButton");
-    expect(diffButton!.classList.contains("active")).to.be.true;
   });
 
-  it("correctly marks the active button based on mode", async () => {
-    const el: SketchViewModeSelect = await fixture(html`
-      <sketch-view-mode-select activeMode="terminal"></sketch-view-mode-select>
-    `);
+  // Check that the mode was updated
+  activeMode = await component.evaluate(
+    (el: SketchViewModeSelect) => el.activeMode,
+  );
+  expect(activeMode).toBe("diff");
 
-    // Terminal button should be active
-    const terminalButton = el.shadowRoot!.querySelector("#showTerminalButton");
-    const chatButton = el.shadowRoot!.querySelector("#showConversationButton");
-    const diffButton = el.shadowRoot!.querySelector("#showDiffButton");
-    const chartsButton = el.shadowRoot!.querySelector("#showChartsButton");
+  // Check that the diff button is now active
+  await expect(component.locator("#showDiffButton.active")).toBeVisible();
+});
 
-    expect(terminalButton!.classList.contains("active")).to.be.true;
-    expect(chatButton!.classList.contains("active")).to.be.false;
-    expect(diffButton!.classList.contains("active")).to.be.false;
-    expect(chartsButton!.classList.contains("active")).to.be.false;
+test("correctly marks the active button based on mode", async ({ mount }) => {
+  const component = await mount(SketchViewModeSelect, {
+    props: {
+      activeMode: "terminal",
+    },
   });
+
+  // Terminal button should be active
+  await expect(component.locator("#showTerminalButton.active")).toBeVisible();
+
+  // Other buttons should not be active
+  await expect(
+    component.locator("#showConversationButton.active"),
+  ).not.toBeVisible();
+  await expect(component.locator("#showDiffButton.active")).not.toBeVisible();
+  await expect(component.locator("#showChartsButton.active")).not.toBeVisible();
 });