[object Object]

← back to Estimate Instant

Bound JSON parsing and validate roll snapshots

28cfeb66ecfbf001a3ba94f966546c99f8931c40 · 2026-08-29 06:28:15 -0700 · Steve Abrams

Files touched

Diff

commit 28cfeb66ecfbf001a3ba94f966546c99f8931c40
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Aug 29 06:28:15 2026 -0700

    Bound JSON parsing and validate roll snapshots
---
 test/calculate-coverage.test.js | 50 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/test/calculate-coverage.test.js b/test/calculate-coverage.test.js
index a4ed230..9cd0e3a 100644
--- a/test/calculate-coverage.test.js
+++ b/test/calculate-coverage.test.js
@@ -2,8 +2,9 @@
 
 const test = require('node:test');
 const assert = require('node:assert/strict');
+const { EventEmitter } = require('node:events');
 const http = require('node:http');
-const { calculateCoverage, handleRequest } = require('../server.js');
+const { body, calculateCoverage, handleRequest, loadRolls, validateRollSnapshot, MAX_JSON_BODY_BYTES } = require('../server.js');
 
 const roll = {
   sku: 'DW-TEST-1',
@@ -150,4 +151,51 @@ test('serves the real local HTTP journey and returns 400 on bad input', async (t
   });
   assert.equal(bad.status, 400);
   assert.equal((await bad.json()).ok, false);
+
+  for (const route of ['/api/calculate-coverage', '/api/estimate', '/api/lead']) {
+    const malformed = await fetch(`${base}${route}`, {
+      method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{bad',
+    });
+    assert.equal(malformed.status, 400, route);
+    assert.match((await malformed.json()).error, /malformed or invalid UTF-8 JSON/i);
+
+    const oversized = await fetch(`${base}${route}`, {
+      method: 'POST', headers: { 'Content-Type': 'application/json' },
+      body: JSON.stringify({ padding: 'x'.repeat(MAX_JSON_BODY_BYTES) }),
+    });
+    assert.equal(oversized.status, 413, route);
+    assert.match((await oversized.json()).error, /exceeds/i);
+  }
+});
+
+test('parses split UTF-8 exactly and settles aborted bodies', async () => {
+  const encoded = Buffer.from(JSON.stringify({ name: 'café ����' }));
+  const split = encoded.indexOf(Buffer.from('����')) + 2;
+  const req = new EventEmitter();
+  const parsedPromise = body(req);
+  req.emit('data', encoded.subarray(0, split));
+  req.emit('data', encoded.subarray(split));
+  req.emit('end');
+  assert.deepEqual(await parsedPromise, { ok: true, value: { name: 'café ����' } });
+
+  const aborted = new EventEmitter();
+  const abortedPromise = body(aborted);
+  aborted.emit('data', Buffer.from('{"name":'));
+  aborted.emit('aborted');
+  assert.deepEqual(await abortedPromise, { ok: false, status: 400, error: 'Request body was aborted.' });
+});
+
+test('validates the complete checked-in roll snapshot and rejects bad schemas', () => {
+  const actual = loadRolls();
+  assert.equal(validateRollSnapshot(actual).ok, true);
+  for (const broken of [
+    [],
+    [{ ...roll, roll_width_in: 0 }],
+    [{ ...roll, match: 'mystery' }],
+    [{ ...roll, shopify_match: true, shopify_sku: '', shopify_price: 0 }],
+    [{ ...roll }, { ...roll }],
+    [{ ...roll, sku: ' DW-TEST-1' }],
+    [{ ...roll, match: ' half-drop ' }],
+    [{ ...roll, shopify_sku: ' DW-SHOPIFY-1 ' }],
+  ]) assert.equal(validateRollSnapshot(broken).ok, false);
 });

← 014cf2e fix: return HTTP 400 on estimate error (null roll / invalid  ·  back to Estimate Instant  ·  Persist parser boundary regressions 943a9a7 →