Testing infrastructure, fix truncating of dataURLs (#26)
* feat: implement comprehensive testing infrastructure - Fix image dataURL truncation bug in security.ts with configurable size limits - Add backend integration tests (22 tests) with Vitest for API validation - Add frontend unit tests (11 tests) for JSON serialization - Implement browser-based E2E tests (8 tests) with Playwright - Create Docker setup for repeatable E2E testing environment - Add GitHub Actions CI workflow for automated testing - Update .gitignore for test artifacts and temporary files Testing Infrastructure: - Backend: Vitest + Supertest for API integration tests - Frontend: Vitest + Testing Library for component tests - E2E: Playwright with Chromium for full browser automation - CI/CD: GitHub Actions with parallel test execution Security Improvements: - Make dataURL size limit configurable (default: 10MB) - Enhanced validation for image dataURLs - Block malicious content (javascript:, script tags) All tests pass: 41 total (22 backend + 11 frontend + 8 E2E) * feat(tests): add comprehensive E2E tests for dashboard workflows and image persistence chore(env): update environment variables for consistent API URL usage fix(api): centralize API request helpers for drawing and collection management style(DrawingCard): enhance accessibility with ARIA attributes and data-testid for testing * cleanup/revise documentation * cleanup/revise documentation * Add end-to-end tests for drawing CRUD, export/import, search/sort, and theme toggle functionalities - Implemented E2E tests for drawing creation, editing, and deletion in `drawing-crud.spec.ts`. - Added tests for export and import features, including JSON and SQLite formats in `export-import.spec.ts`. - Created tests for searching and sorting drawings by name and date in `search-and-sort.spec.ts`. - Developed tests for theme toggle functionality to ensure persistence across sessions in `theme-toggle.spec.ts`. * fix: exclude test files from production build to fix Docker build * feat: implement comprehensive testing infrastructure (#19) * bump version 0.1.7 * feat: implement comprehensive testing infrastructure - Fix image dataURL truncation bug in security.ts with configurable size limits - Add backend integration tests (22 tests) with Vitest for API validation - Add frontend unit tests (11 tests) for JSON serialization - Implement browser-based E2E tests (8 tests) with Playwright - Create Docker setup for repeatable E2E testing environment - Add GitHub Actions CI workflow for automated testing - Update .gitignore for test artifacts and temporary files Testing Infrastructure: - Backend: Vitest + Supertest for API integration tests - Frontend: Vitest + Testing Library for component tests - E2E: Playwright with Chromium for full browser automation - CI/CD: GitHub Actions with parallel test execution Security Improvements: - Make dataURL size limit configurable (default: 10MB) - Enhanced validation for image dataURLs - Block malicious content (javascript:, script tags) All tests pass: 41 total (22 backend + 11 frontend + 8 E2E) * feat(tests): add comprehensive E2E tests for dashboard workflows and image persistence chore(env): update environment variables for consistent API URL usage fix(api): centralize API request helpers for drawing and collection management style(DrawingCard): enhance accessibility with ARIA attributes and data-testid for testing * Add end-to-end tests for drawing CRUD, export/import, search/sort, and theme toggle functionalities - Implemented E2E tests for drawing creation, editing, and deletion in `drawing-crud.spec.ts`. - Added tests for export and import features, including JSON and SQLite formats in `export-import.spec.ts`. - Created tests for searching and sorting drawings by name and date in `search-and-sort.spec.ts`. - Developed tests for theme toggle functionality to ensure persistence across sessions in `theme-toggle.spec.ts`. * Update backend/src/__tests__/testUtils.ts --------- Co-authored-by: Zimeng Xiong <zxzimeng@gmail.com> * version bump 0.1.8 * fix(ci): consolidate E2E server startup to prevent shell isolation issues Background processes started with & in separate GitHub Actions run steps can terminate when those steps complete because each step creates a new shell. This caused the backend and frontend servers to die before the E2E tests could run. Fixed by consolidating server startup and test execution into a single shell step with: - Proper PID tracking for cleanup - Health check loops instead of fixed sleep times - All processes run in the same shell session * fix(ci): use absolute database path for E2E tests * fix(backend): use resolved DATABASE_URL path for export/import endpoints --------- Co-authored-by: Adrian Acala <adrianacala017@gmail.com>
This commit is contained in:
@@ -13,7 +13,6 @@ export const Settings: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { theme, toggleTheme } = useTheme();
|
||||
|
||||
// Import state
|
||||
const [importConfirmation, setImportConfirmation] = useState<{ isOpen: boolean; file: File | null }>({ isOpen: false, file: null });
|
||||
const [importError, setImportError] = useState<{ isOpen: boolean; message: string }>({ isOpen: false, message: '' });
|
||||
const [importSuccess, setImportSuccess] = useState(false);
|
||||
@@ -50,7 +49,6 @@ export const Settings: React.FC = () => {
|
||||
};
|
||||
|
||||
const handleSelectCollection = (id: string | null | undefined) => {
|
||||
// Navigate to dashboard with selected collection
|
||||
if (id === undefined) navigate('/');
|
||||
else if (id === null) navigate('/collections?id=unorganized');
|
||||
else navigate(`/collections?id=${id}`);
|
||||
@@ -61,7 +59,7 @@ export const Settings: React.FC = () => {
|
||||
return (
|
||||
<Layout
|
||||
collections={collections}
|
||||
selectedCollectionId="SETTINGS" // Special ID to highlight Settings in Sidebar if we add logic for it
|
||||
selectedCollectionId="SETTINGS"
|
||||
onSelectCollection={handleSelectCollection}
|
||||
onCreateCollection={handleCreateCollection}
|
||||
onEditCollection={handleEditCollection}
|
||||
@@ -72,7 +70,6 @@ export const Settings: React.FC = () => {
|
||||
</h1>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{/* Theme Toggle */}
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
className="flex flex-col items-center justify-center gap-4 p-8 bg-white dark:bg-neutral-900 border-2 border-black dark:border-neutral-700 rounded-2xl shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] dark:shadow-[4px_4px_0px_0px_rgba(255,255,255,0.2)] hover:shadow-[6px_6px_0px_0px_rgba(0,0,0,1)] dark:hover:shadow-[6px_6px_0px_0px_rgba(255,255,255,0.2)] hover:-translate-y-1 transition-all duration-200 group"
|
||||
@@ -94,7 +91,6 @@ export const Settings: React.FC = () => {
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* Export SQLite (.sqlite) */}
|
||||
<button
|
||||
onClick={() => window.location.href = `${api.API_URL}/export`}
|
||||
className="flex flex-col items-center justify-center gap-4 p-8 bg-white dark:bg-neutral-900 border-2 border-black dark:border-neutral-700 rounded-2xl shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] dark:shadow-[4px_4px_0px_0px_rgba(255,255,255,0.2)] hover:shadow-[6px_6px_0px_0px_rgba(0,0,0,1)] dark:hover:shadow-[6px_6px_0px_0px_rgba(255,255,255,0.2)] hover:-translate-y-1 transition-all duration-200 group"
|
||||
@@ -108,7 +104,6 @@ export const Settings: React.FC = () => {
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* Export SQLite (.db) */}
|
||||
<button
|
||||
onClick={() => window.location.href = `${api.API_URL}/export?format=db`}
|
||||
className="flex flex-col items-center justify-center gap-4 p-8 bg-white dark:bg-neutral-900 border-2 border-black dark:border-neutral-700 rounded-2xl shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] dark:shadow-[4px_4px_0px_0px_rgba(255,255,255,0.2)] hover:shadow-[6px_6px_0px_0px_rgba(0,0,0,1)] dark:hover:shadow-[6px_6px_0px_0px_rgba(255,255,255,0.2)] hover:-translate-y-1 transition-all duration-200 group"
|
||||
@@ -122,7 +117,6 @@ export const Settings: React.FC = () => {
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* Export JSON */}
|
||||
<button
|
||||
onClick={() => window.location.href = `${api.API_URL}/export/json`}
|
||||
className="flex flex-col items-center justify-center gap-4 p-8 bg-white dark:bg-neutral-900 border-2 border-black dark:border-neutral-700 rounded-2xl shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] dark:shadow-[4px_4px_0px_0px_rgba(255,255,255,0.2)] hover:shadow-[6px_6px_0px_0px_rgba(0,0,0,1)] dark:hover:shadow-[6px_6px_0px_0px_rgba(255,255,255,0.2)] hover:-translate-y-1 transition-all duration-200 group"
|
||||
@@ -136,7 +130,6 @@ export const Settings: React.FC = () => {
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* Import Data */}
|
||||
<div className="relative">
|
||||
<input
|
||||
type="file"
|
||||
@@ -183,7 +176,6 @@ export const Settings: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle Bulk Drawing Import
|
||||
const drawingFiles = files.filter(f => f.name.endsWith('.json') || f.name.endsWith('.excalidraw'));
|
||||
if (drawingFiles.length === 0) {
|
||||
setImportError({ isOpen: true, message: 'No supported files found.' });
|
||||
@@ -220,7 +212,6 @@ export const Settings: React.FC = () => {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Version Info */}
|
||||
<div className="flex flex-col items-center justify-center gap-4 p-8 bg-white dark:bg-neutral-900 border-2 border-black dark:border-neutral-700 rounded-2xl shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] dark:shadow-[4px_4px_0px_0px_rgba(255,255,255,0.2)]">
|
||||
<div className="w-16 h-16 bg-gray-50 dark:bg-neutral-800 rounded-2xl flex items-center justify-center border-2 border-gray-100 dark:border-neutral-700">
|
||||
<Info size={32} className="text-gray-600 dark:text-gray-400" />
|
||||
@@ -241,7 +232,6 @@ export const Settings: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Modals */}
|
||||
<ConfirmModal
|
||||
isOpen={importConfirmation.isOpen}
|
||||
title="Import Database"
|
||||
|
||||
Reference in New Issue
Block a user