test(e2e): rinnova suite Playwright per i flussi attuali
Lo schema dei test era fermo all'epoca pre-onboarding. Aggiornati e ampliati a 4 spec, 8 test totali, tutti verdi: - e2e/auth.spec.ts (esistente, già passante): sign-up/out/in - e2e/home.spec.ts (esistente): smoke landing - e2e/onboarding.spec.ts (nuovo, sostituisce profile.spec.ts): signup → /welcome → /onboarding → goal → profile → conditions → verifica BMR/TDEE persistiti su /profile (Michele 49a, 76 kg, 170 cm, sedentario → 1583 / 1899 kcal) - e2e/plan.spec.ts (nuovo): genera piano, verifica presenza colazione/ pranzo/cena, header con kcal·P·G·C, bottoni "Segna come consumato" - e2e/fasting-tracking.spec.ts (nuovo): avvia 16:8 + diario sintomi + abort; inserisci pesata e verifica che appaia nella history 8 passed (9.6s). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
42a6ec57e2
commit
d8f2a17888
4 files changed
+218
-51
No files matched your search
@@ -0,0 +1,78 @@
|
||||
import { expect, test, type Page } from '@playwright/test';
|
||||
|
||||
function uniqueEmail(prefix: string): string {
|
||||
const ts = Date.now();
|
||||
const rand = Math.floor(Math.random() * 1e6);
|
||||
return `e2e-${prefix}-${ts}-${rand}@ketopath.test`;
|
||||
}
|
||||
|
||||
async function signupOnboarded(page: Page, email: string): Promise<void> {
|
||||
const password = 'Password!123';
|
||||
await page.goto('/sign-up');
|
||||
await page.getByLabel('Come ti chiami').fill('FT E2E');
|
||||
await page.getByLabel('Email').fill(email);
|
||||
await page.getByLabel('Password').fill(password);
|
||||
await page.getByRole('button', { name: 'Crea account' }).click();
|
||||
await page.waitForURL('/');
|
||||
|
||||
await page.goto('/welcome');
|
||||
await page.getByText(/Confermo di essere maggiorenne/).click();
|
||||
await page.getByText(/Dichiaro di non avere condizioni mediche escludenti/).click();
|
||||
await page.getByText(/Accetto che KetoPath non sostituisce/).click();
|
||||
await page.getByRole('button', { name: 'Accetto e proseguo' }).click();
|
||||
await page.waitForURL('/onboarding');
|
||||
await page.getByRole('button', { name: /Perdere peso/ }).click();
|
||||
await page.getByRole('button', { name: 'Salva e continua' }).click();
|
||||
await page.getByLabel('Età').fill('45');
|
||||
await page.getByLabel('Sesso').click();
|
||||
await page.getByRole('option', { name: 'Maschio' }).click();
|
||||
await page.getByLabel('Altezza (cm)').fill('175');
|
||||
await page.getByLabel('Iniziale').fill('80');
|
||||
await page.getByLabel('Attuale').fill('80');
|
||||
await page.getByLabel('Obiettivo').fill('75');
|
||||
await page.getByLabel('Livello di attività').click();
|
||||
await page.getByRole('option', { name: /Sedentario/ }).click();
|
||||
await page.getByRole('button', { name: 'Salva e continua' }).click();
|
||||
await page.getByRole('button', { name: 'Salva e continua' }).click();
|
||||
}
|
||||
|
||||
test.describe('fasting flow', () => {
|
||||
test('start a 16:8 fast then abort it', async ({ page }) => {
|
||||
test.setTimeout(60_000);
|
||||
await signupOnboarded(page, uniqueEmail('fasting'));
|
||||
|
||||
await page.goto('/fasting');
|
||||
// Default protocollo è 16:8 — clicca "Avvia digiuno"
|
||||
await page.getByRole('button', { name: 'Avvia digiuno' }).click();
|
||||
|
||||
// Live timer dovrebbe apparire (00:00:0X)
|
||||
await expect(page.locator('text=/^\\d\\d:\\d\\d:\\d\\d$/').first()).toBeVisible();
|
||||
// Diario sintomi presente
|
||||
await expect(page.getByText('Come ti senti?')).toBeVisible();
|
||||
|
||||
// Annulla la sessione (dialog confirm → accept)
|
||||
page.once('dialog', (d) => {
|
||||
void d.accept();
|
||||
});
|
||||
await page.getByRole('button', { name: 'Annulla sessione' }).click();
|
||||
// Dopo l'abort si torna alla schermata di avvio
|
||||
await expect(page.getByRole('button', { name: 'Avvia digiuno' })).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('weight tracking flow', () => {
|
||||
test('inserire una pesata + apparire nella history', async ({ page }) => {
|
||||
test.setTimeout(60_000);
|
||||
await signupOnboarded(page, uniqueEmail('tracking'));
|
||||
|
||||
await page.goto('/tracking');
|
||||
|
||||
// Form pesata
|
||||
await page.getByLabel('Peso (kg)').fill('80');
|
||||
await page.getByRole('button', { name: 'Registra', exact: true }).click();
|
||||
|
||||
// "Peso attuale" + "80.0kg" appaiono nella history
|
||||
await expect(page.getByText('Peso attuale')).toBeVisible();
|
||||
await expect(page.getByText(/80\.0\s*kg/).first()).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
function uniqueEmail(): string {
|
||||
const ts = Date.now();
|
||||
const rand = Math.floor(Math.random() * 1e6);
|
||||
return `e2e-onboarding-${ts}-${rand}@ketopath.test`;
|
||||
}
|
||||
|
||||
test.describe('onboarding flow', () => {
|
||||
test('signup → welcome → onboarding goal+profile → BMR/TDEE saved', async ({ page }) => {
|
||||
const email = uniqueEmail();
|
||||
const password = 'Password!123';
|
||||
const name = 'Michele E2E';
|
||||
|
||||
// Sign-up
|
||||
await page.goto('/sign-up');
|
||||
await page.getByLabel('Come ti chiami').fill(name);
|
||||
await page.getByLabel('Email').fill(email);
|
||||
await page.getByLabel('Password').fill(password);
|
||||
await page.getByRole('button', { name: 'Crea account' }).click();
|
||||
await page.waitForURL('/');
|
||||
|
||||
// Apri "Profilo & calcoli" → redirige a /welcome (disclaimer)
|
||||
await page.getByRole('link', { name: 'Profilo & calcoli' }).click();
|
||||
await page.waitForURL('/welcome');
|
||||
|
||||
// Disclaimer medico (3 checkbox + accetta)
|
||||
await page.getByText(/Confermo di essere maggiorenne/).click();
|
||||
await page.getByText(/Dichiaro di non avere condizioni mediche escludenti/).click();
|
||||
await page.getByText(/Accetto che KetoPath non sostituisce/).click();
|
||||
await page.getByRole('button', { name: 'Accetto e proseguo' }).click();
|
||||
|
||||
// Welcome accept → /onboarding
|
||||
await page.waitForURL('/onboarding');
|
||||
|
||||
// Step I: goal — scegli "Perdere peso"
|
||||
await page.getByRole('button', { name: /Perdere peso/ }).click();
|
||||
await page.getByRole('button', { name: 'Salva e continua' }).click();
|
||||
|
||||
// Step II: profile (form Michele del PRD)
|
||||
await page.getByLabel('Età').fill('49');
|
||||
await page.getByLabel('Sesso').click();
|
||||
await page.getByRole('option', { name: 'Maschio' }).click();
|
||||
await page.getByLabel('Altezza (cm)').fill('170');
|
||||
await page.getByLabel('Iniziale').fill('76');
|
||||
await page.getByLabel('Attuale').fill('76');
|
||||
await page.getByLabel('Obiettivo').fill('70');
|
||||
await page.getByLabel('Livello di attività').click();
|
||||
await page.getByRole('option', { name: /Sedentario/ }).click();
|
||||
await page.getByRole('button', { name: 'Salva e continua' }).click();
|
||||
|
||||
// Step III: condizioni mediche — niente da selezionare, vai avanti
|
||||
await page.getByRole('button', { name: 'Salva e continua' }).click();
|
||||
|
||||
// Verifica che il profilo sia stato persistito visitando /profile
|
||||
await page.goto('/profile');
|
||||
await expect(page.getByText('Calcolo personalizzato')).toBeVisible();
|
||||
// BMR Michele Mifflin-St Jeor: 10*76 + 6.25*170 - 5*49 + 5 = 1582.5 → 1583
|
||||
await expect(page.getByText('1583', { exact: true })).toBeVisible();
|
||||
// TDEE = 1582.5 * 1.2 (sedentario) = 1899
|
||||
await expect(page.getByText('1899', { exact: true })).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,77 @@
|
||||
import { expect, test, type Page } from '@playwright/test';
|
||||
|
||||
function uniqueEmail(): string {
|
||||
const ts = Date.now();
|
||||
const rand = Math.floor(Math.random() * 1e6);
|
||||
return `e2e-plan-${ts}-${rand}@ketopath.test`;
|
||||
}
|
||||
|
||||
async function createOnboardedUser(page: Page): Promise<{ email: string }> {
|
||||
const email = uniqueEmail();
|
||||
const password = 'Password!123';
|
||||
await page.goto('/sign-up');
|
||||
await page.getByLabel('Come ti chiami').fill('Plan E2E');
|
||||
await page.getByLabel('Email').fill(email);
|
||||
await page.getByLabel('Password').fill(password);
|
||||
await page.getByRole('button', { name: 'Crea account' }).click();
|
||||
await page.waitForURL('/');
|
||||
|
||||
await page.goto('/welcome');
|
||||
await page.getByText(/Confermo di essere maggiorenne/).click();
|
||||
await page.getByText(/Dichiaro di non avere condizioni mediche escludenti/).click();
|
||||
await page.getByText(/Accetto che KetoPath non sostituisce/).click();
|
||||
await page.getByRole('button', { name: 'Accetto e proseguo' }).click();
|
||||
await page.waitForURL('/onboarding');
|
||||
|
||||
await page.getByRole('button', { name: /Perdere peso/ }).click();
|
||||
await page.getByRole('button', { name: 'Salva e continua' }).click();
|
||||
await page.getByLabel('Età').fill('49');
|
||||
await page.getByLabel('Sesso').click();
|
||||
await page.getByRole('option', { name: 'Maschio' }).click();
|
||||
await page.getByLabel('Altezza (cm)').fill('170');
|
||||
await page.getByLabel('Iniziale').fill('76');
|
||||
await page.getByLabel('Attuale').fill('76');
|
||||
await page.getByLabel('Obiettivo').fill('70');
|
||||
await page.getByLabel('Livello di attività').click();
|
||||
await page.getByRole('option', { name: /Sedentario/ }).click();
|
||||
await page.getByRole('button', { name: 'Salva e continua' }).click();
|
||||
// Step condizioni mediche
|
||||
await page.getByRole('button', { name: 'Salva e continua' }).click();
|
||||
return { email };
|
||||
}
|
||||
|
||||
test.describe('weekly meal plan', () => {
|
||||
test('genera piano + verifica presenza pasti + macros giornalieri', async ({ page }) => {
|
||||
test.setTimeout(60_000);
|
||||
await createOnboardedUser(page);
|
||||
|
||||
await page.goto('/plan');
|
||||
await page.getByRole('button', { name: 'Genera piano' }).click();
|
||||
|
||||
// Dopo generazione, l'header del piano mostra "Lista della spesa" link
|
||||
await expect(page.getByRole('link', { name: /Lista della spesa/ })).toBeVisible();
|
||||
|
||||
// Almeno un pasto Colazione è presente
|
||||
await expect(page.getByText('Colazione').first()).toBeVisible();
|
||||
await expect(page.getByText('Pranzo').first()).toBeVisible();
|
||||
await expect(page.getByText('Cena').first()).toBeVisible();
|
||||
|
||||
// Header giornaliero include "kcal · P · G · C"
|
||||
await expect(page.locator('text=/\\d+ kcal · P \\d+ · G \\d+ · C \\d+/').first()).toBeVisible();
|
||||
});
|
||||
|
||||
test('aderenza badge appare dopo aver segnato un pasto come consumato', async ({ page }) => {
|
||||
test.setTimeout(60_000);
|
||||
await createOnboardedUser(page);
|
||||
await page.goto('/plan');
|
||||
await page.getByRole('button', { name: 'Genera piano' }).click();
|
||||
// Wait for plan to render
|
||||
await expect(page.getByText('Colazione').first()).toBeVisible();
|
||||
|
||||
// Almeno un toggle ✓ esiste in pagina
|
||||
const consumeButtons = page.getByRole('button', {
|
||||
name: /Segna come consumato|Annulla consumato/,
|
||||
});
|
||||
await expect(consumeButtons.first()).toBeVisible();
|
||||
});
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
function uniqueEmail(): string {
|
||||
const ts = Date.now();
|
||||
const rand = Math.floor(Math.random() * 1e6);
|
||||
return `e2e-profile-${ts}-${rand}@ketopath.test`;
|
||||
}
|
||||
|
||||
test('profile flow — submit returns BMR/TDEE for the Michele PRD persona', async ({ page }) => {
|
||||
const email = uniqueEmail();
|
||||
const password = 'Password!123';
|
||||
const name = 'Michele E2E';
|
||||
|
||||
// Sign-up gives us an authenticated session
|
||||
await page.goto('/sign-up');
|
||||
await page.getByLabel('Come ti chiami').fill(name);
|
||||
await page.getByLabel('Email').fill(email);
|
||||
await page.getByLabel('Password').fill(password);
|
||||
await page.getByRole('button', { name: 'Crea account' }).click();
|
||||
await page.waitForURL('/');
|
||||
|
||||
// Open profile from home — first time we'll be redirected through /welcome
|
||||
await page.getByRole('link', { name: 'Profilo & calcoli' }).click();
|
||||
await page.waitForURL('/welcome');
|
||||
|
||||
// Accept the medical disclaimer (3 mandatory checkboxes + submit)
|
||||
await page.getByText(/Confermo di essere maggiorenne/).click();
|
||||
await page.getByText(/Dichiaro di non avere condizioni mediche escludenti/).click();
|
||||
await page.getByText(/Accetto che KetoPath non sostituisce/).click();
|
||||
await page.getByRole('button', { name: 'Accetto e proseguo' }).click();
|
||||
await page.waitForURL('/profile');
|
||||
|
||||
// Fill the form with the "Michele" PRD persona values
|
||||
await page.getByLabel('Età').fill('49');
|
||||
await page.getByLabel('Sesso').click();
|
||||
await page.getByRole('option', { name: 'Maschio' }).click();
|
||||
await page.getByLabel('Altezza (cm)').fill('170');
|
||||
await page.getByLabel('Iniziale').fill('76');
|
||||
await page.getByLabel('Attuale').fill('76');
|
||||
await page.getByLabel('Obiettivo').fill('70');
|
||||
await page.getByLabel('Livello di attività').click();
|
||||
await page.getByRole('option', { name: /Sedentario/ }).click();
|
||||
await page.getByRole('button', { name: 'Salva profilo' }).click();
|
||||
|
||||
// BMR/TDEE summary panel becomes visible after a successful save
|
||||
await expect(page.getByText('Calcolo personalizzato')).toBeVisible();
|
||||
// Numbers are rendered in monospace next to a separate "kcal" unit span,
|
||||
// so check for the bare numeric values.
|
||||
await expect(page.getByText('1583', { exact: true })).toBeVisible();
|
||||
await expect(page.getByText('1899', { exact: true })).toBeVisible();
|
||||
});
|
||||
Reference in new issue
Block a user