setup onboarding page
This commit is contained in:
122
src/features/onboarding/validation.test.ts
Normal file
122
src/features/onboarding/validation.test.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* 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/);
|
||||
});
|
||||
Reference in New Issue
Block a user