mirror of
https://github.com/immich-app/immich.git
synced 2025-12-21 09:15:44 +03:00
chore: migrate to vitest (#7156)
* chore: jest => vitest * chore: replace jest-when
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { StorageCore } from 'src/cores/storage.core';
|
||||
import { vitest } from 'vitest';
|
||||
|
||||
jest.mock('src/constants', () => ({
|
||||
vitest.mock('src/constants', () => ({
|
||||
APP_MEDIA_LOCATION: '/photos',
|
||||
}));
|
||||
|
||||
|
||||
@@ -6,11 +6,12 @@ import { activityStub } from 'test/fixtures/activity.stub';
|
||||
import { authStub } from 'test/fixtures/auth.stub';
|
||||
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
|
||||
import { newActivityRepositoryMock } from 'test/repositories/activity.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(ActivityService.name, () => {
|
||||
let sut: ActivityService;
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let activityMock: jest.Mocked<IActivityRepository>;
|
||||
let activityMock: Mocked<IActivityRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
accessMock = newAccessRepositoryMock();
|
||||
|
||||
@@ -12,13 +12,14 @@ import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositorie
|
||||
import { newAlbumRepositoryMock } from 'test/repositories/album.repository.mock';
|
||||
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
|
||||
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(AlbumService.name, () => {
|
||||
let sut: AlbumService;
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let albumMock: jest.Mocked<IAlbumRepository>;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let userMock: jest.Mocked<IUserRepository>;
|
||||
let albumMock: Mocked<IAlbumRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let userMock: Mocked<IUserRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
accessMock = newAccessRepositoryMock();
|
||||
|
||||
@@ -6,11 +6,12 @@ import { keyStub } from 'test/fixtures/api-key.stub';
|
||||
import { authStub } from 'test/fixtures/auth.stub';
|
||||
import { newKeyRepositoryMock } from 'test/repositories/api-key.repository.mock';
|
||||
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(APIKeyService.name, () => {
|
||||
let sut: APIKeyService;
|
||||
let keyMock: jest.Mocked<IKeyRepository>;
|
||||
let cryptoMock: jest.Mocked<ICryptoRepository>;
|
||||
let keyMock: Mocked<IKeyRepository>;
|
||||
let cryptoMock: Mocked<ICryptoRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
cryptoMock = newCryptoRepositoryMock();
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { when } from 'jest-when';
|
||||
import { AssetRejectReason, AssetUploadAction } from 'src/dtos/asset-v1-response.dto';
|
||||
import { CreateAssetDto } from 'src/dtos/asset-v1.dto';
|
||||
import { ASSET_CHECKSUM_CONSTRAINT, AssetEntity, AssetType } from 'src/entities/asset.entity';
|
||||
@@ -20,6 +19,7 @@ import { newLibraryRepositoryMock } from 'test/repositories/library.repository.m
|
||||
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
|
||||
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
|
||||
import { QueryFailedError } from 'typeorm';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
const _getCreateAssetDto = (): CreateAssetDto => {
|
||||
const createAssetDto = new CreateAssetDto();
|
||||
@@ -62,23 +62,23 @@ const _getAsset_1 = () => {
|
||||
describe('AssetService', () => {
|
||||
let sut: AssetServiceV1;
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let assetRepositoryMockV1: jest.Mocked<IAssetRepositoryV1>;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let jobMock: jest.Mocked<IJobRepository>;
|
||||
let libraryMock: jest.Mocked<ILibraryRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let userMock: jest.Mocked<IUserRepository>;
|
||||
let assetRepositoryMockV1: Mocked<IAssetRepositoryV1>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let jobMock: Mocked<IJobRepository>;
|
||||
let libraryMock: Mocked<ILibraryRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
let userMock: Mocked<IUserRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
assetRepositoryMockV1 = {
|
||||
get: jest.fn(),
|
||||
getAllByUserId: jest.fn(),
|
||||
getDetectedObjectsByUserId: jest.fn(),
|
||||
getLocationsByUserId: jest.fn(),
|
||||
getSearchPropertiesByUserId: jest.fn(),
|
||||
getAssetsByChecksums: jest.fn(),
|
||||
getExistingAssets: jest.fn(),
|
||||
getByOriginalPath: jest.fn(),
|
||||
get: vitest.fn(),
|
||||
getAllByUserId: vitest.fn(),
|
||||
getDetectedObjectsByUserId: vitest.fn(),
|
||||
getLocationsByUserId: vitest.fn(),
|
||||
getSearchPropertiesByUserId: vitest.fn(),
|
||||
getAssetsByChecksums: vitest.fn(),
|
||||
getExistingAssets: vitest.fn(),
|
||||
getByOriginalPath: vitest.fn(),
|
||||
};
|
||||
|
||||
accessMock = newAccessRepositoryMock();
|
||||
@@ -90,12 +90,11 @@ describe('AssetService', () => {
|
||||
|
||||
sut = new AssetServiceV1(accessMock, assetRepositoryMockV1, assetMock, jobMock, libraryMock, storageMock, userMock);
|
||||
|
||||
when(assetRepositoryMockV1.get)
|
||||
.calledWith(assetStub.livePhotoStillAsset.id)
|
||||
.mockResolvedValue(assetStub.livePhotoStillAsset);
|
||||
when(assetRepositoryMockV1.get)
|
||||
.calledWith(assetStub.livePhotoMotionAsset.id)
|
||||
.mockResolvedValue(assetStub.livePhotoMotionAsset);
|
||||
assetRepositoryMockV1.get.mockImplementation((assetId) =>
|
||||
Promise.resolve(
|
||||
[assetStub.livePhotoMotionAsset, assetStub.livePhotoMotionAsset].find((asset) => asset.id === assetId) ?? null,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
describe('uploadFile', () => {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { BadRequestException, UnauthorizedException } from '@nestjs/common';
|
||||
import { when } from 'jest-when';
|
||||
import { mapAsset } from 'src/dtos/asset-response.dto';
|
||||
import { AssetJobName, AssetStatsResponseDto, UploadFieldName } from 'src/dtos/asset.dto';
|
||||
import { AssetEntity, AssetType } from 'src/entities/asset.entity';
|
||||
import { IAssetStackRepository } from 'src/interfaces/asset-stack.interface';
|
||||
import { AssetStats, IAssetRepository } from 'src/interfaces/asset.interface';
|
||||
import { ClientEvent, IEventRepository } from 'src/interfaces/event.interface';
|
||||
import { IJobRepository, JobItem, JobName } from 'src/interfaces/job.interface';
|
||||
import { IJobRepository, JobName } from 'src/interfaces/job.interface';
|
||||
import { IPartnerRepository } from 'src/interfaces/partner.interface';
|
||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||
import { ISystemConfigRepository } from 'src/interfaces/system-config.interface';
|
||||
@@ -26,6 +25,7 @@ import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.m
|
||||
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
const stats: AssetStats = {
|
||||
[AssetType.IMAGE]: 10,
|
||||
@@ -148,19 +148,25 @@ const uploadTests = [
|
||||
describe(AssetService.name, () => {
|
||||
let sut: AssetService;
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let jobMock: jest.Mocked<IJobRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let userMock: jest.Mocked<IUserRepository>;
|
||||
let eventMock: jest.Mocked<IEventRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let partnerMock: jest.Mocked<IPartnerRepository>;
|
||||
let assetStackMock: jest.Mocked<IAssetStackRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let jobMock: Mocked<IJobRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
let userMock: Mocked<IUserRepository>;
|
||||
let eventMock: Mocked<IEventRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let partnerMock: Mocked<IPartnerRepository>;
|
||||
let assetStackMock: Mocked<IAssetStackRepository>;
|
||||
|
||||
it('should work', () => {
|
||||
expect(sut).toBeDefined();
|
||||
});
|
||||
|
||||
const mockGetById = (assets: AssetEntity[]) => {
|
||||
assetMock.getById.mockImplementation((assetId) =>
|
||||
Promise.resolve(assets.find((asset) => asset.id === assetId) ?? null),
|
||||
);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
accessMock = newAccessRepositoryMock();
|
||||
assetMock = newAssetRepositoryMock();
|
||||
@@ -184,12 +190,7 @@ describe(AssetService.name, () => {
|
||||
assetStackMock,
|
||||
);
|
||||
|
||||
when(assetMock.getById)
|
||||
.calledWith(assetStub.livePhotoStillAsset.id)
|
||||
.mockResolvedValue(assetStub.livePhotoStillAsset as AssetEntity);
|
||||
when(assetMock.getById)
|
||||
.calledWith(assetStub.livePhotoMotionAsset.id)
|
||||
.mockResolvedValue(assetStub.livePhotoMotionAsset as AssetEntity);
|
||||
mockGetById([assetStub.livePhotoStillAsset, assetStub.livePhotoMotionAsset]);
|
||||
});
|
||||
|
||||
describe('canUpload', () => {
|
||||
@@ -299,12 +300,12 @@ describe(AssetService.name, () => {
|
||||
|
||||
describe('getMemoryLane', () => {
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers();
|
||||
jest.setSystemTime(new Date('2024-01-15'));
|
||||
vitest.useFakeTimers();
|
||||
vitest.setSystemTime(new Date('2024-01-15'));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
jest.useRealTimers();
|
||||
vitest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should group the assets correctly', async () => {
|
||||
@@ -469,9 +470,7 @@ describe(AssetService.name, () => {
|
||||
|
||||
it('should update parent asset updatedAt when children are added', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['parent']));
|
||||
when(assetMock.getById)
|
||||
.calledWith('parent', { stack: { assets: true } })
|
||||
.mockResolvedValue(assetStub.image);
|
||||
mockGetById([{ ...assetStub.image, id: 'parent' }]);
|
||||
await sut.updateAll(authStub.user1, {
|
||||
ids: [],
|
||||
stackParentId: 'parent',
|
||||
@@ -488,9 +487,7 @@ describe(AssetService.name, () => {
|
||||
stack: assetStackStub('stack-1', [{ id: 'parent' } as AssetEntity, { id: 'child-1' } as AssetEntity]),
|
||||
} as AssetEntity,
|
||||
]);
|
||||
when(assetStackMock.getById)
|
||||
.calledWith('stack-1')
|
||||
.mockResolvedValue(assetStackStub('stack-1', [{ id: 'parent' } as AssetEntity]));
|
||||
assetStackMock.getById.mockResolvedValue(assetStackStub('stack-1', [{ id: 'parent' } as AssetEntity]));
|
||||
|
||||
await sut.updateAll(authStub.user1, {
|
||||
ids: ['child-1'],
|
||||
@@ -511,12 +508,10 @@ describe(AssetService.name, () => {
|
||||
{ id: 'child-1' } as AssetEntity,
|
||||
{ id: 'child-2' } as AssetEntity,
|
||||
]);
|
||||
when(assetMock.getById)
|
||||
.calledWith('parent', { stack: { assets: true } })
|
||||
.mockResolvedValue({
|
||||
id: 'child-1',
|
||||
stack,
|
||||
} as AssetEntity);
|
||||
assetMock.getById.mockResolvedValue({
|
||||
id: 'child-1',
|
||||
stack,
|
||||
} as AssetEntity);
|
||||
|
||||
await sut.updateAll(authStub.user1, {
|
||||
stackParentId: 'parent',
|
||||
@@ -547,9 +542,7 @@ describe(AssetService.name, () => {
|
||||
it('merge stacks if new child has children', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValueOnce(new Set(['child-1']));
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValueOnce(new Set(['parent']));
|
||||
when(assetMock.getById)
|
||||
.calledWith('parent', { stack: { assets: true } })
|
||||
.mockResolvedValue({ ...assetStub.image, id: 'parent' });
|
||||
assetMock.getById.mockResolvedValue({ ...assetStub.image, id: 'parent' });
|
||||
assetMock.getByIds.mockResolvedValue([
|
||||
{
|
||||
id: 'child-1',
|
||||
@@ -557,9 +550,7 @@ describe(AssetService.name, () => {
|
||||
stack: assetStackStub('stack-1', [{ id: 'child-1' } as AssetEntity, { id: 'child-2' } as AssetEntity]),
|
||||
} as AssetEntity,
|
||||
]);
|
||||
when(assetStackMock.getById)
|
||||
.calledWith('stack-1')
|
||||
.mockResolvedValue(assetStackStub('stack-1', [{ id: 'parent' } as AssetEntity]));
|
||||
assetStackMock.getById.mockResolvedValue(assetStackStub('stack-1', [{ id: 'parent' } as AssetEntity]));
|
||||
|
||||
await sut.updateAll(authStub.user1, {
|
||||
ids: ['child-1'],
|
||||
@@ -579,9 +570,7 @@ describe(AssetService.name, () => {
|
||||
it('should send ws asset update event', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValueOnce(new Set(['asset-1']));
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValueOnce(new Set(['parent']));
|
||||
when(assetMock.getById)
|
||||
.calledWith('parent', { stack: { assets: true } })
|
||||
.mockResolvedValue(assetStub.image);
|
||||
assetMock.getById.mockResolvedValue(assetStub.image);
|
||||
|
||||
await sut.updateAll(authStub.user1, {
|
||||
ids: ['asset-1'],
|
||||
@@ -626,32 +615,10 @@ describe(AssetService.name, () => {
|
||||
});
|
||||
|
||||
describe('handleAssetDeletion', () => {
|
||||
beforeEach(() => {
|
||||
when(jobMock.queue)
|
||||
.calledWith(
|
||||
expect.objectContaining({
|
||||
name: JobName.ASSET_DELETION,
|
||||
}),
|
||||
)
|
||||
.mockImplementation(async (item: JobItem) => {
|
||||
const jobData = (item as { data?: any })?.data || {};
|
||||
await sut.handleAssetDeletion(jobData);
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove faces', async () => {
|
||||
const assetWithFace = { ...assetStub.image, faces: [faceStub.face1, faceStub.mergeFace1] };
|
||||
|
||||
when(assetMock.getById)
|
||||
.calledWith(assetWithFace.id, {
|
||||
faces: {
|
||||
person: true,
|
||||
},
|
||||
library: true,
|
||||
stack: { assets: true },
|
||||
exifInfo: true,
|
||||
})
|
||||
.mockResolvedValue(assetWithFace);
|
||||
assetMock.getById.mockResolvedValue(assetWithFace);
|
||||
|
||||
await sut.handleAssetDeletion({ id: assetWithFace.id });
|
||||
|
||||
@@ -676,16 +643,7 @@ describe(AssetService.name, () => {
|
||||
});
|
||||
|
||||
it('should update stack primary asset if deleted asset was primary asset in a stack', async () => {
|
||||
when(assetMock.getById)
|
||||
.calledWith(assetStub.primaryImage.id, {
|
||||
faces: {
|
||||
person: true,
|
||||
},
|
||||
library: true,
|
||||
stack: { assets: true },
|
||||
exifInfo: true,
|
||||
})
|
||||
.mockResolvedValue(assetStub.primaryImage as AssetEntity);
|
||||
assetMock.getById.mockResolvedValue(assetStub.primaryImage as AssetEntity);
|
||||
|
||||
await sut.handleAssetDeletion({ id: assetStub.primaryImage.id });
|
||||
|
||||
@@ -696,16 +654,7 @@ describe(AssetService.name, () => {
|
||||
});
|
||||
|
||||
it('should only delete generated files for readonly assets', async () => {
|
||||
when(assetMock.getById)
|
||||
.calledWith(assetStub.readOnly.id, {
|
||||
faces: {
|
||||
person: true,
|
||||
},
|
||||
library: true,
|
||||
stack: { assets: true },
|
||||
exifInfo: true,
|
||||
})
|
||||
.mockResolvedValue(assetStub.readOnly);
|
||||
assetMock.getById.mockResolvedValue(assetStub.readOnly);
|
||||
|
||||
await sut.handleAssetDeletion({ id: assetStub.readOnly.id });
|
||||
|
||||
@@ -728,7 +677,7 @@ describe(AssetService.name, () => {
|
||||
});
|
||||
|
||||
it('should not process assets from external library without fromExternal flag', async () => {
|
||||
when(assetMock.getById).calledWith(assetStub.external.id).mockResolvedValue(assetStub.external);
|
||||
assetMock.getById.mockResolvedValue(assetStub.external);
|
||||
|
||||
await sut.handleAssetDeletion({ id: assetStub.external.id });
|
||||
|
||||
@@ -738,16 +687,7 @@ describe(AssetService.name, () => {
|
||||
});
|
||||
|
||||
it('should process assets from external library with fromExternal flag', async () => {
|
||||
when(assetMock.getById)
|
||||
.calledWith(assetStub.external.id, {
|
||||
faces: {
|
||||
person: true,
|
||||
},
|
||||
library: true,
|
||||
stack: { assets: true },
|
||||
exifInfo: true,
|
||||
})
|
||||
.mockResolvedValue(assetStub.external);
|
||||
assetMock.getById.mockResolvedValue(assetStub.external);
|
||||
|
||||
await sut.handleAssetDeletion({ id: assetStub.external.id, fromExternal: true });
|
||||
|
||||
@@ -769,39 +709,12 @@ describe(AssetService.name, () => {
|
||||
});
|
||||
|
||||
it('should delete a live photo', async () => {
|
||||
when(assetMock.getById)
|
||||
.calledWith(assetStub.livePhotoStillAsset.id, {
|
||||
faces: {
|
||||
person: true,
|
||||
},
|
||||
library: true,
|
||||
stack: { assets: true },
|
||||
exifInfo: true,
|
||||
})
|
||||
.mockResolvedValue(assetStub.livePhotoStillAsset);
|
||||
when(assetMock.getById)
|
||||
.calledWith(assetStub.livePhotoMotionAsset.id, {
|
||||
faces: {
|
||||
person: true,
|
||||
},
|
||||
library: true,
|
||||
stack: { assets: true },
|
||||
exifInfo: true,
|
||||
})
|
||||
.mockResolvedValue(assetStub.livePhotoMotionAsset);
|
||||
assetMock.getById.mockResolvedValue(assetStub.livePhotoStillAsset);
|
||||
|
||||
await sut.handleAssetDeletion({ id: assetStub.livePhotoStillAsset.id });
|
||||
|
||||
expect(jobMock.queue.mock.calls).toEqual([
|
||||
[{ name: JobName.ASSET_DELETION, data: { id: assetStub.livePhotoMotionAsset.id } }],
|
||||
[
|
||||
{
|
||||
name: JobName.DELETE_FILES,
|
||||
data: {
|
||||
files: [undefined, undefined, undefined, undefined, 'fake_path/asset_1.mp4'],
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
name: JobName.DELETE_FILES,
|
||||
@@ -814,18 +727,8 @@ describe(AssetService.name, () => {
|
||||
});
|
||||
|
||||
it('should update usage', async () => {
|
||||
when(assetMock.getById)
|
||||
.calledWith(assetStub.image.id, {
|
||||
faces: {
|
||||
person: true,
|
||||
},
|
||||
library: true,
|
||||
stack: { assets: true },
|
||||
exifInfo: true,
|
||||
})
|
||||
.mockResolvedValue(assetStub.image);
|
||||
assetMock.getById.mockResolvedValue(assetStub.image);
|
||||
await sut.handleAssetDeletion({ id: assetStub.image.id });
|
||||
|
||||
expect(userMock.updateUsage).toHaveBeenCalledWith(assetStub.image.ownerId, -5000);
|
||||
});
|
||||
});
|
||||
@@ -874,18 +777,7 @@ describe(AssetService.name, () => {
|
||||
it('make old parent the child of new parent', async () => {
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValueOnce(new Set([assetStub.image.id]));
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValueOnce(new Set(['new']));
|
||||
|
||||
when(assetMock.getById)
|
||||
.calledWith(assetStub.image.id, {
|
||||
faces: {
|
||||
person: true,
|
||||
},
|
||||
library: true,
|
||||
stack: {
|
||||
assets: true,
|
||||
},
|
||||
})
|
||||
.mockResolvedValue({ ...assetStub.image, stackId: 'stack-1' });
|
||||
assetMock.getById.mockResolvedValue({ ...assetStub.image, stackId: 'stack-1' });
|
||||
|
||||
await sut.updateStackParent(authStub.user1, {
|
||||
oldParentId: assetStub.image.id,
|
||||
|
||||
@@ -16,16 +16,17 @@ import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.moc
|
||||
import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
|
||||
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
|
||||
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(AuditService.name, () => {
|
||||
let sut: AuditService;
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let auditMock: jest.Mocked<IAuditRepository>;
|
||||
let cryptoMock: jest.Mocked<ICryptoRepository>;
|
||||
let personMock: jest.Mocked<IPersonRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let userMock: jest.Mocked<IUserRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let auditMock: Mocked<IAuditRepository>;
|
||||
let cryptoMock: Mocked<ICryptoRepository>;
|
||||
let personMock: Mocked<IPersonRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
let userMock: Mocked<IUserRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
accessMock = newAccessRepositoryMock();
|
||||
|
||||
@@ -29,6 +29,7 @@ import { newSharedLinkRepositoryMock } from 'test/repositories/shared-link.repos
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { newUserTokenRepositoryMock } from 'test/repositories/user-token.repository.mock';
|
||||
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
|
||||
import { Mock, Mocked, vitest } from 'vitest';
|
||||
|
||||
// const token = Buffer.from('my-api-key', 'utf8').toString('base64');
|
||||
|
||||
@@ -58,34 +59,34 @@ const oauthUserWithDefaultQuota = {
|
||||
|
||||
describe('AuthService', () => {
|
||||
let sut: AuthService;
|
||||
let accessMock: jest.Mocked<IAccessRepositoryMock>;
|
||||
let cryptoMock: jest.Mocked<ICryptoRepository>;
|
||||
let userMock: jest.Mocked<IUserRepository>;
|
||||
let libraryMock: jest.Mocked<ILibraryRepository>;
|
||||
let loggerMock: jest.Mocked<ILoggerRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let userTokenMock: jest.Mocked<IUserTokenRepository>;
|
||||
let shareMock: jest.Mocked<ISharedLinkRepository>;
|
||||
let keyMock: jest.Mocked<IKeyRepository>;
|
||||
let accessMock: Mocked<IAccessRepositoryMock>;
|
||||
let cryptoMock: Mocked<ICryptoRepository>;
|
||||
let userMock: Mocked<IUserRepository>;
|
||||
let libraryMock: Mocked<ILibraryRepository>;
|
||||
let loggerMock: Mocked<ILoggerRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let userTokenMock: Mocked<IUserTokenRepository>;
|
||||
let shareMock: Mocked<ISharedLinkRepository>;
|
||||
let keyMock: Mocked<IKeyRepository>;
|
||||
|
||||
let callbackMock: jest.Mock;
|
||||
let userinfoMock: jest.Mock;
|
||||
let callbackMock: Mock;
|
||||
let userinfoMock: Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
callbackMock = jest.fn().mockReturnValue({ access_token: 'access-token' });
|
||||
userinfoMock = jest.fn().mockResolvedValue({ sub, email });
|
||||
callbackMock = vitest.fn().mockReturnValue({ access_token: 'access-token' });
|
||||
userinfoMock = vitest.fn().mockResolvedValue({ sub, email });
|
||||
|
||||
jest.spyOn(generators, 'state').mockReturnValue('state');
|
||||
jest.spyOn(Issuer, 'discover').mockResolvedValue({
|
||||
vitest.spyOn(generators, 'state').mockReturnValue('state');
|
||||
vitest.spyOn(Issuer, 'discover').mockResolvedValue({
|
||||
id_token_signing_alg_values_supported: ['RS256'],
|
||||
Client: jest.fn().mockResolvedValue({
|
||||
Client: vitest.fn().mockResolvedValue({
|
||||
issuer: {
|
||||
metadata: {
|
||||
end_session_endpoint: 'http://end-session-endpoint',
|
||||
},
|
||||
},
|
||||
authorizationUrl: jest.fn().mockReturnValue('http://authorization-url'),
|
||||
callbackParams: jest.fn().mockReturnValue({ state: 'state' }),
|
||||
authorizationUrl: vitest.fn().mockReturnValue('http://authorization-url'),
|
||||
callbackParams: vitest.fn().mockReturnValue({ state: 'state' }),
|
||||
callback: callbackMock,
|
||||
userinfo: userinfoMock,
|
||||
}),
|
||||
|
||||
@@ -3,10 +3,11 @@ import { DatabaseService } from 'src/services/database.service';
|
||||
import { ImmichLogger } from 'src/utils/logger';
|
||||
import { Version, VersionType } from 'src/utils/version';
|
||||
import { newDatabaseRepositoryMock } from 'test/repositories/database.repository.mock';
|
||||
import { MockInstance, Mocked, vitest } from 'vitest';
|
||||
|
||||
describe(DatabaseService.name, () => {
|
||||
let sut: DatabaseService;
|
||||
let databaseMock: jest.Mocked<IDatabaseRepository>;
|
||||
let databaseMock: Mocked<IDatabaseRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
databaseMock = newDatabaseRepositoryMock();
|
||||
@@ -22,14 +23,14 @@ describe(DatabaseService.name, () => {
|
||||
[{ vectorExt: DatabaseExtension.VECTORS, extName: 'pgvecto.rs', minVersion: new Version(0, 1, 1) }],
|
||||
[{ vectorExt: DatabaseExtension.VECTOR, extName: 'pgvector', minVersion: new Version(0, 5, 0) }],
|
||||
] as const)('init', ({ vectorExt, extName, minVersion }) => {
|
||||
let fatalLog: jest.SpyInstance;
|
||||
let errorLog: jest.SpyInstance;
|
||||
let warnLog: jest.SpyInstance;
|
||||
let fatalLog: MockInstance;
|
||||
let errorLog: MockInstance;
|
||||
let warnLog: MockInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
fatalLog = jest.spyOn(ImmichLogger.prototype, 'fatal');
|
||||
errorLog = jest.spyOn(ImmichLogger.prototype, 'error');
|
||||
warnLog = jest.spyOn(ImmichLogger.prototype, 'warn');
|
||||
fatalLog = vitest.spyOn(ImmichLogger.prototype, 'fatal');
|
||||
errorLog = vitest.spyOn(ImmichLogger.prototype, 'error');
|
||||
warnLog = vitest.spyOn(ImmichLogger.prototype, 'warn');
|
||||
databaseMock.getPreferredVectorExtension.mockReturnValue(vectorExt);
|
||||
databaseMock.getExtensionVersion.mockResolvedValue(minVersion);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import { when } from 'jest-when';
|
||||
import { DownloadResponseDto } from 'src/dtos/download.dto';
|
||||
import { AssetEntity } from 'src/entities/asset.entity';
|
||||
import { IAssetRepository } from 'src/interfaces/asset.interface';
|
||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||
import { DownloadService } from 'src/services/download.service';
|
||||
@@ -11,6 +11,7 @@ import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositorie
|
||||
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
|
||||
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
|
||||
import { Readable } from 'typeorm/platform/PlatformTools.js';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
const downloadResponse: DownloadResponseDto = {
|
||||
totalSize: 105_000,
|
||||
@@ -25,8 +26,8 @@ const downloadResponse: DownloadResponseDto = {
|
||||
describe(DownloadService.name, () => {
|
||||
let sut: DownloadService;
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
|
||||
it('should work', () => {
|
||||
expect(sut).toBeDefined();
|
||||
@@ -82,8 +83,8 @@ describe(DownloadService.name, () => {
|
||||
|
||||
it('should download an archive', async () => {
|
||||
const archiveMock = {
|
||||
addFile: jest.fn(),
|
||||
finalize: jest.fn(),
|
||||
addFile: vitest.fn(),
|
||||
finalize: vitest.fn(),
|
||||
stream: new Readable(),
|
||||
};
|
||||
|
||||
@@ -105,8 +106,8 @@ describe(DownloadService.name, () => {
|
||||
|
||||
it('should handle duplicate file names', async () => {
|
||||
const archiveMock = {
|
||||
addFile: jest.fn(),
|
||||
finalize: jest.fn(),
|
||||
addFile: vitest.fn(),
|
||||
finalize: vitest.fn(),
|
||||
stream: new Readable(),
|
||||
};
|
||||
|
||||
@@ -128,8 +129,8 @@ describe(DownloadService.name, () => {
|
||||
|
||||
it('should be deterministic', async () => {
|
||||
const archiveMock = {
|
||||
addFile: jest.fn(),
|
||||
finalize: jest.fn(),
|
||||
addFile: vitest.fn(),
|
||||
finalize: vitest.fn(),
|
||||
stream: new Readable(),
|
||||
};
|
||||
|
||||
@@ -223,14 +224,15 @@ describe(DownloadService.name, () => {
|
||||
|
||||
it('should include the video portion of a live photo', async () => {
|
||||
const assetIds = [assetStub.livePhotoStillAsset.id];
|
||||
const assets = [assetStub.livePhotoStillAsset, assetStub.livePhotoMotionAsset];
|
||||
|
||||
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(assetIds));
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.livePhotoStillAsset.id], { exifInfo: true })
|
||||
.mockResolvedValue([assetStub.livePhotoStillAsset]);
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.livePhotoMotionAsset.id], { exifInfo: true })
|
||||
.mockResolvedValue([assetStub.livePhotoMotionAsset]);
|
||||
assetMock.getByIds.mockImplementation(
|
||||
(ids) =>
|
||||
Promise.resolve(
|
||||
ids.map((id) => assets.find((asset) => asset.id === id)).filter((asset) => !!asset),
|
||||
) as Promise<AssetEntity[]>,
|
||||
);
|
||||
|
||||
await expect(sut.getDownloadInfo(authStub.admin, { assetIds })).resolves.toEqual({
|
||||
totalSize: 125_000,
|
||||
|
||||
@@ -23,9 +23,10 @@ import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
|
||||
import { newMetricRepositoryMock } from 'test/repositories/metric.repository.mock';
|
||||
import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
const makeMockHandlers = (status: JobStatus) => {
|
||||
const mock = jest.fn().mockResolvedValue(status);
|
||||
const mock = vitest.fn().mockResolvedValue(status);
|
||||
return Object.fromEntries(Object.values(JobName).map((jobName) => [jobName, mock])) as unknown as Record<
|
||||
JobName,
|
||||
JobHandler
|
||||
@@ -34,12 +35,12 @@ const makeMockHandlers = (status: JobStatus) => {
|
||||
|
||||
describe(JobService.name, () => {
|
||||
let sut: JobService;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let eventMock: jest.Mocked<IEventRepository>;
|
||||
let jobMock: jest.Mocked<IJobRepository>;
|
||||
let personMock: jest.Mocked<IPersonRepository>;
|
||||
let metricMock: jest.Mocked<IMetricRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let eventMock: Mocked<IEventRepository>;
|
||||
let jobMock: Mocked<IJobRepository>;
|
||||
let personMock: Mocked<IPersonRepository>;
|
||||
let metricMock: Mocked<IMetricRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
assetMock = newAssetRepositoryMock();
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import { when } from 'jest-when';
|
||||
import { R_OK } from 'node:constants';
|
||||
import { Stats } from 'node:fs';
|
||||
import { SystemConfigCore } from 'src/cores/system-config.core';
|
||||
import { mapLibrary } from 'src/dtos/library.dto';
|
||||
@@ -28,17 +26,18 @@ import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
|
||||
import { newLibraryRepositoryMock } from 'test/repositories/library.repository.mock';
|
||||
import { makeMockWatcher, newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
describe(LibraryService.name, () => {
|
||||
let sut: LibraryService;
|
||||
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let cryptoMock: jest.Mocked<ICryptoRepository>;
|
||||
let jobMock: jest.Mocked<IJobRepository>;
|
||||
let libraryMock: jest.Mocked<ILibraryRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let databaseMock: jest.Mocked<IDatabaseRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let cryptoMock: Mocked<ICryptoRepository>;
|
||||
let jobMock: Mocked<IJobRepository>;
|
||||
let libraryMock: Mocked<ILibraryRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
let databaseMock: Mocked<IDatabaseRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
configMock = newSystemConfigRepositoryMock();
|
||||
@@ -89,15 +88,13 @@ describe(LibraryService.name, () => {
|
||||
]);
|
||||
|
||||
configMock.load.mockResolvedValue(systemConfigStub.libraryWatchEnabled);
|
||||
libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1);
|
||||
|
||||
when(libraryMock.get)
|
||||
.calledWith(libraryStub.externalLibraryWithImportPaths1.id)
|
||||
.mockResolvedValue(libraryStub.externalLibraryWithImportPaths1);
|
||||
|
||||
when(libraryMock.get)
|
||||
.calledWith(libraryStub.externalLibraryWithImportPaths2.id)
|
||||
.mockResolvedValue(libraryStub.externalLibraryWithImportPaths2);
|
||||
libraryMock.get.mockImplementation((id) =>
|
||||
Promise.resolve(
|
||||
[libraryStub.externalLibraryWithImportPaths1, libraryStub.externalLibraryWithImportPaths2].find(
|
||||
(library) => library.id === id,
|
||||
) || null,
|
||||
),
|
||||
);
|
||||
|
||||
await sut.init();
|
||||
|
||||
@@ -751,7 +748,7 @@ describe(LibraryService.name, () => {
|
||||
|
||||
configMock.load.mockResolvedValue(systemConfigStub.libraryWatchEnabled);
|
||||
|
||||
const mockClose = jest.fn();
|
||||
const mockClose = vitest.fn();
|
||||
storageMock.watch.mockImplementation(makeMockWatcher({ close: mockClose }));
|
||||
|
||||
await sut.init();
|
||||
@@ -1123,7 +1120,7 @@ describe(LibraryService.name, () => {
|
||||
it('should watch and unwatch library', async () => {
|
||||
libraryMock.getAll.mockResolvedValue([libraryStub.externalLibraryWithImportPaths1]);
|
||||
libraryMock.get.mockResolvedValue(libraryStub.externalLibraryWithImportPaths1);
|
||||
const mockClose = jest.fn();
|
||||
const mockClose = vitest.fn();
|
||||
storageMock.watch.mockImplementation(makeMockWatcher({ close: mockClose }));
|
||||
|
||||
await sut.watchAll();
|
||||
@@ -1260,15 +1257,15 @@ describe(LibraryService.name, () => {
|
||||
configMock.load.mockResolvedValue(systemConfigStub.libraryWatchEnabled);
|
||||
libraryMock.get.mockResolvedValue(libraryStub.externalLibrary1);
|
||||
|
||||
when(libraryMock.get)
|
||||
.calledWith(libraryStub.externalLibraryWithImportPaths1.id)
|
||||
.mockResolvedValue(libraryStub.externalLibraryWithImportPaths1);
|
||||
libraryMock.get.mockImplementation((id) =>
|
||||
Promise.resolve(
|
||||
[libraryStub.externalLibraryWithImportPaths1, libraryStub.externalLibraryWithImportPaths2].find(
|
||||
(library) => library.id === id,
|
||||
) || null,
|
||||
),
|
||||
);
|
||||
|
||||
when(libraryMock.get)
|
||||
.calledWith(libraryStub.externalLibraryWithImportPaths2.id)
|
||||
.mockResolvedValue(libraryStub.externalLibraryWithImportPaths2);
|
||||
|
||||
const mockClose = jest.fn();
|
||||
const mockClose = vitest.fn();
|
||||
storageMock.watch.mockImplementation(makeMockWatcher({ close: mockClose }));
|
||||
|
||||
await sut.init();
|
||||
@@ -1545,7 +1542,7 @@ describe(LibraryService.name, () => {
|
||||
it('should detect when import path is in immich media folder', async () => {
|
||||
storageMock.stat.mockResolvedValue({ isDirectory: () => true } as Stats);
|
||||
const validImport = libraryStub.hasImmichPaths.importPaths[1];
|
||||
when(storageMock.checkFileExists).calledWith(validImport, R_OK).mockResolvedValue(true);
|
||||
storageMock.checkFileExists.mockImplementation((importPath) => Promise.resolve(importPath === validImport));
|
||||
|
||||
await expect(
|
||||
sut.validate('library-id', { importPaths: libraryStub.hasImmichPaths.importPaths }),
|
||||
|
||||
@@ -32,17 +32,18 @@ import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock';
|
||||
import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
|
||||
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(MediaService.name, () => {
|
||||
let sut: MediaService;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let jobMock: jest.Mocked<IJobRepository>;
|
||||
let mediaMock: jest.Mocked<IMediaRepository>;
|
||||
let moveMock: jest.Mocked<IMoveRepository>;
|
||||
let personMock: jest.Mocked<IPersonRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let cryptoMock: jest.Mocked<ICryptoRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let jobMock: Mocked<IJobRepository>;
|
||||
let mediaMock: Mocked<IMediaRepository>;
|
||||
let moveMock: Mocked<IMoveRepository>;
|
||||
let personMock: Mocked<IPersonRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
let cryptoMock: Mocked<ICryptoRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
assetMock = newAssetRepositoryMock();
|
||||
|
||||
@@ -7,10 +7,11 @@ import { memoryStub } from 'test/fixtures/memory.stub';
|
||||
import { userStub } from 'test/fixtures/user.stub';
|
||||
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
|
||||
import { newMemoryRepositoryMock } from 'test/repositories/memory.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(MemoryService.name, () => {
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let memoryMock: jest.Mocked<IMemoryRepository>;
|
||||
let memoryMock: Mocked<IMemoryRepository>;
|
||||
let sut: MemoryService;
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { BinaryField } from 'exiftool-vendored';
|
||||
import { when } from 'jest-when';
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { Stats } from 'node:fs';
|
||||
import { constants } from 'node:fs/promises';
|
||||
@@ -34,20 +33,21 @@ import { newMoveRepositoryMock } from 'test/repositories/move.repository.mock';
|
||||
import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
|
||||
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(MetadataService.name, () => {
|
||||
let albumMock: jest.Mocked<IAlbumRepository>;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let cryptoRepository: jest.Mocked<ICryptoRepository>;
|
||||
let jobMock: jest.Mocked<IJobRepository>;
|
||||
let metadataMock: jest.Mocked<IMetadataRepository>;
|
||||
let moveMock: jest.Mocked<IMoveRepository>;
|
||||
let mediaMock: jest.Mocked<IMediaRepository>;
|
||||
let personMock: jest.Mocked<IPersonRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let eventMock: jest.Mocked<IEventRepository>;
|
||||
let databaseMock: jest.Mocked<IDatabaseRepository>;
|
||||
let albumMock: Mocked<IAlbumRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let cryptoRepository: Mocked<ICryptoRepository>;
|
||||
let jobMock: Mocked<IJobRepository>;
|
||||
let metadataMock: Mocked<IMetadataRepository>;
|
||||
let moveMock: Mocked<IMoveRepository>;
|
||||
let mediaMock: Mocked<IMediaRepository>;
|
||||
let personMock: Mocked<IPersonRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
let eventMock: Mocked<IEventRepository>;
|
||||
let databaseMock: Mocked<IDatabaseRepository>;
|
||||
let sut: MetadataService;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -248,14 +248,13 @@ describe(MetadataService.name, () => {
|
||||
const originalDate = new Date('2023-11-21T16:13:17.517Z');
|
||||
const sidecarDate = new Date('2022-01-01T00:00:00.000Z');
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.sidecar]);
|
||||
when(metadataMock.readTags)
|
||||
.calledWith(assetStub.sidecar.originalPath)
|
||||
// higher priority tag
|
||||
.mockResolvedValue({ CreationDate: originalDate.toISOString() });
|
||||
when(metadataMock.readTags)
|
||||
.calledWith(assetStub.sidecar.sidecarPath as string)
|
||||
// lower priority tag, but in sidecar
|
||||
.mockResolvedValue({ CreateDate: sidecarDate.toISOString() });
|
||||
metadataMock.readTags.mockImplementation((path) => {
|
||||
const map = {
|
||||
[assetStub.sidecar.originalPath]: originalDate.toISOString(),
|
||||
[assetStub.sidecar.sidecarPath as string]: sidecarDate.toISOString(),
|
||||
};
|
||||
return Promise.resolve({ CreationDate: map[path] ?? new Date().toISOString() });
|
||||
});
|
||||
|
||||
await sut.handleMetadataExtraction({ id: assetStub.image.id });
|
||||
expect(assetMock.getByIds).toHaveBeenCalledWith([assetStub.sidecar.id]);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { PartnerService } from 'src/services/partner.service';
|
||||
import { authStub } from 'test/fixtures/auth.stub';
|
||||
import { partnerStub } from 'test/fixtures/partner.stub';
|
||||
import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
const responseDto = {
|
||||
admin: <PartnerResponseDto>{
|
||||
@@ -49,8 +50,8 @@ const responseDto = {
|
||||
|
||||
describe(PartnerService.name, () => {
|
||||
let sut: PartnerService;
|
||||
let partnerMock: jest.Mocked<IPartnerRepository>;
|
||||
let accessMock: jest.Mocked<IAccessRepository>;
|
||||
let partnerMock: Mocked<IPartnerRepository>;
|
||||
let accessMock: Mocked<IAccessRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
partnerMock = newPartnerRepositoryMock();
|
||||
|
||||
@@ -31,6 +31,7 @@ import { newSearchRepositoryMock } from 'test/repositories/search.repository.moc
|
||||
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { IsNull } from 'typeorm';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
const responseDto: PersonResponseDto = {
|
||||
id: 'person-1',
|
||||
@@ -61,16 +62,16 @@ const detectFaceMock = {
|
||||
|
||||
describe(PersonService.name, () => {
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let jobMock: jest.Mocked<IJobRepository>;
|
||||
let machineLearningMock: jest.Mocked<IMachineLearningRepository>;
|
||||
let mediaMock: jest.Mocked<IMediaRepository>;
|
||||
let moveMock: jest.Mocked<IMoveRepository>;
|
||||
let personMock: jest.Mocked<IPersonRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let searchMock: jest.Mocked<ISearchRepository>;
|
||||
let cryptoMock: jest.Mocked<ICryptoRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let jobMock: Mocked<IJobRepository>;
|
||||
let machineLearningMock: Mocked<IMachineLearningRepository>;
|
||||
let mediaMock: Mocked<IMediaRepository>;
|
||||
let moveMock: Mocked<IMoveRepository>;
|
||||
let personMock: Mocked<IPersonRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
let searchMock: Mocked<ISearchRepository>;
|
||||
let cryptoMock: Mocked<ICryptoRepository>;
|
||||
let sut: PersonService;
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
@@ -19,18 +19,19 @@ import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.m
|
||||
import { newPersonRepositoryMock } from 'test/repositories/person.repository.mock';
|
||||
import { newSearchRepositoryMock } from 'test/repositories/search.repository.mock';
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
jest.useFakeTimers();
|
||||
vitest.useFakeTimers();
|
||||
|
||||
describe(SearchService.name, () => {
|
||||
let sut: SearchService;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let machineMock: jest.Mocked<IMachineLearningRepository>;
|
||||
let personMock: jest.Mocked<IPersonRepository>;
|
||||
let searchMock: jest.Mocked<ISearchRepository>;
|
||||
let partnerMock: jest.Mocked<IPartnerRepository>;
|
||||
let metadataMock: jest.Mocked<IMetadataRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let machineMock: Mocked<IMachineLearningRepository>;
|
||||
let personMock: Mocked<IPersonRepository>;
|
||||
let searchMock: Mocked<ISearchRepository>;
|
||||
let partnerMock: Mocked<IPartnerRepository>;
|
||||
let metadataMock: Mocked<IMetadataRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
assetMock = newAssetRepositoryMock();
|
||||
|
||||
@@ -13,15 +13,16 @@ import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.r
|
||||
import { newServerInfoRepositoryMock } from 'test/repositories/system-info.repository.mock';
|
||||
import { newSystemMetadataRepositoryMock } from 'test/repositories/system-metadata.repository.mock';
|
||||
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(ServerInfoService.name, () => {
|
||||
let sut: ServerInfoService;
|
||||
let eventMock: jest.Mocked<IEventRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let serverInfoMock: jest.Mocked<IServerInfoRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let userMock: jest.Mocked<IUserRepository>;
|
||||
let systemMetadataMock: jest.Mocked<ISystemMetadataRepository>;
|
||||
let eventMock: Mocked<IEventRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let serverInfoMock: Mocked<IServerInfoRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
let userMock: Mocked<IUserRepository>;
|
||||
let systemMetadataMock: Mocked<ISystemMetadataRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
configMock = newSystemConfigRepositoryMock();
|
||||
|
||||
@@ -12,12 +12,13 @@ import { sharedLinkResponseStub, sharedLinkStub } from 'test/fixtures/shared-lin
|
||||
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
|
||||
import { newCryptoRepositoryMock } from 'test/repositories/crypto.repository.mock';
|
||||
import { newSharedLinkRepositoryMock } from 'test/repositories/shared-link.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(SharedLinkService.name, () => {
|
||||
let sut: SharedLinkService;
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let cryptoMock: jest.Mocked<ICryptoRepository>;
|
||||
let shareMock: jest.Mocked<ISharedLinkRepository>;
|
||||
let cryptoMock: Mocked<ICryptoRepository>;
|
||||
let shareMock: Mocked<ISharedLinkRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
accessMock = newAccessRepositoryMock();
|
||||
|
||||
@@ -15,6 +15,7 @@ import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
|
||||
import { newMachineLearningRepositoryMock } from 'test/repositories/machine-learning.repository.mock';
|
||||
import { newSearchRepositoryMock } from 'test/repositories/search.repository.mock';
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
const asset = {
|
||||
id: 'asset-1',
|
||||
@@ -23,12 +24,12 @@ const asset = {
|
||||
|
||||
describe(SmartInfoService.name, () => {
|
||||
let sut: SmartInfoService;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let jobMock: jest.Mocked<IJobRepository>;
|
||||
let searchMock: jest.Mocked<ISearchRepository>;
|
||||
let machineMock: jest.Mocked<IMachineLearningRepository>;
|
||||
let databaseMock: jest.Mocked<IDatabaseRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let jobMock: Mocked<IJobRepository>;
|
||||
let searchMock: Mocked<ISearchRepository>;
|
||||
let machineMock: Mocked<IMachineLearningRepository>;
|
||||
let databaseMock: Mocked<IDatabaseRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
assetMock = newAssetRepositoryMock();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { when } from 'jest-when';
|
||||
import { Stats } from 'node:fs';
|
||||
import { SystemConfigCore, defaults } from 'src/cores/system-config.core';
|
||||
import { AssetEntity } from 'src/entities/asset.entity';
|
||||
import { AssetPathType } from 'src/entities/move.entity';
|
||||
import { SystemConfig, SystemConfigKey } from 'src/entities/system-config.entity';
|
||||
import { IAlbumRepository } from 'src/interfaces/album.interface';
|
||||
@@ -25,18 +25,19 @@ import { newPersonRepositoryMock } from 'test/repositories/person.repository.moc
|
||||
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(StorageTemplateService.name, () => {
|
||||
let sut: StorageTemplateService;
|
||||
let albumMock: jest.Mocked<IAlbumRepository>;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let moveMock: jest.Mocked<IMoveRepository>;
|
||||
let personMock: jest.Mocked<IPersonRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let userMock: jest.Mocked<IUserRepository>;
|
||||
let cryptoMock: jest.Mocked<ICryptoRepository>;
|
||||
let databaseMock: jest.Mocked<IDatabaseRepository>;
|
||||
let albumMock: Mocked<IAlbumRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let moveMock: Mocked<IMoveRepository>;
|
||||
let personMock: Mocked<IPersonRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
let userMock: Mocked<IUserRepository>;
|
||||
let cryptoMock: Mocked<ICryptoRepository>;
|
||||
let databaseMock: Mocked<IDatabaseRepository>;
|
||||
|
||||
it('should work', () => {
|
||||
expect(sut).toBeDefined();
|
||||
@@ -118,43 +119,28 @@ describe(StorageTemplateService.name, () => {
|
||||
const newMotionPicturePath = `upload/library/${userStub.user1.id}/2022/2022-06-19/${assetStub.livePhotoStillAsset.id}.mp4`;
|
||||
const newStillPicturePath = `upload/library/${userStub.user1.id}/2022/2022-06-19/${assetStub.livePhotoStillAsset.id}.jpeg`;
|
||||
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.livePhotoStillAsset.id], { exifInfo: true })
|
||||
.mockResolvedValue([assetStub.livePhotoStillAsset]);
|
||||
assetMock.getByIds.mockImplementation((ids) => {
|
||||
const assets = [assetStub.livePhotoStillAsset, assetStub.livePhotoMotionAsset];
|
||||
return Promise.resolve(
|
||||
ids.map((id) => assets.find((asset) => asset.id === id)).filter((asset) => !!asset),
|
||||
) as Promise<AssetEntity[]>;
|
||||
});
|
||||
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.livePhotoMotionAsset.id], { exifInfo: true })
|
||||
.mockResolvedValue([assetStub.livePhotoMotionAsset]);
|
||||
moveMock.create.mockResolvedValueOnce({
|
||||
id: '123',
|
||||
entityId: assetStub.livePhotoStillAsset.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.livePhotoStillAsset.originalPath,
|
||||
newPath: newStillPicturePath,
|
||||
});
|
||||
|
||||
when(moveMock.create)
|
||||
.calledWith({
|
||||
entityId: assetStub.livePhotoStillAsset.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.livePhotoStillAsset.originalPath,
|
||||
newPath: newStillPicturePath,
|
||||
})
|
||||
.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.livePhotoStillAsset.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.livePhotoStillAsset.originalPath,
|
||||
newPath: newStillPicturePath,
|
||||
});
|
||||
|
||||
when(moveMock.create)
|
||||
.calledWith({
|
||||
entityId: assetStub.livePhotoMotionAsset.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.livePhotoMotionAsset.originalPath,
|
||||
newPath: newMotionPicturePath,
|
||||
})
|
||||
.mockResolvedValue({
|
||||
id: '124',
|
||||
entityId: assetStub.livePhotoMotionAsset.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.livePhotoMotionAsset.originalPath,
|
||||
newPath: newMotionPicturePath,
|
||||
});
|
||||
moveMock.create.mockResolvedValueOnce({
|
||||
id: '124',
|
||||
entityId: assetStub.livePhotoMotionAsset.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.livePhotoMotionAsset.originalPath,
|
||||
newPath: newMotionPicturePath,
|
||||
});
|
||||
|
||||
await expect(sut.handleMigrationSingle({ id: assetStub.livePhotoStillAsset.id })).resolves.toBe(
|
||||
JobStatus.SUCCESS,
|
||||
@@ -177,34 +163,22 @@ describe(StorageTemplateService.name, () => {
|
||||
const previousFailedNewPath = `upload/library/${userStub.user1.id}/2023/Feb/${assetStub.image.id}.jpg`;
|
||||
const newPath = `upload/library/${userStub.user1.id}/2023/2023-02-23/${assetStub.image.id}.jpg`;
|
||||
|
||||
when(storageMock.checkFileExists).calledWith(assetStub.image.originalPath).mockResolvedValue(true);
|
||||
when(storageMock.checkFileExists).calledWith(previousFailedNewPath).mockResolvedValue(false);
|
||||
|
||||
when(moveMock.getByEntity).calledWith(assetStub.image.id, AssetPathType.ORIGINAL).mockResolvedValue({
|
||||
storageMock.checkFileExists.mockImplementation((path) => Promise.resolve(path === assetStub.image.originalPath));
|
||||
moveMock.getByEntity.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.image.originalPath,
|
||||
newPath: previousFailedNewPath,
|
||||
});
|
||||
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.image.id], { exifInfo: true })
|
||||
.mockResolvedValue([assetStub.image]);
|
||||
|
||||
when(moveMock.update)
|
||||
.calledWith({
|
||||
id: '123',
|
||||
oldPath: assetStub.image.originalPath,
|
||||
newPath,
|
||||
})
|
||||
.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.image.originalPath,
|
||||
newPath,
|
||||
});
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
||||
moveMock.update.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.image.originalPath,
|
||||
newPath,
|
||||
});
|
||||
|
||||
await expect(sut.handleMigrationSingle({ id: assetStub.image.id })).resolves.toBe(JobStatus.SUCCESS);
|
||||
|
||||
@@ -226,38 +200,24 @@ describe(StorageTemplateService.name, () => {
|
||||
const previousFailedNewPath = `upload/library/${userStub.user1.id}/2023/Feb/${assetStub.image.id}.jpg`;
|
||||
const newPath = `upload/library/${userStub.user1.id}/2023/2023-02-23/${assetStub.image.id}.jpg`;
|
||||
|
||||
when(storageMock.checkFileExists).calledWith(assetStub.image.originalPath).mockResolvedValue(false);
|
||||
when(storageMock.checkFileExists).calledWith(previousFailedNewPath).mockResolvedValue(true);
|
||||
when(storageMock.stat)
|
||||
.calledWith(previousFailedNewPath)
|
||||
.mockResolvedValue({ size: 5000 } as Stats);
|
||||
when(cryptoMock.hashFile).calledWith(previousFailedNewPath).mockResolvedValue(assetStub.image.checksum);
|
||||
|
||||
when(moveMock.getByEntity).calledWith(assetStub.image.id, AssetPathType.ORIGINAL).mockResolvedValue({
|
||||
storageMock.checkFileExists.mockImplementation((path) => Promise.resolve(path === previousFailedNewPath));
|
||||
storageMock.stat.mockResolvedValue({ size: 5000 } as Stats);
|
||||
cryptoMock.hashFile.mockResolvedValue(assetStub.image.checksum);
|
||||
moveMock.getByEntity.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.image.originalPath,
|
||||
newPath: previousFailedNewPath,
|
||||
});
|
||||
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.image.id], { exifInfo: true })
|
||||
.mockResolvedValue([assetStub.image]);
|
||||
|
||||
when(moveMock.update)
|
||||
.calledWith({
|
||||
id: '123',
|
||||
oldPath: previousFailedNewPath,
|
||||
newPath,
|
||||
})
|
||||
.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: previousFailedNewPath,
|
||||
newPath,
|
||||
});
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
||||
moveMock.update.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: previousFailedNewPath,
|
||||
newPath,
|
||||
});
|
||||
|
||||
await expect(sut.handleMigrationSingle({ id: assetStub.image.id })).resolves.toBe(JobStatus.SUCCESS);
|
||||
|
||||
@@ -281,30 +241,17 @@ describe(StorageTemplateService.name, () => {
|
||||
userMock.get.mockResolvedValue(userStub.user1);
|
||||
const newPath = `upload/library/${userStub.user1.id}/2023/2023-02-23/${assetStub.image.id}.jpg`;
|
||||
|
||||
when(storageMock.rename).calledWith(assetStub.image.originalPath, newPath).mockRejectedValue({ code: 'EXDEV' });
|
||||
when(storageMock.stat)
|
||||
.calledWith(newPath)
|
||||
.mockResolvedValue({ size: 5000 } as Stats);
|
||||
when(cryptoMock.hashFile).calledWith(newPath).mockResolvedValue(Buffer.from('different-hash', 'utf8'));
|
||||
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.image.id], { exifInfo: true })
|
||||
.mockResolvedValue([assetStub.image]);
|
||||
|
||||
when(moveMock.create)
|
||||
.calledWith({
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.image.originalPath,
|
||||
newPath: newPath,
|
||||
})
|
||||
.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.image.originalPath,
|
||||
newPath,
|
||||
});
|
||||
storageMock.rename.mockRejectedValue({ code: 'EXDEV' });
|
||||
storageMock.stat.mockResolvedValue({ size: 5000 } as Stats);
|
||||
cryptoMock.hashFile.mockResolvedValue(Buffer.from('different-hash', 'utf8'));
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
||||
moveMock.create.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.image.originalPath,
|
||||
newPath,
|
||||
});
|
||||
|
||||
await expect(sut.handleMigrationSingle({ id: assetStub.image.id })).resolves.toBe(JobStatus.SUCCESS);
|
||||
|
||||
@@ -335,38 +282,24 @@ describe(StorageTemplateService.name, () => {
|
||||
const previousFailedNewPath = `upload/library/${userStub.user1.id}/2023/Feb/${assetStub.image.id}.jpg`;
|
||||
const newPath = `upload/library/${userStub.user1.id}/2023/2023-02-23/${assetStub.image.id}.jpg`;
|
||||
|
||||
when(storageMock.checkFileExists).calledWith(assetStub.image.originalPath).mockResolvedValue(false);
|
||||
when(storageMock.checkFileExists).calledWith(previousFailedNewPath).mockResolvedValue(true);
|
||||
when(storageMock.stat)
|
||||
.calledWith(previousFailedNewPath)
|
||||
.mockResolvedValue({ size: failedPathSize } as Stats);
|
||||
when(cryptoMock.hashFile).calledWith(previousFailedNewPath).mockResolvedValue(failedPathChecksum);
|
||||
|
||||
when(moveMock.getByEntity).calledWith(assetStub.image.id, AssetPathType.ORIGINAL).mockResolvedValue({
|
||||
storageMock.checkFileExists.mockImplementation((path) => Promise.resolve(previousFailedNewPath === path));
|
||||
storageMock.stat.mockResolvedValue({ size: failedPathSize } as Stats);
|
||||
cryptoMock.hashFile.mockResolvedValue(failedPathChecksum);
|
||||
moveMock.getByEntity.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: assetStub.image.originalPath,
|
||||
newPath: previousFailedNewPath,
|
||||
});
|
||||
|
||||
when(assetMock.getByIds)
|
||||
.calledWith([assetStub.image.id], { exifInfo: true })
|
||||
.mockResolvedValue([assetStub.image]);
|
||||
|
||||
when(moveMock.update)
|
||||
.calledWith({
|
||||
id: '123',
|
||||
oldPath: previousFailedNewPath,
|
||||
newPath,
|
||||
})
|
||||
.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: previousFailedNewPath,
|
||||
newPath,
|
||||
});
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.image]);
|
||||
moveMock.update.mockResolvedValue({
|
||||
id: '123',
|
||||
entityId: assetStub.image.id,
|
||||
pathType: AssetPathType.ORIGINAL,
|
||||
oldPath: previousFailedNewPath,
|
||||
newPath,
|
||||
});
|
||||
|
||||
await expect(sut.handleMigrationSingle({ id: assetStub.image.id })).resolves.toBe(JobStatus.SUCCESS);
|
||||
|
||||
@@ -408,13 +341,8 @@ describe(StorageTemplateService.name, () => {
|
||||
newPath: 'upload/library/user-id/2023/2023-02-23/asset-id+1.jpg',
|
||||
});
|
||||
|
||||
when(storageMock.checkFileExists)
|
||||
.calledWith('upload/library/user-id/2023/2023-02-23/asset-id.jpg')
|
||||
.mockResolvedValue(true);
|
||||
|
||||
when(storageMock.checkFileExists)
|
||||
.calledWith('upload/library/user-id/2023/2023-02-23/asset-id+1.jpg')
|
||||
.mockResolvedValue(false);
|
||||
storageMock.checkFileExists.mockResolvedValueOnce(true);
|
||||
storageMock.checkFileExists.mockResolvedValueOnce(false);
|
||||
|
||||
await sut.handleMigration();
|
||||
|
||||
@@ -538,18 +466,18 @@ describe(StorageTemplateService.name, () => {
|
||||
oldPath: assetStub.image.originalPath,
|
||||
newPath,
|
||||
});
|
||||
when(storageMock.stat)
|
||||
.calledWith(newPath)
|
||||
.mockResolvedValue({
|
||||
size: 5000,
|
||||
} as Stats);
|
||||
when(storageMock.stat)
|
||||
.calledWith(assetStub.image.originalPath)
|
||||
.mockResolvedValue({
|
||||
atime: new Date(),
|
||||
mtime: new Date(),
|
||||
} as Stats);
|
||||
when(cryptoMock.hashFile).calledWith(newPath).mockResolvedValue(assetStub.image.checksum);
|
||||
storageMock.stat.mockResolvedValueOnce({
|
||||
atime: new Date(),
|
||||
mtime: new Date(),
|
||||
} as Stats);
|
||||
storageMock.stat.mockResolvedValueOnce({
|
||||
size: 5000,
|
||||
} as Stats);
|
||||
storageMock.stat.mockResolvedValueOnce({
|
||||
atime: new Date(),
|
||||
mtime: new Date(),
|
||||
} as Stats);
|
||||
cryptoMock.hashFile.mockResolvedValue(assetStub.image.checksum);
|
||||
|
||||
await sut.handleMigration();
|
||||
|
||||
@@ -581,11 +509,9 @@ describe(StorageTemplateService.name, () => {
|
||||
oldPath: assetStub.image.originalPath,
|
||||
newPath: 'upload/library/user-id/2023/2023-02-23/asset-id.jpg',
|
||||
});
|
||||
when(storageMock.stat)
|
||||
.calledWith('upload/library/user-id/2023/2023-02-23/asset-id.jpg')
|
||||
.mockResolvedValue({
|
||||
size: 100,
|
||||
} as Stats);
|
||||
storageMock.stat.mockResolvedValue({
|
||||
size: 100,
|
||||
} as Stats);
|
||||
|
||||
await sut.handleMigration();
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||
import { StorageService } from 'src/services/storage.service';
|
||||
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(StorageService.name, () => {
|
||||
let sut: StorageService;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
storageMock = newStorageRepositoryMock();
|
||||
|
||||
@@ -12,16 +12,17 @@ import { newAccessRepositoryMock } from 'test/repositories/access.repository.moc
|
||||
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
|
||||
import { newAuditRepositoryMock } from 'test/repositories/audit.repository.mock';
|
||||
import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
const untilDate = new Date(2024);
|
||||
const mapAssetOpts = { auth: authStub.user1, stripMetadata: false, withStack: true };
|
||||
|
||||
describe(SyncService.name, () => {
|
||||
let sut: SyncService;
|
||||
let accessMock: jest.Mocked<IAccessRepository>;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let partnerMock: jest.Mocked<IPartnerRepository>;
|
||||
let auditMock: jest.Mocked<IAuditRepository>;
|
||||
let accessMock: Mocked<IAccessRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let partnerMock: Mocked<IPartnerRepository>;
|
||||
let auditMock: Mocked<IAuditRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
partnerMock = newPartnerRepositoryMock();
|
||||
|
||||
@@ -24,6 +24,7 @@ import { ImmichLogger } from 'src/utils/logger';
|
||||
import { newEventRepositoryMock } from 'test/repositories/event.repository.mock';
|
||||
import { newLoggerRepositoryMock } from 'test/repositories/logger.repository.mock';
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { MockInstance, Mocked, vitest } from 'vitest';
|
||||
|
||||
const updates: SystemConfigEntity[] = [
|
||||
{ key: SystemConfigKey.FFMPEG_CRF, value: 30 },
|
||||
@@ -156,10 +157,10 @@ const updatedConfig = Object.freeze<SystemConfig>({
|
||||
|
||||
describe(SystemConfigService.name, () => {
|
||||
let sut: SystemConfigService;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let eventMock: jest.Mocked<IEventRepository>;
|
||||
let loggerMock: jest.Mocked<ILoggerRepository>;
|
||||
let smartInfoMock: jest.Mocked<ISearchRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
let eventMock: Mocked<IEventRepository>;
|
||||
let loggerMock: Mocked<ILoggerRepository>;
|
||||
let smartInfoMock: Mocked<ISearchRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
delete process.env.IMMICH_CONFIG_FILE;
|
||||
@@ -183,10 +184,10 @@ describe(SystemConfigService.name, () => {
|
||||
});
|
||||
|
||||
describe('getConfig', () => {
|
||||
let warnLog: jest.SpyInstance;
|
||||
let warnLog: MockInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
warnLog = jest.spyOn(ImmichLogger.prototype, 'warn');
|
||||
warnLog = vitest.spyOn(ImmichLogger.prototype, 'warn');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import { when } from 'jest-when';
|
||||
import { AssetIdErrorReason } from 'src/dtos/asset-ids.response.dto';
|
||||
import { TagType } from 'src/entities/tag.entity';
|
||||
import { ITagRepository } from 'src/interfaces/tag.interface';
|
||||
@@ -8,10 +7,11 @@ import { assetStub } from 'test/fixtures/asset.stub';
|
||||
import { authStub } from 'test/fixtures/auth.stub';
|
||||
import { tagResponseStub, tagStub } from 'test/fixtures/tag.stub';
|
||||
import { newTagRepositoryMock } from 'test/repositories/tag.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(TagService.name, () => {
|
||||
let sut: TagService;
|
||||
let tagMock: jest.Mocked<ITagRepository>;
|
||||
let tagMock: Mocked<ITagRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
tagMock = newTagRepositoryMock();
|
||||
@@ -129,9 +129,7 @@ describe(TagService.name, () => {
|
||||
|
||||
it('should reject duplicate asset ids and accept new ones', async () => {
|
||||
tagMock.getById.mockResolvedValue(tagStub.tag1);
|
||||
|
||||
when(tagMock.hasAsset).calledWith(authStub.admin.user.id, 'tag-1', 'asset-1').mockResolvedValue(true);
|
||||
when(tagMock.hasAsset).calledWith(authStub.admin.user.id, 'tag-1', 'asset-2').mockResolvedValue(false);
|
||||
tagMock.hasAsset.mockImplementation((userId, tagId, assetId) => Promise.resolve(assetId === 'asset-1'));
|
||||
|
||||
await expect(
|
||||
sut.addAssets(authStub.admin, 'tag-1', {
|
||||
@@ -160,9 +158,7 @@ describe(TagService.name, () => {
|
||||
|
||||
it('should accept accept ids that are tagged and reject the rest', async () => {
|
||||
tagMock.getById.mockResolvedValue(tagStub.tag1);
|
||||
|
||||
when(tagMock.hasAsset).calledWith(authStub.admin.user.id, 'tag-1', 'asset-1').mockResolvedValue(true);
|
||||
when(tagMock.hasAsset).calledWith(authStub.admin.user.id, 'tag-1', 'asset-2').mockResolvedValue(false);
|
||||
tagMock.hasAsset.mockImplementation((userId, tagId, assetId) => Promise.resolve(assetId === 'asset-1'));
|
||||
|
||||
await expect(
|
||||
sut.removeAssets(authStub.admin, 'tag-1', {
|
||||
|
||||
@@ -7,12 +7,13 @@ import { authStub } from 'test/fixtures/auth.stub';
|
||||
import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositories/access.repository.mock';
|
||||
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
|
||||
import { newPartnerRepositoryMock } from 'test/repositories/partner.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(TimelineService.name, () => {
|
||||
let sut: TimelineService;
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let partnerMock: jest.Mocked<IPartnerRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let partnerMock: Mocked<IPartnerRepository>;
|
||||
beforeEach(() => {
|
||||
accessMock = newAccessRepositoryMock();
|
||||
assetMock = newAssetRepositoryMock();
|
||||
|
||||
@@ -9,13 +9,14 @@ import { IAccessRepositoryMock, newAccessRepositoryMock } from 'test/repositorie
|
||||
import { newAssetRepositoryMock } from 'test/repositories/asset.repository.mock';
|
||||
import { newEventRepositoryMock } from 'test/repositories/event.repository.mock';
|
||||
import { newJobRepositoryMock } from 'test/repositories/job.repository.mock';
|
||||
import { Mocked } from 'vitest';
|
||||
|
||||
describe(TrashService.name, () => {
|
||||
let sut: TrashService;
|
||||
let accessMock: IAccessRepositoryMock;
|
||||
let assetMock: jest.Mocked<IAssetRepository>;
|
||||
let jobMock: jest.Mocked<IJobRepository>;
|
||||
let eventMock: jest.Mocked<IEventRepository>;
|
||||
let assetMock: Mocked<IAssetRepository>;
|
||||
let jobMock: Mocked<IJobRepository>;
|
||||
let eventMock: Mocked<IEventRepository>;
|
||||
|
||||
it('should work', () => {
|
||||
expect(sut).toBeDefined();
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
InternalServerErrorException,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { when } from 'jest-when';
|
||||
import { UpdateUserDto, mapUser } from 'src/dtos/user.dto';
|
||||
import { UserEntity, UserStatus } from 'src/entities/user.entity';
|
||||
import { IAlbumRepository } from 'src/interfaces/album.interface';
|
||||
@@ -26,6 +25,7 @@ import { newLibraryRepositoryMock } from 'test/repositories/library.repository.m
|
||||
import { newStorageRepositoryMock } from 'test/repositories/storage.repository.mock';
|
||||
import { newSystemConfigRepositoryMock } from 'test/repositories/system-config.repository.mock';
|
||||
import { newUserRepositoryMock } from 'test/repositories/user.repository.mock';
|
||||
import { Mocked, vitest } from 'vitest';
|
||||
|
||||
const makeDeletedAt = (daysAgo: number) => {
|
||||
const deletedAt = new Date();
|
||||
@@ -35,14 +35,14 @@ const makeDeletedAt = (daysAgo: number) => {
|
||||
|
||||
describe(UserService.name, () => {
|
||||
let sut: UserService;
|
||||
let userMock: jest.Mocked<IUserRepository>;
|
||||
let cryptoRepositoryMock: jest.Mocked<ICryptoRepository>;
|
||||
let userMock: Mocked<IUserRepository>;
|
||||
let cryptoRepositoryMock: Mocked<ICryptoRepository>;
|
||||
|
||||
let albumMock: jest.Mocked<IAlbumRepository>;
|
||||
let jobMock: jest.Mocked<IJobRepository>;
|
||||
let libraryMock: jest.Mocked<ILibraryRepository>;
|
||||
let storageMock: jest.Mocked<IStorageRepository>;
|
||||
let configMock: jest.Mocked<ISystemConfigRepository>;
|
||||
let albumMock: Mocked<IAlbumRepository>;
|
||||
let jobMock: Mocked<IJobRepository>;
|
||||
let libraryMock: Mocked<ILibraryRepository>;
|
||||
let storageMock: Mocked<IStorageRepository>;
|
||||
let configMock: Mocked<ISystemConfigRepository>;
|
||||
|
||||
beforeEach(() => {
|
||||
albumMock = newAlbumRepositoryMock();
|
||||
@@ -55,10 +55,9 @@ describe(UserService.name, () => {
|
||||
|
||||
sut = new UserService(albumMock, cryptoRepositoryMock, jobMock, libraryMock, storageMock, configMock, userMock);
|
||||
|
||||
when(userMock.get).calledWith(authStub.admin.user.id, {}).mockResolvedValue(userStub.admin);
|
||||
when(userMock.get).calledWith(authStub.admin.user.id, { withDeleted: true }).mockResolvedValue(userStub.admin);
|
||||
when(userMock.get).calledWith(authStub.user1.user.id, {}).mockResolvedValue(userStub.user1);
|
||||
when(userMock.get).calledWith(authStub.user1.user.id, { withDeleted: true }).mockResolvedValue(userStub.user1);
|
||||
userMock.get.mockImplementation((userId) =>
|
||||
Promise.resolve([userStub.admin, userStub.user1].find((user) => user.id === userId) ?? null),
|
||||
);
|
||||
});
|
||||
|
||||
describe('getAll', () => {
|
||||
@@ -136,12 +135,10 @@ describe(UserService.name, () => {
|
||||
});
|
||||
|
||||
it('user can only update its information', async () => {
|
||||
when(userMock.get)
|
||||
.calledWith('not_immich_auth_user_id', {})
|
||||
.mockResolvedValueOnce({
|
||||
...userStub.user1,
|
||||
id: 'not_immich_auth_user_id',
|
||||
});
|
||||
userMock.get.mockResolvedValueOnce({
|
||||
...userStub.user1,
|
||||
id: 'not_immich_auth_user_id',
|
||||
});
|
||||
|
||||
const result = sut.update(
|
||||
{ user: userStub.user1 },
|
||||
@@ -195,7 +192,7 @@ describe(UserService.name, () => {
|
||||
shouldChangePassword: true,
|
||||
};
|
||||
|
||||
when(userMock.update).calledWith(userStub.user1.id, update).mockResolvedValueOnce(userStub.user1);
|
||||
userMock.update.mockResolvedValueOnce(userStub.user1);
|
||||
await sut.update(authStub.admin, update);
|
||||
expect(userMock.update).toHaveBeenCalledWith(userStub.user1.id, {
|
||||
id: 'user-id',
|
||||
@@ -204,7 +201,7 @@ describe(UserService.name, () => {
|
||||
});
|
||||
|
||||
it('update user information should throw error if user not found', async () => {
|
||||
when(userMock.get).calledWith(userStub.user1.id, {}).mockResolvedValueOnce(null);
|
||||
userMock.get.mockResolvedValueOnce(null);
|
||||
|
||||
const result = sut.update(authStub.admin, {
|
||||
id: userStub.user1.id,
|
||||
@@ -217,7 +214,7 @@ describe(UserService.name, () => {
|
||||
it('should let the admin update himself', async () => {
|
||||
const dto = { id: userStub.admin.id, shouldChangePassword: true, isAdmin: true };
|
||||
|
||||
when(userMock.update).calledWith(userStub.admin.id, dto).mockResolvedValueOnce(userStub.admin);
|
||||
userMock.update.mockResolvedValueOnce(userStub.admin);
|
||||
|
||||
await sut.update(authStub.admin, dto);
|
||||
|
||||
@@ -227,7 +224,7 @@ describe(UserService.name, () => {
|
||||
it('should not let the another user become an admin', async () => {
|
||||
const dto = { id: userStub.user1.id, shouldChangePassword: true, isAdmin: true };
|
||||
|
||||
when(userMock.get).calledWith(userStub.user1.id, {}).mockResolvedValueOnce(userStub.user1);
|
||||
userMock.get.mockResolvedValueOnce(userStub.user1);
|
||||
|
||||
await expect(sut.update(authStub.admin, dto)).rejects.toBeInstanceOf(BadRequestException);
|
||||
});
|
||||
@@ -235,7 +232,7 @@ describe(UserService.name, () => {
|
||||
|
||||
describe('restore', () => {
|
||||
it('should throw error if user could not be found', async () => {
|
||||
when(userMock.get).calledWith(userStub.admin.id, { withDeleted: true }).mockResolvedValue(null);
|
||||
userMock.get.mockResolvedValue(null);
|
||||
await expect(sut.restore(authStub.admin, userStub.admin.id)).rejects.toThrowError(BadRequestException);
|
||||
expect(userMock.update).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -298,7 +295,7 @@ describe(UserService.name, () => {
|
||||
|
||||
describe('create', () => {
|
||||
it('should not create a user if there is no local admin account', async () => {
|
||||
when(userMock.getAdmin).calledWith().mockResolvedValueOnce(null);
|
||||
userMock.getAdmin.mockResolvedValueOnce(null);
|
||||
|
||||
await expect(
|
||||
sut.create({
|
||||
@@ -335,6 +332,7 @@ describe(UserService.name, () => {
|
||||
describe('createProfileImage', () => {
|
||||
it('should throw an error if the user does not exist', async () => {
|
||||
const file = { path: '/profile/path' } as Express.Multer.File;
|
||||
userMock.get.mockResolvedValue(null);
|
||||
userMock.update.mockResolvedValue({ ...userStub.admin, profileImagePath: file.path });
|
||||
|
||||
await expect(sut.createProfileImage(authStub.admin, file)).rejects.toThrowError(BadRequestException);
|
||||
@@ -422,7 +420,7 @@ describe(UserService.name, () => {
|
||||
describe('resetAdminPassword', () => {
|
||||
it('should only work when there is an admin account', async () => {
|
||||
userMock.getAdmin.mockResolvedValue(null);
|
||||
const ask = jest.fn().mockResolvedValue('new-password');
|
||||
const ask = vitest.fn().mockResolvedValue('new-password');
|
||||
|
||||
await expect(sut.resetAdminPassword(ask)).rejects.toBeInstanceOf(BadRequestException);
|
||||
|
||||
@@ -431,7 +429,7 @@ describe(UserService.name, () => {
|
||||
|
||||
it('should default to a random password', async () => {
|
||||
userMock.getAdmin.mockResolvedValue(userStub.admin);
|
||||
const ask = jest.fn().mockImplementation(() => {});
|
||||
const ask = vitest.fn().mockImplementation(() => {});
|
||||
|
||||
const response = await sut.resetAdminPassword(ask);
|
||||
|
||||
@@ -445,7 +443,7 @@ describe(UserService.name, () => {
|
||||
|
||||
it('should use the supplied password', async () => {
|
||||
userMock.getAdmin.mockResolvedValue(userStub.admin);
|
||||
const ask = jest.fn().mockResolvedValue('new-password');
|
||||
const ask = vitest.fn().mockResolvedValue('new-password');
|
||||
|
||||
const response = await sut.resetAdminPassword(ask);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user