Skip to content

Commit

Permalink
[CROW-27] Add claim event listener (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
renacargnelutti authored Feb 27, 2023
1 parent 8af0e82 commit 1447ec9
Show file tree
Hide file tree
Showing 17 changed files with 531 additions and 40 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ services:
volumes:
- .:/usr/src/app
- ./node_modules:/usr/src/app/node_modules
restart: unless-stopped
restart: always
depends_on:
- crowdfunding_database

Expand Down
14 changes: 13 additions & 1 deletion src/features/campaigns/campaigns.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,15 @@ import {
CampaignPledge,
CampaignPledgeSchema,
} from './schemas/campaign-pledge.schema';
import {
CampaignClaim,
CampaignClaimSchema,
} from './schemas/campaign-claim.schema';
import { UsersRepository } from '../users/repositories/users/mongo/users.repository';
import { UsersModule } from '../users/users.module';
import { User, UserSchema } from '../users/schemas/user.schema';
import { CampaignClaimService } from './services/campaign-claim/campaign-claim.service';
import { CampaignClaimMongoRepository } from './repositories/mongo/campaign-claim/campaign-claim.repository';

@Module({
imports: [
Expand All @@ -40,6 +46,10 @@ import { User, UserSchema } from '../users/schemas/user.schema';
name: CampaignPledge.name,
schema: CampaignPledgeSchema,
},
{
name: CampaignClaim.name,
schema: CampaignClaimSchema,
},
{
name: User.name,
schema: UserSchema,
Expand All @@ -58,8 +68,10 @@ import { User, UserSchema } from '../users/schemas/user.schema';
CampaignLaunchMongoRepository,
CampaignPledgeService,
CampaignPledgeMongoRepository,
CampaignClaimMongoRepository,
UsersRepository,
CampaignClaimService,
],
exports: [CampaignLaunchService, CampaignPledgeService],
exports: [CampaignLaunchService, CampaignPledgeService, CampaignClaimService],
})
export class CampaignsModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* eslint-disable @typescript-eslint/no-explicit-any */

import { getModelToken } from '@nestjs/mongoose';
import { Test, TestingModule } from '@nestjs/testing';
import { Model, ObjectId } from 'mongoose';

import { CampaignClaim } from 'src/features/campaigns/schemas/campaign-claim.schema';
import { campaignClaimMock } from 'src/features/campaigns/tests/mocks';
import { CampaignClaimMongoRepository } from './campaign-claim.repository';

describe('Campaign Claim Mongo Repository', () => {
let campaignClaimRepository: CampaignClaimMongoRepository;
let campaignClaimModel: Model<CampaignClaim>;

const campaignId = '634f3292a486274ca2f3d47f' as unknown as ObjectId;
const userId = '634f3292a486274ca2f3d47a' as unknown as ObjectId;
const tokenId = '634f3292a486274ca2f3d47b' as unknown as ObjectId;
const amount = '1';

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
CampaignClaimMongoRepository,
{
provide: getModelToken(CampaignClaim.name),
useValue: {
find: jest.fn(),
findOne: jest.fn(),
sort: jest.fn(),
skip: jest.fn(),
limit: jest.fn(),
lean: jest.fn(),
create: jest.fn(),
save: jest.fn(),
},
},
],
}).compile();

campaignClaimRepository = module.get<CampaignClaimMongoRepository>(
CampaignClaimMongoRepository,
);
campaignClaimModel = module.get<Model<CampaignClaim>>(
getModelToken(CampaignClaim.name),
);
});

it('should be defined', () => {
expect(campaignClaimRepository).toBeDefined();
});

describe('create method', () => {
it('should call create method without errors', async () => {
jest
.spyOn(campaignClaimModel, 'create')
.mockReturnValue(campaignClaimMock as any);

const response = await campaignClaimRepository.create({
campaignId,
userId,
tokenId,
amount,
});

expect(response).toStrictEqual(campaignClaimMock);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model, ObjectId } from 'mongoose';

import {
CampaignClaim,
CampaignClaimDocument,
} from '../../../schemas/campaign-claim.schema';

@Injectable()
export class CampaignClaimMongoRepository {
constructor(
@InjectModel(CampaignClaim.name)
private campaignClaimModel: Model<CampaignClaimDocument>,
) {}

// TODO: possible to use an abstract class to define the interface?
async create({
campaignId,
userId,
tokenId,
amount,
}: {
userId: ObjectId;
campaignId: ObjectId;
tokenId: ObjectId;
amount: string;
}) {
return await this.campaignClaimModel.create({
campaign: campaignId,
user: userId,
token: tokenId,
amount,
date: new Date(),
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export class CampaignsMongoRepository {
updateCampaignDto: UpdateCampaignDto;
}) {
const existingCampaign = await this.campaignModel
.findOne({ _id: id })
.findOne({ onchainId: id })
.exec();
if (!existingCampaign) {
throw new NotFoundException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { User } from 'src/features/users/schemas/user.schema';
import { Campaign } from 'src/features/campaigns/schemas/campaign.schema';
import { Token } from 'src/features/tokens/schemas/token.schema';

export type ClaimDocument = Claim & Document;
export type CampaignClaimDocument = CampaignClaim & Document;

@Schema({ timestamps: { createdAt: 'created', updatedAt: 'updated' } })
export class Claim {
export class CampaignClaim {
@Prop({
index: true,
type: MongooseSchema.Types.ObjectId,
Expand All @@ -35,4 +35,4 @@ export class Claim {
date: Date;
}

export const ClaimSchema = SchemaFactory.createForClass(Claim);
export const CampaignClaimSchema = SchemaFactory.createForClass(CampaignClaim);
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/* eslint-disable @typescript-eslint/no-explicit-any */

import { Test, TestingModule } from '@nestjs/testing';

import {
campaignClaimArgumentMock,
campaignClaimMock,
campaignPledgeArgumentMock,
mongoClaimedCampaingStatus,
tokenMock,
userMock,
} from '../../tests/mocks';
import { campaignMock } from 'src/features/users/tests/mocks';
import { CampaignsService } from 'src/features/campaigns/services/campaigns.service';
import { TokensService } from 'src/features/tokens/services/tokens.service';
import { UsersService } from 'src/features/users/services/users.service';
import { CampaignStatusService } from 'src/features/campaign-statuses/services/campaign-statuses.service';
import { CampaignClaimService } from 'src/features/campaigns/services/campaign-claim/campaign-claim.service';
import { CampaignsMongoRepository } from 'src/features/campaigns/repositories/mongo/campaigns.repository';
import { CampaignClaimMongoRepository } from 'src/features/campaigns/repositories/mongo/campaign-claim/campaign-claim.repository';
import { UserCampaignsRepository } from 'src/features/users/repositories/user-campaigns/mongo/user-campaigns.repository';

describe('CampaignClaimService', () => {
let campaignClaimService: CampaignClaimService;
let campaignService: CampaignsService;
let usersService: UsersService;
let tokensService: TokensService;
let campaignStatusService: CampaignStatusService;
let campaignClaimMongoRepository: CampaignClaimMongoRepository;
let campaignMongoRepository: CampaignsMongoRepository;
let userCampaignsMongoRepository: UserCampaignsRepository;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
CampaignClaimService,
{
provide: CampaignsService,
useValue: {
findOne: jest.fn(),
},
},
{
provide: CampaignStatusService,
useValue: {
getStatusByCode: jest.fn(),
},
},
{
provide: UsersService,
useValue: {
findUserByAddress: jest.fn(),
},
},
{
provide: TokensService,
useValue: {
getByDefault: jest.fn(),
},
},
{
provide: CampaignClaimMongoRepository,
useValue: {
create: jest.fn(),
},
},
{
provide: CampaignsMongoRepository,
useValue: {
update: jest.fn(),
},
},
{
provide: UserCampaignsRepository,
useValue: {
updateUserCampaignByEvent: jest.fn(),
},
},
],
}).compile();

campaignClaimService =
module.get<CampaignClaimService>(CampaignClaimService);
campaignService = module.get<CampaignsService>(CampaignsService);
usersService = module.get<UsersService>(UsersService);
tokensService = module.get<TokensService>(TokensService);
campaignStatusService = module.get<CampaignStatusService>(
CampaignStatusService,
);
campaignClaimMongoRepository = module.get<CampaignClaimMongoRepository>(
CampaignClaimMongoRepository,
);
campaignMongoRepository = module.get<CampaignsMongoRepository>(
CampaignsMongoRepository,
);
userCampaignsMongoRepository = module.get<UserCampaignsRepository>(
UserCampaignsRepository,
);
});

it('should be defined', () => {
expect(campaignClaimService).toBeDefined();
});

describe('create method', () => {
it('should call create method and fails because arguments are not right', async () => {
await expect(() =>
campaignClaimService.create('WrongArgument'),
).rejects.toThrow();
});

it('should call create method and fails because there is no associated campaign', async () => {
jest.spyOn(campaignService, 'findOne').mockResolvedValue(null as any);
jest
.spyOn(usersService, 'findUserByAddress')
.mockResolvedValue(userMock as any);
jest
.spyOn(tokensService, 'getByDefault')
.mockResolvedValue(tokenMock as any);

await expect(() =>
campaignClaimService.create(campaignClaimArgumentMock),
).rejects.toThrow();

expect(campaignService.findOne).toBeCalledTimes(1);
expect(usersService.findUserByAddress).toBeCalledTimes(1);
expect(tokensService.getByDefault).toBeCalledTimes(1);
});

it('should call create method without errors', async () => {
jest
.spyOn(campaignService, 'findOne')
.mockResolvedValue({ campaign: campaignMock } as any);
jest
.spyOn(usersService, 'findUserByAddress')
.mockResolvedValue(userMock as any);
jest
.spyOn(tokensService, 'getByDefault')
.mockResolvedValue(tokenMock as any);
jest
.spyOn(campaignClaimMongoRepository, 'create')
.mockResolvedValue(campaignClaimMock as any);
jest
.spyOn(campaignStatusService, 'getStatusByCode')
.mockResolvedValue(mongoClaimedCampaingStatus as any);
jest.spyOn(campaignMongoRepository, 'update').mockResolvedValue(null);
jest
.spyOn(userCampaignsMongoRepository, 'updateUserCampaignByEvent')
.mockResolvedValue(null);

await expect(() =>
campaignClaimService.create(campaignPledgeArgumentMock),
).not.toThrow();

expect(campaignService.findOne).toBeCalledTimes(1);
expect(usersService.findUserByAddress).toBeCalledTimes(1);
expect(tokensService.getByDefault).toBeCalledTimes(1);
});
});
});
Loading

0 comments on commit 1447ec9

Please sign in to comment.