8.0 KiB
8.0 KiB
Testing Guide for Copper Tone Technologies
This document describes the testing strategy and implementation for the Copper Tone Technologies platform.
Testing Stack
Frontend Testing
- Unit Tests: Vitest + Vue Test Utils
- E2E Tests: Cypress
- Coverage: Configured for comprehensive test coverage reporting
Backend Testing
- Unit Tests: Go standard testing library (
testingpackage) - Integration Tests: Testing against real database with test fixtures
- Test Database: Separate database for testing (configured via environment)
Frontend Testing
Running Tests
cd frontend
# Run unit tests
npm run test:unit
# Run unit tests in watch mode
npm run test:unit -- --watch
# Run unit tests with coverage
npm run test:unit -- --coverage
# Run E2E tests (headless)
npm run test:e2e
# Run E2E tests (interactive)
npm run test:e2e:dev
Unit Test Structure
Unit tests are located in src/**/__tests__/ directories, co-located with the code they test.
Example: Store Test
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useAuthStore } from '../auth'
describe('Auth Store', () => {
beforeEach(() => {
setActivePinia(createPinia())
vi.clearAllMocks()
})
it('initializes with correct default state', () => {
const store = useAuthStore()
expect(store.user).toBeNull()
expect(store.token).toBeNull()
})
})
Example: Component Test
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import HelloWorld from '../HelloWorld.vue'
describe('HelloWorld', () => {
it('renders properly', () => {
const wrapper = mount(HelloWorld, { props: { msg: 'Hello' } })
expect(wrapper.text()).toContain('Hello')
})
})
E2E Test Structure
E2E tests are located in cypress/e2e/ directory.
Example: Authentication Flow Test
describe('Authentication Flow', () => {
it('can login with email and password', () => {
cy.intercept('POST', '**/login-email-password', {
statusCode: 200,
body: { token: 'mock-jwt-token' }
}).as('login')
cy.visit('/login')
cy.get('input[type="email"]').type('test@example.com')
cy.get('input[type="password"]').type('password123')
cy.get('button[type="submit"]').click()
cy.wait('@login')
cy.url().should('include', '/dashboard')
})
})
Test Coverage Goals
- Stores: 100% coverage (critical business logic)
- Components: 80%+ coverage
- Views: 70%+ coverage (covered by E2E)
- Utilities: 100% coverage
Backend Testing
Running Tests
cd backend/functions/<service-name>
# Run all tests
go test ./...
# Run tests with verbose output
go test -v ./...
# Run tests with coverage
go test -cover ./...
# Generate coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
Test Structure
Tests are in *_test.go files co-located with the code they test.
Example: Handler Test
func TestHandleRegisterEmailPassword(t *testing.T) {
// Setup test database
testDB := setupTestDB(t)
defer testDB.Close()
// Create test request
reqBody := RegisterEmailPasswordRequest{
Email: "test@example.com",
Password: "SecurePass123!",
Name: "Test User",
}
body, _ := json.Marshal(reqBody)
req := httptest.NewRequest("POST", "/register-email-password", bytes.NewReader(body))
w := httptest.NewRecorder()
// Execute handler
handleRegisterEmailPassword(w, req)
// Assert response
if w.Code != http.StatusCreated {
t.Errorf("Expected status 201, got %d", w.Code)
}
}
Example: Service Function Test
func TestVerifyEthereumSignature(t *testing.T) {
testCases := []struct {
name string
address string
message string
signature string
expected bool
}{
{
name: "valid signature",
address: "0x1234...",
message: "Test message",
signature: "0xabcd...",
expected: true,
},
{
name: "invalid signature",
address: "0x1234...",
message: "Test message",
signature: "0xinvalid",
expected: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := verifyEthereumSignature(tc.address, tc.message, tc.signature)
if result != tc.expected {
t.Errorf("Expected %v, got %v", tc.expected, result)
}
})
}
}
Test Coverage Goals
- Handlers: 90%+ coverage
- Business Logic: 100% coverage
- Utilities: 100% coverage
- Middleware: 95%+ coverage
CI/CD Integration
Gitea Actions Workflows
Tests are automatically run on:
- Pull requests to
develop - Commits to
develop,testing,main
Frontend Workflow (.gitea/workflows/frontend.yml):
- name: Run Unit Tests
run: |
cd frontend
npm run test:unit -- --run
- name: Run E2E Tests
run: |
cd frontend
npm run build
npm run test:e2e
Backend Workflow (.gitea/workflows/backend.yml):
- name: Run Tests
run: |
cd backend/functions/auth-service
go test -v -cover ./...
cd ../work-management-service
go test -v -cover ./...
cd ../payment-service
go test -v -cover ./...
Test Data & Fixtures
Frontend Test Data
Mock data for frontend tests is in src/**/__tests__/fixtures/:
export const mockUser = {
id: 1,
name: 'Test User',
email: 'test@example.com',
roles: ['CLIENT'],
createdAt: new Date().toISOString()
}
export const mockProjects = [
{ id: 1, name: 'Project Alpha', status: 'ACTIVE', ... },
{ id: 2, name: 'Project Beta', status: 'PLANNING', ... }
]
Backend Test Data
Test fixtures in testdata/ directories:
backend/functions/auth-service/
testdata/
users.json
identities.json
Best Practices
Frontend Testing
- Use Descriptive Test Names:
it('redirects to login when accessing protected route while unauthenticated') - Mock External Dependencies: Use
vi.mock()for API calls, localStorage, etc. - Test User Interactions: Focus on user behavior, not implementation details
- Avoid Testing Framework Internals: Don't test Vue Router, Pinia, etc. - test YOUR code
- Use Semantic Queries:
cy.contains('button', 'Login')instead of CSS selectors when possible
Backend Testing
- Use Table-Driven Tests: Test multiple scenarios with a single test function
- Test Error Paths: Don't just test happy path - test failures, edge cases
- Use Subtests:
t.Run(name, func(t *testing.T) { ... })for organized output - Clean Up Resources: Use
defer db.Close(),defer cleanup() - Isolate Tests: Each test should be independent and idempotent
Coverage Reports
Frontend Coverage
Generate HTML coverage report:
cd frontend
npm run test:unit -- --coverage
# Open coverage/index.html in browser
Backend Coverage
Generate HTML coverage report:
cd backend/functions/auth-service
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# Open coverage.html in browser
Continuous Improvement
- Review Coverage Weekly: Identify untested code paths
- Add Tests for Bug Fixes: Every bug fix should include a regression test
- Update E2E Tests: When adding new features, add corresponding E2E tests
- Performance Testing: Monitor test execution time, keep tests fast
- Flaky Tests: Fix or remove tests that intermittently fail