import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import request from 'supertest'; import { afterEach, describe, expect, it } from 'vitest'; import { createApp } from './app'; import type { RuntimeSnapshot } from './lib/config'; import type { RuntimeController } from './lib/runtime'; import { StateStore } from './lib/store'; class FakeRuntime implements RuntimeController { private status: RuntimeSnapshot = { status: 'idle' as const, pid: null, startedAt: null, lastError: null, }; getSnapshot() { return { ...this.status }; } async start() { this.status = { status: 'live', pid: 999, startedAt: new Date('2026-04-01T00:00:00.000Z').toISOString(), lastError: null, }; return this.getSnapshot(); } async restart() { return this.start(); } async reload() { return this.getSnapshot(); } } const cleanupDirs: string[] = []; afterEach(async () => { await Promise.all(cleanupDirs.splice(0).map((dir) => fs.rm(dir, { recursive: true, force: true }))); }); describe('panel api', () => { it('rejects user creation against a non-assignable service', async () => { const app = await createTestApp(); const response = await request(app).post('/api/users').send({ username: 'bad-admin-user', password: 'secret123', serviceId: 'admin', quotaMb: 100, }); expect(response.status).toBe(400); expect(response.body.error).toMatch(/enabled assignable/i); }); it('pauses and deletes a user through the api', async () => { const app = await createTestApp(); const initial = await request(app).get('/api/state'); const userId = initial.body.userRecords[0].id; const username = initial.body.userRecords[0].username; const paused = await request(app).post(`/api/users/${userId}/pause`); expect(paused.status).toBe(200); expect(paused.body.userRecords.find((entry: { id: string }) => entry.id === userId).paused).toBe(true); const removed = await request(app).delete(`/api/users/${userId}`); expect(removed.status).toBe(200); expect(removed.body.userRecords.some((entry: { username: string }) => entry.username === username)).toBe( false, ); }); }); async function createTestApp() { const dir = await fs.mkdtemp(path.join(os.tmpdir(), '3proxy-ui-')); cleanupDirs.push(dir); const runtime = new FakeRuntime(); const store = new StateStore(path.join(dir, 'state', 'panel-state.json')); return createApp({ store, runtime, runtimeRootDir: dir, }); }