diff --git a/docker/index.html b/docker/index.html index 778f555..790e601 100644 --- a/docker/index.html +++ b/docker/index.html @@ -1942,8 +1942,8 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food- .toast { position: fixed; bottom: 80px; - left: 16px; right: 16px; + max-width: calc(100% - 32px); background: var(--text); color: var(--white); padding: 10px 20px; @@ -1951,12 +1951,12 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food- font-size: var(--font-sm); font-weight: 500; z-index: 300; - animation: slideUp 0.35s cubic-bezier(0.16, 1, 0.3, 1) both; + animation: slideInRight 0.35s cubic-bezier(0.16, 1, 0.3, 1) both; text-align: center; pointer-events: none; } .toast.hiding { - animation: slideDown 0.25s ease-in both; + animation: slideOutRight 0.3s ease-in both; } /* -- Stepper -- */ diff --git a/index.html b/index.html index 778f555..790e601 100644 --- a/index.html +++ b/index.html @@ -1942,8 +1942,8 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food- .toast { position: fixed; bottom: 80px; - left: 16px; right: 16px; + max-width: calc(100% - 32px); background: var(--text); color: var(--white); padding: 10px 20px; @@ -1951,12 +1951,12 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food- font-size: var(--font-sm); font-weight: 500; z-index: 300; - animation: slideUp 0.35s cubic-bezier(0.16, 1, 0.3, 1) both; + animation: slideInRight 0.35s cubic-bezier(0.16, 1, 0.3, 1) both; text-align: center; pointer-events: none; } .toast.hiding { - animation: slideDown 0.25s ease-in both; + animation: slideOutRight 0.3s ease-in both; } /* -- Stepper -- */ diff --git a/test-results/.last-run.json b/test-results/.last-run.json deleted file mode 100644 index cbcc1fb..0000000 --- a/test-results/.last-run.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "status": "passed", - "failedTests": [] -} \ No newline at end of file diff --git a/tests/e2e.spec.js b/tests/e2e.spec.js index 8c1d666..449c175 100644 --- a/tests/e2e.spec.js +++ b/tests/e2e.spec.js @@ -89,13 +89,11 @@ test.describe('Karby Eetdagboek', () => { await page.waitForTimeout(800); await page.locator('.food-item').first().click(); await page.waitForTimeout(500); - // Open add-to-meal modal (hier zitten de steppers) await page.locator('#detailAddBtn').click(); await page.waitForTimeout(500); const steppers = page.locator('.portie-stepper'); await expect(steppers.first()).toBeVisible({ timeout: 3000 }); expect(await steppers.count()).toBeGreaterThan(0); - // Eerste stepper heeft count=1 await expect(steppers.first().locator('.portie-stepper-count')).toHaveText('1'); }); @@ -110,12 +108,9 @@ test.describe('Karby Eetdagboek', () => { const steppers = page.locator('.portie-stepper'); const count = await steppers.count(); if (count < 2) { test.skip(); return; } - // + op tweede stepper await steppers.nth(1).locator('.portie-stepper-plus').click(); await page.waitForTimeout(100); - // Eerste moet 0 zijn (gereset) await expect(steppers.first().locator('.portie-stepper-count')).toHaveText('0'); - // Tweede moet 1 zijn await expect(steppers.nth(1).locator('.portie-stepper-count')).toHaveText('1'); }); @@ -128,12 +123,9 @@ test.describe('Karby Eetdagboek', () => { await page.locator('#detailAddBtn').click(); await page.waitForTimeout(500); const firstStepper = page.locator('.portie-stepper').first(); - // Default count = 1 await expect(firstStepper.locator('.portie-stepper-count')).toHaveText('1'); - // Minus klikken → 0 await firstStepper.locator('.portie-stepper-minus').click(); await expect(firstStepper.locator('.portie-stepper-count')).toHaveText('0'); - // Minus moet nu disabled zijn (niet negatief) await expect(firstStepper.locator('.portie-stepper-minus')).toBeDisabled(); }); @@ -146,13 +138,15 @@ test.describe('Karby Eetdagboek', () => { await page.locator('#detailAddBtn').click(); await page.waitForTimeout(500); const firstStepper = page.locator('.portie-stepper').first(); - // active class is pas aanwezig na updatePortionFromSteppers (triggered door +/-) - // Eerst: plus klikken om active te krijgen + // active class na updatePortionFromSteppers triggeren via plus await firstStepper.locator('.portie-stepper-plus').click(); await page.waitForTimeout(100); await expect(firstStepper).toHaveClass(/active/); - // Minus naar 0 → active verliezen + // Minus 2×: 2→1→0, dan active kwijt await firstStepper.locator('.portie-stepper-minus').click(); + await page.waitForTimeout(50); + await firstStepper.locator('.portie-stepper-minus').click(); + await page.waitForTimeout(50); await expect(firstStepper).not.toHaveClass(/active/); }); @@ -177,14 +171,11 @@ test.describe('Karby Eetdagboek', () => { const overlay = page.locator('#settingsModal'); await expect(overlay).toBeVisible(); await expect(overlay).not.toHaveClass(/closing/); - // .modal-overlay heeft animation: fadeIn const overlayAnim = await overlay.evaluate(el => getComputedStyle(el).animationName); expect(overlayAnim).toBe('fadeIn'); - // .modal-sheet heeft animation: slideUp const sheet = overlay.locator('.modal-sheet'); const sheetAnim = await sheet.evaluate(el => getComputedStyle(el).animationName); expect(sheetAnim).toBe('slideUp'); - // Sluiten voor opschoning await page.locator('#settingsModal .modal-close').click(); await page.waitForTimeout(500); }); @@ -203,82 +194,52 @@ test.describe('Karby Eetdagboek', () => { test('meal save: name input is empty by default', async ({ page }) => { await page.goto(BASE); - // Zoek + open detail await page.locator('.search-input').fill('brood'); await page.waitForTimeout(800); await page.locator('.food-item').first().click(); await page.waitForTimeout(500); - // Toevoegen aan eetmoment await page.locator('#detailAddBtn').click(); await page.waitForTimeout(500); - // Terug naar dagboek (sluit addMealModal eerst) - await page.locator('#addMealModal .modal-close').click(); - await page.waitForTimeout(300); - // Sluit detail modal - await page.locator('#detailModal .modal-close').click(); - await page.waitForTimeout(300); - // Naar dagboek tab - await page.locator('#navDagboek').click(); - await page.waitForTimeout(600); - // Zoek save-meal btn en klik + // Item toevoegen via addMealSubmit → sluit modal + gaat naar dagboek + await page.locator('#addMealSubmit').click(); + await page.waitForTimeout(800); const saveBtn = page.locator('.save-meal-btn'); - if (await saveBtn.count() === 0) { - test.skip('geen items in dagboek'); - return; - } + await expect(saveBtn.first()).toBeVisible({ timeout: 5000 }); await saveBtn.first().click(); await page.waitForTimeout(500); const nameInput = page.locator('#mealNameInput'); await expect(nameInput).toBeVisible({ timeout: 5000 }); - // Naamveld moet leeg zijn await expect(nameInput).toHaveValue(''); - // Annuleren await page.locator('#mealNameCancel').click(); await page.waitForTimeout(300); }); test('meal save: empty name toont rode rand en modal blijft open', async ({ page }) => { await page.goto(BASE); - // Zoek + open detail await page.locator('.search-input').fill('brood'); await page.waitForTimeout(800); await page.locator('.food-item').first().click(); await page.waitForTimeout(500); - // Toevoegen aan eetmoment await page.locator('#detailAddBtn').click(); await page.waitForTimeout(500); - // Sluit addMealModal - await page.locator('#addMealModal .modal-close').click(); - await page.waitForTimeout(300); - // Sluit detail modal - await page.locator('#detailModal .modal-close').click(); - await page.waitForTimeout(300); - // Naar dagboek - await page.locator('#navDagboek').click(); - await page.waitForTimeout(600); - // Opslaan als maaltijd + await page.locator('#addMealSubmit').click(); + await page.waitForTimeout(800); const saveBtn = page.locator('.save-meal-btn'); - if (await saveBtn.count() === 0) { - test.skip('geen items in dagboek'); - return; - } + await expect(saveBtn.first()).toBeVisible({ timeout: 5000 }); await saveBtn.first().click(); await page.waitForTimeout(500); const nameInput = page.locator('#mealNameInput'); await expect(nameInput).toBeVisible({ timeout: 5000 }); await expect(nameInput).toHaveValue(''); - // Opslaan zonder naam + // Opslaan zonder naam → validatiefout await page.locator('#mealNameSave').click(); await page.waitForTimeout(300); - // Modal moet nog open zijn (niet gesloten) await expect(nameInput).toBeVisible(); - // Input border moet rood zijn (validation) const borderColor = await nameInput.evaluate(el => getComputedStyle(el).borderColor); const rgb = borderColor.match(/\d+/g).map(Number); - expect(rgb[0]).toBeGreaterThan(150); // R > 150 - expect(rgb[1]).toBeLessThan(100); // G < 100 - expect(rgb[2]).toBeLessThan(100); // B < 100 - // Annuleren + expect(rgb[0]).toBeGreaterThan(150); + expect(rgb[1]).toBeLessThan(100); + expect(rgb[2]).toBeLessThan(100); await page.locator('#mealNameCancel').click(); await page.waitForTimeout(300); }); @@ -290,13 +251,11 @@ test.describe('Karby Eetdagboek', () => { await page.locator('#navDagboek').click(); await page.waitForTimeout(500); const initialDay = await page.locator('#dayLabel').textContent(); - // Next day (tweede .day-nav-btn) const nextBtn = page.locator('.day-nav-btn').nth(1); await nextBtn.click(); await page.waitForTimeout(300); const nextDay = await page.locator('#dayLabel').textContent(); expect(nextDay).not.toBe(initialDay); - // Today reset await page.locator('.day-nav-today').click(); await page.waitForTimeout(300); const todayDay = await page.locator('#dayLabel').textContent(); @@ -336,24 +295,15 @@ test.describe('Karby Eetdagboek', () => { await page.waitForTimeout(800); await page.locator('.food-item').first().click(); await page.waitForTimeout(500); - // Stap 2: Voeg toe aan eetmoment + // Stap 2: Voeg toe via detailAddBtn → addMealModal await page.locator('#detailAddBtn').click(); await page.waitForTimeout(500); - // Sluit addMealModal - await page.locator('#addMealModal .modal-close').click(); - await page.waitForTimeout(300); - // Sluit detail modal (anders overlay intercepteert nav knoppen) - await page.locator('#detailModal .modal-close').click(); - await page.waitForTimeout(300); - // Stap 3: Naar dagboek - await page.locator('#navDagboek').click(); - await page.waitForTimeout(600); + // Stap 3: Klik Toevoegen in addMealModal → item in dagboek + await page.locator('#addMealSubmit').click(); + await page.waitForTimeout(800); // Stap 4: Opslaan als maaltijd const saveBtn = page.locator('.save-meal-btn'); - if (await saveBtn.count() === 0) { - test.skip('geen items in dagboek — kan geen maaltijd opslaan'); - return; - } + await expect(saveBtn.first()).toBeVisible({ timeout: 5000 }); await saveBtn.first().click(); await page.waitForTimeout(500); // Stap 5: Naam invullen en opslaan @@ -362,22 +312,20 @@ test.describe('Karby Eetdagboek', () => { await nameInput.fill('Test ontbijt'); await page.locator('#mealNameSave').click(); await page.waitForTimeout(600); - // De meal wordt opgeslagen, toast verschijnt - // Stap 6: Ga terug naar dagboek om meal-group te zien + // Stap 6: Ga naar dagboek om meal-group te zien await page.locator('#navDagboek').click(); await page.waitForTimeout(800); - // Stap 7: Zoek de meal-group + // Stap 7: Zoek meal-group const mealGroup = page.locator('.eetmoment-meal-group').first(); await expect(mealGroup).toBeVisible({ timeout: 5000 }); - // Stap 8: Items-wrap begint collapsed (hidden class) + // Stap 8: Items-wrap begint collapsed const itemsWrap = mealGroup.locator('.eetmoment-meal-items-wrap'); await expect(itemsWrap).toHaveClass(/hidden/); - // Stap 9: Klik op header om uit te klappen + // Stap 9: Klik header om uit te klappen const header = mealGroup.locator('.eetmoment-meal-header'); await header.click(); await page.waitForTimeout(300); await expect(itemsWrap).not.toHaveClass(/hidden/); - // Chevron moet naar boven wijzen const chevronUp = header.locator('i.fa-chevron-up'); await expect(chevronUp).toBeVisible(); // Stap 10: Klik opnieuw om in te klappen