Files
shd.build/src/routes/isac/weaponmods/secondary-pool-action.test.ts
T
jb 57068b61cd
Validate and deploy production / validate (push) Canceled after 0s
Validate and deploy production / deploy (push) Canceled after 0s
Validate and deploy staging / validate (push) Successful in 28s
Validate and deploy staging / deploy (push) Successful in 1m3s
feat: expand ISAC content modeling
2026-08-03 01:23:20 -04:00

167 lines
4.8 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
const mocks = vi.hoisted(() => ({
audits: [] as Array<Record<string, unknown>>,
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<typeof pool>) => {
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'],
]);
});
});