← back to Dw Photo Capture
5x/tools/captures-missing-check.cjs
31 lines
// Regression check for sweep-1 fix #6: a FRONT-only item counts as missing_back and its card is .miss;
// a single-shot 'photo' item (remote cam) is neither counted nor flagged. Runs in each engine.
const pw = require(process.env.PW || '/Users/macstudio3/Projects/carnegie-internal/node_modules/playwright');
const BASE = process.env.BASE || 'http://127.0.0.1:9987';
(async () => { let bad = 0;
const b0 = await pw.chromium.launch(); const c0 = await b0.newContext({ httpCredentials: { username: 'admin', password: 'DW2024!' } }); const p0 = await c0.newPage();
await p0.goto(BASE + '/healthz');
const jpg = await p0.evaluate(() => { const c = document.createElement('canvas'); c.width = 200; c.height = 150; const g = c.getContext('2d'); g.fillStyle = '#48c'; g.fillRect(0, 0, 200, 150); return c.toDataURL('image/jpeg', .9); });
const post = (u, body) => p0.evaluate(async ([u, body]) => (await fetch(u, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) })).json(), [u, body]);
const before = await p0.evaluate(async () => (await fetch('/api/captures?limit=2000')).json());
const r1 = await post('/api/photo', { dw_sku: 'FRONTONLY-1', dataUrl: jpg, side: 'front' });
const r2 = await post('/api/photo', { dw_sku: 'SINGLESHOT-1', dataUrl: jpg });
const after = await p0.evaluate(async () => (await fetch('/api/captures?limit=2000')).json());
const d = after.missing_back - before.missing_back;
console.log(`${d === 1 ? 'PASS' : 'FAIL'} missing_back delta = ${d} (want 1: front-only counts, photo-only does not)`); if (d !== 1) bad++;
await b0.close();
for (const e of ['chromium', 'webkit', 'firefox']) {
const b = await pw[e].launch(); const ctx = await b.newContext({ httpCredentials: { username: 'admin', password: 'DW2024!' } }); const p = await ctx.newPage();
await p.goto(BASE + '/captures'); await p.waitForSelector('.card');
const st = await p.evaluate(() => { const card = sku => [...document.querySelectorAll('.card')].find(c => c.querySelector('.sku').textContent.startsWith(sku));
const f = card('FRONTONLY-1'), s = card('SINGLESHOT-1');
return { frontMiss: f && f.classList.contains('miss'), frontGap: f && /no BACK/.test(f.textContent), singleMiss: s && s.classList.contains('miss') }; });
await p.selectOption('#sort', 'missing'); await p.waitForTimeout(200);
const firstNonMissIdx = await p.evaluate(() => { const cs = [...document.querySelectorAll('.card')]; const i = cs.findIndex(c => !c.classList.contains('miss')); const j = cs.map(c => c.classList.contains('miss')).lastIndexOf(true); return { i, j }; });
const ok = st.frontMiss && st.frontGap && st.singleMiss === false && (firstNonMissIdx.j < firstNonMissIdx.i || firstNonMissIdx.j === -1);
console.log(`${ok ? 'PASS' : 'FAIL'} ${e}: ${JSON.stringify(st)} sort=missing groups flagged first ${JSON.stringify(firstNonMissIdx)}`); if (!ok) bad++;
await p.evaluate(() => localStorage.clear()); await b.close();
}
process.exit(bad ? 1 : 0);
})();