diff --git a/dashboard/tests/e2e/chat-message.spec.ts b/dashboard/tests/e2e/chat-message.spec.ts
deleted file mode 100644
index 494ca8c6..00000000
--- a/dashboard/tests/e2e/chat-message.spec.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-///
-import { test, expect } from "@playwright/test";
-import { waitForTopologyLoaded } from "../helpers/wait-for-ready";
-
-test.describe("Chat Message Flow", () => {
- // This test suite requires a running instance
- // It will launch one if needed
-
- test("should send a chat message and receive a response", async ({
- page,
- }) => {
- // Skip in CI - requires launching an instance and downloading a model
- test.skip(!!process.env.CI, "Skipped in CI - requires model download");
- test.setTimeout(600000); // 10 minutes
-
- await page.goto("/");
- await waitForTopologyLoaded(page);
-
- // Check if we already have a running instance with chat available
- const chatInput = page.locator('[data-testid="chat-input"]');
- let hasChatReady = await chatInput
- .isVisible({ timeout: 5000 })
- .catch(() => false);
-
- // Check if there's a ready instance (use first() in case multiple exist)
- const readyIndicator = page.locator("text=READY").first();
- let hasReady = await readyIndicator
- .isVisible({ timeout: 2000 })
- .catch(() => false);
-
- if (!hasReady) {
- // Need to launch an instance first
- const modelDropdown = page.locator('[data-testid="model-dropdown"]');
- await expect(modelDropdown).toBeVisible({ timeout: 15000 });
-
- // Wait for placement previews
- await page.waitForTimeout(3000);
-
- const launchButton = page
- .locator('[data-testid="launch-button"]:not([disabled])')
- .first();
- let hasLaunchButton = await launchButton
- .isVisible({ timeout: 10000 })
- .catch(() => false);
-
- if (!hasLaunchButton) {
- // Select a model - prefer Qwen3-0.6B-4bit (smallest)
- await modelDropdown.click();
- await page.waitForTimeout(500);
-
- const qwenOption = page
- .locator('[data-testid="model-option"]', {
- hasText: /qwen.*0\.6b.*4bit/i,
- })
- .first();
- const hasQwen = await qwenOption
- .isVisible({ timeout: 2000 })
- .catch(() => false);
-
- if (hasQwen) {
- await qwenOption.click();
- } else {
- const modelOption = page
- .locator('[data-testid="model-option"]:not([disabled])')
- .first();
- await expect(modelOption).toBeVisible({ timeout: 5000 });
- await modelOption.click();
- }
-
- await expect(launchButton).toBeVisible({ timeout: 30000 });
- }
-
- // Launch the instance
- await launchButton.click();
-
- // Wait for instance to be ready
- await expect(readyIndicator).toBeVisible({ timeout: 300000 }); // 5 min for download
- }
-
- // Now we should have a running instance - wait for chat input to be available
- await expect(chatInput).toBeVisible({ timeout: 30000 });
-
- // Type a simple message
- await chatInput.fill("What is 2+2? Reply with just the number.");
-
- // Click send button
- const sendButton = page.locator('[data-testid="send-button"]');
- await expect(sendButton).toBeVisible();
- await sendButton.click();
-
- // Wait for user message to appear
- const userMessage = page.locator('[data-testid="user-message"]');
- await expect(userMessage).toBeVisible({ timeout: 10000 });
-
- // Wait for assistant response
- const assistantMessage = page.locator('[data-testid="assistant-message"]');
- await expect(assistantMessage).toBeVisible({ timeout: 120000 }); // 2 min for response
-
- // Verify we got some response text
- const responseText = await assistantMessage.textContent();
- expect(responseText).toBeTruthy();
- expect(responseText!.length).toBeGreaterThan(0);
- });
-});
diff --git a/dashboard/tests/e2e/launch-instance.spec.ts b/dashboard/tests/e2e/launch-instance.spec.ts
deleted file mode 100644
index be33ff9a..00000000
--- a/dashboard/tests/e2e/launch-instance.spec.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-///
-import { test, expect } from "@playwright/test";
-import { waitForTopologyLoaded } from "../helpers/wait-for-ready";
-
-test.describe("Launch Model Instance", () => {
- test.beforeEach(async ({ page }) => {
- await page.goto("/");
- await waitForTopologyLoaded(page);
- });
-
- test("should display topology graph on page load", async ({ page }) => {
- const topologyGraph = page.locator('[data-testid="topology-graph"]');
- await expect(topologyGraph).toBeVisible();
- });
-
- test("should display model dropdown on welcome page", async ({ page }) => {
- const modelDropdown = page.locator('[data-testid="model-dropdown"]');
- await expect(modelDropdown).toBeVisible({ timeout: 15000 });
- });
-
- test("should display model cards when model is selected", async ({
- page,
- }) => {
- const modelDropdown = page.locator('[data-testid="model-dropdown"]');
- await expect(modelDropdown).toBeVisible({ timeout: 15000 });
-
- // Wait for API to respond with placement previews
- await page.waitForTimeout(5000);
-
- // Check if launch button is visible (indicates model card is showing)
- const launchButton = page.locator('[data-testid="launch-button"]').first();
- let hasLaunchButton = await launchButton
- .isVisible({ timeout: 5000 })
- .catch(() => false);
-
- if (!hasLaunchButton) {
- // No model selected yet - click dropdown and select one
- await modelDropdown.click();
- await page.waitForTimeout(1000);
-
- const modelOption = page
- .locator('[data-testid="model-option"]:not([disabled])')
- .first();
- await expect(modelOption).toBeVisible({ timeout: 5000 });
-
- await modelOption.click();
- await page.waitForTimeout(3000);
- }
-
- await expect(launchButton).toBeVisible({ timeout: 30000 });
- });
-
- test("should launch a model instance", async ({ page }) => {
- // Skip in CI - requires downloading a model which is too slow
- test.skip(!!process.env.CI, "Skipped in CI - requires model download");
- test.setTimeout(300000); // 5 minutes
-
- const modelDropdown = page.locator('[data-testid="model-dropdown"]');
- await expect(modelDropdown).toBeVisible({ timeout: 15000 });
-
- // Wait for placement previews to load
- await page.waitForTimeout(3000);
-
- // Check if launch button is visible
- const launchButton = page
- .locator('[data-testid="launch-button"]:not([disabled])')
- .first();
- let hasLaunchButton = await launchButton
- .isVisible({ timeout: 10000 })
- .catch(() => false);
-
- if (!hasLaunchButton) {
- // Select a model first - prefer Qwen3-0.6B (smallest)
- await modelDropdown.click();
- await page.waitForTimeout(500);
-
- // Try to find Qwen3-0.6B-4bit specifically (smallest model), otherwise take first available
- const qwenOption = page
- .locator('[data-testid="model-option"]', {
- hasText: /qwen.*0\.6b.*4bit/i,
- })
- .first();
- const hasQwen = await qwenOption
- .isVisible({ timeout: 2000 })
- .catch(() => false);
-
- if (hasQwen) {
- await qwenOption.click();
- } else {
- const modelOption = page
- .locator('[data-testid="model-option"]:not([disabled])')
- .first();
- await expect(modelOption).toBeVisible({ timeout: 5000 });
- await modelOption.click();
- }
-
- await expect(launchButton).toBeVisible({ timeout: 30000 });
- }
-
- // Click launch
- await launchButton.click();
-
- // Wait for instance to start - could be downloading, loading, or ready
- await expect(async () => {
- const isDownloading = await page
- .locator("text=DOWNLOADING")
- .first()
- .isVisible();
- const isReady = await page.locator("text=READY").first().isVisible();
- const isLoading = await page.locator("text=LOADING").first().isVisible();
- const hasLaunching = await launchButton
- .textContent()
- .then((t) => t?.includes("LAUNCHING"));
- expect(
- isDownloading || isReady || isLoading || hasLaunching,
- ).toBeTruthy();
- }).toPass({ timeout: 30000 });
-
- // Wait for instance to be fully ready (this may take a while if downloading)
- await expect(page.locator("text=READY").first()).toBeVisible({
- timeout: 240000,
- }); // 4 min for download
- });
-});
diff --git a/dashboard/tests/visual/chat-interface.spec.ts-snapshots/chat-input-empty-chromium-darwin.png b/dashboard/tests/visual/chat-interface.spec.ts-snapshots/chat-input-empty-chromium-darwin.png
index 60937c23..59dabeb9 100644
Binary files a/dashboard/tests/visual/chat-interface.spec.ts-snapshots/chat-input-empty-chromium-darwin.png and b/dashboard/tests/visual/chat-interface.spec.ts-snapshots/chat-input-empty-chromium-darwin.png differ
diff --git a/dashboard/tests/visual/chat-interface.spec.ts-snapshots/chat-input-with-text-chromium-darwin.png b/dashboard/tests/visual/chat-interface.spec.ts-snapshots/chat-input-with-text-chromium-darwin.png
index ee67f60c..ddb4325a 100644
Binary files a/dashboard/tests/visual/chat-interface.spec.ts-snapshots/chat-input-with-text-chromium-darwin.png and b/dashboard/tests/visual/chat-interface.spec.ts-snapshots/chat-input-with-text-chromium-darwin.png differ
diff --git a/dashboard/tests/visual/homepage.spec.ts-snapshots/topology-graph-chromium-darwin.png b/dashboard/tests/visual/homepage.spec.ts-snapshots/topology-graph-chromium-darwin.png
index 7ddaf996..9a64d4a6 100644
Binary files a/dashboard/tests/visual/homepage.spec.ts-snapshots/topology-graph-chromium-darwin.png and b/dashboard/tests/visual/homepage.spec.ts-snapshots/topology-graph-chromium-darwin.png differ