add voteForsendCoins tests

This commit is contained in:
Claus-Peter Huebner 2023-09-05 16:27:40 +02:00
parent 0d27ea3a62
commit 27aa1ff4f0
6 changed files with 289 additions and 26 deletions

View File

@ -1,14 +1,12 @@
// ATTENTION: DO NOT PUT ANY SECRETS IN HERE (or the .env)
import { Decimal } from 'decimal.js-light'
import dotenv from 'dotenv'
dotenv.config()
/*
import Decimal from 'decimal.js-light'
Decimal.set({
precision: 25,
rounding: Decimal.ROUND_HALF_UP,
})
*/
const constants = {
DB_VERSION: '0071-add-pending_transactions-table',

View File

@ -9,8 +9,8 @@ export class SendCoinsArgs {
@Field(() => String)
userReceiverIdentifier: string
@Field(() => Date)
creationDate: Date
@Field(() => String)
creationDate: string
@Field(() => Decimal)
amount: Decimal

View File

@ -0,0 +1,193 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
import { ApolloServerTestClient } from 'apollo-server-testing'
import { Community as DbCommunity } from '@entity/Community'
import CONFIG from '@/config'
import { User as DbUser } from '@entity/User'
import { fullName } from '@/graphql/util/fullName'
import { GraphQLError } from 'graphql'
import { cleanDB, testEnvironment } from '@test/helpers'
import { logger } from '@test/testSetup'
import { Connection } from '@dbTools/typeorm'
let mutate: ApolloServerTestClient['mutate'], con: Connection
// let query: ApolloServerTestClient['query']
let testEnv: {
mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query']
con: Connection
}
CONFIG.FEDERATION_API = '1_0'
beforeAll(async () => {
testEnv = await testEnvironment(logger)
mutate = testEnv.mutate
// query = testEnv.query
con = testEnv.con
// const server = await createServer()
// con = server.con
// query = createTestClient(server.apollo).query
// mutate = createTestClient(server.apollo).mutate
// DbCommunity.clear()
// DbUser.clear()
await cleanDB()
})
afterAll(async () => {
// await cleanDB()
await con.destroy()
})
describe('SendCoinsResolver', () => {
const voteForSendCoinsMutation = `
mutation (
$communityReceiverIdentifier: String!
$userReceiverIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$communitySenderIdentifier: String!
$userSenderIdentifier: String!
$userSenderName: String!
) {
voteForSendCoins(
communityReceiverIdentifier: $communityReceiverIdentifier
userReceiverIdentifier: $userReceiverIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
communitySenderIdentifier: $communitySenderIdentifier
userSenderIdentifier: $userSenderIdentifier
userSenderName: $userSenderName
)
}
`
describe('voteForSendCoins', () => {
let homeCom: DbCommunity
let foreignCom: DbCommunity
let sendUser: DbUser
let recipUser: DbUser
beforeEach(async () => {
await cleanDB()
homeCom = DbCommunity.create()
homeCom.foreign = false
homeCom.url = 'homeCom-url'
homeCom.name = 'homeCom-Name'
homeCom.description = 'homeCom-Description'
homeCom.creationDate = new Date()
homeCom.publicKey = Buffer.from('homeCom-publicKey')
homeCom.communityUuid = 'homeCom-UUID'
await DbCommunity.insert(homeCom)
foreignCom = DbCommunity.create()
foreignCom.foreign = true
foreignCom.url = 'foreignCom-url'
foreignCom.name = 'foreignCom-Name'
foreignCom.description = 'foreignCom-Description'
foreignCom.creationDate = new Date()
foreignCom.publicKey = Buffer.from('foreignCom-publicKey')
foreignCom.communityUuid = 'foreignCom-UUID'
await DbCommunity.insert(foreignCom)
sendUser = DbUser.create()
sendUser.alias = 'sendUser-alias'
sendUser.firstName = 'sendUser-FirstName'
sendUser.gradidoID = 'sendUser-GradidoID'
sendUser.lastName = 'sendUser-LastName'
await DbUser.insert(sendUser)
recipUser = DbUser.create()
recipUser.alias = 'recipUser-alias'
recipUser.firstName = 'recipUser-FirstName'
recipUser.gradidoID = 'recipUser-GradidoID'
recipUser.lastName = 'recipUser-LastName'
await DbUser.insert(recipUser)
})
describe('unknown recipient community', () => {
it('throws an error', async () => {
jest.clearAllMocks()
expect(
await mutate({
mutation: voteForSendCoinsMutation,
variables: {
communityReceiverIdentifier: 'invalid foreignCom',
userReceiverIdentifier: recipUser.gradidoID,
creationDate: new Date().toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: homeCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [new GraphQLError('voteForSendCoins with wrong communityReceiverIdentifier')],
}),
)
})
})
describe('unknown recipient user', () => {
it('throws an error', async () => {
jest.clearAllMocks()
expect(
await mutate({
mutation: voteForSendCoinsMutation,
variables: {
communityReceiverIdentifier: foreignCom.communityUuid,
userReceiverIdentifier: 'invalid recipient',
creationDate: new Date().toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: homeCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [
new GraphQLError(
'voteForSendCoins with unknown userReceiverIdentifier in the community=',
),
],
}),
)
})
})
describe('valid X-Com-TX voted', () => {
it('throws an error', async () => {
jest.clearAllMocks()
expect(
await mutate({
mutation: voteForSendCoinsMutation,
variables: {
communityReceiverIdentifier: foreignCom.communityUuid,
userReceiverIdentifier: recipUser.gradidoID,
creationDate: new Date().toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: homeCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
data: {
voteForSendCoins: 'recipUser-FirstName recipUser-LastName',
},
}),
)
})
})
})
})

View File

@ -15,7 +15,7 @@ import { fullName } from '@/graphql/util/fullName'
@Resolver()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export class SendCoinsResolver {
@Mutation(() => Boolean)
@Mutation(() => String)
async voteForSendCoins(
@Args()
{
@ -31,30 +31,31 @@ export class SendCoinsResolver {
): Promise<string | null> {
logger.debug(`voteForSendCoins() via apiVersion=1_0 ...`)
let result: string | null = null
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: communityReceiverIdentifier,
})
if (!homeCom) {
throw new LogError(
`voteForSendCoins with wrong communityReceiverIdentifier`,
communityReceiverIdentifier,
)
}
// second check if receiver user exists in this community
const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier })
if (!receiverUser) {
throw new LogError(
`voteForSendCoins with unknown userReceiverIdentifier in the community=`,
homeCom.name,
)
}
try {
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: communityReceiverIdentifier,
})
if (!homeCom) {
throw new LogError(
`voteForSendCoins with wrong communityReceiverIdentifier`,
communityReceiverIdentifier,
)
}
// second check if receiver user exists in this community
const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier })
if (!receiverUser) {
throw new LogError(
`voteForSendCoins with unknown userReceiverIdentifier in the community=`,
homeCom.name,
)
}
const receiveBalance = await calculateRecepientBalance(receiverUser.id, amount, creationDate)
const txDate = new Date(creationDate)
const receiveBalance = await calculateRecepientBalance(receiverUser.id, amount, txDate)
const pendingTx = DbPendingTransaction.create()
pendingTx.amount = amount
pendingTx.balance = receiveBalance ? receiveBalance.balance : new Decimal(0)
pendingTx.balanceDate = creationDate
pendingTx.balanceDate = txDate
pendingTx.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0)
pendingTx.decayStart = receiveBalance ? receiveBalance.decay.start : null
pendingTx.linkedUserCommunityUuid = communitySenderIdentifier
@ -64,6 +65,7 @@ export class SendCoinsResolver {
pendingTx.previous = receiveBalance ? receiveBalance.lastTransactionId : null
pendingTx.state = PendingTransactionState.NEW
pendingTx.typeId = TransactionTypeId.RECEIVE
pendingTx.userId = receiverUser.id
pendingTx.userCommunityUuid = communityReceiverIdentifier
pendingTx.userGradidoID = userReceiverIdentifier
pendingTx.userName = fullName(receiverUser.firstName, receiverUser.lastName)

View File

@ -0,0 +1,7 @@
import { contributionDateFormatter } from '@test/helpers'
describe('contributionDateFormatter', () => {
it('formats the date correctly', () => {
expect(contributionDateFormatter(new Date('Thu Feb 29 2024 13:12:11'))).toEqual('2/29/2024')
})
})

View File

@ -0,0 +1,63 @@
/* eslint-disable @typescript-eslint/unbound-method */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-return */
import { entities } from '@entity/index'
import { createTestClient } from 'apollo-server-testing'
import createServer from '@/server/createServer'
import { logger } from './testSetup'
export const headerPushMock = jest.fn((t) => {
context.token = t.value
})
const context = {
token: '',
setHeaders: {
push: headerPushMock,
forEach: jest.fn(),
},
clientTimezoneOffset: 0,
}
export const cleanDB = async () => {
// this only works as long we do not have foreign key constraints
for (const entity of entities) {
await resetEntity(entity)
}
}
export const testEnvironment = async (testLogger = logger) => {
const server = await createServer(testLogger) // context, testLogger, testI18n)
const con = server.con
const testClient = createTestClient(server.apollo)
const mutate = testClient.mutate
const query = testClient.query
return { mutate, query, con }
}
export const resetEntity = async (entity: any) => {
const items = await entity.find({ withDeleted: true })
if (items.length > 0) {
const ids = items.map((e: any) => e.id)
await entity.delete(ids)
}
}
export const resetToken = () => {
context.token = ''
}
// format date string as it comes from the frontend for the contribution date
export const contributionDateFormatter = (date: Date): string => {
return `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`
}
export const setClientTimezoneOffset = (offset: number): void => {
context.clientTimezoneOffset = offset
}