ci: fix runner image (node:20), add Playwright smoke tests
- Change runner to node:20 (has bash) instead of node:20-alpine - Add tests/smoke.spec.js: 7 tests covering title, welcome screen, COMARCA_PATHS count (43), Lluçanès/Moianès presence, and filter counts (coastal=12, interior=21, mountain=10) - Add playwright.config.js - Fix CI workflow: use 'serve' for static server, proper SSH key setup
This commit is contained in:
@@ -6,7 +6,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# ─────────────────────────────────────────────
|
# ─────────────────────────────────────────────
|
||||||
# JOB 1: Playwright tests
|
# JOB 1: Playwright smoke tests
|
||||||
# ─────────────────────────────────────────────
|
# ─────────────────────────────────────────────
|
||||||
test:
|
test:
|
||||||
name: Playwright tests
|
name: Playwright tests
|
||||||
@@ -19,21 +19,19 @@ jobs:
|
|||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: '20'
|
||||||
cache: 'npm'
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci --omit=dev
|
run: npm ci
|
||||||
|
|
||||||
- name: Install Playwright browsers
|
- name: Install Playwright + Chromium system deps
|
||||||
run: npx playwright install chromium --with-deps
|
run: npx playwright install chromium --with-deps
|
||||||
|
|
||||||
- name: Start app (static HTTP server)
|
- name: Start static HTTP server
|
||||||
run: |
|
run: |
|
||||||
npm install --save-dev http-server
|
npx --yes serve . -l 9090 &
|
||||||
npx http-server . -p 9090 &
|
sleep 3
|
||||||
sleep 2
|
|
||||||
|
|
||||||
- name: Run Playwright tests
|
- name: Run smoke tests
|
||||||
run: npx playwright test --reporter=list
|
run: npx playwright test --reporter=list
|
||||||
env:
|
env:
|
||||||
APP_URL: http://localhost:9090
|
APP_URL: http://localhost:9090
|
||||||
@@ -52,9 +50,11 @@ jobs:
|
|||||||
- name: Setup SSH key
|
- name: Setup SSH key
|
||||||
run: |
|
run: |
|
||||||
mkdir -p ~/.ssh
|
mkdir -p ~/.ssh
|
||||||
echo "${{ secrets.VPS_SSH_KEY }}" > ~/.ssh/id_ed25519
|
printf '%s\n' "$VPS_SSH_KEY" > ~/.ssh/id_ed25519
|
||||||
chmod 600 ~/.ssh/id_ed25519
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
ssh-keyscan -H 80.225.185.50 >> ~/.ssh/known_hosts
|
ssh-keyscan -H 80.225.185.50 >> ~/.ssh/known_hosts
|
||||||
|
env:
|
||||||
|
VPS_SSH_KEY: ${{ secrets.VPS_SSH_KEY }}
|
||||||
|
|
||||||
- name: Upload static files
|
- name: Upload static files
|
||||||
run: |
|
run: |
|
||||||
@@ -63,15 +63,16 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload server files & rebuild
|
- name: Upload server files & rebuild
|
||||||
run: |
|
run: |
|
||||||
ssh -i ~/.ssh/id_ed25519 ubuntu@80.225.185.50 "mkdir -p /srv/docker/builds/comarques"
|
|
||||||
scp -i ~/.ssh/id_ed25519 server.js package.json Dockerfile \
|
scp -i ~/.ssh/id_ed25519 server.js package.json Dockerfile \
|
||||||
ubuntu@80.225.185.50:/srv/docker/builds/comarques/
|
ubuntu@80.225.185.50:/srv/docker/builds/comarques/
|
||||||
ssh -i ~/.ssh/id_ed25519 ubuntu@80.225.185.50 \
|
ssh -i ~/.ssh/id_ed25519 ubuntu@80.225.185.50 \
|
||||||
"cd /srv/docker/builds/comarques && docker build -t comarques-de-catalunya:latest . \
|
"cd /srv/docker/builds/comarques \
|
||||||
&& cd /srv/docker/compose && docker compose up -d comarques"
|
&& docker build -t comarques-de-catalunya:latest . \
|
||||||
|
&& cd /srv/docker/compose \
|
||||||
|
&& docker compose up -d comarques"
|
||||||
|
|
||||||
- name: Health check
|
- name: Health check
|
||||||
run: |
|
run: |
|
||||||
sleep 5
|
sleep 5
|
||||||
curl -fs https://comarques.jaumegar.work/api/health \
|
curl -fs https://comarques.jaumegar.work/api/health \
|
||||||
|| (echo "❌ Health check failed after deploy" && exit 1)
|
|| (echo "Health check failed" && exit 1)
|
||||||
|
|||||||
16
playwright.config.js
Normal file
16
playwright.config.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// playwright.config.js
|
||||||
|
const { defineConfig, devices } = require('@playwright/test');
|
||||||
|
|
||||||
|
module.exports = defineConfig({
|
||||||
|
testDir: './tests',
|
||||||
|
timeout: 30_000,
|
||||||
|
retries: 0,
|
||||||
|
reporter: 'list',
|
||||||
|
use: {
|
||||||
|
baseURL: process.env.APP_URL || 'http://localhost:9090',
|
||||||
|
headless: true,
|
||||||
|
},
|
||||||
|
projects: [
|
||||||
|
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
|
||||||
|
],
|
||||||
|
});
|
||||||
75
tests/smoke.spec.js
Normal file
75
tests/smoke.spec.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
// smoke.spec.js — Basic smoke tests for comarques app
|
||||||
|
// Runs against a static HTTP server (no DB required).
|
||||||
|
// Playwright is invoked with chromium via npx.
|
||||||
|
|
||||||
|
const { test, expect } = require('@playwright/test');
|
||||||
|
|
||||||
|
const BASE = process.env.APP_URL || 'http://localhost:9090';
|
||||||
|
|
||||||
|
test.describe('App loads', () => {
|
||||||
|
test('title is correct', async ({ page }) => {
|
||||||
|
await page.goto(BASE + '/index.html');
|
||||||
|
await expect(page).toHaveTitle(/Comarques de Catalunya/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('welcome screen is shown on first load', async ({ page }) => {
|
||||||
|
await page.goto(BASE + '/index.html');
|
||||||
|
// Clear any existing player so we always land on welcome
|
||||||
|
await page.evaluate(() => localStorage.clear());
|
||||||
|
await page.reload();
|
||||||
|
const welcome = page.locator('#screen-welcome');
|
||||||
|
await expect(welcome).toBeVisible();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('comarca-paths.js', () => {
|
||||||
|
test('COMARCA_PATHS loads and has 43 entries', async ({ page }) => {
|
||||||
|
await page.goto(BASE + '/index.html');
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
const count = await page.evaluate(() => Object.keys(COMARCA_PATHS).length);
|
||||||
|
expect(count).toBe(43);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Lluçanès and Moianès have map paths', async ({ page }) => {
|
||||||
|
await page.goto(BASE + '/index.html');
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
const result = await page.evaluate(() => ({
|
||||||
|
llucanes: !!COMARCA_PATHS['Lluçanès'],
|
||||||
|
moianes: !!COMARCA_PATHS['Moianès'],
|
||||||
|
}));
|
||||||
|
expect(result.llucanes).toBe(true);
|
||||||
|
expect(result.moianes).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('Filters', () => {
|
||||||
|
test('coastal filter returns 12 comarques', async ({ page }) => {
|
||||||
|
await page.goto(BASE + '/index.html');
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
const count = await page.evaluate(() => {
|
||||||
|
activeGroups = new Set(['coastal']);
|
||||||
|
return getActiveComarques().length;
|
||||||
|
});
|
||||||
|
expect(count).toBe(12);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('interior filter returns 21 comarques', async ({ page }) => {
|
||||||
|
await page.goto(BASE + '/index.html');
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
const count = await page.evaluate(() => {
|
||||||
|
activeGroups = new Set(['interior']);
|
||||||
|
return getActiveComarques().length;
|
||||||
|
});
|
||||||
|
expect(count).toBe(21);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('mountain filter returns 10 comarques', async ({ page }) => {
|
||||||
|
await page.goto(BASE + '/index.html');
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
const count = await page.evaluate(() => {
|
||||||
|
activeGroups = new Set(['mountain']);
|
||||||
|
return getActiveComarques().length;
|
||||||
|
});
|
||||||
|
expect(count).toBe(10);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user