mirror of
https://github.com/immich-app/immich.git
synced 2025-04-14 20:16:24 +02:00

* fix(web): No EXIF info on stack navigation * fix(web): No EXIF info on stack navigation * add exif info to get stack query * e2e test
202 lines
6.4 KiB
TypeScript
202 lines
6.4 KiB
TypeScript
import { AssetMediaResponseDto, LoginResponseDto, searchStacks } from '@immich/sdk';
|
|
import { createUserDto, uuidDto } from 'src/fixtures';
|
|
import { errorDto } from 'src/responses';
|
|
import { app, asBearerAuth, utils } from 'src/utils';
|
|
import request from 'supertest';
|
|
import { beforeAll, describe, expect, it } from 'vitest';
|
|
|
|
describe('/stacks', () => {
|
|
let admin: LoginResponseDto;
|
|
let user1: LoginResponseDto;
|
|
let user2: LoginResponseDto;
|
|
let asset: AssetMediaResponseDto;
|
|
|
|
beforeAll(async () => {
|
|
await utils.resetDatabase();
|
|
|
|
admin = await utils.adminSetup();
|
|
|
|
[user1, user2] = await Promise.all([
|
|
utils.userSetup(admin.accessToken, createUserDto.user1),
|
|
utils.userSetup(admin.accessToken, createUserDto.user2),
|
|
]);
|
|
|
|
asset = await utils.createAsset(user1.accessToken);
|
|
});
|
|
|
|
describe('POST /stacks', () => {
|
|
it('should require authentication', async () => {
|
|
const { status, body } = await request(app)
|
|
.post('/stacks')
|
|
.send({ assetIds: [asset.id] });
|
|
|
|
expect(status).toBe(401);
|
|
expect(body).toEqual(errorDto.unauthorized);
|
|
});
|
|
|
|
it('should require at least two assets', async () => {
|
|
const { status, body } = await request(app)
|
|
.post('/stacks')
|
|
.set('Authorization', `Bearer ${user1.accessToken}`)
|
|
.send({ assetIds: [asset.id] });
|
|
|
|
expect(status).toBe(400);
|
|
expect(body).toEqual(errorDto.badRequest());
|
|
});
|
|
|
|
it('should require a valid id', async () => {
|
|
const { status, body } = await request(app)
|
|
.post('/stacks')
|
|
.set('Authorization', `Bearer ${user1.accessToken}`)
|
|
.send({ assetIds: [uuidDto.invalid, uuidDto.invalid] });
|
|
|
|
expect(status).toBe(400);
|
|
expect(body).toEqual(errorDto.badRequest());
|
|
});
|
|
|
|
it('should require access', async () => {
|
|
const user2Asset = await utils.createAsset(user2.accessToken);
|
|
const { status, body } = await request(app)
|
|
.post('/stacks')
|
|
.set('Authorization', `Bearer ${user1.accessToken}`)
|
|
.send({ assetIds: [asset.id, user2Asset.id] });
|
|
|
|
expect(status).toBe(400);
|
|
expect(body).toEqual(errorDto.noPermission);
|
|
});
|
|
|
|
it('should create a stack', async () => {
|
|
const [asset1, asset2] = await Promise.all([
|
|
utils.createAsset(user1.accessToken),
|
|
utils.createAsset(user1.accessToken),
|
|
]);
|
|
|
|
const { status, body } = await request(app)
|
|
.post('/stacks')
|
|
.set('Authorization', `Bearer ${user1.accessToken}`)
|
|
.send({ assetIds: [asset1.id, asset2.id] });
|
|
|
|
expect(status).toBe(201);
|
|
expect(body).toEqual({
|
|
id: expect.any(String),
|
|
primaryAssetId: asset1.id,
|
|
assets: [expect.objectContaining({ id: asset1.id }), expect.objectContaining({ id: asset2.id })],
|
|
});
|
|
});
|
|
|
|
it('should merge an existing stack', async () => {
|
|
const [asset1, asset2, asset3] = await Promise.all([
|
|
utils.createAsset(user1.accessToken),
|
|
utils.createAsset(user1.accessToken),
|
|
utils.createAsset(user1.accessToken),
|
|
]);
|
|
|
|
const response1 = await request(app)
|
|
.post('/stacks')
|
|
.set('Authorization', `Bearer ${user1.accessToken}`)
|
|
.send({ assetIds: [asset1.id, asset2.id] });
|
|
|
|
expect(response1.status).toBe(201);
|
|
|
|
const stacksBefore = await searchStacks({}, { headers: asBearerAuth(user1.accessToken) });
|
|
|
|
const { status, body } = await request(app)
|
|
.post('/stacks')
|
|
.set('Authorization', `Bearer ${user1.accessToken}`)
|
|
.send({ assetIds: [asset1.id, asset3.id] });
|
|
|
|
expect(status).toBe(201);
|
|
expect(body).toEqual({
|
|
id: expect.any(String),
|
|
primaryAssetId: asset1.id,
|
|
assets: expect.arrayContaining([
|
|
expect.objectContaining({ id: asset1.id }),
|
|
expect.objectContaining({ id: asset2.id }),
|
|
expect.objectContaining({ id: asset3.id }),
|
|
]),
|
|
});
|
|
|
|
const stacksAfter = await searchStacks({}, { headers: asBearerAuth(user1.accessToken) });
|
|
expect(stacksAfter.length).toBe(stacksBefore.length);
|
|
});
|
|
});
|
|
|
|
describe('GET /assets/:id', () => {
|
|
it('should include stack details for the primary asset', async () => {
|
|
const [asset1, asset2] = await Promise.all([
|
|
utils.createAsset(user1.accessToken),
|
|
utils.createAsset(user1.accessToken),
|
|
]);
|
|
|
|
await utils.createStack(user1.accessToken, [asset1.id, asset2.id]);
|
|
|
|
const { status, body } = await request(app)
|
|
.get(`/assets/${asset1.id}`)
|
|
.set('Authorization', `Bearer ${user1.accessToken}`);
|
|
|
|
expect(status).toBe(200);
|
|
expect(body).toEqual(
|
|
expect.objectContaining({
|
|
id: asset1.id,
|
|
stack: {
|
|
id: expect.any(String),
|
|
assetCount: 2,
|
|
primaryAssetId: asset1.id,
|
|
},
|
|
}),
|
|
);
|
|
});
|
|
|
|
it('should include stack details for a non-primary asset', async () => {
|
|
const [asset1, asset2] = await Promise.all([
|
|
utils.createAsset(user1.accessToken),
|
|
utils.createAsset(user1.accessToken),
|
|
]);
|
|
|
|
await utils.createStack(user1.accessToken, [asset1.id, asset2.id]);
|
|
|
|
const { status, body } = await request(app)
|
|
.get(`/assets/${asset2.id}`)
|
|
.set('Authorization', `Bearer ${user1.accessToken}`);
|
|
|
|
expect(status).toBe(200);
|
|
expect(body).toEqual(
|
|
expect.objectContaining({
|
|
id: asset2.id,
|
|
stack: {
|
|
id: expect.any(String),
|
|
assetCount: 2,
|
|
primaryAssetId: asset1.id,
|
|
},
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('GET /stacks/:id', () => {
|
|
it('should include exifInfo in stack assets', async () => {
|
|
const [asset1, asset2] = await Promise.all([
|
|
utils.createAsset(user1.accessToken),
|
|
utils.createAsset(user1.accessToken),
|
|
]);
|
|
|
|
const stack = await utils.createStack(user1.accessToken, [asset1.id, asset2.id]);
|
|
|
|
const { status, body } = await request(app)
|
|
.get(`/stacks/${stack.id}`)
|
|
.set('Authorization', `Bearer ${user1.accessToken}`);
|
|
|
|
expect(status).toBe(200);
|
|
expect(body).toEqual(
|
|
expect.objectContaining({
|
|
id: stack.id,
|
|
primaryAssetId: asset1.id,
|
|
assets: expect.arrayContaining([
|
|
expect.objectContaining({ id: asset1.id, exifInfo: expect.any(Object) }),
|
|
expect.objectContaining({ id: asset2.id, exifInfo: expect.any(Object) }),
|
|
]),
|
|
}),
|
|
);
|
|
});
|
|
});
|
|
});
|