// week.mjs — B8 and B9 measured in a real browser. // // Driven by TestWeekAndAllDayFormInARealBrowser, which seeds the week // of 5 October 2026 with an all-day note and two timed events on the // Wednesday, plus an all-day event whose edit URL it passes in. // // 1. Every timed column starts at the same height, whatever sits in // the all-day row above it. // 2. The 10:00 chip is drawn at the 10:00 line, not an hour down. // 3. A 30-minute chip's title is painted inside the chip. // 4. An all-day event's edit form holds its dates — checked through // input.value, which is what a submit sends. import { chromium } from 'playwright'; const [origin, cookieName, cookieValue, editPath] = process.argv.slice(2); if (!origin || !cookieName || !cookieValue || !editPath) { console.error('usage: week.mjs '); process.exit(2); } const failures = []; function check(ok, what) { if (ok) { console.log('ok: ' + what); return; } failures.push(what); console.error('FAIL: ' + what); } const browser = await chromium.launch(); const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 } }); await ctx.addCookies([{ name: cookieName, value: cookieValue, url: origin, httpOnly: true }]); const page = await ctx.newPage(); // ── 1–3. The week ───────────────────────────────────────────────────── await page.goto(origin + '/week/2026-10-07', { waitUntil: 'networkidle' }); const geo = await page.evaluate(() => { const cols = [...document.querySelectorAll('[cal-column]')].map((c) => c.getBoundingClientRect().top); const hourPx = document.querySelector('[cal-hour]').getBoundingClientRect().height; const chip = (title) => { const t = [...document.querySelectorAll('[cal-placed] [cal-chip-title]')].find((s) => s.textContent.includes(title)); if (!t) return null; const chipBox = t.closest('[cal-chip]').getBoundingClientRect(); const titleBox = t.getBoundingClientRect(); const colTop = t.closest('[cal-column]').getBoundingClientRect().top; return { chipTop: chipBox.top, chipBottom: chipBox.bottom, titleTop: titleBox.top, titleBottom: titleBox.bottom, titleWidth: titleBox.width, colTop }; }; // Where the 10:00 LABEL draws its line: the label box minus the // translate that lifts it onto the rule it names. const label = document.querySelectorAll('[cal-hour]')[10]; const lift = new DOMMatrix(getComputedStyle(label).transform).m42; const tenLine = label.getBoundingClientRect().top - lift; return { cols, hourPx, tenLine, focus: chip('Focus time'), quick: chip('Quick sync') }; }); console.log(JSON.stringify(geo)); check(geo.cols.length === 7, `seven timed columns (got ${geo.cols.length})`); check(geo.cols.every((top) => Math.abs(top - geo.cols[0]) < 0.5), `every timed column starts at the same height (${geo.cols.join(', ')})`); check(geo.focus && Math.abs(geo.focus.chipTop - geo.tenLine) < 2, `the 10:00 chip is beside the 10:00 label (chip ${geo.focus?.chipTop}, label line ${geo.tenLine})`); check(geo.quick && geo.quick.titleWidth > 8 && geo.quick.titleBottom - geo.quick.titleTop >= 12 && geo.quick.titleTop >= geo.quick.chipTop - 0.5 && geo.quick.titleBottom <= geo.quick.chipBottom + 0.5, `the 30-minute chip paints its title inside itself (${JSON.stringify(geo.quick)})`); await page.screenshot({ path: '/tmp/calendar-week-allday.png', fullPage: false }); // ── 4. The all-day edit form, with and without script ───────────────── for (const js of [true, false]) { const c = await browser.newContext({ javaScriptEnabled: js }); await c.addCookies([{ name: cookieName, value: cookieValue, url: origin, httpOnly: true }]); const p = await c.newPage(); await p.goto(origin + editPath, { waitUntil: 'networkidle' }); const values = await p.evaluate(() => ({ start: document.querySelector('input[name="start"]').value, end: document.querySelector('input[name="end"]').value, })); check(values.start === '2026-10-12' && values.end === '2026-10-14', `all-day edit form holds its dates, js=${js} (${JSON.stringify(values)})`); await c.close(); } await browser.close(); if (failures.length) { console.error(`${failures.length} check(s) failed`); process.exit(1); } console.log('all week/all-day checks passed');