import { tap, expect } from '@git.zone/tstest/tapbundle'; import { makeTestDb } from './helpers/services.js'; import type * as smartdata from '@push.rocks/smartdata'; import { SmartMigration } from '../ts/index.js'; let db: smartdata.SmartdataDb; let cleanup: () => Promise; tap.test('setup: connect shared db', async () => { const r = await makeTestDb('dryrun'); db = r.db; cleanup = r.cleanup; }); tap.test('dryRun: returns plan without invoking handlers', async () => { const m = new SmartMigration({ targetVersion: '2.0.0', db, ledgerName: 'dryrun', dryRun: true, }); let stepCalled = false; m .step('a').from('1.0.0').to('1.5.0').up(async () => { stepCalled = true; }) .step('b').from('1.5.0').to('2.0.0').up(async () => { stepCalled = true; }); const r = await m.run(); expect(stepCalled).toBeFalse(); expect(r.stepsApplied).toHaveLength(0); expect(r.stepsSkipped).toHaveLength(2); expect(r.stepsSkipped.map((s) => s.id)).toEqual(['a', 'b']); expect(r.currentVersionAfter).toEqual('2.0.0'); // The ledger should still be in its initial state (currentVersion = null). const current = await m.getCurrentVersion(); expect(current).toBeNull(); }); tap.test('plan(): returns plan without writing or running', async () => { const m = new SmartMigration({ targetVersion: '2.0.0', db, ledgerName: 'plan_only' }); let stepCalled = false; m .step('a').from('1.0.0').to('2.0.0').up(async () => { stepCalled = true; }); const planResult = await m.plan(); expect(stepCalled).toBeFalse(); expect(planResult.stepsSkipped).toHaveLength(1); expect(planResult.stepsApplied).toHaveLength(0); expect(planResult.currentVersionAfter).toEqual('2.0.0'); // Plan does not modify the ledger. const current = await m.getCurrentVersion(); expect(current).toBeNull(); }); tap.test('dryRun: models freshInstallVersion on an empty database', async () => { const m = new SmartMigration({ targetVersion: '2.0.0', db, ledgerName: 'dryrun_fresh', freshInstallVersion: '2.0.0', dryRun: true, }); let stepCalled = false; m.step('a').from('1.0.0').to('2.0.0').up(async () => { stepCalled = true; }); const r = await m.run(); expect(stepCalled).toBeFalse(); expect(r.wasFreshInstall).toBeTrue(); expect(r.stepsSkipped).toHaveLength(0); expect(r.currentVersionBefore).toBeNull(); expect(r.currentVersionAfter).toEqual('2.0.0'); expect(await m.getCurrentVersion()).toBeNull(); }); tap.test('plan(): does not use freshInstallVersion when user data already exists', async () => { await db.mongoDb.collection('dryrun_preexisting_users').insertOne({ id: 'user-1' }); const m = new SmartMigration({ targetVersion: '2.0.0', db, ledgerName: 'plan_preexisting', freshInstallVersion: '2.0.0', }); let stepCalled = false; m.step('a').from('1.0.0').to('2.0.0').up(async () => { stepCalled = true; }); const r = await m.plan(); expect(stepCalled).toBeFalse(); expect(r.wasFreshInstall).toBeFalse(); expect(r.stepsSkipped).toHaveLength(1); expect(r.stepsSkipped[0].id).toEqual('a'); expect(r.currentVersionAfter).toEqual('2.0.0'); expect(await m.getCurrentVersion()).toBeNull(); }); tap.test('cleanup: close shared db', async () => { await cleanup(); }); export default tap.start();