// Exercises the exact regression: an empty 200 body must throw, not resolve to undefined. const { getJson, HttpError } = await import('/tmp/prt-test/client.mjs'); let pass = 0, fail = 0; const check = (name, ok) => { ok ? (pass++, console.log(' PASS', name)) : (fail++, console.log(' FAIL', name)); }; // 1. Real endpoint still works. const cat = await getJson('http://127.0.0.1:3500/api/catalog'); check('catalog loads', cat.products.length === 179); // 2. Empty 200 body -> throws (previously: JSON.parse crash that killed Promise.all). globalThis.fetch = async () => new Response('', { status: 200 }); try { await getJson('/empty'); check('empty body throws', false); } catch (e) { check('empty body throws HttpError', e instanceof HttpError && /Empty response/.test(e.message)); } // 3. 404 surfaces its status so the caller can show "not found" instead of an error. globalThis.fetch = async () => new Response(JSON.stringify({error:'Not found'}), { status: 404 }); try { await getJson('/missing'); check('404 throws', false); } catch (e) { check('404 carries status', e.status === 404 && e.message === 'Not found'); } // 4. A transient failure is retried once and then succeeds. let n = 0; globalThis.fetch = async () => (++n === 1 ? new Response('', { status: 200 }) : new Response(JSON.stringify({ok:true}), { status: 200 })); check('retries once then succeeds', (await getJson('/flaky')).ok === true && n === 2); console.log(`\n${pass} passed, ${fail} failed`); process.exit(fail ? 1 : 0);