import type { GameDTO } from '$lib/api/schema-helpers'; import { describe, expect, it } from 'vitest'; import { blankDraft, isDirty, nextOrder, toDraft, toDto } from './draft'; describe('toDraft / toDto', () => { it('replaces every null with a value the inputs can bind to', () => { const draft = toDraft({ id: 3, name: null, longName: null, order: undefined, smashId: undefined }); expect(draft).toEqual({ id: 3, name: '', longName: '', order: 0, imgUrl: '', wordPressTag: '', wordPressTagOs: '', smashId: null }); }); it('stores blank and whitespace-only text as NULL, not as an empty string', () => { const dto = toDto({ ...blankDraft, name: 'SF6', longName: ' ', imgUrl: '' }); expect(dto.longName).toBeNull(); expect(dto.imgUrl).toBeNull(); expect(dto.name).toBe('SF6'); }); it('trims text on the way out', () => { expect(toDto({ ...blankDraft, name: ' SF6 ' }).name).toBe('SF6'); }); it('round-trips a full game', () => { const game: GameDTO = { id: 4, name: 'SF6', longName: 'Street Fighter 6', order: 2, imgUrl: 'https://example.test/sf6.png', wordPressTag: 'sf6', wordPressTagOs: 'sf6-os', smashId: 43868 }; expect(toDto(toDraft(game))).toEqual(game); }); }); describe('isDirty', () => { /* * The editor used to compare `JSON.stringify` output, which is key-order * dependent: an identical draft built with its keys in another order read as * unsaved changes. */ it('is false for equal drafts regardless of key order', () => { const a = { ...blankDraft, name: 'SF6', order: 2 }; const reordered = { order: 2, smashId: null, wordPressTagOs: '', wordPressTag: '', imgUrl: '', longName: '', name: 'SF6', id: 0 }; expect(JSON.stringify(a)).not.toBe(JSON.stringify(reordered)); expect(isDirty(a, reordered)).toBe(false); }); it('detects a change in any field', () => { const base = { ...blankDraft, name: 'SF6' }; expect(isDirty(base, { ...base, name: 'SFV' })).toBe(true); expect(isDirty(base, { ...base, order: 9 })).toBe(true); expect(isDirty(base, { ...base, smashId: 1 })).toBe(true); expect(isDirty(base, { ...base })).toBe(false); }); it('distinguishes null from 0 for the nullable numbers', () => { expect(isDirty({ ...blankDraft, smashId: null }, { ...blankDraft, smashId: 0 })).toBe(true); }); }); describe('nextOrder', () => { it('sorts a new game after the current last one', () => { expect(nextOrder([{ order: 1 }, { order: 5 }, { order: 3 }])).toBe(6); }); it('starts at 1 for an empty catalogue', () => { expect(nextOrder([])).toBe(1); }); it('treats a missing order as 0', () => { expect(nextOrder([{ order: undefined }])).toBe(1); }); });