refactor: restructure test utilities and enhance context view tests

- Refactored test utilities by consolidating and organizing helper functions into dedicated modules for better maintainability and clarity.
- Introduced new utility functions for interactions, waiting, and element retrieval, improving the readability of test cases.
- Updated context view tests to utilize the new utility functions, enhancing test reliability and reducing code duplication.
- Removed deprecated utility functions and ensured all tests are aligned with the new structure.
This commit is contained in:
Kacper
2025-12-15 02:40:09 +01:00
parent a412f5d0fb
commit 0b1123e3ce
29 changed files with 3478 additions and 3191 deletions

View File

@@ -1,206 +1,29 @@
import { test, expect, Page } from "@playwright/test";
import { test, expect } from "@playwright/test";
import * as fs from "fs";
import * as path from "path";
import {
resetContextDirectory,
createContextFileOnDisk,
contextFileExistsOnDisk,
setupProjectWithFixture,
getFixturePath,
navigateToContext,
waitForFileContentToLoad,
switchToEditMode,
waitForContextFile,
selectContextFile,
simulateFileDrop,
setContextEditorContent,
getContextEditorContent,
clickElement,
fillInput,
getByTestId,
waitForNetworkIdle,
} from "./utils";
// Workspace root detection (same pattern as spec-editor-persistence.spec.ts)
function getWorkspaceRoot(): string {
const cwd = process.cwd();
if (cwd.includes("apps/app")) {
return path.resolve(cwd, "../..");
}
return cwd;
}
const WORKSPACE_ROOT = getWorkspaceRoot();
const FIXTURE_PATH = path.join(WORKSPACE_ROOT, "test/fixtures/projectA");
const CONTEXT_PATH = path.join(FIXTURE_PATH, ".automaker/context");
const WORKSPACE_ROOT = path.resolve(process.cwd(), "../..");
const TEST_IMAGE_SRC = path.join(WORKSPACE_ROOT, "apps/app/public/logo.png");
/**
* Reset the context directory to empty state
*/
function resetContextDirectory(): void {
if (fs.existsSync(CONTEXT_PATH)) {
fs.rmSync(CONTEXT_PATH, { recursive: true });
}
fs.mkdirSync(CONTEXT_PATH, { recursive: true });
}
/**
* Create a context file directly on disk (for test setup)
*/
function createContextFileOnDisk(filename: string, content: string): void {
const filePath = path.join(CONTEXT_PATH, filename);
fs.writeFileSync(filePath, content);
}
/**
* Check if a context file exists on disk
*/
function contextFileExistsOnDisk(filename: string): boolean {
const filePath = path.join(CONTEXT_PATH, filename);
return fs.existsSync(filePath);
}
/**
* Set up localStorage with a project pointing to our test fixture
*/
async function setupProjectWithFixture(page: Page, projectPath: string) {
await page.addInitScript((pathArg: string) => {
const mockProject = {
id: "test-project-fixture",
name: "projectA",
path: pathArg,
lastOpened: new Date().toISOString(),
};
const mockState = {
state: {
projects: [mockProject],
currentProject: mockProject,
currentView: "context",
theme: "dark",
sidebarOpen: true,
apiKeys: { anthropic: "", google: "" },
chatSessions: [],
chatHistoryOpen: false,
maxConcurrency: 3,
},
version: 0,
};
localStorage.setItem("automaker-storage", JSON.stringify(mockState));
// Mark setup as complete
const setupState = {
state: {
isFirstRun: false,
setupComplete: true,
currentStep: "complete",
skipClaudeSetup: false,
},
version: 0,
};
localStorage.setItem("automaker-setup", JSON.stringify(setupState));
}, projectPath);
}
/**
* Navigate to context view after page load
*/
async function navigateToContextView(page: Page) {
const contextNav = page.locator('[data-testid="nav-context"]');
await contextNav.waitFor({ state: "visible", timeout: 10000 });
await contextNav.click();
await page.waitForSelector('[data-testid="context-view"]', { timeout: 10000 });
}
/**
* Wait for file content panel to load (either editor, preview, or image)
*/
async function waitForFileContentToLoad(page: Page): Promise<void> {
// Wait for either the editor, preview, or image to appear
await page.waitForSelector(
'[data-testid="context-editor"], [data-testid="markdown-preview"], [data-testid="image-preview"]',
{ timeout: 10000 }
);
}
/**
* Switch from preview mode to edit mode for markdown files
* Markdown files open in preview mode by default, this helper switches to edit mode
*/
async function switchToEditMode(page: Page): Promise<void> {
// First wait for content to load
await waitForFileContentToLoad(page);
const isPreview = await page
.locator('[data-testid="markdown-preview"]')
.isVisible()
.catch(() => false);
if (isPreview) {
await page.locator('[data-testid="toggle-preview-mode"]').click();
await page.waitForSelector('[data-testid="context-editor"]', {
timeout: 5000,
});
}
}
/**
* Wait for a specific file to appear in the file list
*/
async function waitForContextFile(
page: Page,
filename: string,
timeout: number = 10000
): Promise<void> {
const locator = page.locator(`[data-testid="context-file-${filename}"]`);
await locator.waitFor({ state: "visible", timeout });
}
/**
* Click a file in the list and wait for it to be selected (toolbar visible)
* Uses JavaScript click to ensure React event handler fires
*/
async function selectContextFile(
page: Page,
filename: string,
timeout: number = 10000
): Promise<void> {
const fileButton = page.locator(`[data-testid="context-file-${filename}"]`);
await fileButton.waitFor({ state: "visible", timeout });
// Small delay to ensure React has finished rendering the file list
await page.waitForTimeout(200);
// Use JavaScript click to ensure React onClick handler fires
await fileButton.evaluate((el) => (el as HTMLButtonElement).click());
// Wait for the file to be selected (toolbar with delete button becomes visible)
// Use poll to handle async file loading
await expect(page.locator('[data-testid="delete-context-file"]')).toBeVisible({
timeout,
});
}
/**
* Simulate drag and drop of a file onto an element
*/
async function simulateFileDrop(
page: Page,
targetSelector: string,
fileName: string,
fileContent: string,
mimeType: string = "text/plain"
): Promise<void> {
await page.evaluate(
({ selector, content, name, mime }) => {
const target = document.querySelector(selector);
if (!target) throw new Error(`Element not found: ${selector}`);
const file = new File([content], name, { type: mime });
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
// Dispatch drag events
target.dispatchEvent(
new DragEvent("dragover", {
dataTransfer,
bubbles: true,
})
);
target.dispatchEvent(
new DragEvent("drop", {
dataTransfer,
bubbles: true,
})
);
},
{ selector: targetSelector, content: fileContent, name: fileName, mime: mimeType }
);
}
// Configure all tests to run serially to prevent interference with shared context directory
test.describe.configure({ mode: "serial" });
@@ -218,32 +41,30 @@ test.describe("Context View - File Management", () => {
});
test("should create a new MD context file", async ({ page }) => {
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Click Add File button
await page.locator('[data-testid="add-context-file"]').click();
await clickElement(page, "add-context-file");
await page.waitForSelector('[data-testid="add-context-dialog"]', {
timeout: 5000,
});
// Select text type (should be default)
await page.locator('[data-testid="add-text-type"]').click();
await clickElement(page, "add-text-type");
// Enter filename
await page
.locator('[data-testid="new-file-name"]')
.fill("test-context.md");
await fillInput(page, "new-file-name", "test-context.md");
// Enter content
const testContent = "# Test Context\n\nThis is test content";
await page.locator('[data-testid="new-file-content"]').fill(testContent);
await fillInput(page, "new-file-content", testContent);
// Click confirm
await page.locator('[data-testid="confirm-add-file"]').click();
await clickElement(page, "confirm-add-file");
// Wait for dialog to close
await page.waitForFunction(
@@ -286,11 +107,11 @@ test.describe("Context View - File Management", () => {
const originalContent = "# Original Content\n\nThis will be edited.";
createContextFileOnDisk("edit-test.md", originalContent);
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Click on the existing file and wait for it to be selected
await selectContextFile(page, "edit-test.md");
@@ -308,10 +129,10 @@ test.describe("Context View - File Management", () => {
// Modify content
const newContent = "# Modified Content\n\nThis has been edited.";
await page.locator('[data-testid="context-editor"]').fill(newContent);
await setContextEditorContent(page, newContent);
// Click save
await page.locator('[data-testid="save-context-file"]').click();
await clickElement(page, "save-context-file");
// Wait for save to complete
await page.waitForFunction(
@@ -324,10 +145,10 @@ test.describe("Context View - File Management", () => {
// Reload page
await page.reload();
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
// Navigate back to context view
await navigateToContextView(page);
await navigateToContext(page);
// Wait for file to appear after reload and select it
await selectContextFile(page, "edit-test.md");
@@ -343,9 +164,7 @@ test.describe("Context View - File Management", () => {
});
// Verify content persisted
const persistedContent = await page
.locator('[data-testid="context-editor"]')
.inputValue();
const persistedContent = await getContextEditorContent(page);
expect(persistedContent).toBe(newContent);
});
@@ -353,21 +172,19 @@ test.describe("Context View - File Management", () => {
// Create a test file on disk first
createContextFileOnDisk("delete-test.md", "# Delete Me");
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Click on the file to select it
const fileButton = page.locator(
'[data-testid="context-file-delete-test.md"]'
);
const fileButton = await getByTestId(page, "context-file-delete-test.md");
await fileButton.waitFor({ state: "visible", timeout: 5000 });
await fileButton.click();
// Click delete button
await page.locator('[data-testid="delete-context-file"]').click();
await clickElement(page, "delete-context-file");
// Wait for delete dialog
await page.waitForSelector('[data-testid="delete-context-dialog"]', {
@@ -375,7 +192,7 @@ test.describe("Context View - File Management", () => {
});
// Confirm deletion
await page.locator('[data-testid="confirm-delete-file"]').click();
await clickElement(page, "confirm-delete-file");
// Wait for dialog to close
await page.waitForFunction(
@@ -384,32 +201,31 @@ test.describe("Context View - File Management", () => {
);
// Verify file is removed from list
await expect(
page.locator('[data-testid="context-file-delete-test.md"]')
).not.toBeVisible();
const deletedFile = await getByTestId(page, "context-file-delete-test.md");
await expect(deletedFile).not.toBeVisible();
// Verify file is removed from disk
expect(contextFileExistsOnDisk("delete-test.md")).toBe(false);
});
test("should upload an image context file", async ({ page }) => {
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Click Add File button
await page.locator('[data-testid="add-context-file"]').click();
await clickElement(page, "add-context-file");
await page.waitForSelector('[data-testid="add-context-dialog"]', {
timeout: 5000,
});
// Select image type
await page.locator('[data-testid="add-image-type"]').click();
await clickElement(page, "add-image-type");
// Enter filename
await page.locator('[data-testid="new-file-name"]').fill("test-image.png");
await fillInput(page, "new-file-name", "test-image.png");
// Upload image using file input
await page.setInputFiles(
@@ -421,7 +237,7 @@ test.describe("Context View - File Management", () => {
await page.waitForTimeout(500);
// Click confirm
await page.locator('[data-testid="confirm-add-file"]').click();
await clickElement(page, "confirm-add-file");
// Wait for dialog to close
await page.waitForFunction(
@@ -430,9 +246,7 @@ test.describe("Context View - File Management", () => {
);
// Verify file appears in list
const fileButton = page.locator(
'[data-testid="context-file-test-image.png"]'
);
const fileButton = await getByTestId(page, "context-file-test-image.png");
await expect(fileButton).toBeVisible();
// Click on the image to view it
@@ -449,13 +263,14 @@ test.describe("Context View - File Management", () => {
// Create a test image file on disk as base64 data URL (matching app's storage format)
const imageContent = fs.readFileSync(TEST_IMAGE_SRC);
const base64DataUrl = `data:image/png;base64,${imageContent.toString("base64")}`;
fs.writeFileSync(path.join(CONTEXT_PATH, "delete-image.png"), base64DataUrl);
const contextPath = path.join(getFixturePath(), ".automaker/context");
fs.writeFileSync(path.join(contextPath, "delete-image.png"), base64DataUrl);
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Wait for the image file and select it
await selectContextFile(page, "delete-image.png");
@@ -464,7 +279,7 @@ test.describe("Context View - File Management", () => {
await waitForFileContentToLoad(page);
// Click delete button
await page.locator('[data-testid="delete-context-file"]').click();
await clickElement(page, "delete-context-file");
// Wait for delete dialog
await page.waitForSelector('[data-testid="delete-context-dialog"]', {
@@ -472,7 +287,7 @@ test.describe("Context View - File Management", () => {
});
// Confirm deletion
await page.locator('[data-testid="confirm-delete-file"]').click();
await clickElement(page, "confirm-delete-file");
// Wait for dialog to close
await page.waitForFunction(
@@ -481,9 +296,8 @@ test.describe("Context View - File Management", () => {
);
// Verify file is removed from list
await expect(
page.locator('[data-testid="context-file-delete-image.png"]')
).not.toBeVisible();
const deletedImageFile = await getByTestId(page, "context-file-delete-image.png");
await expect(deletedImageFile).not.toBeVisible();
});
test("should toggle markdown preview mode", async ({ page }) => {
@@ -492,11 +306,11 @@ test.describe("Context View - File Management", () => {
"# Heading\n\n**Bold text** and *italic text*\n\n- List item 1\n- List item 2";
createContextFileOnDisk("preview-test.md", mdContent);
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Click on the markdown file
const fileButton = page.locator(
@@ -509,14 +323,12 @@ test.describe("Context View - File Management", () => {
await page.waitForTimeout(500);
// Check if preview button is visible (indicates it's a markdown file)
const previewToggle = page.locator('[data-testid="toggle-preview-mode"]');
const previewToggle = await getByTestId(page, "toggle-preview-mode");
await expect(previewToggle).toBeVisible();
// Check current mode - if we see markdown-preview, we're in preview mode
const isInPreviewMode = await page
.locator('[data-testid="markdown-preview"]')
.isVisible()
.catch(() => false);
const markdownPreview = await getByTestId(page, "markdown-preview");
const isInPreviewMode = await markdownPreview.isVisible().catch(() => false);
if (isInPreviewMode) {
// Click to switch to edit mode
@@ -526,12 +338,9 @@ test.describe("Context View - File Management", () => {
});
// Verify editor is shown
await expect(
page.locator('[data-testid="context-editor"]')
).toBeVisible();
await expect(
page.locator('[data-testid="markdown-preview"]')
).not.toBeVisible();
const editor = await getByTestId(page, "context-editor");
await expect(editor).toBeVisible();
await expect(markdownPreview).not.toBeVisible();
// Click to switch back to preview mode
await previewToggle.click();
@@ -540,9 +349,7 @@ test.describe("Context View - File Management", () => {
});
// Verify preview is shown
await expect(
page.locator('[data-testid="markdown-preview"]')
).toBeVisible();
await expect(markdownPreview).toBeVisible();
} else {
// We're in edit mode, click to switch to preview
await previewToggle.click();
@@ -551,9 +358,7 @@ test.describe("Context View - File Management", () => {
});
// Verify preview is shown
await expect(
page.locator('[data-testid="markdown-preview"]')
).toBeVisible();
await expect(markdownPreview).toBeVisible();
// Click to switch back to edit mode
await previewToggle.click();
@@ -562,9 +367,8 @@ test.describe("Context View - File Management", () => {
});
// Verify editor is shown
await expect(
page.locator('[data-testid="context-editor"]')
).toBeVisible();
const editor = await getByTestId(page, "context-editor");
await expect(editor).toBeVisible();
}
});
});
@@ -584,20 +388,20 @@ test.describe("Context View - Drag and Drop", () => {
test("should handle drag and drop of MD file onto textarea in add dialog", async ({
page,
}) => {
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Open add file dialog
await page.locator('[data-testid="add-context-file"]').click();
await clickElement(page, "add-context-file");
await page.waitForSelector('[data-testid="add-context-dialog"]', {
timeout: 5000,
});
// Ensure text type is selected
await page.locator('[data-testid="add-text-type"]').click();
await clickElement(page, "add-text-type");
// Simulate drag and drop of a .md file onto the textarea
const droppedContent = "# Dropped Content\n\nThis was dragged and dropped.";
@@ -624,7 +428,7 @@ test.describe("Context View - Drag and Drop", () => {
expect(filenameValue).toBe("dropped-file.md");
// Confirm and create the file
await page.locator('[data-testid="confirm-add-file"]').click();
await clickElement(page, "confirm-add-file");
// Wait for dialog to close
await page.waitForFunction(
@@ -633,19 +437,18 @@ test.describe("Context View - Drag and Drop", () => {
);
// Verify file was created
await expect(
page.locator('[data-testid="context-file-dropped-file.md"]')
).toBeVisible();
const droppedFile = await getByTestId(page, "context-file-dropped-file.md");
await expect(droppedFile).toBeVisible();
});
test("should handle drag and drop of file onto main view", async ({
page,
}) => {
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Wait for the context view to be fully loaded
await page.waitForSelector('[data-testid="context-file-list"]', {
@@ -665,9 +468,7 @@ test.describe("Context View - Drag and Drop", () => {
await waitForContextFile(page, "main-drop.txt", 15000);
// Verify file appears in the file list
const fileButton = page.locator(
'[data-testid="context-file-main-drop.txt"]'
);
const fileButton = await getByTestId(page, "context-file-main-drop.txt");
await expect(fileButton).toBeVisible();
// Select file and verify content
@@ -676,9 +477,7 @@ test.describe("Context View - Drag and Drop", () => {
timeout: 5000,
});
const editorContent = await page
.locator('[data-testid="context-editor"]')
.inputValue();
const editorContent = await getContextEditorContent(page);
expect(editorContent).toBe(droppedContent);
});
});
@@ -701,30 +500,27 @@ test.describe("Context View - Edge Cases", () => {
// Create an existing file
createContextFileOnDisk("test.md", "# Original Content");
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Verify the original file exists
await expect(
page.locator('[data-testid="context-file-test.md"]')
).toBeVisible();
const originalFile = await getByTestId(page, "context-file-test.md");
await expect(originalFile).toBeVisible();
// Try to create another file with the same name
await page.locator('[data-testid="add-context-file"]').click();
await clickElement(page, "add-context-file");
await page.waitForSelector('[data-testid="add-context-dialog"]', {
timeout: 5000,
});
await page.locator('[data-testid="add-text-type"]').click();
await page.locator('[data-testid="new-file-name"]').fill("test.md");
await page
.locator('[data-testid="new-file-content"]')
.fill("# New Content - Overwritten");
await clickElement(page, "add-text-type");
await fillInput(page, "new-file-name", "test.md");
await fillInput(page, "new-file-content", "# New Content - Overwritten");
await page.locator('[data-testid="confirm-add-file"]').click();
await clickElement(page, "confirm-add-file");
// Wait for dialog to close
await page.waitForFunction(
@@ -733,12 +529,10 @@ test.describe("Context View - Edge Cases", () => {
);
// File should still exist (was overwritten)
await expect(
page.locator('[data-testid="context-file-test.md"]')
).toBeVisible();
await expect(originalFile).toBeVisible();
// Select the file and verify the new content
await page.locator('[data-testid="context-file-test.md"]').click();
await originalFile.click();
// Wait for content to load
await page.waitForTimeout(500);
@@ -750,69 +544,59 @@ test.describe("Context View - Edge Cases", () => {
timeout: 5000,
});
const editorContent = await page
.locator('[data-testid="context-editor"]')
.inputValue();
const editorContent = await getContextEditorContent(page);
expect(editorContent).toBe("# New Content - Overwritten");
});
test("should handle special characters in filename", async ({ page }) => {
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Test file with parentheses
await page.locator('[data-testid="add-context-file"]').click();
await clickElement(page, "add-context-file");
await page.waitForSelector('[data-testid="add-context-dialog"]', {
timeout: 5000,
});
await page.locator('[data-testid="add-text-type"]').click();
await page.locator('[data-testid="new-file-name"]').fill("context (1).md");
await page
.locator('[data-testid="new-file-content"]')
.fill("Content with parentheses in filename");
await clickElement(page, "add-text-type");
await fillInput(page, "new-file-name", "context (1).md");
await fillInput(page, "new-file-content", "Content with parentheses in filename");
await page.locator('[data-testid="confirm-add-file"]').click();
await clickElement(page, "confirm-add-file");
await page.waitForFunction(
() => !document.querySelector('[data-testid="add-context-dialog"]'),
{ timeout: 5000 }
);
// Verify file is created - use CSS escape for special characters
await expect(
page.locator('[data-testid="context-file-context (1).md"]')
).toBeVisible();
const fileWithParens = await getByTestId(page, "context-file-context (1).md");
await expect(fileWithParens).toBeVisible();
// Test file with hyphens and underscores
await page.locator('[data-testid="add-context-file"]').click();
await clickElement(page, "add-context-file");
await page.waitForSelector('[data-testid="add-context-dialog"]', {
timeout: 5000,
});
await page.locator('[data-testid="add-text-type"]').click();
await page
.locator('[data-testid="new-file-name"]')
.fill("test-file_v2.md");
await page
.locator('[data-testid="new-file-content"]')
.fill("Content with hyphens and underscores");
await clickElement(page, "add-text-type");
await fillInput(page, "new-file-name", "test-file_v2.md");
await fillInput(page, "new-file-content", "Content with hyphens and underscores");
await page.locator('[data-testid="confirm-add-file"]').click();
await clickElement(page, "confirm-add-file");
await page.waitForFunction(
() => !document.querySelector('[data-testid="add-context-dialog"]'),
{ timeout: 5000 }
);
// Verify file is created
await expect(
page.locator('[data-testid="context-file-test-file_v2.md"]')
).toBeVisible();
const fileWithHyphens = await getByTestId(page, "context-file-test-file_v2.md");
await expect(fileWithHyphens).toBeVisible();
// Verify both files are accessible
await page.locator('[data-testid="context-file-test-file_v2.md"]').click();
await fileWithHyphens.click();
// Wait for content to load
await page.waitForTimeout(500);
@@ -824,42 +608,39 @@ test.describe("Context View - Edge Cases", () => {
timeout: 5000,
});
const content = await page
.locator('[data-testid="context-editor"]')
.inputValue();
const content = await getContextEditorContent(page);
expect(content).toBe("Content with hyphens and underscores");
});
test("should handle empty content", async ({ page }) => {
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Create file with empty content
await page.locator('[data-testid="add-context-file"]').click();
await clickElement(page, "add-context-file");
await page.waitForSelector('[data-testid="add-context-dialog"]', {
timeout: 5000,
});
await page.locator('[data-testid="add-text-type"]').click();
await page.locator('[data-testid="new-file-name"]').fill("empty-file.md");
await clickElement(page, "add-text-type");
await fillInput(page, "new-file-name", "empty-file.md");
// Don't fill any content - leave it empty
await page.locator('[data-testid="confirm-add-file"]').click();
await clickElement(page, "confirm-add-file");
await page.waitForFunction(
() => !document.querySelector('[data-testid="add-context-dialog"]'),
{ timeout: 5000 }
);
// Verify file is created
await expect(
page.locator('[data-testid="context-file-empty-file.md"]')
).toBeVisible();
const emptyFile = await getByTestId(page, "context-file-empty-file.md");
await expect(emptyFile).toBeVisible();
// Select file and verify editor shows empty content
await page.locator('[data-testid="context-file-empty-file.md"]').click();
await emptyFile.click();
// Wait for content to load
await page.waitForTimeout(500);
@@ -871,19 +652,17 @@ test.describe("Context View - Edge Cases", () => {
timeout: 5000,
});
const editorContent = await page
.locator('[data-testid="context-editor"]')
.inputValue();
const editorContent = await getContextEditorContent(page);
expect(editorContent).toBe("");
// Verify save works with empty content
// The save button should be disabled when there are no changes
// Let's add some content first, then clear it and save
await page.locator('[data-testid="context-editor"]').fill("temporary");
await page.locator('[data-testid="context-editor"]').fill("");
await setContextEditorContent(page, "temporary");
await setContextEditorContent(page, "");
// Save should work
await page.locator('[data-testid="save-context-file"]').click();
await clickElement(page, "save-context-file");
await page.waitForFunction(
() =>
document
@@ -898,21 +677,21 @@ test.describe("Context View - Edge Cases", () => {
const testContent = "# Persistence Test\n\nThis content should persist.";
createContextFileOnDisk("persist-test.md", testContent);
await setupProjectWithFixture(page, FIXTURE_PATH);
await setupProjectWithFixture(page, getFixturePath());
await page.goto("/");
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
await navigateToContextView(page);
await navigateToContext(page);
// Verify file exists before refresh
await waitForContextFile(page, "persist-test.md", 10000);
// Refresh the page
await page.reload();
await page.waitForLoadState("networkidle");
await waitForNetworkIdle(page);
// Navigate back to context view
await navigateToContextView(page);
await navigateToContext(page);
// Select the file after refresh (uses robust clicking mechanism)
await selectContextFile(page, "persist-test.md");