From f99371d3e77ca2c7a4d5b8786f073bfd50ff92c4 Mon Sep 17 00:00:00 2001 From: Niraj Date: Mon, 31 Mar 2025 15:45:05 +0545 Subject: [PATCH 01/45] feat: add skeleton tests for proposal budget features --- .../playwright/lib/helpers/cardano.ts | 5 +++ .../proposalBudget.dRep.spec.ts | 11 +++++ .../proposalBudget.loggedin.spec.ts | 14 ++++++ .../11-proposal-budget/proposalBudget.spec.ts | 31 +++++++++++++ .../proposalBudgetSubmission.loggedin.spec.ts | 45 +++++++++++++++++++ .../proposalBudgetSubmission.spec.ts | 12 +++++ 6 files changed, 118 insertions(+) create mode 100644 tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts create mode 100644 tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.spec.ts diff --git a/tests/govtool-frontend/playwright/lib/helpers/cardano.ts b/tests/govtool-frontend/playwright/lib/helpers/cardano.ts index ad7126a94..ab686da31 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/cardano.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/cardano.ts @@ -65,3 +65,8 @@ export async function skipIfMainnet() { test.skip(); } } + +export async function skipTestForProposalBudget() { + await allure.description("Proposal budget features are not yet available."); + test.skip(); +} diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts new file mode 100644 index 000000000..a028c0d46 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts @@ -0,0 +1,11 @@ +import { test } from "@fixtures/walletExtension"; +import { setAllureEpic } from "@helpers/allure"; +import { skipTestForProposalBudget } from "@helpers/cardano"; + +test.beforeEach(async ({}) => { + await setAllureEpic("11. Proposal Budget"); + await skipTestForProposalBudget(); +}); + +test("11K. Should allow registered DRep to vote on a proposal", async ({}) => {}); +test("11L. Should display DRep tag, name and ID when a registered DRep comments on a proposal", async ({}) => {}); diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.spec.ts new file mode 100644 index 000000000..187ec9091 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.spec.ts @@ -0,0 +1,14 @@ +import { test } from "@fixtures/walletExtension"; +import { setAllureEpic } from "@helpers/allure"; +import { skipTestForProposalBudget } from "@helpers/cardano"; + +test.beforeEach(async ({}) => { + await setAllureEpic("11. Proposal Budget"); + await skipTestForProposalBudget(); +}); + +test("11H. Should restrict non registered DRep users from voting", async () => {}); + +test("11I. Should comments on any proposal", async ({}) => {}); + +test("11J. Should reply to any comments", async ({}) => {}); diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts new file mode 100644 index 000000000..14f989679 --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -0,0 +1,31 @@ +import { test } from "@fixtures/walletExtension"; +import { setAllureEpic } from "@helpers/allure"; +import { skipTestForProposalBudget } from "@helpers/cardano"; + +test.beforeEach(async ({}) => { + await setAllureEpic("11. Proposal Budget"); + await skipTestForProposalBudget(); +}); + +test("11A. Should access budget proposal page", async ({}) => {}); + +test.describe("Budget proposal list manipulation", () => { + test("11B_1. Should search for budget proposals by title", async ({}) => {}); + + test("11B_2. Should filter budget proposals by categories", async ({}) => {}); + + test("11B_3. Should sort budget proposals", async ({}) => {}); +}); + +test("11C. Should show view-all categorized budget proposal", async ({}) => {}); + +test("11D. Should share budget proposal", async ({}) => {}); + +test("11E. Should view comments with count indications on a budget proposal", async () => {}); + +test.describe("Restricted access to interact budget proposal", () => { + test("11F_1. Should restrict users without wallets from commenting", async () => {}); + test("11F_2. Should restrict users without wallets from voting", async () => {}); +}); + +test("11G. Should sort the budget proposal comments", async ({}) => {}); 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 new file mode 100644 index 000000000..097726dea --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.loggedin.spec.ts @@ -0,0 +1,45 @@ +import { test } from "@fixtures/walletExtension"; +import { setAllureEpic } from "@helpers/allure"; +import { skipTestForProposalBudget } from "@helpers/cardano"; + +test.beforeEach(async ({}) => { + await setAllureEpic("12. Proposal Budget Submission"); + await skipTestForProposalBudget(); +}); + +test("12B. Should access proposal creation page in connected state", async ({}) => {}); + +test("12C. Should view draft proposal", async ({}) => {}); + +test.describe("Budget proposal field verification", () => { + test("12D_1. Should verify all field of “contact information” section", async ({}) => {}); + test("12D_2. Should verify all field of “proposal ownership” section", async ({}) => {}); + test("12D_3. Should verify all field of “problem statements and proposal benefits” section", async ({}) => {}); + test("12D_4. Should verify all field of “costing” section", async ({}) => {}); + test("12D_5. Should verify all field of “further information” section", async ({}) => {}); + test("12D_6. Should verify all field of “administration and auditing” section", async ({}) => {}); + test("12D_7. Should verify all field of “submit” section", async ({}) => {}); +}); + +test.describe("Budget proposal field validation", () => { + test("12E_1. Should accept valid data in “contact information” section", async ({}) => {}); + test("12E_2. Should accept valid data in “proposal ownership” section", async ({}) => {}); + test("12E_3. Should accept valid data in “problem statements and proposal benefits” section", async ({}) => {}); + test("12E_4. Should accept valid data in “costing” section", async ({}) => {}); + test("12E_5. Should accept valid data in “further information” section", async ({}) => {}); + test("12E_6. Should accept valid data in “administration and auditing” section", async ({}) => {}); + test("12E_7. Should accept valid data in “submit” section", async ({}) => {}); + test("12F_1. Should reject invalid data in “contact information” section", async ({}) => {}); + test("12F_2. Should reject invalid data in “proposal ownership” section", async ({}) => {}); + test("12F_3. Should reject invalid data in “problem statements and proposal benefits” section", async ({}) => {}); + test("12F_4. Should reject invalid data in “costing” section", async ({}) => {}); + test("12F_5. Should reject invalid data in “further information” section", async ({}) => {}); + test("12F_6. Should reject invalid data in “administration and auditing” section", async ({}) => {}); + test("12F_7. Should reject invalid data in “submit” section", async ({}) => {}); +}); + +test("12G. Should validate and review submitted budget proposal", async ({}) => {}); +test("12H. Should save a budget proposal as a draft", async ({}) => {}); + +test("12I. Should submit a valid budget proposal", async ({}) => {}); +test("12J. Should submit a valid draft budget proposal", async ({}) => {}); diff --git a/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.spec.ts b/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.spec.ts new file mode 100644 index 000000000..b190f37fe --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.spec.ts @@ -0,0 +1,12 @@ +import { test } from "@fixtures/walletExtension"; +import { setAllureEpic } from "@helpers/allure"; +import { skipTestForProposalBudget } from "@helpers/cardano"; + +test.beforeEach(async ({}) => { + await setAllureEpic("12. Proposal Budget Submission"); + await skipTestForProposalBudget(); +}); + +test("12A. Should restrict from creating a budget proposal in disconnect state", async ({ + page, +}) => {}); From 24aac2f39769df275dae6c26b862a88eba5c2db7 Mon Sep 17 00:00:00 2001 From: Niraj Date: Wed, 2 Apr 2025 13:29:54 +0545 Subject: [PATCH 02/45] tests: restrict budget proposal creation in disconnect state --- .../proposalBudgetSubmission.spec.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.spec.ts b/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.spec.ts index b190f37fe..3ea61045e 100644 --- a/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.spec.ts +++ b/tests/govtool-frontend/playwright/tests/12-proposal-budget-submission/proposalBudgetSubmission.spec.ts @@ -1,12 +1,22 @@ import { test } from "@fixtures/walletExtension"; import { setAllureEpic } from "@helpers/allure"; -import { skipTestForProposalBudget } from "@helpers/cardano"; +import { isMobile } from "@helpers/mobile"; +import { expect } from "@playwright/test"; test.beforeEach(async ({}) => { await setAllureEpic("12. Proposal Budget Submission"); - await skipTestForProposalBudget(); }); test("12A. Should restrict from creating a budget proposal in disconnect state", async ({ page, -}) => {}); +}) => { + await page.goto("/"); + if (isMobile(page)) { + await page.getByTestId("open-drawer-button").click(); + } + await page.getByTestId("budget-discussion-link").click(); + await expect(page.getByTestId("verify-identity-button")).not.toBeVisible(); + await expect( + page.getByTestId("propose-a-budget-discussion-button") + ).not.toBeVisible(); +}); From 78c1f23a61a0d935195e870712515f1951bcf9f7 Mon Sep 17 00:00:00 2001 From: Niraj Date: Wed, 2 Apr 2025 13:36:31 +0545 Subject: [PATCH 03/45] tests: access budget discussion page --- .../lib/pages/budgetDiscussionPage.ts | 23 +++++++++++++++++++ .../11-proposal-budget/proposalBudget.spec.ts | 13 ++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts new file mode 100644 index 000000000..165875a2b --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts @@ -0,0 +1,23 @@ +import { Page } from "@playwright/test"; +import environments from "lib/constants/environments"; + +export default class BudgetDiscussionPage { + // Buttons + readonly drawerBtn = this.page.getByTestId("open-drawer-button"); + readonly proposalBudgetDiscussionBtn = this.page.getByTestId( + "propose-a-budget-discussion-button" + ); + readonly verifyIdentityBtn = this.page.getByTestId("verify-identity-button"); + + constructor(private readonly page: Page) {} + + get currentPage(): Page { + return this.page; + } + + async goto() { + await this.page.goto(`${environments.frontendUrl}/budget_discussion`); + // wait for the proposal cards to load + await this.page.waitForTimeout(2_000); + } +} diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts index 14f989679..66eedb74a 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -1,13 +1,20 @@ import { test } from "@fixtures/walletExtension"; import { setAllureEpic } from "@helpers/allure"; -import { skipTestForProposalBudget } from "@helpers/cardano"; +import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; +import { expect } from "@playwright/test"; test.beforeEach(async ({}) => { await setAllureEpic("11. Proposal Budget"); - await skipTestForProposalBudget(); }); -test("11A. Should access budget proposal page", async ({}) => {}); +test("11A. Should access budget proposal page in disconnect state", async ({ page }) => { + const budgetDiscussionPage = new BudgetDiscussionPage(page); + await budgetDiscussionPage.goto(); + + await expect( + budgetDiscussionPage.currentPage.getByText("/Budget Proposals/i") + ).toHaveCount(2); +}); test.describe("Budget proposal list manipulation", () => { test("11B_1. Should search for budget proposals by title", async ({}) => {}); From e964180ae753872520bea992a4645d98a1001556 Mon Sep 17 00:00:00 2001 From: Niraj Date: Wed, 2 Apr 2025 14:21:10 +0545 Subject: [PATCH 04/45] tests: search budget proposal by title --- .../lib/pages/budgetDiscussionPage.ts | 21 ++++++- .../11-proposal-budget/proposalBudget.spec.ts | 58 ++++++++++++++++++- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts index 165875a2b..71bd2acea 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts @@ -1,4 +1,5 @@ -import { Page } from "@playwright/test"; +import { waitedLoop } from "@helpers/waitedLoop"; +import { expect, Page } from "@playwright/test"; import environments from "lib/constants/environments"; export default class BudgetDiscussionPage { @@ -9,6 +10,9 @@ export default class BudgetDiscussionPage { ); readonly verifyIdentityBtn = this.page.getByTestId("verify-identity-button"); + // input + readonly searchInput = this.page.getByTestId("search-input"); + constructor(private readonly page: Page) {} get currentPage(): Page { @@ -20,4 +24,19 @@ export default class BudgetDiscussionPage { // wait for the proposal cards to load await this.page.waitForTimeout(2_000); } + + async getAllProposals() { + const proposalCardSelector = + '[data-testid^="budget-discussion-"][data-testid$="-card"]'; + + await waitedLoop(async () => { + const count = await this.page.locator(proposalCardSelector).count(); + return count > 0; + }); + const proposalCards = await this.page.locator(proposalCardSelector).all(); + + expect(true, "No budget proposals found.").toBeTruthy(); + + return proposalCards; + } } diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts index 66eedb74a..19a5e58ef 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -1,5 +1,6 @@ import { test } from "@fixtures/walletExtension"; import { setAllureEpic } from "@helpers/allure"; +import { functionWaitedAssert } from "@helpers/waitedLoop"; import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; import { expect } from "@playwright/test"; @@ -7,7 +8,9 @@ test.beforeEach(async ({}) => { await setAllureEpic("11. Proposal Budget"); }); -test("11A. Should access budget proposal page in disconnect state", async ({ page }) => { +test("11A. Should access budget proposal page in disconnect state", async ({ + page, +}) => { const budgetDiscussionPage = new BudgetDiscussionPage(page); await budgetDiscussionPage.goto(); @@ -17,7 +20,58 @@ test("11A. Should access budget proposal page in disconnect state", async ({ pag }); test.describe("Budget proposal list manipulation", () => { - test("11B_1. Should search for budget proposals by title", async ({}) => {}); + test("11B_1. Should search for budget proposals by title", async ({ + page, + }) => { + let proposalName = "EchoFeed"; + let proposalNameSet = false; + + await page.route("**/api/bds?**", async (route) => { + const response = await route.fetch(); + const json = await response.json(); + if (!proposalNameSet && "data" in json && json["data"].length > 0) { + const randomIndex = Math.floor(Math.random() * json["data"].length); + proposalName = + json["data"][randomIndex]["attributes"]["bd_proposal_detail"]["data"][ + "attributes" + ]["proposal_name"]; + proposalNameSet = true; + } + await route.fulfill({ + status: 200, + contentType: "application/json", + body: JSON.stringify(json), + }); + }); + + const responsePromise = page.waitForResponse("**/api/bds?**"); + const budgetDiscussionPage = new BudgetDiscussionPage(page); + await budgetDiscussionPage.goto(); + + await responsePromise; + + await budgetDiscussionPage.searchInput.fill(proposalName); + + await page.waitForTimeout(2000); + + await functionWaitedAssert( + async () => { + const proposalCards = await budgetDiscussionPage.getAllProposals(); + for (const proposalCard of proposalCards) { + await expect(proposalCard).toBeVisible(); + const proposalTitle = await proposalCard + .getByTestId("budget-discussion-title") + .textContent(); + expect(proposalTitle.toLowerCase()).toContain( + proposalName.toLowerCase() + ); + } + }, + { + message: `A proposal card does not contain the search term ${proposalName}`, + } + ); + }); test("11B_2. Should filter budget proposals by categories", async ({}) => {}); From 3a41668a45eb8de856004f11c3e93dccc4bbedaa Mon Sep 17 00:00:00 2001 From: Niraj Date: Wed, 2 Apr 2025 15:07:06 +0545 Subject: [PATCH 05/45] tests: budget proposal filter --- .../lib/pages/budgetDiscussionPage.ts | 82 ++++++++++++++++++- .../govtool-frontend/playwright/lib/types.ts | 8 ++ .../11-proposal-budget/proposalBudget.spec.ts | 23 +++++- 3 files changed, 109 insertions(+), 4 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts index 71bd2acea..d474f424d 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts @@ -1,5 +1,6 @@ -import { waitedLoop } from "@helpers/waitedLoop"; -import { expect, Page } from "@playwright/test"; +import { functionWaitedAssert, waitedLoop } from "@helpers/waitedLoop"; +import { expect, Locator, Page } from "@playwright/test"; +import { BudgetProposalType } from "@types"; import environments from "lib/constants/environments"; export default class BudgetDiscussionPage { @@ -9,6 +10,7 @@ export default class BudgetDiscussionPage { "propose-a-budget-discussion-button" ); readonly verifyIdentityBtn = this.page.getByTestId("verify-identity-button"); + readonly filterBtn = this.page.getByTestId("filter-button"); // input readonly searchInput = this.page.getByTestId("search-input"); @@ -39,4 +41,80 @@ export default class BudgetDiscussionPage { return proposalCards; } + + async clickRadioButtonsByNames(names: string[]) { + for (const name of names) { + const budgetProposalValue = Object.values(BudgetProposalType).includes( + name as BudgetProposalType + ); + if (budgetProposalValue) { + await this.page.getByLabel(name).click(); + } + } + } + + async filterProposalByNames(names: string[]) { + await this.clickRadioButtonsByNames(names); + } + + async unFilterProposalByNames(names: string[]) { + await this.clickRadioButtonsByNames(names); + } + + async applyAndValidateFilters( + filters: string[], + validateFunction: (proposalCard: any, filters: string[]) => Promise + ) { + await this.page.waitForTimeout(4_000); // wait for the proposals to load + // single filter + for (const filter of filters) { + await this.filterProposalByNames([filter]); + await this.validateFilters([filter], validateFunction); + await this.unFilterProposalByNames([filter]); + } + + // multiple filter + const multipleFilters = [...filters]; + while (multipleFilters.length > 1) { + await this.filterProposalByNames(multipleFilters); + await this.validateFilters(multipleFilters, validateFunction); + await this.unFilterProposalByNames(multipleFilters); + multipleFilters.pop(); + } + } + + async validateFilters( + filters: string[], + validateFunction: (proposalCard: any, filters: string[]) => Promise + ) { + await functionWaitedAssert(async () => { + const proposalCards = await this.getAllProposals(); + + for (const proposalCard of proposalCards) { + if (await proposalCard.isVisible()) { + const type = await proposalCard + .getByTestId("budget-proposal-type") + .textContent(); + const hasFilter = await validateFunction(proposalCard, filters); + + expect( + hasFilter, + !hasFilter && + `A budget proposal type ${type} does not contain on ${filters}` + ).toBe(true); + } + } + }); + } + + async _validateTypeFiltersInProposalCard( + proposalCard: Locator, + filters: string[] + ): Promise { + const govActionType = await proposalCard + .getByTestId("budget-proposal-type") + .textContent(); + + return filters.includes(govActionType); + } } diff --git a/tests/govtool-frontend/playwright/lib/types.ts b/tests/govtool-frontend/playwright/lib/types.ts index 84cc17c38..9aead83cb 100644 --- a/tests/govtool-frontend/playwright/lib/types.ts +++ b/tests/govtool-frontend/playwright/lib/types.ts @@ -323,3 +323,11 @@ export interface InvalidMetadataType { url: string; hash: string; } + +export enum BudgetProposalType { + Core = "Core", + Research = "Research", + GovernanceSupport = "Governance Support", + MarketingAndInnovation = "Marketing & Innovation", + NoCategory = "No Category", +} diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts index 19a5e58ef..4765b93bd 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -3,6 +3,7 @@ import { setAllureEpic } from "@helpers/allure"; import { functionWaitedAssert } from "@helpers/waitedLoop"; import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; import { expect } from "@playwright/test"; +import { BudgetProposalType } from "@types"; test.beforeEach(async ({}) => { await setAllureEpic("11. Proposal Budget"); @@ -73,9 +74,27 @@ test.describe("Budget proposal list manipulation", () => { ); }); - test("11B_2. Should filter budget proposals by categories", async ({}) => {}); + test.describe("Filter and sort budget proposals", () => { + let budgetDiscussionPage: BudgetDiscussionPage; - test("11B_3. Should sort budget proposals", async ({}) => {}); + test.beforeEach(async ({ page }) => { + budgetDiscussionPage = new BudgetDiscussionPage(page); + await budgetDiscussionPage.goto(); + }); + + test("11B_2. Should filter budget proposals by categories", async () => { + test.slow(); + await budgetDiscussionPage.filterBtn.click(); + + // proposal type filter + await budgetDiscussionPage.applyAndValidateFilters( + Object.values(BudgetProposalType), + budgetDiscussionPage._validateTypeFiltersInProposalCard + ); + }); + + test("11B_3. Should sort budget proposals", async ({}) => {}); + }); }); test("11C. Should show view-all categorized budget proposal", async ({}) => {}); From d67b5b266cffc1a2b8f44f1cb108e3da1b06aa59 Mon Sep 17 00:00:00 2001 From: Niraj Date: Wed, 2 Apr 2025 15:16:17 +0545 Subject: [PATCH 06/45] tests: sort budget proposal by asc and desc --- .../lib/pages/budgetDiscussionPage.ts | 29 ++++++++++++++++++- .../11-proposal-budget/proposalBudget.spec.ts | 12 +++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts index d474f424d..03b0a9725 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts @@ -1,6 +1,6 @@ import { functionWaitedAssert, waitedLoop } from "@helpers/waitedLoop"; import { expect, Locator, Page } from "@playwright/test"; -import { BudgetProposalType } from "@types"; +import { BudgetProposalType, ProposedGovAction } from "@types"; import environments from "lib/constants/environments"; export default class BudgetDiscussionPage { @@ -11,6 +11,7 @@ export default class BudgetDiscussionPage { ); readonly verifyIdentityBtn = this.page.getByTestId("verify-identity-button"); readonly filterBtn = this.page.getByTestId("filter-button"); + readonly sortBtn = this.page.getByTestId("sort-button"); // input readonly searchInput = this.page.getByTestId("search-input"); @@ -117,4 +118,30 @@ export default class BudgetDiscussionPage { return filters.includes(govActionType); } + + async sortAndValidate( + option: "asc" | "desc", + validationFn: (p1: ProposedGovAction, p2: ProposedGovAction) => boolean + ) { + const responsePromise = this.page.waitForResponse((response) => + response + .url() + .includes(`&sort[createdAt]=${option}&populate[0]=bd_costing`) + ); + + await this.sortBtn.click(); + const response = await responsePromise; + + let proposals: ProposedGovAction[] = (await response.json()).data; + + // API validation + for (let i = 0; i <= proposals.length - 2; i++) { + console.log( + proposals[i].attributes.createdAt, + proposals[i + 1].attributes.createdAt + ); + const isValid = validationFn(proposals[i], proposals[i + 1]); + expect(isValid).toBe(true); + } + } } diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts index 4765b93bd..537af9148 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -93,7 +93,17 @@ test.describe("Budget proposal list manipulation", () => { ); }); - test("11B_3. Should sort budget proposals", async ({}) => {}); + test("11B_3. Should sort budget proposals", async () => { + await budgetDiscussionPage.sortAndValidate( + "asc", + (p1, p2) => p1.attributes.createdAt <= p2.attributes.createdAt + ); + + await budgetDiscussionPage.sortAndValidate( + "desc", + (p1, p2) => p1.attributes.createdAt >= p2.attributes.createdAt + ); + }); }); }); From 811f3d6538bfad835eab7221b49b19bd18a7d959 Mon Sep 17 00:00:00 2001 From: Niraj Date: Wed, 2 Apr 2025 15:25:51 +0545 Subject: [PATCH 07/45] tests: view-all functionality for categorized budget proposals --- .../11-proposal-budget/proposalBudget.spec.ts | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts index 537af9148..19e2221a9 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -1,5 +1,6 @@ import { test } from "@fixtures/walletExtension"; import { setAllureEpic } from "@helpers/allure"; +import { injectLogger } from "@helpers/page"; import { functionWaitedAssert } from "@helpers/waitedLoop"; import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; import { expect } from "@playwright/test"; @@ -81,7 +82,7 @@ test.describe("Budget proposal list manipulation", () => { budgetDiscussionPage = new BudgetDiscussionPage(page); await budgetDiscussionPage.goto(); }); - + test("11B_2. Should filter budget proposals by categories", async () => { test.slow(); await budgetDiscussionPage.filterBtn.click(); @@ -98,7 +99,7 @@ test.describe("Budget proposal list manipulation", () => { "asc", (p1, p2) => p1.attributes.createdAt <= p2.attributes.createdAt ); - + await budgetDiscussionPage.sortAndValidate( "desc", (p1, p2) => p1.attributes.createdAt >= p2.attributes.createdAt @@ -107,7 +108,45 @@ test.describe("Budget proposal list manipulation", () => { }); }); -test("11C. Should show view-all categorized budget proposal", async ({}) => {}); +test("11C. Should show view-all categorized budget proposal", async ({ + browser, +}) => { + await Promise.all( + Object.values(BudgetProposalType).map(async (proposalType: string) => { + const context = await browser.newContext(); + const page = await context.newPage(); + injectLogger(page); + + const budgetDiscussionPage = new BudgetDiscussionPage(page); + await budgetDiscussionPage.goto(); + const isShowAllButtonVisible = await page + .waitForSelector( + `[data-testid="${proposalType.toLowerCase().replace(/ /g, "-")}-show-all-button"]`, + { timeout: 60_000 } + ) + .then(() => true) + .catch(() => false); + + if (isShowAllButtonVisible) { + await page + .getByTestId( + proposalType.toLowerCase().replace(/ /g, "-") + "-show-all-button" + ) + .click(); + + const proposalCards = await budgetDiscussionPage.getAllProposals(); + + for (const proposalCard of proposalCards) { + await expect( + proposalCard.getByTestId("budget-discussion-type") + ).toHaveText(proposalType, { timeout: 60_000 }); + } + } else { + expect(true, `No ${proposalType} found`).toBeTruthy(); + } + }) + ); +}); test("11D. Should share budget proposal", async ({}) => {}); From b368b3890abdcc586e5b0a6778ab2bb197c4cf92 Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 10:23:21 +0545 Subject: [PATCH 08/45] chore: add BudgetDiscussionDetailsPage and viewFirstProposal method --- .../lib/pages/budgetDiscussionDetailsPage.ts | 23 +++++++++++++++++++ .../lib/pages/budgetDiscussionPage.ts | 11 +++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts new file mode 100644 index 000000000..e3f09b7d0 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts @@ -0,0 +1,23 @@ +import { Page } from "@playwright/test"; +import environments from "lib/constants/environments"; + +export default class BudgetDiscussionDetailsPage { + // Buttons + readonly shareBtn = this.page.getByTestId("share-button"); + readonly copyLinkBtn = this.page.getByTestId("copy-link"); + + // content + readonly copyLinkText = this.page.getByTestId("copy-link-text"); + + constructor(private readonly page: Page) {} + + get currentPage(): Page { + return this.page; + } + + async goto(proposalId: string) { + await this.page.goto( + `${environments.frontendUrl}/budget_discussion/${proposalId}` + ); + } +} diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts index 03b0a9725..0530f0447 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts @@ -2,6 +2,7 @@ import { functionWaitedAssert, waitedLoop } from "@helpers/waitedLoop"; import { expect, Locator, Page } from "@playwright/test"; import { BudgetProposalType, ProposedGovAction } from "@types"; import environments from "lib/constants/environments"; +import BudgetDiscussionDetailsPage from "./budgetDiscussionDetailsPage"; export default class BudgetDiscussionPage { // Buttons @@ -28,6 +29,16 @@ export default class BudgetDiscussionPage { await this.page.waitForTimeout(2_000); } + async viewFirstProposal(): Promise { + await this.page + .locator( + '[data-testid^="budget-discussion-"][data-testid$="-view-details"]' + ) + .first() + .click(); + return new BudgetDiscussionDetailsPage(this.page); + } + async getAllProposals() { const proposalCardSelector = '[data-testid^="budget-discussion-"][data-testid$="-card"]'; From a27a6456e5f094c37db8606376e4363a827a3389 Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 10:23:39 +0545 Subject: [PATCH 09/45] tests: sharing functionality for budget proposal --- .../11-proposal-budget/proposalBudget.spec.ts | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts index 19e2221a9..73fc89278 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -1,6 +1,8 @@ +import environments from "@constants/environments"; import { test } from "@fixtures/walletExtension"; import { setAllureEpic } from "@helpers/allure"; import { injectLogger } from "@helpers/page"; +import { extractProposalIdFromUrl } from "@helpers/string"; import { functionWaitedAssert } from "@helpers/waitedLoop"; import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; import { expect } from "@playwright/test"; @@ -148,7 +150,28 @@ test("11C. Should show view-all categorized budget proposal", async ({ ); }); -test("11D. Should share budget proposal", async ({}) => {}); +test("11D. Should share budget proposal", async ({ page, context }) => { + await context.grantPermissions(["clipboard-read", "clipboard-write"]); + const budgetDiscussionPage = new BudgetDiscussionPage(page); + await budgetDiscussionPage.goto(); + + const budgetDiscussionDetailsPage = + await budgetDiscussionPage.viewFirstProposal(); + + const currentPageUrl = page.url(); + const proposalId = extractProposalIdFromUrl(currentPageUrl); + + await budgetDiscussionDetailsPage.shareBtn.click(); + await budgetDiscussionDetailsPage.copyLinkBtn.click(); + await expect(budgetDiscussionDetailsPage.copyLinkText).toBeVisible(); + + const copiedTextDRepDirectory = await page.evaluate(() => + navigator.clipboard.readText() + ); + const expectedCopyUrl = `${environments.frontendUrl}/budget_discussion/${proposalId}`; + + expect(copiedTextDRepDirectory).toEqual(expectedCopyUrl); +}); test("11E. Should view comments with count indications on a budget proposal", async () => {}); From f82916d355a13af35e53e2385f2d2fe0e8e9402c Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 10:38:00 +0545 Subject: [PATCH 10/45] fix: update budget proposal selection to use data-testid and remove console logs --- .../playwright/lib/pages/budgetDiscussionPage.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts index 0530f0447..144c3c02f 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts @@ -60,7 +60,7 @@ export default class BudgetDiscussionPage { name as BudgetProposalType ); if (budgetProposalValue) { - await this.page.getByLabel(name).click(); + await this.page.getByTestId(`${name.toLowerCase()}-radio`).click(); } } } @@ -147,10 +147,6 @@ export default class BudgetDiscussionPage { // API validation for (let i = 0; i <= proposals.length - 2; i++) { - console.log( - proposals[i].attributes.createdAt, - proposals[i + 1].attributes.createdAt - ); const isValid = validationFn(proposals[i], proposals[i + 1]); expect(isValid).toBe(true); } From f4103a117ed26ec5faa6133a94e7467b50fc9c35 Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 10:38:15 +0545 Subject: [PATCH 11/45] test: update regex for budget proposals title matching --- .../playwright/tests/11-proposal-budget/proposalBudget.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts index 73fc89278..f88dfbcf0 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -19,7 +19,7 @@ test("11A. Should access budget proposal page in disconnect state", async ({ await budgetDiscussionPage.goto(); await expect( - budgetDiscussionPage.currentPage.getByText("/Budget Proposals/i") + budgetDiscussionPage.currentPage.getByText(/Budget Proposals/i) ).toHaveCount(2); }); From d22e479213f42255ed57f124aa6ac1752d8e7708 Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 12:03:57 +0545 Subject: [PATCH 12/45] chore: add mock data for budget proposal, polls and comments --- .../playwright/lib/_mock/budgetProposal.json | 171 ++++++++++++++++++ .../lib/_mock/budgetProposalComments.json | 66 +++++++ .../lib/_mock/budgetProposalPoll.json | 23 +++ 3 files changed, 260 insertions(+) create mode 100644 tests/govtool-frontend/playwright/lib/_mock/budgetProposal.json create mode 100644 tests/govtool-frontend/playwright/lib/_mock/budgetProposalComments.json create mode 100644 tests/govtool-frontend/playwright/lib/_mock/budgetProposalPoll.json diff --git a/tests/govtool-frontend/playwright/lib/_mock/budgetProposal.json b/tests/govtool-frontend/playwright/lib/_mock/budgetProposal.json new file mode 100644 index 000000000..af582a4ce --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/_mock/budgetProposal.json @@ -0,0 +1,171 @@ +{ + "data": { + "id": 49, + "attributes": { + "privacy_policy": true, + "intersect_named_administrator": true, + "prop_comments_number": 2, + "is_active": true, + "createdAt": "2025-03-31T12:08:38.908Z", + "updatedAt": "2025-04-01T08:09:46.924Z", + "intersect_admin_further_text": null, + "creator": { + "data": { + "id": 1300, + "attributes": { + "username": "e0d7ccd5f411be1bb732a3770fd4c79b74bd5fc75ac76bdfe73f2d8893", + "email": "e0d7ccd5f411be1bb732a3770fd4c79b74bd5fc75ac76bdfe73f2d8893@example.com", + "provider": "local", + "confirmed": true, + "blocked": false, + "govtool_username": "intersectadmin", + "createdAt": "2025-03-31T09:43:04.102Z", + "updatedAt": "2025-03-31T09:43:17.516Z" + } + } + }, + "bd_costing": { + "data": { + "id": 49, + "attributes": { + "ada_amount": "0", + "amount_in_preferred_currency": "300000", + "usd_to_ada_conversion_rate": "0", + "cost_breakdown": "25% up front, 75% on delivery.\n\nUp front: $75,000\nOn delivery: $225,000", + "createdAt": "2025-03-31T12:08:38.879Z", + "updatedAt": "2025-03-31T12:08:38.879Z", + "preferred_currency": { + "data": { + "id": 1, + "attributes": { + "currency_name": "United States Dollar", + "currency_letter_code": "USD", + "currency_number_code": "840", + "createdAt": "2025-03-31T08:49:25.530Z", + "updatedAt": "2025-03-31T08:49:25.530Z", + "publishedAt": "2025-03-31T08:49:25.529Z" + } + } + } + } + } + }, + "bd_proposal_detail": { + "data": { + "id": 49, + "attributes": { + "experience": "Wanchain has already deployed cross-chain value bridges to Cardano. Wanchain has also already deployed XPort on other networks.", + "proposal_name": "Deploy XPort, Wanchain's cross-chain data transfer protocol, to Cardano", + "key_dependencies": "No dependencies", + "maintain_and_support": "Wanchain will provide ongoing maintenance.", + "proposal_description": "Blockchain interoperability is essential for the growth and adoption of decentralized technologies. As a leading blockchain network, Cardano has established itself as a secure, scalable, and research-driven ecosystem. However, interoperability with other blockchains remains limited. Wanchain’s XPort protocol offers a decentralized, secure, and efficient cross-chain data transfer solution, making it an ideal candidate to bridge Cardano with external blockchain ecosystems. This proposal is for the deployment of XPort to Cardano, enabling seamless cross-chain data transfers between Cardano and other blockchain networks.\n\nAbout Cross-Chain Data Transfer Protocols\n\nCross-Chain Data Transfer Protocols enable data to be passed from one blockchain to another. Rather than only moving fungible and non-fungible tokens, which are a specific type of data structure, Cross-Chain Data Transfer Protocols can move any type of data. Importantly, Cross-Chain Data Transfer Protocols can feed data into 3rd party smart contracts to seamlessly execute on-chain logic and create novel cross-chain applications.\n\nThe basic flow of all Cross-Chain Data Transfers Protocols is as follows:\n\n- A user or smart contract records arbitrary data on the source chain\n- The off-chain component detects these data\n- The off-chain component records these data on the destination chain\n- A smart contract executes on-chain logic on the destination chain using these data\n\nAbout XPort\n\nTrue to its legacy, XPort is deceptively simple. It essentially just detects data on a source blockchain then exports it to the destination chain in the correct format.\n\nXPort is composed of two basic elements: one robust off-chain relayer and a set of rudimentary on-chain smart contracts called Cross-Chain Gateways.\n\n1. The off-chain relayer is the same Bridge Node Group that secures all cross-chain transactions executed using the Wanchain Bridge. These permissionless Bridge Nodes are rotated and re-elected monthly. They use Multiparty Computation and Shamir’s Secret Sharing cryptography to transfer messages and arbitrary data across chains.\n\n2. A smart contract, called a Cross-Chain Gateway, is deployed on each supported blockchain. These Cross-Chain Gateways have limited functionality — they can essentially only send and receive data. They serve as the point of contact for all 3rd party developers.\n\nImportantly, XPort is designed to be compliant with the Enterprise Ethereum Alliance’s Distributed Ledger Technology Interoperability Specification, co-authored by Wanchain’s VP on Engineering Dr. Weijia Zhang.\n\nMore technical information about XPort: https://docs.wanchain.org/latest-major-updates/xport-wanchains-cross-chain-data-transfer-protocol-development-handbook", + "key_proposal_deliverables": "- XPort interface definition adjustment to support Cardano\n\n- XPort deployed on Cardano Pre-Production\n\n- XPort deployed on Cardano Mainnet: developers will be able to build applications that seamlessly span multiple networks using XPort", + "resourcing_duration_estimates": "Budget: 400,000 USD\nTeam size: ~30\nDuration: 9 months", + "other_contract_type": "", + "createdAt": "2025-03-31T12:08:38.864Z", + "updatedAt": "2025-03-31T12:08:38.864Z", + "contract_type_name": { + "data": { + "id": 3, + "attributes": { + "contract_type_name": "Service Level Agreement", + "createdAt": "2025-03-31T08:49:37.711Z", + "updatedAt": "2025-03-31T08:49:37.711Z", + "publishedAt": "2025-03-31T08:49:37.710Z" + } + } + } + } + } + }, + "bd_further_information": { + "data": { + "id": 49, + "attributes": { + "createdAt": "2025-03-31T12:08:38.891Z", + "updatedAt": "2025-03-31T12:08:38.891Z", + "proposal_links": [] + } + } + }, + "bd_psapb": { + "data": { + "id": 49, + "attributes": { + "problem_statement": "Seamless cross-chain communication is a challenge for permissionless blockchains due to their inherent lack of interoperability. This limitation is rooted in their trustless nature, as blockchains need a mechanism to verify the authenticity of data before processing it. When dealing with heterogeneous blockchain networks, each with their own distinct ruleset and security guarantees, cross-chain communication is currently impossible without the intervention of an off-chain component.\n\nIn many ways, this problem is just the oracle problem. The oracle problem, for those who are unfamiliar, refers to a blockchain’s inability to access external data, rendering it isolated. An additional piece of infrastructure — whether you want to call it a bridge, an oracle or a relayer — is needed to connect the blockchain and the off-chain data. With cross-chain communication, the problem is the same. The data that needs to be accessed just happens to be on another blockchain!\n\nCross-Chain Data Transfer Protocols enable data to be passed from one blockchain to another. Rather than only moving fungible and non-fungible tokens, which are a specific type of data structure, Cross-Chain Data Transfer Protocols can move any type of data. Importantly, Cross-Chain Data Transfer Protocols can feed data into 3rd party smart contracts to seamlessly execute on-chain logic and create novel cross-chain applications.\n\nThis proposal is to deploy XPort, Wanchain's cross-chain data transfer protocol, to Cardano.", + "proposal_benefit": "Once deployed, XPort will allow arbitrary data to flow between Cardano, any EVM, and select non-EVM networks. This will enable developers to develop applications that span multiple blockchains. It will also empower developers to shift their focus from extracting value out of a blockchain to importing execution logic into one. \n\nOther potential benefits include but are not limited to:\n\n- Improved interoperability between Cardano and the of the industry\n- Expanded access to liquidity and assets on other chains\n- Greater abstraction to improve UX\n- Reduced bridge risk\n- Improved developer experience\n- More modular application design/New types of applications", + "supplementary_endorsement": "Wanchain is the longest running cross-chain bridge in the blockchain industry and is the primary cross-chain value bridge currently servicing the Cardano mainnet. It has received good support from the Cardano community (multiple approved Catalyst proposals) and Cardano Dapps (like Liqwid).", + "explain_proposal_roadmap": "", + "createdAt": "2025-03-31T12:08:38.846Z", + "updatedAt": "2025-03-31T12:08:38.846Z", + "committee_name": { + "data": { + "id": 2, + "attributes": { + "committee_name": "Product Committee", + "createdAt": "2025-03-31T08:50:27.431Z", + "updatedAt": "2025-03-31T08:50:27.431Z", + "publishedAt": "2025-03-31T08:50:27.429Z" + } + } + }, + "roadmap_name": { + "data": { + "id": 2, + "attributes": { + "roadmap_name": "Architectural Excellence", + "createdAt": "2025-03-31T08:49:40.879Z", + "updatedAt": "2025-03-31T08:49:40.879Z", + "publishedAt": "2025-03-31T08:49:40.877Z" + } + } + }, + "type_name": { + "data": { + "id": 6, + "attributes": { + "type_name": "Core", + "createdAt": "2025-03-31T10:40:44.559Z", + "updatedAt": "2025-03-31T10:40:45.976Z", + "publishedAt": "2025-03-31T10:40:45.971Z" + } + } + } + } + } + }, + "bd_proposal_ownership": { + "data": { + "id": 50, + "attributes": { + "agreed": true, + "group_name": "", + "company_name": "Wanchain", + "type_of_group": "", + "social_handles": "https://x.com/wanchain_org, https://x.com/TemujinLouie", + "submited_on_behalf": "Company", + "company_domain_name": "wanchain.org", + "proposal_public_champion": "Submission lead listed above", + "key_info_to_identify_group": "", + "createdAt": "2025-03-31T12:08:38.826Z", + "updatedAt": "2025-03-31T12:08:38.826Z", + "be_country": { + "data": { + "id": 32, + "attributes": { + "country_name": "British Virgin Islands", + "alfa_2_code": "VG", + "alfa_3_code": "VGB", + "createdAt": "2025-03-31T08:49:04.220Z", + "updatedAt": "2025-03-31T08:49:04.220Z", + "publishedAt": "2025-03-31T08:49:04.219Z" + } + } + } + } + } + } + } + }, + "meta": {} +} diff --git a/tests/govtool-frontend/playwright/lib/_mock/budgetProposalComments.json b/tests/govtool-frontend/playwright/lib/_mock/budgetProposalComments.json new file mode 100644 index 000000000..0668996f9 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/_mock/budgetProposalComments.json @@ -0,0 +1,66 @@ +{ + "data": [ + { + "id": 427, + "attributes": { + "proposal_id": null, + "comment_parent_id": null, + "user_id": "1187", + "comment_text": "test comment 2", + "createdAt": "2025-04-03T06:04:32.388Z", + "updatedAt": "2025-04-03T06:04:32.388Z", + "bd_proposal_id": "49", + "drep_id": "34b1eb01917db5d3f39757c94e85004c5e3d41462fd1d82da01264a9", + "comments_reports": { + "data": [] + }, + "user_govtool_username": "testeternl1", + "subcommens_number": 0 + } + }, + { + "id": 426, + "attributes": { + "proposal_id": null, + "comment_parent_id": null, + "user_id": "1187", + "comment_text": "test comment 1", + "createdAt": "2025-04-03T06:04:23.380Z", + "updatedAt": "2025-04-03T06:04:23.380Z", + "bd_proposal_id": "49", + "drep_id": "34b1eb01917db5d3f39757c94e85004c5e3d41462fd1d82da01264a9", + "comments_reports": { + "data": [] + }, + "user_govtool_username": "testeternl1", + "subcommens_number": 0 + } + }, + { + "id": 384, + "attributes": { + "proposal_id": null, + "comment_parent_id": null, + "user_id": "38", + "comment_text": "test comment", + "createdAt": "2025-04-01T08:09:39.135Z", + "updatedAt": "2025-04-01T08:09:39.135Z", + "bd_proposal_id": "49", + "drep_id": null, + "comments_reports": { + "data": [] + }, + "user_govtool_username": "testlace", + "subcommens_number": 1 + } + } + ], + "meta": { + "pagination": { + "page": 1, + "pageSize": 25, + "pageCount": 1, + "total": 3 + } + } +} diff --git a/tests/govtool-frontend/playwright/lib/_mock/budgetProposalPoll.json b/tests/govtool-frontend/playwright/lib/_mock/budgetProposalPoll.json new file mode 100644 index 000000000..82cd4f535 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/_mock/budgetProposalPoll.json @@ -0,0 +1,23 @@ +{ + "data": [ + { + "id": 48, + "attributes": { + "bd_proposal_id": "49", + "poll_yes": 0, + "poll_no": 0, + "is_poll_active": true, + "createdAt": "2025-03-31T12:08:38.928Z", + "updatedAt": "2025-03-31T12:08:38.928Z" + } + } + ], + "meta": { + "pagination": { + "page": 1, + "pageSize": 1, + "pageCount": 1, + "total": 1 + } + } +} From c1e0a0ae339c64f489431b99e691f95d0bf5243e Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 12:04:52 +0545 Subject: [PATCH 13/45] test: enhance budget proposal tests with comment viewing and access restrictions --- .../lib/pages/budgetDiscussionDetailsPage.ts | 17 ++++- .../11-proposal-budget/proposalBudget.spec.ts | 72 +++++++++++++++++-- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts index e3f09b7d0..936479c0c 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts @@ -1,13 +1,26 @@ -import { Page } from "@playwright/test"; +import { expect, Page } from "@playwright/test"; +import { CommentResponse } from "@types"; import environments from "lib/constants/environments"; export default class BudgetDiscussionDetailsPage { - // Buttons + // buttons readonly shareBtn = this.page.getByTestId("share-button"); readonly copyLinkBtn = this.page.getByTestId("copy-link"); + readonly commentBtn = this.page.getByTestId("comment-button"); + readonly replyBtn = this.page.getByTestId("reply-button"); + readonly replyCommentBtn = this.page.getByTestId("reply-comment-button"); + readonly pollYesBtn = this.page.getByTestId("poll-yes-button"); + readonly pollNoBtn = this.page.getByTestId("poll-no-button"); + readonly sortCommentsBtn = this.page.getByTestId("sort-comments"); // content readonly copyLinkText = this.page.getByTestId("copy-link-text"); + readonly pollVoteCard = this.page.getByTestId("poll-vote-card"); + readonly totalComments = this.page.getByTestId("total-comments"); + + // Input + readonly commentInput = this.page.getByTestId("comment-input"); + readonly replyInput = this.page.getByTestId("reply-input"); constructor(private readonly page: Page) {} diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts index f88dfbcf0..499ab7ca1 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -1,12 +1,18 @@ import environments from "@constants/environments"; +import { faker } from "@faker-js/faker"; import { test } from "@fixtures/walletExtension"; import { setAllureEpic } from "@helpers/allure"; import { injectLogger } from "@helpers/page"; import { extractProposalIdFromUrl } from "@helpers/string"; import { functionWaitedAssert } from "@helpers/waitedLoop"; +import BudgetDiscussionDetailsPage from "@pages/budgetDiscussionDetailsPage"; import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; import { expect } from "@playwright/test"; -import { BudgetProposalType } from "@types"; +import { BudgetProposalType, CommentResponse } from "@types"; + +const mockBudgetProposal = require("../../lib/_mock/budgetProposal.json"); +const mockPoll = require("../../lib/_mock/budgetProposalPoll.json"); +const mockComments = require("../../lib/_mock/budgetProposalComments.json"); test.beforeEach(async ({}) => { await setAllureEpic("11. Proposal Budget"); @@ -173,11 +179,65 @@ test("11D. Should share budget proposal", async ({ page, context }) => { expect(copiedTextDRepDirectory).toEqual(expectedCopyUrl); }); -test("11E. Should view comments with count indications on a budget proposal", async () => {}); +test("11E. Should view comments with count indications on a budget proposal", async ({ + page, +}) => { + let responsePromise = page.waitForResponse((response) => + response.url().includes(`/api/comments`) + ); + + const budgetDiscussionPage = new BudgetDiscussionPage(page); + await budgetDiscussionPage.goto(); -test.describe("Restricted access to interact budget proposal", () => { - test("11F_1. Should restrict users without wallets from commenting", async () => {}); - test("11F_2. Should restrict users without wallets from voting", async () => {}); + const budgetDiscussionDetailsPage = + await budgetDiscussionPage.viewFirstProposal(); + const response = await responsePromise; + + const comments: CommentResponse[] = (await response.json()).data; + + await responsePromise; + + await expect(budgetDiscussionDetailsPage.totalComments).toHaveText( + comments.length.toString() + ); }); -test("11G. Should sort the budget proposal comments", async ({}) => {}); +test.describe("Restricted access to interact budget proposal", () => { + let budgetDiscussionDetailsPage: BudgetDiscussionDetailsPage; + + test.beforeEach(async ({ page }) => { + await page.route("**/api/bds/**", async (route) => + route.fulfill({ + body: JSON.stringify(mockBudgetProposal), + }) + ); + + await page.route("**/api/bd-polls**", async (route) => + route.fulfill({ + body: JSON.stringify(mockPoll), + }) + ); + + await page.route("**/api/comments**", async (route) => + route.fulfill({ + body: JSON.stringify(mockComments), + }) + ); + + budgetDiscussionDetailsPage = new BudgetDiscussionDetailsPage(page); + await budgetDiscussionDetailsPage.goto(mockBudgetProposal.data.id); + }); + test("11F_1. Should restrict users without wallets from commenting", async () => { + await budgetDiscussionDetailsPage.commentInput.fill( + faker.lorem.paragraph() + ); + + await expect(budgetDiscussionDetailsPage.commentBtn).toBeDisabled(); + }); + test("11F_2. Should restrict users without wallets from voting", async () => { + await expect(budgetDiscussionDetailsPage.pollVoteCard).not.toBeVisible(); + await expect(budgetDiscussionDetailsPage.pollYesBtn).not.toBeVisible(); + + await expect(budgetDiscussionDetailsPage.pollNoBtn).not.toBeVisible(); + }); +}); From 515b07b9ed056fc261818c5050b9fe66b9547bdb Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 12:37:22 +0545 Subject: [PATCH 14/45] feat: add budgetProposal01Wallet and corresponding auth setup for budget proposals --- .../playwright/lib/constants/staticWallets.ts | 2 ++ tests/govtool-frontend/playwright/package.json | 2 +- .../govtool-frontend/playwright/tests/auth.setup.ts | 12 ++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts index b1b1edd5d..6026775b9 100644 --- a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts +++ b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts @@ -27,6 +27,8 @@ export const proposal07Wallet: StaticWallet = staticWallets[16]; export const proposal08Wallet: StaticWallet = staticWallets[17]; export const proposal09Wallet: StaticWallet = staticWallets[18]; +export const budgetProposal01Wallet: StaticWallet = staticWallets[19]; + export const adaHolderWallets = [ adaHolder01Wallet, adaHolder02Wallet, diff --git a/tests/govtool-frontend/playwright/package.json b/tests/govtool-frontend/playwright/package.json index dc24100b7..48f48a1f6 100644 --- a/tests/govtool-frontend/playwright/package.json +++ b/tests/govtool-frontend/playwright/package.json @@ -26,7 +26,7 @@ "test": "npx playwright test", "format": "prettier . --write", "test:outcomes": "npx playwright test outcomes.spec.ts --ui", - "generate-wallets": "ts-node ./generate_wallets.ts 19" + "generate-wallets": "ts-node ./generate_wallets.ts 20" }, "dependencies": { "@cardanoapi/cardano-test-wallet": "^3.0.0", diff --git a/tests/govtool-frontend/playwright/tests/auth.setup.ts b/tests/govtool-frontend/playwright/tests/auth.setup.ts index 136a74098..849e28a45 100644 --- a/tests/govtool-frontend/playwright/tests/auth.setup.ts +++ b/tests/govtool-frontend/playwright/tests/auth.setup.ts @@ -7,6 +7,7 @@ import { adaHolder04Wallet, adaHolder05Wallet, adaHolder06Wallet, + budgetProposal01Wallet, dRep01Wallet, dRep02Wallet, proposal01Wallet, @@ -51,6 +52,8 @@ const proposal07AuthFile = ".auth/proposal07.json"; const proposal08AuthFile = ".auth/proposal08.json"; const proposal09AuthFile = ".auth/proposal09.json"; +const budgetProposal01AuthFile = ".auth/budgetProposal01.json"; + setup.beforeEach(async () => { await setAllureEpic("Setup"); await setAllureStory("Authentication"); @@ -218,3 +221,12 @@ setup("Create Proposal 09 auth", async ({ page, context }) => { auth: proposal09AuthFile, }); }); + +setup("Create Budget Proposal 01 auth", async ({ page, context }) => { + await createAuthWithUserName({ + page, + context, + wallet: budgetProposal01Wallet, + auth: budgetProposal01AuthFile, + }); +}); From e744b15b9ffb5d2879b8a9f479ce3912cf50b609 Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 12:38:53 +0545 Subject: [PATCH 15/45] test: budget discussion page login user functionality --- .../lib/pages/budgetDiscussionDetailsPage.ts | 39 ++++++++++ .../govtool-frontend/playwright/lib/types.ts | 3 + .../proposalBudget.loggedin.spec.ts | 71 +++++++++++++++++-- .../11-proposal-budget/proposalBudget.spec.ts | 2 + 4 files changed, 109 insertions(+), 6 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts index 936479c0c..13421ae3a 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts @@ -33,4 +33,43 @@ export default class BudgetDiscussionDetailsPage { `${environments.frontendUrl}/budget_discussion/${proposalId}` ); } + + async sortAndValidate( + order: string, + validationFn: (date1: string, date2: string) => boolean + ) { + const responsePromise = this.page.waitForResponse((response) => + response.url().includes(`&sort[createdAt]=${order}`) + ); + + await this.sortCommentsBtn.click(); + const response = await responsePromise; + + const comments: CommentResponse[] = (await response.json()).data; + + // API validation + for (let i = 0; i < comments.length - 1; i++) { + const isValid = validationFn( + comments[i].attributes.updatedAt, + comments[i + 1].attributes.updatedAt + ); + expect(isValid).toBe(true); + } + } + + async addComment(comment: string) { + await this.commentInput.fill(comment); + ``; + await this.commentBtn.click(); + } + + async replyComment(reply: string) { + await this.page + .locator('[data-testid^="comment-"][data-testid$="-content-card"]') + .first() + .getByTestId("reply-button") + .click(); + await this.replyInput.fill(reply); + await this.replyCommentBtn.click(); + } } diff --git a/tests/govtool-frontend/playwright/lib/types.ts b/tests/govtool-frontend/playwright/lib/types.ts index 9aead83cb..a51363a3c 100644 --- a/tests/govtool-frontend/playwright/lib/types.ts +++ b/tests/govtool-frontend/playwright/lib/types.ts @@ -166,6 +166,9 @@ export type CommentResponse = { comment_text: string; createdAt: string; updatedAt: string; + bd_proposal_id: string | null; + drep_id: string | null; + comments_reports: any; user_govtool_username: string; subcommens_number: number; }; diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.spec.ts index 187ec9091..e73882eac 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.spec.ts @@ -1,14 +1,73 @@ +import { budgetProposal01Wallet } from "@constants/staticWallets"; +import { faker } from "@faker-js/faker"; import { test } from "@fixtures/walletExtension"; import { setAllureEpic } from "@helpers/allure"; -import { skipTestForProposalBudget } from "@helpers/cardano"; +import BudgetDiscussionDetailsPage from "@pages/budgetDiscussionDetailsPage"; +import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; +import { expect } from "@playwright/test"; -test.beforeEach(async ({}) => { +test.beforeEach(async () => { await setAllureEpic("11. Proposal Budget"); - await skipTestForProposalBudget(); }); -test("11H. Should restrict non registered DRep users from voting", async () => {}); +test.describe("Budget proposal logged in state", () => { + test.use({ + storageState: ".auth/budgetProposal01.json", + wallet: budgetProposal01Wallet, + }); -test("11I. Should comments on any proposal", async ({}) => {}); + let budgetDiscussionDetailsPage: BudgetDiscussionDetailsPage; -test("11J. Should reply to any comments", async ({}) => {}); + test.beforeEach(async ({ page }) => { + const budgetDiscussionPage = new BudgetDiscussionPage(page); + await budgetDiscussionPage.goto(); + await budgetDiscussionPage.verifyIdentityBtn.click(); + budgetDiscussionDetailsPage = + await budgetDiscussionPage.viewFirstProposal(); + }); + + test("11G. Should sort the budget proposal comments", async ({ page }) => { + for (let i = 0; i < 4; i++) { + const comment = faker.lorem.paragraph(2); + await budgetDiscussionDetailsPage.addComment(comment); + await page.waitForTimeout(2_000); + } + await budgetDiscussionDetailsPage.sortAndValidate( + "asc", + (date1, date2) => new Date(date1) <= new Date(date2) + ); + }); + + test("11H. Should restrict non registered DRep users from voting", async () => { + // wait for the page to load + await budgetDiscussionDetailsPage.currentPage.waitForTimeout(5_000); + + await expect(budgetDiscussionDetailsPage.pollVoteCard).not.toBeVisible(); + await expect(budgetDiscussionDetailsPage.pollYesBtn).not.toBeVisible(); + + await expect(budgetDiscussionDetailsPage.pollNoBtn).not.toBeVisible(); + }); + + test("11I. Should comments on any proposal", async ({}) => { + const comment = faker.lorem.paragraph(2); + await budgetDiscussionDetailsPage.addComment(comment); + await expect( + budgetDiscussionDetailsPage.currentPage + .locator('[data-testid^="comment-"][data-testid$="-content"]') + .first() + ).toHaveText(comment); + }); + + test("11J. Should reply to any comments", async ({}) => { + const randComment = faker.lorem.paragraph(2); + const randReply = faker.lorem.words(5); + + await budgetDiscussionDetailsPage.addComment(randComment); + + await budgetDiscussionDetailsPage.replyComment(randReply); + const replyRendered = await budgetDiscussionDetailsPage.currentPage + .locator(`[data-testid^="reply-"][data-testid$="-content"]`) + .textContent(); + expect(replyRendered).toContain(randReply); + }); +}); diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts index 499ab7ca1..7fe7d33e2 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -235,6 +235,8 @@ test.describe("Restricted access to interact budget proposal", () => { await expect(budgetDiscussionDetailsPage.commentBtn).toBeDisabled(); }); test("11F_2. Should restrict users without wallets from voting", async () => { + // wait for the page to load + await budgetDiscussionDetailsPage.currentPage.waitForTimeout(5_000); await expect(budgetDiscussionDetailsPage.pollVoteCard).not.toBeVisible(); await expect(budgetDiscussionDetailsPage.pollYesBtn).not.toBeVisible(); From ec593ae0cab5d7e22b0f7456e25b62a8ed1a5c3c Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 16:07:10 +0545 Subject: [PATCH 16/45] chore: add budget discussion submission page with createBudgetProposal --- .../lib/pages/budgetDiscussionPage.ts | 6 +- .../pages/budgetDiscussionSubmissionPage.ts | 537 ++++++++++++++++++ .../govtool-frontend/playwright/lib/types.ts | 185 +++++- 3 files changed, 724 insertions(+), 4 deletions(-) create mode 100644 tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts index 144c3c02f..bfc46e193 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts @@ -1,6 +1,6 @@ import { functionWaitedAssert, waitedLoop } from "@helpers/waitedLoop"; import { expect, Locator, Page } from "@playwright/test"; -import { BudgetProposalType, ProposedGovAction } from "@types"; +import { BudgetDiscussionEnum, ProposedGovAction } from "@types"; import environments from "lib/constants/environments"; import BudgetDiscussionDetailsPage from "./budgetDiscussionDetailsPage"; @@ -56,8 +56,8 @@ export default class BudgetDiscussionPage { async clickRadioButtonsByNames(names: string[]) { for (const name of names) { - const budgetProposalValue = Object.values(BudgetProposalType).includes( - name as BudgetProposalType + const budgetProposalValue = Object.values(BudgetDiscussionEnum).includes( + name as BudgetDiscussionEnum ); if (budgetProposalValue) { await this.page.getByTestId(`${name.toLowerCase()}-radio`).click(); diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts new file mode 100644 index 000000000..73171ad29 --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts @@ -0,0 +1,537 @@ +import environments from "@constants/environments"; +import { fa, faker } from "@faker-js/faker"; +import { extractProposalIdFromUrl } from "@helpers/string"; +import { Page, expect } from "@playwright/test"; +import { + AdministrationAndAuditingProps, + BudgetCostingProps, + BudgetDiscussionEnum, + BudgetProposalContactInformationProps, + BudgetProposalDetailsProps, + BudgetProposalOwnershipProps, + BudgetProposalProblemStatementAndBenefitProps, + BudgetProposalProps, + CommitteeAlignmentEnum, + CompanyEnum, + LocationEnum, + PreferredCurrencyEnum, + ProposalChampionEnum, + ProposalContractingEnum, + ProposalLink, + RoadmapNameEnum, +} from "@types"; + +const formErrors = { + proposalTitle: "title-input-error", + abstract: "abstract-helper-error", + motivation: "motivation-helper-error", + rationale: "rationale-helper-error", + receivingAddress: "receiving-address-0-text-error", + amount: "amount-0-text-error", + constitutionalUrl: "prop-constitution-url-text-error", + guardrailsScriptUrl: "prop-guardrails-script-url-input-error", + link: "link-0-url-input-error", +}; + +export default class BudgetDiscussionSubmissionPage { + // buttons + readonly skipBtn = this.page.getByTestId("skip-button"); + readonly createBudgetProposalBtn = this.page.getByTestId( + "propose-a-budget-discussion-button" + ); + + readonly continueBtn = this.page.getByTestId("continue-button"); + readonly addLinkBtn = this.page.getByTestId("add-link-button"); + readonly verifyIdentityBtn = this.page.getByTestId("verify-identity-button"); + readonly saveDraftBtn = this.page.getByTestId("save-draft-button"); + readonly submitBtn = this.page.getByTestId("submit-button"); + readonly countryOfIncorporationBtn = this.page.getByTestId( + "country-of-incorporation" + ); + + 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 + + // input + readonly linkTextInput = this.page.getByTestId("link-0-text-input"); + readonly linkUrlInput = this.page.getByTestId("link-0-url-input"); + + // contact-information + readonly beneficiaryFullNameInput = this.page.getByLabel( + "Beneficiary Full Name *" + ); //BUG missing test Ids + readonly beneficiaryEmailInput = this.page.getByLabel("Beneficiary e-mail *"); //BUG missing test Ids + readonly submissionLeadFullNameInput = this.page.getByLabel( + "Submission Lead Full Name *" + ); //BUG missing test Ids + readonly submissionLeadEmailInput = this.page.getByLabel( + "Submission Lead Email *" + ); //BUG missing test Ids + + // proposal-ownership + readonly companyNameInput = this.page.getByLabel("Company Name *"); //BUG missing test Ids + readonly companyDomainName = this.page.getByLabel("Company Domain Name *"); //BUG missing test Ids + readonly groupNameInput = this.page.getByLabel("Group Name *"); //BUG missing test Ids + readonly groupTypeInput = this.page.getByLabel("Type of Group *"); //BUG missing test Ids + readonly keyInformationOfGroupInput = this.page.getByLabel( + "Key Information to Identify" + ); //BUG missing test Ids + readonly contactDetailsInput = this.page.getByLabel( + "Please provide your preferred" + ); //BUG missing test Ids + + // problem-statements + readonly problemStatementInput = this.page.getByTestId( + "problem-statement-input" + ); + readonly proposalBenefitInput = this.page.getByTestId( + "proposal-benefit-input" + ); + readonly suplimentaryEndorsementInput = this.page.getByTestId( + "supplementary-endorsement-input" + ); + readonly productRoadmapDescriptionInput = this.page.getByLabel( + "Please explain how your" + ); // BUG missing test Ids + + // proposal-details + readonly proposalNameInput = this.page.getByLabel( + "What is your proposed name to" + ); //BUG missing testId + readonly proposalDescriptionInput = this.page.getByTestId( + "proposal-description-input" + ); + readonly proposalKeyDependenciesInput = this.page.getByTestId( + "key-dependencies-input" + ); + readonly proposalMaintainAndSupportInput = this.page.getByLabel( + "How will this proposal be" + ); //BUG missing testId + readonly milestonesInput = this.page.getByTestId( + "key-proposal-deliverables-input" + ); + readonly teamSizeAndDurationInput = this.page.getByTestId( + "resourcing-duration-estimates-input" + ); + readonly previousExperienceInput = this.page.getByLabel( + "Please provide previous" + ); //BUG missing testId + readonly otherDescriptionInput = this.page.getByLabel( + "Please describe what you have" + ); + + // costing + readonly adaAmountInput = this.page.getByLabel("ADA Amount *"); //BUG missing test Ids + readonly usaToAdaCnversionRateInput = this.page.getByLabel( + "USD to ADA Conversion Rate *" + ); //BUG missing test Ids + readonly preferredCurrencyAmountInput = this.page.getByLabel( + "Amount in preferred currency *" + ); + readonly costBreakdownInput = this.page.getByTestId("cost-breakdown-input"); + readonly venderDetailsInput = this.page.getByLabel("Please provide further"); //BUG missing test Ids + + // select + readonly beneficiaryCountrySelect = this.page.getByTestId( + "beneficiary-country-of-residence" + ); + readonly beneficiaryNationalitySelect = this.page.getByTestId( + "beneficiary-nationality" + ); + + readonly companyTypeSelect = this.page.getByTestId("beneficiary-nationality"); //BUG wrong test id + readonly publicChampion = this.page.getByTestId("proposal-public-champion"); + + readonly roadmapNameSelect = this.page.getByTestId("roadmap-name"); + readonly budgetDiscussionTypeSelect = this.page.getByTestId( + "budget-discussion-type-name" + ); + readonly committeeAlignmentTypeSelect = this.page.getByTestId( + "committee-alignment-type" + ); + + readonly contractingTypeSelect = this.page.getByTestId("contract-type-name"); + readonly preferredCurrencySelect = + this.page.getByTestId("preferred-currency"); + + readonly intersectNamedAdministratorSelect = this.page.getByTestId( + "itersect-named-administrator" + ); + + // content + readonly linkTextContent = this.page.getByTestId("link-0-text-content"); + readonly linkUrlContent = this.page.getByTestId("link-0-url-content"); + + constructor(private readonly page: Page) {} + + async goto() { + await this.page.goto(`${environments.frontendUrl}/budget_discussion`); + + await this.verifyIdentityBtn.click(); + await this.createBudgetProposalBtn.click(); + + await this.continueBtn.click(); + } + + async fillupContactInformationForm( + contactInformation: BudgetProposalContactInformationProps + ) { + await this.beneficiaryFullNameInput.fill( + contactInformation.beneficiaryFullName + ); + await this.beneficiaryEmailInput.fill(contactInformation.beneficiaryEmail); + await this.beneficiaryCountrySelect.click(); + await this.page + .getByTestId( + `${contactInformation.beneficiaryCountry.toLowerCase()}-button` + ) + .click(); + await this.beneficiaryNationalitySelect.click(); + await this.page + .getByRole("option", { name: contactInformation.beneficiaryNationality }) + .click(); + + await this.submissionLeadFullNameInput.fill( + contactInformation.submissionLeadFullName + ); + await this.submissionLeadEmailInput.fill( + contactInformation.submissionLeadEmail + ); + + await this.continueBtn.click(); + } + + async fillupProposalOwnershipForm( + proposalOwnership: BudgetProposalOwnershipProps + ) { + await this.companyTypeSelect.click(); + await this.page + .getByRole("option", { name: proposalOwnership.companyType }) + .click(); //BUG missing testId + + await this.publicChampion.click(); + await this.page + .getByRole("option", { name: proposalOwnership.publicChampion }) + .click(); //BUG missing testId + + await this.contactDetailsInput.fill(proposalOwnership.contactDetails); + + if (proposalOwnership.companyType === "Group") { + await this.groupNameInput.fill(proposalOwnership.groupName); + await this.groupTypeInput.fill(proposalOwnership.groupType); + await this.keyInformationOfGroupInput.fill( + proposalOwnership.groupKeyIdentity + ); + } + if (proposalOwnership.companyType === "Company") { + await this.companyNameInput.fill(proposalOwnership.companyName); + await this.companyDomainName.fill(proposalOwnership.companyDomainName); + await this.countryOfIncorporationBtn.click(); + await this.page + .getByTestId( + `${proposalOwnership.countryOfIncorportation.toLowerCase()}-button` + ) + .click(); + } + await this.agreeCheckbox.click(); + + await this.continueBtn.click(); + } + + async fillupProblemStatementAndBenefitsForm( + problemStatementAndBenefits: BudgetProposalProblemStatementAndBenefitProps + ) { + await this.problemStatementInput.fill( + problemStatementAndBenefits.problemStatement + ); + await this.proposalBenefitInput.fill( + problemStatementAndBenefits.proposalBenefits + ); + await this.suplimentaryEndorsementInput.fill( + problemStatementAndBenefits.suplimentaryEndorsement + ); + + await this.roadmapNameSelect.click(); + await this.page + .getByTestId( + `${problemStatementAndBenefits.roadmapName.toLowerCase()}-button` + ) + .click(); + + if ( + problemStatementAndBenefits.roadmapName === + "It supports the product roadmap" + ) { + await this.productRoadmapDescriptionInput.fill( + problemStatementAndBenefits.productRoadmapDescription + ); + } + + await this.budgetDiscussionTypeSelect.click(); + await this.page + .getByTestId( + `${problemStatementAndBenefits.budgetDiscussionType.toLowerCase()}-button` + ) + .click(); + + await this.committeeAlignmentTypeSelect.click(); + await this.page + .getByTestId( + `${problemStatementAndBenefits.committeeAlignmentType.toLowerCase()}-button` + ) + .click(); + + await this.continueBtn.click(); + } + + async fillupProposalDetailsForm(proposalDetails: BudgetProposalDetailsProps) { + await this.proposalNameInput.fill(proposalDetails.proposalName); + await this.proposalDescriptionInput.fill( + proposalDetails.proposalDescription + ); + await this.proposalKeyDependenciesInput.fill( + proposalDetails.proposalKeyDependencies + ); + await this.proposalMaintainAndSupportInput.fill( + proposalDetails.proposalMaintainAndSupport + ); + await this.milestonesInput.fill(proposalDetails.milestones); + await this.teamSizeAndDurationInput.fill( + proposalDetails.teamSizeAndDuration + ); + await this.previousExperienceInput.fill(proposalDetails.previousExperience); + + await this.contractingTypeSelect.click(); + await this.page + .getByTestId(`${proposalDetails.contracting.toLowerCase()}-button`) + .click(); + if (proposalDetails.contracting === "Other") { + await this.otherDescriptionInput.fill(proposalDetails.otherDescription); + } + await this.continueBtn.click(); + } + + async fillupCostingForm(costing: BudgetCostingProps) { + await this.adaAmountInput.fill(costing.adaAmount.toString()); + await this.usaToAdaCnversionRateInput.fill( + costing.usaToAdaCnversionRate.toString() + ); + await this.preferredCurrencySelect.click(); + await this.page + .getByTestId(`${costing.preferredCurrency.toLowerCase()}-button`) + .click(); + await this.preferredCurrencyAmountInput.fill( + costing.AmountInPreferredCurrency.toString() + ); + await this.costBreakdownInput.fill(costing.costBreakdown); + + await this.continueBtn.click(); + } + + async fillupFurtherInformation(proposal_links: Array) { + for (let i = 0; i < proposal_links.length; i++) { + if (i > 0) { + await this.addLinkBtn.click(); + } + await this.page + .getByTestId(`link-${i}-url-input`) + .fill(proposal_links[i].prop_link); + await this.page + .getByTestId(`link-${i}-text-input`) + .fill(proposal_links[i].prop_link_text); + } + await this.continueBtn.click(); + } + + async fillupForm(budgetProposal: BudgetProposalProps) { + await this.fillupContactInformationForm(budgetProposal.contactInformation); + + await this.fillupProposalOwnershipForm(budgetProposal.proposalOwnership); + + await this.fillupProblemStatementAndBenefitsForm( + budgetProposal.problemStatementAndBenefits + ); + + await this.fillupProposalDetailsForm(budgetProposal.proposalDetails); + await this.fillupCostingForm(budgetProposal.costing); + await this.fillupFurtherInformation(budgetProposal.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 + ); + } + await this.continueBtn.click(); + + await this.submitCheckbox.click(); + await this.continueBtn.click(); + } + + async getAllDrafts() { + await expect( + this.page.locator('[data-testid^="draft-"][data-testid$="-card"]') + ).toBeVisible({ timeout: 60_000 }); // slow rendering + + return await this.page + .locator('[data-testid^="draft-"][data-testid$="-card"]') + .all(); + } + + async getFirstDraft() { + await expect( + this.page.locator('[data-testid^="draft-"][data-testid$="-card"]').first() + ).toBeVisible({ timeout: 60_000 }); // slow rendering + + return this.page + .locator('[data-testid^="draft-"][data-testid$="-card"]') + .first(); + } + + async viewFirstDraft() { + await expect( + this.page.locator('[data-testid^="draft-"][data-testid$="-card"]') + ).toBeVisible({ timeout: 60_000 }); // slow rendering + + return await this.page + .locator('[data-testid^="draft-"][data-testid$="-start-editing"]') + .first() + .click(); + } + + generateValidBudgetProposalContactInformation(): BudgetProposalContactInformationProps { + return { + beneficiaryFullName: faker.person.fullName(), + beneficiaryEmail: faker.internet.email(), + beneficiaryCountry: faker.helpers.arrayElement( + Object.values(LocationEnum) + ), + beneficiaryNationality: faker.helpers.arrayElement( + Object.values(LocationEnum) + ), + submissionLeadFullName: faker.person.fullName(), + submissionLeadEmail: faker.internet.email(), + }; + } + + generateValidBudgetProposalProblemStatementAndBenefits(): BudgetProposalProblemStatementAndBenefitProps { + return { + problemStatement: faker.lorem.paragraph(2), + proposalBenefits: faker.lorem.paragraph(2), + roadmapName: faker.helpers.arrayElement(Object.values(RoadmapNameEnum)), + budgetDiscussionType: faker.helpers.arrayElement( + Object.values(BudgetDiscussionEnum).filter( + (type) => type !== "No Category" + ) + ), + productRoadmapDescription: faker.lorem.paragraph(2), + committeeAlignmentType: faker.helpers.arrayElement( + Object.values(CommitteeAlignmentEnum) + ), + suplimentaryEndorsement: faker.lorem.paragraph(2), + }; + } + + generateValidProposalOwnerShip(): BudgetProposalOwnershipProps { + return { + companyType: faker.helpers.arrayElement(Object.values(CompanyEnum)), + publicChampion: faker.helpers.arrayElement( + Object.values(ProposalChampionEnum) + ), + contactDetails: faker.internet.email(), + groupName: faker.company.name(), + groupType: faker.company.buzzVerb(), + groupKeyIdentity: faker.lorem.paragraph(2), + companyName: faker.company.name(), + companyDomainName: faker.internet.domainName(), + countryOfIncorportation: faker.helpers.arrayElement( + Object.values(LocationEnum) + ), + }; + } + + generateValidBudgetProposalDetails(): BudgetProposalDetailsProps { + return { + proposalName: faker.lorem.words(3), + proposalDescription: faker.lorem.paragraph(2), + proposalKeyDependencies: faker.lorem.paragraph(1), + proposalMaintainAndSupport: faker.lorem.paragraph(2), + milestones: faker.lorem.lines(2), + teamSizeAndDuration: faker.lorem.paragraph(2), + previousExperience: faker.lorem.paragraph(2), + contracting: faker.helpers.arrayElement( + Object.values(ProposalContractingEnum) + ), + otherDescription: faker.lorem.paragraph(2), + }; + } + + generateValidCosting(): BudgetCostingProps { + return { + adaAmount: faker.number.int({ min: 100, max: 10000 }), + usaToAdaCnversionRate: faker.number.int({ min: 1, max: 100 }), + preferredCurrency: faker.helpers.arrayElement( + Object.values(PreferredCurrencyEnum) + ), + AmountInPreferredCurrency: faker.number.int({ min: 1, max: 100 }), + costBreakdown: faker.lorem.paragraph(2), + }; + } + + generateValidFurtherInformation(): Array { + return [ + { + prop_link: faker.internet.url(), + prop_link_text: faker.lorem.words(2), + }, + { + prop_link: faker.internet.url(), + prop_link_text: faker.lorem.words(2), + }, + ]; + } + + generateAdministrationAndAuditing(): AdministrationAndAuditingProps { + return { + intersectAdministration: faker.datatype.boolean(), + venderDetails: faker.lorem.paragraph(2), + }; + } + + generateValidBudgetProposalInformation(): BudgetProposalProps { + return { + contactInformation: this.generateValidBudgetProposalContactInformation(), + proposalOwnership: this.generateValidProposalOwnerShip(), + problemStatementAndBenefits: + this.generateValidBudgetProposalProblemStatementAndBenefits(), + proposalDetails: this.generateValidBudgetProposalDetails(), + costing: this.generateValidCosting(), + furtherInformation: this.generateValidFurtherInformation(), + administrationAndAuditing: this.generateAdministrationAndAuditing(), + }; + } + + async createBudgetProposal(): Promise { + const budgetProposalRequest: BudgetProposalProps = + this.generateValidBudgetProposalInformation(); + + await this.fillupForm(budgetProposalRequest); + await this.continueBtn.click(); // BUG incorrect test id -> submit-button + + // assert to check if the proposal is created and navigated to details page + await expect(this.page.getByTestId("review-version")).toBeVisible({ + timeout: 60_000, + }); + + const currentPageUrl = this.page.url(); + return extractProposalIdFromUrl(currentPageUrl); + } +} diff --git a/tests/govtool-frontend/playwright/lib/types.ts b/tests/govtool-frontend/playwright/lib/types.ts index a51363a3c..ffb225fb4 100644 --- a/tests/govtool-frontend/playwright/lib/types.ts +++ b/tests/govtool-frontend/playwright/lib/types.ts @@ -327,10 +327,193 @@ export interface InvalidMetadataType { hash: string; } -export enum BudgetProposalType { +export enum BudgetDiscussionEnum { Core = "Core", Research = "Research", GovernanceSupport = "Governance Support", MarketingAndInnovation = "Marketing & Innovation", NoCategory = "No Category", } + +export interface BudgetProposalContactInformationProps { + beneficiaryFullName: string; + beneficiaryEmail: string; + beneficiaryCountry: string; + beneficiaryNationality: string; + submissionLeadFullName: string; + submissionLeadEmail: string; +} + +export type CompanyType = "Individual" | "Company" | "Group"; +export enum CompanyEnum { + Individual = "Individual", + Company = "Company", + Group = "Group", +} + +export type ProposalChampionType = + | "Beneficiary listed above" + | "Submission lead listed above"; +export enum ProposalChampionEnum { + BeneficiaryListedAbove = "Beneficiary listed above", + SubmissionLeadListedAbove = "Submission lead listed above", +} + +export interface BudgetProposalOwnershipProps { + companyType: CompanyType; + publicChampion: ProposalChampionType; + contactDetails: string; + groupName?: string; + groupType?: string; + groupKeyIdentity?: string; + companyName?: string; + companyDomainName?: string; + countryOfIncorportation?: string; +} + +export type RoadmapNameType = + | "Scaling the L1 Engine" + | "Architectural Excellence" + | "Leios" + | "Incoming Liquidity" + | "L2 Expansion" + | "Programmable Assets" + | "Multiple Node Implementations" + | "SPO Incentive Improvements" + | "It doesn't align" + | "It supports the product roadmap" + | "Developer / User Experience"; + +export enum RoadmapNameEnum { + ScalingTheL1Engine = "Scaling the L1 Engine", + ArchitecturalExcellence = "Architectural Excellence", + Leios = "Leios", + IncomingLiquidity = "Incoming Liquidity", + L2Expansion = "L2 Expansion", + ProgrammableAssets = "Programmable Assets", + MultipleNodeImplementations = "Multiple Node Implementations", + SPOIncentiveImprovements = "SPO Incentive Improvements", + NoAlignment = "It doesn't align", + SupportsProductRoadmap = "It supports the product roadmap", + DeveloperUserExperience = "Developer / User Experience", +} + +export type BudgetDiscussionType = + | "Core" + | "Research" + | "Governance Support" + | "Marketing & Innovation" + | "None of these"; + +export enum CommitteeAlignmentEnum { + TechnicalSteeringCommittee = "Technical Steering Committee", + ProductCommittee = "Product Committee", + OpenSourceCommittee = "Open Source Committee", + CivicsCommittee = "Civics Committee", + MembershipAndCommunityCommittee = "Membership & Community Committee", + BudgetCommittee = "Budget Committee", + MarketingCommittee = "Marketing Committee", + Unsure = "Unsure", + None = "None", +} + +export type CommitteeAlignmentType = + | "Technical Steering Committee" + | "Product Committee" + | "Open Source Committee" + | "Civics Committee" + | "Membership & Community Committee" + | "Budget Committee" + | "Marketing Committee" + | "Unsure" + | "None"; + +export enum LocationEnum { + Nepal = "Nepal", + Netherlands = "Netherlands", + UnitedStates = "United States", + UnitedKingdom = "United Kingdom", + Canada = "Canada", + Australia = "Australia", + Germany = "Germany", + France = "France", + Japan = "Japan", + SouthKorea = "South Korea", +} + +export interface BudgetProposalProblemStatementAndBenefitProps { + problemStatement: string; + proposalBenefits: string; + roadmapName: RoadmapNameType; + productRoadmapDescription?: string; + budgetDiscussionType: BudgetDiscussionType; + committeeAlignmentType: CommitteeAlignmentType; + suplimentaryEndorsement: string; +} + +export type ProposalContractingType = + | "Milestone Based Fixed Price" + | "Time and Materials" + | "Service Level Agreement" + | "Other" + | "Reimbursement" + | "Intersect Procurement Process"; + +export enum ProposalContractingEnum { + MilestoneBasedFixedPrice = "Milestone Based Fixed Price", + TimeAndMaterials = "Time and Materials", + ServiceLevelAgreement = "Service Level Agreement", + Other = "Other", + Reimbursement = "Reimbursement", + IntersectProcurementProcess = "Intersect Procurement Process", +} + +export interface BudgetProposalDetailsProps { + proposalName: string; + proposalDescription: string; + proposalKeyDependencies: string; + proposalMaintainAndSupport: string; + milestones: string; + teamSizeAndDuration: string; + previousExperience: string; + contracting: ProposalContractingType; + otherDescription?: string; +} + +export type preferredCurrencyType = + | "United States Dollar" + | "Euro" + | "Japanese Yen" + | "Australian Dollar" + | "Nepalese Rupee"; + +export enum PreferredCurrencyEnum { + UnitedStatesDollar = "United States Dollar", + Euro = "Euro", + JapaneseYen = "Japanese Yen", + AustralianDollar = "Australian Dollar", + NepaleseRupee = "Nepalese Rupee", +} + +export interface BudgetCostingProps { + adaAmount: number; + usaToAdaCnversionRate: number; + preferredCurrency: preferredCurrencyType; + AmountInPreferredCurrency: number; + costBreakdown: string; +} + +export interface AdministrationAndAuditingProps { + intersectAdministration: boolean; + venderDetails: string; +} + +export interface BudgetProposalProps { + contactInformation: BudgetProposalContactInformationProps; + proposalOwnership: BudgetProposalOwnershipProps; + problemStatementAndBenefits: BudgetProposalProblemStatementAndBenefitProps; + proposalDetails: BudgetProposalDetailsProps; + costing: BudgetCostingProps; + furtherInformation: Array; + administrationAndAuditing: AdministrationAndAuditingProps; +} From bd0a5cbefe1fd7f58b89f70d126d329618362be3 Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 16:07:37 +0545 Subject: [PATCH 17/45] feat: add budget proposal fixture --- .../playwright/lib/fixtures/budgetProposal.ts | 35 +++++++++++++++++++ .../lib/pages/budgetDiscussionDetailsPage.ts | 8 +++++ 2 files changed, 43 insertions(+) create mode 100644 tests/govtool-frontend/playwright/lib/fixtures/budgetProposal.ts diff --git a/tests/govtool-frontend/playwright/lib/fixtures/budgetProposal.ts b/tests/govtool-frontend/playwright/lib/fixtures/budgetProposal.ts new file mode 100644 index 000000000..da0bf956e --- /dev/null +++ b/tests/govtool-frontend/playwright/lib/fixtures/budgetProposal.ts @@ -0,0 +1,35 @@ +import { budgetProposal01Wallet } from "@constants/staticWallets"; +import { test as base } from "@fixtures/walletExtension"; +import { createNewPageWithWallet } from "@helpers/page"; +import BudgetDiscussionDetailsPage from "@pages/budgetDiscussionDetailsPage"; +import BudgetDiscussionSubmissionPage from "@pages/budgetDiscussionSubmissionPage"; + +type TestOptions = { + proposalId: number; +}; + +export const test = base.extend({ + proposalId: async ({ browser }, use) => { + // setup + const budgetProposalPage = await createNewPageWithWallet(browser, { + storageState: ".auth/budgetProposal01.json", + wallet: budgetProposal01Wallet, + }); + + const budgetProposalCreationPage = new BudgetDiscussionSubmissionPage( + budgetProposalPage + ); + await budgetProposalCreationPage.goto(); + + const proposalId = await budgetProposalCreationPage.createBudgetProposal(); + + const budgetProposalDetailsPage = new BudgetDiscussionDetailsPage( + budgetProposalPage + ); + + await use(proposalId); + + // cleanup + await budgetProposalDetailsPage.deleteProposal(); + }, +}); diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts index 13421ae3a..cde23e911 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts @@ -72,4 +72,12 @@ export default class BudgetDiscussionDetailsPage { await this.replyInput.fill(reply); await this.replyCommentBtn.click(); } + + async deleteProposal() { + await this.page.waitForTimeout(2_000); + + await this.page.getByTestId("menu-button").click(); + await this.page.getByTestId("delete-proposal").click(); + await this.page.getByTestId("delete-proposal-yes-button").click(); + } } From 5adc882ebc73e586b0677fe97baea2d99f3fe28c Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 16:07:55 +0545 Subject: [PATCH 18/45] fix: update budget proposal type references to use BudgetDiscussionEnum --- .../tests/11-proposal-budget/proposalBudget.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts index 7fe7d33e2..28aa18e6c 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -8,7 +8,7 @@ import { functionWaitedAssert } from "@helpers/waitedLoop"; import BudgetDiscussionDetailsPage from "@pages/budgetDiscussionDetailsPage"; import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; import { expect } from "@playwright/test"; -import { BudgetProposalType, CommentResponse } from "@types"; +import { BudgetDiscussionEnum, CommentResponse } from "@types"; const mockBudgetProposal = require("../../lib/_mock/budgetProposal.json"); const mockPoll = require("../../lib/_mock/budgetProposalPoll.json"); @@ -97,7 +97,7 @@ test.describe("Budget proposal list manipulation", () => { // proposal type filter await budgetDiscussionPage.applyAndValidateFilters( - Object.values(BudgetProposalType), + Object.values(BudgetDiscussionEnum), budgetDiscussionPage._validateTypeFiltersInProposalCard ); }); @@ -120,7 +120,7 @@ test("11C. Should show view-all categorized budget proposal", async ({ browser, }) => { await Promise.all( - Object.values(BudgetProposalType).map(async (proposalType: string) => { + Object.values(BudgetDiscussionEnum).map(async (proposalType: string) => { const context = await browser.newContext(); const page = await context.newPage(); injectLogger(page); From a76d04b136e6082f737c7a4394cef0637117186c Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 16:53:36 +0545 Subject: [PATCH 19/45] tests: poll vote and change vote behaviour by registered dRep --- .../lib/pages/budgetDiscussionDetailsPage.ts | 13 +++ .../lib/pages/budgetDiscussionPage.ts | 10 +++ .../proposalBudget.dRep.spec.ts | 86 +++++++++++++++++-- .../playwright/tests/dRep.setup.ts | 2 +- 4 files changed, 105 insertions(+), 6 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts index cde23e911..d62eb6688 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts @@ -12,6 +12,10 @@ export default class BudgetDiscussionDetailsPage { readonly pollYesBtn = this.page.getByTestId("poll-yes-button"); readonly pollNoBtn = this.page.getByTestId("poll-no-button"); readonly sortCommentsBtn = this.page.getByTestId("sort-comments"); + readonly changeVoteBtn = this.page.getByTestId("change-vote-button"); + readonly changeVoteYesBtn = this.page.getByTestId( + "change-poll-vote-yes-button" + ); // content readonly copyLinkText = this.page.getByTestId("copy-link-text"); @@ -73,6 +77,15 @@ export default class BudgetDiscussionDetailsPage { await this.replyCommentBtn.click(); } + async voteOnPoll(vote: string) { + await this.page.getByTestId(`poll-${vote.toLowerCase()}-button`).click(); + } + + async changePollVote() { + await this.changeVoteBtn.click(); + await this.changeVoteYesBtn.click(); + } + async deleteProposal() { await this.page.waitForTimeout(2_000); diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts index bfc46e193..1bbc03545 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts @@ -151,4 +151,14 @@ export default class BudgetDiscussionPage { expect(isValid).toBe(true); } } + + async setUsername(name: string) { + await this.page.getByTestId("username-input").fill(name); + + const proceedBtn = this.page.getByTestId("proceed-button"); + await proceedBtn.click(); + await proceedBtn.click(); + + await this.page.getByTestId("close-button").click(); + } } diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts index a028c0d46..56ede82db 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts @@ -1,11 +1,87 @@ +import { createTempDRepAuth } from "@datafactory/createAuth"; +import { faker } from "@faker-js/faker"; import { test } from "@fixtures/walletExtension"; import { setAllureEpic } from "@helpers/allure"; -import { skipTestForProposalBudget } from "@helpers/cardano"; +import { createNewPageWithWallet } from "@helpers/page"; +import BudgetDiscussionDetailsPage from "@pages/budgetDiscussionDetailsPage"; +import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; +import { expect, Page } from "@playwright/test"; +import walletManager from "lib/walletManager"; +import { valid as mockValid } from "@mock/index"; -test.beforeEach(async ({}) => { +test.beforeEach(async () => { await setAllureEpic("11. Proposal Budget"); - await skipTestForProposalBudget(); }); -test("11K. Should allow registered DRep to vote on a proposal", async ({}) => {}); -test("11L. Should display DRep tag, name and ID when a registered DRep comments on a proposal", async ({}) => {}); +test.describe("Budget proposal dRep behaviour", () => { + let budgetDiscussionDetailsPage: BudgetDiscussionDetailsPage; + let dRepId: string; + test.beforeEach(async ({ browser, page }) => { + const wallet = await walletManager.popWallet("registeredDRep"); + dRepId = wallet.dRepId; + + const tempDRepAuth = await createTempDRepAuth(page, wallet); + + const dRepPage = await createNewPageWithWallet(browser, { + storageState: tempDRepAuth, + wallet, + }); + const budgetDiscussionPage = new BudgetDiscussionPage(dRepPage); + await budgetDiscussionPage.goto(); + await budgetDiscussionPage.verifyIdentityBtn.click(); + await budgetDiscussionPage.setUsername(mockValid.username()); + budgetDiscussionDetailsPage = + await budgetDiscussionPage.viewFirstProposal(); + await expect(budgetDiscussionDetailsPage.pollVoteCard).toBeVisible({ + timeout: 60_000, + }); + }); + + test("11K. Should allow registered DRep to vote on a proposal", async () => { + const pollVotes = ["Yes", "No"]; + const choice = faker.helpers.arrayElement(pollVotes); + console.log(choice); + await budgetDiscussionDetailsPage.voteOnPoll(choice); + + await expect(budgetDiscussionDetailsPage.pollYesBtn).not.toBeVisible(); + await expect(budgetDiscussionDetailsPage.pollNoBtn).not.toBeVisible(); + await expect( + budgetDiscussionDetailsPage.currentPage.getByTestId( + `poll-${choice.toLowerCase()}-count` + ) + ).toHaveText(`${choice}: (100%)`); + // opposite of random choice vote + const oppositeVote = pollVotes.filter((vote) => vote !== choice)[0]; + await expect( + budgetDiscussionDetailsPage.currentPage.getByTestId( + `poll-${oppositeVote.toLowerCase()}-count` + ) + ).toHaveText(`${oppositeVote}: (0%)`); + }); + + test("11L. Should allow registered DRep to change vote on a proposal", async () => { + const pollVotes = ["Yes", "No"]; + const choice = faker.helpers.arrayElement(pollVotes); + console.log(choice); + await budgetDiscussionDetailsPage.voteOnPoll(choice); + await budgetDiscussionDetailsPage.changePollVote(); + + await expect(budgetDiscussionDetailsPage.pollYesBtn).not.toBeVisible(); + await expect(budgetDiscussionDetailsPage.pollNoBtn).not.toBeVisible(); + + // vote must be changed + await expect( + budgetDiscussionDetailsPage.currentPage.getByTestId( + `poll-${choice.toLowerCase()}-count` + ) + ).toHaveText(`${choice}: (0%)`, { timeout: 60_000 }); + // opposite of random choice vote + const oppositeVote = pollVotes.filter((vote) => vote !== choice)[0]; + await expect( + budgetDiscussionDetailsPage.currentPage.getByTestId( + `poll-${oppositeVote.toLowerCase()}-count` + ) + ).toHaveText(`${oppositeVote}: (100%)`); + }); + test("11M. Should display DRep tag, name and ID when a registered DRep comments on a proposal", async ({}) => {}); +}); diff --git a/tests/govtool-frontend/playwright/tests/dRep.setup.ts b/tests/govtool-frontend/playwright/tests/dRep.setup.ts index 239e10e6d..c09ca10e0 100644 --- a/tests/govtool-frontend/playwright/tests/dRep.setup.ts +++ b/tests/govtool-frontend/playwright/tests/dRep.setup.ts @@ -13,7 +13,7 @@ import walletManager from "lib/walletManager"; import { functionWaitedAssert } from "@helpers/waitedLoop"; const REGISTER_DREP_WALLETS_COUNT = 6; -const DREP_WALLETS_COUNT = 10; +const DREP_WALLETS_COUNT = 12; let dRepDeposit: number; From 7db6d74f6b7681daade9ec03b57fc00af687a436 Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 16:57:48 +0545 Subject: [PATCH 20/45] tests: access proposal creation page in connected state --- .../proposalBudgetSubmission.loggedin.spec.ts | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) 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 097726dea..0e3e97932 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 @@ -1,13 +1,27 @@ +import { budgetProposal01Wallet } from "@constants/staticWallets"; import { test } from "@fixtures/walletExtension"; import { setAllureEpic } from "@helpers/allure"; -import { skipTestForProposalBudget } from "@helpers/cardano"; +import BudgetDiscussionSubmissionPage from "@pages/budgetDiscussionSubmissionPage"; +import { expect } from "@playwright/test"; test.beforeEach(async ({}) => { await setAllureEpic("12. Proposal Budget Submission"); - await skipTestForProposalBudget(); }); -test("12B. Should access proposal creation page in connected state", async ({}) => {}); +test.use({ + storageState: ".auth/budgetProposal01.json", + wallet: budgetProposal01Wallet, +}); + +test("12B. Should access proposal creation page in connected state", async ({ + page, +}) => { + const budgetProposalSubmissionPage = new BudgetDiscussionSubmissionPage(page); + await budgetProposalSubmissionPage.goto(); + await expect( + budgetProposalSubmissionPage.beneficiaryFullNameInput + ).toBeVisible(); +}); test("12C. Should view draft proposal", async ({}) => {}); From 79b9522419633932ab4c8aa405bb25443346536d Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 19:36:10 +0545 Subject: [PATCH 21/45] fix: budget proposal filter test due to testIds --- .../playwright/lib/pages/budgetDiscussionDetailsPage.ts | 1 - .../playwright/lib/pages/budgetDiscussionPage.ts | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts index d62eb6688..410491a28 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts @@ -63,7 +63,6 @@ export default class BudgetDiscussionDetailsPage { async addComment(comment: string) { await this.commentInput.fill(comment); - ``; await this.commentBtn.click(); } diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts index 1bbc03545..8de114c53 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts @@ -60,7 +60,7 @@ export default class BudgetDiscussionPage { name as BudgetDiscussionEnum ); if (budgetProposalValue) { - await this.page.getByTestId(`${name.toLowerCase()}-radio`).click(); + await this.page.getByLabel(name).click(); } } } @@ -105,7 +105,7 @@ export default class BudgetDiscussionPage { for (const proposalCard of proposalCards) { if (await proposalCard.isVisible()) { const type = await proposalCard - .getByTestId("budget-proposal-type") + .getByTestId("budget-discussion-type") .textContent(); const hasFilter = await validateFunction(proposalCard, filters); @@ -124,9 +124,12 @@ export default class BudgetDiscussionPage { filters: string[] ): Promise { const govActionType = await proposalCard - .getByTestId("budget-proposal-type") + .getByTestId("budget-discussion-type") .textContent(); + if (govActionType === "None of these") { + return filters.includes("No Category"); + } return filters.includes(govActionType); } From d098b686f70eb63b789df0fab6e93f5ad8ecad90 Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 19:40:56 +0545 Subject: [PATCH 22/45] fix: catgegorized budget proposal type due to no category --- .../playwright/lib/pages/budgetDiscussionPage.ts | 2 +- .../tests/11-proposal-budget/proposalBudget.spec.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts index 8de114c53..0d6264e8a 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionPage.ts @@ -128,7 +128,7 @@ export default class BudgetDiscussionPage { .textContent(); if (govActionType === "None of these") { - return filters.includes("No Category"); + return filters.includes(BudgetDiscussionEnum.NoCategory); } return filters.includes(govActionType); } diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts index 28aa18e6c..9e7fc2ce2 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.spec.ts @@ -145,9 +145,13 @@ test("11C. Should show view-all categorized budget proposal", async ({ const proposalCards = await budgetDiscussionPage.getAllProposals(); for (const proposalCard of proposalCards) { + const ExpectedProposalType = + proposalType === BudgetDiscussionEnum.NoCategory + ? "None of these" + : proposalType; await expect( proposalCard.getByTestId("budget-discussion-type") - ).toHaveText(proposalType, { timeout: 60_000 }); + ).toHaveText(ExpectedProposalType, { timeout: 60_000 }); } } else { expect(true, `No ${proposalType} found`).toBeTruthy(); From 8ebc3b9ee875c780c5ae2d01cb70cb3378b18e7d Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 20:04:17 +0545 Subject: [PATCH 23/45] chore: add given name on registered dRep wallet json --- .../playwright/lib/helpers/metadata.ts | 8 +++----- tests/govtool-frontend/playwright/lib/types.ts | 1 + .../playwright/tests/dRep.setup.ts | 14 ++++++++++++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/helpers/metadata.ts b/tests/govtool-frontend/playwright/lib/helpers/metadata.ts index 267d9e177..39f34da0a 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/metadata.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/metadata.ts @@ -56,11 +56,9 @@ async function calculateMetadataHash() { export async function uploadMetadataAndGetJsonHash() { const { hexDigest: dataHash, jsonData } = await calculateMetadataHash(); - const url = await metadataBucketService.uploadMetadata( - faker.person.firstName(), - jsonData - ); - return { dataHash, url }; + const givenName = faker.person.firstName(); + const url = await metadataBucketService.uploadMetadata(givenName, jsonData); + return { dataHash, url, givenName }; } export async function uploadScriptAndGenerateUrl(payload: Object) { diff --git a/tests/govtool-frontend/playwright/lib/types.ts b/tests/govtool-frontend/playwright/lib/types.ts index ffb225fb4..7173a5529 100644 --- a/tests/govtool-frontend/playwright/lib/types.ts +++ b/tests/govtool-frontend/playwright/lib/types.ts @@ -3,6 +3,7 @@ import { CardanoTestWalletJson } from "@cardanoapi/cardano-test-wallet/types"; export type StaticWallet = CardanoTestWalletJson & { dRepId: string; address: string; + givenName?: string; }; export type KuberValue = { diff --git a/tests/govtool-frontend/playwright/tests/dRep.setup.ts b/tests/govtool-frontend/playwright/tests/dRep.setup.ts index c09ca10e0..dd50a232b 100644 --- a/tests/govtool-frontend/playwright/tests/dRep.setup.ts +++ b/tests/govtool-frontend/playwright/tests/dRep.setup.ts @@ -11,6 +11,7 @@ import { test as setup } from "@fixtures/walletExtension"; import kuberService from "@services/kuberService"; import walletManager from "lib/walletManager"; import { functionWaitedAssert } from "@helpers/waitedLoop"; +import { StaticWallet } from "@types"; const REGISTER_DREP_WALLETS_COUNT = 6; const DREP_WALLETS_COUNT = 12; @@ -64,7 +65,7 @@ setup("Register DRep of static wallets", async () => { setup("Setup temporary DRep wallets", async () => { setup.setTimeout(3 * environments.txTimeOut); - const dRepWallets = await generateWallets(DREP_WALLETS_COUNT); + const dRepWallets: StaticWallet[] = await generateWallets(DREP_WALLETS_COUNT); const registerDRepWallets = await generateWallets( REGISTER_DREP_WALLETS_COUNT ); @@ -78,7 +79,16 @@ setup("Setup temporary DRep wallets", async () => { // Submit metadata to obtain a URL and generate hash value. const metadataPromises = dRepWallets.map(async (dRepWallet) => { - return { ...(await uploadMetadataAndGetJsonHash()), wallet: dRepWallet }; + const metadataResponse = await uploadMetadataAndGetJsonHash(); + const index = dRepWallets.indexOf(dRepWallet); + dRepWallets[index] = { + ...dRepWallet, + givenName: metadataResponse.givenName, + }; + return { + ...metadataResponse, + wallet: dRepWallet, + }; }); const metadatasAndDRepWallets = await Promise.all(metadataPromises); From 49e03ba92fc2aab575274cba37487b9a2ed0f727 Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 20:27:52 +0545 Subject: [PATCH 24/45] fix: given name set on wallet issue --- tests/govtool-frontend/playwright/lib/_mock/index.ts | 8 ++++++-- .../playwright/lib/helpers/metadata.ts | 12 ++++++++---- .../govtool-frontend/playwright/tests/dRep.setup.ts | 3 ++- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/_mock/index.ts b/tests/govtool-frontend/playwright/lib/_mock/index.ts index 79214f128..692d74859 100644 --- a/tests/govtool-frontend/playwright/lib/_mock/index.ts +++ b/tests/govtool-frontend/playwright/lib/_mock/index.ts @@ -149,7 +149,11 @@ export const valid = { return `ipfs://${randomCID}`; }, - metadata: (paymentAddress: string, imageObject: imageObject) => ({ + metadata: ( + paymentAddress: string, + imageObject: imageObject, + givenName: string + ) => ({ "@context": { "@language": "en-us", CIP100: @@ -212,7 +216,7 @@ export const valid = { authors: [], hashAlgorithm: "blake2b-256", body: { - givenName: faker.person.firstName(), + givenName: givenName, image: imageObject, motivations: faker.lorem.paragraph(2), objectives: faker.lorem.paragraph(2), diff --git a/tests/govtool-frontend/playwright/lib/helpers/metadata.ts b/tests/govtool-frontend/playwright/lib/helpers/metadata.ts index 39f34da0a..98e908456 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/metadata.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/metadata.ts @@ -39,8 +39,9 @@ async function calculateMetadataHash() { contentUrl: imageUrl, sha256: imageSHA256, }; + const givenName = faker.person.firstName(); const data = JSON.stringify( - mockValid.metadata(paymentAddress, imageObject), + mockValid.metadata(paymentAddress, imageObject, givenName), null, 2 ); @@ -48,15 +49,18 @@ async function calculateMetadataHash() { const hexDigest = calculateHash(data); const jsonData = JSON.parse(data); - return { hexDigest, jsonData }; + return { hexDigest, jsonData, givenName }; } catch (error) { console.error("Error reading file:", error); } } export async function uploadMetadataAndGetJsonHash() { - const { hexDigest: dataHash, jsonData } = await calculateMetadataHash(); - const givenName = faker.person.firstName(); + const { + hexDigest: dataHash, + jsonData, + givenName, + } = await calculateMetadataHash(); const url = await metadataBucketService.uploadMetadata(givenName, jsonData); return { dataHash, url, givenName }; } diff --git a/tests/govtool-frontend/playwright/tests/dRep.setup.ts b/tests/govtool-frontend/playwright/tests/dRep.setup.ts index dd50a232b..abaa36116 100644 --- a/tests/govtool-frontend/playwright/tests/dRep.setup.ts +++ b/tests/govtool-frontend/playwright/tests/dRep.setup.ts @@ -80,10 +80,11 @@ setup("Setup temporary DRep wallets", async () => { // Submit metadata to obtain a URL and generate hash value. const metadataPromises = dRepWallets.map(async (dRepWallet) => { const metadataResponse = await uploadMetadataAndGetJsonHash(); + const givenName = metadataResponse.givenName; const index = dRepWallets.indexOf(dRepWallet); dRepWallets[index] = { ...dRepWallet, - givenName: metadataResponse.givenName, + givenName, }; return { ...metadataResponse, From 140d6df5843c0a9d52da18472776d27bff01463c Mon Sep 17 00:00:00 2001 From: Niraj Date: Thu, 3 Apr 2025 20:44:55 +0545 Subject: [PATCH 25/45] tests: display dRep tag, name and id on registered dRep comment --- .../proposalBudget.dRep.spec.ts | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts index 56ede82db..667a3ef97 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts @@ -8,6 +8,7 @@ import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; import { expect, Page } from "@playwright/test"; import walletManager from "lib/walletManager"; import { valid as mockValid } from "@mock/index"; +import { StaticWallet } from "@types"; test.beforeEach(async () => { await setAllureEpic("11. Proposal Budget"); @@ -15,10 +16,9 @@ test.beforeEach(async () => { test.describe("Budget proposal dRep behaviour", () => { let budgetDiscussionDetailsPage: BudgetDiscussionDetailsPage; - let dRepId: string; + let wallet: StaticWallet; test.beforeEach(async ({ browser, page }) => { - const wallet = await walletManager.popWallet("registeredDRep"); - dRepId = wallet.dRepId; + wallet = await walletManager.popWallet("registeredDRep"); const tempDRepAuth = await createTempDRepAuth(page, wallet); @@ -40,7 +40,7 @@ test.describe("Budget proposal dRep behaviour", () => { test("11K. Should allow registered DRep to vote on a proposal", async () => { const pollVotes = ["Yes", "No"]; const choice = faker.helpers.arrayElement(pollVotes); - console.log(choice); + await budgetDiscussionDetailsPage.voteOnPoll(choice); await expect(budgetDiscussionDetailsPage.pollYesBtn).not.toBeVisible(); @@ -62,7 +62,7 @@ test.describe("Budget proposal dRep behaviour", () => { test("11L. Should allow registered DRep to change vote on a proposal", async () => { const pollVotes = ["Yes", "No"]; const choice = faker.helpers.arrayElement(pollVotes); - console.log(choice); + await budgetDiscussionDetailsPage.voteOnPoll(choice); await budgetDiscussionDetailsPage.changePollVote(); @@ -83,5 +83,31 @@ test.describe("Budget proposal dRep behaviour", () => { ) ).toHaveText(`${oppositeVote}: (100%)`); }); - test("11M. Should display DRep tag, name and ID when a registered DRep comments on a proposal", async ({}) => {}); + + test("11M. Should display DRep tag, name and ID when a registered DRep comments on a proposal", async () => { + const comment = faker.lorem.paragraph(2); + await budgetDiscussionDetailsPage.addComment(comment); + + await expect( + budgetDiscussionDetailsPage.currentPage + .locator('[data-testid^="comment-"][data-testid$="-content"]') + .first() + ).toHaveText(comment); + + const dRepCommentedCard = budgetDiscussionDetailsPage.currentPage + .locator('[data-testid^="comment-"][data-testid$="-content-card"]') + .first(); + + await expect( + dRepCommentedCard.getByText("DRep", { exact: true }) + ).toBeVisible(); + + await expect(dRepCommentedCard.getByTestId("given-name")).toHaveText( + wallet.givenName + ); + + await expect(dRepCommentedCard.getByTestId("drep-id")).toHaveText( + wallet.dRepId + ); + }); }); From 0b80ed47b55ca98ccaf789547e85339fa25ba48f Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 08:29:17 +0545 Subject: [PATCH 26/45] fix: proposal creation issue due to update on testids --- .../lib/pages/budgetDiscussionDetailsPage.ts | 3 ++- .../pages/budgetDiscussionSubmissionPage.ts | 26 ++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts index 410491a28..eabc87f2a 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts @@ -16,6 +16,7 @@ export default class BudgetDiscussionDetailsPage { readonly changeVoteYesBtn = this.page.getByTestId( "change-poll-vote-yes-button" ); + readonly verifyIdentityBtn = this.page.getByTestId("verify-identity-button"); // content readonly copyLinkText = this.page.getByTestId("copy-link-text"); @@ -32,7 +33,7 @@ export default class BudgetDiscussionDetailsPage { return this.page; } - async goto(proposalId: string) { + async goto(proposalId: number) { await this.page.goto( `${environments.frontendUrl}/budget_discussion/${proposalId}` ); diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts index 73171ad29..fd2c67850 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts @@ -141,7 +141,7 @@ export default class BudgetDiscussionSubmissionPage { "beneficiary-nationality" ); - readonly companyTypeSelect = this.page.getByTestId("beneficiary-nationality"); //BUG wrong test id + readonly companyTypeSelect = this.page.getByTestId("beneficiary-type"); readonly publicChampion = this.page.getByTestId("proposal-public-champion"); readonly roadmapNameSelect = this.page.getByTestId("roadmap-name"); @@ -190,7 +190,9 @@ export default class BudgetDiscussionSubmissionPage { .click(); await this.beneficiaryNationalitySelect.click(); await this.page - .getByRole("option", { name: contactInformation.beneficiaryNationality }) + .getByTestId( + `${contactInformation.beneficiaryNationality.toLowerCase()}-button` + ) .click(); await this.submissionLeadFullNameInput.fill( @@ -411,12 +413,12 @@ export default class BudgetDiscussionSubmissionPage { return { beneficiaryFullName: faker.person.fullName(), beneficiaryEmail: faker.internet.email(), - beneficiaryCountry: faker.helpers.arrayElement( - Object.values(LocationEnum) - ), - beneficiaryNationality: faker.helpers.arrayElement( - Object.values(LocationEnum) - ), + beneficiaryCountry: faker.helpers + .arrayElement(Object.values(LocationEnum)) + .replace(/ /g, "-"), + beneficiaryNationality: faker.helpers + .arrayElement(Object.values(LocationEnum)) + .replace(/ /g, "-"), submissionLeadFullName: faker.person.fullName(), submissionLeadEmail: faker.internet.email(), }; @@ -452,9 +454,9 @@ export default class BudgetDiscussionSubmissionPage { groupKeyIdentity: faker.lorem.paragraph(2), companyName: faker.company.name(), companyDomainName: faker.internet.domainName(), - countryOfIncorportation: faker.helpers.arrayElement( - Object.values(LocationEnum) - ), + countryOfIncorportation: faker.helpers + .arrayElement(Object.values(LocationEnum)) + .replace(/ /g, "-"), }; } @@ -524,7 +526,7 @@ export default class BudgetDiscussionSubmissionPage { this.generateValidBudgetProposalInformation(); await this.fillupForm(budgetProposalRequest); - await this.continueBtn.click(); // BUG incorrect test id -> submit-button + await this.submitBtn.click(); // BUG incorrect test id -> submit-button // assert to check if the proposal is created and navigated to details page await expect(this.page.getByTestId("review-version")).toBeVisible({ From d7f5df9ce1b8dbcc1ee54d55781b74f9f0710d8a Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 08:30:42 +0545 Subject: [PATCH 27/45] fix: dRep poll vote/comment issue fix: remove unnecessary temp dRep wallets and use static wallets for poll vote and comment test and use fixture to poll vote on new proposal --- .../proposalBudget.dRep.spec.ts | 140 +++++++++--------- .../playwright/tests/dRep.setup.ts | 14 +- 2 files changed, 80 insertions(+), 74 deletions(-) diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts index 667a3ef97..66f2cf098 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts @@ -1,91 +1,87 @@ -import { createTempDRepAuth } from "@datafactory/createAuth"; import { faker } from "@faker-js/faker"; -import { test } from "@fixtures/walletExtension"; +import { test } from "@fixtures/budgetProposal"; import { setAllureEpic } from "@helpers/allure"; -import { createNewPageWithWallet } from "@helpers/page"; import BudgetDiscussionDetailsPage from "@pages/budgetDiscussionDetailsPage"; +import { expect } from "@playwright/test"; +import { dRep01Wallet } from "@constants/staticWallets"; import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; -import { expect, Page } from "@playwright/test"; -import walletManager from "lib/walletManager"; -import { valid as mockValid } from "@mock/index"; -import { StaticWallet } from "@types"; test.beforeEach(async () => { await setAllureEpic("11. Proposal Budget"); }); test.describe("Budget proposal dRep behaviour", () => { - let budgetDiscussionDetailsPage: BudgetDiscussionDetailsPage; - let wallet: StaticWallet; - test.beforeEach(async ({ browser, page }) => { - wallet = await walletManager.popWallet("registeredDRep"); - - const tempDRepAuth = await createTempDRepAuth(page, wallet); - - const dRepPage = await createNewPageWithWallet(browser, { - storageState: tempDRepAuth, - wallet, - }); - const budgetDiscussionPage = new BudgetDiscussionPage(dRepPage); - await budgetDiscussionPage.goto(); - await budgetDiscussionPage.verifyIdentityBtn.click(); - await budgetDiscussionPage.setUsername(mockValid.username()); - budgetDiscussionDetailsPage = - await budgetDiscussionPage.viewFirstProposal(); - await expect(budgetDiscussionDetailsPage.pollVoteCard).toBeVisible({ - timeout: 60_000, - }); + test.use({ + storageState: ".auth/dRep01.json", + wallet: dRep01Wallet, }); - test("11K. Should allow registered DRep to vote on a proposal", async () => { - const pollVotes = ["Yes", "No"]; - const choice = faker.helpers.arrayElement(pollVotes); - - await budgetDiscussionDetailsPage.voteOnPoll(choice); + test.describe("Budget proposal voting", () => { + let budgetDiscussionDetailsPage: BudgetDiscussionDetailsPage; + test.beforeEach(async ({ page, proposalId }) => { + budgetDiscussionDetailsPage = new BudgetDiscussionDetailsPage(page); + await budgetDiscussionDetailsPage.goto(proposalId); - await expect(budgetDiscussionDetailsPage.pollYesBtn).not.toBeVisible(); - await expect(budgetDiscussionDetailsPage.pollNoBtn).not.toBeVisible(); - await expect( - budgetDiscussionDetailsPage.currentPage.getByTestId( - `poll-${choice.toLowerCase()}-count` - ) - ).toHaveText(`${choice}: (100%)`); - // opposite of random choice vote - const oppositeVote = pollVotes.filter((vote) => vote !== choice)[0]; - await expect( - budgetDiscussionDetailsPage.currentPage.getByTestId( - `poll-${oppositeVote.toLowerCase()}-count` - ) - ).toHaveText(`${oppositeVote}: (0%)`); - }); - - test("11L. Should allow registered DRep to change vote on a proposal", async () => { - const pollVotes = ["Yes", "No"]; - const choice = faker.helpers.arrayElement(pollVotes); - - await budgetDiscussionDetailsPage.voteOnPoll(choice); - await budgetDiscussionDetailsPage.changePollVote(); + await budgetDiscussionDetailsPage.verifyIdentityBtn.click(); + }); - await expect(budgetDiscussionDetailsPage.pollYesBtn).not.toBeVisible(); - await expect(budgetDiscussionDetailsPage.pollNoBtn).not.toBeVisible(); + test("11K. Should allow registered DRep to vote on a proposal", async () => { + const pollVotes = ["Yes", "No"]; + const choice = faker.helpers.arrayElement(pollVotes); + + await budgetDiscussionDetailsPage.voteOnPoll(choice); + + await expect(budgetDiscussionDetailsPage.pollYesBtn).not.toBeVisible(); + await expect(budgetDiscussionDetailsPage.pollNoBtn).not.toBeVisible(); + await expect( + budgetDiscussionDetailsPage.currentPage.getByTestId( + `poll-${choice.toLowerCase()}-count` + ) + ).toHaveText(`${choice}: (100%)`); + // opposite of random choice vote + const oppositeVote = pollVotes.filter((vote) => vote !== choice)[0]; + await expect( + budgetDiscussionDetailsPage.currentPage.getByTestId( + `poll-${oppositeVote.toLowerCase()}-count` + ) + ).toHaveText(`${oppositeVote}: (0%)`); + }); - // vote must be changed - await expect( - budgetDiscussionDetailsPage.currentPage.getByTestId( - `poll-${choice.toLowerCase()}-count` - ) - ).toHaveText(`${choice}: (0%)`, { timeout: 60_000 }); - // opposite of random choice vote - const oppositeVote = pollVotes.filter((vote) => vote !== choice)[0]; - await expect( - budgetDiscussionDetailsPage.currentPage.getByTestId( - `poll-${oppositeVote.toLowerCase()}-count` - ) - ).toHaveText(`${oppositeVote}: (100%)`); + test("11L. Should allow registered DRep to change vote on a proposal", async () => { + test.slow(); + const pollVotes = ["Yes", "No"]; + const choice = faker.helpers.arrayElement(pollVotes); + + await budgetDiscussionDetailsPage.voteOnPoll(choice); + await budgetDiscussionDetailsPage.changePollVote(); + + await expect(budgetDiscussionDetailsPage.pollYesBtn).not.toBeVisible(); + await expect(budgetDiscussionDetailsPage.pollNoBtn).not.toBeVisible(); + + // vote must be changed + await expect( + budgetDiscussionDetailsPage.currentPage.getByTestId( + `poll-${choice.toLowerCase()}-count` + ) + ).toHaveText(`${choice}: (0%)`, { timeout: 60_000 }); + // opposite of random choice vote + const oppositeVote = pollVotes.filter((vote) => vote !== choice)[0]; + await expect( + budgetDiscussionDetailsPage.currentPage.getByTestId( + `poll-${oppositeVote.toLowerCase()}-count` + ) + ).toHaveText(`${oppositeVote}: (100%)`); + }); }); - test("11M. Should display DRep tag, name and ID when a registered DRep comments on a proposal", async () => { + test("11M. Should display DRep tag, name and ID when a registered DRep comments on a proposal", async ({ + page, + }) => { const comment = faker.lorem.paragraph(2); + const budgetDiscussionPage = new BudgetDiscussionPage(page); + await budgetDiscussionPage.goto(); + const budgetDiscussionDetailsPage = + await budgetDiscussionPage.viewFirstProposal(); await budgetDiscussionDetailsPage.addComment(comment); await expect( @@ -103,11 +99,11 @@ test.describe("Budget proposal dRep behaviour", () => { ).toBeVisible(); await expect(dRepCommentedCard.getByTestId("given-name")).toHaveText( - wallet.givenName + dRep01Wallet.givenName ); await expect(dRepCommentedCard.getByTestId("drep-id")).toHaveText( - wallet.dRepId + dRep01Wallet.dRepId ); }); }); diff --git a/tests/govtool-frontend/playwright/tests/dRep.setup.ts b/tests/govtool-frontend/playwright/tests/dRep.setup.ts index abaa36116..7677ec7f5 100644 --- a/tests/govtool-frontend/playwright/tests/dRep.setup.ts +++ b/tests/govtool-frontend/playwright/tests/dRep.setup.ts @@ -14,7 +14,7 @@ import { functionWaitedAssert } from "@helpers/waitedLoop"; import { StaticWallet } from "@types"; const REGISTER_DREP_WALLETS_COUNT = 6; -const DREP_WALLETS_COUNT = 12; +const DREP_WALLETS_COUNT = 9; let dRepDeposit: number; @@ -41,7 +41,17 @@ setup("Register DRep of static wallets", async () => { try { // Submit metadata to obtain a URL and generate hash value. const metadataPromises = dRepWallets.map(async (dRepWallet) => { - return { ...(await uploadMetadataAndGetJsonHash()), wallet: dRepWallet }; + const metadataResponse = await uploadMetadataAndGetJsonHash(); + const givenName = metadataResponse.givenName; + const index = dRepWallets.indexOf(dRepWallet); + dRepWallets[index] = { + ...dRepWallet, + givenName, + }; + return { + ...metadataResponse, + wallet: dRepWallet, + }; }); const metadataAndDRepWallets = await Promise.all(metadataPromises); From dd28dd6c1a80dcaa8941d2268dfcb1abfe495abd Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 10:41:51 +0545 Subject: [PATCH 28/45] feat: add dRep03Wallet and corresponding auth setup --- .../playwright/lib/constants/staticWallets.ts | 29 ++++++++++--------- .../playwright/tests/auth.setup.ts | 11 +++++++ 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts index 6026775b9..cc78d6526 100644 --- a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts +++ b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts @@ -5,29 +5,30 @@ export const faucetWallet = staticWallets[0]; export const dRep01Wallet = staticWallets[1]; export const dRep02Wallet = staticWallets[2]; +export const dRep03Wallet = staticWallets[3]; -export const adaHolder01Wallet = staticWallets[3]; -export const adaHolder02Wallet = staticWallets[4]; +export const adaHolder01Wallet = staticWallets[4]; +export const adaHolder02Wallet = staticWallets[5]; export const adaHolder03Wallet = staticWallets[6]; export const adaHolder04Wallet = staticWallets[7]; export const adaHolder05Wallet = staticWallets[8]; export const adaHolder06Wallet = staticWallets[9]; // Does not takes part in transaction -export const user01Wallet: StaticWallet = staticWallets[5]; +export const user01Wallet: StaticWallet = staticWallets[10]; // Username is already set -export const proposal01Wallet: StaticWallet = staticWallets[10]; -export const proposal02Wallet: StaticWallet = staticWallets[11]; -export const proposal03Wallet: StaticWallet = staticWallets[12]; -export const proposal04Wallet: StaticWallet = staticWallets[13]; -export const proposal05Wallet: StaticWallet = staticWallets[14]; -export const proposal06Wallet: StaticWallet = staticWallets[15]; -export const proposal07Wallet: StaticWallet = staticWallets[16]; -export const proposal08Wallet: StaticWallet = staticWallets[17]; -export const proposal09Wallet: StaticWallet = staticWallets[18]; +export const proposal01Wallet: StaticWallet = staticWallets[11]; +export const proposal02Wallet: StaticWallet = staticWallets[12]; +export const proposal03Wallet: StaticWallet = staticWallets[13]; +export const proposal04Wallet: StaticWallet = staticWallets[14]; +export const proposal05Wallet: StaticWallet = staticWallets[15]; +export const proposal06Wallet: StaticWallet = staticWallets[16]; +export const proposal07Wallet: StaticWallet = staticWallets[17]; +export const proposal08Wallet: StaticWallet = staticWallets[18]; +export const proposal09Wallet: StaticWallet = staticWallets[19]; -export const budgetProposal01Wallet: StaticWallet = staticWallets[19]; +export const budgetProposal01Wallet: StaticWallet = staticWallets[20]; export const adaHolderWallets = [ adaHolder01Wallet, @@ -40,7 +41,7 @@ export const adaHolderWallets = [ export const userWallets = [user01Wallet]; -export const dRepWallets = [dRep01Wallet, dRep02Wallet]; +export const dRepWallets = [dRep01Wallet, dRep02Wallet, dRep03Wallet]; export const proposalWallets = [ proposal01Wallet, diff --git a/tests/govtool-frontend/playwright/tests/auth.setup.ts b/tests/govtool-frontend/playwright/tests/auth.setup.ts index 849e28a45..06c8c67f4 100644 --- a/tests/govtool-frontend/playwright/tests/auth.setup.ts +++ b/tests/govtool-frontend/playwright/tests/auth.setup.ts @@ -10,6 +10,7 @@ import { budgetProposal01Wallet, dRep01Wallet, dRep02Wallet, + dRep03Wallet, proposal01Wallet, proposal02Wallet, proposal03Wallet, @@ -32,6 +33,7 @@ import { skipIfNotHardFork } from "@helpers/cardano"; const dRep01AuthFile = ".auth/dRep01.json"; const dRep02AuthFile = ".auth/dRep02.json"; +const dRep03AuthFile = ".auth/dRep03.json"; const adaHolder01AuthFile = ".auth/adaHolder01.json"; const adaHolder02AuthFile = ".auth/adaHolder02.json"; @@ -78,6 +80,15 @@ setup("Create DRep 02 auth", async ({ page, context }) => { }); }); +setup("Create DRep 03 auth with username", async ({ page, context }) => { + await createAuthWithUserName({ + page, + context, + wallet: dRep03Wallet, + auth: dRep03AuthFile, + }); +}); + setup("Create User 01 auth", async ({ page, context }) => { await createAuth({ page, From a17b0eee884aefc46ad73a3ed70ca05a0fab1eac Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 10:42:57 +0545 Subject: [PATCH 29/45] fix: country of incorportation and budgetDiscussion auth --- .../lib/pages/budgetDiscussionSubmissionPage.ts | 4 ++-- .../11-proposal-budget/proposalBudget.dRep.spec.ts | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts index fd2c67850..f48ab8bf3 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts @@ -233,7 +233,7 @@ export default class BudgetDiscussionSubmissionPage { await this.countryOfIncorporationBtn.click(); await this.page .getByTestId( - `${proposalOwnership.countryOfIncorportation.toLowerCase()}-button` + `${proposalOwnership.countryOfIncorportation.toLowerCase()}-country-of-incorporation-button` ) .click(); } @@ -526,7 +526,7 @@ export default class BudgetDiscussionSubmissionPage { this.generateValidBudgetProposalInformation(); await this.fillupForm(budgetProposalRequest); - await this.submitBtn.click(); // BUG incorrect test id -> submit-button + await this.submitBtn.click(); // assert to check if the proposal is created and navigated to details page await expect(this.page.getByTestId("review-version")).toBeVisible({ diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts index 66f2cf098..8af3b53bb 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts @@ -3,7 +3,7 @@ import { test } from "@fixtures/budgetProposal"; import { setAllureEpic } from "@helpers/allure"; import BudgetDiscussionDetailsPage from "@pages/budgetDiscussionDetailsPage"; import { expect } from "@playwright/test"; -import { dRep01Wallet } from "@constants/staticWallets"; +import { dRep03Wallet } from "@constants/staticWallets"; import BudgetDiscussionPage from "@pages/budgetDiscussionPage"; test.beforeEach(async () => { @@ -12,8 +12,8 @@ test.beforeEach(async () => { test.describe("Budget proposal dRep behaviour", () => { test.use({ - storageState: ".auth/dRep01.json", - wallet: dRep01Wallet, + storageState: ".auth/dRep03.json", + wallet: dRep03Wallet, }); test.describe("Budget proposal voting", () => { @@ -99,11 +99,11 @@ test.describe("Budget proposal dRep behaviour", () => { ).toBeVisible(); await expect(dRepCommentedCard.getByTestId("given-name")).toHaveText( - dRep01Wallet.givenName + dRep03Wallet.givenName ); await expect(dRepCommentedCard.getByTestId("drep-id")).toHaveText( - dRep01Wallet.dRepId + dRep03Wallet.dRepId ); }); }); From 4a5bf1a8e238cf4e8668aa6013461da19b1dd0e2 Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 10:43:21 +0545 Subject: [PATCH 30/45] fix: improve faucet setup balance retrieval with waited assertion --- .../govtool-frontend/playwright/tests/faucet.setup.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/govtool-frontend/playwright/tests/faucet.setup.ts b/tests/govtool-frontend/playwright/tests/faucet.setup.ts index c0f61e63e..129fc35b7 100644 --- a/tests/govtool-frontend/playwright/tests/faucet.setup.ts +++ b/tests/govtool-frontend/playwright/tests/faucet.setup.ts @@ -6,6 +6,7 @@ import { pollTransaction } from "@helpers/transaction"; import { test as setup } from "@fixtures/walletExtension"; import { loadAmountFromFaucet } from "@services/faucetService"; import kuberService from "@services/kuberService"; +import { functionWaitedAssert } from "@helpers/waitedLoop"; setup.describe.configure({ timeout: environments.txTimeOut }); @@ -16,9 +17,15 @@ setup.beforeEach(async () => { }); setup("Faucet setup", async () => { - const balance = await kuberService.getBalance(faucetWallet.address); - if (balance > 100_000) return; + let balance: number; + functionWaitedAssert( + async () => { + balance = await kuberService.getBalance(faucetWallet.address); + }, + { message: "get balance" } + ); + if (balance > 100_000) return; const res = await loadAmountFromFaucet(faucetWallet.address); await pollTransaction(res.txid); }); From dad65fa65324925f520931ef1f2c616ff77eade7 Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 11:46:42 +0545 Subject: [PATCH 31/45] tests: create and view draft bidget proposal --- .../playwright/lib/constants/staticWallets.ts | 1 + .../pages/budgetDiscussionSubmissionPage.ts | 46 ++++-- .../proposalBudgetSubmission.loggedin.spec.ts | 132 ++++++++++++------ .../playwright/tests/auth.setup.ts | 11 ++ 4 files changed, 134 insertions(+), 56 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts index cc78d6526..42a5490a3 100644 --- a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts +++ b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts @@ -29,6 +29,7 @@ export const proposal08Wallet: StaticWallet = staticWallets[18]; export const proposal09Wallet: StaticWallet = staticWallets[19]; export const budgetProposal01Wallet: StaticWallet = staticWallets[20]; +export const budgetProposal02Wallet: StaticWallet = staticWallets[21]; export const adaHolderWallets = [ adaHolder01Wallet, diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts index f48ab8bf3..f2dd72216 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts @@ -39,11 +39,13 @@ export default class BudgetDiscussionSubmissionPage { readonly createBudgetProposalBtn = this.page.getByTestId( "propose-a-budget-discussion-button" ); + readonly closeDraftBtn = this.page.getByTestId("close-button"); + readonly cancelBtn = this.page.getByTestId("cancel-button"); readonly continueBtn = this.page.getByTestId("continue-button"); readonly addLinkBtn = this.page.getByTestId("add-link-button"); readonly verifyIdentityBtn = this.page.getByTestId("verify-identity-button"); - readonly saveDraftBtn = this.page.getByTestId("save-draft-button"); + readonly saveDraftBtn = this.page.getByTestId("draft-button"); readonly submitBtn = this.page.getByTestId("submit-button"); readonly countryOfIncorporationBtn = this.page.getByTestId( "country-of-incorporation" @@ -380,33 +382,36 @@ export default class BudgetDiscussionSubmissionPage { async getAllDrafts() { await expect( - this.page.locator('[data-testid^="draft-"][data-testid$="-card"]') + this.page + .locator('[data-testid^="draft-"][data-testid$="-proposal"]') + .first() ).toBeVisible({ timeout: 60_000 }); // slow rendering return await this.page - .locator('[data-testid^="draft-"][data-testid$="-card"]') + .locator('[data-testid^="draft-"][data-testid$="-proposal"]') .all(); } async getFirstDraft() { await expect( - this.page.locator('[data-testid^="draft-"][data-testid$="-card"]').first() + this.page + .locator('[data-testid^="draft-"][data-testid$="-proposal"]') + .first() ).toBeVisible({ timeout: 60_000 }); // slow rendering return this.page - .locator('[data-testid^="draft-"][data-testid$="-card"]') + .locator('[data-testid^="draft-"][data-testid$="-proposal"]') .first(); } - async viewFirstDraft() { + async viewLastDraft() { await expect( - this.page.locator('[data-testid^="draft-"][data-testid$="-card"]') + this.page + .locator('[data-testid^="draft-"][data-testid$="-proposal"]') + .last() ).toBeVisible({ timeout: 60_000 }); // slow rendering - return await this.page - .locator('[data-testid^="draft-"][data-testid$="-start-editing"]') - .first() - .click(); + return await this.page.getByTestId("draft-start-editing").last().click(); } generateValidBudgetProposalContactInformation(): BudgetProposalContactInformationProps { @@ -521,6 +526,25 @@ export default class BudgetDiscussionSubmissionPage { }; } + async createDraftBudgetProposal(fillAllDetails = false) { + const budgetProposal = this.generateValidBudgetProposalInformation(); + + if (fillAllDetails) { + await this.fillupForm(budgetProposal); + } else { + await this.fillupContactInformationForm( + budgetProposal.contactInformation + ); + } + + await this.saveDraftBtn.click(); + await this.closeDraftBtn.click(); + await this.cancelBtn.click(); + await this.createBudgetProposalBtn.click(); + + return fillAllDetails ? budgetProposal : budgetProposal.contactInformation; + } + async createBudgetProposal(): Promise { const budgetProposalRequest: BudgetProposalProps = this.generateValidBudgetProposalInformation(); 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 0e3e97932..5a46d097f 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 @@ -1,59 +1,101 @@ -import { budgetProposal01Wallet } from "@constants/staticWallets"; -import { test } from "@fixtures/walletExtension"; +import { + budgetProposal01Wallet, + budgetProposal02Wallet, +} from "@constants/staticWallets"; +import { test } from "@fixtures/budgetProposal"; import { setAllureEpic } from "@helpers/allure"; +import { createNewPageWithWallet } from "@helpers/page"; import BudgetDiscussionSubmissionPage from "@pages/budgetDiscussionSubmissionPage"; import { expect } from "@playwright/test"; +import { BudgetProposalContactInformationProps } from "@types"; -test.beforeEach(async ({}) => { +test.beforeEach(async () => { await setAllureEpic("12. Proposal Budget Submission"); }); -test.use({ - storageState: ".auth/budgetProposal01.json", - wallet: budgetProposal01Wallet, -}); +test.describe("Budget proposal 01 wallet", () => { + test.use({ + storageState: ".auth/budgetProposal01.json", + wallet: budgetProposal01Wallet, + }); -test("12B. Should access proposal creation page in connected state", async ({ - page, -}) => { - const budgetProposalSubmissionPage = new BudgetDiscussionSubmissionPage(page); - await budgetProposalSubmissionPage.goto(); - await expect( - budgetProposalSubmissionPage.beneficiaryFullNameInput - ).toBeVisible(); -}); + test("12B. Should access proposal creation page in connected state", async ({ + page, + }) => { + const budgetProposalSubmissionPage = new BudgetDiscussionSubmissionPage( + page + ); + await budgetProposalSubmissionPage.goto(); + await expect( + budgetProposalSubmissionPage.beneficiaryFullNameInput + ).toBeVisible(); + }); -test("12C. Should view draft proposal", async ({}) => {}); + test.describe("Budget proposal field verification", () => { + test("12D_1. Should verify all field of “contact information” section", async ({}) => {}); + test("12D_2. Should verify all field of “proposal ownership” section", async ({}) => {}); + test("12D_3. Should verify all field of “problem statements and proposal benefits” section", async ({}) => {}); + test("12D_4. Should verify all field of “costing” section", async ({}) => {}); + test("12D_5. Should verify all field of “further information” section", async ({}) => {}); + test("12D_6. Should verify all field of “administration and auditing” section", async ({}) => {}); + test("12D_7. Should verify all field of “submit” section", async ({}) => {}); + }); -test.describe("Budget proposal field verification", () => { - test("12D_1. Should verify all field of “contact information” section", async ({}) => {}); - test("12D_2. Should verify all field of “proposal ownership” section", async ({}) => {}); - test("12D_3. Should verify all field of “problem statements and proposal benefits” section", async ({}) => {}); - test("12D_4. Should verify all field of “costing” section", async ({}) => {}); - test("12D_5. Should verify all field of “further information” section", async ({}) => {}); - test("12D_6. Should verify all field of “administration and auditing” section", async ({}) => {}); - test("12D_7. Should verify all field of “submit” section", async ({}) => {}); -}); + test.describe("Budget proposal field validation", () => { + test("12E_1. Should accept valid data in “contact information” section", async ({}) => {}); + test("12E_2. Should accept valid data in “proposal ownership” section", async ({}) => {}); + test("12E_3. Should accept valid data in “problem statements and proposal benefits” section", async ({}) => {}); + test("12E_4. Should accept valid data in “costing” section", async ({}) => {}); + test("12E_5. Should accept valid data in “further information” section", async ({}) => {}); + test("12E_6. Should accept valid data in “administration and auditing” section", async ({}) => {}); + test("12E_7. Should accept valid data in “submit” section", async ({}) => {}); + test("12F_1. Should reject invalid data in “contact information” section", async ({}) => {}); + test("12F_2. Should reject invalid data in “proposal ownership” section", async ({}) => {}); + test("12F_3. Should reject invalid data in “problem statements and proposal benefits” section", async ({}) => {}); + test("12F_4. Should reject invalid data in “costing” section", async ({}) => {}); + test("12F_5. Should reject invalid data in “further information” section", async ({}) => {}); + test("12F_6. Should reject invalid data in “administration and auditing” section", async ({}) => {}); + test("12F_7. Should reject invalid data in “submit” section", async ({}) => {}); + }); -test.describe("Budget proposal field validation", () => { - test("12E_1. Should accept valid data in “contact information” section", async ({}) => {}); - test("12E_2. Should accept valid data in “proposal ownership” section", async ({}) => {}); - test("12E_3. Should accept valid data in “problem statements and proposal benefits” section", async ({}) => {}); - test("12E_4. Should accept valid data in “costing” section", async ({}) => {}); - test("12E_5. Should accept valid data in “further information” section", async ({}) => {}); - test("12E_6. Should accept valid data in “administration and auditing” section", async ({}) => {}); - test("12E_7. Should accept valid data in “submit” section", async ({}) => {}); - test("12F_1. Should reject invalid data in “contact information” section", async ({}) => {}); - test("12F_2. Should reject invalid data in “proposal ownership” section", async ({}) => {}); - test("12F_3. Should reject invalid data in “problem statements and proposal benefits” section", async ({}) => {}); - test("12F_4. Should reject invalid data in “costing” section", async ({}) => {}); - test("12F_5. Should reject invalid data in “further information” section", async ({}) => {}); - test("12F_6. Should reject invalid data in “administration and auditing” section", async ({}) => {}); - test("12F_7. Should reject invalid data in “submit” section", async ({}) => {}); + test("12G. Should validate and review submitted budget proposal", async ({}) => {}); }); -test("12G. Should validate and review submitted budget proposal", async ({}) => {}); -test("12H. Should save a budget proposal as a draft", async ({}) => {}); +test("12C. Should save and view draft proposal", async ({ browser }) => { + const page = await createNewPageWithWallet(browser, { + storageState: ".auth/budgetProposal02.json", + wallet: budgetProposal02Wallet, + }); + + const budgetSubmissionPage = new BudgetDiscussionSubmissionPage(page); + await budgetSubmissionPage.goto(); + const draftContactInformationContent = + (await budgetSubmissionPage.createDraftBudgetProposal()) as BudgetProposalContactInformationProps; + const getAddDrafts = await budgetSubmissionPage.getAllDrafts(); + + expect(getAddDrafts.length).toBeGreaterThan(0); + + await budgetSubmissionPage.viewLastDraft(); + + await expect(budgetSubmissionPage.beneficiaryFullNameInput).toHaveValue( + draftContactInformationContent.beneficiaryFullName + ); + await expect(budgetSubmissionPage.beneficiaryEmailInput).toHaveValue( + draftContactInformationContent.beneficiaryEmail + ); + await expect(budgetSubmissionPage.beneficiaryCountrySelect).toHaveText( + draftContactInformationContent.beneficiaryCountry + ); + await expect(budgetSubmissionPage.beneficiaryNationalitySelect).toHaveText( + draftContactInformationContent.beneficiaryNationality + ); + await expect(budgetSubmissionPage.submissionLeadFullNameInput).toHaveValue( + draftContactInformationContent.submissionLeadFullName + ); + await expect(budgetSubmissionPage.submissionLeadEmailInput).toHaveValue( + draftContactInformationContent.submissionLeadEmail + ); +}); -test("12I. Should submit a valid budget proposal", async ({}) => {}); -test("12J. Should submit a valid draft budget proposal", async ({}) => {}); +test("12H. Should submit a valid budget proposal", async ({}) => {}); +test("12I. Should submit a valid draft budget proposal", async ({}) => {}); diff --git a/tests/govtool-frontend/playwright/tests/auth.setup.ts b/tests/govtool-frontend/playwright/tests/auth.setup.ts index 06c8c67f4..6b05f92ff 100644 --- a/tests/govtool-frontend/playwright/tests/auth.setup.ts +++ b/tests/govtool-frontend/playwright/tests/auth.setup.ts @@ -8,6 +8,7 @@ import { adaHolder05Wallet, adaHolder06Wallet, budgetProposal01Wallet, + budgetProposal02Wallet, dRep01Wallet, dRep02Wallet, dRep03Wallet, @@ -55,6 +56,7 @@ const proposal08AuthFile = ".auth/proposal08.json"; const proposal09AuthFile = ".auth/proposal09.json"; const budgetProposal01AuthFile = ".auth/budgetProposal01.json"; +const budgetProposal02AuthFile = ".auth/budgetProposal02.json"; setup.beforeEach(async () => { await setAllureEpic("Setup"); @@ -241,3 +243,12 @@ setup("Create Budget Proposal 01 auth", async ({ page, context }) => { auth: budgetProposal01AuthFile, }); }); + +setup("Create Budget Proposal 02 auth", async ({ page, context }) => { + await createAuthWithUserName({ + page, + context, + wallet: budgetProposal02Wallet, + auth: budgetProposal02AuthFile, + }); +}); From 7344adb5afdedffbebde1e4d6b961660181c09d2 Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 12:51:53 +0545 Subject: [PATCH 32/45] feat: add budgetProposal03 and budgetProposal04 wallets with corresponding auth setup --- .../playwright/lib/constants/staticWallets.ts | 2 ++ .../playwright/tests/auth.setup.ts | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts index 42a5490a3..17f486606 100644 --- a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts +++ b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts @@ -30,6 +30,8 @@ export const proposal09Wallet: StaticWallet = staticWallets[19]; export const budgetProposal01Wallet: StaticWallet = staticWallets[20]; export const budgetProposal02Wallet: StaticWallet = staticWallets[21]; +export const budgetProposal03Wallet: StaticWallet = staticWallets[22]; +export const budgetProposal04Wallet: StaticWallet = staticWallets[23]; export const adaHolderWallets = [ adaHolder01Wallet, diff --git a/tests/govtool-frontend/playwright/tests/auth.setup.ts b/tests/govtool-frontend/playwright/tests/auth.setup.ts index 6b05f92ff..2732ff065 100644 --- a/tests/govtool-frontend/playwright/tests/auth.setup.ts +++ b/tests/govtool-frontend/playwright/tests/auth.setup.ts @@ -9,6 +9,8 @@ import { adaHolder06Wallet, budgetProposal01Wallet, budgetProposal02Wallet, + budgetProposal03Wallet, + budgetProposal04Wallet, dRep01Wallet, dRep02Wallet, dRep03Wallet, @@ -57,6 +59,8 @@ const proposal09AuthFile = ".auth/proposal09.json"; const budgetProposal01AuthFile = ".auth/budgetProposal01.json"; const budgetProposal02AuthFile = ".auth/budgetProposal02.json"; +const budgetProposal03AuthFile = ".auth/budgetProposal03.json"; +const budgetProposal04AuthFile = ".auth/budgetProposal04.json"; setup.beforeEach(async () => { await setAllureEpic("Setup"); @@ -252,3 +256,21 @@ setup("Create Budget Proposal 02 auth", async ({ page, context }) => { auth: budgetProposal02AuthFile, }); }); + +setup("Create Budget Proposal 03 auth", async ({ page, context }) => { + await createAuthWithUserName({ + page, + context, + wallet: budgetProposal03Wallet, + auth: budgetProposal03AuthFile, + }); +}); + +setup("Create Budget Proposal 04 auth", async ({ page, context }) => { + await createAuthWithUserName({ + page, + context, + wallet: budgetProposal04Wallet, + auth: budgetProposal04AuthFile, + }); +}); From 54e6e0d0ab319c67cc5b5e90f9d3249c0cbd14bd Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 12:53:23 +0545 Subject: [PATCH 33/45] test: submit valid budget draft and proposal --- .../playwright/lib/fixtures/budgetProposal.ts | 3 +- .../lib/pages/budgetDiscussionDetailsPage.ts | 135 +++++++++++++++++- .../pages/budgetDiscussionSubmissionPage.ts | 10 +- .../proposalBudgetSubmission.loggedin.spec.ts | 55 ++++++- 4 files changed, 196 insertions(+), 7 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/fixtures/budgetProposal.ts b/tests/govtool-frontend/playwright/lib/fixtures/budgetProposal.ts index da0bf956e..f620d523a 100644 --- a/tests/govtool-frontend/playwright/lib/fixtures/budgetProposal.ts +++ b/tests/govtool-frontend/playwright/lib/fixtures/budgetProposal.ts @@ -21,7 +21,8 @@ export const test = base.extend({ ); await budgetProposalCreationPage.goto(); - const proposalId = await budgetProposalCreationPage.createBudgetProposal(); + const { proposalId } = + await budgetProposalCreationPage.createBudgetProposal(); const budgetProposalDetailsPage = new BudgetDiscussionDetailsPage( budgetProposalPage diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts index eabc87f2a..99d3ec1b1 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts @@ -1,5 +1,8 @@ import { expect, Page } from "@playwright/test"; -import { CommentResponse } from "@types"; +import { + BudgetProposalProps, + CommentResponse, +} from "@types"; import environments from "lib/constants/environments"; export default class BudgetDiscussionDetailsPage { @@ -17,11 +20,57 @@ export default class BudgetDiscussionDetailsPage { "change-poll-vote-yes-button" ); readonly verifyIdentityBtn = this.page.getByTestId("verify-identity-button"); + readonly readMoreBtn = this.page.getByTestId("read-more-button"); // content readonly copyLinkText = this.page.getByTestId("copy-link-text"); readonly pollVoteCard = this.page.getByTestId("poll-vote-card"); readonly totalComments = this.page.getByTestId("total-comments"); + readonly linkTextContent = this.page.getByTestId("link-0-text-content"); + readonly linkUrlContent = this.page.getByTestId("link-0-url-content"); + readonly budgetDiscussionTypeContent = this.page + .getByTestId("budget-discussion-type") + .first(); + readonly publicProposalChampionContent = this.page.getByTestId( + "public-proposal-champion" + ); + readonly socialHandlesContent = this.page.getByTestId("social-handles"); + readonly problemStatementContent = this.page.getByTestId("problem-statement"); + readonly proposalBenefitsContent = this.page.getByTestId("problem-benefit"); + readonly productRoadMapContent = this.page.getByTestId("product-roadmap"); + readonly alignProposalComittesContent = this.page.getByTestId( + "align-proposal-committees" + ); + readonly evidenceContent = this.page.getByTestId("evidence"); + readonly proposalNameContent = this.page.getByTestId("proposal-name"); + readonly proposalDescriptionContent = this.page.getByTestId( + "proposal-description" + ); + readonly proposalKeyDependenciesContent = this.page.getByTestId( + "proposal-key-dependencies" + ); + readonly milestonesContent = this.page.getByTestId("proposal-milestone"); + readonly proposalResourcesAndEstimates = this.page.getByTestId( + "proposal-resources-&-duration-estimates" + ); + readonly projectExperienceContent = + this.page.getByTestId("project-experience"); + readonly proposalContractingContent = this.page.getByTestId( + "proposal-contracting" + ); + readonly costingAmountContent = this.page.getByTestId("consting-amount"); // BUG typo + readonly costingConversionRateContent = this.page.getByTestId( + "costing-conversion-rate" + ); + readonly constingPreferedCurrencyContent = this.page.getByTestId( + "costing-preferred-currency" + ); + readonly costingPreferedCurrencyAmountContent = this.page.getByTestId( + "costing-prefereed-currency-amount" + ); + readonly costBreakdownContent = this.page.getByTestId("cost-breakdown"); + readonly includeAsAuditorContent = + this.page.getByTestId("include-as-auditor"); // Input readonly commentInput = this.page.getByTestId("comment-input"); @@ -93,4 +142,88 @@ export default class BudgetDiscussionDetailsPage { await this.page.getByTestId("delete-proposal").click(); await this.page.getByTestId("delete-proposal-yes-button").click(); } + + async validateProposalDetails(budgetProposal: BudgetProposalProps) { + await this.readMoreBtn.click(); + + // proposal ownership validation + await expect(this.publicProposalChampionContent).toHaveText( + budgetProposal.proposalOwnership.publicChampion + ); + await expect(this.socialHandlesContent).toHaveText( + budgetProposal.proposalOwnership.contactDetails + ); + + // problem statement and benefits validation + await expect(this.problemStatementContent).toHaveText( + budgetProposal.problemStatementAndBenefits.problemStatement + ); + await expect(this.proposalBenefitsContent).toHaveText( + budgetProposal.problemStatementAndBenefits.proposalBenefits + ); + await expect(this.productRoadMapContent).toHaveText( + budgetProposal.problemStatementAndBenefits.roadmapName + ); + await expect(this.budgetDiscussionTypeContent).toHaveText( + budgetProposal.problemStatementAndBenefits.budgetDiscussionType + ); + await expect(this.alignProposalComittesContent).toHaveText( + budgetProposal.problemStatementAndBenefits.committeeAlignmentType + ); + await expect(this.evidenceContent).toHaveText( + budgetProposal.problemStatementAndBenefits.suplimentaryEndorsement + ); + + // proposal details validation + await expect(this.proposalNameContent).toHaveText( + budgetProposal.proposalDetails.proposalName + ); + await expect(this.proposalDescriptionContent).toHaveText( + budgetProposal.proposalDetails.proposalDescription + ); + await expect(this.proposalKeyDependenciesContent).toHaveText( + budgetProposal.proposalDetails.proposalKeyDependencies + ); + await expect(this.milestonesContent).toHaveText( + budgetProposal.proposalDetails.milestones + ); + await expect(this.proposalResourcesAndEstimates).toHaveText( + budgetProposal.proposalDetails.teamSizeAndDuration + ); + await expect(this.projectExperienceContent).toHaveText( + budgetProposal.proposalDetails.previousExperience + ); + await expect(this.proposalContractingContent).toHaveText( + budgetProposal.proposalDetails.contracting + ); + + // costing validation + await expect(this.costingAmountContent).toHaveText( + budgetProposal.costing.adaAmount.toString() + ); + await expect(this.costingConversionRateContent).toHaveText( + budgetProposal.costing.usaToAdaCnversionRate.toString() + ); + await expect(this.constingPreferedCurrencyContent).toHaveText( + budgetProposal.costing.preferredCurrency + ); + await expect(this.costingPreferedCurrencyAmountContent).toHaveText( + budgetProposal.costing.AmountInPreferredCurrency.toString() + ); + await expect(this.costBreakdownContent).toHaveText( + budgetProposal.costing.costBreakdown + ); + + // further information validation + await expect(this.linkTextContent).toHaveText( + budgetProposal.furtherInformation[0].prop_link_text + ); + + // administration and auditing validation + await expect(this.includeAsAuditorContent).toHaveText( + budgetProposal.administrationAndAuditing.intersectAdministration + ? "Yes" + : "No" + ); + } } diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts index f2dd72216..aa9f638cf 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts @@ -545,7 +545,10 @@ export default class BudgetDiscussionSubmissionPage { return fillAllDetails ? budgetProposal : budgetProposal.contactInformation; } - async createBudgetProposal(): Promise { + async createBudgetProposal(): Promise<{ + proposalId: number; + proposalDetails: BudgetProposalProps; + }> { const budgetProposalRequest: BudgetProposalProps = this.generateValidBudgetProposalInformation(); @@ -558,6 +561,9 @@ export default class BudgetDiscussionSubmissionPage { }); const currentPageUrl = this.page.url(); - return extractProposalIdFromUrl(currentPageUrl); + return { + proposalId: extractProposalIdFromUrl(currentPageUrl), + proposalDetails: budgetProposalRequest, + }; } } 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 5a46d097f..f43a70cdb 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 @@ -1,13 +1,19 @@ import { budgetProposal01Wallet, budgetProposal02Wallet, + budgetProposal03Wallet, + budgetProposal04Wallet, } from "@constants/staticWallets"; import { test } from "@fixtures/budgetProposal"; import { setAllureEpic } from "@helpers/allure"; import { createNewPageWithWallet } from "@helpers/page"; +import BudgetDiscussionDetailsPage from "@pages/budgetDiscussionDetailsPage"; import BudgetDiscussionSubmissionPage from "@pages/budgetDiscussionSubmissionPage"; import { expect } from "@playwright/test"; -import { BudgetProposalContactInformationProps } from "@types"; +import { + BudgetProposalContactInformationProps, + BudgetProposalProps, +} from "@types"; test.beforeEach(async () => { await setAllureEpic("12. Proposal Budget Submission"); @@ -97,5 +103,48 @@ test("12C. Should save and view draft proposal", async ({ browser }) => { ); }); -test("12H. Should submit a valid budget proposal", async ({}) => {}); -test("12I. Should submit a valid draft budget proposal", async ({}) => {}); +test("12H. Should submit a valid budget proposal", async ({ browser }) => { + const page = await createNewPageWithWallet(browser, { + storageState: ".auth/budgetProposal03.json", + wallet: budgetProposal03Wallet, + }); + const budgetSubmissionPage = new BudgetDiscussionSubmissionPage(page); + await budgetSubmissionPage.goto(); + const { proposalId, proposalDetails } = + await budgetSubmissionPage.createBudgetProposal(); + + const budgetDiscussionDetailsPage = new BudgetDiscussionDetailsPage(page); + await budgetDiscussionDetailsPage.goto(proposalId); + + await budgetDiscussionDetailsPage.validateProposalDetails(proposalDetails); + + await budgetDiscussionDetailsPage.deleteProposal(); +}); + +test("12I. Should submit a valid draft budget proposal", async ({ + browser, +}) => { + test.slow(); + const page = await createNewPageWithWallet(browser, { + storageState: ".auth/budgetProposal04.json", + wallet: budgetProposal04Wallet, + }); + + const budgetSubmissionPage = new BudgetDiscussionSubmissionPage(page); + await budgetSubmissionPage.goto(); + const draftContact = (await budgetSubmissionPage.createDraftBudgetProposal( + true + )) as BudgetProposalProps; + + await budgetSubmissionPage.viewLastDraft(); + + for (let i = 0; i < 8; i++) { + await budgetSubmissionPage.continueBtn.click(); + } + await budgetSubmissionPage.submitBtn.click(); + + const budgetDiscussionDetailsPage = new BudgetDiscussionDetailsPage(page); + await budgetDiscussionDetailsPage.validateProposalDetails(draftContact); + + await budgetDiscussionDetailsPage.deleteProposal(); +}); From cdd56405c09a86584868f3c0e94d32e2f0894e21 Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 12:55:15 +0545 Subject: [PATCH 34/45] refactor: remove unused skipTestForProposalBudget function --- tests/govtool-frontend/playwright/lib/helpers/cardano.ts | 5 ----- .../playwright/lib/pages/budgetDiscussionDetailsPage.ts | 5 +---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/helpers/cardano.ts b/tests/govtool-frontend/playwright/lib/helpers/cardano.ts index ab686da31..ad7126a94 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/cardano.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/cardano.ts @@ -65,8 +65,3 @@ export async function skipIfMainnet() { test.skip(); } } - -export async function skipTestForProposalBudget() { - await allure.description("Proposal budget features are not yet available."); - test.skip(); -} diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts index 99d3ec1b1..b86872428 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts @@ -1,8 +1,5 @@ import { expect, Page } from "@playwright/test"; -import { - BudgetProposalProps, - CommentResponse, -} from "@types"; +import { BudgetProposalProps, CommentResponse } from "@types"; import environments from "lib/constants/environments"; export default class BudgetDiscussionDetailsPage { From ce88512ff0cda2c843c227fba8f9352451468eaf Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 13:00:53 +0545 Subject: [PATCH 35/45] chore: update proposal creation page access test --- .../proposalBudgetSubmission.loggedin.spec.ts | 73 ++++++++++--------- 1 file changed, 40 insertions(+), 33 deletions(-) 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 f43a70cdb..e3434968a 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 @@ -28,43 +28,50 @@ test.describe("Budget proposal 01 wallet", () => { test("12B. Should access proposal creation page in connected state", async ({ page, }) => { - const budgetProposalSubmissionPage = new BudgetDiscussionSubmissionPage( - page - ); - await budgetProposalSubmissionPage.goto(); - await expect( - budgetProposalSubmissionPage.beneficiaryFullNameInput - ).toBeVisible(); - }); + await page.goto("/"); + await page.getByTestId("budget-discussion-link").click(); + await page.getByTestId("verify-identity-button").click(); - test.describe("Budget proposal field verification", () => { - test("12D_1. Should verify all field of “contact information” section", async ({}) => {}); - test("12D_2. Should verify all field of “proposal ownership” section", async ({}) => {}); - test("12D_3. Should verify all field of “problem statements and proposal benefits” section", async ({}) => {}); - test("12D_4. Should verify all field of “costing” section", async ({}) => {}); - test("12D_5. Should verify all field of “further information” section", async ({}) => {}); - test("12D_6. Should verify all field of “administration and auditing” section", async ({}) => {}); - test("12D_7. Should verify all field of “submit” section", async ({}) => {}); + await expect( + page.getByTestId("propose-a-budget-discussion-button") + ).toBeVisible({ timeout: 60_000 }); }); - test.describe("Budget proposal field validation", () => { - test("12E_1. Should accept valid data in “contact information” section", async ({}) => {}); - test("12E_2. Should accept valid data in “proposal ownership” section", async ({}) => {}); - test("12E_3. Should accept valid data in “problem statements and proposal benefits” section", async ({}) => {}); - test("12E_4. Should accept valid data in “costing” section", async ({}) => {}); - test("12E_5. Should accept valid data in “further information” section", async ({}) => {}); - test("12E_6. Should accept valid data in “administration and auditing” section", async ({}) => {}); - test("12E_7. Should accept valid data in “submit” section", async ({}) => {}); - test("12F_1. Should reject invalid data in “contact information” section", async ({}) => {}); - test("12F_2. Should reject invalid data in “proposal ownership” section", async ({}) => {}); - test("12F_3. Should reject invalid data in “problem statements and proposal benefits” section", async ({}) => {}); - test("12F_4. Should reject invalid data in “costing” section", async ({}) => {}); - test("12F_5. Should reject invalid data in “further information” section", async ({}) => {}); - test("12F_6. Should reject invalid data in “administration and auditing” section", async ({}) => {}); - test("12F_7. Should reject invalid data in “submit” section", async ({}) => {}); + test.describe("Budget proposal with proposalSubmissionPageNavigation", () => { + let budgetProposalSubmissionPage: BudgetDiscussionSubmissionPage; + test.beforeEach(async ({ page }) => { + const budgetSubmissionPage = new BudgetDiscussionSubmissionPage(page); + await budgetSubmissionPage.goto(); + }); + test.describe("Budget proposal field verification", () => { + test("12D_1. Should verify all field of “contact information” section", async ({}) => {}); + test("12D_2. Should verify all field of “proposal ownership” section", async ({}) => {}); + test("12D_3. Should verify all field of “problem statements and proposal benefits” section", async ({}) => {}); + test("12D_4. Should verify all field of “costing” section", async ({}) => {}); + test("12D_5. Should verify all field of “further information” section", async ({}) => {}); + test("12D_6. Should verify all field of “administration and auditing” section", async ({}) => {}); + test("12D_7. Should verify all field of “submit” section", async ({}) => {}); + }); + + test.describe("Budget proposal field validation", () => { + test("12E_1. Should accept valid data in “contact information” section", async ({}) => {}); + test("12E_2. Should accept valid data in “proposal ownership” section", async ({}) => {}); + test("12E_3. Should accept valid data in “problem statements and proposal benefits” section", async ({}) => {}); + test("12E_4. Should accept valid data in “costing” section", async ({}) => {}); + test("12E_5. Should accept valid data in “further information” section", async ({}) => {}); + test("12E_6. Should accept valid data in “administration and auditing” section", async ({}) => {}); + test("12E_7. Should accept valid data in “submit” section", async ({}) => {}); + test("12F_1. Should reject invalid data in “contact information” section", async ({}) => {}); + test("12F_2. Should reject invalid data in “proposal ownership” section", async ({}) => {}); + test("12F_3. Should reject invalid data in “problem statements and proposal benefits” section", async ({}) => {}); + test("12F_4. Should reject invalid data in “costing” section", async ({}) => {}); + test("12F_5. Should reject invalid data in “further information” section", async ({}) => {}); + test("12F_6. Should reject invalid data in “administration and auditing” section", async ({}) => {}); + test("12F_7. Should reject invalid data in “submit” section", async ({}) => {}); + }); + + test("12G. Should validate and review submitted budget proposal", async ({}) => {}); }); - - test("12G. Should validate and review submitted budget proposal", async ({}) => {}); }); test("12C. Should save and view draft proposal", async ({ browser }) => { From ecce28de2ac5884691d438acc04cecdfa7397b75 Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 13:55:52 +0545 Subject: [PATCH 36/45] tests: budget discussion form field visibility --- .../pages/budgetDiscussionSubmissionPage.ts | 73 ++++--- .../proposalBudgetSubmission.loggedin.spec.ts | 184 ++++++++++++++++-- 2 files changed, 214 insertions(+), 43 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts index aa9f638cf..968426c2f 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts @@ -74,7 +74,9 @@ export default class BudgetDiscussionSubmissionPage { // proposal-ownership readonly companyNameInput = this.page.getByLabel("Company Name *"); //BUG missing test Ids - readonly companyDomainName = this.page.getByLabel("Company Domain Name *"); //BUG missing test Ids + readonly companyDomainNameInput = this.page.getByLabel( + "Company Domain Name *" + ); //BUG missing test Ids readonly groupNameInput = this.page.getByLabel("Group Name *"); //BUG missing test Ids readonly groupTypeInput = this.page.getByLabel("Type of Group *"); //BUG missing test Ids readonly keyInformationOfGroupInput = this.page.getByLabel( @@ -144,7 +146,9 @@ export default class BudgetDiscussionSubmissionPage { ); readonly companyTypeSelect = this.page.getByTestId("beneficiary-type"); - readonly publicChampion = this.page.getByTestId("proposal-public-champion"); + readonly publicChampionSelect = this.page.getByTestId( + "proposal-public-champion" + ); readonly roadmapNameSelect = this.page.getByTestId("roadmap-name"); readonly budgetDiscussionTypeSelect = this.page.getByTestId( @@ -168,6 +172,10 @@ export default class BudgetDiscussionSubmissionPage { constructor(private readonly page: Page) {} + get currentPage(): Page { + return this.page; + } + async goto() { await this.page.goto(`${environments.frontendUrl}/budget_discussion`); @@ -215,7 +223,7 @@ export default class BudgetDiscussionSubmissionPage { .getByRole("option", { name: proposalOwnership.companyType }) .click(); //BUG missing testId - await this.publicChampion.click(); + await this.publicChampionSelect.click(); await this.page .getByRole("option", { name: proposalOwnership.publicChampion }) .click(); //BUG missing testId @@ -231,7 +239,9 @@ export default class BudgetDiscussionSubmissionPage { } if (proposalOwnership.companyType === "Company") { await this.companyNameInput.fill(proposalOwnership.companyName); - await this.companyDomainName.fill(proposalOwnership.companyDomainName); + await this.companyDomainNameInput.fill( + proposalOwnership.companyDomainName + ); await this.countryOfIncorporationBtn.click(); await this.page .getByTestId( @@ -349,35 +359,46 @@ export default class BudgetDiscussionSubmissionPage { await this.continueBtn.click(); } - async fillupForm(budgetProposal: BudgetProposalProps) { + async fillupForm(budgetProposal: BudgetProposalProps, stage = 8) { await this.fillupContactInformationForm(budgetProposal.contactInformation); - await this.fillupProposalOwnershipForm(budgetProposal.proposalOwnership); + if (stage > 2) { + await this.fillupProposalOwnershipForm(budgetProposal.proposalOwnership); + } - await this.fillupProblemStatementAndBenefitsForm( - budgetProposal.problemStatementAndBenefits - ); + if (stage > 3) { + await this.fillupProblemStatementAndBenefitsForm( + budgetProposal.problemStatementAndBenefits + ); + } - await this.fillupProposalDetailsForm(budgetProposal.proposalDetails); - await this.fillupCostingForm(budgetProposal.costing); - await this.fillupFurtherInformation(budgetProposal.furtherInformation); + if (stage > 4) { + await this.fillupProposalDetailsForm(budgetProposal.proposalDetails); + } + if (stage > 5) { + await this.fillupCostingForm(budgetProposal.costing); + } + if (stage > 6) { + await this.fillupFurtherInformation(budgetProposal.furtherInformation); + } + if (stage > 7) { + await this.intersectNamedAdministratorSelect.click(); - await this.intersectNamedAdministratorSelect.click(); + await this.page + .getByTestId( + `${budgetProposal.administrationAndAuditing.intersectAdministration}-button` + ) + .click(); + if (!budgetProposal.administrationAndAuditing.intersectAdministration) { + await this.venderDetailsInput.fill( + budgetProposal.administrationAndAuditing.venderDetails + ); + } + await this.continueBtn.click(); - await this.page - .getByTestId( - `${budgetProposal.administrationAndAuditing.intersectAdministration}-button` - ) - .click(); - if (!budgetProposal.administrationAndAuditing.intersectAdministration) { - await this.venderDetailsInput.fill( - budgetProposal.administrationAndAuditing.venderDetails - ); + await this.submitCheckbox.click(); + await this.continueBtn.click(); } - await this.continueBtn.click(); - - await this.submitCheckbox.click(); - await this.continueBtn.click(); } async getAllDrafts() { 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 e3434968a..b42d941cc 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 @@ -13,6 +13,7 @@ import { expect } from "@playwright/test"; import { BudgetProposalContactInformationProps, BudgetProposalProps, + CompanyEnum, } from "@types"; test.beforeEach(async () => { @@ -40,34 +41,183 @@ test.describe("Budget proposal 01 wallet", () => { test.describe("Budget proposal with proposalSubmissionPageNavigation", () => { let budgetProposalSubmissionPage: BudgetDiscussionSubmissionPage; test.beforeEach(async ({ page }) => { - const budgetSubmissionPage = new BudgetDiscussionSubmissionPage(page); - await budgetSubmissionPage.goto(); + budgetProposalSubmissionPage = new BudgetDiscussionSubmissionPage(page); + await budgetProposalSubmissionPage.goto(); }); + test.describe("Budget proposal field verification", () => { - test("12D_1. Should verify all field of “contact information” section", async ({}) => {}); - test("12D_2. Should verify all field of “proposal ownership” section", async ({}) => {}); - test("12D_3. Should verify all field of “problem statements and proposal benefits” section", async ({}) => {}); - test("12D_4. Should verify all field of “costing” section", async ({}) => {}); - test("12D_5. Should verify all field of “further information” section", async ({}) => {}); - test("12D_6. Should verify all field of “administration and auditing” section", async ({}) => {}); - test("12D_7. Should verify all field of “submit” section", async ({}) => {}); + test("12D_1. Should verify all field of “contact information” section", async () => { + await expect( + budgetProposalSubmissionPage.beneficiaryFullNameInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.beneficiaryEmailInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.beneficiaryCountrySelect + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.beneficiaryNationalitySelect + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.submissionLeadFullNameInput + ).toBeVisible(); + }); + + test("12D_2. Should verify all field of “proposal ownership” section", async () => { + const proposalContactInformationContent = + budgetProposalSubmissionPage.generateValidBudgetProposalContactInformation(); + await budgetProposalSubmissionPage.fillupContactInformationForm( + proposalContactInformationContent + ); + + // default field + await expect( + budgetProposalSubmissionPage.companyTypeSelect + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.publicChampionSelect + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.contactDetailsInput + ).toBeVisible(); + + // company type field + await budgetProposalSubmissionPage.companyTypeSelect.click(); + await budgetProposalSubmissionPage.currentPage + .getByRole("option", { name: CompanyEnum.Company }) + .click(); //BUG missing testId + + await expect( + budgetProposalSubmissionPage.companyNameInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.companyDomainNameInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.countryOfIncorporationBtn + ).toBeVisible(); + + // group type field + await budgetProposalSubmissionPage.companyTypeSelect.click(); + await budgetProposalSubmissionPage.currentPage + .getByRole("option", { name: CompanyEnum.Group }) + .click(); //BUG missing testId + await expect(budgetProposalSubmissionPage.groupNameInput).toBeVisible(); + await expect(budgetProposalSubmissionPage.groupTypeInput).toBeVisible(); + await expect( + budgetProposalSubmissionPage.keyInformationOfGroupInput + ).toBeVisible(); + }); + + test("12D_3. Should verify all field of “problem statements and proposal benefits” section", async () => { + const proposalInformation = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm(proposalInformation, 3); + + await expect( + budgetProposalSubmissionPage.problemStatementInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.proposalBenefitInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.roadmapNameSelect + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.budgetDiscussionTypeSelect + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.committeeAlignmentTypeSelect + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.suplimentaryEndorsementInput + ).toBeVisible(); + }); + + test("12D_4. Should verify all field of “proposal details” section", async () => { + const proposalInformation = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm(proposalInformation, 4); + + await expect( + budgetProposalSubmissionPage.proposalNameInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.proposalDescriptionInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.proposalKeyDependenciesInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.milestonesInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.teamSizeAndDurationInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.previousExperienceInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.contractingTypeSelect + ).toBeVisible(); + }); + + test("12D_5. Should verify all field of “costing” section", async () => { + const proposalInformation = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm(proposalInformation, 5); + + await expect(budgetProposalSubmissionPage.adaAmountInput).toBeVisible(); + await expect( + budgetProposalSubmissionPage.usaToAdaCnversionRateInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.preferredCurrencySelect + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.preferredCurrencyAmountInput + ).toBeVisible(); + await expect( + budgetProposalSubmissionPage.costBreakdownInput + ).toBeVisible(); + }); + + test("12D_6. Should verify all field of “further information” section", async () => { + const proposalInformation = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm(proposalInformation, 6); + + await expect(budgetProposalSubmissionPage.linkTextInput).toBeVisible(); + await expect(budgetProposalSubmissionPage.linkUrlInput).toBeVisible(); + await expect(budgetProposalSubmissionPage.addLinkBtn).toBeVisible(); + }); + + test("12D_7. Should verify all field of “administration and auditing” section", async () => { + const proposalInformation = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm(proposalInformation, 7); + + await expect( + budgetProposalSubmissionPage.intersectNamedAdministratorSelect + ).toBeVisible(); + }); }); test.describe("Budget proposal field validation", () => { test("12E_1. Should accept valid data in “contact information” section", async ({}) => {}); test("12E_2. Should accept valid data in “proposal ownership” section", async ({}) => {}); test("12E_3. Should accept valid data in “problem statements and proposal benefits” section", async ({}) => {}); - test("12E_4. Should accept valid data in “costing” section", async ({}) => {}); - test("12E_5. Should accept valid data in “further information” section", async ({}) => {}); - test("12E_6. Should accept valid data in “administration and auditing” section", async ({}) => {}); - test("12E_7. Should accept valid data in “submit” section", async ({}) => {}); + test("12E_4. Should accept valid data in “proposal details” section", async ({}) => {}); + test("12E_5. Should accept valid data in “costing” section", async ({}) => {}); + test("12E_6. Should accept valid data in “further information” section", async ({}) => {}); + test("12F_1. Should reject invalid data in “contact information” section", async ({}) => {}); test("12F_2. Should reject invalid data in “proposal ownership” section", async ({}) => {}); test("12F_3. Should reject invalid data in “problem statements and proposal benefits” section", async ({}) => {}); - test("12F_4. Should reject invalid data in “costing” section", async ({}) => {}); - test("12F_5. Should reject invalid data in “further information” section", async ({}) => {}); - test("12F_6. Should reject invalid data in “administration and auditing” section", async ({}) => {}); - test("12F_7. Should reject invalid data in “submit” section", async ({}) => {}); + test("12E_4. Should accept invalid data in “proposal details” section", async ({}) => {}); + test("12F_5. Should reject invalid data in “costing” section", async ({}) => {}); + test("12F_6. Should reject invalid data in “further information” section", async ({}) => {}); }); test("12G. Should validate and review submitted budget proposal", async ({}) => {}); From 5a95dc4a49c791e2aaa15930b2a836f28f65371b Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 14:08:33 +0545 Subject: [PATCH 37/45] fix: change generate wallet to 24 --- tests/govtool-frontend/playwright/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/govtool-frontend/playwright/package.json b/tests/govtool-frontend/playwright/package.json index 48f48a1f6..a57cd1b79 100644 --- a/tests/govtool-frontend/playwright/package.json +++ b/tests/govtool-frontend/playwright/package.json @@ -26,7 +26,7 @@ "test": "npx playwright test", "format": "prettier . --write", "test:outcomes": "npx playwright test outcomes.spec.ts --ui", - "generate-wallets": "ts-node ./generate_wallets.ts 20" + "generate-wallets": "ts-node ./generate_wallets.ts 24" }, "dependencies": { "@cardanoapi/cardano-test-wallet": "^3.0.0", From 87ba0a33f687717744114f4716b3cd90c74158c5 Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 15:20:23 +0545 Subject: [PATCH 38/45] tests: validate review submitted budget proposal --- .../lib/pages/budgetDiscussionDetailsPage.ts | 4 +- .../pages/budgetDiscussionSubmissionPage.ts | 275 +++++++++++++++++- .../govtool-frontend/playwright/lib/types.ts | 12 +- .../proposalBudgetSubmission.loggedin.spec.ts | 10 +- 4 files changed, 278 insertions(+), 23 deletions(-) diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts index b86872428..9ac2efb25 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionDetailsPage.ts @@ -199,7 +199,7 @@ export default class BudgetDiscussionDetailsPage { budgetProposal.costing.adaAmount.toString() ); await expect(this.costingConversionRateContent).toHaveText( - budgetProposal.costing.usaToAdaCnversionRate.toString() + budgetProposal.costing.adaToUsdConversionRate.toString() ); await expect(this.constingPreferedCurrencyContent).toHaveText( budgetProposal.costing.preferredCurrency @@ -218,7 +218,7 @@ export default class BudgetDiscussionDetailsPage { // administration and auditing validation await expect(this.includeAsAuditorContent).toHaveText( - budgetProposal.administrationAndAuditing.intersectAdministration + budgetProposal.administrationAndAuditing.intersectAdministration === true ? "Yes" : "No" ); diff --git a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts index 968426c2f..9d2ff5197 100644 --- a/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/budgetDiscussionSubmissionPage.ts @@ -170,6 +170,93 @@ export default class BudgetDiscussionSubmissionPage { readonly linkTextContent = this.page.getByTestId("link-0-text-content"); readonly linkUrlContent = this.page.getByTestId("link-0-url-content"); + // contact information + readonly beneficiaryFullNameContent = this.page.getByTestId( + "beneficiary-full-name-content" + ); + readonly beneficiaryCountryOfResidenceContent = this.page.getByTestId( + "beneficiary-country-of-residence-content" + ); + + // proposal ownership + readonly companyTypeContent = this.page.getByTestId( + "submited-on-behalf-content" + ); + readonly groupNameContent = this.page.getByTestId("group-name-content"); + readonly groupTypeContent = this.page.getByTestId("group-type-content"); + readonly groupKeyIdentityContent = this.page.getByTestId( + "group-identity-information-content" + ); + readonly companyNameContent = this.page.getByTestId("company-name-content"); + readonly companyDomainNameContent = this.page.getByTestId( + "company-domain-name-content" + ); + readonly countryOfIncorporationContent = this.page.getByTestId( + "country-of-incorporation-content" + ); + readonly providePreferredContent = this.page.getByTestId( + "provide-preferred-content" + ); + readonly socialHandlesContent = this.page.getByTestId( + "social-handles-content" + ); + + // problem statements and benefits + readonly problemStatementContent = this.page.getByTestId( + "problem-statement-content" + ); + readonly proposalBenefitsContent = this.page.getByTestId( + "proposal-benefit-content" + ); + readonly roadmapContent = this.page.getByTestId("roadmap-content"); + readonly budgetCategoryContent = this.page.getByTestId( + "budget-category-content" + ); + readonly committeeContent = this.page.getByTestId("committee-content"); + readonly endorsementContent = this.page.getByTestId("endorsement-content"); + + // proposal details + readonly proposalNameContent = this.page.getByTestId("proposal-name-content"); + readonly proposalDescriptionContent = this.page.getByTestId( + "proposal-description-content" + ); + readonly proposalKeyDependenciesContent = this.page.getByTestId( + "key-dependencies-content" + ); + readonly proposalMaintainAndSupportContent = this.page.getByTestId( + "maintain-and-support-content" + ); + readonly proposalDeliverablesContent = this.page.getByTestId( + "key-proposal-deliverables-content" + ); + readonly resourcingDurationEstimatesContent = this.page.getByTestId( + "resourcing-duration-estimates-content" + ); + readonly experienceContent = this.page.getByTestId("experience-content"); + readonly contractingContent = this.page.getByTestId( + "contracting-type-name-content" + ); + + // costing + readonly adaAmountContent = this.page.getByTestId("ada-amount-content"); + readonly adaToUsdConversionRateContent = this.page.getByTestId( + "usd-to-ada-conversion-rate-content" + ); // BUG typo + readonly preferredCurrencyContent = this.page.getByTestId( + "preferred-currency-content" + ); + readonly preferredCurrencyAmountContent = this.page.getByTestId( + "amount-in-preferred-currency-content" + ); + readonly costBreakdownContent = this.page.getByTestId( + "cost-breakdown-content" + ); + + // administration and auditing + readonly intersectAdministrationContent = this.page.getByTestId( + "intersect-named-administrator-content" + ); + constructor(private readonly page: Page) {} get currentPage(): Page { @@ -195,13 +282,13 @@ export default class BudgetDiscussionSubmissionPage { await this.beneficiaryCountrySelect.click(); await this.page .getByTestId( - `${contactInformation.beneficiaryCountry.toLowerCase()}-button` + `${contactInformation.beneficiaryCountry.toLowerCase().replace(/ /g, "-")}-button` ) .click(); await this.beneficiaryNationalitySelect.click(); await this.page .getByTestId( - `${contactInformation.beneficiaryNationality.toLowerCase()}-button` + `${contactInformation.beneficiaryNationality.toLowerCase().replace(/ /g, "-")}-button` ) .click(); @@ -245,7 +332,7 @@ export default class BudgetDiscussionSubmissionPage { await this.countryOfIncorporationBtn.click(); await this.page .getByTestId( - `${proposalOwnership.countryOfIncorportation.toLowerCase()}-country-of-incorporation-button` + `${proposalOwnership.countryOfIncorportation.toLowerCase().replace(/ /g, "-")}-country-of-incorporation-button` ) .click(); } @@ -330,7 +417,7 @@ export default class BudgetDiscussionSubmissionPage { async fillupCostingForm(costing: BudgetCostingProps) { await this.adaAmountInput.fill(costing.adaAmount.toString()); await this.usaToAdaCnversionRateInput.fill( - costing.usaToAdaCnversionRate.toString() + costing.adaToUsdConversionRate.toString() ); await this.preferredCurrencySelect.click(); await this.page @@ -439,12 +526,12 @@ export default class BudgetDiscussionSubmissionPage { return { beneficiaryFullName: faker.person.fullName(), beneficiaryEmail: faker.internet.email(), - beneficiaryCountry: faker.helpers - .arrayElement(Object.values(LocationEnum)) - .replace(/ /g, "-"), - beneficiaryNationality: faker.helpers - .arrayElement(Object.values(LocationEnum)) - .replace(/ /g, "-"), + beneficiaryCountry: faker.helpers.arrayElement( + Object.values(LocationEnum) + ), + beneficiaryNationality: faker.helpers.arrayElement( + Object.values(LocationEnum) + ), submissionLeadFullName: faker.person.fullName(), submissionLeadEmail: faker.internet.email(), }; @@ -480,9 +567,9 @@ export default class BudgetDiscussionSubmissionPage { groupKeyIdentity: faker.lorem.paragraph(2), companyName: faker.company.name(), companyDomainName: faker.internet.domainName(), - countryOfIncorportation: faker.helpers - .arrayElement(Object.values(LocationEnum)) - .replace(/ /g, "-"), + countryOfIncorportation: faker.helpers.arrayElement( + Object.values(LocationEnum) + ), }; } @@ -505,7 +592,7 @@ export default class BudgetDiscussionSubmissionPage { generateValidCosting(): BudgetCostingProps { return { adaAmount: faker.number.int({ min: 100, max: 10000 }), - usaToAdaCnversionRate: faker.number.int({ min: 1, max: 100 }), + adaToUsdConversionRate: faker.number.int({ min: 1, max: 100 }), preferredCurrency: faker.helpers.arrayElement( Object.values(PreferredCurrencyEnum) ), @@ -587,4 +674,164 @@ export default class BudgetDiscussionSubmissionPage { proposalDetails: budgetProposalRequest, }; } + + async validateReviewBudgetProposal( + proposalInformations: BudgetProposalProps + ) { + // contact information + await expect(this.beneficiaryFullNameContent).toHaveText( + proposalInformations.contactInformation.beneficiaryFullName + ); + await expect(this.beneficiaryCountryOfResidenceContent).toHaveText( + proposalInformations.contactInformation.beneficiaryCountry + ); + //BUG missing testId + await expect( + this.currentPage.getByText( + proposalInformations.contactInformation.beneficiaryNationality, + { exact: true } + ) + ).toBeVisible(); + //BUG missing testId + await expect( + this.currentPage.getByText( + proposalInformations.contactInformation.submissionLeadEmail, + { exact: true } + ) + ).toBeVisible(); + //BUG missing testId + await expect( + this.currentPage.getByText( + proposalInformations.contactInformation.submissionLeadFullName, + { exact: true } + ) + ).toBeVisible(); + + // proposal ownership + await expect(this.companyTypeContent).toHaveText( + proposalInformations.proposalOwnership.companyType + ); + await expect(this.providePreferredContent).toHaveText( + proposalInformations.proposalOwnership.publicChampion + ); + await expect(this.socialHandlesContent).toHaveText( + proposalInformations.proposalOwnership.contactDetails + ); + + if ( + proposalInformations.proposalOwnership.companyType === CompanyEnum.Company + ) { + await expect(this.companyNameContent).toHaveText( + proposalInformations.proposalOwnership.companyName + ); + await expect(this.companyDomainNameContent).toHaveText( + proposalInformations.proposalOwnership.companyDomainName + ); + await expect(this.countryOfIncorporationContent).toHaveText( + proposalInformations.proposalOwnership.countryOfIncorportation + ); + } + if ( + proposalInformations.proposalOwnership.companyType === CompanyEnum.Group + ) { + await expect(this.groupNameContent).toHaveText( + proposalInformations.proposalOwnership.groupName + ); + await expect(this.groupTypeContent).toHaveText( + proposalInformations.proposalOwnership.groupType + ); + await expect(this.groupKeyIdentityContent).toHaveText( + proposalInformations.proposalOwnership.groupKeyIdentity + ); + } + + // problem statement and proposal benefits + await expect(this.problemStatementContent).toHaveText( + proposalInformations.problemStatementAndBenefits.problemStatement + ); + await expect(this.proposalBenefitsContent).toHaveText( + proposalInformations.problemStatementAndBenefits.proposalBenefits + ); + await expect(this.roadmapContent).toHaveText( + proposalInformations.problemStatementAndBenefits.roadmapName + ); + await expect(this.budgetCategoryContent).toHaveText( + proposalInformations.problemStatementAndBenefits.budgetDiscussionType + ); + await expect(this.committeeContent).toHaveText( + proposalInformations.problemStatementAndBenefits.committeeAlignmentType + ); + await expect(this.endorsementContent).toHaveText( + proposalInformations.problemStatementAndBenefits.suplimentaryEndorsement + ); + + // proposal details + await expect(this.proposalNameContent).toHaveText( + proposalInformations.proposalDetails.proposalName + ); + await expect(this.proposalDescriptionContent).toHaveText( + proposalInformations.proposalDetails.proposalDescription + ); + await expect(this.proposalKeyDependenciesContent).toHaveText( + proposalInformations.proposalDetails.proposalKeyDependencies + ); + await expect(this.proposalMaintainAndSupportContent).toHaveText( + proposalInformations.proposalDetails.proposalMaintainAndSupport + ); + await expect(this.proposalDeliverablesContent).toHaveText( + proposalInformations.proposalDetails.milestones + ); + await expect(this.resourcingDurationEstimatesContent).toHaveText( + proposalInformations.proposalDetails.teamSizeAndDuration + ); + await expect(this.experienceContent).toHaveText( + proposalInformations.proposalDetails.previousExperience + ); + await expect(this.contractingContent).toHaveText( + proposalInformations.proposalDetails.contracting + ); + + // costing + await expect(this.adaAmountContent).toHaveText( + proposalInformations.costing.adaAmount.toString() + ); + await expect(this.adaToUsdConversionRateContent).toHaveText( + proposalInformations.costing.adaToUsdConversionRate.toString() + ); + + const preferredCurrencyShortForm = Object.keys(PreferredCurrencyEnum).find( + (key) => + PreferredCurrencyEnum[key as keyof typeof PreferredCurrencyEnum] === + proposalInformations.costing.preferredCurrency + ); + + await expect(this.preferredCurrencyContent).toHaveText( + preferredCurrencyShortForm + ); + await expect(this.preferredCurrencyAmountContent).toHaveText( + proposalInformations.costing.AmountInPreferredCurrency.toString() + ); + await expect(this.costBreakdownContent).toHaveText( + proposalInformations.costing.costBreakdown + ); + + // further information + for (let i = 0; i < proposalInformations.furtherInformation.length; i++) { + //BUG missing testId + await expect( + this.currentPage.getByRole("link", { + name: proposalInformations.furtherInformation[i].prop_link_text, + exact: true, + }) + ).toBeVisible(); + } + + // administration and auditing + await expect(this.intersectAdministrationContent).toHaveText( + proposalInformations.administrationAndAuditing.intersectAdministration === + true + ? "Yes" + : "No" + ); + } } diff --git a/tests/govtool-frontend/playwright/lib/types.ts b/tests/govtool-frontend/playwright/lib/types.ts index 7173a5529..4efb623d6 100644 --- a/tests/govtool-frontend/playwright/lib/types.ts +++ b/tests/govtool-frontend/playwright/lib/types.ts @@ -489,16 +489,16 @@ export type preferredCurrencyType = | "Nepalese Rupee"; export enum PreferredCurrencyEnum { - UnitedStatesDollar = "United States Dollar", - Euro = "Euro", - JapaneseYen = "Japanese Yen", - AustralianDollar = "Australian Dollar", - NepaleseRupee = "Nepalese Rupee", + USD = "United States Dollar", + EUR = "Euro", + JPY = "Japanese Yen", + AUD = "Australian Dollar", + NPR = "Nepalese Rupee", } export interface BudgetCostingProps { adaAmount: number; - usaToAdaCnversionRate: number; + adaToUsdConversionRate: number; preferredCurrency: preferredCurrencyType; AmountInPreferredCurrency: 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 b42d941cc..dda04ae39 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 @@ -220,7 +220,15 @@ test.describe("Budget proposal 01 wallet", () => { test("12F_6. Should reject invalid data in “further information” section", async ({}) => {}); }); - test("12G. Should validate and review submitted budget proposal", async ({}) => {}); + test("12G. Should validate and review submitted budget proposal", async () => { + const proposalInformations = + budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); + await budgetProposalSubmissionPage.fillupForm(proposalInformations); + + await budgetProposalSubmissionPage.validateReviewBudgetProposal( + proposalInformations + ); + }); }); }); From 250d1acdf13a59a95ad9b4c03343805ed2c136d0 Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 15:24:37 +0545 Subject: [PATCH 39/45] chore: skip pending implementation tests and add description --- .../proposalBudgetSubmission.loggedin.spec.ts | 39 +++++++++++-------- 1 file changed, 23 insertions(+), 16 deletions(-) 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 dda04ae39..181b37138 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 @@ -15,6 +15,7 @@ import { BudgetProposalProps, CompanyEnum, } from "@types"; +import { allure } from "allure-playwright"; test.beforeEach(async () => { await setAllureEpic("12. Proposal Budget Submission"); @@ -204,22 +205,6 @@ test.describe("Budget proposal 01 wallet", () => { }); }); - test.describe("Budget proposal field validation", () => { - test("12E_1. Should accept valid data in “contact information” section", async ({}) => {}); - test("12E_2. Should accept valid data in “proposal ownership” section", async ({}) => {}); - test("12E_3. Should accept valid data in “problem statements and proposal benefits” section", async ({}) => {}); - test("12E_4. Should accept valid data in “proposal details” section", async ({}) => {}); - test("12E_5. Should accept valid data in “costing” section", async ({}) => {}); - test("12E_6. Should accept valid data in “further information” section", async ({}) => {}); - - test("12F_1. Should reject invalid data in “contact information” section", async ({}) => {}); - test("12F_2. Should reject invalid data in “proposal ownership” section", async ({}) => {}); - test("12F_3. Should reject invalid data in “problem statements and proposal benefits” section", async ({}) => {}); - test("12E_4. Should accept invalid data in “proposal details” section", async ({}) => {}); - test("12F_5. Should reject invalid data in “costing” section", async ({}) => {}); - test("12F_6. Should reject invalid data in “further information” section", async ({}) => {}); - }); - test("12G. Should validate and review submitted budget proposal", async () => { const proposalInformations = budgetProposalSubmissionPage.generateValidBudgetProposalInformation(); @@ -232,6 +217,28 @@ test.describe("Budget proposal 01 wallet", () => { }); }); +test.describe("Budget proposal field validation", () => { + test.beforeEach(async () => { + await allure.description( + "Field validation tests are pending implementation." + ); + test.skip(); + }); + test("12E_1. Should accept valid data in “contact information” section", async ({}) => {}); + test("12E_2. Should accept valid data in “proposal ownership” section", async ({}) => {}); + test("12E_3. Should accept valid data in “problem statements and proposal benefits” section", async ({}) => {}); + test("12E_4. Should accept valid data in “proposal details” section", async ({}) => {}); + test("12E_5. Should accept valid data in “costing” section", async ({}) => {}); + test("12E_6. Should accept valid data in “further information” section", async ({}) => {}); + + test("12F_1. Should reject invalid data in “contact information” section", async ({}) => {}); + test("12F_2. Should reject invalid data in “proposal ownership” section", async ({}) => {}); + test("12F_3. Should reject invalid data in “problem statements and proposal benefits” section", async ({}) => {}); + test("12E_4. Should accept invalid data in “proposal details” section", async ({}) => {}); + test("12F_5. Should reject invalid data in “costing” section", async ({}) => {}); + test("12F_6. Should reject invalid data in “further information” section", async ({}) => {}); +}); + test("12C. Should save and view draft proposal", async ({ browser }) => { const page = await createNewPageWithWallet(browser, { storageState: ".auth/budgetProposal02.json", From a9019195b3e0e8387219464e221d73d92f7ec895 Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 15:32:04 +0545 Subject: [PATCH 40/45] fix: update DREP_WALLETS_COUNT to 10 --- tests/govtool-frontend/playwright/tests/dRep.setup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/govtool-frontend/playwright/tests/dRep.setup.ts b/tests/govtool-frontend/playwright/tests/dRep.setup.ts index 7677ec7f5..9dde14e07 100644 --- a/tests/govtool-frontend/playwright/tests/dRep.setup.ts +++ b/tests/govtool-frontend/playwright/tests/dRep.setup.ts @@ -14,7 +14,7 @@ import { functionWaitedAssert } from "@helpers/waitedLoop"; import { StaticWallet } from "@types"; const REGISTER_DREP_WALLETS_COUNT = 6; -const DREP_WALLETS_COUNT = 9; +const DREP_WALLETS_COUNT = 10; let dRepDeposit: number; From 13007b6b5528cb5853340e0a9641230460db1df0 Mon Sep 17 00:00:00 2001 From: Niraj Date: Fri, 4 Apr 2025 15:48:36 +0545 Subject: [PATCH 41/45] fix: click verifyiIdentityBtn before viewProposal --- .../tests/11-proposal-budget/proposalBudget.dRep.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts index 8af3b53bb..b1bb7dad2 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.dRep.spec.ts @@ -80,6 +80,7 @@ test.describe("Budget proposal dRep behaviour", () => { const comment = faker.lorem.paragraph(2); const budgetDiscussionPage = new BudgetDiscussionPage(page); await budgetDiscussionPage.goto(); + await budgetDiscussionPage.verifyIdentityBtn.click(); const budgetDiscussionDetailsPage = await budgetDiscussionPage.viewFirstProposal(); await budgetDiscussionDetailsPage.addComment(comment); From 9fb6e7c27ba7b3dad04dd9ab8520bdc66c7d0912 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 06:28:25 +0000 Subject: [PATCH 42/45] chore: update @intersect.mbo/pdf-ui to 0.7.0-beta-13 --- govtool/frontend/package-lock.json | 8 ++++---- govtool/frontend/package.json | 2 +- govtool/frontend/yarn.lock | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/govtool/frontend/package-lock.json b/govtool/frontend/package-lock.json index 855e2ec75..5c25715d5 100644 --- a/govtool/frontend/package-lock.json +++ b/govtool/frontend/package-lock.json @@ -15,7 +15,7 @@ "@hookform/resolvers": "^3.3.1", "@intersect.mbo/govtool-outcomes-pillar-ui": "1.3.0", "@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8", - "@intersect.mbo/pdf-ui": "0.7.0-beta-12", + "@intersect.mbo/pdf-ui": "0.7.0-beta-13", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.4", "@rollup/plugin-babel": "^6.0.4", @@ -3423,9 +3423,9 @@ "license": "ISC" }, "node_modules/@intersect.mbo/pdf-ui": { - "version": "0.7.0-beta-12", - "resolved": "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-12.tgz", - "integrity": "sha512-f6G9AOi2k7Fbz+DUHtkfSzGsbfCi0e2inNw7Ft6hiTxVU7CGn9kY3bzMPcdBlV25xPnpBA3+ObLGX81H7cC5aA==", + "version": "0.7.0-beta-13", + "resolved": "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-13.tgz", + "integrity": "sha512-X7iUviqzNiuQyaYp5bZ3XwUztU5wM/B1LiMYBNy+0uEQpKL/Dzsld4LxY+P81BQJMz9skPm1Wi8S/ob7frOGXQ==", "dependencies": { "@emurgo/cardano-serialization-lib-asmjs": "^12.0.0-beta.2", "@fontsource/poppins": "^5.0.14", diff --git a/govtool/frontend/package.json b/govtool/frontend/package.json index 892dd60ed..c245f8cb7 100644 --- a/govtool/frontend/package.json +++ b/govtool/frontend/package.json @@ -29,7 +29,7 @@ "@hookform/resolvers": "^3.3.1", "@intersect.mbo/govtool-outcomes-pillar-ui": "1.3.0", "@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8", - "@intersect.mbo/pdf-ui": "0.7.0-beta-12", + "@intersect.mbo/pdf-ui": "0.7.0-beta-13", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.4", "@rollup/plugin-babel": "^6.0.4", diff --git a/govtool/frontend/yarn.lock b/govtool/frontend/yarn.lock index ccc260fd4..a2144af38 100644 --- a/govtool/frontend/yarn.lock +++ b/govtool/frontend/yarn.lock @@ -1512,10 +1512,10 @@ resolved "https://registry.npmjs.org/@intersect.mbo/intersectmbo.org-icons-set/-/intersectmbo.org-icons-set-1.1.0.tgz" integrity sha512-sjKEtnK9eLYH/8kCD0YRQCms3byFA/tnSsei9NHTZbBYX9sBpeX6ErfR0sKYjOSxQOxl4FumX9D0X+vHIqxo8g== -"@intersect.mbo/pdf-ui@0.7.0-beta-12": - version "0.7.0-beta-12" - resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-12.tgz" - integrity sha512-f6G9AOi2k7Fbz+DUHtkfSzGsbfCi0e2inNw7Ft6hiTxVU7CGn9kY3bzMPcdBlV25xPnpBA3+ObLGX81H7cC5aA== +"@intersect.mbo/pdf-ui@0.7.0-beta-13": + version "0.7.0-beta-13" + resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-13.tgz" + integrity sha512-X7iUviqzNiuQyaYp5bZ3XwUztU5wM/B1LiMYBNy+0uEQpKL/Dzsld4LxY+P81BQJMz9skPm1Wi8S/ob7frOGXQ== dependencies: "@emurgo/cardano-serialization-lib-asmjs" "^12.0.0-beta.2" "@fontsource/poppins" "^5.0.14" From 76ebe612935e147593c002d22f607d56c93ff6c5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 13:36:44 +0000 Subject: [PATCH 43/45] chore: update @intersect.mbo/pdf-ui to 0.7.0-beta-14 --- govtool/frontend/package-lock.json | 8 ++++---- govtool/frontend/package.json | 2 +- govtool/frontend/yarn.lock | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/govtool/frontend/package-lock.json b/govtool/frontend/package-lock.json index 5c25715d5..1212d8512 100644 --- a/govtool/frontend/package-lock.json +++ b/govtool/frontend/package-lock.json @@ -15,7 +15,7 @@ "@hookform/resolvers": "^3.3.1", "@intersect.mbo/govtool-outcomes-pillar-ui": "1.3.0", "@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8", - "@intersect.mbo/pdf-ui": "0.7.0-beta-13", + "@intersect.mbo/pdf-ui": "0.7.0-beta-14", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.4", "@rollup/plugin-babel": "^6.0.4", @@ -3423,9 +3423,9 @@ "license": "ISC" }, "node_modules/@intersect.mbo/pdf-ui": { - "version": "0.7.0-beta-13", - "resolved": "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-13.tgz", - "integrity": "sha512-X7iUviqzNiuQyaYp5bZ3XwUztU5wM/B1LiMYBNy+0uEQpKL/Dzsld4LxY+P81BQJMz9skPm1Wi8S/ob7frOGXQ==", + "version": "0.7.0-beta-14", + "resolved": "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-14.tgz", + "integrity": "sha512-ewj+AHa+bdhLf88WEWGLKCPvRu0LJ9qpUfHA5d5Qpzy+7vT7iAy+ejR6qJD0Nnm5x50QTMaAuv5jONP6gYy9wg==", "dependencies": { "@emurgo/cardano-serialization-lib-asmjs": "^12.0.0-beta.2", "@fontsource/poppins": "^5.0.14", diff --git a/govtool/frontend/package.json b/govtool/frontend/package.json index c245f8cb7..1943e740b 100644 --- a/govtool/frontend/package.json +++ b/govtool/frontend/package.json @@ -29,7 +29,7 @@ "@hookform/resolvers": "^3.3.1", "@intersect.mbo/govtool-outcomes-pillar-ui": "1.3.0", "@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8", - "@intersect.mbo/pdf-ui": "0.7.0-beta-13", + "@intersect.mbo/pdf-ui": "0.7.0-beta-14", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.4", "@rollup/plugin-babel": "^6.0.4", diff --git a/govtool/frontend/yarn.lock b/govtool/frontend/yarn.lock index a2144af38..6534e7f28 100644 --- a/govtool/frontend/yarn.lock +++ b/govtool/frontend/yarn.lock @@ -1512,10 +1512,10 @@ resolved "https://registry.npmjs.org/@intersect.mbo/intersectmbo.org-icons-set/-/intersectmbo.org-icons-set-1.1.0.tgz" integrity sha512-sjKEtnK9eLYH/8kCD0YRQCms3byFA/tnSsei9NHTZbBYX9sBpeX6ErfR0sKYjOSxQOxl4FumX9D0X+vHIqxo8g== -"@intersect.mbo/pdf-ui@0.7.0-beta-13": - version "0.7.0-beta-13" - resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-13.tgz" - integrity sha512-X7iUviqzNiuQyaYp5bZ3XwUztU5wM/B1LiMYBNy+0uEQpKL/Dzsld4LxY+P81BQJMz9skPm1Wi8S/ob7frOGXQ== +"@intersect.mbo/pdf-ui@0.7.0-beta-14": + version "0.7.0-beta-14" + resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-14.tgz" + integrity sha512-ewj+AHa+bdhLf88WEWGLKCPvRu0LJ9qpUfHA5d5Qpzy+7vT7iAy+ejR6qJD0Nnm5x50QTMaAuv5jONP6gYy9wg== dependencies: "@emurgo/cardano-serialization-lib-asmjs" "^12.0.0-beta.2" "@fontsource/poppins" "^5.0.14" From c2e825c3db431c2d41699039d2a341fc3503a324 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 16:06:27 +0000 Subject: [PATCH 44/45] chore: update @intersect.mbo/pdf-ui to 0.7.0-beta-15 --- govtool/frontend/package-lock.json | 8 ++++---- govtool/frontend/package.json | 2 +- govtool/frontend/yarn.lock | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/govtool/frontend/package-lock.json b/govtool/frontend/package-lock.json index 1212d8512..441973679 100644 --- a/govtool/frontend/package-lock.json +++ b/govtool/frontend/package-lock.json @@ -15,7 +15,7 @@ "@hookform/resolvers": "^3.3.1", "@intersect.mbo/govtool-outcomes-pillar-ui": "1.3.0", "@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8", - "@intersect.mbo/pdf-ui": "0.7.0-beta-14", + "@intersect.mbo/pdf-ui": "0.7.0-beta-15", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.4", "@rollup/plugin-babel": "^6.0.4", @@ -3423,9 +3423,9 @@ "license": "ISC" }, "node_modules/@intersect.mbo/pdf-ui": { - "version": "0.7.0-beta-14", - "resolved": "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-14.tgz", - "integrity": "sha512-ewj+AHa+bdhLf88WEWGLKCPvRu0LJ9qpUfHA5d5Qpzy+7vT7iAy+ejR6qJD0Nnm5x50QTMaAuv5jONP6gYy9wg==", + "version": "0.7.0-beta-15", + "resolved": "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-15.tgz", + "integrity": "sha512-/kUP72niN12mb1VKOhtuwxV/IJHy1/lwwCf7CdpnTW6odn0cMAhTVve8rEP0/9NDMp/+15TJ/xuqZSrmNdjr0g==", "dependencies": { "@emurgo/cardano-serialization-lib-asmjs": "^12.0.0-beta.2", "@fontsource/poppins": "^5.0.14", diff --git a/govtool/frontend/package.json b/govtool/frontend/package.json index 1943e740b..2aa2d5ecd 100644 --- a/govtool/frontend/package.json +++ b/govtool/frontend/package.json @@ -29,7 +29,7 @@ "@hookform/resolvers": "^3.3.1", "@intersect.mbo/govtool-outcomes-pillar-ui": "1.3.0", "@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8", - "@intersect.mbo/pdf-ui": "0.7.0-beta-14", + "@intersect.mbo/pdf-ui": "0.7.0-beta-15", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.4", "@rollup/plugin-babel": "^6.0.4", diff --git a/govtool/frontend/yarn.lock b/govtool/frontend/yarn.lock index 6534e7f28..3cc75ebcc 100644 --- a/govtool/frontend/yarn.lock +++ b/govtool/frontend/yarn.lock @@ -1512,10 +1512,10 @@ resolved "https://registry.npmjs.org/@intersect.mbo/intersectmbo.org-icons-set/-/intersectmbo.org-icons-set-1.1.0.tgz" integrity sha512-sjKEtnK9eLYH/8kCD0YRQCms3byFA/tnSsei9NHTZbBYX9sBpeX6ErfR0sKYjOSxQOxl4FumX9D0X+vHIqxo8g== -"@intersect.mbo/pdf-ui@0.7.0-beta-14": - version "0.7.0-beta-14" - resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-14.tgz" - integrity sha512-ewj+AHa+bdhLf88WEWGLKCPvRu0LJ9qpUfHA5d5Qpzy+7vT7iAy+ejR6qJD0Nnm5x50QTMaAuv5jONP6gYy9wg== +"@intersect.mbo/pdf-ui@0.7.0-beta-15": + version "0.7.0-beta-15" + resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-15.tgz" + integrity sha512-/kUP72niN12mb1VKOhtuwxV/IJHy1/lwwCf7CdpnTW6odn0cMAhTVve8rEP0/9NDMp/+15TJ/xuqZSrmNdjr0g== dependencies: "@emurgo/cardano-serialization-lib-asmjs" "^12.0.0-beta.2" "@fontsource/poppins" "^5.0.14" From 1c69063898c7fce0ebb76c1266f6548b4dde11d3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 8 Apr 2025 17:56:35 +0000 Subject: [PATCH 45/45] chore: update @intersect.mbo/pdf-ui to 0.7.0-beta-16 --- govtool/frontend/package-lock.json | 8 ++++---- govtool/frontend/package.json | 2 +- govtool/frontend/yarn.lock | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/govtool/frontend/package-lock.json b/govtool/frontend/package-lock.json index 441973679..8aa3981da 100644 --- a/govtool/frontend/package-lock.json +++ b/govtool/frontend/package-lock.json @@ -15,7 +15,7 @@ "@hookform/resolvers": "^3.3.1", "@intersect.mbo/govtool-outcomes-pillar-ui": "1.3.0", "@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8", - "@intersect.mbo/pdf-ui": "0.7.0-beta-15", + "@intersect.mbo/pdf-ui": "0.7.0-beta-16", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.4", "@rollup/plugin-babel": "^6.0.4", @@ -3423,9 +3423,9 @@ "license": "ISC" }, "node_modules/@intersect.mbo/pdf-ui": { - "version": "0.7.0-beta-15", - "resolved": "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-15.tgz", - "integrity": "sha512-/kUP72niN12mb1VKOhtuwxV/IJHy1/lwwCf7CdpnTW6odn0cMAhTVve8rEP0/9NDMp/+15TJ/xuqZSrmNdjr0g==", + "version": "0.7.0-beta-16", + "resolved": "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-16.tgz", + "integrity": "sha512-2I7BSg+5FDGhlvwLdZk0teVhtPMRQ1uDWKQiwobIF41cM0b+iT2CJMDL5MJk6tsM2/2JBbOEev9VrsHSanrCVA==", "dependencies": { "@emurgo/cardano-serialization-lib-asmjs": "^12.0.0-beta.2", "@fontsource/poppins": "^5.0.14", diff --git a/govtool/frontend/package.json b/govtool/frontend/package.json index 2aa2d5ecd..e64dd9cd9 100644 --- a/govtool/frontend/package.json +++ b/govtool/frontend/package.json @@ -29,7 +29,7 @@ "@hookform/resolvers": "^3.3.1", "@intersect.mbo/govtool-outcomes-pillar-ui": "1.3.0", "@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8", - "@intersect.mbo/pdf-ui": "0.7.0-beta-15", + "@intersect.mbo/pdf-ui": "0.7.0-beta-16", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.4", "@rollup/plugin-babel": "^6.0.4", diff --git a/govtool/frontend/yarn.lock b/govtool/frontend/yarn.lock index 3cc75ebcc..f22212f21 100644 --- a/govtool/frontend/yarn.lock +++ b/govtool/frontend/yarn.lock @@ -1512,10 +1512,10 @@ resolved "https://registry.npmjs.org/@intersect.mbo/intersectmbo.org-icons-set/-/intersectmbo.org-icons-set-1.1.0.tgz" integrity sha512-sjKEtnK9eLYH/8kCD0YRQCms3byFA/tnSsei9NHTZbBYX9sBpeX6ErfR0sKYjOSxQOxl4FumX9D0X+vHIqxo8g== -"@intersect.mbo/pdf-ui@0.7.0-beta-15": - version "0.7.0-beta-15" - resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-15.tgz" - integrity sha512-/kUP72niN12mb1VKOhtuwxV/IJHy1/lwwCf7CdpnTW6odn0cMAhTVve8rEP0/9NDMp/+15TJ/xuqZSrmNdjr0g== +"@intersect.mbo/pdf-ui@0.7.0-beta-16": + version "0.7.0-beta-16" + resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.7.0-beta-16.tgz" + integrity sha512-2I7BSg+5FDGhlvwLdZk0teVhtPMRQ1uDWKQiwobIF41cM0b+iT2CJMDL5MJk6tsM2/2JBbOEev9VrsHSanrCVA== dependencies: "@emurgo/cardano-serialization-lib-asmjs" "^12.0.0-beta.2" "@fontsource/poppins" "^5.0.14"