- Backend: pytest with unit tests (auth, rbac, config) and integration tests (auth flow, docker, files) - Frontend: vitest with unit tests (api client) and component tests (login) - CI: Gitea Actions workflow for automated testing with coverage reports - Documentation: TESTING.md guide with setup, usage, and best practices - Coverage goals: 80%+ backend, 70%+ frontend
7.1 KiB
Testing Guide
This document describes how to run and write tests for the NAS Dashboard project.
Overview
The project has comprehensive test coverage for both backend (Python/FastAPI) and frontend (Svelte 5):
- Backend: pytest with unit and integration tests
- Frontend: Vitest with unit and component tests
- CI: Automated testing via Gitea Actions
Backend Testing
Setup
cd dashboard/backend
pip install -r requirements.txt
pip install -r requirements-dev.txt
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=. --cov-report=term --cov-report=html
# Run only unit tests
pytest tests/unit/ -v
# Run only integration tests
pytest tests/integration/ -v
# Run specific test file
pytest tests/unit/test_auth.py -v
# Run specific test
pytest tests/unit/test_auth.py::TestPasswordHashing::test_hash_and_verify_password -v
Test Structure
dashboard/backend/tests/
├── conftest.py # Shared fixtures
├── unit/
│ ├── test_auth.py # JWT, TOTP, password hashing
│ ├── test_rbac.py # Role-based access control
│ └── test_config.py # IP parsing, env validation
└── integration/
├── test_auth_flow.py # Login, refresh, logout flows
├── test_docker.py # Container operations
└── test_files.py # File operations
Key Fixtures
mock_config: Mocked configuration with test valuestemp_auth_file: Temporary auth.json for testingtemp_rbac_file: Temporary rbac.json for testingvalid_access_token: Valid JWT access tokenadmin_headers: Headers with admin authenticationmock_docker_client: Mocked Docker SDK client
Writing Tests
Example unit test:
def test_hash_and_verify_password(self):
"""Test that password hashing and verification works."""
password = "test_password_123"
hashed = get_password_hash(password)
assert hashed != password
assert verify_password(password, hashed)
Example integration test:
def test_login_success_no_2fa(self, test_app, mock_config, temp_auth_file):
"""Test successful login without 2FA."""
password = "test_password"
hashed = get_password_hash(password)
save_password_hash(hashed)
response = test_app.post(
"/api/auth/login",
json={"username": "testadmin", "password": password, "totp_code": ""}
)
assert response.status_code == 200
assert response.json()["user"] == "testadmin"
Frontend Testing
Setup
cd dashboard/frontend
npm install
Running Tests
# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Run in watch mode
npm test -- --watch
# Run specific test file
npm test -- tests/unit/api.test.js
# Run with UI
npm run test:ui
Test Structure
dashboard/frontend/tests/
├── setup.js # Global test setup
├── unit/
│ └── api.test.js # API client tests
├── components/
│ └── Login.test.js # Login component tests
└── integration/
└── (future tests)
Mocked APIs
The test setup (tests/setup.js) provides mocks for:
fetch- HTTP requestsWebSocket- WebSocket connectionsSpeechRecognition/speechSynthesis- Web Speech APInavigator.credentials- WebAuthnlocalStorage- Local storageResizeObserver- Resize observerMutationObserver- Mutation observer
Writing Tests
Example unit test:
it('should set and get token', () => {
setToken('test-token-123');
expect(getToken()).toBe('test-token-123');
});
Example component test:
it('should render login form', () => {
render(Login);
expect(screen.getByLabelText(/username/i)).toBeTruthy();
expect(screen.getByLabelText(/password/i)).toBeTruthy();
});
Coverage Goals
- Backend: 80%+ overall, 95%+ for critical paths (auth, RBAC)
- Frontend: 70%+ overall, 80%+ for critical components
CI Integration
Tests run automatically on:
- Push to
mainbranch - Pull requests to
main
The CI workflow (.gitea/workflows/test.yml) runs:
- Backend unit tests
- Backend integration tests
- Frontend tests with coverage
- Uploads coverage reports as artifacts
Viewing CI Results
- Go to the Gitea repository
- Click on "Actions" tab
- Select the workflow run
- Download coverage artifacts
Common Issues
Backend Tests
Issue: ModuleNotFoundError: No module named 'fastapi'
Solution: Install dependencies: pip install -r requirements.txt -r requirements-dev.txt
Issue: RuntimeError: SECRET_KEY must be set
Solution: Tests use mocked config, ensure conftest.py is loaded
Issue: Permission denied on temp files
Solution: Check that /tmp is writable
Frontend Tests
Issue: Cannot find module '@testing-library/svelte'
Solution: Install dependencies: npm install
Issue: ReferenceError: WebSocket is not defined
Solution: Ensure tests/setup.js is loaded (check vitest.config.js)
Issue: Component tests fail with Svelte 5 runes
Solution: Use @testing-library/svelte v5.2.3+ which supports Svelte 5
Best Practices
Backend
- Use fixtures: Leverage shared fixtures from
conftest.py - Mock external services: Always mock Docker, SSH, HTTP clients
- Test edge cases: Invalid inputs, expired tokens, permission errors
- Atomic tests: Each test should be independent
- Clear test names: Use descriptive names that explain what's being tested
Frontend
- Test behavior, not implementation: Focus on user interactions
- Mock API calls: Use
vi.fn()to mock fetch responses - Test accessibility: Use
getByRole,getByLabelTextfrom testing-library - Avoid testing internal state: Test what the user sees
- Keep tests simple: One assertion per test when possible
Debugging Tests
Backend
# Run with verbose output
pytest -vv
# Run with print statements visible
pytest -s
# Run with debugger on failure
pytest --pdb
# Run specific test with full output
pytest tests/unit/test_auth.py::TestPasswordHashing -vv -s
Frontend
# Run with verbose output
npm test -- --reporter=verbose
# Run in UI mode for debugging
npm run test:ui
# Run single test file in watch mode
npm test -- tests/unit/api.test.js --watch
Adding New Tests
Backend
- Create test file in appropriate directory (
tests/unit/ortests/integration/) - Import necessary fixtures from
conftest.py - Write test classes and methods
- Run tests to verify
Frontend
- Create test file in appropriate directory (
tests/unit/,tests/components/, ortests/integration/) - Import necessary mocks and utilities
- Write test cases using
describeandit - Run tests to verify