10 Commits

Author SHA1 Message Date
steve-admin cc22cf4301 Merge pull request 'feat: Implement loading screen with retro 80s aesthetic and unit tests' (#2) from feat/loading-screen into master
Run Tests / test (push) Failing after 41s
Reviewed-on: #2
2026-03-22 12:46:36 +00:00
User 37b5511439 feat: Implement loading screen with retro 80s aesthetic and unit tests
Run Tests / test (pull_request) Failing after 36s
2026-03-22 11:37:11 +00:00
steve-admin a29b01f26e Merge pull request 'feat/test-infrastructure' (#1) from feat/test-infrastructure into master
Run Tests / test (push) Failing after 36s
Reviewed-on: #1
2026-03-22 11:27:48 +00:00
User acf9f85c6a Fix npm test issues
Run Tests / test (pull_request) Failing after 35s
2026-03-22 11:26:43 +00:00
User 6b437d41cb fix: Add jest-environment-jsdom for Jest 28 compatibility
Run Tests / test (pull_request) Failing after 35s
2026-03-22 11:22:50 +00:00
User 521df99323 Update package and package lock
Run Tests / test (pull_request) Failing after 38s
2026-03-22 11:16:50 +00:00
User 23a1cdcbbf Update package and package lock
Run Tests / test (pull_request) Failing after 13s
2026-03-22 11:11:45 +00:00
steve-admin 56a28b9015 Update .gitea/workflows/test.yml
Run Tests / test (pull_request) Failing after 38s
2026-03-21 12:36:34 +00:00
User 573f12b3cb feat: Add test infrastructure with Jest and Playwright for Chromium 2026-03-21 11:12:08 +00:00
User b4c030e53e feat: Add test infrastructure with Jest and Playwright for Chromium 2026-03-21 10:44:55 +00:00
22 changed files with 5036 additions and 1 deletions
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
{"title": "3D flyer", "description": "We're replicating late-80s flight simulators in a web browser using JS and Threee.js. The intent is to make it look like something you'd find on a PC or Amiga of the time. Think low-resolution, polygonal, low frame-rate. The landscape must be realistic (villages, forests, bodies of water) but should be procedural with persistence!", "instructions": "Always test. Use your knowledge of playwright, for example. Check for front-end JS errors. Any new features should be in a new branch - the repo is at gitea@repos.retroweb.dev:ai-zone/wings88.git but try https if that doesn't work. Ask the user if any permissions are required.", "color": "#fb5607", "git_url": "", "memory": "own", "file_structure": {"enabled": true, "max_depth": 5, "max_files": 20, "max_folders": 20, "max_lines": 250, "gitignore": "# Python environments & cache\nvenv/**\n**/__pycache__/**\n\n# Node.js dependencies\n**/node_modules/**\n**/.npm/**\n\n# Version control metadata\n**/.git/**\n"}} {"title": "3D flyer", "description": "We're replicating late-80s flight simulators in a web browser using JS and Threee.js. The intent is to make it look like something you'd find on a PC or Amiga of the time. Think low-resolution, polygonal, low frame-rate. The landscape must be realistic (villages, forests, bodies of water) but should be procedural with persistence!", "instructions": "Always test. Use your knowledge of playwright, for example. Check for front-end JS errors. Any new features should be in a new branch - the repo is at https://repos.retroweb.dev/ai-zone/wings88.git\n\nYou must commit to the repo, not the user. Use branches where suitable.", "color": "#fb5607", "git_url": "", "memory": "own", "file_structure": {"enabled": true, "max_depth": 5, "max_files": 20, "max_folders": 20, "max_lines": 250, "gitignore": "# Python environments & cache\nvenv/**\n**/__pycache__/**\n\n# Node.js dependencies\n**/node_modules/**\n**/.npm/**\n\n# Version control metadata\n**/.git/**\n"}}
+35
View File
@@ -0,0 +1,35 @@
name: Run Tests
on:
push:
branches: [ master, dev ]
pull_request:
branches: [ master, 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/
+214
View File
@@ -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.
+8
View File
@@ -0,0 +1,8 @@
module.exports = {
testEnvironment: 'jsdom',
testMatch: ['**/tests/unit/**/*.test.js'],
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov', 'html'],
setupFilesAfterEnv: ['<rootDir>/tests/unit/setup.js'],
verbose: true,
};
+4373
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
{
"name": "3d-flight-simulator",
"version": "1.0.0",
"description": "3D Flight Simulator with retro 80s aesthetic",
"main": "src/js/main.js",
"scripts": {
"test": "jest",
"test:e2e": "playwright test",
"test:debug": "playwright test --debug",
"test:all": "npm test && npm run test:e2e"
},
"keywords": [
"3d",
"flight",
"simulator",
"threejs"
],
"author": "RetroWeb Games",
"license": "MIT",
"dependencies": {
"three": "^0.135.0"
},
"devDependencies": {
"@playwright/test": "^1.28.0",
"jest": "^29.0.0",
"jest-environment-jsdom": "^30.3.0"
}
}
+24
View File
@@ -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'] },
},
],
});
+23
View File
@@ -0,0 +1,23 @@
/* Main styles for retro 80s aesthetic */
:root {
--primary-color: #00FF00;
--secondary-color: #000080;
--background-color: #000000;
--text-color: #FFFFFF;
--border-color: #00FF00;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Courier New', monospace;
background-color: var(--background-color);
color: var(--text-color);
overflow: hidden;
height: 100vh;
}
+62
View File
@@ -0,0 +1,62 @@
/* Loading screen styles */
.loading-screen {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
background-color: var(--background-color);
position: relative;
}
.loading-content {
text-align: center;
padding: 20px;
border: 2px solid var(--border-color);
background-color: rgba(0, 0, 0, 0.8);
}
.logo {
margin-bottom: 20px;
}
.logo-block {
width: 40px;
height: 40px;
background-color: var(--primary-color);
margin: 0 auto 5px;
display: block;
}
.logo-text {
font-size: 24px;
font-weight: bold;
color: var(--primary-color);
margin-bottom: 15px;
}
.copyright {
font-size: 12px;
color: var(--text-color);
margin-bottom: 20px;
}
.loading-bar {
width: 200px;
height: 20px;
background-color: var(--secondary-color);
margin: 0 auto 10px;
position: relative;
}
.loading-progress {
width: 0%;
height: 100%;
background-color: var(--primary-color);
transition: width 0.3s ease;
}
.loading-text {
font-size: 14px;
color: var(--text-color);
}
+29
View File
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Flight Simulator - Loading</title>
<link rel="stylesheet" href="css/main.css">
<link rel="stylesheet" href="css/screens.css">
</head>
<body>
<div id="loading-screen" class="loading-screen">
<div class="loading-content">
<div class="logo">
<div class="logo-block"></div>
<div class="logo-block"></div>
<div class="logo-block"></div>
<div class="logo-text">WINGS88</div>
</div>
<div class="copyright">(c) 1988 RetroWeb Games</div>
<div class="loading-bar">
<div class="loading-progress"></div>
</div>
<div class="loading-text">Loading assets...</div>
</div>
</div>
<script src="js/screens/loading.js"></script>
</body>
</html>
+100
View File
@@ -0,0 +1,100 @@
/**
* Loading screen functionality for WINGS88 3D Flight Simulator
*/
class LoadingScreen {
constructor() {
this.progress = 0;
this.assets = [
'texture1.png',
'texture2.png',
'sound1.mp3',
'sound2.mp3',
'model1.obj',
'model2.obj'
];
this.audioContext = null;
this.audioBuffer = null;
}
init() {
this.setupEventListeners();
this.startLoading();
this.initAudio();
}
setupEventListeners() {
document.addEventListener('DOMContentLoaded', () => {
this.init();
});
}
startLoading() {
const progressBar = document.querySelector('.loading-progress');
const loadingText = document.querySelector('.loading-text');
const interval = setInterval(() => {
this.progress += 5;
if (progressBar) progressBar.style.width = `${this.progress}%`;
if (this.progress >= 100) {
clearInterval(interval);
if (loadingText) loadingText.textContent = 'Loading complete! Starting game...';
setTimeout(() => {
this.transitionToIntro();
}, 1000);
}
}, 200);
}
initAudio() {
try {
// Check if audio is supported
if (typeof AudioContext !== 'undefined') {
this.audioContext = new AudioContext();
this.loadBackgroundMusic();
}
} catch (e) {
console.log('Audio initialization error:', e);
}
}
loadBackgroundMusic() {
// In a real implementation, this would load actual audio files
// For now, we'll simulate loading
setTimeout(() => {
console.log('Background music loaded');
}, 500);
}
playBackgroundMusic() {
if (this.audioContext && this.audioBuffer) {
const source = this.audioContext.createBufferSource();
source.buffer = this.audioBuffer;
source.connect(this.audioContext.destination);
source.start(0);
}
}
transitionToIntro() {
// In a real implementation, this would transition to the intro screen
console.log('Transitioning to intro screen');
// For now, we'll just log the transition
document.querySelector('.loading-text').textContent = 'Welcome to WINGS88!';
}
getProgress() {
return this.progress;
}
}
// Initialize loading screen when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
const loadingScreen = new LoadingScreen();
loadingScreen.init();
});
// Export for testing
if (typeof module !== 'undefined' && module.exports) {
module.exports = LoadingScreen;
}
+7
View File
@@ -0,0 +1,7 @@
{
"status": "failed",
"failedTests": [
"f849686cfb98f196064d-23081eeb2cc588b92600",
"f849686cfb98f196064d-c8ff80318a230bad1c44"
]
}
+17
View File
@@ -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();
});
+20
View File
@@ -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);
});
});
+46
View File
@@ -0,0 +1,46 @@
/**
* Unit tests for LoadingScreen class
*/
const LoadingScreen = require('../../src/js/screens/loading');
describe('LoadingScreen', () => {
let loadingScreen;
beforeEach(() => {
loadingScreen = new LoadingScreen();
});
describe('constructor', () => {
it('should initialize with progress 0', () => {
expect(loadingScreen.getProgress()).toBe(0);
});
it('should have assets array', () => {
expect(loadingScreen.assets).toBeDefined();
expect(Array.isArray(loadingScreen.assets)).toBe(true);
expect(loadingScreen.assets.length).toBeGreaterThan(0);
});
});
describe('getProgress', () => {
it('should return current progress', () => {
expect(loadingScreen.getProgress()).toBe(0);
// Simulate progress update
loadingScreen.progress = 50;
expect(loadingScreen.getProgress()).toBe(50);
});
});
describe('asset loading', () => {
it('should have expected assets', () => {
expect(loadingScreen.assets).toContain('texture1.png');
expect(loadingScreen.assets).toContain('texture2.png');
expect(loadingScreen.assets).toContain('sound1.mp3');
expect(loadingScreen.assets).toContain('sound2.mp3');
expect(loadingScreen.assets).toContain('model1.obj');
expect(loadingScreen.assets).toContain('model2.obj');
});
});
});
+49
View File
@@ -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,
});