Update application ports to 3050 and enhance Playwright tests with WebGL mock
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(npm test:*)",
|
||||
"Bash(npm run:*)",
|
||||
"Bash(npx playwright:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
# Copilot Instructions for line-of-sight
|
||||
|
||||
## Purpose
|
||||
This repository is a full-stack geospatial app:
|
||||
- `frontend/`: React + Vite + MapLibre UI
|
||||
- `backend/`: Express API with PostGIS queries
|
||||
- `docker/` and `docker-compose.yml`: local orchestration and DB initialization
|
||||
|
||||
Prefer small, focused changes that keep frontend/backend contracts stable.
|
||||
|
||||
## First Commands to Know
|
||||
Use these commands first when validating changes.
|
||||
|
||||
### Docker-first workflow (preferred)
|
||||
- Start stack: `docker-compose up --build`
|
||||
- Stop stack: `docker-compose down`
|
||||
- Backend tests: `docker-compose exec backend npm test`
|
||||
- Frontend unit tests: `docker-compose exec frontend npm test -- --run`
|
||||
- Frontend E2E tests: `docker-compose exec frontend npm run test:e2e`
|
||||
- Seed geodata: `docker-compose exec backend npm run seed-data`
|
||||
|
||||
### Local workflow (without Docker)
|
||||
- Root Node version: `nvm use` (uses `.nvmrc`, currently Node 24)
|
||||
- Backend dev: `cd backend && npm install && npm run dev`
|
||||
- Frontend dev: `cd frontend && npm install && npm run start`
|
||||
|
||||
## Architecture and Boundaries
|
||||
- Backend API entrypoint: `backend/app/server.js`
|
||||
- Defines `GET /api/line-of-sight` and `GET /api/health`
|
||||
- Performs destination/path generation and PostGIS querying
|
||||
- Frontend app entrypoint: `frontend/src/App.jsx`
|
||||
- Owns map lifecycle, animation, and UI state
|
||||
- Calls backend via `frontend/src/services/api.js`
|
||||
- Database bootstrap: `docker/init.sql`
|
||||
- Enables PostGIS and creates `cities` with spatial index
|
||||
|
||||
When changing behavior, prefer backend geospatial logic over duplicating calculations in the frontend.
|
||||
|
||||
## Project Conventions
|
||||
- Keep geospatial coordinates in WGS84 (`SRID 4326`) and preserve existing lat/lon parameter naming.
|
||||
- Keep API responses JSON-compatible and backward compatible unless explicitly requested.
|
||||
- Keep frontend styles in `frontend/src/styles/` (project uses custom CSS, not utility CSS frameworks).
|
||||
- Avoid broad refactors in `App.jsx` unless task requires it; map lifecycle and refs are tightly coupled.
|
||||
|
||||
## Testing Expectations
|
||||
- Backend tests live in `backend/tests/` and use Jest + Supertest.
|
||||
- Frontend unit tests live in `frontend/src/__tests__/` and use Vitest + Testing Library.
|
||||
- E2E tests live in `frontend/e2e/` and use Playwright.
|
||||
- For feature changes:
|
||||
- Run the closest unit tests first.
|
||||
- Run E2E tests when user flows or map interactions are changed.
|
||||
|
||||
## Common Pitfalls
|
||||
- PostGIS must be available before backend geospatial endpoints are exercised.
|
||||
- `docker-compose.yml` pins Postgres service to `linux/arm64`; this can affect non-ARM hosts.
|
||||
- Data import script (`backend/scripts/import_cities.js`) depends on `wget` and `unzip` availability.
|
||||
- `README.md` contains roadmap/history notes; trust current scripts/config in source files first.
|
||||
|
||||
## CI Notes
|
||||
CI config is in `.gitea/workflows/test.yml`.
|
||||
- Backend and frontend tests run on Node 24.
|
||||
- Frontend unit tests run with `npm test -- --run`.
|
||||
- E2E runs in Playwright container.
|
||||
|
||||
## Link, Do Not Duplicate
|
||||
For detailed setup and product context, reference:
|
||||
- `README.md`
|
||||
- `GEMINI.md`
|
||||
|
||||
Keep this file focused on actionable agent guidance and repo-specific guardrails.
|
||||
@@ -0,0 +1,112 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## What This Project Is
|
||||
|
||||
**Line of Sight** is a geospatial web app that draws a great-circle line from a user-selected point on Earth in a chosen direction, then finds all cities along that path. It includes a flight-over animation that speeds up 20x over water and slows to normal speed over land.
|
||||
|
||||
## Commands
|
||||
|
||||
### Docker (preferred workflow)
|
||||
|
||||
```bash
|
||||
docker-compose up --build # Start all services (frontend :3050, backend :3001, postgres)
|
||||
docker-compose down # Stop all services
|
||||
docker-compose logs -f # View logs
|
||||
|
||||
# Run tests inside containers
|
||||
docker-compose exec backend npm test
|
||||
docker-compose exec frontend npm test -- --run
|
||||
docker-compose exec frontend npm run test:e2e
|
||||
```
|
||||
|
||||
### Local development (without Docker)
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
cd backend && npm run dev # Nodemon dev server on :3001
|
||||
|
||||
# Frontend
|
||||
cd frontend && npm run start # Vite dev server on :3050
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
```bash
|
||||
# Backend unit tests (Jest + Supertest)
|
||||
cd backend && npm test
|
||||
|
||||
# Frontend unit tests (Vitest)
|
||||
cd frontend && npm test # Watch mode
|
||||
cd frontend && npm test -- --run # Single run (CI mode)
|
||||
|
||||
# E2E tests (Playwright)
|
||||
cd frontend && npm run test:e2e
|
||||
|
||||
# Seed the database with GeoNames city data
|
||||
cd backend && npm run seed-data
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
cd frontend && npm run build # Vite production build → frontend/build/
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
This is a monorepo with three services orchestrated by Docker Compose:
|
||||
|
||||
```
|
||||
frontend/ → React 19 + Vite 6 SPA (MapLibre GL, Turf.js, Axios)
|
||||
backend/ → Node 24 + Express 5 REST API
|
||||
docker/ → PostgreSQL + PostGIS initialization
|
||||
```
|
||||
|
||||
### Data flow
|
||||
|
||||
1. User clicks map → sets start point (lat/lon)
|
||||
2. User selects direction (0–360°) and tolerance (km radius)
|
||||
3. Frontend calls `GET /api/line-of-sight?lat=&lon=&direction=&tolerance=`
|
||||
4. Backend generates 80 path points along a great-circle arc (up to 20,000 km)
|
||||
5. For each point, a PostGIS `ST_DWithin()` query finds cities within tolerance
|
||||
6. Backend also checks whether each point is over land (500 km radius land check)
|
||||
7. Response includes line coordinates with per-point water flags and matching cities
|
||||
8. Frontend renders the path on a 3D globe map and shows city markers
|
||||
|
||||
### Backend: `backend/app/server.js`
|
||||
|
||||
Single-file Express app. Key internals:
|
||||
- `calculateDestination()` — Haversine formula for great-circle destination points
|
||||
- `GET /api/line-of-sight` — main endpoint: path generation + PostGIS city lookup
|
||||
- `GET /api/health` — health check
|
||||
- Returns up to 200 cities ordered by position along the line
|
||||
|
||||
### Frontend: `frontend/src/App.jsx`
|
||||
|
||||
Single large React component (~687 lines) managing all state and map logic:
|
||||
- MapLibre GL map with 3D globe projection and terrain/sky effects
|
||||
- Direction slider drives a live preview line before the user commits
|
||||
- After "Show Line of Sight", map locks (prevents moving start point)
|
||||
- Flight animation uses Turf.js to interpolate positions along the path; speed is 1× over land, 20× over water with smooth acceleration (0.005 step), predictive look-ahead of 2000 km
|
||||
- New cities are fetched every 2000 km during flight via the same API
|
||||
- Three map styles: light, dark, satellite (Esri tiles)
|
||||
|
||||
### Database
|
||||
|
||||
PostGIS `cities` table with a GIST index on `geom GEOGRAPHY(POINT, 4326)`. All coordinates use WGS84 / SRID 4326. The init SQL seeds 10 major cities; the `seed-data` script imports from GeoNames for a fuller dataset.
|
||||
|
||||
## Conventions
|
||||
|
||||
- **Geospatial**: WGS84 / SRID 4326 everywhere; PostGIS `GEOGRAPHY` type for distance queries
|
||||
- **API**: RESTful; query params for `GET /api/line-of-sight`; env var `VITE_API_URL` (frontend) or `DATABASE_URL` (backend)
|
||||
- **Styling**: Plain CSS files in `frontend/src/styles/` — no CSS framework
|
||||
- **Tests**: Backend mocks the `pg` Pool; frontend mocks MapLibre GL and the API service. E2E tests use Playwright with a mock API response
|
||||
|
||||
## CI
|
||||
|
||||
Gitea workflow (`.gitea/workflows/test.yml`) runs on push/PR to `main`:
|
||||
1. **backend-test** — `npm ci && npm test`
|
||||
2. **frontend-test** — `npm ci && npm test -- --run`
|
||||
3. **e2e-test** — uses `mcr.microsoft.com/playwright:v1.50.1` container
|
||||
@@ -51,7 +51,7 @@ docker-compose up --build
|
||||
|
||||
### 3. Access Application
|
||||
|
||||
- **Frontend**: http://localhost:3000
|
||||
- **Frontend**: http://localhost:3050
|
||||
- **Backend API**: http://localhost:3001
|
||||
- **Database**: localhost:5432 (PostgreSQL with PostGIS)
|
||||
|
||||
@@ -219,7 +219,7 @@ npm run dev
|
||||
### Port Already in Use
|
||||
```bash
|
||||
# Find process using port
|
||||
lsof -i :3000
|
||||
lsof -i :3050
|
||||
lsof -i :3001
|
||||
|
||||
# Kill process
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ services:
|
||||
dockerfile: Dockerfile
|
||||
container_name: line-of-sight-frontend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
- "3050:3050"
|
||||
environment:
|
||||
- VITE_API_URL=http://localhost:3001/api
|
||||
depends_on:
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ RUN npm install
|
||||
COPY . .
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3000
|
||||
EXPOSE 3050
|
||||
|
||||
# Set environment variable for API URL
|
||||
ENV VITE_API_URL=http://localhost:3001/api
|
||||
|
||||
@@ -1,14 +1,80 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
// MapLibre GL requires WebGL which isn't available in headless Chromium.
|
||||
// Intercept the module request and return a lightweight mock so React can render.
|
||||
const MAPLIBRE_MOCK = `
|
||||
class Map {
|
||||
constructor(opts) {
|
||||
this._listeners = {};
|
||||
Promise.resolve().then(() => this._emit('style.load'));
|
||||
}
|
||||
_emit(event) {
|
||||
(this._listeners[event] || []).forEach(fn => fn());
|
||||
}
|
||||
on(event, fn) {
|
||||
if (!this._listeners[event]) this._listeners[event] = [];
|
||||
this._listeners[event].push(fn);
|
||||
return this;
|
||||
}
|
||||
off(event, fn) {
|
||||
this._listeners[event] = (this._listeners[event] || []).filter(l => l !== fn);
|
||||
return this;
|
||||
}
|
||||
remove() {}
|
||||
getSource() { return null; }
|
||||
getLayer() { return null; }
|
||||
addSource() {}
|
||||
addLayer() {}
|
||||
removeLayer() {}
|
||||
removeSource() {}
|
||||
setSky() {}
|
||||
setTerrain() {}
|
||||
setLayoutProperty() {}
|
||||
flyTo() {}
|
||||
jumpTo() {}
|
||||
setStyle() { Promise.resolve().then(() => this._emit('style.load')); }
|
||||
getCanvas() { return document.createElement('canvas'); }
|
||||
project() { return { x: 0, y: 0 }; }
|
||||
unproject() { return { lng: 0, lat: 0 }; }
|
||||
}
|
||||
class Marker {
|
||||
constructor(opts) {
|
||||
this._el = (opts && opts.element) || document.createElement('div');
|
||||
}
|
||||
setLngLat() { return this; }
|
||||
addTo() { return this; }
|
||||
remove() {}
|
||||
getLngLat() { return { lng: 0, lat: 0 }; }
|
||||
getElement() { return this._el; }
|
||||
}
|
||||
class Popup {
|
||||
setLngLat() { return this; }
|
||||
setDOMContent() { return this; }
|
||||
addTo() { return this; }
|
||||
remove() {}
|
||||
}
|
||||
class LngLatBounds {
|
||||
extend() { return this; }
|
||||
}
|
||||
export default { Map, Marker, Popup, LngLatBounds };
|
||||
`;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.route('**maplibre-gl.js*', async route => {
|
||||
await route.fulfill({ contentType: 'application/javascript', body: MAPLIBRE_MOCK });
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Line of Sight Application', () => {
|
||||
test('should load the home page and show settings', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await expect(page.locator('text=Line of Sight Settings')).toBeVisible();
|
||||
await expect(page.locator('text=Direction')).toBeVisible();
|
||||
await expect(page.locator('label:has-text("Direction")')).toBeVisible();
|
||||
});
|
||||
|
||||
test('should be able to toggle map style', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.waitForSelector('h3:text("Line of Sight Settings")', { timeout: 10000 });
|
||||
const darkButton = page.locator('button:text("Dark")');
|
||||
await darkButton.click();
|
||||
await expect(darkButton).toHaveClass(/active-style/);
|
||||
@@ -16,10 +82,8 @@ test.describe('Line of Sight Application', () => {
|
||||
|
||||
test('should show results when clicking the search button', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
// Mock the API response to avoid dependency on backend for E2E if desired,
|
||||
// but here we let it hit the real backend if it's up.
|
||||
// For a robust E2E in CI, we usually mock.
|
||||
await page.waitForSelector('h3:text("Line of Sight Settings")', { timeout: 10000 });
|
||||
|
||||
await page.route('**/api/line-of-sight*', async route => {
|
||||
const json = {
|
||||
success: true,
|
||||
|
||||
@@ -82,4 +82,4 @@ Error generating stack: `+a.message+`
|
||||
<div id='root'></div>
|
||||
</body>
|
||||
</html>
|
||||
<script id="playwrightReportBase64" type="application/zip">data:application/zip;base64,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</script>
|
||||
<script id="playwrightReportBase64" type="application/zip">data:application/zip;base64,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</script>
|
||||
@@ -8,9 +8,17 @@ export default defineConfig({
|
||||
workers: process.env.CI ? 1 : undefined,
|
||||
reporter: process.env.CI ? 'list' : 'html',
|
||||
use: {
|
||||
baseURL: 'http://localhost:3000',
|
||||
baseURL: 'http://localhost:3050',
|
||||
trace: 'on-first-retry',
|
||||
headless: true,
|
||||
launchOptions: {
|
||||
args: [
|
||||
'--enable-webgl',
|
||||
'--ignore-gpu-blocklist',
|
||||
'--use-gl=angle',
|
||||
'--use-angle=swiftshader-webgl',
|
||||
],
|
||||
},
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
@@ -20,7 +28,7 @@ export default defineConfig({
|
||||
],
|
||||
webServer: {
|
||||
command: 'npm run start',
|
||||
url: 'http://localhost:3000',
|
||||
url: 'http://localhost:3050',
|
||||
reuseExistingServer: !process.env.CI,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
{
|
||||
"status": "failed",
|
||||
"failedTests": [
|
||||
"a510cc93a867214a2ea0-87d527ee6ab9fa6e55ec",
|
||||
"a510cc93a867214a2ea0-64f1332b15a123b767f1",
|
||||
"a510cc93a867214a2ea0-ebcb65ad8c44378dd3e8"
|
||||
]
|
||||
"status": "passed",
|
||||
"failedTests": []
|
||||
}
|
||||
@@ -10,7 +10,7 @@ export default defineConfig({
|
||||
exclude: ['**/e2e/**', '**/node_modules/**'],
|
||||
},
|
||||
server: {
|
||||
port: 3000,
|
||||
port: 3050,
|
||||
host: '0.0.0.0',
|
||||
},
|
||||
build: {
|
||||
|
||||
Reference in New Issue
Block a user