Testing Guide for Gx ComponentKit
This document provides comprehensive information about testing the Gx ComponentKit component library.
Testing Stack
- Test Runner: Vitest - Fast unit test framework for Vite projects
- Vue Testing: @vue/test-utils - Official Vue.js testing utilities
- DOM Environment: happy-dom - Lightweight DOM implementation
- Coverage: c8 - Native V8 code coverage
- Mocking: Built-in Vitest mocking capabilities
Available Scripts
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests once (CI mode)
npm run test:run
# Run tests with coverage report
npm run test:coverage
# Run tests with UI interface
npm run test:ui
Test Structure
Directory Layout
src/
├── components/
│ ├── __tests__/
│ │ ├── GxModal.test.ts
│ │ ├── GxCountdown.test.ts
│ │ ├── GxThemeWrapper.test.ts
│ │ └── GxPageStart.test.ts
│ └── ...
├── composables/
│ ├── __tests__/
│ │ ├── useMedia.test.ts
│ │ └── useErrors.test.ts
│ └── ...
└── test/
├── setup.ts # Global test setup
├── test-utils.ts # Testing utilities
└── basic.test.ts # Basic functionality tests
Test Categories
1. Component Tests
Test Vue components in isolation with proper props, events, and rendering.
Example: GxThemeWrapper
import { mount } from '@vue/test-utils'
import GxThemeWrapper from '../GxThemeWrapper.vue'
describe('GxThemeWrapper', () => {
it('applies theme colors correctly', () => {
const wrapper = mount(GxThemeWrapper, {
props: {
theme: {
background_color: '#ffffff',
text_color: '#333333'
}
}
})
const element = wrapper.element as HTMLElement
expect(element.style.backgroundColor).toBe('#ffffff')
expect(element.style.color).toBe('#333333')
})
})
2. Composable Tests
Test Vue composables for state management and business logic.
Example: useErrors
import { useErrors } from '../useErrors'
describe('useErrors', () => {
it('manages error state correctly', () => {
const errors = useErrors()
errors.addError('Test error')
expect(errors.errorMessages.value).toEqual(['Test error'])
expect(errors.hasErrors.value).toBe(true)
errors.clearErrors()
expect(errors.hasErrors.value).toBe(false)
})
})
3. Integration Tests
Test component interactions and complex workflows.
4. Utility Tests
Test helper functions and utilities.
Testing Patterns
1. Component Testing Patterns
Basic Rendering
it('renders correctly', () => {
const wrapper = mount(Component)
expect(wrapper.exists()).toBe(true)
})
Props Testing
it('accepts and uses props correctly', () => {
const wrapper = mount(Component, {
props: { title: 'Test Title' }
})
expect(wrapper.text()).toContain('Test Title')
})
Event Testing
it('emits events correctly', async () => {
const wrapper = mount(Component)
await wrapper.find('button').trigger('click')
expect(wrapper.emitted('click')).toBeTruthy()
})
Slot Testing
it('renders slot content', () => {
const wrapper = mount(Component, {
slots: {
default: '<div class="test-content">Slot Content</div>'
}
})
expect(wrapper.find('.test-content').exists()).toBe(true)
})
2. Async Testing Patterns
Timer Testing
import { vi } from 'vitest'
beforeEach(() => {
vi.useFakeTimers()
})
afterEach(() => {
vi.useRealTimers()
})
it('handles timers correctly', async () => {
const wrapper = mount(CountdownComponent, {
props: { duration: 5 }
})
vi.advanceTimersByTime(1000)
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('4')
})
Promise Testing
it('handles async operations', async () => {
const mockPromise = Promise.resolve('result')
const wrapper = mount(Component)
await wrapper.vm.asyncMethod()
expect(wrapper.vm.result).toBe('result')
})
3. Mocking Patterns
API Mocking
import { vi } from 'vitest'
const mockApi = {
getData: vi.fn().mockResolvedValue({ data: 'test' })
}
vi.mock('@/api', () => ({
default: mockApi
}))
Browser API Mocking
// Mock getUserMedia for camera tests
Object.defineProperty(navigator, 'mediaDevices', {
writable: true,
value: {
getUserMedia: vi.fn().mockResolvedValue(mockStream)
}
})
Test Utilities
Custom Mount Helper
// src/test/test-utils.ts
export function mountWithProps(
component: Component,
additionalProps: Record<string, any> = {},
options: Record<string, any> = {}
) {
const defaultProps = {
theme: mockTheme,
pluginVars: mockPluginVars,
// ... other common props
}
return mount(component, {
props: { ...defaultProps, ...additionalProps },
...options,
})
}
Mock Data
export const mockTheme = {
background_color: '#ffffff',
text_color: '#333333',
primary_color: '#007bff',
}
export const mockPluginVars = {
primary_color: '#007bff',
projectId: 123,
apiBaseUrl: 'https://api.test.com',
}
Coverage Requirements
Target Coverage Levels
- Statements: 90%+
- Branches: 85%+
- Functions: 90%+
- Lines: 90%+
Coverage Reports
# Generate coverage report
npm run test:coverage
# View HTML coverage report
open coverage/index.html
Coverage Configuration
Coverage is configured in vitest.config.ts:
export default defineConfig({
test: {
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
exclude: [
'node_modules/',
'src/test/',
'**/*.d.ts',
'dist/',
],
thresholds: {
statements: 90,
branches: 85,
functions: 90,
lines: 90
}
},
},
})
Best Practices
1. Test Organization
- Group related tests using
describeblocks - Use descriptive test names that explain the expected behavior
- Follow the AAA pattern: Arrange, Act, Assert
2. Test Independence
- Each test should be independent and not rely on other tests
- Use
beforeEachandafterEachfor setup and cleanup - Reset mocks between tests
3. Mock Strategy
- Mock external dependencies (APIs, browser APIs)
- Don't mock the code you're testing
- Use realistic mock data
4. Async Testing
- Always await async operations
- Use fake timers for time-dependent tests
- Handle promise rejections properly
5. Component Testing
- Test behavior, not implementation details
- Focus on user interactions and expected outcomes
- Test edge cases and error conditions
Debugging Tests
Running Specific Tests
# Run specific test file
npm run test:run src/components/__tests__/GxModal.test.ts
# Run tests matching pattern
npm run test:run -- --grep "modal"
# Run tests in specific directory
npm run test:run src/components/__tests__/
Debug Mode
# Run tests with debug output
npm run test:run -- --reporter=verbose
# Run tests in watch mode for development
npm run test:watch
VS Code Integration
Add to .vscode/settings.json:
{
"vitest.enable": true,
"vitest.commandLine": "npm run test"
}
Continuous Integration
GitHub Actions Example
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci
- run: npm run test:coverage
- uses: codecov/codecov-action@v3
Common Issues and Solutions
1. Component Not Rendering
Problem: Component wrapper is empty Solution: Check if all required props are provided
2. Async Test Failures
Problem: Tests fail intermittently Solution: Ensure proper awaiting of async operations
3. Mock Not Working
Problem: Mock functions not being called Solution: Verify mock is set up before component mount
4. Timer Tests Failing
Problem: Timer-based tests are flaky
Solution: Use vi.useFakeTimers() and vi.advanceTimersByTime()
Contributing
When adding new components or features:
- Write tests alongside your code
- Aim for high test coverage
- Include both happy path and edge case tests
- Update this documentation if adding new testing patterns
- Run the full test suite before submitting PRs