← back to Estimate Instant

test/calculate-coverage.test.js

216 lines

'use strict';

const test = require('node:test');
const assert = require('node:assert/strict');
const { EventEmitter } = require('node:events');
const http = require('node:http');
const { body, calculateCoverage, handleRequest, loadRolls, validateRollSnapshot, MAX_JSON_BODY_BYTES } = require('../server.js');

const roll = {
  sku: 'DW-TEST-1',
  shopify_sku: 'DW-SHOPIFY-1',
  pattern: 'Test Pattern',
  roll_width_in: 24,
  roll_length_ft: 30,
  pattern_repeat_in: 0,
  match: 'straight',
  price_per_roll: 100,
  shopify_price: 100,
  shopify_match: true,
};

test('calculates the documented room contract without external data', () => {
  const result = calculateCoverage({
    sku: 'dw-test-1', room_width_ft: 10, room_height_ft: 8, num_walls: 4,
  }, [roll], 'example.test');
  assert.equal(result.ok, true);
  assert.equal(result.rolls_needed, 7);
  assert.equal(result.total_cost, 700);
  assert.equal(result.quote_authoritative, true);
  assert.equal(result.data_source, 'local-rollspec-snapshot');
  assert.match(result.notes.join(' '), /confirm current specifications and price/i);
});

test('rejects false-match Shopify aliases and withholds prototype pricing', () => {
  const prototype = { ...roll, sku: 'DW-PROTOTYPE', shopify_sku: 'DW-STANDIN', shopify_match: false };
  const alias = calculateCoverage({
    sku: 'DW-STANDIN', room_width_ft: 10, room_height_ft: 8, num_walls: 1,
  }, [prototype]);
  assert.equal(alias.ok, false);

  const local = calculateCoverage({
    sku: 'DW-PROTOTYPE', room_width_ft: 10, room_height_ft: 8, num_walls: 1,
  }, [prototype]);
  assert.equal(local.ok, true);
  assert.equal(local.total_cost, null);
  assert.equal(local.price_per_roll, null);
  assert.equal(local.quote_authoritative, false);
  assert.match(local.notes.join(' '), /pricing is withheld/i);
});

test('accepts the Shopify SKU alias', () => {
  const result = calculateCoverage({
    sku: 'DW-SHOPIFY-1', room_width_ft: 10, room_height_ft: 8, num_walls: 1,
  }, [roll], 'example.test');
  assert.equal(result.ok, true);
  assert.equal(result.sku, 'DW-TEST-1');
});

test('rejects coercible and oversized dimension inputs', () => {
  for (const value of [true, '10', [10]]) {
    const result = calculateCoverage({ sku: roll.sku, room_width_ft: value, room_height_ft: 8, num_walls: 1 }, [roll]);
    assert.equal(result.ok, false, `${JSON.stringify(value)} must not be coerced`);
  }
  for (const input of [
    { room_width_ft: 10, room_height_ft: '8', num_walls: 1 },
    { room_width_ft: 10, room_height_ft: 8, num_walls: true },
    { room_width_ft: 1001, room_height_ft: 8, num_walls: 1 },
    { room_width_ft: 1e308, room_height_ft: 8, num_walls: 100 },
    { room_width_ft: 10, room_height_ft: 101, num_walls: 1 },
    { room_width_ft: 10, room_height_ft: 8, num_walls: 101 },
  ]) {
    const result = calculateCoverage({ sku: roll.sku, ...input }, [roll]);
    assert.equal(result.ok, false);
    assert.doesNotMatch(JSON.stringify(result), /"ok":true/);
  }
});

test('fails closed when malformed roll data produces non-finite output', () => {
  const broken = { ...roll, roll_width_in: 0 };
  const result = calculateCoverage({ sku: roll.sku, room_width_ft: 10, room_height_ft: 8, num_walls: 1 }, [broken]);
  assert.equal(result.ok, false);
  assert.match(result.errors.join(' '), /roll specification is invalid/i);
});

test('rejects invalid finite roll specs and unsupported match values', () => {
  for (const patch of [
    { roll_width_in: -24 },
    { roll_length_ft: -30 },
    { pattern_repeat_in: -1 },
    { match: 'mystery' },
  ]) {
    const result = calculateCoverage(
      { sku: roll.sku, room_width_ft: 10, room_height_ft: 8, num_walls: 1 },
      [{ ...roll, ...patch }]
    );
    assert.equal(result.ok, false);
    assert.match(result.errors.join(' '), /roll specification is invalid/i);
  }
});

test('prefers an exact canonical SKU and rejects ambiguous aliases', () => {
  const alias = { ...roll, sku: 'PROTO', shopify_sku: 'COLLIDE', shopify_match: true };
  const canonical = { ...roll, sku: 'COLLIDE', shopify_sku: 'OTHER', shopify_match: true };
  const exact = calculateCoverage(
    { sku: 'COLLIDE', room_width_ft: 10, room_height_ft: 8, num_walls: 1 },
    [alias, canonical]
  );
  assert.equal(exact.ok, true);
  assert.equal(exact.sku, 'COLLIDE');

  const ambiguous = calculateCoverage(
    { sku: 'SAME-ALIAS', room_width_ft: 10, room_height_ft: 8, num_walls: 1 },
    [
      { ...roll, sku: 'ONE', shopify_sku: 'SAME-ALIAS' },
      { ...roll, sku: 'TWO', shopify_sku: 'SAME-ALIAS' },
    ]
  );
  assert.equal(ambiguous.ok, false);
  assert.match(ambiguous.errors.join(' '), /ambiguous matched Shopify SKU/i);
});

test('rejects missing SKU, invalid dimensions, fractional walls, and unknown SKU', () => {
  const invalid = calculateCoverage({ sku: '', room_width_ft: 0, room_height_ft: Infinity, num_walls: 1.5 }, [roll]);
  assert.equal(invalid.ok, false);
  assert.equal(invalid.errors.length, 4);
  const unknown = calculateCoverage({ sku: 'NOPE', room_width_ft: 10, room_height_ft: 8, num_walls: 1 }, [roll]);
  assert.deepEqual(unknown, { ok: false, errors: ['No local roll specification found for SKU NOPE.'] });
});

test('serves the real local HTTP journey and returns 400 on bad input', async (t) => {
  const server = http.createServer(handleRequest);
  await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
  t.after(() => new Promise((resolve) => server.close(resolve)));
  const base = `http://127.0.0.1:${server.address().port}`;

  const good = await fetch(`${base}/api/calculate-coverage`, {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ sku: 'DW-GRAS-01', room_width_ft: 10, room_height_ft: 8, num_walls: 4 }),
  });
  assert.equal(good.status, 200);
  const payload = await good.json();
  assert.equal(payload.ok, true);
  assert.equal(payload.data_source, 'local-rollspec-snapshot');
  assert.equal(payload.quote_authoritative, false);
  assert.equal(payload.total_cost, null);
  assert.equal(payload.price_per_roll, null);
  assert.match(payload.notes.join(' '), /pricing is withheld/i);

  const bad = await fetch(`${base}/api/calculate-coverage`, {
    method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}',
  });
  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.' });

  const invalidUtf8 = new EventEmitter();
  const invalidUtf8Promise = body(invalidUtf8);
  invalidUtf8.emit('data', Buffer.from([0x7b, 0x22, 0x78, 0x22, 0x3a, 0xff, 0x7d]));
  invalidUtf8.emit('end');
  assert.deepEqual(await invalidUtf8Promise,
    { ok: false, status: 400, error: 'Malformed or invalid UTF-8 JSON body.' });

  const closed = new EventEmitter();
  const closedPromise = body(closed);
  closed.emit('data', Buffer.from('{"name":'));
  closed.emit('close');
  assert.deepEqual(await closedPromise,
    { ok: false, status: 400, error: 'Request body closed before completion.' });
});

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);
});