← back to NationalPaperHangers Yfr2 C3
tests/measure-tier.test.js
202 lines
'use strict';
const test = require('node:test');
const assert = require('node:assert/strict');
const { POLICY_VERSION, classifyMeasureTier } = require('../lib/domain/measure-tier');
function base(overrides = {}) {
return {
environment: 'production',
is_test: false,
captured_at: '2026-08-01T12:00:00Z',
consent_at: '2026-08-01T12:01:00Z',
consent_version: 'measure-routing-v1',
consent_purposes: ['installer_routing'],
zip: '33138',
routed_to: 42,
routed_at: '2026-08-01T12:02:00Z',
lead_state: 'routed',
contact_preference: 'email',
customer_email: 'buyer@example.test',
customer_phone: null,
sqft: 240,
rolls: null,
measurement_method: 'calculator',
...overrides
};
}
test('returns the stable policy version and Standard for minimum explicit eligibility', () => {
const result = classifyMeasureTier(base());
assert.equal(result.policy_version, POLICY_VERSION);
assert.equal(result.tier, 'standard');
assert.deepEqual(result.reason_codes, [
'has_sqft',
'spec_missing_product_or_material',
'spec_missing_rolls',
'spec_missing_surface_state',
'spec_missing_timeline',
'spec_missing_valid_room_capture',
'spec_missing_wall_count'
]);
});
test('classifies Specification-ready only when every structured predicate passes', () => {
const result = classifyMeasureTier(base({
rolls: 8,
wall_count: 4,
product_sku: 'DW-100',
timeline_band: 'within_90_days',
surface_state: 'painted_drywall',
room_captures: [{
wall_width_ft: 12,
wall_height_ft: 9,
photo_url: '/uploads/bookings/0123456789abcdef01234567.jpg'
}]
}));
assert.equal(result.tier, 'spec_ready');
assert.deepEqual(result.reason_codes, [
'has_product_or_material', 'has_rolls', 'has_sqft', 'has_surface_state',
'has_timeline', 'has_valid_room_capture', 'has_wall_count'
]);
});
test('product_name and notes never satisfy structured Specification-ready fields', () => {
const result = classifyMeasureTier(base({
rolls: 8,
wall_count: 4,
product_name: 'Marketing name only',
notes: 'painted wall, install next week, photos attached',
room_captures: [{
wall_width_ft: 12,
wall_height_ft: 9,
photo_url: '/uploads/bookings/0123456789abcdef01234567.jpg'
}]
}));
assert.equal(result.tier, 'standard');
assert.ok(result.reason_codes.includes('spec_missing_product_or_material'));
assert.ok(result.reason_codes.includes('spec_missing_surface_state'));
assert.ok(result.reason_codes.includes('spec_missing_timeline'));
});
test('explicit test and non-production records are excluded', () => {
assert.deepEqual(classifyMeasureTier(base({ is_test: true })).tier, 'ineligible');
assert.ok(classifyMeasureTier(base({ is_test: true })).reason_codes.includes('test_record'));
assert.ok(classifyMeasureTier(base({ environment: 'staging' })).reason_codes.includes('not_production'));
assert.ok(classifyMeasureTier(base({ is_test: undefined })).reason_codes.includes('missing_test_provenance'));
});
test('missing consent, routing, contact, and scope are reported without inference', () => {
const result = classifyMeasureTier(base({
consent_at: null,
consent_version: null,
consent_purposes: [],
routed_to: null,
routed_at: null,
lead_state: 'captured',
contact_preference: 'email',
customer_email: null,
sqft: null,
rolls: 0,
measurement_method: null
}));
assert.equal(result.tier, 'ineligible');
assert.deepEqual(result.reason_codes, [
'ineligible_lead_state',
'missing_consent_at',
'missing_consent_version',
'missing_installer_routing_consent',
'missing_or_invalid_measurement_method',
'missing_positive_scope',
'missing_routed_at',
'missing_routed_to',
'missing_valid_preferred_contact'
]);
});
test('contact preference is enforced exactly', () => {
assert.equal(classifyMeasureTier(base({ contact_preference: 'phone', customer_email: 'buyer@example.test', customer_phone: null })).tier, 'ineligible');
assert.equal(classifyMeasureTier(base({ contact_preference: 'either', customer_email: null, customer_phone: '+13055550123' })).tier, 'standard');
assert.ok(classifyMeasureTier(base({ contact_preference: null })).reason_codes.includes('missing_or_invalid_contact_preference'));
});
test('all eligible lead states classify and terminal/no-route states do not', () => {
for (const lead_state of ['routed', 'viewed', 'accepted', 'declined', 'expired']) {
assert.equal(classifyMeasureTier(base({ lead_state })).tier, 'standard', lead_state);
}
for (const lead_state of ['captured', 'no_installer', 'superseded', null]) {
assert.equal(classifyMeasureTier(base({ lead_state })).tier, 'ineligible', String(lead_state));
}
});
test('malformed or partial room captures cannot qualify as Specification-ready', () => {
const common = {
rolls: 8, wall_count: 4, material: 'grasscloth', timeline_band: 'within_90_days',
surface_state: 'painted_drywall'
};
for (const room_captures of [
null,
[],
[{}],
[{ wall_width_ft: 12 }],
[{ wall_width_ft: 12, wall_height_ft: 9 }],
[{ wall_width_ft: 12, wall_height_ft: 9, photo_url: 'https://attacker.test/photo.jpg' }],
[{ wall_width_ft: 12, wall_height_ft: 0, photo_url: '/uploads/bookings/0123456789abcdef01234567.jpg' }]
]) {
const result = classifyMeasureTier(base({ ...common, room_captures }));
assert.equal(result.tier, 'standard');
assert.ok(result.reason_codes.includes('spec_missing_valid_room_capture'));
}
});
test('invalid ZIP, date, method, and preferred-contact formats are ineligible', () => {
const cases = [
['zip', '33138-1234', 'invalid_or_missing_zip'],
['captured_at', 'not-a-date', 'missing_captured_at'],
['measurement_method', 'guessed_from_notes', 'missing_or_invalid_measurement_method'],
['customer_email', 'not-an-email', 'missing_valid_preferred_contact']
];
for (const [field, value, reason] of cases) {
const result = classifyMeasureTier(base({ [field]: value }));
assert.equal(result.tier, 'ineligible', field);
assert.ok(result.reason_codes.includes(reason), field);
}
});
test('accepts database numeric strings but rejects JavaScript coercion traps', () => {
assert.equal(classifyMeasureTier(base({ sqft: '240', routed_to: '42' })).tier, 'standard');
for (const value of [true, false, [], [240], {}, ' 240', '240x', '-1']) {
assert.equal(classifyMeasureTier(base({ sqft: value })).tier, 'ineligible', `sqft=${String(value)}`);
}
for (const value of [true, [], [42], {}, '042', '42.0', '-1']) {
assert.equal(classifyMeasureTier(base({ routed_to: value })).tier, 'ineligible', `routed_to=${String(value)}`);
}
});
test('accepts Date/ISO timestamps and rejects coercible non-timestamps', () => {
assert.equal(classifyMeasureTier(base({ captured_at: new Date('2026-08-01T12:00:00Z') })).tier, 'standard');
assert.equal(classifyMeasureTier(base({ captured_at: '2024-02-29T12:00:00+05:30' })).tier, 'standard');
for (const value of [
true, 1, [], {}, '2026-08-01', '08/01/2026',
'0000-01-01T12:00:00Z', '2026-02-29T12:00:00Z', '2026-02-31T12:00:00Z', '2026-13-01T12:00:00Z',
'2026-01-01T24:00:00Z', '2026-01-01T12:60:00Z', '2026-01-01T12:00:60Z',
'2026-01-01T12:00:00+24:00'
]) {
assert.equal(classifyMeasureTier(base({ captured_at: value })).tier, 'ineligible', String(value));
}
});
test('room capture dimensions reject coercible arrays and booleans', () => {
const spec = {
rolls: 8, wall_count: 4, material: 'grasscloth', timeline_band: 'within_90_days',
surface_state: 'painted_drywall'
};
for (const wall_width_ft of [true, [12], {}, ' 12']) {
const result = classifyMeasureTier(base({ ...spec, room_captures: [{
wall_width_ft, wall_height_ft: 9,
photo_url: '/uploads/bookings/0123456789abcdef01234567.jpg'
}] }));
assert.equal(result.tier, 'standard', String(wall_width_ft));
}
});