Skip to content

Commit

Permalink
fix expense seeding (#554)
Browse files Browse the repository at this point in the history
* added: env variable for CAMPAIGN_ADMIN_MAIL in deployment config

* ensure all campaigns have single vault and heavily-funded campaign has approved expenses

* fixed: typescript errors in expense tests
  • Loading branch information
quantum-grit authored Sep 29, 2023
1 parent deca0d3 commit afd94b6
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 139 deletions.
33 changes: 22 additions & 11 deletions apps/api/src/expenses/expenses.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Test, TestingModule } from '@nestjs/testing'
import { ExpensesController } from './expenses.controller'
import { ExpensesService } from './expenses.service'
import { MockPrismaService, prismaMock } from '../prisma/prisma-client.mock'
import { ExpenseStatus, ExpenseType, Currency } from '@prisma/client'
import { ExpenseStatus, ExpenseType, Currency, Person, Campaign } from '@prisma/client'
import { mockReset } from 'jest-mock-extended'
import { CreateExpenseDto } from './dto/create-expense.dto'
import { UpdateExpenseDto } from './dto/update-expense.dto'
import { S3Service } from '../s3/s3.service'
import { KeycloakTokenParsed } from '../auth/keycloak'

const mockData = [
{
Expand Down Expand Up @@ -69,16 +70,16 @@ describe('ExpensesController', () => {
const campaign = {}
const user = { sub: '00000000-0000-0000-0000-000000000013' }

prismaMock.person.findFirst.mockResolvedValue(person)
prismaMock.campaign.findFirst.mockResolvedValue(campaign)
prismaMock.person.findFirst.mockResolvedValue(person as Person)
prismaMock.campaign.findFirst.mockResolvedValue(campaign as Campaign)
prismaMock.expense.create.mockResolvedValue(expense)
prismaMock.vault.update.mockResolvedValue(vault)
prismaMock.vault.findFirst.mockResolvedValue(vault)
prismaMock.$transaction.mockResolvedValue([expense, vault])

const createDto: CreateExpenseDto = { ...expense }

const result = await controller.create(user, createDto, [])
const result = await controller.create(user as KeycloakTokenParsed, createDto)

expect(result).toEqual(expense)
expect(prismaMock.expense.create).toHaveBeenCalledWith({ data: createDto })
Expand Down Expand Up @@ -132,8 +133,8 @@ describe('ExpensesController', () => {

const campaign = {}

prismaMock.person.findFirst.mockResolvedValue(person)
prismaMock.campaign.findFirst.mockResolvedValue(campaign)
prismaMock.person.findFirst.mockResolvedValue(person as Person)
prismaMock.campaign.findFirst.mockResolvedValue(campaign as Campaign)
prismaMock.vault.findFirstOrThrow.mockResolvedValue(vault)
prismaMock.expense.findFirstOrThrow.mockResolvedValue(expense)
prismaMock.vault.update.mockResolvedValue(vault)
Expand All @@ -147,7 +148,7 @@ describe('ExpensesController', () => {
}

// act
const result = await controller.update(user, expense.id, updateDto)
const result = await controller.update(user as KeycloakTokenParsed, expense.id, updateDto)

// assert
expect(result).toEqual(expense)
Expand Down Expand Up @@ -193,7 +194,9 @@ describe('ExpensesController', () => {
vaultId: vault.id,
}

await expect(controller.update(user, expense.id, updateDto)).rejects.toThrow()
await expect(
controller.update(user as KeycloakTokenParsed, expense.id, updateDto),
).rejects.toThrow()
//expect an exception
expect(prismaMock.expense.update).not.toHaveBeenCalled()
})
Expand Down Expand Up @@ -233,15 +236,23 @@ describe('ExpensesController', () => {
}

// assert
await expect(controller.update(user, approvedExpense.id, updateDto)).rejects.toThrow()
await expect(controller.update(user, cancelledExpense.id, updateDto)).rejects.toThrow()
await expect(
controller.update(user as KeycloakTokenParsed, approvedExpense.id, updateDto),
).rejects.toThrow()
await expect(
controller.update(user as KeycloakTokenParsed, cancelledExpense.id, updateDto),
).rejects.toThrow()
expect(prismaMock.expense.update).not.toHaveBeenCalled()
expect(prismaMock.vault.update).not.toHaveBeenCalled()
})

it('should not update an expense, when its vault is being changed', async () => {
const expense = mockData[0]

const user: KeycloakTokenParsed = {
sub: '00000000-0000-0000-0000-000000000012',
} as KeycloakTokenParsed

const vault = {
id: '00000000-0000-0000-0000-000000000016',
name: 'vault1',
Expand All @@ -262,7 +273,7 @@ describe('ExpensesController', () => {
}

// assert
await expect(controller.update(expense.id, updateDto)).rejects.toThrow()
await expect(controller.update(user, expense.id, updateDto)).rejects.toThrow()
expect(prismaMock.expense.update).not.toHaveBeenCalled()
expect(prismaMock.vault.update).not.toHaveBeenCalled()
})
Expand Down
2 changes: 1 addition & 1 deletion db/seed/campaign/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const prisma = new PrismaClient()
const SEED_ACTIVE_CAMPAIGNS = 5
const SEED_RANDOM_CAMPAIGNS = 5
const SEED_COMPLETED_CAMPAIGNS = 3
const SEED_HEAVILY_FUNDED_CAMPAIGNS = 3
const SEED_HEAVILY_FUNDED_CAMPAIGNS = 1

export async function campaignSeed() {
console.log('Campaigns seed')
Expand Down
19 changes: 14 additions & 5 deletions db/seed/donation/seed.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { PrismaClient, PaymentProvider, DonationStatus, DonationType, Person } from '@prisma/client'
import {
PrismaClient,
PaymentProvider,
DonationStatus,
DonationType,
Person,
CampaignState,
} from '@prisma/client'

import { donationFactory } from './factory'

Expand Down Expand Up @@ -78,8 +85,8 @@ async function seedRandomDonations({ person }: SeedData) {
async function seedDonationsForCompletedCampaign({ person }: SeedData) {
const completedCampaignVault = await prisma.vault.findFirst({
where: {
name: {
contains: 'completed',
campaign: {
state: CampaignState.complete,
},
},
})
Expand Down Expand Up @@ -119,8 +126,10 @@ async function seedDonationsForCompletedCampaign({ person }: SeedData) {
async function seedDonationsForHeavilyFundedCampaign({ person }: SeedData) {
const heavilyFundedCampaignVault = await prisma.vault.findFirst({
where: {
name: {
contains: 'heavily-funded',
campaign: {
title: {
contains: 'heavily-funded',
},
},
},
})
Expand Down
4 changes: 2 additions & 2 deletions db/seed/expense/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export const expenseFactory = Factory.define<Expense>(({ associations }) => ({
vaultId: associations.vaultId || faker.datatype.uuid(),
documentId: associations.documentId || null,
approvedById: associations.approvedById || null,
amount: faker.datatype.number(),
amount: faker.datatype.number({ min: 1, max: 20000 }),
currency: faker.helpers.arrayElement(Object.values(Currency)),
status: faker.helpers.arrayElement(Object.values(ExpenseStatus)),
status: ExpenseStatus.pending,
deleted: faker.datatype.boolean(),
spentAt: faker.date.past(),
}))
19 changes: 17 additions & 2 deletions db/seed/expense/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,33 @@ const prisma = new PrismaClient()
export async function expenseSeed() {
console.log('Expense seed')

const vault = await prisma.vault.findFirst()
const vault = await prisma.vault.findFirst({
where: {
campaign: {
title: {
contains: 'heavily-funded',
},
},
},
})

if (!vault) {
throw new Error('There are no vaults created yet!')
}

const coordinator = await prisma.coordinator.findFirst()

if (!coordinator) {
throw new Error('There are no coordinators created yet!')
}

const expensesData: Expense[] = expenseFactory.buildList(
20,
11,
{},
{
associations: {
vaultId: vault.id,
approvedById: coordinator.personId,
},
},
)
Expand Down
150 changes: 32 additions & 118 deletions db/seed/vault/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,123 +7,37 @@ const prisma = new PrismaClient()
export async function vaultSeed() {
console.log('Vault seed')

await seedVaultsForRandomCampaign()
await seedVaultForCompletedCampaign()
await seedVaultForHeavilyFundedCampaign()
}

async function seedVaultsForRandomCampaign() {
const campaign = await prisma.campaign
.findMany()
.then((campaigns) => faker.helpers.arrayElement(campaigns))

if (!campaign) {
throw new Error('There are no campaigns created yet!')
}

const randomCampaignVaultsData: Vault[] = vaultFactory.buildList(
20,
{
currency: Currency.BGN,
amount: 0, // Initializing with 0 and fill the correct amount after donations have been seeded
},
{
associations: {
campaignId: campaign.id,
},
},
)

const insertRandomCampaignVaults = await prisma.vault.createMany({
data: randomCampaignVaultsData,
skipDuplicates: true,
})

console.log({ insertRandomCampaignVaults })
}

async function seedVaultForCompletedCampaign() {
const completedCampaign = await prisma.campaign.findFirst({
where: {
state: CampaignState.complete,
},
})

if (!completedCampaign) {
throw new Error('There is no completed campaign created')
}

const completedCampaignVault = await prisma.vault.findFirst({
where: {
campaignId: completedCampaign.id,
},
})

if (completedCampaignVault) {
console.log('{ Completed campaign vault already exists }')
return
await seedVaultsForCampaigns()

async function seedVaultsForCampaigns() {
const campaigns = await prisma.campaign.findMany()

if (!campaigns) {
throw new Error('There are no campaigns created yet!')
}

let vaults: Vault[] = []
campaigns.map(async (campaign) => {
vaults.push(
vaultFactory.build(
{
currency: Currency.BGN,
amount: 0, // Initializing with 0 and fill the correct amount after donations have been seeded
},
{
associations: {
campaignId: campaign.id,
},
},
),
)
})

const insertRandomCampaignVaults = await prisma.vault.createMany({
data: vaults,
skipDuplicates: true,
})

console.log({ insertRandomCampaignVaults })
}

const completedCampaignVaultData: Vault = vaultFactory.build(
{
name: faker.finance.accountName() + ' completed',
currency: Currency.BGN,
amount: 0, // Initializing with 0 and fill the correct amount after donations have been seeded
},
{
associations: {
campaignId: completedCampaign.id,
},
},
)

const insertCompletedCampaignVault = await prisma.vault.create({
data: completedCampaignVaultData,
})

console.log(`{ insertCompletedCampaignVault: ${!!insertCompletedCampaignVault} }`)
}

async function seedVaultForHeavilyFundedCampaign() {
const heavilyFundedCampaign = await prisma.campaign.findFirst({
where: {
title: {
contains: 'heavily-funded',
},
},
})

if (!heavilyFundedCampaign) {
throw new Error('There is no heavily funded campaign created')
}

const heavilyFundedCampaignVault = await prisma.vault.findFirst({
where: {
campaignId: heavilyFundedCampaign.id,
},
})

if (heavilyFundedCampaignVault) {
console.log('{ Heavily-funded campaign vault already exists }')
return
}

const heavilyFundedCampaignVaultData: Vault = vaultFactory.build(
{
name: faker.finance.accountName() + ' heavily-funded',
currency: Currency.BGN,
amount: 0, // Initializing with 0 and fill the correct amount after donations have been seeded
},
{
associations: {
campaignId: heavilyFundedCampaign.id,
},
},
)

const insertHeavilyFundedCampaignVault = await prisma.vault.create({
data: heavilyFundedCampaignVaultData,
})

console.log(`{ insertHeavilyFundedCampaignVault: ${!!insertHeavilyFundedCampaignVault} }`)
}

0 comments on commit afd94b6

Please sign in to comment.