From 7a758b220fd5ab2e5a98cdeb12c756d89728ca1a Mon Sep 17 00:00:00 2001 From: Niraj Date: Wed, 23 Apr 2025 10:36:33 +0545 Subject: [PATCH 1/5] test: add submit section field verification test --- .../lib/pages/budgetDiscussionSubmissionPage.ts | 11 ++++++----- .../proposalBudgetSubmission.loggedin.spec.ts | 13 +++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts index fef1c0fb7..91f3d0070 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts @@ -58,7 +58,7 @@ export default class BudgetDiscussionSubmissionPage { readonly agreeCheckbox = this.page.getByLabel( "I agree to the information in" ); //BUG missing test Ids - readonly submitCheckbox = this.page.getByLabel("I consent to the public"); //BUG missing test Ids + readonly submitCheckbox = this.page.getByTestId("submit-checkbox"); // input readonly linkTextInput = this.page.getByTestId("link-0-text-input"); @@ -417,7 +417,7 @@ export default class BudgetDiscussionSubmissionPage { async fillupForm( budgetProposal: BudgetProposalProps, - stage: BudgetProposalStageEnum = BudgetProposalStageEnum.AdministrationAndAuditing + stage: BudgetProposalStageEnum = BudgetProposalStageEnum.Review ) { await this.fillupProposalOwnershipForm(budgetProposal.proposalOwnership); @@ -450,9 +450,10 @@ export default class BudgetDiscussionSubmissionPage { ); } await this.continueBtn.click(); - - await this.submitCheckbox.click(); - await this.continueBtn.click(); + if (stage > BudgetProposalStageEnum.AdministrationAndAuditing) { + await this.submitCheckbox.click(); + await this.continueBtn.click(); + } } } diff --git a/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts index 6ef9ed4ab..52cfd5836 100644 --- a/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts +++ b/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts @@ -197,6 +197,19 @@ test.describe("Budget proposal 01 wallet", () => { ).toBeVisible(); await expect(budgetProposalSubmissionPage.continueBtn).toBeDisabled(); }); + + test("12D_7. Should verify all field of “Submit” section", async () => { + const proposalInformation = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm( + proposalInformation, + BudgetProposalStageEnum.AdministrationAndAuditing + ); + + await expect(budgetProposalSubmissionPage.submitCheckbox).toBeVisible(); + await expect(budgetProposalSubmissionPage.saveDraftBtn).toBeVisible(); + await expect(budgetProposalSubmissionPage.continueBtn).toBeDisabled(); + }); }); test("12G. Should validate and review submitted budget proposal", async () => { From b24283c01ea134e1e632d0056428f881ec9b085a Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 24 Apr 2025 08:39:37 +0545 Subject: [PATCH 2/5] refactor: improve formatWithThousandSeparator function to handle string inputs --- .../playwright/lib/helpers/adaFormat.ts | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/helpers/adaFormat.ts b/tests/govtool-frontend/playwright/lib/helpers/adaFormat.ts index 0943d84a1..fedb9e809 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/adaFormat.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/adaFormat.ts @@ -37,15 +37,26 @@ export const correctDRepDirectoryFormat = (ada: number | undefined) => { return "0"; }; -export const formatWithThousandSeparator = ( - amount: number | undefined, - isAda: boolean = true -) => { - const updatedAmount = !isAda ? Math.ceil(amount / LOVELACE) : amount; - if (updatedAmount) { - return updatedAmount.toLocaleString("en-us", { - maximumFractionDigits: 3, - }); +export function formatWithThousandSeparator( + value: number | string, + isAda = true +): string { + if (value === undefined || value === null) { + return "0"; } - return "0"; -}; + + let numericValue: number; + if (typeof value === "string") { + numericValue = parseInt(value.replace(/,/g, "")); + } else { + numericValue = value; + } + + if (isAda) { + numericValue = Math.ceil(numericValue / LOVELACE); + } + + return numericValue.toLocaleString("en-US", { + maximumFractionDigits: 3, + }); +} From 8b6784c449f3695293bb011b8f49ee6fb2f274a5 Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 24 Apr 2025 09:44:05 +0545 Subject: [PATCH 3/5] tests: add remaining proposal budget validation test --- .../playwright/lib/helpers/string.ts | 6 + .../pages/budgetDiscussionSubmissionPage.ts | 317 +++++++++++++++--- .../lib/pages/governanceActionsPage.ts | 2 +- .../govtool-frontend/playwright/lib/types.ts | 6 +- .../proposalBudgetSubmission.loggedin.spec.ts | 195 +++++++---- 5 files changed, 419 insertions(+), 107 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/helpers/string.ts b/tests/govtool-frontend/playwright/lib/helpers/string.ts index 745928196..30093b65c 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/string.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/string.ts @@ -25,3 +25,9 @@ export function toCamelCase(str: string) { ) .join(""); } + +export function generateParagraph(isValid: boolean, isEmpty: boolean): string { + if (isValid) return faker.lorem.paragraph(2); + const text = isEmpty ? "" : faker.lorem.paragraph(15001); + return text; +} diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts index 91f3d0070..249e79e7a 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts @@ -1,9 +1,9 @@ import environments from "@constants/environments"; import { faker } from "@faker-js/faker"; import { formatWithThousandSeparator } from "@helpers/adaFormat"; -import { extractProposalIdFromUrl } from "@helpers/string"; +import { extractProposalIdFromUrl, generateParagraph } from "@helpers/string"; import { invalid, valid } from "@mock/index"; -import { Page, expect } from "@playwright/test"; +import { Locator, Page, expect } from "@playwright/test"; import { AdministrationAndAuditingProps, BudgetCostingProps, @@ -265,7 +265,8 @@ export default class BudgetDiscussionSubmissionPage { } async fillupProposalOwnershipForm( - proposalOwnership: BudgetProposalOwnershipProps + proposalOwnership: BudgetProposalOwnershipProps, + isNaviagted = true ) { await this.companyTypeSelect.click(); await this.page @@ -293,13 +294,16 @@ export default class BudgetDiscussionSubmissionPage { ) .click(); } - await this.agreeCheckbox.click(); - await this.continueBtn.click(); + if (isNaviagted) { + await this.agreeCheckbox.click(); + await this.continueBtn.click(); + } } async fillupProblemStatementAndBenefitsForm( - problemStatementAndBenefits: BudgetProposalProblemStatementAndBenefitProps + problemStatementAndBenefits: BudgetProposalProblemStatementAndBenefitProps, + isNaviagated = true ) { await this.problemStatementInput.fill( problemStatementAndBenefits.problemStatement @@ -341,10 +345,14 @@ export default class BudgetDiscussionSubmissionPage { ) .click(); - await this.continueBtn.click(); + if (isNaviagated) { + await this.continueBtn.click(); + } } - async fillupProposalDetailsForm(proposalDetails: BudgetProposalDetailsProps) { + async fillupProposalDetailsFormWithoutContractingType( + proposalDetails: BudgetProposalDetailsProps + ) { await this.proposalNameInput.fill(proposalDetails.proposalName); await this.proposalDescriptionInput.fill( proposalDetails.proposalDescription @@ -360,7 +368,10 @@ export default class BudgetDiscussionSubmissionPage { proposalDetails.teamSizeAndDuration ); await this.previousExperienceInput.fill(proposalDetails.previousExperience); + } + async fillupProposalDetailsForm(proposalDetails: BudgetProposalDetailsProps) { + await this.fillupProposalDetailsFormWithoutContractingType(proposalDetails); await this.contractingTypeSelect.click(); await this.page .getByTestId(`${proposalDetails.contracting.toLowerCase()}-button`) @@ -368,22 +379,27 @@ export default class BudgetDiscussionSubmissionPage { if (proposalDetails.contracting === "Other") { await this.otherDescriptionInput.fill(proposalDetails.otherDescription); } + await this.continueBtn.click(); } - async fillupCostingForm(costing: BudgetCostingProps) { + async fillupCostingFormWithoutPreferredCurrency(costing: BudgetCostingProps) { await this.adaAmountInput.fill(costing.adaAmount.toString()); await this.usaToAdaCnversionRateInput.fill( costing.usdToAdaConversionRate.toString() ); + await this.costBreakdownInput.fill(costing.costBreakdown); + await this.preferredCurrencyInput.fill( + costing.AmountInPreferredCurrency.toString() + ); + } + + async fillupCostingForm(costing: BudgetCostingProps) { + await this.fillupCostingFormWithoutPreferredCurrency(costing); await this.preferredCurrencySelect.click(); await this.page .getByTestId(`${costing.preferredCurrency.toLowerCase()}-button`) .click(); - await this.preferredCurrencyInput.fill( - costing.AmountInPreferredCurrency.toString() - ); - await this.costBreakdownInput.fill(costing.costBreakdown); await this.continueBtn.click(); } @@ -403,17 +419,17 @@ export default class BudgetDiscussionSubmissionPage { await this.continueBtn.click(); } - async fillCostingSectionExceptAmountInputs() { - const costing = this.generateValidCosting(); - await this.preferredCurrencySelect.click(); - await this.page - .getByTestId(`${costing.preferredCurrency.toLowerCase()}-button`) - .click(); - await this.preferredCurrencyInput.fill( - costing.AmountInPreferredCurrency.toString() - ); - await this.costBreakdownInput.fill(costing.costBreakdown.toString()); - } + // async fillCostingSectionExceptAmountInputs() { + // const costing = this.generateValidCosting(); + // await this.preferredCurrencySelect.click(); + // await this.page + // .getByTestId(`${costing.preferredCurrency.toLowerCase()}-button`) + // .click(); + // await this.preferredCurrencyInput.fill( + // costing.AmountInPreferredCurrency.toString() + // ); + // await this.costBreakdownInput.fill(costing.costBreakdown.toString()); + // } async fillupForm( budgetProposal: BudgetProposalProps, @@ -538,6 +554,20 @@ export default class BudgetDiscussionSubmissionPage { ), }; } + generateInvalidProposalOwnerShip(): BudgetProposalOwnershipProps { + return { + groupName: invalid.paragraph(50), + groupType: invalid.paragraph(50), + groupKeyIdentity: invalid.paragraph(50), + companyName: invalid.paragraph(50), + companyDomainName: invalid.paragraph(50), + companyType: faker.helpers.arrayElement(Object.values(CompanyEnum)), + contactDetails: faker.lorem.paragraph(2), + countryOfIncorportation: faker.helpers.arrayElement( + Object.values(LocationEnum) + ), + }; + } generateValidBudgetProposalDetails(): BudgetProposalDetailsProps { return { @@ -567,6 +597,18 @@ export default class BudgetDiscussionSubmissionPage { }; } + generateInValidCosting(): BudgetCostingProps { + return { + adaAmount: faker.lorem.paragraph(2), + usdToAdaConversionRate: faker.lorem.paragraph(2), + preferredCurrency: faker.helpers.arrayElement( + Object.values(PreferredCurrencyEnum) + ), + AmountInPreferredCurrency: faker.lorem.paragraph(2), + costBreakdown: invalid.paragraph(150001), + }; + } + generateValidFurtherInformation(): Array { return [ { @@ -768,21 +810,200 @@ export default class BudgetDiscussionSubmissionPage { ); } - async validateCostingSection(isValid: boolean = true) { - const adaAmount = isValid - ? faker.number.int({ min: 100, max: 10000 }) - : faker.lorem.paragraph(2); - const usdToAdaCnversionRate = isValid - ? faker.number.int({ min: 1, max: 100 }) - : faker.lorem.paragraph(2); - const preferredCurrency = isValid - ? faker.number.int({ min: 100, max: 10000 }) - : faker.lorem.paragraph(2); - await this.adaAmountInput.fill(adaAmount.toString()); - await this.usaToAdaCnversionRateInput.fill( - usdToAdaCnversionRate.toString() + async assertInputTextEquality( + actualLocator: Locator, + expected: string, + isValid: boolean = true + ) { + const actual = await actualLocator.inputValue(); + + if (isValid) { + expect(actual, { + message: actual !== expected && `${actual} is not equal to ${expected}`, + }).toEqual(expected); + } else { + expect(actual, { + message: actual === expected && `${actual} is equal to ${expected}`, + }).not.toEqual(expected); + } + } + + async validateProposalOwnershipSection( + proposalOwnership: BudgetProposalOwnershipProps, + isValid: boolean = true + ) { + const companyTypeSelectContent = await this.companyTypeSelect.textContent(); + + if (isValid) { + if (proposalOwnership.companyType === "Company") { + const countryOfIncorporationBtnContent = + await this.countryOfIncorporationBtn.textContent(); + await this.assertInputTextEquality( + this.companyDomainNameInput, + proposalOwnership.companyDomainName + ); + await this.assertInputTextEquality( + this.companyNameInput, + proposalOwnership.companyName + ); + + expect(countryOfIncorporationBtnContent, { + message: + countryOfIncorporationBtnContent !== + proposalOwnership.countryOfIncorportation && + `${countryOfIncorporationBtnContent} is not equal to ${proposalOwnership.countryOfIncorportation}`, + }).toEqual(proposalOwnership.countryOfIncorportation); + } + if (proposalOwnership.companyType === "Group") { + await this.assertInputTextEquality( + this.groupNameInput, + proposalOwnership.groupName + ); + await this.assertInputTextEquality( + this.groupTypeInput, + proposalOwnership.groupType + ); + await this.assertInputTextEquality( + this.keyInformationOfGroupInput, + proposalOwnership.groupKeyIdentity + ); + } + + expect(companyTypeSelectContent, { + message: + companyTypeSelectContent !== proposalOwnership.companyType && + `${companyTypeSelectContent} is not equal to ${proposalOwnership.companyType}`, + }).toEqual(proposalOwnership.companyType); + + await this.assertInputTextEquality( + this.contactDetailsInput, + proposalOwnership.contactDetails + ); + + await expect(this.continueBtn).toBeEnabled(); + } else { + await expect(this.continueBtn).toBeDisabled(); + } + } + + async validateProblemStatementsAndProposalBenefitsSection( + isValid: boolean = true + ) { + const isFirst = Math.random() > 0.5; + + const problemStatement = generateParagraph(isValid, isFirst); + const proposalBenefit = generateParagraph(isValid, !isFirst); + const suplimentaryEndorsement = isValid + ? faker.lorem.paragraph(2) + : faker.lorem.paragraph(15001); + + await this.problemStatementInput.fill(problemStatement); + await this.suplimentaryEndorsementInput.fill(suplimentaryEndorsement); + await this.proposalBenefitInput.fill(proposalBenefit); + + if (problemStatement.length !== 0) { + await this.assertInputTextEquality( + this.problemStatementInput, + problemStatement, + isValid + ); + } + + await this.assertInputTextEquality( + this.suplimentaryEndorsementInput, + suplimentaryEndorsement, + isValid + ); + + if (proposalBenefit.length !== 0) { + await this.assertInputTextEquality( + this.proposalBenefitInput, + proposalBenefit, + isValid + ); + } + if (isValid) { + await expect(this.continueBtn).toBeEnabled(); + } else { + await expect(this.continueBtn).toBeDisabled(); + } + } + + async validateProposalDetailsSection(isValid: boolean = true) { + const isFirst = Math.random() > 0.5; + const isSecond = Math.random() > 0.5; + + const proposalName = isValid ? faker.lorem.paragraph(2) : ""; + const proposalDescription = generateParagraph(isValid, isFirst); + const proposalKeyDependencies = generateParagraph( + isValid, + isFirst && isSecond + ); + const proposalMaintainAndSupport = isValid ? faker.lorem.paragraph(2) : ""; + const milestones = generateParagraph(isValid, !isFirst); + const teamSizeAndDuration = generateParagraph( + isValid, + !isFirst && isSecond ); - await this.preferredCurrencyInput.fill(preferredCurrency.toString()); + const previousExperience = isValid ? faker.lorem.paragraph(2) : ""; + + const fieldValues = { + proposalName, + proposalDescription, + proposalKeyDependencies, + proposalMaintainAndSupport, + milestones, + teamSizeAndDuration, + previousExperience, + contracting: faker.helpers.arrayElement( + Object.values(ProposalContractingEnum) + ), + otherDescription: faker.lorem.paragraph(2), + }; + + await this.fillupProposalDetailsFormWithoutContractingType(fieldValues); + + if (proposalDescription.length !== 0) { + await this.assertInputTextEquality( + this.proposalDescriptionInput, + proposalDescription, + isValid + ); + } + if (proposalKeyDependencies.length !== 0) { + await this.assertInputTextEquality( + this.proposalKeyDependenciesInput, + proposalKeyDependencies, + isValid + ); + } + + if (milestones.length !== 0) { + await this.assertInputTextEquality( + this.milestonesInput, + milestones, + isValid + ); + } + if (teamSizeAndDuration.length !== 0) { + await this.assertInputTextEquality( + this.teamSizeAndDurationInput, + teamSizeAndDuration, + isValid + ); + } + if (isValid) { + await expect(this.continueBtn).toBeEnabled(); + } else { + await expect(this.continueBtn).toBeDisabled(); + } + } + + async validateCostingSection( + costingValue: BudgetCostingProps, + isValid: boolean = true + ) { + await this.fillupCostingFormWithoutPreferredCurrency(costingValue); const adaErrorElement = this.page.getByTestId(formErrors.adaAmount); const usdToAdaConversionRateErrorElement = this.page.getByTestId( formErrors.usdToAdaConversionError @@ -798,32 +1019,38 @@ export default class BudgetDiscussionSubmissionPage { if (isValid) { await expect(adaErrorElement, { - message: isAdaAmountErrorVisible && `${adaAmount} is an invalid amount`, + message: + isAdaAmountErrorVisible && + `${costingValue.adaAmount} is an invalid amount`, }).toBeHidden(); await expect(usdToAdaConversionRateErrorElement, { message: isUsdToAdaConversionRateErrorVisible && - `${usdToAdaCnversionRate} is an invalid amount`, + `${costingValue.usdToAdaConversionRate} is an invalid amount`, }).toBeHidden(); await expect(preferredCurrencyErrorElement, { message: isPreferredCurrencyErrorVisible && - `${preferredCurrency} is an invalid amount`, + `${costingValue.preferredCurrency} is an invalid amount`, }).toBeHidden(); + await expect(this.continueBtn).toBeEnabled(); } else { await expect(adaErrorElement, { - message: !isAdaAmountErrorVisible && `${adaAmount} is a valid amount`, + message: + !isAdaAmountErrorVisible && + `${costingValue.adaAmount} is a valid amount`, }).toBeVisible(); await expect(usdToAdaConversionRateErrorElement, { message: !isUsdToAdaConversionRateErrorVisible && - `${usdToAdaCnversionRate} is a valid amount`, + `${costingValue.usdToAdaConversionRate} is a valid amount`, }).toBeVisible(); await expect(preferredCurrencyErrorElement, { message: !isPreferredCurrencyErrorVisible && - `${preferredCurrency} is a valid amount`, + `${costingValue.preferredCurrency} is a valid amount`, }).toBeVisible(); + await expect(this.continueBtn).toBeDisabled(); } } @@ -843,10 +1070,12 @@ export default class BudgetDiscussionSubmissionPage { await expect(errorElement, { message: isErrorVisible && `${url} is an invalid URL`, }).toBeHidden(); + await expect(this.continueBtn).toBeEnabled(); } else { await expect(errorElement, { message: !isErrorVisible && `${url} is a valid URL`, }).toBeVisible(); + await expect(this.continueBtn).toBeDisabled(); } } } diff --git a/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts b/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts index 5ac4a9512..d096b2965 100644 --- a/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/governanceActionsPage.ts @@ -114,7 +114,7 @@ export default class GovernanceActionsPage { const proposalCards = await this.getAllProposals(); for (const proposalCard of proposalCards) { - if (await proposalCard.isVisible()) { + if (await proposalCard.locator('[data-testid$="-type"]').isVisible()) { const hasFilter = await this._validateFiltersInProposalCard( proposalCard, filters diff --git a/tests/govtool-frontend/playwright/lib/types.ts b/tests/govtool-frontend/playwright/lib/types.ts index 07e1fe92b..2ea7c02a6 100644 --- a/tests/govtool-frontend/playwright/lib/types.ts +++ b/tests/govtool-frontend/playwright/lib/types.ts @@ -488,10 +488,10 @@ export enum PreferredCurrencyEnum { } export interface BudgetCostingProps { - adaAmount: number; - usdToAdaConversionRate: number; + adaAmount: string | number; + usdToAdaConversionRate: string | number; preferredCurrency: preferredCurrencyType; - AmountInPreferredCurrency: number; + AmountInPreferredCurrency: string | number; costBreakdown: string; } diff --git a/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts index 52cfd5836..f2f478be8 100644 --- a/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts +++ b/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts @@ -4,6 +4,7 @@ import { budgetProposal03Wallet, budgetProposal04Wallet, } from "@constants/staticWallets"; +import { faker } from "@faker-js/faker"; import { test } from "@fixtures/budgetProposal"; import { setAllureEpic } from "@helpers/allure"; import { createNewPageWithWallet } from "@helpers/page"; @@ -15,6 +16,8 @@ import { BudgetProposalProps, BudgetProposalStageEnum, CompanyEnum, + PreferredCurrencyEnum, + ProposalContractingEnum, } from "@types"; test.beforeEach(async () => { @@ -222,76 +225,150 @@ test.describe("Budget proposal 01 wallet", () => { ); }); test.describe("Budget proposal field validation", () => { - test("12E_1. Should accept valid data in “Costing” section", async () => { - test.slow(); // Brute-force testing with 50 random data - const proposalInformation = - budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); - await budgetProposalSubmissionPage.fillupForm( - proposalInformation, - BudgetProposalStageEnum.ProposalDetails - ); - - for (let i = 0; i < 50; i++) { - await budgetProposalSubmissionPage.validateCostingSection(); - } - - await budgetProposalSubmissionPage.fillCostingSectionExceptAmountInputs(); - await expect(budgetProposalSubmissionPage.continueBtn).toBeEnabled(); + const budgetProposalValidationReason = [ + { title: "accept valid data", isValid: true }, + { title: "reject invalid data", isValid: false }, + ]; + budgetProposalValidationReason.forEach(({ isValid, title }) => { + test(`12${isValid ? "E" : "F"}_1. Should ${title} in “Proposal Ownership” section`, async () => { + test.slow(); // Brute-force testing with 25 random data + + if (isValid) { + await budgetProposalSubmissionPage.agreeCheckbox.click(); + } + + for (let i = 0; i < 25; i++) { + const validProposalOwnership = + budgetProposalSubmissionPage.generateValidProposalOwnerShip(); + const invalidProposalOwnerShip = + budgetProposalSubmissionPage.generateInvalidProposalOwnerShip(); + const proposalOwnership = isValid + ? validProposalOwnership + : invalidProposalOwnerShip; + await budgetProposalSubmissionPage.fillupProposalOwnershipForm( + proposalOwnership, + false + ); + await budgetProposalSubmissionPage.validateProposalOwnershipSection( + proposalOwnership, + isValid + ); + } + }); }); - test("12E_2. Should accept valid data in “further information” section", async () => { - test.slow(); // Brute-force testing with 50 random data - const proposalInformation = - budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); - await budgetProposalSubmissionPage.fillupForm( - proposalInformation, - BudgetProposalStageEnum.Costing - ); + budgetProposalValidationReason.forEach(({ isValid, title }) => { + test(`12${isValid ? "E" : "F"}_2. Should ${title} in “problem statements and proposal benefits” section`, async () => { + test.slow(); // Brute-force testing with 25 random data + const proposalInformations = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm( + proposalInformations, + BudgetProposalStageEnum.ProposalOwnership + ); - for (let i = 0; i < 50; i++) { - await budgetProposalSubmissionPage.validateFurtherInformationSection(); - } + const budgetProposalProblemStatementAndBenefits = + budgetProposalSubmissionPage.generateValidBudgetProposalProblemStatementAndBenefits(); + await budgetProposalSubmissionPage.fillupProblemStatementAndBenefitsForm( + budgetProposalProblemStatementAndBenefits, + false + ); - for (let i = 0; i < 18; i++) { - await expect(budgetProposalSubmissionPage.addLinkBtn).toBeVisible(); - await budgetProposalSubmissionPage.addLinkBtn.click(); - } - await expect(budgetProposalSubmissionPage.addLinkBtn).toBeHidden(); - await expect(budgetProposalSubmissionPage.continueBtn).toBeEnabled(); + for (let i = 0; i < 25; i++) { + await budgetProposalSubmissionPage.validateProblemStatementsAndProposalBenefitsSection( + isValid + ); + } + }); }); - test("12F_1. Should reject valid data in “Costing” section", async () => { - test.slow(); // Brute-force testing with 50 random data - const proposalInformation = - budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); - await budgetProposalSubmissionPage.fillupForm( - proposalInformation, - BudgetProposalStageEnum.ProposalDetails - ); - - for (let i = 0; i < 50; i++) { - await budgetProposalSubmissionPage.validateCostingSection(false); - } + budgetProposalValidationReason.forEach(({ isValid, title }) => { + test(`12${isValid ? "E" : "F"}_3. Should ${title} in “proposal details” section`, async () => { + test.slow(); // Brute-force testing with 25 random data + const proposalInformations = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm( + proposalInformations, + BudgetProposalStageEnum.ProblemStatementAndBenefits + ); - await budgetProposalSubmissionPage.fillCostingSectionExceptAmountInputs(); - await expect(budgetProposalSubmissionPage.continueBtn).toBeDisabled(); + await budgetProposalSubmissionPage.contractingTypeSelect.click(); + const contractingType = faker.helpers + .arrayElement(Object.values(ProposalContractingEnum)) + .toLowerCase(); + await budgetProposalSubmissionPage.currentPage + .getByTestId(`${contractingType}-button`) + .click(); + if (contractingType === "Other") { + await budgetProposalSubmissionPage.otherDescriptionInput.fill( + faker.lorem.paragraph(2) + ); + } + + for (let i = 0; i < 25; i++) { + await budgetProposalSubmissionPage.validateProposalDetailsSection( + isValid + ); + } + }); }); - test("12F_2. Should reject invalid data in “further information” section", async () => { - test.slow(); // Brute-force testing with 50 random data - const proposalInformation = - budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); - await budgetProposalSubmissionPage.fillupForm( - proposalInformation, - BudgetProposalStageEnum.Costing - ); + budgetProposalValidationReason.forEach(({ isValid, title }) => { + test(`12${isValid ? "E" : "F"}_4. Should ${title} in “Costing” section`, async () => { + test.slow(); // Brute-force testing with 25 random data + const proposalInformation = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm( + proposalInformation, + BudgetProposalStageEnum.ProposalDetails + ); - for (let i = 0; i < 50; i++) { - await budgetProposalSubmissionPage.validateFurtherInformationSection( - false + await budgetProposalSubmissionPage.preferredCurrencySelect.click(); + await budgetProposalSubmissionPage.currentPage + .getByTestId( + `${faker.helpers + .arrayElement(Object.values(PreferredCurrencyEnum)) + .toLowerCase()}-button` + ) + .click(); + + for (let i = 0; i < 25; i++) { + const invalidCostingValues = + budgetProposalSubmissionPage.generateInValidCosting(); + const validCostingValues = + budgetProposalSubmissionPage.generateValidCosting(); + const costingValues = isValid + ? validCostingValues + : invalidCostingValues; + await budgetProposalSubmissionPage.validateCostingSection( + costingValues, + isValid + ); + } + }); + }); + + budgetProposalValidationReason.forEach(({ isValid, title }) => { + test(`12${isValid ? "E" : "F"}_5. Should ${title} in “further information” section`, async () => { + test.slow(); // Brute-force testing with 25 random data + const proposalInformation = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm( + proposalInformation, + BudgetProposalStageEnum.Costing ); - } - await expect(budgetProposalSubmissionPage.continueBtn).toBeDisabled(); + + for (let i = 0; i < 25; i++) { + await budgetProposalSubmissionPage.validateFurtherInformationSection( + isValid + ); + } + for (let i = 0; i < 18; i++) { + await expect(budgetProposalSubmissionPage.addLinkBtn).toBeVisible(); + await budgetProposalSubmissionPage.addLinkBtn.click(); + } + await expect(budgetProposalSubmissionPage.addLinkBtn).toBeHidden(); + }); }); }); }); From e7c86a9f7c2664fbca59deae5feef6cbce84131a Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 24 Apr 2025 11:39:33 +0545 Subject: [PATCH 4/5] test: add validation test for administration and submit section --- .../playwright/lib/helpers/adaFormat.ts | 2 +- .../pages/budgetDiscussionSubmissionPage.ts | 60 ++++++++++++------- .../proposalBudgetSubmission.loggedin.spec.ts | 37 ++++++++++++ 3 files changed, 75 insertions(+), 24 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/helpers/adaFormat.ts b/tests/govtool-frontend/playwright/lib/helpers/adaFormat.ts index fedb9e809..4c75378c4 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/adaFormat.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/adaFormat.ts @@ -52,7 +52,7 @@ export function formatWithThousandSeparator( numericValue = value; } - if (isAda) { + if (!isAda) { numericValue = Math.ceil(numericValue / LOVELACE); } diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts index 249e79e7a..66a0a20c7 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts @@ -419,17 +419,21 @@ export default class BudgetDiscussionSubmissionPage { await this.continueBtn.click(); } - // async fillCostingSectionExceptAmountInputs() { - // const costing = this.generateValidCosting(); - // await this.preferredCurrencySelect.click(); - // await this.page - // .getByTestId(`${costing.preferredCurrency.toLowerCase()}-button`) - // .click(); - // await this.preferredCurrencyInput.fill( - // costing.AmountInPreferredCurrency.toString() - // ); - // await this.costBreakdownInput.fill(costing.costBreakdown.toString()); - // } + async fillupAdministrationAndAuditing( + administrationAndAuditing: AdministrationAndAuditingProps + ) { + await this.intersectNamedAdministratorSelect.click(); + await this.page + .getByTestId( + `${administrationAndAuditing.intersectAdministration}-button` + ) + .click(); + if (!administrationAndAuditing.intersectAdministration) { + await this.venderDetailsInput.fill( + administrationAndAuditing.venderDetails + ); + } + } async fillupForm( budgetProposal: BudgetProposalProps, @@ -453,18 +457,9 @@ export default class BudgetDiscussionSubmissionPage { await this.fillupFurtherInformation(budgetProposal.furtherInformation); } if (stage > BudgetProposalStageEnum.FurtherInformation) { - await this.intersectNamedAdministratorSelect.click(); - - await this.page - .getByTestId( - `${budgetProposal.administrationAndAuditing.intersectAdministration}-button` - ) - .click(); - if (!budgetProposal.administrationAndAuditing.intersectAdministration) { - await this.venderDetailsInput.fill( - budgetProposal.administrationAndAuditing.venderDetails - ); - } + this.fillupAdministrationAndAuditing( + budgetProposal.administrationAndAuditing + ); await this.continueBtn.click(); if (stage > BudgetProposalStageEnum.AdministrationAndAuditing) { await this.submitCheckbox.click(); @@ -1078,4 +1073,23 @@ export default class BudgetDiscussionSubmissionPage { await expect(this.continueBtn).toBeDisabled(); } } + + async validateAdministrationAndAuditingSection(isValid: boolean = true) { + if (isValid) { + const validateAdministrationAndAuditingSection = + this.generateAdministrationAndAuditing(); + await this.fillupAdministrationAndAuditing( + validateAdministrationAndAuditingSection + ); + await expect(this.continueBtn).toBeEnabled(); + } else { + // continue button will be disabled if type is not selected or if the type is "No" and the vender details is not filled + const isFalse = faker.datatype.boolean(); + if (isFalse) { + await this.intersectNamedAdministratorSelect.click(); + await this.page.getByTestId("false-button").click(); + } + await expect(this.continueBtn).toBeDisabled(); + } + } } diff --git a/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts index f2f478be8..af9aa95cb 100644 --- a/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts +++ b/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts @@ -370,6 +370,43 @@ test.describe("Budget proposal 01 wallet", () => { await expect(budgetProposalSubmissionPage.addLinkBtn).toBeHidden(); }); }); + + budgetProposalValidationReason.forEach(({ isValid, title }) => { + test(`12${isValid ? "E" : "F"}_6. Should ${title} in “Administration and Auditing” section`, async () => { + const proposalInformation = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm( + proposalInformation, + BudgetProposalStageEnum.FurtherInformation + ); + for (let i = 0; i < 25; i++) { + await budgetProposalSubmissionPage.validateAdministrationAndAuditingSection( + isValid + ); + } + }); + }); + + budgetProposalValidationReason.forEach(({ isValid, title }) => { + test(`12${isValid ? "E" : "F"}_7. Should ${title} in “Submit” section`, async () => { + const proposalInformation = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm( + proposalInformation, + BudgetProposalStageEnum.AdministrationAndAuditing + ); + if (isValid) { + await budgetProposalSubmissionPage.submitCheckbox.click(); + await expect( + budgetProposalSubmissionPage.continueBtn + ).toBeEnabled(); + } else { + await expect( + budgetProposalSubmissionPage.continueBtn + ).toBeDisabled(); + } + }); + }); }); }); }); From cc98da6f36ff81a74f68f1ea1e30482ed7f074f0 Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 24 Apr 2025 11:42:44 +0545 Subject: [PATCH 5/5] chore: remove unnecessary division on outcome votes --- .../playwright/tests/9-outcomes/outcomes.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/govtool-frontend/playwright/tests/9-outcomes/outcomes.spec.ts b/tests/govtool-frontend/playwright/tests/9-outcomes/outcomes.spec.ts index e856fe4ff..bdce3eacc 100644 --- a/tests/govtool-frontend/playwright/tests/9-outcomes/outcomes.spec.ts +++ b/tests/govtool-frontend/playwright/tests/9-outcomes/outcomes.spec.ts @@ -453,7 +453,7 @@ test("9G. Should display correct vote counts on outcome details page", async ({ name: "Explicit", }) ).toHaveText( - `Explicit${formatWithThousandSeparator(Math.ceil(proposalToCheck.pool_abstain_votes) / 1000000)}` + `Explicit${formatWithThousandSeparator(proposalToCheck.pool_abstain_votes, false)}` ); //BUG missing testIds await expect( govActionDetailsPage.sPosResultData