1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-24 10:37:28 +02:00

refactor(e2e): use better dummy assets (#7536)

This commit is contained in:
Jason Rasmussen 2024-02-29 12:07:01 -05:00 committed by GitHub
parent af0de1a768
commit 100363c7be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 88 additions and 54 deletions

20
e2e/package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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 })],
});
});

View File

@ -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,
{
isFavorite: true,
isReadOnly: true,
fileCreatedAt: yesterday.toISO(),
fileModifiedAt: yesterday.toISO(),
},
{ filename: 'example.mp4' },
),
apiUtils.createAsset(user1.accessToken, {
isFavorite: true,
isReadOnly: true,
fileCreatedAt: yesterday.toISO(),
fileModifiedAt: yesterday.toISO(),
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,
{
isArchived: true,
isFavorite: true,
},
{ filename: 'example.mp4' },
),
apiUtils.createAsset(userStats.accessToken, {
isArchived: true,
isFavorite: true,
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 });

View File

@ -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
View 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;
};

View File

@ -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)) {