diff --git a/e2e/portalicious/pages/PaymentsPage.ts b/e2e/portalicious/pages/PaymentsPage.ts index 25e0a03efe..d8ca3ffdd9 100644 --- a/e2e/portalicious/pages/PaymentsPage.ts +++ b/e2e/portalicious/pages/PaymentsPage.ts @@ -182,6 +182,32 @@ class PaymentsPage extends BasePage { await this.exportDropdown.click(); await this.page.getByRole('menuitem', { name: option }).click(); } + + async validateGraphStatus({ + pending, + successful, + failed, + }: { + pending: number; + successful: number; + failed: number; + }) { + await this.page.waitForTimeout(1000); // Wait for the graph to be updated after the loader is hidden + const graph = await this.page.locator('canvas').getAttribute('aria-label'); + + if (graph) { + const graphText = graph + .replace('Payment status chart.', '') + .replace(/\s+/g, ' ') + .trim(); + + expect(graphText).toContain( + `Pending: ${pending}, Successful: ${successful}, Failed: ${failed}`, + ); + } else { + throw new Error('Graph attribute is null'); + } + } } export default PaymentsPage; diff --git a/e2e/portalicious/tests/DoPayment/DoSuccessfulPayment.spec.ts b/e2e/portalicious/tests/DoPayment/DoSuccessfulPayment.spec.ts index f6b833605e..fe0e119b40 100644 --- a/e2e/portalicious/tests/DoPayment/DoSuccessfulPayment.spec.ts +++ b/e2e/portalicious/tests/DoPayment/DoSuccessfulPayment.spec.ts @@ -66,9 +66,7 @@ test('[31970] Do successful payment', async ({ page }) => { date: lastPaymentDate, paymentAmount: defaultMaxTransferValue, registrationsNumber: numberOfPas, - successfulTransfers: - defaultMaxTransferValue - - registrationsOCW[4].paymentAmountMultiplier * defaultTransferValue, + successfulTransfers: defaultMaxTransferValue, failedTransfers: 0, }); // DO NOT MAKE IT A RULE!!! diff --git a/e2e/portalicious/tests/ViewPayment/GraphDisplaysAllCorrectPaymentStatuses.spec.ts b/e2e/portalicious/tests/ViewPayment/GraphDisplaysAllCorrectPaymentStatuses.spec.ts new file mode 100644 index 0000000000..eb96219fd9 --- /dev/null +++ b/e2e/portalicious/tests/ViewPayment/GraphDisplaysAllCorrectPaymentStatuses.spec.ts @@ -0,0 +1,71 @@ +import { test } from '@playwright/test'; +import { format } from 'date-fns'; + +import { SeedScript } from '@121-service/src/scripts/enum/seed-script.enum'; +import NLRCProgram from '@121-service/src/seed-data/program/program-nlrc-ocw.json'; +import { seedIncludedRegistrations } from '@121-service/test/helpers/registration.helper'; +import { + getAccessToken, + resetDB, + resetDuplicateRegistrations, +} from '@121-service/test/helpers/utility.helper'; +import { + programIdOCW, + registrationOCW1, + registrationOCW6Fail, +} from '@121-service/test/registrations/pagination/pagination-data'; + +import LoginPage from '@121-e2e/portalicious/pages/LoginPage'; +import PaymentsPage from '@121-e2e/portalicious/pages/PaymentsPage'; + +test.beforeEach(async ({ page }) => { + await resetDB(SeedScript.nlrcMultiple); + const accessToken = await getAccessToken(); + await seedIncludedRegistrations( + [registrationOCW1, registrationOCW6Fail], + programIdOCW, + accessToken, + ); + await resetDuplicateRegistrations(4); + + // Login + const loginPage = new LoginPage(page); + await page.goto('/'); + await loginPage.login( + process.env.USERCONFIG_121_SERVICE_EMAIL_ADMIN, + process.env.USERCONFIG_121_SERVICE_PASSWORD_ADMIN, + ); +}); + +test('[32297] Graph should reflect transfer statuses', async ({ page }) => { + const paymentsPage = new PaymentsPage(page); + const projectTitle = NLRCProgram.titlePortal.en; + const lastPaymentDate = `${format(new Date(), 'dd/MM/yyyy')}`; + + await test.step('Navigate to Program payments', async () => { + await paymentsPage.selectProgram(projectTitle); + + await paymentsPage.navigateToProgramPage('Payments'); + }); + + await test.step('Do payment', async () => { + await paymentsPage.createPayment(); + await paymentsPage.startPayment(); + // Assert redirection to payment overview page + await page.waitForURL((url) => + url.pathname.startsWith(`/en-GB/project/${programIdOCW}/payments/1`), + ); + // Assert payment overview page by payment date/ title + await paymentsPage.validatePaymentsDetailsPageByDate(lastPaymentDate); + }); + + await test.step('Validate payemnt in progress in Payment overview', async () => { + await paymentsPage.validateToastMessage('Payment created.'); + await paymentsPage.waitForPaymentToComplete(); + await paymentsPage.validateGraphStatus({ + pending: 0, + successful: 16, + failed: 16, + }); + }); +}); diff --git a/interfaces/Portalicious/src/app/pages/project-payment/project-payment.page.ts b/interfaces/Portalicious/src/app/pages/project-payment/project-payment.page.ts index f00ec90cb6..b295ff8146 100644 --- a/interfaces/Portalicious/src/app/pages/project-payment/project-payment.page.ts +++ b/interfaces/Portalicious/src/app/pages/project-payment/project-payment.page.ts @@ -33,6 +33,7 @@ import { import { MetricApiService } from '~/domains/metric/metric.api.service'; import { PaymentMetricDetails } from '~/domains/metric/metric.model'; import { PaymentApiService } from '~/domains/payment/payment.api.service'; +import { PaymentAggregate } from '~/domains/payment/payment.model'; import { ProjectApiService } from '~/domains/project/project.api.service'; import { projectHasFspWithExportFileIntegration } from '~/domains/project/project.helper'; import { @@ -107,8 +108,16 @@ export class ProjectPaymentPageComponent { ); payment = injectQuery(() => ({ ...this.paymentApiService.getPayment(this.projectId, this.paymentId)(), - // Refetch the data every second if a payment is in progress - refetchInterval: this.paymentStatus.data()?.inProgress ? 1000 : undefined, + // Refetch the data every second if a payment count !== transactions count + refetchInterval: this.refetchPayment() ? 1000 : undefined, + success: (data: PaymentAggregate) => { + if ( + data.success.count + data.failed.count + data.waiting.count === + this.transactions.data()?.length + ) { + this.refetchPayment.set(false); + } + }, })); payments = injectQuery(this.paymentApiService.getPayments(this.projectId)); transactions = injectQuery( @@ -118,6 +127,8 @@ export class ProjectPaymentPageComponent { }), ); + refetchPayment = signal(true); + allPaymentsLink = computed(() => [ '/', AppRoutes.project, diff --git a/services/121-service/test/registrations/pagination/pagination-data.ts b/services/121-service/test/registrations/pagination/pagination-data.ts index 1059e33cda..2d5be158c9 100644 --- a/services/121-service/test/registrations/pagination/pagination-data.ts +++ b/services/121-service/test/registrations/pagination/pagination-data.ts @@ -97,6 +97,22 @@ export const registrationOCW5 = { whatsappPhoneNumber: '14155235556', }; +export const registrationOCW6Fail = { + referenceId: '54e62864557597e0d', + preferredLanguage: LanguageEnum.nl, + paymentAmountMultiplier: 3, + fullName: 'Test mock-fail-create-customer', + phoneNumber: '14155235555', + programFinancialServiceProviderConfigurationName: + FinancialServiceProviders.intersolveVisa, + whatsappPhoneNumber: '14155235555', + addressStreet: 'AnotherStreet', + addressHouseNumber: '4', + addressHouseNumberAddition: 'C', + addressPostalCode: '4567DE', + addressCity: 'AnotherCity', +}; + export const registrationsOCW = [ registrationOCW1, registrationOCW2,