feat: Admin Area System: Database Backup/Restore and Danger Zone
This commit is contained in:
@@ -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');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user