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