import { expect, test } from '@nuxt/test-utils/playwright' import type { Page } from '@playwright/test' test.describe('API de geocodage', () => { test('resout une ville en coordonnees', async ({ request }) => { const res = await request.get('/api/geocode?q=lille') expect(res.ok()).toBeTruthy() const places = await res.json() expect(places.length).toBeGreaterThan(0) expect(places[0].lat).toBeCloseTo(50.63, 1) expect(places[0].lon).toBeCloseTo(3.05, 1) }) test('trouve une ville hors de France', async ({ request }) => { const res = await request.get('/api/geocode?q=Bruxelles') const places = await res.json() // La BAN ignore la Belgique : sans Photon, on retomberait sur un hameau du Loiret. const belge = places.find((p: { label: string }) => p.label.includes('Belgique')) expect(belge).toBeDefined() expect(belge.lat).toBeCloseTo(50.85, 1) }) test('renvoie un tableau vide sur une saisie trop courte', async ({ request }) => { const res = await request.get('/api/geocode?q=li') expect(await res.json()).toEqual([]) }) }) test.describe('Comparateur', () => { const bouton = (page: Page) => page.getByRole('button', { name: 'Comparer', exact: true }) /** Remplit un champ puis choisit une proposition dans SA propre liste. */ async function choisir(page: Page, id: string, champ: string, saisie: string, index = 0) { await page.getByLabel(champ).fill(saisie) await page.locator(`#${id}-list [role="option"]`).nth(index).click() } async function comparer(page: Page) { await choisir(page, 'from', 'Départ', 'Lille', 0) await choisir(page, 'to', 'Arrivée', 'Bruxelles', 1) await bouton(page).click() } test.beforeEach(async ({ page }) => { // On simule les appels sortants : un test e2e ne doit dependre // ni du quota OpenRouteService ni de la disponibilite de Transitous. await page.route('**/api/geocode**', route => route.fulfill({ json: [ { label: 'Lille, France', lat: 50.6292, lon: 3.0573 }, { label: 'Bruxelles, Belgique', lat: 50.8503, lon: 4.3517 }, ], })) await page.route('**/api/compare', route => route.fulfill({ json: [ { mode: 'bike', distanceKm: 116, durationMin: 402, co2Grams: 0 }, { mode: 'train', distanceKm: 97, durationMin: 136, co2Grams: 2339, transfers: 2 }, { mode: 'bus', distanceKm: 97, durationMin: 137, co2Grams: 3321, transfers: 2 }, { mode: 'electric_car', distanceKm: 118, durationMin: 86, co2Grams: 12176 }, ], })) await page.goto('/') }) test('interdit le calcul tant qu aucun lieu n est choisi', async ({ page }) => { await expect(bouton(page)).toBeDisabled() }) test('ferme la liste apres selection sans la rouvrir', async ({ page }) => { await choisir(page, 'from', 'Départ', 'Lille', 0) // Le watch se redeclenchait sur la valeur ecrite par select() et rouvrait // la liste : le champ suivant devenait inatteignable a la souris. await page.waitForTimeout(600) await expect(page.locator('#from-list')).toHaveCount(0) }) test('reflete le modele quand il change de l exterieur', async ({ page }) => { await choisir(page, 'from', 'Départ', 'Lille', 0) await choisir(page, 'to', 'Arrivée', 'Bruxelles', 1) // Sans watch sur le modele, l'inversion laissait les champs inchanges // et l'affichage mentait sur ce qui allait etre calcule. await page.getByRole('button', { name: 'Inverser' }).click() await expect(page.getByLabel('Départ')).toHaveValue('Bruxelles, Belgique') await expect(page.getByLabel('Arrivée')).toHaveValue('Lille, France') }) test('interdit le calcul si la saisie ne correspond plus au lieu choisi', async ({ page }) => { await choisir(page, 'from', 'Départ', 'Lille', 0) await choisir(page, 'to', 'Arrivée', 'Bruxelles', 1) await expect(bouton(page)).toBeEnabled() await page.getByLabel('Arrivée').fill('Bruxel') await expect(bouton(page)).toBeDisabled() }) test('lance un calcul depuis un trajet d exemple', async ({ page }) => { await page.getByRole('button', { name: 'Lille → Paris' }).click() await expect(page.getByRole('heading', { level: 3 })).toHaveCount(4) }) test('affiche les quatre modes du plus sobre au plus emetteur', async ({ page }) => { await comparer(page) // Le titre porte aussi le chevron et la duree : on cherche le libelle // dans son contenu plutot qu'une egalite stricte. const titles = page.getByRole('heading', { level: 3 }) await expect(titles).toHaveCount(4) await expect(titles.nth(0)).toContainText('Vélo') await expect(titles.nth(3)).toContainText('Voiture électrique') }) test('rappelle les lieux reellement compares', async ({ page }) => { await comparer(page) const rappel = page.getByRole('heading', { level: 2 }) await expect(rappel).toContainText('Lille, France') await expect(rappel).toContainText('Bruxelles, Belgique') }) test('affiche les correspondances des transports en commun', async ({ page }) => { await comparer(page) await expect(page.getByText('2 corresp.').first()).toBeVisible() }) test('convertit les emissions en kilogrammes au-dela de mille grammes', async ({ page }) => { await comparer(page) await expect(page.getByText('12.2 kg CO₂e')).toBeVisible() await expect(page.getByText('0 g CO₂e')).toBeVisible() }) test('previent l utilisateur quand le calcul echoue', async ({ page }) => { await page.route('**/api/compare', route => route.fulfill({ status: 500, json: {} })) await comparer(page) await expect(page.getByRole('alert')).toBeVisible() }) })