u
This commit is contained in:
210
scripts/test-tombstone.js
Normal file
210
scripts/test-tombstone.js
Normal file
@@ -0,0 +1,210 @@
|
||||
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 articletombstone table and deletion flow ---');
|
||||
|
||||
const tempDir = mkdtempSync(join(tmpdir(), 'test-tombstone-'));
|
||||
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 {
|
||||
// 1. Verify table exists and has expected columns
|
||||
console.log('1. Checking articletombstone schema...');
|
||||
const tableInfo = provider.db.pragma('table_info("articletombstone")');
|
||||
const colNames = tableInfo.map((c) => c.name);
|
||||
console.log('articletombstone columns:', colNames);
|
||||
assert.deepEqual(colNames, [
|
||||
'id',
|
||||
'company_id',
|
||||
'article_id',
|
||||
'sku',
|
||||
'name',
|
||||
'taxrate',
|
||||
'net',
|
||||
'deleted_at',
|
||||
]);
|
||||
|
||||
// Setup company first
|
||||
console.log('2. Setting up base data...');
|
||||
const googleAuthId = await store.google_auth.add('tombstone-tester@example.com');
|
||||
const company = await store.company.create({
|
||||
name: 'Tombstone Corp',
|
||||
iso639: 'de',
|
||||
taxrate: 19,
|
||||
reducedtaxrate: 7,
|
||||
googleAuthId,
|
||||
});
|
||||
await store.google_auth.setSelectedCompany(googleAuthId, company.id);
|
||||
|
||||
// 3. Test CHECK constraint (article_id IS NOT NULL OR sku IS NOT NULL)
|
||||
console.log('3. Testing CHECK constraint...');
|
||||
// Setting both article_id and sku to NULL should fail
|
||||
assert.throws(() => {
|
||||
provider.db.prepare(`
|
||||
INSERT INTO articletombstone (company_id, article_id, sku, name)
|
||||
VALUES (?, NULL, NULL, 'Test')
|
||||
`).run(company.id);
|
||||
}, /CHECK constraint failed/);
|
||||
|
||||
// article_id present, sku null -> should succeed
|
||||
const r1 = provider.db.prepare(`
|
||||
INSERT INTO articletombstone (company_id, article_id, sku, name)
|
||||
VALUES (?, 999, NULL, 'Only ID')
|
||||
`).run(company.id);
|
||||
assert.ok(r1.lastInsertRowid);
|
||||
|
||||
// sku present, article_id null -> should succeed
|
||||
const r2 = provider.db.prepare(`
|
||||
INSERT INTO articletombstone (company_id, article_id, sku, name)
|
||||
VALUES (?, NULL, 'SKU-ONLY', 'Only SKU')
|
||||
`).run(company.id);
|
||||
assert.ok(r2.lastInsertRowid);
|
||||
|
||||
// Clean up manual test entries
|
||||
provider.db.prepare('DELETE FROM articletombstone').run();
|
||||
|
||||
// 4. Test article deletion flow
|
||||
console.log('4. Creating test article...');
|
||||
|
||||
const article = await store.article.createUnderParent({
|
||||
googleAuthId,
|
||||
parentId: company.rootCategoryId,
|
||||
name: 'Coffee Mug',
|
||||
});
|
||||
|
||||
// Set prices for the article
|
||||
await store.article.setPricesBySku(googleAuthId, article.sku, [
|
||||
{ price: 12.50, tax: 19, minmultiplier: 1 },
|
||||
]);
|
||||
|
||||
// Verify article exists
|
||||
const detailBefore = await store.article.getBySku(googleAuthId, article.sku);
|
||||
assert.equal(detailBefore.article.name, 'Coffee Mug');
|
||||
assert.equal(detailBefore.article.prices[0].net, 12.50);
|
||||
assert.equal(detailBefore.article.prices[0].taxRate, 19);
|
||||
|
||||
// Delete the article
|
||||
console.log('4. Deleting article and checking tombstone creation...');
|
||||
await store.article.delete(googleAuthId, article.sku);
|
||||
|
||||
// Verify article is deleted
|
||||
await assert.rejects(
|
||||
() => store.article.getBySku(googleAuthId, article.sku),
|
||||
/Article not found/
|
||||
);
|
||||
|
||||
// Verify tombstone record
|
||||
const tombstones = provider.db.prepare('SELECT * FROM articletombstone WHERE sku = ?').all(article.sku);
|
||||
assert.equal(tombstones.length, 1);
|
||||
const tomb = tombstones[0];
|
||||
console.log('Created tombstone:', tomb);
|
||||
assert.equal(tomb.company_id, company.id);
|
||||
assert.equal(tomb.article_id, article.id);
|
||||
assert.equal(tomb.sku, article.sku);
|
||||
assert.equal(tomb.name, 'Coffee Mug');
|
||||
assert.equal(tomb.net, 12.50);
|
||||
assert.equal(tomb.taxrate, 19);
|
||||
assert.ok(tomb.deleted_at);
|
||||
|
||||
// 5. Test cascading deletion with father and variants
|
||||
console.log('5. Testing father with variant child deletion...');
|
||||
const father = await store.article.createUnderParent({
|
||||
googleAuthId,
|
||||
parentId: company.rootCategoryId,
|
||||
name: 'Pants',
|
||||
});
|
||||
const attrName = await store.attributename.create(googleAuthId, { name: 'Größe' });
|
||||
await store.article.toggleFather(googleAuthId, father.sku, {
|
||||
isFather: true,
|
||||
attributeNameId: attrName.id,
|
||||
});
|
||||
const child = await store.article.addChild(googleAuthId, father.sku, { value: 'M' });
|
||||
await store.article.setPricesBySku(googleAuthId, child.article.sku, [
|
||||
{ price: 49.99, tax: 19, minmultiplier: 1 },
|
||||
]);
|
||||
|
||||
// Delete child via removeChild with deleteArticle
|
||||
console.log('Deleting child via removeChild({ deleteArticle: true })...');
|
||||
await store.article.removeChild(googleAuthId, father.sku, child.article.sku, { deleteArticle: true });
|
||||
|
||||
// Add another child and delete father with cascade: true
|
||||
const child2 = await store.article.addChild(googleAuthId, father.sku, { value: 'L' });
|
||||
console.log('Deleting father with cascade: true...');
|
||||
await store.article.delete(googleAuthId, father.sku, { cascade: true });
|
||||
|
||||
const allTombstones = provider.db.prepare('SELECT * FROM articletombstone ORDER BY id ASC').all();
|
||||
assert.equal(allTombstones.length, 4);
|
||||
|
||||
// 1st tombstone: Coffee Mug
|
||||
assert.equal(allTombstones[0].name, 'Coffee Mug');
|
||||
assert.equal(allTombstones[0].sku, '1');
|
||||
assert.equal(allTombstones[0].net, 12.5);
|
||||
assert.equal(allTombstones[0].taxrate, 19);
|
||||
|
||||
// 2nd tombstone: Pants - M (deleted via removeChild)
|
||||
assert.equal(allTombstones[1].name, 'Pants - M');
|
||||
assert.equal(allTombstones[1].sku, child.article.sku);
|
||||
assert.equal(allTombstones[1].net, 49.99);
|
||||
assert.equal(allTombstones[1].taxrate, 19);
|
||||
|
||||
// 3rd tombstone: Pants - L (child deleted in cascade)
|
||||
assert.equal(allTombstones[2].name, 'Pants - L');
|
||||
assert.equal(allTombstones[2].sku, child2.article.sku);
|
||||
|
||||
// 4th tombstone: Pants (father deleted in cascade)
|
||||
assert.equal(allTombstones[3].name, 'Pants');
|
||||
assert.equal(allTombstones[3].sku, father.sku);
|
||||
|
||||
// 6. Test posterminal maxknowntombstoneid column and updates
|
||||
console.log('6. Testing posterminal maxknowntombstoneid column...');
|
||||
const posterminalCols = provider.db.pragma('table_info("posterminal")').map((c) => c.name);
|
||||
assert.ok(posterminalCols.includes('maxknowntombstoneid'), 'posterminal should have maxknowntombstoneid column');
|
||||
|
||||
const terminal = await store.posterminal.upsert(googleAuthId, {
|
||||
name: 'POS Terminal 1',
|
||||
pairingpin: '1234',
|
||||
});
|
||||
assert.equal(terminal.maxknowntombstoneid, null);
|
||||
|
||||
// Pair terminal
|
||||
await store.posterminal.pair(terminal.id, {
|
||||
token: 'tok-123',
|
||||
clientserial: 'SN-001',
|
||||
pairedAt: new Date().toISOString(),
|
||||
});
|
||||
|
||||
const foundByToken = await store.posterminal.findByToken('tok-123');
|
||||
assert.equal(foundByToken.id, terminal.id);
|
||||
assert.equal(foundByToken.maxknowntombstoneid, null);
|
||||
|
||||
// Update maxknowntombstoneid
|
||||
await store.posterminal.setMaxKnownTombstoneId(terminal.id, 4);
|
||||
|
||||
const foundAfterUpdate = await store.posterminal.findByToken('tok-123');
|
||||
assert.equal(foundAfterUpdate.maxknowntombstoneid, 4);
|
||||
|
||||
console.log('✅ ALL TOMBSTONE TESTS PASSED');
|
||||
} finally {
|
||||
try {
|
||||
rmSync(tempDir, { recursive: true, force: true });
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
run().catch((err) => {
|
||||
console.error('Test failed:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user