This document defines the testing conventions and directory structure for the Tabularis project.
All utility functions and testable logic must be placed in src/utils/ with simple, descriptive names without the "Utils" suffix.
Correct:
src/utils/dataGrid.tssrc/utils/contextMenu.tssrc/utils/sqlGenerator.tssrc/utils/sql.ts
Incorrect:
(wrong location)src/components/ui/dataGridUtils.ts(wrong naming - no Utils suffix)src/utils/dataGridUtils.ts
All test files must be placed in a parallel tests/ directory that mirrors the structure of src/.
project-root/
├── src/
│ ├── utils/
│ │ ├── dataGrid.ts
│ │ ├── contextMenu.ts
│ │ └── sqlGenerator.ts
│ └── themes/
│ ├── colorUtils.ts
│ └── themeRegistry.ts
├── tests/
│ ├── setup.ts # Test setup file
│ ├── utils/
│ │ ├── dataGrid.test.ts
│ │ ├── contextMenu.test.ts
│ │ └── sqlGenerator.test.ts
│ └── themes/
│ ├── colorUtils.test.ts
│ └── themeRegistry.test.ts
Use standard relative or absolute imports:
// From a component
import { formatCellValue } from "../../utils/dataGrid";
// From another util
import { hexToRgb } from "./colorUtils";
// Using path alias
import { splitQueries } from "@/utils/sql";Always use relative imports from tests/ to src/:
// Correct - from tests/utils/dataGrid.test.ts
import { formatCellValue } from "../../src/utils/dataGrid";
// Correct - from tests/themes/colorUtils.test.ts
import { hexToRgb } from "../../src/themes/colorUtils";
// Incorrect - relative to same directory (would fail after move)
~~import { formatCellValue } from "./dataGrid";~~Test files must follow the pattern: [filename].test.ts
dataGrid.ts→dataGrid.test.tssqlGenerator.ts→sqlGenerator.test.ts
Extract pure, testable logic from components into src/utils/:
- Data transformation functions - formatters, parsers, converters
- Calculation functions - positioning, sorting, filtering logic
- Validation functions - input validation, sanitization
- SQL generators - query builders, schema generators
Before (in component):
// In DataGrid.tsx
const formatCellValue = (value: unknown): string => {
if (value === null) return "NULL";
if (typeof value === "boolean") return value ? "true" : "false";
return String(value);
};After (extracted):
// In src/utils/dataGrid.ts
export function formatCellValue(value: unknown, nullLabel = "NULL"): string {
if (value === null || value === undefined) return nullLabel;
if (typeof value === "boolean") return value ? "true" : "false";
if (typeof value === "object") return JSON.stringify(value);
return String(value);
}
// In DataGrid.tsx
import { formatCellValue } from "../../utils/dataGrid";Organize tests using describe blocks that mirror the structure of the module:
describe('dataGrid', () => {
describe('formatCellValue', () => {
it('should format null values', () => { ... });
it('should format boolean values', () => { ... });
});
describe('getColumnSortState', () => {
it('should detect ASC sort', () => { ... });
it('should detect DESC sort', () => { ... });
});
});Aim for comprehensive coverage of extracted utilities:
- All exported functions must have tests
- Edge cases must be covered (null, undefined, empty strings, boundary values)
- Error conditions should be tested where applicable
- Multiple database drivers should be tested for SQL generators
# Run all tests
pnpm test
# Run tests in watch mode
pnpm test --watch
# Run specific test file
pnpm test tests/utils/dataGrid.test.ts
# Run with coverage
pnpm test --coverageTests are configured in vitest.config.ts:
- Test files are discovered in
tests/directory - Setup file:
./tests/setup.ts - Environment:
jsdomfor DOM-related tests