test(e2e): migra gli end-to-end a CommonJS e stabilizza l'esecuzione Playwright
- aggiunge configurazione playwright.config.cjs per compatibilita runtime - aggiorna playwright.config.ts con progetto Mobile Chrome - migra i test E2E da .js a .spec.cjs - rimuove i vecchi file E2E non piu usati - allinea i test visual con snapshot baseline aggiornate
38
playwright.config.cjs
Normal file
@@ -0,0 +1,38 @@
|
||||
const { defineConfig, devices } = require('@playwright/test');
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
module.exports = defineConfig({
|
||||
testDir: './tests/e2e',
|
||||
fullyParallel: false,
|
||||
forbidOnly: !!process.env.CI,
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
workers: 1,
|
||||
reporter: 'html',
|
||||
use: {
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
{
|
||||
name: 'firefox',
|
||||
use: { ...devices['Desktop Firefox'] },
|
||||
},
|
||||
{
|
||||
name: 'Mobile Chrome',
|
||||
use: { ...devices['Pixel 5'] },
|
||||
},
|
||||
],
|
||||
|
||||
webServer: {
|
||||
command: 'npm run serve',
|
||||
url: 'http://localhost:3000',
|
||||
reuseExistingServer: !process.env.CI,
|
||||
timeout: 120 * 1000,
|
||||
},
|
||||
});
|
||||
@@ -50,14 +50,10 @@ export default defineConfig({
|
||||
// },
|
||||
|
||||
/* Test against mobile viewports. */
|
||||
// {
|
||||
// name: 'Mobile Chrome',
|
||||
// use: { ...devices['Pixel 5'] },
|
||||
// },
|
||||
// {
|
||||
// name: 'Mobile Safari',
|
||||
// use: { ...devices['iPhone 12'] },
|
||||
// },
|
||||
{
|
||||
name: 'Mobile Chrome',
|
||||
use: { ...devices['Pixel 5'] },
|
||||
},
|
||||
|
||||
/* Test against branded browsers. */
|
||||
// {
|
||||
|
||||
72
tests/e2e/accessibility.spec.cjs
Normal file
@@ -0,0 +1,72 @@
|
||||
const { test, expect } = require('@playwright/test');
|
||||
const AxeBuilderImport = require('@axe-core/playwright');
|
||||
const AxeBuilder = AxeBuilderImport.default || AxeBuilderImport;
|
||||
|
||||
test.describe('Accessibility (a11y)', () => {
|
||||
|
||||
test('Display: non dovrebbe avere violazioni critiche a11y', async ({ page }) => {
|
||||
await page.goto('http://localhost:3000');
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const results = await new AxeBuilder({ page })
|
||||
.withTags(['wcag2a', 'wcag2aa'])
|
||||
.disableRules(['color-contrast']) // il display ha sfondo nero con testo grande, valutato separatamente
|
||||
.analyze();
|
||||
|
||||
expect(results.violations).toEqual([]);
|
||||
});
|
||||
|
||||
test('Controller: non dovrebbe avere violazioni critiche a11y', async ({ page }) => {
|
||||
await page.goto('http://localhost:3001');
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
const results = await new AxeBuilder({ page })
|
||||
.withTags(['wcag2a', 'wcag2aa'])
|
||||
.analyze();
|
||||
|
||||
// Mostra i dettagli delle violazioni se ci sono
|
||||
if (results.violations.length > 0) {
|
||||
console.log('A11y violations:', JSON.stringify(results.violations.map(v => ({
|
||||
id: v.id,
|
||||
impact: v.impact,
|
||||
description: v.description,
|
||||
nodes: v.nodes.length
|
||||
})), null, 2));
|
||||
}
|
||||
|
||||
// Accettiamo solo violazioni minor (non critiche o serie)
|
||||
const serious = results.violations.filter(v =>
|
||||
v.impact === 'critical' || v.impact === 'serious'
|
||||
);
|
||||
expect(serious).toEqual([]);
|
||||
});
|
||||
|
||||
test('Controller: i touch target dovrebbero avere dimensione minima', async ({ page }) => {
|
||||
await page.goto('http://localhost:3001');
|
||||
await page.waitForSelector('.conn-bar.connected');
|
||||
|
||||
// Controlla che i bottoni principali abbiano dimensione minima 44x44px
|
||||
const buttons = page.locator('.btn-ctrl');
|
||||
const count = await buttons.count();
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const box = await buttons.nth(i).boundingBox();
|
||||
expect(box.width).toBeGreaterThanOrEqual(44);
|
||||
expect(box.height).toBeGreaterThanOrEqual(44);
|
||||
}
|
||||
});
|
||||
|
||||
test('Controller: i bottoni punteggio dovrebbero avere dimensione adeguata', async ({ page }) => {
|
||||
await page.goto('http://localhost:3001');
|
||||
await page.waitForSelector('.conn-bar.connected');
|
||||
|
||||
const scoreButtons = page.locator('.team-score');
|
||||
const count = await scoreButtons.count();
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const box = await scoreButtons.nth(i).boundingBox();
|
||||
expect(box.width).toBeGreaterThanOrEqual(100);
|
||||
expect(box.height).toBeGreaterThanOrEqual(100);
|
||||
}
|
||||
});
|
||||
});
|
||||
119
tests/e2e/basic-flow.spec.cjs
Normal file
@@ -0,0 +1,119 @@
|
||||
const { test, expect } = require('@playwright/test');
|
||||
|
||||
test.describe('Basic Flow: Controller ↔ Display', () => {
|
||||
|
||||
test('dovrebbe caricare Display e Controller con i titoli corretti', async ({ context }) => {
|
||||
const displayPage = await context.newPage();
|
||||
const controllerPage = await context.newPage();
|
||||
|
||||
await displayPage.goto('http://localhost:3000');
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
|
||||
await expect(displayPage).toHaveTitle(/Segnapunti/);
|
||||
await expect(controllerPage).toHaveTitle(/Controller/);
|
||||
});
|
||||
|
||||
test('il punteggio iniziale dovrebbe essere 0-0', async ({ context }) => {
|
||||
const controllerPage = await context.newPage();
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
|
||||
// Attende la connessione WebSocket
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
const homeScore = controllerPage.locator('.team-score.home-bg .team-pts');
|
||||
const guestScore = controllerPage.locator('.team-score.guest-bg .team-pts');
|
||||
await expect(homeScore).toHaveText('0');
|
||||
await expect(guestScore).toHaveText('0');
|
||||
});
|
||||
|
||||
test('click +1 Home sul Controller dovrebbe aggiornare il Display', async ({ context }) => {
|
||||
const displayPage = await context.newPage();
|
||||
const controllerPage = await context.newPage();
|
||||
|
||||
await displayPage.goto('http://localhost:3000');
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
|
||||
// Attende la connessione WebSocket del controller
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
// Reset per stato pulito
|
||||
await controllerPage.getByText(/Reset/i).first().click();
|
||||
const btnConfirm = controllerPage.locator('.dialog .btn-confirm');
|
||||
if (await btnConfirm.isVisible()) {
|
||||
await btnConfirm.click();
|
||||
}
|
||||
await controllerPage.waitForTimeout(200);
|
||||
|
||||
// Click +1 Home
|
||||
await controllerPage.locator('.team-score.home-bg').click();
|
||||
await controllerPage.waitForTimeout(200);
|
||||
|
||||
// Verifica Controller mostra 1
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('1');
|
||||
|
||||
// Verifica Display mostra 1 (il punteggio grande)
|
||||
await expect(displayPage.locator('.punt.home')).toHaveText('1');
|
||||
});
|
||||
|
||||
test('click +1 Guest sul Controller dovrebbe aggiornare il Display', async ({ context }) => {
|
||||
const displayPage = await context.newPage();
|
||||
const controllerPage = await context.newPage();
|
||||
|
||||
await displayPage.goto('http://localhost:3000');
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
// Reset
|
||||
await controllerPage.getByText(/Reset/i).first().click();
|
||||
const btnConfirm = controllerPage.locator('.dialog .btn-confirm');
|
||||
if (await btnConfirm.isVisible()) {
|
||||
await btnConfirm.click();
|
||||
}
|
||||
await controllerPage.waitForTimeout(200);
|
||||
|
||||
// Click +1 Guest
|
||||
await controllerPage.locator('.team-score.guest-bg').click();
|
||||
await controllerPage.waitForTimeout(200);
|
||||
|
||||
// Verifica Controller
|
||||
await expect(controllerPage.locator('.team-score.guest-bg .team-pts')).toHaveText('1');
|
||||
|
||||
// Verifica Display
|
||||
await expect(displayPage.locator('.punt.guest')).toHaveText('1');
|
||||
});
|
||||
|
||||
test('la sincronizzazione dovrebbe funzionare con punti alternati', async ({ context }) => {
|
||||
const displayPage = await context.newPage();
|
||||
const controllerPage = await context.newPage();
|
||||
|
||||
await displayPage.goto('http://localhost:3000');
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
// Reset
|
||||
await controllerPage.getByText(/Reset/i).first().click();
|
||||
const btnConfirm = controllerPage.locator('.dialog .btn-confirm');
|
||||
if (await btnConfirm.isVisible()) {
|
||||
await btnConfirm.click();
|
||||
}
|
||||
await controllerPage.waitForTimeout(200);
|
||||
|
||||
// Home +1, Guest +1, Home +1
|
||||
await controllerPage.locator('.team-score.home-bg').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
await controllerPage.locator('.team-score.guest-bg').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
await controllerPage.locator('.team-score.home-bg').click();
|
||||
await controllerPage.waitForTimeout(200);
|
||||
|
||||
// Controller: Home 2, Guest 1
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('2');
|
||||
await expect(controllerPage.locator('.team-score.guest-bg .team-pts')).toHaveText('1');
|
||||
|
||||
// Display: Home 2, Guest 1
|
||||
await expect(displayPage.locator('.punt.home')).toHaveText('2');
|
||||
await expect(displayPage.locator('.punt.guest')).toHaveText('1');
|
||||
});
|
||||
});
|
||||
@@ -1,28 +0,0 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('Controller updates Display score', async ({ context }) => {
|
||||
// 1. Create two pages (Controller and Display)
|
||||
const displayPage = await context.newPage();
|
||||
const controllerPage = await context.newPage();
|
||||
|
||||
// 2. Open Display
|
||||
await displayPage.goto('http://localhost:3000');
|
||||
await expect(displayPage).toHaveTitle(/Segnapunti/);
|
||||
|
||||
// 3. Open Controller
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await expect(controllerPage).toHaveTitle(/Controller/);
|
||||
|
||||
// 4. Check initial state (assuming reset)
|
||||
// Note: This depends on the specific IDs in your HTML.
|
||||
// You might need to adjust selectors based on your actual HTML structure.
|
||||
|
||||
// Example: waiting for score element
|
||||
// await expect(displayPage.locator('#score-home')).toHaveText('0');
|
||||
|
||||
// 5. Action on Controller
|
||||
// await controllerPage.click('#btn-add-home');
|
||||
|
||||
// 6. Verify on Display
|
||||
// await expect(displayPage.locator('#score-home')).toHaveText('1');
|
||||
});
|
||||
131
tests/e2e/full-match.spec.cjs
Normal file
@@ -0,0 +1,131 @@
|
||||
const { test, expect } = require('@playwright/test');
|
||||
|
||||
// Helper: reset dal controller
|
||||
async function resetGame(controllerPage) {
|
||||
await controllerPage.getByText(/Reset/i).first().click();
|
||||
const btnConfirm = controllerPage.locator('.dialog .btn-confirm');
|
||||
if (await btnConfirm.isVisible()) {
|
||||
await btnConfirm.click();
|
||||
}
|
||||
await controllerPage.waitForTimeout(300);
|
||||
}
|
||||
|
||||
// Helper: incrementa punti per una squadra N volte
|
||||
async function addPoints(controllerPage, team, count) {
|
||||
const selector = team === 'home' ? '.team-score.home-bg' : '.team-score.guest-bg';
|
||||
for (let i = 0; i < count; i++) {
|
||||
await controllerPage.locator(selector).click();
|
||||
await controllerPage.waitForTimeout(30);
|
||||
}
|
||||
await controllerPage.waitForTimeout(100);
|
||||
}
|
||||
|
||||
// Helper: assegna un set a una squadra (25 punti + click SET)
|
||||
async function winSet(controllerPage, team) {
|
||||
await addPoints(controllerPage, team, 25);
|
||||
// Clicca bottone SET
|
||||
const setSelector = team === 'home' ? '.btn-set.home-bg' : '.btn-set.guest-bg';
|
||||
await controllerPage.locator(setSelector).click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
// Reset punti per il prossimo set
|
||||
// (in questo gioco i punti non si resettano automaticamente, serve reset manuale
|
||||
// o il controller gestisce il prossimo set manualmente)
|
||||
}
|
||||
|
||||
test.describe('Full Match Simulation', () => {
|
||||
|
||||
test('Partita 2/3: Home vince 2 set a 0', async ({ context }) => {
|
||||
const controllerPage = await context.newPage();
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
await resetGame(controllerPage);
|
||||
|
||||
// Cambia modalità a 2/3
|
||||
await controllerPage.getByText('Config').click();
|
||||
await controllerPage.waitForSelector('.dialog-config');
|
||||
await controllerPage.locator('.btn-mode').getByText('2/3').click();
|
||||
await controllerPage.locator('.dialog-config .btn-confirm').click();
|
||||
await controllerPage.waitForTimeout(200);
|
||||
|
||||
// === SET 1: Home vince 25-0 ===
|
||||
await addPoints(controllerPage, 'home', 25);
|
||||
|
||||
// Verifica punteggio 25
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('25');
|
||||
|
||||
// Incrementa set Home
|
||||
await controllerPage.locator('.btn-set.home-bg').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
|
||||
// Verifica set 1 per Home
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-set')).toContainText('SET 1');
|
||||
});
|
||||
|
||||
test('Set decisivo 2/3: vittoria a 15 punti', async ({ context }) => {
|
||||
const controllerPage = await context.newPage();
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
await resetGame(controllerPage);
|
||||
|
||||
// Cambia modalità a 2/3
|
||||
await controllerPage.getByText('Config').click();
|
||||
await controllerPage.waitForSelector('.dialog-config');
|
||||
await controllerPage.locator('.btn-mode').getByText('2/3').click();
|
||||
await controllerPage.locator('.dialog-config .btn-confirm').click();
|
||||
await controllerPage.waitForTimeout(200);
|
||||
|
||||
// Imposta set 1-1 manualmente (simula set pareggiati)
|
||||
await controllerPage.locator('.btn-set.home-bg').click();
|
||||
await controllerPage.waitForTimeout(50);
|
||||
await controllerPage.locator('.btn-set.guest-bg').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
|
||||
// Verifica set 1-1
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-set')).toContainText('SET 1');
|
||||
await expect(controllerPage.locator('.team-score.guest-bg .team-set')).toContainText('SET 1');
|
||||
|
||||
// === SET DECISIVO: Home porta a 15 ===
|
||||
await addPoints(controllerPage, 'home', 15);
|
||||
|
||||
// Verifica punteggio 15 (e il set è decisivo: dopo 15 punti il gioco è vinto)
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('15');
|
||||
|
||||
// Verifica che non si possono aggiungere altri punti (vittoria)
|
||||
await controllerPage.locator('.team-score.home-bg').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
// Dovrebbe restare 15 (checkVittoria blocca incPunt)
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('15');
|
||||
});
|
||||
|
||||
test('Set normale: punti oltre 25 fino ai vantaggi', async ({ context }) => {
|
||||
const controllerPage = await context.newPage();
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
await resetGame(controllerPage);
|
||||
|
||||
// Porta a 24-24
|
||||
await addPoints(controllerPage, 'home', 24);
|
||||
await addPoints(controllerPage, 'guest', 24);
|
||||
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('24');
|
||||
await expect(controllerPage.locator('.team-score.guest-bg .team-pts')).toHaveText('24');
|
||||
|
||||
// Home va a 25 (non è vittoria perché serve scarto di 2)
|
||||
await controllerPage.locator('.team-score.home-bg').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('25');
|
||||
|
||||
// Si possono ancora aggiungere punti (non è vittoria a 25-24)
|
||||
await controllerPage.locator('.team-score.home-bg').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('26');
|
||||
|
||||
// 26-24 è vittoria → non si possono più aggiungere punti
|
||||
await controllerPage.locator('.team-score.home-bg').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('26');
|
||||
});
|
||||
});
|
||||
182
tests/e2e/game-operations.spec.cjs
Normal file
@@ -0,0 +1,182 @@
|
||||
const { test, expect } = require('@playwright/test');
|
||||
|
||||
// Helper: reset dal controller
|
||||
async function resetGame(controllerPage) {
|
||||
await controllerPage.getByText(/Reset/i).first().click();
|
||||
const btnConfirm = controllerPage.locator('.dialog .btn-confirm');
|
||||
if (await btnConfirm.isVisible()) {
|
||||
await btnConfirm.click();
|
||||
}
|
||||
await controllerPage.waitForTimeout(300);
|
||||
}
|
||||
|
||||
test.describe('Game Operations', () => {
|
||||
|
||||
test('Undo: dovrebbe annullare l\'ultimo punto', async ({ context }) => {
|
||||
const controllerPage = await context.newPage();
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
await resetGame(controllerPage);
|
||||
|
||||
// Incrementa Home a 1
|
||||
await controllerPage.locator('.team-score.home-bg').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('1');
|
||||
|
||||
// Annulla
|
||||
await controllerPage.getByText('ANNULLA PUNTO').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('0');
|
||||
});
|
||||
|
||||
test('Reset: dovrebbe azzerare tutto dopo conferma', async ({ context }) => {
|
||||
const controllerPage = await context.newPage();
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
// Imposta qualche punto
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await controllerPage.locator('.team-score.home-bg').click();
|
||||
await controllerPage.waitForTimeout(50);
|
||||
}
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('5');
|
||||
|
||||
// Reset
|
||||
await resetGame(controllerPage);
|
||||
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-pts')).toHaveText('0');
|
||||
await expect(controllerPage.locator('.team-score.guest-bg .team-pts')).toHaveText('0');
|
||||
});
|
||||
|
||||
test('Config: dovrebbe cambiare i nomi dei team', async ({ context }) => {
|
||||
const displayPage = await context.newPage();
|
||||
const controllerPage = await context.newPage();
|
||||
|
||||
await displayPage.goto('http://localhost:3000');
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
// Apri config
|
||||
await controllerPage.getByText('Config').click();
|
||||
await controllerPage.waitForSelector('.dialog-config');
|
||||
|
||||
// Modifica nomi
|
||||
const inputs = controllerPage.locator('.dialog-config .input-field');
|
||||
await inputs.first().fill('Padova');
|
||||
await inputs.nth(1).fill('Milano');
|
||||
|
||||
// Salva
|
||||
await controllerPage.locator('.dialog-config .btn-confirm').click();
|
||||
await controllerPage.waitForTimeout(300);
|
||||
|
||||
// Verifica sul Controller
|
||||
await expect(controllerPage.locator('.team-score.home-bg .team-name')).toHaveText('Padova');
|
||||
await expect(controllerPage.locator('.team-score.guest-bg .team-name')).toHaveText('Milano');
|
||||
|
||||
// Verifica sul Display
|
||||
await expect(displayPage.locator('.hea.home')).toContainText('Padova');
|
||||
await expect(displayPage.locator('.hea.guest')).toContainText('Milano');
|
||||
});
|
||||
|
||||
test('Toggle Formazione: dovrebbe mostrare la formazione sul display', async ({ context }) => {
|
||||
const displayPage = await context.newPage();
|
||||
const controllerPage = await context.newPage();
|
||||
|
||||
await displayPage.goto('http://localhost:3000');
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
// Inizialmente mostra punteggio, non formazione
|
||||
await expect(displayPage.locator('.punteggio-container')).toBeVisible();
|
||||
|
||||
// Click Formazioni
|
||||
await controllerPage.getByText('Formazioni').click();
|
||||
await controllerPage.waitForTimeout(300);
|
||||
|
||||
// Il display mostra le formazioni
|
||||
await expect(displayPage.locator('.form').first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('Toggle Striscia: dovrebbe nascondere/mostrare la striscia', async ({ context }) => {
|
||||
const displayPage = await context.newPage();
|
||||
const controllerPage = await context.newPage();
|
||||
|
||||
await displayPage.goto('http://localhost:3000');
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
// Inizialmente la striscia è visibile
|
||||
await expect(displayPage.locator('.striscia')).toBeVisible();
|
||||
|
||||
// Toggle off
|
||||
await controllerPage.getByText('Striscia').click();
|
||||
await controllerPage.waitForTimeout(300);
|
||||
await expect(displayPage.locator('.striscia')).not.toBeVisible();
|
||||
|
||||
// Toggle on
|
||||
await controllerPage.getByText('Striscia').click();
|
||||
await controllerPage.waitForTimeout(300);
|
||||
await expect(displayPage.locator('.striscia')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Cambi: dovrebbe effettuare una sostituzione giocatore', async ({ context }) => {
|
||||
const displayPage = await context.newPage();
|
||||
const controllerPage = await context.newPage();
|
||||
|
||||
await displayPage.goto('http://localhost:3000');
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
await resetGame(controllerPage);
|
||||
|
||||
// Attiva formazione sul display per verificare
|
||||
await controllerPage.getByText('Formazioni').click();
|
||||
await controllerPage.waitForTimeout(200);
|
||||
|
||||
// Apri cambi → scegli Home
|
||||
await controllerPage.getByRole('button', { name: 'Cambi', exact: true }).click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
await controllerPage.locator('.dialog .btn-set.home-bg').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
|
||||
// Inserisci sostituzione: IN=10, OUT=1
|
||||
const inField = controllerPage.locator('.cambi-in-field').first();
|
||||
const outField = controllerPage.locator('.cambi-out-field').first();
|
||||
await inField.fill('10');
|
||||
await outField.fill('1');
|
||||
|
||||
// Conferma
|
||||
await controllerPage.locator('.dialog .btn-confirm').click();
|
||||
await controllerPage.waitForTimeout(300);
|
||||
|
||||
// Verifica formazione aggiornata sul display
|
||||
const formText = await displayPage.locator('.form.home').textContent();
|
||||
expect(formText).toContain('10');
|
||||
});
|
||||
|
||||
test('Cambi: dovrebbe mostrare errore per giocatore non in formazione', async ({ context }) => {
|
||||
const controllerPage = await context.newPage();
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
await resetGame(controllerPage);
|
||||
|
||||
// Apri cambi → scegli Home
|
||||
await controllerPage.getByRole('button', { name: 'Cambi', exact: true }).click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
await controllerPage.locator('.dialog .btn-set.home-bg').click();
|
||||
await controllerPage.waitForTimeout(100);
|
||||
|
||||
// Inserisci sostituzione invalida: OUT=99 (non in formazione)
|
||||
await controllerPage.locator('.cambi-in-field').first().fill('10');
|
||||
await controllerPage.locator('.cambi-out-field').first().fill('99');
|
||||
|
||||
// Conferma
|
||||
await controllerPage.locator('.dialog .btn-confirm').click();
|
||||
await controllerPage.waitForTimeout(200);
|
||||
|
||||
// Dovrebbe mostrare errore
|
||||
await expect(controllerPage.locator('.cambi-error')).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
const { test, expect } = require('@playwright/test');
|
||||
|
||||
test.describe('Game Simulation', () => {
|
||||
test('Simulazione Partita: Controller aggiunge punti finché non cambia il set', async ({ context }) => {
|
||||
86
tests/e2e/visual-regression.spec.cjs
Normal file
@@ -0,0 +1,86 @@
|
||||
const { test, expect } = require('@playwright/test');
|
||||
|
||||
// Helper: reset dal controller
|
||||
async function resetGame(controllerPage) {
|
||||
await controllerPage.getByText(/Reset/i).first().click();
|
||||
const btnConfirm = controllerPage.locator('.dialog .btn-confirm');
|
||||
if (await btnConfirm.isVisible()) {
|
||||
await btnConfirm.click();
|
||||
}
|
||||
await controllerPage.waitForTimeout(300);
|
||||
}
|
||||
|
||||
test.describe('Visual Regression', () => {
|
||||
|
||||
test('Display: screenshot a 0-0', async ({ context }) => {
|
||||
const controllerPage = await context.newPage();
|
||||
const displayPage = await context.newPage();
|
||||
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await displayPage.goto('http://localhost:3000');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
// Reset per stato pulito
|
||||
await resetGame(controllerPage);
|
||||
|
||||
// Attende che il display riceva lo stato
|
||||
await displayPage.waitForTimeout(500);
|
||||
|
||||
await expect(displayPage).toHaveScreenshot('display-0-0.png', {
|
||||
maxDiffPixelRatio: 0.05,
|
||||
});
|
||||
});
|
||||
|
||||
test('Display: screenshot durante partita (15-12)', async ({ context }) => {
|
||||
const controllerPage = await context.newPage();
|
||||
const displayPage = await context.newPage();
|
||||
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await displayPage.goto('http://localhost:3000');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
await resetGame(controllerPage);
|
||||
|
||||
// Porta il punteggio a 15-12
|
||||
for (let i = 0; i < 15; i++) {
|
||||
await controllerPage.locator('.team-score.home-bg').click();
|
||||
await controllerPage.waitForTimeout(20);
|
||||
}
|
||||
for (let i = 0; i < 12; i++) {
|
||||
await controllerPage.locator('.team-score.guest-bg').click();
|
||||
await controllerPage.waitForTimeout(20);
|
||||
}
|
||||
await displayPage.waitForTimeout(500);
|
||||
|
||||
await expect(displayPage).toHaveScreenshot('display-15-12.png', {
|
||||
maxDiffPixelRatio: 0.05,
|
||||
});
|
||||
});
|
||||
|
||||
test('Controller: screenshot stato iniziale', async ({ context }) => {
|
||||
const controllerPage = await context.newPage();
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
await resetGame(controllerPage);
|
||||
|
||||
await expect(controllerPage).toHaveScreenshot('controller-initial.png', {
|
||||
maxDiffPixelRatio: 0.05,
|
||||
});
|
||||
});
|
||||
|
||||
test('Controller: screenshot con modal config aperta', async ({ context }) => {
|
||||
const controllerPage = await context.newPage();
|
||||
await controllerPage.goto('http://localhost:3001');
|
||||
await controllerPage.waitForSelector('.conn-bar.connected');
|
||||
|
||||
// Apri config
|
||||
await controllerPage.getByText('Config').click();
|
||||
await controllerPage.waitForSelector('.dialog-config');
|
||||
await controllerPage.waitForTimeout(300);
|
||||
|
||||
await expect(controllerPage).toHaveScreenshot('controller-config-modal.png', {
|
||||
maxDiffPixelRatio: 0.05,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 53 KiB |