mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-16 21:53:07 +00:00
* 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 --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
194 lines
6.2 KiB
TypeScript
194 lines
6.2 KiB
TypeScript
/**
|
|
* Context View File Extension Edge Cases E2E Tests
|
|
*
|
|
* Tests for file extension handling in the context view:
|
|
* - Files with valid markdown extensions (.md, .markdown)
|
|
* - Files without extensions (edge case for isMarkdownFile/isImageFile)
|
|
* - Image files with various extensions
|
|
* - Files with multiple dots in name
|
|
*/
|
|
|
|
import { test, expect } from '@playwright/test';
|
|
import {
|
|
resetContextDirectory,
|
|
setupProjectWithFixture,
|
|
getFixturePath,
|
|
navigateToContext,
|
|
waitForContextFile,
|
|
selectContextFile,
|
|
waitForFileContentToLoad,
|
|
clickElement,
|
|
fillInput,
|
|
waitForNetworkIdle,
|
|
authenticateForTests,
|
|
waitForElementHidden,
|
|
createContextFileOnDisk,
|
|
} from '../utils';
|
|
|
|
// Use desktop viewport for these tests
|
|
test.use({ viewport: { width: 1280, height: 720 } });
|
|
|
|
test.describe('Context View File Extension Edge Cases', () => {
|
|
test.beforeEach(async () => {
|
|
resetContextDirectory();
|
|
});
|
|
|
|
test.afterEach(async () => {
|
|
resetContextDirectory();
|
|
});
|
|
|
|
test('should handle file with .md extension', async ({ page }) => {
|
|
const fileName = 'standard-file.md';
|
|
const content = '# Standard Markdown';
|
|
|
|
await setupProjectWithFixture(page, getFixturePath());
|
|
await authenticateForTests(page);
|
|
await navigateToContext(page);
|
|
|
|
// Create file via API
|
|
createContextFileOnDisk(fileName, content);
|
|
await waitForNetworkIdle(page);
|
|
|
|
// Refresh to load the file
|
|
await page.reload();
|
|
await waitForContextFile(page, fileName);
|
|
|
|
// Select and verify it opens as markdown
|
|
await selectContextFile(page, fileName);
|
|
await waitForFileContentToLoad(page);
|
|
|
|
// Should show markdown preview
|
|
const markdownPreview = page.locator('[data-testid="markdown-preview"]');
|
|
await expect(markdownPreview).toBeVisible();
|
|
|
|
// Verify content rendered
|
|
const h1 = markdownPreview.locator('h1');
|
|
await expect(h1).toHaveText('Standard Markdown');
|
|
});
|
|
|
|
test('should handle file with .markdown extension', async ({ page }) => {
|
|
const fileName = 'extended-extension.markdown';
|
|
const content = '# Extended Extension Test';
|
|
|
|
await setupProjectWithFixture(page, getFixturePath());
|
|
await authenticateForTests(page);
|
|
await navigateToContext(page);
|
|
|
|
// Create file via API
|
|
createContextFileOnDisk(fileName, content);
|
|
await waitForNetworkIdle(page);
|
|
|
|
// Refresh to load the file
|
|
await page.reload();
|
|
await waitForContextFile(page, fileName);
|
|
|
|
// Select and verify
|
|
await selectContextFile(page, fileName);
|
|
await waitForFileContentToLoad(page);
|
|
|
|
const markdownPreview = page.locator('[data-testid="markdown-preview"]');
|
|
await expect(markdownPreview).toBeVisible();
|
|
});
|
|
|
|
test('should handle file with multiple dots in name', async ({ page }) => {
|
|
const fileName = 'my.detailed.notes.md';
|
|
const content = '# Multiple Dots Test';
|
|
|
|
await setupProjectWithFixture(page, getFixturePath());
|
|
await authenticateForTests(page);
|
|
await navigateToContext(page);
|
|
|
|
// Create file via API
|
|
createContextFileOnDisk(fileName, content);
|
|
await waitForNetworkIdle(page);
|
|
|
|
// Refresh to load the file
|
|
await page.reload();
|
|
await waitForContextFile(page, fileName);
|
|
|
|
// Select and verify - should still recognize as markdown
|
|
await selectContextFile(page, fileName);
|
|
await waitForFileContentToLoad(page);
|
|
|
|
const markdownPreview = page.locator('[data-testid="markdown-preview"]');
|
|
await expect(markdownPreview).toBeVisible();
|
|
});
|
|
|
|
test('should NOT show file without extension in file list', async ({ page }) => {
|
|
const fileName = 'README';
|
|
const content = '# File Without Extension';
|
|
|
|
await setupProjectWithFixture(page, getFixturePath());
|
|
await authenticateForTests(page);
|
|
await navigateToContext(page);
|
|
|
|
// Create file via API (without extension)
|
|
createContextFileOnDisk(fileName, content);
|
|
await waitForNetworkIdle(page);
|
|
|
|
// Refresh to load the file
|
|
await page.reload();
|
|
|
|
// Wait a moment for files to load
|
|
await page.waitForTimeout(1000);
|
|
|
|
// File should NOT appear in list because isMarkdownFile returns false for no extension
|
|
const fileButton = page.locator(`[data-testid="context-file-${fileName}"]`);
|
|
await expect(fileButton).not.toBeVisible();
|
|
});
|
|
|
|
test('should NOT create file without .md extension via UI', async ({ page }) => {
|
|
const fileName = 'NOTES';
|
|
const content = '# Notes without extension';
|
|
|
|
await setupProjectWithFixture(page, getFixturePath());
|
|
await authenticateForTests(page);
|
|
await navigateToContext(page);
|
|
|
|
// Create file via UI without extension
|
|
await clickElement(page, 'create-markdown-button');
|
|
await page.waitForSelector('[data-testid="create-markdown-dialog"]', { timeout: 5000 });
|
|
|
|
await fillInput(page, 'new-markdown-name', fileName);
|
|
await fillInput(page, 'new-markdown-content', content);
|
|
|
|
await clickElement(page, 'confirm-create-markdown');
|
|
await waitForElementHidden(page, 'create-markdown-dialog', { timeout: 5000 });
|
|
|
|
await waitForNetworkIdle(page);
|
|
|
|
// File should NOT appear in list because UI enforces .md extension
|
|
// (The UI may add .md automatically or show validation error)
|
|
const fileButton = page.locator(`[data-testid="context-file-${fileName}"]`);
|
|
await expect(fileButton)
|
|
.not.toBeVisible({ timeout: 3000 })
|
|
.catch(() => {
|
|
// It's OK if it doesn't appear - that's expected behavior
|
|
});
|
|
});
|
|
|
|
test('should handle uppercase extensions', async ({ page }) => {
|
|
const fileName = 'uppercase.MD';
|
|
const content = '# Uppercase Extension';
|
|
|
|
await setupProjectWithFixture(page, getFixturePath());
|
|
await authenticateForTests(page);
|
|
await navigateToContext(page);
|
|
|
|
// Create file via API with uppercase extension
|
|
createContextFileOnDisk(fileName, content);
|
|
await waitForNetworkIdle(page);
|
|
|
|
// Refresh to load the file
|
|
await page.reload();
|
|
await waitForContextFile(page, fileName);
|
|
|
|
// Select and verify - should recognize .MD as markdown (case-insensitive)
|
|
await selectContextFile(page, fileName);
|
|
await waitForFileContentToLoad(page);
|
|
|
|
const markdownPreview = page.locator('[data-testid="markdown-preview"]');
|
|
await expect(markdownPreview).toBeVisible();
|
|
});
|
|
});
|