You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
knowfoolery/frontend/apps/web/e2e/critical-flows-extended.spe...

176 lines
7.0 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { expect, test } from '@playwright/test'
test.describe('critical frontend flows - extended', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/')
await page.evaluate(() => {
localStorage.clear()
})
})
test('profile route requires auth, then allows access after demo login', async ({ page }) => {
await page.goto('/profile')
await expect(page.getByText('Connexion requise pour accéder au profil joueur.')).toBeVisible()
await page.getByRole('button', { name: 'Se connecter (mode démo)' }).click()
await expect(page.getByText('Statistiques joueur')).toBeVisible()
await expect(page.getByText(/Parties jouées/i)).toBeVisible()
})
test('start new game from home and render first playable question', async ({ page }) => {
await page.goto('/')
const homeNameInput = page.getByTestId('home-player-name-input')
await homeNameInput.evaluate((el) => {
const input = el as HTMLInputElement
input.value = 'E2E Player'
input.dispatchEvent(new Event('input', { bubbles: true }))
input.dispatchEvent(new Event('change', { bubbles: true }))
})
await page.getByRole('button', { name: 'Démarrer la partie' }).click()
await expect(page).toHaveURL(/\/game$/)
await expect(page.getByRole('heading', { name: 'Partie' })).toBeVisible()
await expect(page.getByText('Thème : Général')).toBeVisible()
await expect(page.getByText('Quel est le plus petit nombre premier ?')).toBeVisible()
await expect(page.getByLabel('Ta réponse')).toBeVisible()
await expect(page.getByText('3 restant(s)')).toBeVisible()
})
test('hint usage reduces awarded score for a correct answer', async ({ page }) => {
await page.goto('/game')
await page.getByRole('button', { name: 'Indice (score réduit)' }).click()
await expect(page.getByText('Confirmer lindice')).toBeVisible()
await page.locator('button', { hasText: 'Oui, utiliser un indice' }).click()
await expect(page.getByText(/Indice:/i)).toBeVisible()
const answerInput = page.getByLabel('Ta réponse')
await answerInput.evaluate((el) => {
const input = el as HTMLInputElement
input.value = '2'
input.dispatchEvent(new Event('input', { bubbles: true }))
input.dispatchEvent(new Event('change', { bubbles: true }))
})
await page.getByRole('button', { name: 'Envoyer' }).click()
await expect(page).toHaveURL(/\/results$/)
await expect(page.getByText('Score final : 1')).toBeVisible()
})
test.fixme('after 3 wrong answers, game advances to next question', async ({ page }) => {
await page.goto('/game')
await page.getByLabel('Ta réponse').fill('wrong')
await page.getByRole('button', { name: 'Envoyer' }).click()
await page.getByLabel('Ta réponse').fill('wrong')
await page.getByRole('button', { name: 'Envoyer' }).click()
await page.getByLabel('Ta réponse').fill('wrong')
await page.getByRole('button', { name: 'Envoyer' }).click()
await expect(page.getByText('Question 2')).toBeVisible()
await expect(page.getByText("Plus d'essais.")).not.toBeVisible()
})
test.fixme('session timeout ends game and redirects to results', async ({ page }) => {
await page.goto('/game')
await expect(page.getByRole('heading', { name: 'Partie' })).toBeVisible()
await expect(page).toHaveURL(/\/results$/)
await expect(page.getByText(/Temps écoulé/i)).toBeVisible()
})
test('results remain visible after page reload', async ({ page }) => {
await page.goto('/')
await page.evaluate(() => {
localStorage.setItem(
'kf.lastResult',
JSON.stringify({
playerName: 'Reload Tester',
finalScore: 7,
answered: 4,
correct: 3,
successRate: 75,
durationSec: 95,
leaderboardPosition: 2,
finishedAt: new Date().toISOString(),
})
)
})
await page.goto('/results')
await expect(page.getByText('Score final : 7')).toBeVisible()
await page.reload()
await expect(page.getByText('Score final : 7')).toBeVisible()
await expect(page.getByText('Position leaderboard : #2')).toBeVisible()
})
test.fixme('leaderboard shows empty and error states from API', async ({ page }) => {
await page.goto('/leaderboard')
await expect(page.getByText('Aucun score pour le moment.')).toBeVisible()
await page.getByRole('button', { name: 'Rafraîchir' }).click()
await expect(page.getByText(/Erreur|Impossible/i)).toBeVisible()
})
test.fixme('admin can create, edit, then delete a question', async ({ page }) => {
await page.goto('/admin/questions')
await page.getByTestId('admin-theme-input').fill('Science')
await page.getByTestId('admin-question-input').fill('Quelle planète est rouge ?')
await page.getByTestId('admin-answer-input').fill('Mars')
await page.getByTestId('admin-hint-input').fill('4e planète')
await page.getByTestId('admin-create-question').click()
await expect(page.getByText('Quelle planète est rouge ?')).toBeVisible()
await page
.getByRole('button', { name: /Modifier/i })
.first()
.click()
await page
.getByTestId('admin-question-input')
.fill('Quelle planète est appelée planète rouge ?')
await page.getByRole('button', { name: /Enregistrer la modification/i }).click()
await expect(page.getByText('Quelle planète est appelée planète rouge ?')).toBeVisible()
await page.getByRole('button', { name: 'Supprimer' }).first().click()
await expect(page.getByText('Quelle planète est appelée planète rouge ?')).toHaveCount(0)
})
test('admin form validation blocks invalid submission', async ({ page }) => {
await page.goto('/admin/questions')
await page.getByTestId('admin-theme-input').fill('')
await page.getByTestId('admin-question-input').fill('')
await page.getByTestId('admin-answer-input').fill('')
await page.getByTestId('admin-create-question').click()
await expect(page.getByText('Theme, question et réponse sont requis.')).toBeVisible()
})
})
test.describe('critical frontend flows - mobile viewport', () => {
test.use({ viewport: { width: 390, height: 844 } })
test('mobile player flow keeps core controls visible', async ({ page }) => {
await page.goto('/')
await page.evaluate(() => {
localStorage.clear()
})
const mobileNameInput = page.getByTestId('home-player-name-input')
await mobileNameInput.evaluate((el) => {
const input = el as HTMLInputElement
input.value = 'Mobile Player'
input.dispatchEvent(new Event('input', { bubbles: true }))
input.dispatchEvent(new Event('change', { bubbles: true }))
})
await page.getByRole('button', { name: 'Démarrer la partie' }).click()
await expect(page).toHaveURL(/\/game$/)
await expect(page.getByRole('button', { name: 'Envoyer' })).toBeVisible()
await expect(page.getByRole('button', { name: 'Indice (score réduit)' })).toBeVisible()
await expect(page.getByLabel('Ta réponse')).toBeVisible()
})
})