Files
daily_console_web/src/features/onboarding/validation.test.ts
2026-09-02 11:26:00 +05:30

123 lines
4.4 KiB
TypeScript

/**
* Setup validation.
*
* The rule every message here follows: say what is wrong AND how to fix it. A
* store owner who is told "invalid input" has learned nothing they did not
* already know, and the person it fails is the least technical user on the
* platform — somebody setting up a shop for the first time.
*/
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { isValid, validateDelivery, validateStoreInfo } from './validation';
const store = (over: Partial<Parameters<typeof validateStoreInfo>[0]> = {}) =>
validateStoreInfo({
tenantname: 'Testmart',
primarycontact: '9876543210',
primaryemail: 'owner@testmart.in',
address: '1 Test Street',
city: 'Coimbatore',
postcode: '641001',
opentime: '08:00',
closetime: '22:00',
...over,
});
test('a complete store passes', () => {
assert.equal(isValid(store()), true);
});
test('every required field is named when missing', () => {
const e = store({ tenantname: '', primarycontact: '', address: '', city: '', postcode: '' });
for (const field of ['tenantname', 'primarycontact', 'address', 'city', 'postcode']) {
assert.ok(e[field], `${field} was accepted empty`);
}
});
/*
Counting the digits back is the difference between a message somebody can act
on and one they argue with. "Please enter a valid phone number" on a number that
looks fine is the worst kind of error.
*/
test('a wrong-length phone says how many digits it got', () => {
assert.match(String(store({ primarycontact: '98765' })['primarycontact']), /5 digits/);
assert.match(String(store({ postcode: '6410' })['postcode']), /4 digits/);
});
// Pasted numbers carry spaces, +91 and brackets. Those are the user's habit,
// not an error.
test('a formatted phone number is accepted', () => {
assert.equal(store({ primarycontact: '+91 98765 43210' })['primarycontact'], undefined);
});
test('email is optional but must be usable when given', () => {
assert.equal(store({ primaryemail: '' })['primaryemail'], undefined);
assert.ok(store({ primaryemail: 'owner@' })['primaryemail']);
assert.ok(store({ primaryemail: 'owner.testmart.in' })['primaryemail']);
});
// The example from the brief, and a real ordering mistake: a shop that closes
// before it opens takes no orders all day and nothing explains why.
test('closing time must be after opening time', () => {
const e = store({ opentime: '22:00', closetime: '08:00' });
assert.match(String(e['closetime']), /later than opening/);
});
/* ── Delivery ────────────────────────────────────────────────────────────── */
const delivery = (over: Partial<Parameters<typeof validateDelivery>[0]> = {}) =>
validateDelivery({
offersDelivery: true,
radiusKm: '5',
minOrder: '199',
charge: '30',
freeAbove: '499',
mins: '45',
...over,
});
test('a complete delivery setup passes', () => {
assert.equal(isValid(delivery()), true);
});
test('the delivery question itself must be answered', () => {
assert.ok(validateDelivery({
offersDelivery: null, radiusKm: '', minOrder: '', charge: '', freeAbove: '', mins: '',
})['offersDelivery']);
});
/*
A shop that does not deliver must not be held up by delivery fields it cannot
see. Validating hidden inputs is how a form refuses to submit for reasons
nobody can find on screen.
*/
test('saying no to delivery asks for nothing else', () => {
const e = validateDelivery({
offersDelivery: false, radiusKm: '', minOrder: '', charge: '', freeAbove: '', mins: '',
});
assert.equal(isValid(e), true);
});
test('radius and delivery time are required when delivering', () => {
assert.ok(delivery({ radiusKm: '' })['radiusKm']);
assert.ok(delivery({ mins: '' })['mins']);
assert.ok(delivery({ radiusKm: '0' })['radiusKm']);
});
test('the money fields are optional', () => {
assert.equal(isValid(delivery({ minOrder: '', charge: '', freeAbove: '' })), true);
});
test('negative money is refused', () => {
assert.ok(delivery({ charge: '-10' })['charge']);
});
/*
Free delivery below the minimum order means every order qualifies — the opposite
of what the shopkeeper is trying to set up, and it would only be noticed in the
takings.
*/
test('free-delivery threshold below the minimum order is caught', () => {
assert.match(String(delivery({ minOrder: '500', freeAbove: '200' })['freeAbove']), /every order/);
});