Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 26 additions & 19 deletions server/src/services/activity.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { BadRequestException } from '@nestjs/common';
import { ReactionType } from 'src/dtos/activity.dto';
import { ActivityService } from 'src/services/activity.service';
import { ActivityFactory } from 'test/factories/activity.factory';
import { AuthFactory } from 'test/factories/auth.factory';
import { getForActivity } from 'test/mappers';
import { factory, newUuid, newUuids } from 'test/small.factory';
import { newUuid, newUuids } from 'test/small.factory';
import { newTestService, ServiceMocks } from 'test/utils';

describe(ActivityService.name, () => {
Expand All @@ -24,7 +26,7 @@ describe(ActivityService.name, () => {
mocks.access.album.checkOwnerAccess.mockResolvedValue(new Set([albumId]));
mocks.activity.search.mockResolvedValue([]);

await expect(sut.getAll(factory.auth({ user: { id: userId } }), { assetId, albumId })).resolves.toEqual([]);
await expect(sut.getAll(AuthFactory.create({ id: userId }), { assetId, albumId })).resolves.toEqual([]);

expect(mocks.activity.search).toHaveBeenCalledWith({ assetId, albumId, isLiked: undefined });
});
Expand All @@ -36,7 +38,7 @@ describe(ActivityService.name, () => {
mocks.activity.search.mockResolvedValue([]);

await expect(
sut.getAll(factory.auth({ user: { id: userId } }), { assetId, albumId, type: ReactionType.LIKE }),
sut.getAll(AuthFactory.create({ id: userId }), { assetId, albumId, type: ReactionType.LIKE }),
).resolves.toEqual([]);

expect(mocks.activity.search).toHaveBeenCalledWith({ assetId, albumId, isLiked: true });
Expand All @@ -48,7 +50,9 @@ describe(ActivityService.name, () => {
mocks.access.album.checkOwnerAccess.mockResolvedValue(new Set([albumId]));
mocks.activity.search.mockResolvedValue([]);

await expect(sut.getAll(factory.auth(), { assetId, albumId, type: ReactionType.COMMENT })).resolves.toEqual([]);
await expect(sut.getAll(AuthFactory.create(), { assetId, albumId, type: ReactionType.COMMENT })).resolves.toEqual(
[],
);

expect(mocks.activity.search).toHaveBeenCalledWith({ assetId, albumId, isLiked: false });
});
Expand All @@ -61,7 +65,10 @@ describe(ActivityService.name, () => {
mocks.activity.getStatistics.mockResolvedValue({ comments: 1, likes: 3 });
mocks.access.album.checkOwnerAccess.mockResolvedValue(new Set([albumId]));

await expect(sut.getStatistics(factory.auth(), { assetId, albumId })).resolves.toEqual({ comments: 1, likes: 3 });
await expect(sut.getStatistics(AuthFactory.create(), { assetId, albumId })).resolves.toEqual({
comments: 1,
likes: 3,
});
});
});

Expand All @@ -70,18 +77,18 @@ describe(ActivityService.name, () => {
const [albumId, assetId] = newUuids();

await expect(
sut.create(factory.auth(), { albumId, assetId, type: ReactionType.COMMENT, comment: 'comment' }),
sut.create(AuthFactory.create(), { albumId, assetId, type: ReactionType.COMMENT, comment: 'comment' }),
).rejects.toBeInstanceOf(BadRequestException);
});

it('should create a comment', async () => {
const [albumId, assetId, userId] = newUuids();
const activity = factory.activity({ albumId, assetId, userId });
const activity = ActivityFactory.create({ albumId, assetId, userId });

mocks.access.activity.checkCreateAccess.mockResolvedValue(new Set([albumId]));
mocks.activity.create.mockResolvedValue(getForActivity(activity));

await sut.create(factory.auth({ user: { id: userId } }), {
await sut.create(AuthFactory.create({ id: userId }), {
albumId,
assetId,
type: ReactionType.COMMENT,
Expand All @@ -99,68 +106,68 @@ describe(ActivityService.name, () => {

it('should fail because activity is disabled for the album', async () => {
const [albumId, assetId] = newUuids();
const activity = factory.activity({ albumId, assetId });
const activity = ActivityFactory.create({ albumId, assetId });

mocks.access.album.checkOwnerAccess.mockResolvedValue(new Set([albumId]));
mocks.activity.create.mockResolvedValue(getForActivity(activity));

await expect(
sut.create(factory.auth(), { albumId, assetId, type: ReactionType.COMMENT, comment: 'comment' }),
sut.create(AuthFactory.create(), { albumId, assetId, type: ReactionType.COMMENT, comment: 'comment' }),
).rejects.toBeInstanceOf(BadRequestException);
});

it('should create a like', async () => {
const [albumId, assetId, userId] = newUuids();
const activity = factory.activity({ userId, albumId, assetId, isLiked: true });
const activity = ActivityFactory.create({ userId, albumId, assetId, isLiked: true });

mocks.access.activity.checkCreateAccess.mockResolvedValue(new Set([albumId]));
mocks.activity.create.mockResolvedValue(getForActivity(activity));
mocks.activity.search.mockResolvedValue([]);

await sut.create(factory.auth({ user: { id: userId } }), { albumId, assetId, type: ReactionType.LIKE });
await sut.create(AuthFactory.create({ id: userId }), { albumId, assetId, type: ReactionType.LIKE });

expect(mocks.activity.create).toHaveBeenCalledWith({ userId: activity.userId, albumId, assetId, isLiked: true });
});

it('should skip if like exists', async () => {
const [albumId, assetId] = newUuids();
const activity = factory.activity({ albumId, assetId, isLiked: true });
const activity = ActivityFactory.create({ albumId, assetId, isLiked: true });

mocks.access.album.checkOwnerAccess.mockResolvedValue(new Set([albumId]));
mocks.access.activity.checkCreateAccess.mockResolvedValue(new Set([albumId]));
mocks.activity.search.mockResolvedValue([getForActivity(activity)]);

await sut.create(factory.auth(), { albumId, assetId, type: ReactionType.LIKE });
await sut.create(AuthFactory.create(), { albumId, assetId, type: ReactionType.LIKE });

expect(mocks.activity.create).not.toHaveBeenCalled();
});
});

describe('delete', () => {
it('should require access', async () => {
await expect(sut.delete(factory.auth(), newUuid())).rejects.toBeInstanceOf(BadRequestException);
await expect(sut.delete(AuthFactory.create(), newUuid())).rejects.toBeInstanceOf(BadRequestException);

expect(mocks.activity.delete).not.toHaveBeenCalled();
});

it('should let the activity owner delete a comment', async () => {
const activity = factory.activity();
const activity = ActivityFactory.create();

mocks.access.activity.checkOwnerAccess.mockResolvedValue(new Set([activity.id]));
mocks.activity.delete.mockResolvedValue();

await sut.delete(factory.auth(), activity.id);
await sut.delete(AuthFactory.create(), activity.id);

expect(mocks.activity.delete).toHaveBeenCalledWith(activity.id);
});

it('should let the album owner delete a comment', async () => {
const activity = factory.activity();
const activity = ActivityFactory.create();

mocks.access.activity.checkAlbumOwnerAccess.mockResolvedValue(new Set([activity.id]));
mocks.activity.delete.mockResolvedValue();

await sut.delete(factory.auth(), activity.id);
await sut.delete(AuthFactory.create(), activity.id);

expect(mocks.activity.delete).toHaveBeenCalledWith(activity.id);
});
Expand Down
77 changes: 42 additions & 35 deletions server/src/services/api-key.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { BadRequestException, ForbiddenException } from '@nestjs/common';
import { Permission } from 'src/enum';
import { ApiKeyService } from 'src/services/api-key.service';
import { factory, newUuid } from 'test/small.factory';
import { ApiKeyFactory } from 'test/factories/api-key.factory';
import { AuthFactory } from 'test/factories/auth.factory';
import { SessionFactory } from 'test/factories/session.factory';
import { newUuid } from 'test/small.factory';
import { newTestService, ServiceMocks } from 'test/utils';

describe(ApiKeyService.name, () => {
Expand All @@ -14,8 +17,8 @@ describe(ApiKeyService.name, () => {

describe('create', () => {
it('should create a new key', async () => {
const auth = factory.auth();
const apiKey = factory.apiKey({ userId: auth.user.id, permissions: [Permission.All] });
const auth = AuthFactory.create();
const apiKey = ApiKeyFactory.create({ userId: auth.user.id, permissions: [Permission.All] });
const key = 'super-secret';

mocks.crypto.randomBytesAsText.mockReturnValue(key);
Expand All @@ -34,8 +37,8 @@ describe(ApiKeyService.name, () => {
});

it('should not require a name', async () => {
const auth = factory.auth();
const apiKey = factory.apiKey({ userId: auth.user.id });
const auth = AuthFactory.create();
const apiKey = ApiKeyFactory.create({ userId: auth.user.id });
const key = 'super-secret';

mocks.crypto.randomBytesAsText.mockReturnValue(key);
Expand All @@ -54,7 +57,9 @@ describe(ApiKeyService.name, () => {
});

it('should throw an error if the api key does not have sufficient permissions', async () => {
const auth = factory.auth({ apiKey: { permissions: [Permission.AssetRead] } });
const auth = AuthFactory.from()
.apiKey({ permissions: [Permission.AssetRead] })
.build();

await expect(sut.create(auth, { permissions: [Permission.AssetUpdate] })).rejects.toBeInstanceOf(
BadRequestException,
Expand All @@ -65,7 +70,7 @@ describe(ApiKeyService.name, () => {
describe('update', () => {
it('should throw an error if the key is not found', async () => {
const id = newUuid();
const auth = factory.auth();
const auth = AuthFactory.create();

mocks.apiKey.getById.mockResolvedValue(void 0);

Expand All @@ -77,8 +82,8 @@ describe(ApiKeyService.name, () => {
});

it('should update a key', async () => {
const auth = factory.auth();
const apiKey = factory.apiKey({ userId: auth.user.id });
const auth = AuthFactory.create();
const apiKey = ApiKeyFactory.create({ userId: auth.user.id });
const newName = 'New name';

mocks.apiKey.getById.mockResolvedValue(apiKey);
Expand All @@ -93,8 +98,8 @@ describe(ApiKeyService.name, () => {
});

it('should update permissions', async () => {
const auth = factory.auth();
const apiKey = factory.apiKey({ userId: auth.user.id });
const auth = AuthFactory.create();
const apiKey = ApiKeyFactory.create({ userId: auth.user.id });
const newPermissions = [Permission.ActivityCreate, Permission.ActivityRead, Permission.ActivityUpdate];

mocks.apiKey.getById.mockResolvedValue(apiKey);
Expand All @@ -111,8 +116,8 @@ describe(ApiKeyService.name, () => {
describe('api key auth', () => {
it('should prevent adding Permission.all', async () => {
const permissions = [Permission.ApiKeyCreate, Permission.ApiKeyUpdate, Permission.AssetRead];
const auth = factory.auth({ apiKey: { permissions } });
const apiKey = factory.apiKey({ userId: auth.user.id, permissions });
const auth = AuthFactory.from().apiKey({ permissions }).build();
const apiKey = ApiKeyFactory.create({ userId: auth.user.id, permissions });

mocks.apiKey.getById.mockResolvedValue(apiKey);

Expand All @@ -125,8 +130,8 @@ describe(ApiKeyService.name, () => {

it('should prevent adding a new permission', async () => {
const permissions = [Permission.ApiKeyCreate, Permission.ApiKeyUpdate, Permission.AssetRead];
const auth = factory.auth({ apiKey: { permissions } });
const apiKey = factory.apiKey({ userId: auth.user.id, permissions });
const auth = AuthFactory.from().apiKey({ permissions }).build();
const apiKey = ApiKeyFactory.create({ userId: auth.user.id, permissions });

mocks.apiKey.getById.mockResolvedValue(apiKey);

Expand All @@ -138,8 +143,10 @@ describe(ApiKeyService.name, () => {
});

it('should allow removing permissions', async () => {
const auth = factory.auth({ apiKey: { permissions: [Permission.ApiKeyUpdate, Permission.AssetRead] } });
const apiKey = factory.apiKey({
const auth = AuthFactory.from()
.apiKey({ permissions: [Permission.ApiKeyUpdate, Permission.AssetRead] })
.build();
const apiKey = ApiKeyFactory.create({
userId: auth.user.id,
permissions: [Permission.AssetRead, Permission.AssetDelete],
});
Expand All @@ -158,10 +165,10 @@ describe(ApiKeyService.name, () => {
});

it('should allow adding new permissions', async () => {
const auth = factory.auth({
apiKey: { permissions: [Permission.ApiKeyUpdate, Permission.AssetRead, Permission.AssetUpdate] },
});
const apiKey = factory.apiKey({ userId: auth.user.id, permissions: [Permission.AssetRead] });
const auth = AuthFactory.from()
.apiKey({ permissions: [Permission.ApiKeyUpdate, Permission.AssetRead, Permission.AssetUpdate] })
.build();
const apiKey = ApiKeyFactory.create({ userId: auth.user.id, permissions: [Permission.AssetRead] });

mocks.apiKey.getById.mockResolvedValue(apiKey);
mocks.apiKey.update.mockResolvedValue(apiKey);
Expand All @@ -183,7 +190,7 @@ describe(ApiKeyService.name, () => {

describe('delete', () => {
it('should throw an error if the key is not found', async () => {
const auth = factory.auth();
const auth = AuthFactory.create();
const id = newUuid();

mocks.apiKey.getById.mockResolvedValue(void 0);
Expand All @@ -194,8 +201,8 @@ describe(ApiKeyService.name, () => {
});

it('should delete a key', async () => {
const auth = factory.auth();
const apiKey = factory.apiKey({ userId: auth.user.id });
const auth = AuthFactory.create();
const apiKey = ApiKeyFactory.create({ userId: auth.user.id });

mocks.apiKey.getById.mockResolvedValue(apiKey);
mocks.apiKey.delete.mockResolvedValue();
Expand All @@ -208,8 +215,8 @@ describe(ApiKeyService.name, () => {

describe('getMine', () => {
it('should not work with a session token', async () => {
const session = factory.session();
const auth = factory.auth({ session });
const session = SessionFactory.create();
const auth = AuthFactory.from().session(session).build();

mocks.apiKey.getById.mockResolvedValue(void 0);

Expand All @@ -219,8 +226,8 @@ describe(ApiKeyService.name, () => {
});

it('should throw an error if the key is not found', async () => {
const apiKey = factory.authApiKey();
const auth = factory.auth({ apiKey });
const apiKey = ApiKeyFactory.create();
const auth = AuthFactory.from().apiKey(apiKey).build();

mocks.apiKey.getById.mockResolvedValue(void 0);

Expand All @@ -230,8 +237,8 @@ describe(ApiKeyService.name, () => {
});

it('should get a key by id', async () => {
const auth = factory.auth();
const apiKey = factory.apiKey({ userId: auth.user.id });
const auth = AuthFactory.create();
const apiKey = ApiKeyFactory.create({ userId: auth.user.id });

mocks.apiKey.getById.mockResolvedValue(apiKey);

Expand All @@ -243,7 +250,7 @@ describe(ApiKeyService.name, () => {

describe('getById', () => {
it('should throw an error if the key is not found', async () => {
const auth = factory.auth();
const auth = AuthFactory.create();
const id = newUuid();

mocks.apiKey.getById.mockResolvedValue(void 0);
Expand All @@ -254,8 +261,8 @@ describe(ApiKeyService.name, () => {
});

it('should get a key by id', async () => {
const auth = factory.auth();
const apiKey = factory.apiKey({ userId: auth.user.id });
const auth = AuthFactory.create();
const apiKey = ApiKeyFactory.create({ userId: auth.user.id });

mocks.apiKey.getById.mockResolvedValue(apiKey);

Expand All @@ -267,8 +274,8 @@ describe(ApiKeyService.name, () => {

describe('getAll', () => {
it('should return all the keys for a user', async () => {
const auth = factory.auth();
const apiKey = factory.apiKey({ userId: auth.user.id });
const auth = AuthFactory.create();
const apiKey = ApiKeyFactory.create({ userId: auth.user.id });

mocks.apiKey.getByUserId.mockResolvedValue([apiKey]);

Expand Down
9 changes: 5 additions & 4 deletions server/src/services/asset.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { AssetStats } from 'src/repositories/asset.repository';
import { AssetService } from 'src/services/asset.service';
import { AssetFactory } from 'test/factories/asset.factory';
import { AuthFactory } from 'test/factories/auth.factory';
import { PartnerFactory } from 'test/factories/partner.factory';
import { authStub } from 'test/fixtures/auth.stub';
import { getForAsset, getForAssetDeletion, getForPartner } from 'test/mappers';
import { factory, newUuid } from 'test/small.factory';
Expand Down Expand Up @@ -80,8 +81,8 @@ describe(AssetService.name, () => {
});

it('should not include partner assets if not in timeline', async () => {
const partner = factory.partner({ inTimeline: false });
const auth = factory.auth({ user: { id: partner.sharedWithId } });
const partner = PartnerFactory.create({ inTimeline: false });
const auth = AuthFactory.create({ id: partner.sharedWithId });

mocks.asset.getRandom.mockResolvedValue([getForAsset(AssetFactory.create())]);
mocks.partner.getAll.mockResolvedValue([getForPartner(partner)]);
Expand All @@ -92,8 +93,8 @@ describe(AssetService.name, () => {
});

it('should include partner assets if in timeline', async () => {
const partner = factory.partner({ inTimeline: true });
const auth = factory.auth({ user: { id: partner.sharedWithId } });
const partner = PartnerFactory.create({ inTimeline: true });
const auth = AuthFactory.create({ id: partner.sharedWithId });

mocks.asset.getRandom.mockResolvedValue([getForAsset(AssetFactory.create())]);
mocks.partner.getAll.mockResolvedValue([getForPartner(partner)]);
Expand Down
Loading
Loading