AI Implementation feature(871): Admin Area System: Database Backup/Restore and Danger Zone (#61)

This commit was merged in pull request #61.
This commit is contained in:
2026-07-23 12:10:41 +00:00
parent 6bac67fad7
commit 470ddd30c3
42 changed files with 3996 additions and 55 deletions
+76
View File
@@ -0,0 +1,76 @@
process.env.DATABASE_PATH = ':memory:';
process.env.THEMES_DIR = './themes';
process.env.FRONTEND_DIST = './frontend/dist';
import {
coerceSystemError,
destructiveCopy,
deriveBackupFilename,
friendlySystemErrorMessage,
} from '../../frontend/src/app/features/admin/system/system.pure';
describe('Job 871: friendlySystemErrorMessage mapping', () => {
it('returns the friendly token-expired message for SYSTEM_TOKEN_EXPIRED', () => {
const err = { status: 400, code: 'SYSTEM_TOKEN_EXPIRED', message: 'expired' };
expect(friendlySystemErrorMessage('restore-backup', err)).toContain('expired');
expect(friendlySystemErrorMessage('restore-backup', err)).toMatch(/Re-authenticate/i);
});
it('returns a specific message for SYSTEM_RESTORE_ROLLED_BACK', () => {
expect(friendlySystemErrorMessage('restore-backup', { status: 500, code: 'SYSTEM_RESTORE_ROLLED_BACK', message: 'rb' }))
.toContain('rolled back');
});
it('falls back to operation message when code is unknown', () => {
expect(friendlySystemErrorMessage('wipe-challenges', { status: 500, code: 'WEIRD', message: 'broken' }))
.toBe('broken');
});
it('falls back to the operation default when message is empty', () => {
expect(friendlySystemErrorMessage('reset-scores', { status: 500, code: 'WEIRD', message: '' }))
.toContain('Reset scores failed');
});
});
describe('Job 871: destructiveCopy', () => {
it('reset-scores confirms with RESET SCORES', () => {
expect(destructiveCopy('reset-scores').confirmation).toBe('RESET SCORES');
});
it('wipe-challenges confirms with WIPE CHALLENGES', () => {
expect(destructiveCopy('wipe-challenges').confirmation).toBe('WIPE CHALLENGES');
});
it('restore-backup confirms with RESTORE BACKUP', () => {
expect(destructiveCopy('restore-backup').confirmation).toBe('RESTORE BACKUP');
});
});
describe('Job 871: deriveBackupFilename', () => {
it('contains today date and .json', () => {
const name = deriveBackupFilename();
expect(name).toMatch(/^hipctf-backup-\d{4}-\d{2}-\d{2}\.json$/);
});
});
describe('Job 871: coerceSystemError', () => {
it('reads body from HttpErrorResponse shape', () => {
const out = coerceSystemError(
{ status: 400, error: { code: 'X', message: 'Y' } },
'fallback',
);
expect(out.code).toBe('X');
expect(out.message).toBe('Y');
expect(out.status).toBe(400);
});
it('falls back when no envelope is present', () => {
const out = coerceSystemError(new Error('boom'), 'fallback');
expect(out.code).toBe('INTERNAL');
expect(out.message).toBe('boom');
});
it('falls back for null', () => {
const out = coerceSystemError(null, 'fallback');
expect(out.code).toBe('INTERNAL');
expect(out.message).toBe('fallback');
});
});