110 lines
4.2 KiB
JavaScript
110 lines
4.2 KiB
JavaScript
/**
|
|||
|
|
* Integration test for the `customer_sync_full_name` database trigger
|
||
|
|
* (migration 20260922120000_customer_name_parts).
|
||
|
|
*
|
||
|
|
* The trigger is SQL, not Prisma, so jest's unit suite cannot cover it — it
|
||
|
|
* needs a live database. Run it against a development DB:
|
||
|
|
*
|
||
|
|
* node scripts/test-name-trigger.cjs
|
||
|
|
*
|
||
|
|
* Exits non-zero on any failure. It creates ONE temporary Customer row and
|
||
|
|
* deletes it again; the deletion is reported on stdout (CHANGELOG rule 2).
|
||
|
|
*
|
||
|
|
* The three directions required by the owner's ruling of 2026-09-22:
|
||
|
|
* parts only -> fullName is rebuilt
|
||
|
|
* fullName only -> the parts are re-derived
|
||
|
|
* both at once -> THE PARTS WIN
|
||
|
|
*/
|
||
|
|
const { PrismaClient } = require('@prisma/client');
|
||
|
|
|
||
|
|
const prisma = new PrismaClient();
|
||
|
|
let failures = 0;
|
||
|
|
|
||
|
|
function check(condition, message) {
|
||
|
|
if (!condition) failures++;
|
||
|
|
console.log(`${condition ? ' PASS' : ' FAIL'} ${message}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
const read = async (id) =>
|
||
|
|
(
|
||
|
|
await prisma.$queryRawUnsafe(
|
||
|
|
`SELECT "fullName","firstName","lastName","makingChargeOffsetPercent" AS pct
|
||
|
|
FROM "Customer" WHERE id=$1`,
|
||
|
|
id,
|
||
|
|
)
|
||
|
|
)[0];
|
||
|
|
|
||
|
|
(async () => {
|
||
|
|
const id = 'trigger-test-' + Date.now();
|
||
|
|
const unique = Date.now();
|
||
|
|
|
||
|
|
await prisma.$executeRawUnsafe(
|
||
|
|
`INSERT INTO "Customer"
|
||
|
|
(id,"fullName","firstName","lastName",mobile,"nationalCode","passwordHash","updatedAt")
|
||
|
|
VALUES ($1,'',$2,$3,$4,$5,'x',NOW())`,
|
||
|
|
id,
|
||
|
|
'محمد علی',
|
||
|
|
'احمدی',
|
||
|
|
'09' + String(unique).slice(-9),
|
||
|
|
'NC' + unique,
|
||
|
|
);
|
||
|
|
|
||
|
|
// The owner's worked example: a two-token FIRST name must survive intact.
|
||
|
|
console.log('\nCASE 0 — INSERT with parts only («محمد علی» + «احمدی»)');
|
||
|
|
let r = await read(id);
|
||
|
|
console.log(' ', JSON.stringify(r));
|
||
|
|
check(r.fullName === 'محمد علی احمدی', 'fullName rebuilt from the parts');
|
||
|
|
check(r.firstName === 'محمد علی', 'a two-token first name is NOT re-split');
|
||
|
|
check(r.lastName === 'احمدی', 'last name kept separate');
|
||
|
|
|
||
|
|
console.log('\nCASE 1 — UPDATE the parts only');
|
||
|
|
await prisma.$executeRawUnsafe(
|
||
|
|
`UPDATE "Customer" SET "firstName"='رضا',"lastName"='کریمی' WHERE id=$1`,
|
||
|
|
id,
|
||
|
|
);
|
||
|
|
r = await read(id);
|
||
|
|
console.log(' ', JSON.stringify(r));
|
||
|
|
check(r.fullName === 'رضا کریمی', 'fullName rebuilt from the parts');
|
||
|
|
|
||
|
|
console.log('\nCASE 2 — UPDATE fullName only');
|
||
|
|
await prisma.$executeRawUnsafe(`UPDATE "Customer" SET "fullName"='سعید موسوی' WHERE id=$1`, id);
|
||
|
|
r = await read(id);
|
||
|
|
console.log(' ', JSON.stringify(r));
|
||
|
|
check(r.firstName === 'سعید' && r.lastName === 'موسوی', 'parts re-derived from fullName');
|
||
|
|
|
||
|
|
console.log('\nCASE 3 — UPDATE BOTH in one statement (the parts must win)');
|
||
|
|
await prisma.$executeRawUnsafe(
|
||
|
|
`UPDATE "Customer" SET "fullName"='IGNORED',"firstName"='نرگس',"lastName"='رحیمی' WHERE id=$1`,
|
||
|
|
id,
|
||
|
|
);
|
||
|
|
r = await read(id);
|
||
|
|
console.log(' ', JSON.stringify(r));
|
||
|
|
check(r.fullName === 'نرگس رحیمی', 'parts win; the submitted fullName is discarded');
|
||
|
|
|
||
|
|
console.log('\nCASE 4 — a multi-token fullName splits first-token / rest');
|
||
|
|
await prisma.$executeRawUnsafe(`UPDATE "Customer" SET "fullName"='سید محمد حسینی' WHERE id=$1`, id);
|
||
|
|
r = await read(id);
|
||
|
|
console.log(' ', JSON.stringify(r));
|
||
|
|
check(r.firstName === 'سید' && r.lastName === 'محمد حسینی', 'first token / the rest');
|
||
|
|
|
||
|
|
console.log('\nCASE 5 — an unrelated update leaves the name untouched');
|
||
|
|
const before = await read(id);
|
||
|
|
await prisma.$executeRawUnsafe(`UPDATE "Customer" SET mobile=mobile WHERE id=$1`, id);
|
||
|
|
const after = await read(id);
|
||
|
|
check(JSON.stringify(before) === JSON.stringify(after), 'no-op update changes nothing');
|
||
|
|
|
||
|
|
console.log('\nCASE 6 — makingChargeOffsetPercent');
|
||
|
|
check(Number(after.pct) === 0, 'defaults to 0, so no existing price moves');
|
||
|
|
|
||
|
|
await prisma.$executeRawUnsafe(`DELETE FROM "Customer" WHERE id=$1`, id);
|
||
|
|
console.log(`\nCleanup: deleted 1 temporary Customer row (${id}).`);
|
||
|
|
|
||
|
|
console.log(failures === 0 ? '\nALL PASSED' : `\n${failures} FAILED`);
|
||
|
|
await prisma.$disconnect();
|
||
|
|
process.exit(failures ? 1 : 0);
|
||
|
|
})().catch(async (e) => {
|
||
|
|
console.error(e);
|
||
|
|
await prisma.$disconnect();
|
||
|
|
process.exit(1);
|
||
|
|
});
|