import { Page, Locator } from "@playwright/test"; import { clickElement, fillInput } from "../core/interactions"; import { waitForElement, waitForElementHidden } from "../core/waiting"; import { getByTestId } from "../core/elements"; import { expect } from "@playwright/test"; /** * Get the context file list element */ export async function getContextFileList(page: Page): Promise { return page.locator('[data-testid="context-file-list"]'); } /** * Click on a context file in the list */ export async function clickContextFile( page: Page, fileName: string ): Promise { const fileButton = page.locator(`[data-testid="context-file-${fileName}"]`); await fileButton.click(); } /** * Get the context editor element */ export async function getContextEditor(page: Page): Promise { return page.locator('[data-testid="context-editor"]'); } /** * Get the context editor content */ export async function getContextEditorContent(page: Page): Promise { const editor = await getByTestId(page, "context-editor"); return await editor.inputValue(); } /** * Set the context editor content */ export async function setContextEditorContent( page: Page, content: string ): Promise { const editor = await getByTestId(page, "context-editor"); await editor.fill(content); } /** * Open the add context file dialog */ export async function openAddContextFileDialog(page: Page): Promise { await clickElement(page, "add-context-file"); await waitForElement(page, "add-context-dialog"); } /** * Create a text context file via the UI */ export async function createContextFile( page: Page, filename: string, content: string ): Promise { await openAddContextFileDialog(page); await clickElement(page, "add-text-type"); await fillInput(page, "new-file-name", filename); await fillInput(page, "new-file-content", content); await clickElement(page, "confirm-add-file"); await waitForElementHidden(page, "add-context-dialog"); } /** * Create an image context file via the UI */ export async function createContextImage( page: Page, filename: string, imagePath: string ): Promise { await openAddContextFileDialog(page); await clickElement(page, "add-image-type"); await fillInput(page, "new-file-name", filename); await page.setInputFiles('[data-testid="image-upload-input"]', imagePath); await clickElement(page, "confirm-add-file"); await waitForElementHidden(page, "add-context-dialog"); } /** * Delete a context file via the UI (must be selected first) */ export async function deleteSelectedContextFile(page: Page): Promise { await clickElement(page, "delete-context-file"); await waitForElement(page, "delete-context-dialog"); await clickElement(page, "confirm-delete-file"); await waitForElementHidden(page, "delete-context-dialog"); } /** * Save the current context file */ export async function saveContextFile(page: Page): Promise { await clickElement(page, "save-context-file"); // Wait for save to complete (button shows "Saved") await page.waitForFunction( () => document .querySelector('[data-testid="save-context-file"]') ?.textContent?.includes("Saved"), { timeout: 5000 } ); } /** * Toggle markdown preview mode */ export async function toggleContextPreviewMode(page: Page): Promise { await clickElement(page, "toggle-preview-mode"); } /** * Wait for a specific file to appear in the context file list */ export async function waitForContextFile( page: Page, filename: string, timeout: number = 10000 ): Promise { const locator = await getByTestId(page, `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 */ export async function selectContextFile( page: Page, filename: string, timeout: number = 10000 ): Promise { const fileButton = await getByTestId(page, `context-file-${filename}`); await fileButton.waitFor({ state: "visible", timeout }); // 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) const deleteButton = await getByTestId(page, "delete-context-file"); await expect(deleteButton).toBeVisible({ timeout, }); } /** * Wait for file content panel to load (either editor, preview, or image) */ export async function waitForFileContentToLoad(page: Page): Promise { // 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 */ export async function switchToEditMode(page: Page): Promise { // First wait for content to load await waitForFileContentToLoad(page); const markdownPreview = await getByTestId(page, "markdown-preview"); const isPreview = await markdownPreview.isVisible().catch(() => false); if (isPreview) { await clickElement(page, "toggle-preview-mode"); await page.waitForSelector('[data-testid="context-editor"]', { timeout: 5000, }); } }