Files
dashlibstorage/scripts/test-variant-flow.js
2026-10-01 17:40:04 +02:00

131 lines
5.3 KiB
JavaScript

import assert from 'node:assert/strict';
import { mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import LibDashStore from '../src/index.js';
import { BetterSqlite3Provider } from '../src/providers/sqlite3/index.js';
async function run() {
console.log('--- Testing Variant Flow: Next-Free SKU, Fathersort Reclaim, and Duplicate Protection ---');
const tempDir = mkdtempSync(join(tmpdir(), 'test-variants-'));
const dbFile = join(tempDir, 'test.db');
const storageDir = join(tempDir, 'storage');
const provider = new BetterSqlite3Provider({
filename: dbFile,
storageDir,
});
await provider.initialize();
const store = await new LibDashStore(provider);
try {
const googleAuthId = await store.google_auth.add('variant-tester@example.com');
const company = await store.company.create({
name: 'Variant Corp',
iso639: 'de',
taxrate: 19,
reducedtaxrate: 7,
googleAuthId,
});
await store.google_auth.setSelectedCompany(googleAuthId, company.id);
// Create father article
const father = await store.article.createUnderParent({
googleAuthId,
parentId: company.rootCategoryId,
name: 'T-Shirt',
});
const attrName = await store.attributename.create(googleAuthId, { name: 'Farbe' });
await store.article.toggleFather(googleAuthId, father.sku, {
isFather: true,
attributeNameId: attrName.id,
});
console.log('1. Add initial children (Rot, Blau, Grün)...');
const child1 = await store.article.addChild(googleAuthId, father.sku, { value: 'Rot' });
const child2 = await store.article.addChild(googleAuthId, father.sku, { value: 'Blau' });
const child3 = await store.article.addChild(googleAuthId, father.sku, { value: 'Grün' });
assert.equal(child1.article.sku, `${father.sku}-1`);
assert.equal(child2.article.sku, `${father.sku}-2`);
assert.equal(child3.article.sku, `${father.sku}-3`);
let list = await store.article.listChildren(googleAuthId, father.sku);
assert.equal(list.length, 3);
assert.deepEqual(list.map((c) => c.fathersort), [0, 1, 2]);
console.log('2. Testing Duplicate Variant Protection (Defect 3)...');
await assert.rejects(
async () => {
await store.article.addChild(googleAuthId, father.sku, { value: 'Rot' });
},
(err) => {
assert.match(err.message, /Variant with this attribute value already exists/);
return true;
},
'Expected duplicate variant attribute value to be rejected'
);
console.log('3. Unlink middle child (child2 / SKU-2) -> leaves orphan holding SKU-2 (Bug A & B)...');
await store.article.removeChild(googleAuthId, father.sku, child2.article.sku, {
deleteArticle: false,
});
// Check that remaining children's fathersort was recompacted
list = await store.article.listChildren(googleAuthId, father.sku);
assert.equal(list.length, 2);
assert.deepEqual(list.map((c) => c.sku), [child1.article.sku, child3.article.sku]);
assert.deepEqual(list.map((c) => c.fathersort), [0, 1]);
// Check orphan still exists in DB
const orphan = await store.article.getBySku(googleAuthId, child2.article.sku);
assert.equal(orphan.article.fatherArticleId, null);
assert.equal(orphan.article.sku, `${father.sku}-2`);
console.log('4. Add new child (Gelb) -> SKU must NOT collide with orphan (Bug A: next free index)...');
const child4 = await store.article.addChild(googleAuthId, father.sku, { value: 'Gelb' });
// Since SKU-1, SKU-2 (orphan), SKU-3 exist, next free index is 4
assert.equal(child4.article.sku, `${father.sku}-4`);
list = await store.article.listChildren(googleAuthId, father.sku);
assert.equal(list.length, 3);
assert.deepEqual(list.map((c) => c.fathersort), [0, 1, 2]);
console.log('5. Testing gaps in fathersort (Evidence: father with child at fathersort: 1)...');
// Unlink child3 and child4 so only child1 remains
await store.article.removeChild(googleAuthId, father.sku, child3.article.sku, { deleteArticle: true });
await store.article.removeChild(googleAuthId, father.sku, child4.article.sku, { deleteArticle: true });
// Manually force child1's fathersort: 1 to simulate pre-existing gap state (like father 94)
await provider.query(
`UPDATE article SET fathersort = 1 WHERE sku = @sku`,
{ sku: child1.article.sku }
);
list = await store.article.listChildren(googleAuthId, father.sku);
assert.equal(list.length, 1);
assert.equal(list[0].fathersort, 1); // exactly like father 94
// Now adding a variant MUST NOT hit UNIQUE constraint failed (409)
console.log('Adding variant to father with child at fathersort: 1...');
const child5 = await store.article.addChild(googleAuthId, father.sku, { value: 'Schwarz' });
assert.ok(child5);
list = await store.article.listChildren(googleAuthId, father.sku);
assert.equal(list.length, 2);
// Fathersort should have picked 0 (next free non-negative integer)
assert.deepEqual(list.map((c) => c.fathersort), [0, 1]);
console.log('✅ ALL VARIANT FLOW TESTS PASSED');
} finally {
try {
rmSync(tempDir, { recursive: true, force: true });
} catch {}
}
}
run().catch((err) => {
console.error('Test failed:', err);
process.exit(1);
});