import { describe, expect, it } from 'vitest'; import { cardContentHash } from '@cards/domain'; import { hashVersionCards } from '../src/lib/marketplace/version-hash.ts'; describe('hashVersionCards', () => { const card1 = { type: 'basic', fields: { front: 'Q1', back: 'A1' }, ord: 0 }; const card2 = { type: 'basic', fields: { front: 'Q2', back: 'A2' }, ord: 1 }; it('is deterministic', async () => { const a = await hashVersionCards([card1, card2]); const b = await hashVersionCards([card1, card2]); expect(a).toBe(b); }); it('changes when card order changes', async () => { const original = await hashVersionCards([card1, card2]); const swapped = await hashVersionCards([ { ...card1, ord: 1 }, { ...card2, ord: 0 }, ]); expect(original).not.toBe(swapped); }); it('changes when a field changes', async () => { const original = await hashVersionCards([card1, card2]); const tweaked = await hashVersionCards([ card1, { ...card2, fields: { ...card2.fields, back: 'A2-edited' } }, ]); expect(original).not.toBe(tweaked); }); it('input order independent (sorts by ord)', async () => { const inOrder = await hashVersionCards([card1, card2]); const reversedInput = await hashVersionCards([card2, card1]); expect(inOrder).toBe(reversedInput); }); it('uses cardContentHash for per-card identity (consumes @cards/domain SoT)', async () => { // Smoke: changing fields without changing the type must change the // per-card hash (cardContentHash semantics) and therefore the // version hash. const a = await cardContentHash({ type: 'basic', fields: { front: 'X', back: 'Y' } }); const b = await cardContentHash({ type: 'basic', fields: { front: 'X', back: 'Y2' } }); expect(a).not.toBe(b); }); });