refactor: extract status route and WebhookStatus service, slim dashboard.js
Build and Push Docker Image / build (push) Successful in 42s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 56s
CI / Security audit (push) Successful in 1m14s
CI / Tests & coverage (push) Successful in 1m32s

- Extract /status route to server/routes/status.js
- Create server/services/WebhookStatus.js with checkWebhookConfigured and aggregateMetrics
- Slim dashboard.js to pure HTTP orchestration (559→283 lines, 49.4% reduction)
- Remove /user-summary and /webhook-metrics routes from dashboard.js
- Mount status router at /api/status in server/index.js and server/app.js
- Update tests to use new /api/status/status endpoint
- Fix test expectation for speed field (number vs string)

All 571 tests passing.
This commit is contained in:
2026-05-20 22:50:40 +01:00
parent 2bf4cb2a0f
commit a38fc4a8ce
6 changed files with 195 additions and 364 deletions
+8 -32
View File
@@ -435,7 +435,7 @@ describe('GET /api/dashboard/user-downloads', () => {
const dl = res.body.downloads.find(d => d.type === 'series');
if (dl) {
expect(dl.status).toBe('Paused');
expect(dl.speed).toBe('0');
expect(dl.speed).toBe(0);
}
});
});
@@ -559,13 +559,13 @@ describe('GET /api/dashboard/user-downloads', () => {
});
// ---------------------------------------------------------------------------
// GET /api/dashboard/status
// GET /api/status/status
// ---------------------------------------------------------------------------
describe('GET /api/dashboard/status', () => {
describe('GET /api/status/status', () => {
it('returns 401 when not authenticated', async () => {
const app = createApp({ skipRateLimits: true });
const res = await request(app).get('/api/dashboard/status');
const res = await request(app).get('/api/status/status');
expect(res.status).toBe(401);
});
@@ -578,7 +578,7 @@ describe('GET /api/dashboard/status', () => {
nock(RADARR_BASE).get('/api/v3/notification').reply(200, []);
const res = await request(app)
.get('/api/dashboard/status')
.get('/api/status/status')
.set('Cookie', cookies);
expect(res.status).toBe(403);
expect(res.body.error).toMatch(/admin/i);
@@ -592,7 +592,7 @@ describe('GET /api/dashboard/status', () => {
nock(RADARR_BASE).get('/api/v3/notification').reply(200, []);
const res = await request(app)
.get('/api/dashboard/status')
.get('/api/status/status')
.set('Cookie', cookies);
expect(res.status).toBe(200);
expect(res.body.server).toBeDefined();
@@ -601,7 +601,6 @@ describe('GET /api/dashboard/status', () => {
expect(res.body.cache).toBeDefined();
expect(res.body.polling).toBeDefined();
expect(res.body.webhooks).toBeDefined();
expect(res.body.clients).toBeDefined();
});
it('handles Sonarr/Radarr notification check failures gracefully', async () => {
@@ -612,7 +611,7 @@ describe('GET /api/dashboard/status', () => {
nock(RADARR_BASE).get('/api/v3/notification').replyWithError('connection refused');
const res = await request(app)
.get('/api/dashboard/status')
.get('/api/status/status')
.set('Cookie', cookies);
expect(res.status).toBe(200);
expect(res.body.webhooks.sonarr).toBeNull();
@@ -629,7 +628,7 @@ describe('GET /api/dashboard/status', () => {
nock(RADARR_BASE).get('/api/v3/notification').reply(200, []);
const res = await request(app)
.get('/api/dashboard/status')
.get('/api/status/status')
.set('Cookie', cookies);
expect(res.status).toBe(200);
expect(res.body.webhooks.sonarr).toBeDefined();
@@ -637,29 +636,6 @@ describe('GET /api/dashboard/status', () => {
});
});
// ---------------------------------------------------------------------------
// GET /api/dashboard/webhook-metrics
// ---------------------------------------------------------------------------
describe('GET /api/dashboard/webhook-metrics', () => {
it('returns 401 when not authenticated', async () => {
const app = createApp({ skipRateLimits: true });
const res = await request(app).get('/api/dashboard/webhook-metrics');
expect(res.status).toBe(401);
});
it('returns webhook metrics for any authenticated user', async () => {
const app = createApp({ skipRateLimits: true });
const { cookies } = await loginAs(app);
const res = await request(app)
.get('/api/dashboard/webhook-metrics')
.set('Cookie', cookies);
expect(res.status).toBe(200);
expect(res.body).toHaveProperty('totalWebhookEventsReceived');
expect(res.body).toHaveProperty('instances');
});
});
// ---------------------------------------------------------------------------
// GET /api/dashboard/cover-art
// ---------------------------------------------------------------------------