mirror of
https://github.com/immich-app/immich.git
synced 2024-12-29 15:11:58 +00:00
refactor(e2e): use better dummy assets (#7536)
This commit is contained in:
parent
af0de1a768
commit
100363c7be
7 changed files with 88 additions and 54 deletions
20
e2e/package-lock.json
generated
20
e2e/package-lock.json
generated
|
@ -15,6 +15,7 @@
|
|||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^20.11.17",
|
||||
"@types/pg": "^8.11.0",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
||||
"@typescript-eslint/parser": "^7.1.0",
|
||||
|
@ -26,6 +27,7 @@
|
|||
"exiftool-vendored": "^24.5.0",
|
||||
"luxon": "^3.4.4",
|
||||
"pg": "^8.11.3",
|
||||
"pngjs": "^7.0.0",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-organize-imports": "^3.2.4",
|
||||
"socket.io-client": "^4.7.4",
|
||||
|
@ -1236,6 +1238,15 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pngjs": {
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/pngjs/-/pngjs-6.0.4.tgz",
|
||||
"integrity": "sha512-atAK9xLKOnxiuArxcHovmnOUUGBZOQ3f0vCf43FnoKs6XnqiambT1kkJWmdo71IR+BoXSh+CueeFR0GfH3dTlQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
|
||||
|
@ -3897,6 +3908,15 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/pngjs": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
|
||||
"integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.35",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz",
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^20.11.17",
|
||||
"@types/pg": "^8.11.0",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
"@types/supertest": "^6.0.2",
|
||||
"@typescript-eslint/eslint-plugin": "^7.1.0",
|
||||
"@typescript-eslint/parser": "^7.1.0",
|
||||
|
@ -34,6 +35,7 @@
|
|||
"exiftool-vendored": "^24.5.0",
|
||||
"luxon": "^3.4.4",
|
||||
"pg": "^8.11.3",
|
||||
"pngjs": "^7.0.0",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-organize-imports": "^3.2.4",
|
||||
"socket.io-client": "^4.7.4",
|
||||
|
|
|
@ -256,7 +256,7 @@ describe('/album', () => {
|
|||
expect(status).toBe(200);
|
||||
expect(body).toEqual({
|
||||
...user1Albums[0],
|
||||
assets: [expect.objectContaining(user1Albums[0].assets[0])],
|
||||
assets: [expect.objectContaining({ id: user1Albums[0].assets[0].id })],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -268,7 +268,7 @@ describe('/album', () => {
|
|||
expect(status).toBe(200);
|
||||
expect(body).toEqual({
|
||||
...user2Albums[0],
|
||||
assets: [expect.objectContaining(user2Albums[0].assets[0])],
|
||||
assets: [expect.objectContaining({ id: user2Albums[0].assets[0].id })],
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -280,7 +280,7 @@ describe('/album', () => {
|
|||
expect(status).toBe(200);
|
||||
expect(body).toEqual({
|
||||
...user1Albums[0],
|
||||
assets: [expect.objectContaining(user1Albums[0].assets[0])],
|
||||
assets: [expect.objectContaining({ id: user1Albums[0].assets[0].id })],
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -59,30 +59,25 @@ describe('/asset', () => {
|
|||
]);
|
||||
|
||||
// asset location
|
||||
assetLocation = await apiUtils.createAsset(
|
||||
admin.accessToken,
|
||||
{},
|
||||
{
|
||||
assetLocation = await apiUtils.createAsset(admin.accessToken, {
|
||||
assetData: {
|
||||
filename: 'thompson-springs.jpg',
|
||||
bytes: await readFile(locationAssetFilepath),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
await wsUtils.waitForEvent({ event: 'upload', assetId: assetLocation.id });
|
||||
|
||||
user1Assets = await Promise.all([
|
||||
apiUtils.createAsset(user1.accessToken),
|
||||
apiUtils.createAsset(user1.accessToken),
|
||||
apiUtils.createAsset(
|
||||
user1.accessToken,
|
||||
{
|
||||
apiUtils.createAsset(user1.accessToken, {
|
||||
isFavorite: true,
|
||||
isReadOnly: true,
|
||||
fileCreatedAt: yesterday.toISO(),
|
||||
fileModifiedAt: yesterday.toISO(),
|
||||
},
|
||||
{ filename: 'example.mp4' },
|
||||
),
|
||||
assetData: { filename: 'example.mp4' },
|
||||
}),
|
||||
apiUtils.createAsset(user1.accessToken),
|
||||
apiUtils.createAsset(user1.accessToken),
|
||||
]);
|
||||
|
@ -98,14 +93,11 @@ describe('/asset', () => {
|
|||
apiUtils.createAsset(userStats.accessToken),
|
||||
apiUtils.createAsset(userStats.accessToken, { isFavorite: true }),
|
||||
apiUtils.createAsset(userStats.accessToken, { isArchived: true }),
|
||||
apiUtils.createAsset(
|
||||
userStats.accessToken,
|
||||
{
|
||||
apiUtils.createAsset(userStats.accessToken, {
|
||||
isArchived: true,
|
||||
isFavorite: true,
|
||||
},
|
||||
{ filename: 'example.mp4' },
|
||||
),
|
||||
assetData: { filename: 'example.mp4' },
|
||||
}),
|
||||
]);
|
||||
|
||||
const person1 = await apiUtils.createPerson(user1.accessToken, {
|
||||
|
@ -615,11 +607,9 @@ describe('/asset', () => {
|
|||
for (const { input, expected } of tests) {
|
||||
it(`should generate a thumbnail for ${input}`, async () => {
|
||||
const filepath = join(testAssetDir, input);
|
||||
const { id, duplicate } = await apiUtils.createAsset(
|
||||
admin.accessToken,
|
||||
{},
|
||||
{ bytes: await readFile(filepath), filename: basename(filepath) },
|
||||
);
|
||||
const { id, duplicate } = await apiUtils.createAsset(admin.accessToken, {
|
||||
assetData: { bytes: await readFile(filepath), filename: basename(filepath) },
|
||||
});
|
||||
|
||||
expect(duplicate).toBe(false);
|
||||
|
||||
|
@ -635,14 +625,12 @@ describe('/asset', () => {
|
|||
|
||||
it('should handle a duplicate', async () => {
|
||||
const filepath = 'formats/jpeg/el_torcal_rocks.jpeg';
|
||||
const { duplicate } = await apiUtils.createAsset(
|
||||
admin.accessToken,
|
||||
{},
|
||||
{
|
||||
const { duplicate } = await apiUtils.createAsset(admin.accessToken, {
|
||||
assetData: {
|
||||
bytes: await readFile(join(testAssetDir, filepath)),
|
||||
filename: basename(filepath),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
expect(duplicate).toBe(true);
|
||||
});
|
||||
|
@ -669,14 +657,12 @@ describe('/asset', () => {
|
|||
|
||||
for (const { filepath, checksum } of motionTests) {
|
||||
it(`should extract motionphoto video from ${filepath}`, async () => {
|
||||
const response = await apiUtils.createAsset(
|
||||
admin.accessToken,
|
||||
{},
|
||||
{
|
||||
const response = await apiUtils.createAsset(admin.accessToken, {
|
||||
assetData: {
|
||||
bytes: await readFile(join(testAssetDir, filepath)),
|
||||
filename: basename(filepath),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
await wsUtils.waitForEvent({ event: 'upload', assetId: response.id });
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ describe('/download', () => {
|
|||
.set('Authorization', `Bearer ${admin.accessToken}`);
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(response.headers['content-type']).toEqual('image/jpeg');
|
||||
expect(response.headers['content-type']).toEqual('image/png');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
31
e2e/src/generators.ts
Normal file
31
e2e/src/generators.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import { PNG } from 'pngjs';
|
||||
|
||||
const createPNG = (r: number, g: number, b: number) => {
|
||||
const image = new PNG({ width: 1, height: 1 });
|
||||
image.data[0] = r;
|
||||
image.data[1] = g;
|
||||
image.data[2] = b;
|
||||
image.data[3] = 255;
|
||||
return PNG.sync.write(image);
|
||||
};
|
||||
|
||||
function* newPngFactory() {
|
||||
for (let r = 0; r < 255; r++) {
|
||||
for (let g = 0; g < 255; g++) {
|
||||
for (let b = 0; b < 255; b++) {
|
||||
yield createPNG(r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const pngFactory = newPngFactory();
|
||||
|
||||
export const makeRandomImage = () => {
|
||||
const { value } = pngFactory.next();
|
||||
if (!value) {
|
||||
throw new Error('Ran out of random asset data');
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
|
@ -21,7 +21,6 @@ import {
|
|||
} from '@immich/sdk';
|
||||
import { BrowserContext } from '@playwright/test';
|
||||
import { exec, spawn } from 'node:child_process';
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { access } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'node:path';
|
||||
|
@ -29,6 +28,7 @@ import { promisify } from 'node:util';
|
|||
import pg from 'pg';
|
||||
import { io, type Socket } from 'socket.io-client';
|
||||
import { loginDto, signupDto } from 'src/fixtures';
|
||||
import { makeRandomImage } from 'src/generators';
|
||||
import request from 'supertest';
|
||||
|
||||
const execPromise = promisify(exec);
|
||||
|
@ -241,6 +241,8 @@ export const wsUtils = {
|
|||
},
|
||||
};
|
||||
|
||||
type AssetData = { bytes?: Buffer; filename: string };
|
||||
|
||||
export const apiUtils = {
|
||||
setup: () => {
|
||||
defaults.baseUrl = app;
|
||||
|
@ -269,11 +271,7 @@ export const apiUtils = {
|
|||
createAlbum({ createAlbumDto: dto }, { headers: asBearerAuth(accessToken) }),
|
||||
createAsset: async (
|
||||
accessToken: string,
|
||||
dto?: Partial<Omit<CreateAssetDto, 'assetData'>>,
|
||||
data?: {
|
||||
bytes?: Buffer;
|
||||
filename: string;
|
||||
},
|
||||
dto?: Partial<Omit<CreateAssetDto, 'assetData'>> & { assetData?: AssetData },
|
||||
) => {
|
||||
const _dto = {
|
||||
deviceAssetId: 'test-1',
|
||||
|
@ -283,15 +281,12 @@ export const apiUtils = {
|
|||
...dto,
|
||||
};
|
||||
|
||||
const _assetData = {
|
||||
bytes: randomBytes(32),
|
||||
filename: 'example.jpg',
|
||||
...data,
|
||||
};
|
||||
const assetData = dto?.assetData?.bytes || makeRandomImage();
|
||||
const filename = dto?.assetData?.filename || 'example.png';
|
||||
|
||||
const builder = request(app)
|
||||
.post(`/asset/upload`)
|
||||
.attach('assetData', _assetData.bytes, _assetData.filename)
|
||||
.attach('assetData', assetData, filename)
|
||||
.set('Authorization', `Bearer ${accessToken}`);
|
||||
|
||||
for (const [key, value] of Object.entries(_dto)) {
|
||||
|
|
Loading…
Reference in a new issue