test: remediate test suite, enable skipped frontend/SSE tests, and add comprehensive unit tests
Build and Push Docker Image / build (push) Successful in 53s
Docs Check / Markdown lint (push) Successful in 1m36s
Licence Check / Licence compatibility and copyright header verification (push) Failing after 2m31s
CI / Security audit (push) Successful in 2m55s
Docs Check / Mermaid diagram parse check (push) Successful in 3m24s
CI / Swagger Validation & Coverage (push) Successful in 3m30s
CI / Tests & coverage (push) Successful in 3m50s
Build and Push Docker Image / build (push) Successful in 53s
Docs Check / Markdown lint (push) Successful in 1m36s
Licence Check / Licence compatibility and copyright header verification (push) Failing after 2m31s
CI / Security audit (push) Successful in 2m55s
Docs Check / Mermaid diagram parse check (push) Successful in 3m24s
CI / Swagger Validation & Coverage (push) Successful in 3m30s
CI / Tests & coverage (push) Successful in 3m50s
- Deleted redundant unit test file tests/unit/dashboard.test.js - Enabled skipped frontend DOM state and API tests in tests/frontend/state.test.js - Fixed Supertest client socket abort exception in SSE stream integration tests using new graceful testClose parameter - Consolidated duplicate helpers in server/routes/history.js and server/utils/arrRetrievers.js to unified services TagMatcher and DownloadAssembler - Added comprehensive unit tests for loadSecrets.js, PollingSonarrRetriever.js, PollingRadarrRetriever.js, and ombiHelpers.js - Achieved a 100% Vitest pass rate (834/834 tests) with robust code coverage
This commit is contained in:
+242
-24
@@ -63,40 +63,258 @@ describe('state object', () => {
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Skipped tests with explanations
|
||||
// Enabled tests with robust mocking
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe.skip('frontend API functions (enableOmbiWebhook, testOmbiWebhook)', () => {
|
||||
it('enableOmbiWebhook makes POST request to /api/ombi/webhook/enable', () => {
|
||||
// Skipped because:
|
||||
// 1. These functions make actual fetch calls to backend endpoints
|
||||
// 2. They depend on the global state object (csrfToken)
|
||||
// 3. The backend endpoints are already tested in tests/integration/ombi.test.js
|
||||
// 4. Testing would require mocking fetch and state, which adds complexity
|
||||
// TODO: Could be added later with proper mocking infrastructure
|
||||
});
|
||||
import { enableOmbiWebhook as apiEnableOmbiWebhook, testOmbiWebhook as apiTestOmbiWebhook } from '../../client/src/api.js';
|
||||
import { renderWebhookStatus, enableOmbiWebhook as uiEnableOmbiWebhook, testOmbiWebhook as uiTestOmbiWebhook } from '../../client/src/ui/webhooks.js';
|
||||
|
||||
it('testOmbiWebhook makes POST request to /api/ombi/webhook/test', () => {
|
||||
// Same reasoning as above
|
||||
const mockFetch = vi.fn().mockImplementation((url, init) => {
|
||||
if (url === '/api/ombi/webhook/enable') {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ success: true })
|
||||
});
|
||||
}
|
||||
if (url === '/api/ombi/webhook/test') {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ success: true })
|
||||
});
|
||||
}
|
||||
if (url === '/api/webhook/config') {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({ valid: true })
|
||||
});
|
||||
}
|
||||
if (url === '/api/sonarr/notifications') {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve([])
|
||||
});
|
||||
}
|
||||
if (url === '/api/radarr/notifications') {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve([])
|
||||
});
|
||||
}
|
||||
if (url === '/api/ombi/webhook/status') {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({
|
||||
enabled: true,
|
||||
triggers: {
|
||||
requestAvailable: true,
|
||||
requestApproved: true,
|
||||
requestDeclined: true,
|
||||
requestPending: true,
|
||||
requestProcessing: true
|
||||
},
|
||||
stats: {
|
||||
eventsReceived: 10,
|
||||
pollsSkipped: 5,
|
||||
lastWebhookTimestamp: Date.now() - 60000
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
if (url === '/api/webhook/metrics') {
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({})
|
||||
});
|
||||
}
|
||||
return Promise.resolve({
|
||||
ok: false,
|
||||
status: 404
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip('frontend UI functions (webhooks.js Ombi functions)', () => {
|
||||
function setupDomForOmbiWebhooks() {
|
||||
document.body.innerHTML = `
|
||||
<div id="webhooks-section"></div>
|
||||
<div id="webhooks-content"></div>
|
||||
<div id="webhooks-toggle"></div>
|
||||
<div id="webhook-loading" class="hidden"></div>
|
||||
<div id="sonarr-status"></div>
|
||||
<button id="enable-sonarr-webhook"></button>
|
||||
<button id="test-sonarr-webhook"></button>
|
||||
<div id="sonarr-triggers"></div>
|
||||
<div id="sonarr-stats"></div>
|
||||
<div id="radarr-status"></div>
|
||||
<button id="enable-radarr-webhook"></button>
|
||||
<button id="test-radarr-webhook"></button>
|
||||
<div id="radarr-triggers"></div>
|
||||
<div id="radarr-stats"></div>
|
||||
<div id="ombi-status"></div>
|
||||
<button id="enable-ombi-webhook"></button>
|
||||
<button id="test-ombi-webhook"></button>
|
||||
<div id="ombi-triggers" class="hidden">
|
||||
<div id="ombi-requestAvailable"></div>
|
||||
<div id="ombi-requestApproved"></div>
|
||||
<div id="ombi-requestDeclined"></div>
|
||||
<div id="ombi-requestPending"></div>
|
||||
<div id="ombi-requestProcessing"></div>
|
||||
</div>
|
||||
<div id="ombi-stats" class="hidden">
|
||||
<div id="ombi-events"></div>
|
||||
<div id="ombi-polls"></div>
|
||||
<div id="ombi-last"></div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
describe('frontend API functions (enableOmbiWebhook, testOmbiWebhook)', () => {
|
||||
beforeEach(() => {
|
||||
global.fetch = mockFetch;
|
||||
mockFetch.mockClear();
|
||||
state.csrfToken = 'test-csrf-token';
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
delete global.fetch;
|
||||
});
|
||||
|
||||
it('enableOmbiWebhook makes POST request to /api/ombi/webhook/enable', async () => {
|
||||
const result = await apiEnableOmbiWebhook();
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/ombi/webhook/enable', {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRF-Token': 'test-csrf-token' }
|
||||
});
|
||||
expect(result).toEqual({ success: true });
|
||||
});
|
||||
|
||||
it('testOmbiWebhook makes POST request to /api/ombi/webhook/test', async () => {
|
||||
const result = await apiTestOmbiWebhook();
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/ombi/webhook/test', {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRF-Token': 'test-csrf-token' }
|
||||
});
|
||||
expect(result).toEqual({ success: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('frontend UI functions (webhooks.js Ombi functions)', () => {
|
||||
beforeEach(() => {
|
||||
global.fetch = mockFetch;
|
||||
mockFetch.mockClear();
|
||||
global.alert = vi.fn();
|
||||
setupDomForOmbiWebhooks();
|
||||
state.csrfToken = 'test-csrf-token';
|
||||
|
||||
// Set up default state for Ombi webhook
|
||||
state.ombiWebhook = {
|
||||
enabled: false,
|
||||
triggers: {
|
||||
requestAvailable: false,
|
||||
requestApproved: false,
|
||||
requestDeclined: false,
|
||||
requestPending: false,
|
||||
requestProcessing: false
|
||||
},
|
||||
stats: null
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
delete global.fetch;
|
||||
delete global.alert;
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
it('renderWebhookStatus renders Ombi webhook status correctly', () => {
|
||||
// Skipped because:
|
||||
// 1. The renderWebhookStatus function is tightly coupled to the DOM
|
||||
// 2. It requires extensive DOM setup (multiple elements with specific IDs)
|
||||
// 3. It depends on the global state object
|
||||
// 4. The logic is straightforward (conditional rendering based on state)
|
||||
// 5. Integration testing via E2E would be more appropriate
|
||||
// TODO: Could be added later with proper DOM mocking or E2E tests
|
||||
// 1. Test disabled state
|
||||
state.ombiWebhook.enabled = false;
|
||||
renderWebhookStatus();
|
||||
expect(document.getElementById('ombi-status').textContent).toBe('○ Disabled');
|
||||
expect(document.getElementById('enable-ombi-webhook').classList.contains('hidden')).toBe(false);
|
||||
expect(document.getElementById('test-ombi-webhook').classList.contains('hidden')).toBe(true);
|
||||
expect(document.getElementById('ombi-triggers').classList.contains('hidden')).toBe(true);
|
||||
|
||||
// 2. Test enabled state with triggers and stats
|
||||
state.ombiWebhook.enabled = true;
|
||||
state.ombiWebhook.triggers.requestAvailable = true;
|
||||
state.ombiWebhook.triggers.requestApproved = true;
|
||||
state.ombiWebhook.stats = {
|
||||
eventsReceived: 42,
|
||||
pollsSkipped: 17,
|
||||
lastWebhookTimestamp: Date.now() - 3600000 // 1 hour ago
|
||||
};
|
||||
renderWebhookStatus();
|
||||
expect(document.getElementById('ombi-status').textContent).toBe('● Enabled');
|
||||
expect(document.getElementById('enable-ombi-webhook').classList.contains('hidden')).toBe(true);
|
||||
expect(document.getElementById('test-ombi-webhook').classList.contains('hidden')).toBe(false);
|
||||
expect(document.getElementById('ombi-triggers').classList.contains('hidden')).toBe(false);
|
||||
|
||||
// Check triggers rendering
|
||||
expect(document.getElementById('ombi-requestAvailable').textContent).toBe('✓');
|
||||
expect(document.getElementById('ombi-requestApproved').textContent).toBe('✓');
|
||||
expect(document.getElementById('ombi-requestDeclined').textContent).toBe('✗');
|
||||
|
||||
// Check stats rendering
|
||||
expect(document.getElementById('ombi-stats').classList.contains('hidden')).toBe(false);
|
||||
expect(document.getElementById('ombi-events').textContent).toBe('42');
|
||||
expect(document.getElementById('ombi-polls').textContent).toBe('17');
|
||||
expect(document.getElementById('ombi-last').textContent).toBe('1h ago');
|
||||
});
|
||||
|
||||
it('enableOmbiWebhook UI handler calls API and updates state', () => {
|
||||
// Same reasoning as above
|
||||
it('enableOmbiWebhook UI handler calls API and updates state', async () => {
|
||||
// Mock the state returned by fetchWebhookStatus to enable it
|
||||
mockFetch.mockImplementation((url) => {
|
||||
if (url === '/api/ombi/webhook/enable') {
|
||||
return Promise.resolve({ ok: true, json: () => Promise.resolve({ success: true }) });
|
||||
}
|
||||
if (url === '/api/ombi/webhook/status') {
|
||||
// Return updated state where it is enabled
|
||||
return Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({
|
||||
enabled: true,
|
||||
triggers: {
|
||||
requestAvailable: true,
|
||||
requestApproved: false,
|
||||
requestDeclined: false,
|
||||
requestPending: false,
|
||||
requestProcessing: false
|
||||
},
|
||||
stats: null
|
||||
})
|
||||
});
|
||||
}
|
||||
// For all other config fetches, return basic values
|
||||
return Promise.resolve({ ok: true, json: () => Promise.resolve({}) });
|
||||
});
|
||||
|
||||
await uiEnableOmbiWebhook();
|
||||
|
||||
// Should make POST call to enable
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/ombi/webhook/enable', {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRF-Token': 'test-csrf-token' }
|
||||
});
|
||||
|
||||
// State should be updated
|
||||
expect(state.ombiWebhook.enabled).toBe(true);
|
||||
|
||||
// Render the webhook status to update the DOM
|
||||
renderWebhookStatus();
|
||||
|
||||
// UI should show enabled status
|
||||
expect(document.getElementById('ombi-status').textContent).toBe('● Enabled');
|
||||
});
|
||||
|
||||
it('testOmbiWebhook UI handler calls API and updates state', () => {
|
||||
// Same reasoning as above
|
||||
it('testOmbiWebhook UI handler calls API and updates state', async () => {
|
||||
await uiTestOmbiWebhook();
|
||||
|
||||
// Should make POST call to test
|
||||
expect(mockFetch).toHaveBeenCalledWith('/api/ombi/webhook/test', {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRF-Token': 'test-csrf-token' }
|
||||
});
|
||||
|
||||
// Should alert success
|
||||
expect(global.alert).toHaveBeenCalledWith('Ombi webhook test sent successfully!');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user