feat: Add Ombi request filtering and search
Build and Push Docker Image / build (push) Successful in 1m29s
Docs Check / Markdown lint (push) Successful in 1m51s
Licence Check / Licence compatibility and copyright header verification (push) Failing after 2m3s
CI / Security audit (push) Successful in 2m54s
CI / Swagger Validation & Coverage (push) Successful in 3m6s
Docs Check / Mermaid diagram parse check (push) Successful in 3m13s
CI / Tests & coverage (push) Successful in 3m31s
Build and Push Docker Image / build (push) Successful in 1m29s
Docs Check / Markdown lint (push) Successful in 1m51s
Licence Check / Licence compatibility and copyright header verification (push) Failing after 2m3s
CI / Security audit (push) Successful in 2m54s
CI / Swagger Validation & Coverage (push) Successful in 3m6s
Docs Check / Mermaid diagram parse check (push) Successful in 3m13s
CI / Tests & coverage (push) Successful in 3m31s
- Add request filters UI (type, status, sort, search) - Implement dual-layer filtering (server + client) - Add ombiFilters utility for consistent filtering logic - Persist filter preferences in localStorage - Add SSE support for real-time Ombi request updates - Add webhook endpoints for Ombi integration - Update OpenAPI spec for new endpoints - Add unit tests for filter logic and UI - Add integration tests for Ombi routes
This commit is contained in:
@@ -143,6 +143,9 @@ afterEach(() => {
|
||||
// GET /api/ombi/requests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// TODO: Unskip these tests once arrRetrieverRegistry can be properly mocked.
|
||||
// The tests need to control the return value of getOmbiRequests() to test
|
||||
// user filtering, showAll parameter, and edge cases reliably.
|
||||
describe.skip('GET /api/ombi/requests', () => {
|
||||
let app;
|
||||
|
||||
@@ -387,6 +390,163 @@ describe.skip('GET /api/ombi/requests', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GET /api/ombi/requests — query param filtering
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const FILTERED_MOVIE_REQUESTS = [
|
||||
{ id: 1, title: 'The Batman', requestedDate: '2026-05-21T10:00:00.000Z', available: false, approved: true, denied: false, requested: true, theMovieDbId: 414906 },
|
||||
{ id: 2, title: 'Batman Returns', requestedDate: '2026-05-10T10:00:00.000Z', available: true, approved: true, denied: false, requested: true, theMovieDbId: 414907 }
|
||||
];
|
||||
|
||||
const FILTERED_TV_REQUESTS = [
|
||||
{ id: 3, title: 'Superman Show', requestedDate: '2026-05-15T10:00:00.000Z', available: false, approved: false, denied: false, requested: true, theMovieDbId: 101 }
|
||||
];
|
||||
|
||||
describe('GET /api/ombi/requests query params', () => {
|
||||
let app;
|
||||
let arrRetrieverRegistry;
|
||||
|
||||
beforeEach(() => {
|
||||
app = makeApp();
|
||||
setupOmbiRequestMocks(FILTERED_MOVIE_REQUESTS, FILTERED_TV_REQUESTS);
|
||||
|
||||
// Reset the singleton registry so it re-initializes on each request
|
||||
arrRetrieverRegistry = require('../../server/utils/arrRetrievers');
|
||||
arrRetrieverRegistry.retrievers.clear();
|
||||
arrRetrieverRegistry.initialized = false;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (arrRetrieverRegistry) {
|
||||
arrRetrieverRegistry.retrievers.clear();
|
||||
arrRetrieverRegistry.initialized = false;
|
||||
}
|
||||
});
|
||||
|
||||
it('filters by type=movie', async () => {
|
||||
const { cookies } = await authenticateUser(app, 'AdminUser', true);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/api/ombi/requests?type=movie&showAll=true')
|
||||
.set('Cookie', cookies)
|
||||
.expect(200);
|
||||
|
||||
expect(res.body.requests.movie.length, `Body was: ${JSON.stringify(res.body)}`).toBe(2);
|
||||
expect(res.body.requests.tv).toHaveLength(0);
|
||||
expect(res.body.total).toBe(2);
|
||||
});
|
||||
|
||||
it('filters by type=tv', async () => {
|
||||
const { cookies } = await authenticateUser(app, 'AdminUser', true);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/api/ombi/requests?type=tv&showAll=true')
|
||||
.set('Cookie', cookies)
|
||||
.expect(200);
|
||||
|
||||
expect(res.body.requests.movie).toHaveLength(0);
|
||||
expect(res.body.requests.tv).toHaveLength(1);
|
||||
expect(res.body.total).toBe(1);
|
||||
});
|
||||
|
||||
it('filters by status=pending', async () => {
|
||||
const { cookies } = await authenticateUser(app, 'AdminUser', true);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/api/ombi/requests?status=pending&showAll=true')
|
||||
.set('Cookie', cookies)
|
||||
.expect(200);
|
||||
|
||||
expect(res.body.total).toBe(1);
|
||||
expect(res.body.requests.tv[0].title).toBe('Superman Show');
|
||||
});
|
||||
|
||||
it('filters by status=available', async () => {
|
||||
const { cookies } = await authenticateUser(app, 'AdminUser', true);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/api/ombi/requests?status=available&showAll=true')
|
||||
.set('Cookie', cookies)
|
||||
.expect(200);
|
||||
|
||||
expect(res.body.total).toBe(1);
|
||||
expect(res.body.requests.movie[0].title).toBe('Batman Returns');
|
||||
});
|
||||
|
||||
it('sorts by title_asc', async () => {
|
||||
const { cookies } = await authenticateUser(app, 'AdminUser', true);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/api/ombi/requests?sort=title_asc&showAll=true')
|
||||
.set('Cookie', cookies)
|
||||
.expect(200);
|
||||
|
||||
const all = [...res.body.requests.movie, ...res.body.requests.tv];
|
||||
expect(all.map(r => r.title)).toEqual(['Batman Returns', 'The Batman', 'Superman Show']);
|
||||
});
|
||||
|
||||
it('sorts by title_desc', async () => {
|
||||
const { cookies } = await authenticateUser(app, 'AdminUser', true);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/api/ombi/requests?sort=title_desc&showAll=true')
|
||||
.set('Cookie', cookies)
|
||||
.expect(200);
|
||||
|
||||
const all = [...res.body.requests.movie, ...res.body.requests.tv];
|
||||
expect(all.map(r => r.title)).toEqual(['The Batman', 'Batman Returns', 'Superman Show']);
|
||||
});
|
||||
|
||||
it('sorts by requestedDate_desc (default)', async () => {
|
||||
const { cookies } = await authenticateUser(app, 'AdminUser', true);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/api/ombi/requests?showAll=true')
|
||||
.set('Cookie', cookies)
|
||||
.expect(200);
|
||||
|
||||
const all = [...res.body.requests.movie, ...res.body.requests.tv];
|
||||
expect(all.map(r => r.title)).toEqual(['The Batman', 'Batman Returns', 'Superman Show']);
|
||||
});
|
||||
|
||||
it('searches by title substring', async () => {
|
||||
const { cookies } = await authenticateUser(app, 'AdminUser', true);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/api/ombi/requests?search=bat&showAll=true')
|
||||
.set('Cookie', cookies)
|
||||
.expect(200);
|
||||
|
||||
expect(res.body.total).toBe(2);
|
||||
expect(res.body.requests.movie).toHaveLength(2);
|
||||
expect(res.body.requests.tv).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('combines multiple query params', async () => {
|
||||
const { cookies } = await authenticateUser(app, 'AdminUser', true);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/api/ombi/requests?type=movie&status=approved&search=bat&sort=title_asc&showAll=true')
|
||||
.set('Cookie', cookies)
|
||||
.expect(200);
|
||||
|
||||
expect(res.body.total).toBe(1);
|
||||
expect(res.body.requests.movie[0].title).toBe('The Batman');
|
||||
});
|
||||
|
||||
it('invalid sort falls back to default', async () => {
|
||||
const { cookies } = await authenticateUser(app, 'AdminUser', true);
|
||||
|
||||
const res = await request(app)
|
||||
.get('/api/ombi/requests?sort=invalid&showAll=true')
|
||||
.set('Cookie', cookies)
|
||||
.expect(200);
|
||||
|
||||
expect(res.body.total).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GET /api/ombi/webhook/status
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user