From 6632272ef922f7af42dfcc6589c09d322a1d408d Mon Sep 17 00:00:00 2001 From: ali Date: Tue, 26 Nov 2024 16:50:24 +0330 Subject: [PATCH 1/7] Add tests for userCaps resolver --- src/resolvers/qAccResolver.test.ts | 163 +++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/src/resolvers/qAccResolver.test.ts b/src/resolvers/qAccResolver.test.ts index 9f5b02956..8cf118097 100644 --- a/src/resolvers/qAccResolver.test.ts +++ b/src/resolvers/qAccResolver.test.ts @@ -24,9 +24,11 @@ import { import { projectUserDonationCap, projectUserTotalDonationAmounts, + userCaps, } from '../../test/graphqlQueries'; import { ProjectRoundRecord } from '../entities/projectRoundRecord'; import { EarlyAccessRound } from '../entities/earlyAccessRound'; +import { GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE } from '../constants/gitcoin'; describe( 'projectUserTotalDonationAmount() test cases', @@ -38,6 +40,8 @@ describe( projectUserDonationCapTestCases, ); +describe('userCaps() test cases', userCapsTestCases); + function projectUserTotalDonationAmountTestCases() { it('should return total donation amount of a user for a project', async () => { it('should return total donation amount of a user for a project', async () => { @@ -236,3 +240,162 @@ function projectUserDonationCapTestCases() { ); }); } + +function userCapsTestCases() { + let project; + let user; + let accessToken; + let qfRound1: QfRound; + beforeEach(async () => { + project = await saveProjectDirectlyToDb(createProjectData()); + + user = await saveUserDirectlyToDb(generateRandomEtheriumAddress()); + accessToken = await generateTestAccessToken(user.id); + + qfRound1 = await QfRound.create({ + roundNumber: 1, + isActive: true, + name: new Date().toString() + ' - 1', + allocatedFund: 100, + minimumPassportScore: 12, + slug: new Date().getTime().toString() + ' - 1', + beginDate: new Date('2001-01-14'), + endDate: new Date('2001-01-16'), + roundUSDCapPerProject: 10000, + roundUSDCapPerUserPerProject: 2500, + tokenPrice: 0.5, + }).save(); + sinon.useFakeTimers({ + now: qfRound1.beginDate.getTime(), + }); + }); + afterEach(async () => { + // Clean up the database after each test + await ProjectRoundRecord.delete({}); + await Donation.delete({ projectId: project.id }); + await QfRound.delete(qfRound1.id); + + sinon.restore(); + }); + it('should return correct caps for a user with GitcoinPassport', async () => { + // Save donations + const donationAmount = 100; + await saveDonationDirectlyToDb( + { + ...createDonationData(), + amount: donationAmount, + status: DONATION_STATUS.VERIFIED, + qfRoundId: qfRound1.id, + }, + user.id, + project.id, + ); + + // Simulate valid GitcoinPassport score + sinon.stub(user, 'analysisScore').value(80); + sinon.stub(user, 'passportScoreUpdateTimestamp').value(new Date()); + sinon.stub(user, 'hasEnoughAnalysisScore').value(true); + + // Act: Call the resolver through a GraphQL query + const response: ExecutionResult<{ + userCaps: { + qAccCap: number; + gitcoinPassport?: { + unusedCap: number; + }; + zkId?: { + unusedCap: number; + }; + }; + }> = await axios.post( + graphqlUrl, + { + query: userCaps, + variables: { projectId: project.id }, + }, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }, + ); + + // Assert: Verify the response matches expected values + assert.equal(response.data?.userCaps?.qAccCap, 4900); // Adjust based on logic + assert.equal(response.data?.userCaps?.gitcoinPassport?.unusedCap, 1200); + assert.isUndefined(response.data?.userCaps?.zkId); + }); + + it('should return correct caps for a user with ZkId', async () => { + // Save donations + const donationAmount = 500; + await saveDonationDirectlyToDb( + { + ...createDonationData(), + amount: donationAmount, + status: DONATION_STATUS.VERIFIED, + }, + user.id, + project.id, + ); + + sinon.stub(user, 'privadoVerified').value(true); + + // Act: Call the resolver through a GraphQL query + const response: ExecutionResult<{ + userCaps: { + qAccCap: number; + gitcoinPassport?: { + unusedCap: number; + }; + zkId?: { + unusedCap: number; + }; + }; + }> = await axios.post( + graphqlUrl, + { + query: userCaps, + variables: { projectId: project.id }, + }, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }, + ); + + // Assert: Verify the response matches expected values + assert.equal(response.data?.userCaps?.qAccCap, 4500); // Adjust based on logic + assert.equal(response.data?.userCaps?.zkId?.unusedCap, 900); + assert.isUndefined(response.data?.userCaps?.gitcoinPassport); + }); + + it('should throw an error if the user does not meet the minimum analysis score', async () => { + // Simulate invalid GitcoinPassport score + sinon.stub(user, 'analysisScore').value(40); // Below threshold + sinon.stub(user, 'hasEnoughAnalysisScore').value(false); + + // Act: Call the resolver through a GraphQL query and expect an error + try { + await axios.post( + graphqlUrl, + { + query: userCaps, + variables: { projectId: project.id }, + }, + { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }, + ); + } catch (error: any) { + // Assert: Verify the error message + assert.equal( + error.response.data.errors[0].message, + `analysis score is less than ${GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE}`, + ); + } + }); +} From 31ad1c372bed52636339d72b32f9da6b207aa74a Mon Sep 17 00:00:00 2001 From: ali Date: Tue, 26 Nov 2024 16:54:36 +0330 Subject: [PATCH 2/7] fix input of test --- src/resolvers/qAccResolver.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/resolvers/qAccResolver.test.ts b/src/resolvers/qAccResolver.test.ts index 8cf118097..195d8e469 100644 --- a/src/resolvers/qAccResolver.test.ts +++ b/src/resolvers/qAccResolver.test.ts @@ -334,6 +334,7 @@ function userCapsTestCases() { ...createDonationData(), amount: donationAmount, status: DONATION_STATUS.VERIFIED, + qfRoundId: qfRound1.id, }, user.id, project.id, From 3ebd200e3d9b9a3109b5215a3b8be5638842cfdc Mon Sep 17 00:00:00 2001 From: ali Date: Tue, 26 Nov 2024 17:26:21 +0330 Subject: [PATCH 3/7] change field name based on changes --- src/resolvers/qAccResolver.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resolvers/qAccResolver.test.ts b/src/resolvers/qAccResolver.test.ts index 195d8e469..f9b565e87 100644 --- a/src/resolvers/qAccResolver.test.ts +++ b/src/resolvers/qAccResolver.test.ts @@ -294,7 +294,7 @@ function userCapsTestCases() { // Simulate valid GitcoinPassport score sinon.stub(user, 'analysisScore').value(80); sinon.stub(user, 'passportScoreUpdateTimestamp').value(new Date()); - sinon.stub(user, 'hasEnoughAnalysisScore').value(true); + sinon.stub(user, 'hasEnoughGitcoinAnalysisScore').value(true); // Act: Call the resolver through a GraphQL query const response: ExecutionResult<{ @@ -375,7 +375,7 @@ function userCapsTestCases() { it('should throw an error if the user does not meet the minimum analysis score', async () => { // Simulate invalid GitcoinPassport score sinon.stub(user, 'analysisScore').value(40); // Below threshold - sinon.stub(user, 'hasEnoughAnalysisScore').value(false); + sinon.stub(user, 'hasEnoughGitcoinAnalysisScore').value(false); // Act: Call the resolver through a GraphQL query and expect an error try { From 7f9628afbdf9f64d55ff36b3d8135c6cc622a834 Mon Sep 17 00:00:00 2001 From: ali Date: Tue, 26 Nov 2024 17:43:48 +0330 Subject: [PATCH 4/7] make variables dynamic --- src/resolvers/qAccResolver.test.ts | 36 +++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/resolvers/qAccResolver.test.ts b/src/resolvers/qAccResolver.test.ts index f9b565e87..485614bf0 100644 --- a/src/resolvers/qAccResolver.test.ts +++ b/src/resolvers/qAccResolver.test.ts @@ -28,7 +28,10 @@ import { } from '../../test/graphqlQueries'; import { ProjectRoundRecord } from '../entities/projectRoundRecord'; import { EarlyAccessRound } from '../entities/earlyAccessRound'; -import { GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE } from '../constants/gitcoin'; +import { + GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE, + MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_IN_USD, +} from '../constants/gitcoin'; describe( 'projectUserTotalDonationAmount() test cases', @@ -296,7 +299,6 @@ function userCapsTestCases() { sinon.stub(user, 'passportScoreUpdateTimestamp').value(new Date()); sinon.stub(user, 'hasEnoughGitcoinAnalysisScore').value(true); - // Act: Call the resolver through a GraphQL query const response: ExecutionResult<{ userCaps: { qAccCap: number; @@ -320,9 +322,18 @@ function userCapsTestCases() { }, ); - // Assert: Verify the response matches expected values - assert.equal(response.data?.userCaps?.qAccCap, 4900); // Adjust based on logic - assert.equal(response.data?.userCaps?.gitcoinPassport?.unusedCap, 1200); + assert.equal( + response.data?.userCaps?.qAccCap, + Number(qfRound1.roundUSDCapPerUserPerProject) / + Number(qfRound1.tokenPrice) - + donationAmount, + ); + assert.equal( + response.data?.userCaps?.gitcoinPassport?.unusedCap, + MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_IN_USD / + Number(qfRound1.tokenPrice) - + donationAmount, + ); assert.isUndefined(response.data?.userCaps?.zkId); }); @@ -342,7 +353,6 @@ function userCapsTestCases() { sinon.stub(user, 'privadoVerified').value(true); - // Act: Call the resolver through a GraphQL query const response: ExecutionResult<{ userCaps: { qAccCap: number; @@ -367,8 +377,18 @@ function userCapsTestCases() { ); // Assert: Verify the response matches expected values - assert.equal(response.data?.userCaps?.qAccCap, 4500); // Adjust based on logic - assert.equal(response.data?.userCaps?.zkId?.unusedCap, 900); + assert.equal( + response.data?.userCaps?.qAccCap, + Number(qfRound1.roundUSDCapPerUserPerProject) / + Number(qfRound1.tokenPrice) - + donationAmount, + ); + assert.equal( + response.data?.userCaps?.zkId?.unusedCap, + Number(qfRound1.roundUSDCapPerUserPerProject) / + Number(qfRound1.tokenPrice) - + donationAmount, + ); assert.isUndefined(response.data?.userCaps?.gitcoinPassport); }); From 069635f1d66402b2538a67fd67b41e155217303c Mon Sep 17 00:00:00 2001 From: Amin Latifi Date: Tue, 26 Nov 2024 17:50:02 +0330 Subject: [PATCH 5/7] Renamed variable --- src/resolvers/qAccResolver.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resolvers/qAccResolver.test.ts b/src/resolvers/qAccResolver.test.ts index 485614bf0..382a764e0 100644 --- a/src/resolvers/qAccResolver.test.ts +++ b/src/resolvers/qAccResolver.test.ts @@ -30,7 +30,7 @@ import { ProjectRoundRecord } from '../entities/projectRoundRecord'; import { EarlyAccessRound } from '../entities/earlyAccessRound'; import { GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE, - MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_IN_USD, + MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD, } from '../constants/gitcoin'; describe( @@ -330,7 +330,7 @@ function userCapsTestCases() { ); assert.equal( response.data?.userCaps?.gitcoinPassport?.unusedCap, - MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_IN_USD / + MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD / Number(qfRound1.tokenPrice) - donationAmount, ); From 4ace67219cc437f3d138fcd12cc031202b4f1b30 Mon Sep 17 00:00:00 2001 From: ali Date: Tue, 26 Nov 2024 18:00:21 +0330 Subject: [PATCH 6/7] fix variable names --- src/resolvers/qAccResolver.test.ts | 4 ++-- test/graphqlQueries.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/resolvers/qAccResolver.test.ts b/src/resolvers/qAccResolver.test.ts index 485614bf0..382a764e0 100644 --- a/src/resolvers/qAccResolver.test.ts +++ b/src/resolvers/qAccResolver.test.ts @@ -30,7 +30,7 @@ import { ProjectRoundRecord } from '../entities/projectRoundRecord'; import { EarlyAccessRound } from '../entities/earlyAccessRound'; import { GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE, - MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_IN_USD, + MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD, } from '../constants/gitcoin'; describe( @@ -330,7 +330,7 @@ function userCapsTestCases() { ); assert.equal( response.data?.userCaps?.gitcoinPassport?.unusedCap, - MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_IN_USD / + MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD / Number(qfRound1.tokenPrice) - donationAmount, ); diff --git a/test/graphqlQueries.ts b/test/graphqlQueries.ts index 6c4f78f5c..ef9a5f732 100644 --- a/test/graphqlQueries.ts +++ b/test/graphqlQueries.ts @@ -2165,10 +2165,10 @@ export const userCaps = ` userCaps(projectId: $projectId) { qAccCap gitcoinPassport { - unusedCapped + unusedCap } zkId { - unusedCapped + unusedCap } } } From d93517228e403aaf9253d68ee85e5aff01c20d6a Mon Sep 17 00:00:00 2001 From: ali Date: Wed, 27 Nov 2024 04:26:47 +0330 Subject: [PATCH 7/7] fix tests --- src/resolvers/qAccResolver.test.ts | 56 +++++++++++++++++------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/src/resolvers/qAccResolver.test.ts b/src/resolvers/qAccResolver.test.ts index 382a764e0..723552ae5 100644 --- a/src/resolvers/qAccResolver.test.ts +++ b/src/resolvers/qAccResolver.test.ts @@ -32,6 +32,7 @@ import { GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE, MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD, } from '../constants/gitcoin'; +import { PrivadoAdapter } from '../adapters/privado/privadoAdapter'; describe( 'projectUserTotalDonationAmount() test cases', @@ -269,7 +270,7 @@ function userCapsTestCases() { tokenPrice: 0.5, }).save(); sinon.useFakeTimers({ - now: qfRound1.beginDate.getTime(), + now: new Date('2001-01-15').getTime(), }); }); afterEach(async () => { @@ -295,18 +296,20 @@ function userCapsTestCases() { ); // Simulate valid GitcoinPassport score - sinon.stub(user, 'analysisScore').value(80); - sinon.stub(user, 'passportScoreUpdateTimestamp').value(new Date()); - sinon.stub(user, 'hasEnoughGitcoinAnalysisScore').value(true); + user.analysisScore = 80; + user.passportScoreUpdateTimestamp = new Date(); + await user.save(); const response: ExecutionResult<{ - userCaps: { - qAccCap: number; - gitcoinPassport?: { - unusedCap: number; - }; - zkId?: { - unusedCap: number; + data: { + userCaps: { + qAccCap: number; + gitcoinPassport?: { + unusedCap: number; + }; + zkId?: { + unusedCap: number; + }; }; }; }> = await axios.post( @@ -323,18 +326,18 @@ function userCapsTestCases() { ); assert.equal( - response.data?.userCaps?.qAccCap, + response.data?.data.userCaps?.qAccCap, Number(qfRound1.roundUSDCapPerUserPerProject) / Number(qfRound1.tokenPrice) - donationAmount, ); assert.equal( - response.data?.userCaps?.gitcoinPassport?.unusedCap, + response.data?.data.userCaps?.gitcoinPassport?.unusedCap, MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD / Number(qfRound1.tokenPrice) - donationAmount, ); - assert.isUndefined(response.data?.userCaps?.zkId); + assert.isNull(response.data?.data.userCaps?.zkId); }); it('should return correct caps for a user with ZkId', async () => { @@ -351,16 +354,19 @@ function userCapsTestCases() { project.id, ); - sinon.stub(user, 'privadoVerified').value(true); + user.privadoVerifiedRequestIds = [PrivadoAdapter.privadoRequestId]; + await user.save(); const response: ExecutionResult<{ - userCaps: { - qAccCap: number; - gitcoinPassport?: { - unusedCap: number; - }; - zkId?: { - unusedCap: number; + data: { + userCaps: { + qAccCap: number; + gitcoinPassport?: { + unusedCap: number; + }; + zkId?: { + unusedCap: number; + }; }; }; }> = await axios.post( @@ -378,18 +384,18 @@ function userCapsTestCases() { // Assert: Verify the response matches expected values assert.equal( - response.data?.userCaps?.qAccCap, + response.data?.data.userCaps?.qAccCap, Number(qfRound1.roundUSDCapPerUserPerProject) / Number(qfRound1.tokenPrice) - donationAmount, ); assert.equal( - response.data?.userCaps?.zkId?.unusedCap, + response.data?.data.userCaps?.zkId?.unusedCap, Number(qfRound1.roundUSDCapPerUserPerProject) / Number(qfRound1.tokenPrice) - donationAmount, ); - assert.isUndefined(response.data?.userCaps?.gitcoinPassport); + assert.isNull(response.data?.data.userCaps?.gitcoinPassport); }); it('should throw an error if the user does not meet the minimum analysis score', async () => {