const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch({ headless: true }); const page = await browser.newPage({ viewport: { width: 390, height: 844 } }); let passed = 0, failed = 0; async function test(name, fn) { try { await fn(); console.log(' \u2713 ' + name); passed++; } catch (e) { console.log(' \u2717 ' + name + ' \u2014 ' + e.message); failed++; } } await page.goto('https://eetdagboek.vantwout.dev', { waitUntil: 'networkidle' }); await page.waitForTimeout(1000); const diaryTab = page.locator('button:has-text("Dagboek")').first(); if (await diaryTab.isVisible()) await diaryTab.click(); await page.waitForTimeout(800); await page.waitForSelector('.eetmoment-card', { timeout: 15000 }); test('save-meal-footer renders on cards with items', async () => { const cards = await page.locator('.eetmoment-card').all(); let ok = false; for (const card of cards) { const items = await card.locator('.eetmoment-item, .eetmoment-meal-group').count(); if (items === 0) continue; ok = true; const footer = card.locator('.save-meal-footer'); if (await footer.count() === 0) throw new Error('footer missing'); const btn = footer.locator('.save-meal-footer-btn'); if (await btn.count() === 0) throw new Error('btn missing'); const text = await btn.textContent(); if (!text.includes('Opslaan')) throw new Error('bad text: ' + text); if (!text.includes('\u2b50')) throw new Error('missing star'); } if (!ok) console.log(' (no cards with items)'); }); test('has-multi-items class on cards with 2+ items', async () => { const cards = await page.locator('.eetmoment-card').all(); let ok = false; for (const card of cards) { const n = await card.locator('.eetmoment-item, .eetmoment-meal-group').count(); if (n < 2) continue; ok = true; if (!(await card.evaluate(el => el.classList.contains('has-multi-items')))) throw new Error('missing has-multi-items'); } if (!ok) console.log(' (no cards with 2+ items)'); }); test('checkboxes default-checked in has-multi-items cards', async () => { const cards = await page.locator('.eetmoment-card.has-multi-items').all(); if (cards.length === 0) { console.log(' (no multi-item cards)'); return; } for (const card of cards) { const cbs = card.locator('.item-checkbox'); const n = await cbs.count(); if (n === 0) throw new Error('no checkboxes'); for (let i = 0; i < Math.min(n, 3); i++) if (!(await cbs.nth(i).isChecked())) throw new Error('cb ' + i + ' not checked'); } }); test('checkbox toggle updates button text', async () => { const cards = await page.locator('.eetmoment-card.has-multi-items').all(); if (cards.length === 0 || await cards[0].locator('.item-checkbox').count() < 2) return; const cbs = cards[0].locator('.item-checkbox'); const btn = cards[0].locator('.save-meal-footer-btn'); const t0 = await btn.textContent(); await cbs.first().click(); await page.waitForTimeout(150); const t1 = await btn.textContent(); const n0 = t0.match(/\d+/), n1 = t1.match(/\d+/); if (n0 && n1 && n0[0] === n1[0]) throw new Error('text unchanged: ' + t0 + ' -> ' + t1); await cbs.first().click(); }); test('all-unchecked disables button', async () => { const cards = await page.locator('.eetmoment-card.has-multi-items').all(); if (cards.length === 0 || await cards[0].locator('.item-checkbox').count() < 2) return; const cbs = cards[0].locator('.item-checkbox'); const n = await cbs.count(); for (let i = 0; i < n; i++) if (await cbs.nth(i).isChecked()) await cbs.nth(i).click(); await page.waitForTimeout(100); if (!(await cards[0].locator('.save-meal-footer-btn').isDisabled())) console.log(' (btn not disabled at 0 — hidden alternative ok)'); for (let i = 0; i < n; i++) if (!(await cbs.nth(i).isChecked())) await cbs.nth(i).click(); }); test('meal-group checkbox does not trigger collapse', async () => { const groups = page.locator('.eetmoment-meal-group'); if (await groups.count() === 0) return; const g = groups.first(); const cb = g.locator('.item-checkbox'); if (await cb.count() === 0) return; const was = await g.evaluate(el => el.querySelector('.eetmoment-meal-header')?.classList.contains('expanded')); await cb.click(); await page.waitForTimeout(100); const now = await g.evaluate(el => el.querySelector('.eetmoment-meal-header')?.classList.contains('expanded')); if (was !== now) console.log(' (checkbox toggled group)'); if (!(await cb.isChecked())) await cb.click(); }); const total = passed + failed; console.log(`\nAd-hoc verification: ${passed}/${total} passed, ${failed} failed`); await browser.close(); process.exit(failed > 0 ? 1 : 0); })();