-
Notifications
You must be signed in to change notification settings - Fork 3
Description
🧪 Testing Implementation
Description
Implement a pragmatic testing strategy focusing on critical functionality that provides the most value. We need tests that catch real bugs, not tests for the sake of coverage metrics.
Testing Philosophy
- Test behavior, not implementation details
- Focus on critical data operations
- Prioritize areas prone to regression
- Test edge cases and error handling
- Keep tests maintainable and fast
Phase 1: Critical Core Tests (High Priority)
1. Data Integrity Tests
Why: Prevent data corruption and loss (relates to Issue #11)
// tests/utils/fieldSupport.test.ts
describe('Field Support Detection', () => {
test('should correctly identify supported field types', () => {
expect(isFieldEditable({ type: 'string' })).toBe(true);
expect(isFieldEditable({ type: 'geometry' })).toBe(false);
});
test('should respect readonly fields', () => {
expect(isFieldEditable({
type: 'string',
meta: { readonly: true }
})).toBe(false);
});
test('should handle unknown field types safely', () => {
expect(isFieldEditable({ type: 'custom_unknown' })).toBe(false);
});
});2. API Operations Tests
Why: Core CRUD operations must work reliably
// tests/composables/api.test.ts
describe('API Operations', () => {
test('should correctly format update payload', () => {
const payload = formatUpdatePayload(field, value);
expect(payload).toHaveProperty(field.key);
expect(payload[field.key]).toBe(value);
});
test('should handle null values correctly', () => {
const payload = formatUpdatePayload(field, null);
expect(payload[field.key]).toBeNull();
});
test('should handle batch updates', async () => {
const updates = await batchUpdate(items, changes);
expect(updates).toHaveLength(items.length);
});
});3. Translation Field Tests
Why: Complex logic prone to bugs (Issues #8)
// tests/composables/useLanguageSelector.test.ts
describe('Language Selection', () => {
test('should detect existing languages for field', () => {
const fields = [
{ key: 'title:en-US' },
{ key: 'title:de-DE' }
];
const existing = getExistingLanguages('title', fields);
expect(existing).toContain('en-US');
expect(existing).toContain('de-DE');
expect(existing).not.toContain('fr-FR');
});
test('should filter out already selected languages', () => {
const available = getAvailableLanguages('title', fields);
expect(available).not.toContain('en-US');
expect(available).toContain('fr-FR');
});
});4. Filter & Search Tests
Why: Complex search logic with type detection
// tests/utils/search.test.ts
describe('Search Type Detection', () => {
test('should detect UUID search', () => {
const uuid = '123e4567-e89b-12d3-a456-426614174000';
expect(getSearchType(uuid)).toBe('uuid');
});
test('should detect numeric search', () => {
expect(getSearchType('123')).toBe('numeric');
expect(getSearchType('abc')).toBe('text');
});
test('should build correct filter for each type', () => {
const textFilter = buildSearchFilter('text', 'test');
expect(textFilter._icontains).toBe('test');
const uuidFilter = buildSearchFilter('uuid', uuid);
expect(uuidFilter._eq).toBe(uuid);
});
});Phase 2: UI Component Tests (Medium Priority)
5. Cell Renderer Tests
Why: Ensure data displays correctly
// tests/components/CellRenderers.test.ts
describe('Cell Renderers', () => {
test('ImageCell should handle missing images gracefully', () => {
const wrapper = mount(ImageCell, {
props: { value: null }
});
expect(wrapper.find('.placeholder').exists()).toBe(true);
});
test('StatusCell should apply correct color class', () => {
const wrapper = mount(StatusCell, {
props: { value: 'active', status: 'success' }
});
expect(wrapper.classes()).toContain('status-success');
});
});6. Inline Editor Tests
Why: Critical for data entry (Issues #5, #9, #10)
// tests/components/InlineEditPopover.test.ts
describe('Inline Edit Popover', () => {
test('should open for supported fields', async () => {
const field = { type: 'string', key: 'title' };
const wrapper = mount(InlineEditPopover, {
props: { field, value: 'test' }
});
await wrapper.trigger('click');
expect(wrapper.find('.editor').exists()).toBe(true);
});
test('should not open for unsupported fields', async () => {
const field = { type: 'geometry', key: 'location' };
const wrapper = mount(InlineEditPopover, {
props: { field, value: {} }
});
await wrapper.trigger('click');
expect(wrapper.find('.editor').exists()).toBe(false);
expect(wrapper.emitted('warning')).toBeTruthy();
});
});Phase 3: Integration Tests (Lower Priority)
7. Pagination Tests
// tests/composables/useTablePagination.test.ts
describe('Pagination', () => {
test('should calculate correct page ranges', () => {
const { startIndex, endIndex } = getPageRange(3, 25);
expect(startIndex).toBe(50);
expect(endIndex).toBe(75);
});
});8. Sort Tests
// tests/composables/useTableSort.test.ts
describe('Table Sorting', () => {
test('should toggle sort direction', () => {
const sort = { by: 'name', desc: false };
const newSort = toggleSort(sort, 'name');
expect(newSort.desc).toBe(true);
});
});Test Infrastructure
Setup Required
// package.json
{
"scripts": {
"test": "vitest",
"test:watch": "vitest --watch",
"test:coverage": "vitest --coverage",
"test:ui": "vitest --ui"
},
"devDependencies": {
"@vue/test-utils": "^2.4.0",
"@vitest/ui": "^1.0.0",
"vitest": "^1.0.0",
"happy-dom": "^12.0.0",
"@testing-library/vue": "^8.0.0"
}
}Test Configuration
// vitest.config.ts
import { defineConfig } from 'vitest/config';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
test: {
environment: 'happy-dom',
coverage: {
reporter: ['text', 'json', 'html'],
exclude: ['node_modules/', 'tests/']
}
}
});Testing Guidelines
What TO Test
✅ Business logic (calculations, transformations)
✅ Data mutations (ensure data isn't accidentally modified)
✅ Edge cases (null, undefined, empty arrays)
✅ Error handling (API failures, invalid inputs)
✅ Complex conditions (multi-language detection, field support)
What NOT to Test
❌ Directus internals (trust the framework)
❌ Simple getters/setters (no logic)
❌ CSS/Styling (visual regression tests later)
❌ Third-party libraries (they have their own tests)
❌ Trivial computed properties (unless complex)
Success Metrics
- Zero data corruption bugs in production
- 80% reduction in regression bugs
- Tests run in < 30 seconds
- New features include tests
- CI/CD pipeline with test gates
Implementation Priority
- Week 1: Field support & API tests (prevent data loss)
- Week 2: Translation & search tests (complex logic)
- Week 3: Component tests (user interactions)
- Week 4: Integration tests & CI setup
GitHub Actions Integration
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
- name: Install dependencies
run: pnpm install
- name: Run tests
run: pnpm test
- name: Upload coverage
uses: codecov/codecov-action@v3Note: This testing strategy focuses on preventing real bugs rather than achieving coverage metrics. Start with Phase 1 as these tests provide the most value for effort invested.