Files
Immich/server/src/controllers/library.controller.spec.ts
T

182 lines
6.7 KiB
TypeScript

import request from 'supertest';
import { LibraryController } from 'src/controllers/library.controller.js';
import { LibraryService } from 'src/services/library.service.js';
import { factory } from 'test/small.factory.js';
import { ControllerContext, controllerSetup, mockBaseService } from 'test/utils.js';
describe(LibraryController.name, () => {
let ctx: ControllerContext;
const service = mockBaseService(LibraryService);
beforeAll(async () => {
ctx = await controllerSetup(LibraryController, [{ provide: LibraryService, useValue: service }]);
return () => ctx.close();
});
beforeEach(() => {
service.resetAllMocks();
ctx.reset();
});
const id = factory.uuid();
describe('POST /libraries', () => {
it('should require an owner id', async () => {
const { status, body } = await request(ctx.getHttpServer()).post('/libraries').send({});
expect(status).toBe(400);
expect(body).toEqual(
factory.responses.validationError([
{ path: ['ownerId'], message: 'Invalid input: expected string, received undefined' },
]),
);
expect(service.create).not.toHaveBeenCalled();
});
it('should reject duplicate import paths', async () => {
const { status, body } = await request(ctx.getHttpServer())
.post('/libraries')
.send({ ownerId: id, importPaths: ['/path', '/path'] });
expect(status).toBe(400);
expect(body).toEqual(
factory.responses.validationError([{ path: ['importPaths'], message: 'Array must have unique items' }]),
);
expect(service.create).not.toHaveBeenCalled();
});
it('should reject duplicate exclusion patterns', async () => {
const { status, body } = await request(ctx.getHttpServer())
.post('/libraries')
.send({ ownerId: id, exclusionPatterns: ['**/Raw/**', '**/Raw/**'] });
expect(status).toBe(400);
expect(body).toEqual(
factory.responses.validationError([{ path: ['exclusionPatterns'], message: 'Array must have unique items' }]),
);
expect(service.create).not.toHaveBeenCalled();
});
});
describe('PUT /libraries/:id', () => {
it('should require a valid uuid', async () => {
const { status, body } = await request(ctx.getHttpServer())
.put('/libraries/invalid')
.send({ name: 'New Library Name' });
expect(status).toBe(400);
expect(body).toEqual(factory.responses.validationError([{ path: ['id'], message: 'Invalid UUID' }]));
expect(service.update).not.toHaveBeenCalled();
});
it('should reject an empty name', async () => {
const { status, body } = await request(ctx.getHttpServer()).put(`/libraries/${id}`).send({ name: '' });
expect(status).toBe(400);
expect(body).toEqual(
factory.responses.validationError([
{ path: ['name'], message: 'Too small: expected string to have >=1 characters' },
]),
);
expect(service.update).not.toHaveBeenCalled();
});
it('should reject an empty import path', async () => {
const { status, body } = await request(ctx.getHttpServer())
.put(`/libraries/${id}`)
.send({ importPaths: [''] });
expect(status).toBe(400);
expect(body).toEqual(
factory.responses.validationError([{ path: ['importPaths'], message: 'Array items must not be empty' }]),
);
expect(service.update).not.toHaveBeenCalled();
});
it('should reject duplicate import paths', async () => {
const { status, body } = await request(ctx.getHttpServer())
.put(`/libraries/${id}`)
.send({ importPaths: ['/path', '/path'] });
expect(status).toBe(400);
expect(body).toEqual(
factory.responses.validationError([{ path: ['importPaths'], message: 'Array must have unique items' }]),
);
expect(service.update).not.toHaveBeenCalled();
});
it('should reject an empty exclusion pattern', async () => {
const { status, body } = await request(ctx.getHttpServer())
.put(`/libraries/${id}`)
.send({ exclusionPatterns: [''] });
expect(status).toBe(400);
expect(body).toEqual(
factory.responses.validationError([{ path: ['exclusionPatterns'], message: 'Array items must not be empty' }]),
);
expect(service.update).not.toHaveBeenCalled();
});
it('should reject duplicate exclusion patterns', async () => {
const { status, body } = await request(ctx.getHttpServer())
.put(`/libraries/${id}`)
.send({ exclusionPatterns: ['**/*.jpg', '**/*.jpg'] });
expect(status).toBe(400);
expect(body).toEqual(
factory.responses.validationError([{ path: ['exclusionPatterns'], message: 'Array must have unique items' }]),
);
expect(service.update).not.toHaveBeenCalled();
});
});
describe('POST /libraries/:id/validate', () => {
it('should require a valid uuid', async () => {
const { status, body } = await request(ctx.getHttpServer()).post('/libraries/invalid/validate').send({});
expect(status).toBe(400);
expect(body).toEqual(factory.responses.validationError([{ path: ['id'], message: 'Invalid UUID' }]));
expect(service.validate).not.toHaveBeenCalled();
});
it('should not require import paths', async () => {
service.validate.mockResolvedValue({ importPaths: [] });
const { status } = await request(ctx.getHttpServer()).post(`/libraries/${id}/validate`).send({});
expect(status).toBe(200);
expect(service.validate).toHaveBeenCalledWith(id, {});
});
});
describe('GET /libraries/:id/statistics', () => {
it('should require a valid uuid', async () => {
const { status, body } = await request(ctx.getHttpServer()).get('/libraries/invalid/statistics');
expect(status).toBe(400);
expect(body).toEqual(factory.responses.validationError([{ path: ['id'], message: 'Invalid UUID' }]));
expect(service.getStatistics).not.toHaveBeenCalled();
});
});
describe('POST /libraries/:id/scan', () => {
it('should require a valid uuid', async () => {
const { status, body } = await request(ctx.getHttpServer()).post('/libraries/invalid/scan');
expect(status).toBe(400);
expect(body).toEqual(factory.responses.validationError([{ path: ['id'], message: 'Invalid UUID' }]));
expect(service.queueScan).not.toHaveBeenCalled();
});
});
describe('DELETE /libraries/:id', () => {
it('should require a valid uuid', async () => {
const { status, body } = await request(ctx.getHttpServer()).delete('/libraries/invalid');
expect(status).toBe(400);
expect(body).toEqual(factory.responses.validationError([{ path: ['id'], message: 'Invalid UUID' }]));
expect(service.delete).not.toHaveBeenCalled();
});
});
});