diff --git a/.gitea/workflows/test.yml b/.gitea/workflows/test.yml new file mode 100644 index 0000000..c1fd493 --- /dev/null +++ b/.gitea/workflows/test.yml @@ -0,0 +1,35 @@ +name: Run Tests + +on: + push: + branches: [ main, dev ] + pull_request: + branches: [ main, dev ] + +jobs: + test: + runs-on: ubuntu-latest + container: node:18 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install dependencies + run: npm ci + + - name: Install Playwright browsers + run: npx playwright install --with-deps chromium + + - name: Run unit tests + run: npm test + + - name: Run Playwright tests + run: npx playwright test + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v3 + with: + name: test-results + path: test-results/ diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 0000000..5b89183 --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,214 @@ +# Testing Guide + +This document provides information on how to run tests for the 3D Flight Simulator project. + +## ๐Ÿงช Test Structure + +The project uses a combination of unit tests and end-to-end tests: + +``` +tests/ +โ”œโ”€โ”€ unit/ # Unit tests (Jest) +โ”‚ โ””โ”€โ”€ *.test.js # Test files +โ””โ”€โ”€ integration/ # Integration tests (Playwright) + โ””โ”€โ”€ *.spec.js # Test files +``` + +## ๐Ÿš€ Running Tests + +### Prerequisites + +- Node.js (v16 or higher) +- npm or yarn +- Playwright browsers (installed automatically when running tests) + +### Running Unit Tests + +To run unit tests using Jest: + +```bash +# Run all unit tests +npm test + +# Run unit tests in watch mode +npm test -- --watch + +# Run specific test file +npm test -- tests/unit/example.test.js + +# Run tests with coverage +npm test -- --coverage +``` + +### Running Playwright Tests + +To run end-to-end tests using Playwright: + +```bash +# Run all Playwright tests +npm run test:e2e + +# Run tests in headed mode (visible browser) +npx playwright test --headed + +# Run tests for specific browser +npx playwright test --project=chromium + +# Run specific test file +npx playwright test tests/integration/example.spec.js + +# Run tests in debug mode +npm run test:debug +``` + +### Running All Tests + +To run both unit and Playwright tests: + +```bash +npm run test:all +``` + +## ๐Ÿ“ Writing Tests + +### Unit Tests + +Unit tests are written using Jest and should test individual functions or components in isolation. + +**Example:** + +```javascript +// tests/unit/math.test.js +describe('Math utilities', () => { + it('should add two numbers', () => { + const result = add(2, 3); + expect(result).toBe(5); + }); +}); +``` + +### Playwright Tests + +Playwright tests are written using the Playwright Test Runner and should test user interactions and page behavior. + +**Example:** + +```javascript +// tests/integration/loading-screen.spec.js +const { test, expect } = require('@playwright/test'); + +test('should display loading screen', async ({ page }) => { + await page.goto('/'); + await expect(page).toHaveTitle(/3D Flight Simulator/); + await expect(page.locator('.loading-screen')).toBeVisible(); +}); +``` + +## ๐Ÿ”ง Test Configuration + +### Jest Configuration + +The Jest configuration is located in `jest.config.js`. Key settings: + +- `testEnvironment`: 'node' (for backend tests) +- `testMatch`: '**/tests/unit/**/*.test.js' +- `coverageDirectory`: 'coverage' + +### Playwright Configuration + +The Playwright configuration is located in `playwright.config.js`. Key settings: + +- `testDir`: './tests' +- `use`: { `baseURL`: 'http://localhost:3000' } +- `projects`: [chromium] (default browser) + +## ๐Ÿ“Š Test Reports + +### Jest Reports + +Jest generates reports in the following formats: + +- Text summary (console output) +- LCOV format (for coverage tools) +- HTML coverage report (in `coverage/lcov-report/index.html`) + +### Playwright Reports + +Playwright generates the following reports: + +- Test results (console output) +- Trace files (for failed tests) +- Video recordings (for failed tests) +- Screenshots (for failed tests) + +To view Playwright reports: + +```bash +# View last test report +npx playwright show-report + +# View trace for specific test +npx playwright show-trace trace/trace.zip +``` + +## ๐Ÿค– Continuous Integration + +The project uses Gitea Actions for continuous integration. The workflow is defined in: + +`.gitea/workflows/test.yml` + +This workflow runs on: +- Push events to `main` and `dev` branches +- Pull request events targeting `main` and `dev` branches + +The workflow performs the following steps: +1. Checkout code +2. Install dependencies +3. Install Playwright browsers +4. Run unit tests +5. Run Playwright tests +6. Upload test artifacts (if tests fail) + +## ๐Ÿ’ก Best Practices + +1. **Test Naming**: Use descriptive test names that explain what is being tested +2. **Test Organization**: Group related tests in the same test file +3. **Test Isolation**: Ensure tests don't depend on each other +4. **Test Coverage**: Aim for high coverage, especially for critical paths +5. **Test Data**: Use realistic test data that matches production scenarios +6. **Test Performance**: Keep tests fast to encourage running them frequently + +## ๐Ÿ› Debugging Tests + +### Debugging Unit Tests + +```bash +# Run tests in debug mode +npm test -- --debug + +# Run specific test in debug mode +npm test -- --testNamePattern="should add two numbers" --debug +``` + +### Debugging Playwright Tests + +```bash +# Run tests in debug mode +npm run test:debug + +# Pause on first test failure +npx playwright test --debug + +# Use Chrome DevTools +npx playwright test --headed +``` + +## ๐Ÿ“ž Support + +If you encounter issues with the test infrastructure, please: +1. Check the test output for error messages +2. Verify that all dependencies are installed +3. Ensure your Node.js version is compatible +4. Review the test configuration files + +For questions or issues, please open an issue in the repository. diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..fb49678 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + testEnvironment: 'node', + testMatch: ['**/tests/unit/**/*.test.js'], + coverageDirectory: 'coverage', + coverageReporters: ['text', 'lcov', 'html'], + setupFilesAfterEnv: ['/tests/unit/setup.js'], + verbose: true, +}; diff --git a/playwright.config.js b/playwright.config.js new file mode 100644 index 0000000..0f5b6ab --- /dev/null +++ b/playwright.config.js @@ -0,0 +1,24 @@ +const { defineConfig, devices } = require('@playwright/test'); + +module.exports = defineConfig({ + testDir: './tests', + timeout: 30000, + expect: { + timeout: 5000, + }, + fullyParallel: true, + workers: 1, + retries: 1, + reporter: 'list', + use: { + baseURL: 'http://localhost:3000', + trace: 'on-first-retry', + video: 'on-first-retry', + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chromium'] }, + }, + ], +}); diff --git a/tests/integration/example.spec.js b/tests/integration/example.spec.js new file mode 100644 index 0000000..86f3360 --- /dev/null +++ b/tests/integration/example.spec.js @@ -0,0 +1,17 @@ +/** + * Example Playwright tests for the 3D Flight Simulator project + */ + +const { test, expect } = require('@playwright/test'); + +test('should display loading screen', async ({ page }) => { + await page.goto('/'); + await expect(page).toHaveTitle(/3D Flight Simulator/); + await expect(page.locator('.loading-screen')).toBeVisible(); +}); + +test('should navigate to intro screen', async ({ page }) => { + await page.goto('/'); + await page.click('.start-button'); + await expect(page.locator('.intro-screen')).toBeVisible(); +}); diff --git a/tests/unit/example.test.js b/tests/unit/example.test.js new file mode 100644 index 0000000..494a666 --- /dev/null +++ b/tests/unit/example.test.js @@ -0,0 +1,20 @@ +/** + * Example unit tests for the 3D Flight Simulator project + */ + +describe('Math utilities', () => { + it('should add two numbers', () => { + const result = 2 + 3; + expect(result).toBe(5); + }); + + it('should subtract two numbers', () => { + const result = 5 - 2; + expect(result).toBe(3); + }); + + it('should multiply two numbers', () => { + const result = 3 * 4; + expect(result).toBe(12); + }); +}); diff --git a/tests/unit/setup.js b/tests/unit/setup.js new file mode 100644 index 0000000..b2deef2 --- /dev/null +++ b/tests/unit/setup.js @@ -0,0 +1,49 @@ +/** + * Jest setup file + * This file runs before any tests are executed + */ + +// Add any global setup here +// For example: mocking global objects, setting up test environment, etc. + +// Example: Mock localStorage +const localStorageMock = (() => { + let store = {}; + return { + getItem: (key) => store[key] || null, + setItem: (key, value) => { + store[key] = value.toString(); + }, + removeItem: (key) => { + delete store[key]; + }, + clear: () => { + store = {}; + }, + }; +})(); + +Object.defineProperty(window, 'localStorage', { + value: localStorageMock, +}); + +// Example: Mock sessionStorage +const sessionStorageMock = (() => { + let store = {}; + return { + getItem: (key) => store[key] || null, + setItem: (key, value) => { + store[key] = value.toString(); + }, + removeItem: (key) => { + delete store[key]; + }, + clear: () => { + store = {}; + }, + }; +})(); + +Object.defineProperty(window, 'sessionStorage', { + value: sessionStorageMock, +});