mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
* feat: user pincode * pr feedback * chore: cleanup --------- Co-authored-by: Jason Rasmussen <jason@rasm.me>
192 lines
7.4 KiB
TypeScript
192 lines
7.4 KiB
TypeScript
import { AuthController } from 'src/controllers/auth.controller';
|
|
import { LoginResponseDto } from 'src/dtos/auth.dto';
|
|
import { AuthService } from 'src/services/auth.service';
|
|
import request from 'supertest';
|
|
import { errorDto } from 'test/medium/responses';
|
|
import { ControllerContext, controllerSetup, mockBaseService } from 'test/utils';
|
|
|
|
describe(AuthController.name, () => {
|
|
let ctx: ControllerContext;
|
|
const service = mockBaseService(AuthService);
|
|
|
|
beforeAll(async () => {
|
|
ctx = await controllerSetup(AuthController, [{ provide: AuthService, useValue: service }]);
|
|
return () => ctx.close();
|
|
});
|
|
|
|
beforeEach(() => {
|
|
service.resetAllMocks();
|
|
ctx.reset();
|
|
});
|
|
|
|
describe('POST /auth/admin-sign-up', () => {
|
|
const name = 'admin';
|
|
const email = 'admin@immich.cloud';
|
|
const password = 'password';
|
|
|
|
it('should require an email address', async () => {
|
|
const { status, body } = await request(ctx.getHttpServer()).post('/auth/admin-sign-up').send({ name, password });
|
|
expect(status).toEqual(400);
|
|
expect(body).toEqual(errorDto.badRequest());
|
|
});
|
|
|
|
it('should require a password', async () => {
|
|
const { status, body } = await request(ctx.getHttpServer()).post('/auth/admin-sign-up').send({ name, email });
|
|
expect(status).toEqual(400);
|
|
expect(body).toEqual(errorDto.badRequest());
|
|
});
|
|
|
|
it('should require a name', async () => {
|
|
const { status, body } = await request(ctx.getHttpServer()).post('/auth/admin-sign-up').send({ email, password });
|
|
expect(status).toEqual(400);
|
|
expect(body).toEqual(errorDto.badRequest());
|
|
});
|
|
|
|
it('should require a valid email', async () => {
|
|
const { status, body } = await request(ctx.getHttpServer())
|
|
.post('/auth/admin-sign-up')
|
|
.send({ name, email: 'immich', password });
|
|
expect(status).toEqual(400);
|
|
expect(body).toEqual(errorDto.badRequest());
|
|
});
|
|
|
|
it('should transform email to lower case', async () => {
|
|
service.adminSignUp.mockReset();
|
|
const { status } = await request(ctx.getHttpServer())
|
|
.post('/auth/admin-sign-up')
|
|
.send({ name: 'admin', password: 'password', email: 'aDmIn@IMMICH.cloud' });
|
|
expect(status).toEqual(201);
|
|
expect(service.adminSignUp).toHaveBeenCalledWith(expect.objectContaining({ email: 'admin@immich.cloud' }));
|
|
});
|
|
|
|
it('should accept an email with a local domain', async () => {
|
|
const { status } = await request(ctx.getHttpServer())
|
|
.post('/auth/admin-sign-up')
|
|
.send({ name: 'admin', password: 'password', email: 'admin@local' });
|
|
expect(status).toEqual(201);
|
|
});
|
|
});
|
|
|
|
describe('POST /auth/login', () => {
|
|
it(`should require an email and password`, async () => {
|
|
const { status, body } = await request(ctx.getHttpServer()).post('/auth/login').send({ name: 'admin' });
|
|
expect(status).toBe(400);
|
|
expect(body).toEqual(
|
|
errorDto.badRequest([
|
|
'email should not be empty',
|
|
'email must be an email',
|
|
'password should not be empty',
|
|
'password must be a string',
|
|
]),
|
|
);
|
|
});
|
|
|
|
it(`should not allow null email`, async () => {
|
|
const { status, body } = await request(ctx.getHttpServer())
|
|
.post('/auth/login')
|
|
.send({ name: 'admin', email: null, password: 'password' });
|
|
expect(status).toBe(400);
|
|
expect(body).toEqual(errorDto.badRequest(['email should not be empty', 'email must be an email']));
|
|
});
|
|
|
|
it(`should not allow null password`, async () => {
|
|
const { status, body } = await request(ctx.getHttpServer())
|
|
.post('/auth/login')
|
|
.send({ name: 'admin', email: 'admin@immich.cloud', password: null });
|
|
expect(status).toBe(400);
|
|
expect(body).toEqual(errorDto.badRequest(['password should not be empty', 'password must be a string']));
|
|
});
|
|
|
|
it('should reject an invalid email', async () => {
|
|
service.login.mockResolvedValue({ accessToken: 'access-token' } as LoginResponseDto);
|
|
|
|
const { status, body } = await request(ctx.getHttpServer())
|
|
.post('/auth/login')
|
|
.send({ name: 'admin', email: [], password: 'password' });
|
|
|
|
expect(status).toBe(400);
|
|
expect(body).toEqual(errorDto.badRequest(['email must be an email']));
|
|
});
|
|
|
|
it('should transform the email to all lowercase', async () => {
|
|
service.login.mockResolvedValue({ accessToken: 'access-token' } as LoginResponseDto);
|
|
|
|
const { status } = await request(ctx.getHttpServer())
|
|
.post('/auth/login')
|
|
.send({ name: 'admin', email: 'aDmIn@iMmIcH.ApP', password: 'password' });
|
|
|
|
expect(status).toBe(201);
|
|
expect(service.login).toHaveBeenCalledWith(
|
|
expect.objectContaining({ email: 'admin@immich.app' }),
|
|
expect.anything(),
|
|
);
|
|
});
|
|
|
|
it('should accept an email with a local domain', async () => {
|
|
service.login.mockResolvedValue({ accessToken: 'access-token' } as LoginResponseDto);
|
|
|
|
const { status } = await request(ctx.getHttpServer())
|
|
.post('/auth/login')
|
|
.send({ name: 'admin', email: 'admin@local', password: 'password' });
|
|
|
|
expect(status).toEqual(201);
|
|
expect(service.login).toHaveBeenCalledWith(expect.objectContaining({ email: 'admin@local' }), expect.anything());
|
|
});
|
|
});
|
|
|
|
describe('POST /auth/change-password', () => {
|
|
it('should be an authenticated route', async () => {
|
|
await request(ctx.getHttpServer())
|
|
.post('/auth/change-password')
|
|
.send({ password: 'password', newPassword: 'Password1234' });
|
|
expect(ctx.authenticate).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('POST /auth/pin-code', () => {
|
|
it('should be an authenticated route', async () => {
|
|
await request(ctx.getHttpServer()).post('/auth/pin-code').send({ pinCode: '123456' });
|
|
expect(ctx.authenticate).toHaveBeenCalled();
|
|
});
|
|
|
|
it('should reject 5 digits', async () => {
|
|
const { status, body } = await request(ctx.getHttpServer()).post('/auth/pin-code').send({ pinCode: '12345' });
|
|
expect(status).toEqual(400);
|
|
expect(body).toEqual(errorDto.badRequest(['pinCode must be a 6-digit numeric string']));
|
|
});
|
|
|
|
it('should reject 7 digits', async () => {
|
|
const { status, body } = await request(ctx.getHttpServer()).post('/auth/pin-code').send({ pinCode: '1234567' });
|
|
expect(status).toEqual(400);
|
|
expect(body).toEqual(errorDto.badRequest(['pinCode must be a 6-digit numeric string']));
|
|
});
|
|
|
|
it('should reject non-numbers', async () => {
|
|
const { status, body } = await request(ctx.getHttpServer()).post('/auth/pin-code').send({ pinCode: 'A12345' });
|
|
expect(status).toEqual(400);
|
|
expect(body).toEqual(errorDto.badRequest(['pinCode must be a 6-digit numeric string']));
|
|
});
|
|
});
|
|
|
|
describe('PUT /auth/pin-code', () => {
|
|
it('should be an authenticated route', async () => {
|
|
await request(ctx.getHttpServer()).put('/auth/pin-code').send({ pinCode: '123456', newPinCode: '654321' });
|
|
expect(ctx.authenticate).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('DELETE /auth/pin-code', () => {
|
|
it('should be an authenticated route', async () => {
|
|
await request(ctx.getHttpServer()).delete('/auth/pin-code').send({ pinCode: '123456' });
|
|
expect(ctx.authenticate).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('GET /auth/status', () => {
|
|
it('should be an authenticated route', async () => {
|
|
await request(ctx.getHttpServer()).get('/auth/status');
|
|
expect(ctx.authenticate).toHaveBeenCalled();
|
|
});
|
|
});
|
|
});
|