import { beforeEach, describe, expect, it, vi } from 'vitest'; const mocks = vi.hoisted(() => ({ audits: [] as Array>, database: { exec: vi.fn(async () => undefined), prepare: vi.fn(async () => ({ get: vi.fn(async (...statIds: unknown[]) => ({ count: statIds.length })), })), }, getModSecondaryPool: vi.fn(), recordIsacAudit: vi.fn(), replaceModSecondaryPool: vi.fn(), requirePermission: vi.fn(async (user) => user), })); vi.mock('$lib/server/auth/session', () => ({ getSessionUser: vi.fn(async () => ({ id: 'operator-1' })), })); vi.mock('$lib/server/auth/authorization', () => ({ requireDataView: vi.fn(async (user) => user), requirePermission: mocks.requirePermission, })); vi.mock('$lib/server/database', () => ({ getDatabase: vi.fn(async () => mocks.database), })); vi.mock('$lib/server/audit', () => ({ auditRecord: vi.fn(), recordIsacAudit: mocks.recordIsacAudit, })); vi.mock('$lib/server/data-moderation', () => ({ getPendingEntities: vi.fn(async () => []), })); vi.mock('$lib/server/managed-images', () => ({ applyGameDataRender: vi.fn(), ManagedImageValidationError: class extends Error {}, managedImageUrl: vi.fn(() => ''), processManagedImage: vi.fn(), readGameDataRenderMutation: vi.fn(), })); vi.mock('$lib/server/mod-secondary-pools', () => ({ getModSecondaryPool: mocks.getModSecondaryPool, replaceModSecondaryPool: mocks.replaceModSecondaryPool, })); import { actions } from './+page.server'; const endpoints = ( level1Min: number, level1Max: number, level20Min: number, level20Max: number, ) => ({ level1Min, level1Max, level20Min, level20Max }); const pool = (suffix: string, offset = 0) => [ { statId: `critical-hit-chance-${suffix}`, values: { Specialized: endpoints(1 + offset, 2 + offset, 3 + offset, 4 + offset), Superior: endpoints(2 + offset, 3 + offset, 4 + offset, 5 + offset), 'High-end': endpoints(3 + offset, 4 + offset, 5 + offset, 6 + offset), }, }, { statId: `critical-hit-damage-${suffix}`, values: { Specialized: endpoints(4 + offset, 5 + offset, 6 + offset, 7 + offset), Superior: endpoints(5 + offset, 6 + offset, 7 + offset, 8 + offset), 'High-end': endpoints(6 + offset, 7 + offset, 8 + offset, 9 + offset), }, }, ]; const request = (secondaryRanges: ReturnType) => { const form = new FormData(); form.set('id', 'weapon-mod-secondary-pool'); form.set('secondaryRanges', JSON.stringify(secondaryRanges)); return new Request('http://localhost/isac/weaponmods?/saveSecondaryPool', { method: 'POST', body: form, }); }; describe('Weapon Mod shared secondary pool action', () => { beforeEach(() => { vi.clearAllMocks(); mocks.audits.length = 0; mocks.recordIsacAudit.mockImplementation(async (event) => { mocks.audits.push(event); }); }); it('audits the complete contract and commits the transaction', async () => { const before = pool('before'); const after = pool('after', 1); mocks.getModSecondaryPool .mockResolvedValueOnce(before) .mockResolvedValueOnce(after); const result = await actions.saveSecondaryPool?.({ cookies: {} as never, request: request(after), } as never); expect(result).toMatchObject({ weaponModSecondaryPoolSaved: true, weaponModSecondaryPoolMode: 'edit', resultToken: expect.any(String), }); expect(mocks.requirePermission).toHaveBeenCalledWith( { id: 'operator-1' }, 'data.manage', ); expect(mocks.replaceModSecondaryPool).toHaveBeenCalledWith( mocks.database, 'weapon', after, ); expect(mocks.audits).toEqual([ { actorId: 'operator-1', category: 'game_data', action: 'weapon_mod_secondary_pool.updated', entityId: 'weapon-mod-secondary-pool', before, after, database: mocks.database, }, ]); expect(mocks.database.exec.mock.calls).toEqual([ ['BEGIN IMMEDIATE'], ['COMMIT'], ]); }); it('rolls back without committing when the audit write fails', async () => { const before = pool('before'); const after = pool('after', 1); const auditError = new Error('audit insert failed'); mocks.getModSecondaryPool .mockResolvedValueOnce(before) .mockResolvedValueOnce(after); mocks.recordIsacAudit.mockRejectedValueOnce(auditError); await expect( actions.saveSecondaryPool?.({ cookies: {} as never, request: request(after), } as never), ).rejects.toThrow(auditError); expect(mocks.recordIsacAudit).toHaveBeenCalledOnce(); expect(mocks.database.exec).toHaveBeenCalledWith('ROLLBACK'); expect(mocks.database.exec).not.toHaveBeenCalledWith('COMMIT'); expect(mocks.database.exec.mock.calls).toEqual([ ['BEGIN IMMEDIATE'], ['ROLLBACK'], ]); }); });