92 lines
4.2 KiB
TypeScript
92 lines
4.2 KiB
TypeScript
/**
|
||
* The fold from the catalogue's 31 categories into the app's ten aisles.
|
||
*
|
||
* The stakes here are not cosmetic. `subcategoryid` is the only thing the
|
||
* customer app groups by, and a category that folds to nothing lands the
|
||
* product in "Uncategorized" — which is the state the whole platform was in.
|
||
*/
|
||
import assert from 'node:assert/strict';
|
||
import { test } from 'node:test';
|
||
import {
|
||
APP_AISLES,
|
||
FALLBACK_AISLE_IDS,
|
||
aisleForCategory,
|
||
aisleIdForCategory,
|
||
aisleIdsFrom,
|
||
} from './appAisle';
|
||
import { CATEGORY_REGISTRY, UNKNOWN_CATEGORY } from './productCategory';
|
||
|
||
const ids = aisleIdsFrom(undefined);
|
||
|
||
test('every one of the 31 categories folds into an aisle', () => {
|
||
const orphans = CATEGORY_REGISTRY.map((entry) => entry.category).filter(
|
||
(category) => aisleForCategory(category) === null,
|
||
);
|
||
assert.deepEqual(orphans, [], 'a category with no aisle is a product the app cannot show');
|
||
});
|
||
|
||
// "General" is the ladder saying it does not know. Inventing an aisle for it
|
||
// would put an unidentified product on a real shelf, which is worse than the
|
||
// app's own "Uncategorized" heading — that one at least tells the truth.
|
||
test('the unknown bucket deliberately has no aisle', () => {
|
||
assert.equal(aisleForCategory(UNKNOWN_CATEGORY), null);
|
||
assert.equal(aisleIdForCategory(UNKNOWN_CATEGORY, ids), 0);
|
||
});
|
||
|
||
test('a name that is not a category at all folds to nothing', () => {
|
||
assert.equal(aisleForCategory(''), null);
|
||
assert.equal(aisleForCategory(undefined), null);
|
||
assert.equal(aisleForCategory('Category 2'), null, 'the old default is not an aisle');
|
||
});
|
||
|
||
test('the things a shopper would look for land where they would look', () => {
|
||
assert.equal(aisleForCategory('Spices & Masalas'), 'Foodgrains & Pulses');
|
||
assert.equal(aisleForCategory('Dairy'), 'Dairy, Deli & Egg');
|
||
assert.equal(aisleForCategory('Hair Care'), 'Beauty & Personal Care');
|
||
assert.equal(aisleForCategory('Household Cleaning'), 'Hygiene Essentials');
|
||
assert.equal(aisleForCategory('Cooking Oils'), 'Oil & Ghee');
|
||
assert.equal(aisleForCategory('Biscuits & Cookies'), 'Bakes & Nuts');
|
||
});
|
||
|
||
// The registry writes an en-dash; a sheet typed by hand will not. Two strings
|
||
// that read the same must not reach different aisles.
|
||
test('dash and spacing variants reach the same aisle', () => {
|
||
assert.equal(aisleForCategory('Household – Agarbatti'), 'Hygiene Essentials');
|
||
assert.equal(aisleForCategory('Household - Agarbatti'), 'Hygiene Essentials');
|
||
assert.equal(aisleForCategory('household—agarbatti'), 'Hygiene Essentials');
|
||
assert.equal(aisleForCategory(' HEALTH CARE – ANTISEPTIC '), 'Hygiene Essentials');
|
||
});
|
||
|
||
/* ── Ids come from the platform's list, never from the wrong table ────────── */
|
||
|
||
// `productsubcategories` holds these ten names at 14-23; the app's utils list
|
||
// holds the same ten at 9-18. Matching on the name is what keeps a product out
|
||
// of the second set, which the grouping does not read.
|
||
test('ids are taken from the rows the API returned, by name', () => {
|
||
const live = aisleIdsFrom([
|
||
{ subcatid: 15, subcatname: 'Dairy, Deli & Egg', categoryid: 2 },
|
||
{ subcatid: 21, subcatname: 'Snacks & Drinks', categoryid: 2 },
|
||
]);
|
||
assert.equal(aisleIdForCategory('Dairy', live), 15);
|
||
assert.equal(aisleIdForCategory('Chocolates', live), 21);
|
||
});
|
||
|
||
// A name the API did not return has no id from it — but the aisle is still one
|
||
// of the ten, so the last-known id is better than 0, which means "no aisle".
|
||
test('a missing row falls back to the last known id rather than to zero', () => {
|
||
const partial = aisleIdsFrom([{ subcatid: 15, subcatname: 'Dairy, Deli & Egg', categoryid: 2 }]);
|
||
assert.equal(aisleIdForCategory('Cooking Oils', partial), FALLBACK_AISLE_IDS['Oil & Ghee']);
|
||
});
|
||
|
||
test('an empty response falls back to the whole known list', () => {
|
||
const empty = aisleIdsFrom([]);
|
||
assert.equal(empty.size, APP_AISLES.length);
|
||
assert.equal(aisleIdForCategory('Eggs', empty), FALLBACK_AISLE_IDS['Dairy, Deli & Egg']);
|
||
});
|
||
|
||
test('every aisle has an id, and no two share one', () => {
|
||
const values = APP_AISLES.map((aisle) => FALLBACK_AISLE_IDS[aisle]);
|
||
assert.equal(new Set(values).size, values.length);
|
||
assert.ok(values.every((id) => id > 0));
|
||
});
|