Files
automaker/apps/ui/tests/context/mobile-context-operations.spec.ts
gsxdsm 70d400793b Fix: memory and context views mobile friendly (#818)
* Changes from fix/memory-and-context-mobile-friendly

* fix: Improve file extension detection and add path traversal protection

* refactor: Extract file extension utilities and add path traversal guards

Code review improvements:
- Extract isMarkdownFilename and isImageFilename to shared image-utils.ts
- Remove duplicated code from context-view.tsx and memory-view.tsx
- Add path traversal guard for context fixture utilities (matching memory)
- Add 7 new tests for context fixture path traversal protection
- Total 61 tests pass

Addresses code review feedback from PR #813

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: Add e2e tests for profiles crud and board background persistence

* Update apps/ui/playwright.config.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix: Add robust test navigation handling and file filtering

* fix: Format NODE_OPTIONS configuration on single line

* test: Update profiles and board background persistence tests

* test: Replace iPhone 13 Pro with Pixel 5 for mobile test consistency

* Update apps/ui/src/components/views/context-view.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* chore: Remove test project directory

* feat: Filter context files by type and improve mobile menu visibility

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-26 08:37:33 -08:00

132 lines
4.2 KiB
TypeScript

/**
* Mobile Context View Operations E2E Tests
*
* Tests for file operations on mobile in the context view:
* - Deleting files via dropdown menu on mobile
* - Creating files via mobile actions panel
*/
import { test, expect, devices } from '@playwright/test';
import {
resetContextDirectory,
setupProjectWithFixture,
getFixturePath,
navigateToContext,
waitForContextFile,
clickElement,
fillInput,
waitForNetworkIdle,
authenticateForTests,
contextFileExistsOnDisk,
waitForElementHidden,
} from '../utils';
// Use mobile viewport for mobile tests in Chromium CI
test.use({ ...devices['Pixel 5'] });
test.describe('Mobile Context View Operations', () => {
test.beforeEach(async () => {
resetContextDirectory();
});
test.afterEach(async () => {
resetContextDirectory();
});
test('should create a file via mobile actions panel', async ({ page }) => {
const fileName = 'mobile-created.md';
await setupProjectWithFixture(page, getFixturePath());
await authenticateForTests(page);
await navigateToContext(page);
// Create a test file via mobile actions panel
await clickElement(page, 'header-actions-panel-trigger');
await clickElement(page, 'create-markdown-button-mobile');
await page.waitForSelector('[data-testid="create-markdown-dialog"]', { timeout: 5000 });
await fillInput(page, 'new-markdown-name', fileName);
await fillInput(page, 'new-markdown-content', '# Created on Mobile');
await clickElement(page, 'confirm-create-markdown');
await waitForElementHidden(page, 'create-markdown-dialog', { timeout: 5000 });
await waitForNetworkIdle(page);
await waitForContextFile(page, fileName);
// Verify file appears in list
const fileButton = page.locator(`[data-testid="context-file-${fileName}"]`);
await expect(fileButton).toBeVisible();
// Verify file exists on disk
expect(contextFileExistsOnDisk(fileName)).toBe(true);
});
test('should delete a file via dropdown menu on mobile', async ({ page }) => {
const fileName = 'delete-via-menu-test.md';
await setupProjectWithFixture(page, getFixturePath());
await authenticateForTests(page);
await navigateToContext(page);
// Create a test file
await clickElement(page, 'header-actions-panel-trigger');
await clickElement(page, 'create-markdown-button-mobile');
await page.waitForSelector('[data-testid="create-markdown-dialog"]', { timeout: 5000 });
await fillInput(page, 'new-markdown-name', fileName);
await fillInput(page, 'new-markdown-content', '# File to Delete');
await clickElement(page, 'confirm-create-markdown');
await waitForElementHidden(page, 'create-markdown-dialog', { timeout: 5000 });
await waitForNetworkIdle(page);
await waitForContextFile(page, fileName);
// Verify file exists
expect(contextFileExistsOnDisk(fileName)).toBe(true);
// Close actions panel if still open
await page.keyboard.press('Escape');
await page.waitForTimeout(300);
// Click on the file menu dropdown - hover first to make it visible
const fileRow = page.locator(`[data-testid="context-file-${fileName}"]`);
await fileRow.hover();
const fileMenuButton = page.locator(`[data-testid="context-file-menu-${fileName}"]`);
await fileMenuButton.click({ force: true });
// Wait for dropdown
await page.waitForTimeout(300);
// Click delete in dropdown
const deleteMenuItem = page.locator(`[data-testid="delete-context-file-${fileName}"]`);
await deleteMenuItem.click();
// Wait for file to be removed from list
await waitForElementHidden(page, `context-file-${fileName}`, { timeout: 5000 });
// Verify file no longer exists on disk
expect(contextFileExistsOnDisk(fileName)).toBe(false);
});
test('should import file button be available in actions panel', async ({ page }) => {
await setupProjectWithFixture(page, getFixturePath());
await authenticateForTests(page);
await navigateToContext(page);
// Open actions panel
await clickElement(page, 'header-actions-panel-trigger');
// Verify import button is visible in actions panel
const importButton = page.locator('[data-testid="import-file-button-mobile"]');
await expect(importButton).toBeVisible();
});
});