diff --git a/tests/govtool-frontend/playwright/README.md b/tests/govtool-frontend/playwright/README.md index 3dea35622..deb18fae4 100644 --- a/tests/govtool-frontend/playwright/README.md +++ b/tests/govtool-frontend/playwright/README.md @@ -174,7 +174,7 @@ npm run generate-wallets ### 🔁 Run All Tests -- **Pre-requisite**: Ensure the faucet address holds at least **412,000 ADA**. +- **Pre-requisite**: Ensure the faucet address holds at least **512,000 ADA**. #### 🖥️ UI Mode @@ -270,7 +270,7 @@ npm run test:headless:proposal-pillar #### 5. **Proposal Discussion** -- **Pre-requisite**: Ensure the faucet address holds at least **401,000 ADA**. +- **Pre-requisite**: Ensure the faucet address holds at least **501,000 ADA**. #### 🖥️ UI Mode diff --git a/tests/govtool-frontend/playwright/docs/proposal-discussion.png b/tests/govtool-frontend/playwright/docs/proposal-discussion.png index 70e72a7be..f0e8179cc 100644 Binary files a/tests/govtool-frontend/playwright/docs/proposal-discussion.png and b/tests/govtool-frontend/playwright/docs/proposal-discussion.png differ diff --git a/tests/govtool-frontend/playwright/lib/constants/auth.ts b/tests/govtool-frontend/playwright/lib/constants/auth.ts index b853b7c2b..5b18819e5 100644 --- a/tests/govtool-frontend/playwright/lib/constants/auth.ts +++ b/tests/govtool-frontend/playwright/lib/constants/auth.ts @@ -21,6 +21,8 @@ export const proposal07AuthFile = ".auth/proposal07.json"; export const proposal08AuthFile = ".auth/proposal08.json"; export const proposal09AuthFile = ".auth/proposal09.json"; +export const proposalSubmissionAuthFile = ".auth/proposalSubmission.json"; + export const budgetProposal01AuthFile = ".auth/budgetProposal01.json"; export const budgetProposal02AuthFile = ".auth/budgetProposal02.json"; export const budgetProposal03AuthFile = ".auth/budgetProposal03.json"; diff --git a/tests/govtool-frontend/playwright/lib/helpers/page.ts b/tests/govtool-frontend/playwright/lib/helpers/page.ts index d63af0711..eea8361a6 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/page.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/page.ts @@ -3,6 +3,7 @@ import loadDemosExtension from "@fixtures/loadExtension"; import { Browser, ConsoleMessage, Page } from "@playwright/test"; import { StaticWallet } from "@types"; import { Logger } from "./logger"; +import kuberService from "@services/kuberService"; interface NewPageConfig { storageState?: string; @@ -48,3 +49,13 @@ export function injectLogger(page: Page) { page.isLoggerInjected = true; } } + +export async function logWalletDetails(address: string) { + try { + const balance = await kuberService.getBalance(address); + console.log("wallet balance", balance); + } catch (error) { + console.log("failed to get balance", error); + } + console.log("wallet address", address); +} diff --git a/tests/govtool-frontend/playwright/lib/pages/proposalSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/proposalSubmissionPage.ts index 0c3d7cc09..1ceb85d65 100644 --- a/tests/govtool-frontend/playwright/lib/pages/proposalSubmissionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/proposalSubmissionPage.ts @@ -126,6 +126,10 @@ export default class ProposalSubmissionPage { constructor(private readonly page: Page) {} + get currentPage(): Page { + return this.page; + } + async goto() { await this.page.goto(`${environments.frontendUrl}/proposal_discussion`); diff --git a/tests/govtool-frontend/playwright/lib/walletManager.ts b/tests/govtool-frontend/playwright/lib/walletManager.ts index ad6401b5c..53192e886 100644 --- a/tests/govtool-frontend/playwright/lib/walletManager.ts +++ b/tests/govtool-frontend/playwright/lib/walletManager.ts @@ -42,6 +42,13 @@ class WalletManager { ); await this.writeWallets(updatedWallets, purpose); } + async getFirstWalletByPurpose(purpose: Purpose): Promise { + const wallets = await this.readWallets(purpose); + if (wallets.length === 0) { + throw new Error(`No wallets found for purpose: ${purpose}`); + } + return wallets[0]; + } async popWallet(purpose: Purpose): Promise { const popCb = async () => { diff --git a/tests/govtool-frontend/playwright/playwright.config.ts b/tests/govtool-frontend/playwright/playwright.config.ts index cc14955aa..4e8757478 100644 --- a/tests/govtool-frontend/playwright/playwright.config.ts +++ b/tests/govtool-frontend/playwright/playwright.config.ts @@ -72,6 +72,12 @@ export default defineConfig({ testMatch: "**/proposal-budget.auth.setup.ts", teardown: environments.ci && "cleanup faucet", }, + { + name: "proposal submission ga auth setup", + testMatch: "**/proposal-submission.ga.auth.setup.ts", + dependencies: environments.ci ? ["proposal setup"] : [], + teardown: environments.ci && "cleanup faucet", + }, { name: "dRep setup", testMatch: "**/dRep.setup.ts", @@ -112,7 +118,7 @@ export default defineConfig({ use: { ...devices["Desktop Chrome"] }, testMatch: "**/*.ga.spec.ts", dependencies: environments.ci - ? ["proposal setup"] + ? ["proposal submission ga auth setup"] : [], teardown: environments.ci && "cleanup artifacts", }, diff --git a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.pb.spec.ts b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.pb.spec.ts index 12c1ba5be..d8747f469 100644 --- a/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.pb.spec.ts +++ b/tests/govtool-frontend/playwright/tests/11-proposal-budget/proposalBudget.loggedin.pb.spec.ts @@ -67,7 +67,7 @@ test.describe("Budget proposal logged in state", () => { await budgetDiscussionDetailsPage.replyComment(randReply); const replyRendered = await budgetDiscussionDetailsPage.currentPage - .locator(`[data-testid^="reply-"][data-testid$="-content"]`) + .locator(`[data-testid^="subcomment-"][data-testid$="-content"]`) .textContent(); expect(replyRendered).toContain(randReply); }); diff --git a/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.ga.spec.ts b/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.ga.spec.ts index 8e181bf1f..3826af310 100644 --- a/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.ga.spec.ts +++ b/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.ga.spec.ts @@ -2,7 +2,7 @@ import environments from "@constants/environments"; import { createTempUserAuth } from "@datafactory/createAuth"; import { test } from "@fixtures/proposal"; import { setAllureEpic } from "@helpers/allure"; -import { createNewPageWithWallet } from "@helpers/page"; +import { createNewPageWithWallet, logWalletDetails } from "@helpers/page"; import { waitForTxConfirmation } from "@helpers/transaction"; import ProposalDiscussionPage from "@pages/proposalDiscussionPage"; import ProposalSubmissionPage from "@pages/proposalSubmissionPage"; @@ -13,9 +13,12 @@ import { } from "@helpers/cardano"; import { ProposalType } from "@types"; import walletManager from "lib/walletManager"; -import { valid } from "@mock/index"; +import { valid as mockValid, invalid as mockInvalid } from "@mock/index"; import { rewardAddressBech32 } from "@helpers/shellyWallet"; import { getWalletConfigForFaucet } from "@helpers/index"; +import { faker } from "@faker-js/faker"; +import { proposalSubmissionAuthFile } from "@constants/auth"; +import ProposalDiscussionDetailsPage from "@pages/proposalDiscussionDetailsPage"; test.beforeEach(async () => { await setAllureEpic("7. Proposal submission"); @@ -31,6 +34,7 @@ Object.values(ProposalType).forEach((proposalType, index) => { test.setTimeout(testInfo.timeout + environments.txTimeOut); const wallet = await walletManager.popWallet("proposalSubmission"); + await logWalletDetails(wallet.address); const tempUserAuth = await createTempUserAuth(page, wallet); @@ -42,7 +46,7 @@ Object.values(ProposalType).forEach((proposalType, index) => { const proposalDiscussionPage = new ProposalDiscussionPage(userPage); await proposalDiscussionPage.goto(); await proposalDiscussionPage.verifyIdentityBtn.click(); - await proposalDiscussionPage.setUsername(valid.username()); + await proposalDiscussionPage.setUsername(mockValid.username()); const proposalSubmissionPage = new ProposalSubmissionPage(userPage); await proposalSubmissionPage.proposalCreateBtn.click(); @@ -72,3 +76,136 @@ Object.values(ProposalType).forEach((proposalType, index) => { await waitForTxConfirmation(userPage); }); }); + +test.describe("Proposed as a governance action", async () => { + let proposalSubmissionPage: ProposalSubmissionPage; + let proposalDiscussionDetailPage: ProposalDiscussionDetailsPage; + let proposalId: number; + + test.beforeEach(async ({ browser }) => { + const proposalSubmissionWallet = + await walletManager.getFirstWalletByPurpose("proposalSubmissionCopy"); + await logWalletDetails(proposalSubmissionWallet.address); + + const page = await createNewPageWithWallet(browser, { + storageState: proposalSubmissionAuthFile, + wallet: proposalSubmissionWallet, + }); + + proposalSubmissionPage = new ProposalSubmissionPage(page); + await proposalSubmissionPage.goto(); + + proposalDiscussionDetailPage = new ProposalDiscussionDetailsPage(page); + + const rewardAddress = rewardAddressBech32( + environments.networkId, + getWalletConfigForFaucet().stake.pkh + ); + + proposalId = await proposalSubmissionPage.createProposal(rewardAddress); + await proposalDiscussionDetailPage.submitAsGABtn.click(); + await proposalSubmissionPage.currentPage + .getByTestId("agree-checkbox") + .click(); + await proposalSubmissionPage.continueBtn.click(); + }); + + test.afterEach(async () => { + // cleanup + await proposalDiscussionDetailPage.goto(proposalId); + + const isVerifyIdentityBtnVisible = + await proposalDiscussionDetailPage.verifyIdentityBtn.isVisible(); + + if (isVerifyIdentityBtnVisible) { + await proposalDiscussionDetailPage.verifyIdentityBtn.click(); + } + + await proposalDiscussionDetailPage.deleteProposal(); + }); + + test.describe("Metadata anchor validation", () => { + test("7J_1. Should accept valid metadata anchor on proposal submission", async () => { + test.slow(); // Brute-force testing with 50 random data + for (let i = 0; i < 50; i++) { + await proposalSubmissionPage.metadataUrlInput.fill(mockValid.url()); + await expect( + proposalSubmissionPage.currentPage.getByTestId("url-input-error-text") + ).toBeHidden(); + } + }); + + test("7J_2. Should reject invalid metadata anchor on proposal submission", async () => { + test.slow(); // Brute-force testing with 50 random data + for (let i = 0; i < 50; i++) { + await proposalSubmissionPage.metadataUrlInput.fill( + mockInvalid.url(false) + ); + await expect( + proposalSubmissionPage.currentPage.getByTestId("url-input-error-text") + ).toBeVisible(); + } + + const sentenceWithoutSpace = faker.lorem + .sentence(128) + .replace(/[\s.]/g, ""); + const metadataAnchorGreaterThan128Bytes = + faker.internet.url({ appendSlash: true }) + sentenceWithoutSpace; + + await proposalSubmissionPage.metadataUrlInput.fill( + metadataAnchorGreaterThan128Bytes + ); + + await expect( + proposalSubmissionPage.currentPage.getByTestId("url-input-error-text") + ).toBeVisible(); // BUG better to add different test id compare to invalid url testid + }); + }); + + test("7K. Should reject invalid proposal metadata", async () => { + await proposalSubmissionPage.metadataUrlInput.fill(faker.internet.url()); + await proposalSubmissionPage.submitBtn.click(); + + await expect( + proposalSubmissionPage.currentPage.getByTestId("url-error-modal-title") + ).toHaveText(/the url you entered cannot be found/i); + }); + + test("7P. Should navigate to the edit proposal page when 'goto data edit screen' is selected if data does not match the anchor URL", async () => { + const invalidMetadataAnchorUrl = "https://www.google.com"; + + await proposalSubmissionPage.metadataUrlInput.fill( + invalidMetadataAnchorUrl + ); + await proposalSubmissionPage.submitBtn.click(); + + await expect( + proposalSubmissionPage.currentPage.getByTestId("data-not-match-modal") + ).toBeVisible(); + await expect( + proposalSubmissionPage.currentPage.getByTestId( + "data-not-match-modal-go-to-data-button" + ) + ).toBeVisible(); + + await proposalSubmissionPage.currentPage + .getByTestId("data-not-match-modal-go-to-data-button") + .click(); + + await expect( + proposalSubmissionPage.currentPage.getByTestId("governance-action-type") + ).toBeVisible(); + await expect( + proposalSubmissionPage.currentPage.getByTestId("title-input") + ).toBeVisible(); + await expect( + proposalSubmissionPage.currentPage.getByTestId("abstract-input") + ).toBeVisible(); + await expect( + proposalSubmissionPage.currentPage.getByTestId("motivation-input") + ).toBeVisible(); + await expect( + proposalSubmissionPage.currentPage.getByTestId("rationale-input") + ).toBeVisible(); + }); +}); diff --git a/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.loggedin.pd.spec.ts b/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.loggedin.pd.spec.ts index f4b0bdf36..d7126799a 100644 --- a/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.loggedin.pd.spec.ts +++ b/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.loggedin.pd.spec.ts @@ -306,66 +306,25 @@ test.describe("Proposal created logged state", () => { }); }); - test.describe("Proposed as a governance action", () => { - let proposalSubmissionPage: ProposalSubmissionPage; - test.beforeEach(async ({ page, proposalId }) => { - const proposalDiscussionDetailsPage = new ProposalDiscussionDetailsPage( - page - ); - await proposalDiscussionDetailsPage.goto(proposalId); - - await proposalDiscussionDetailsPage.verifyIdentityBtn.click(); - await proposalDiscussionDetailsPage.submitAsGABtn.click(); - - proposalSubmissionPage = new ProposalSubmissionPage(page); - await page.getByTestId("agree-checkbox").click(); - await proposalSubmissionPage.continueBtn.click(); - }); - - test.describe("Metadata anchor validation", () => { - test("7J_1. Should accept valid metadata anchor on proposal submission", async ({ - page, - }) => { - test.slow(); // Brute-force testing with 100 random data - for (let i = 0; i < 50; i++) { - await proposalSubmissionPage.metadataUrlInput.fill(mockValid.url()); - await expect(page.getByTestId("url-input-error-text")).toBeHidden(); - } - }); - - test("7J_2. Should reject invalid metadata anchor on proposal submission", async ({ - page, - }) => { - test.slow(); // Brute-force testing with 100 random data - for (let i = 0; i < 50; i++) { - await proposalSubmissionPage.metadataUrlInput.fill( - invalid.url(false) - ); - await expect(page.getByTestId("url-input-error-text")).toBeVisible(); - } - - const sentenceWithoutSpace = faker.lorem - .sentence(128) - .replace(/[\s.]/g, ""); - const metadataAnchorGreaterThan128Bytes = - faker.internet.url({ appendSlash: true }) + sentenceWithoutSpace; - - await proposalSubmissionPage.metadataUrlInput.fill( - metadataAnchorGreaterThan128Bytes - ); - - await expect(page.getByTestId("url-input-error-text")).toBeVisible(); // BUG better to add different test id compare to invalid url testid - }); - }); + test("7O. Should display insufficient balance modal when submitting proposal with insufficient funds", async ({ + page, + proposalId, + }) => { + const proposalDiscussionDetailsPage = new ProposalDiscussionDetailsPage( + page + ); + await proposalDiscussionDetailsPage.goto(proposalId); - test("7K. Should reject invalid proposal metadata", async ({ page }) => { - await proposalSubmissionPage.metadataUrlInput.fill(faker.internet.url()); - await proposalSubmissionPage.submitBtn.click(); + await proposalDiscussionDetailsPage.verifyIdentityBtn.click(); + await proposalDiscussionDetailsPage.submitAsGABtn.click(); - await expect(page.getByTestId("url-error-modal-title")).toHaveText( - /the url you entered cannot be found/i - ); - }); + const proposalSubmissionPage = new ProposalSubmissionPage(page); + await expect( + proposalSubmissionPage.currentPage.getByText( + "Insufficient wallet balance", + { exact: true } + ) + ).toBeVisible(); // BUG missing test id }); }); diff --git a/tests/govtool-frontend/playwright/tests/8-proposal-discussion/proposalDiscussion.loggedin.pd.spec.ts b/tests/govtool-frontend/playwright/tests/8-proposal-discussion/proposalDiscussion.loggedin.pd.spec.ts index 62b91df76..98f4c4e36 100644 --- a/tests/govtool-frontend/playwright/tests/8-proposal-discussion/proposalDiscussion.loggedin.pd.spec.ts +++ b/tests/govtool-frontend/playwright/tests/8-proposal-discussion/proposalDiscussion.loggedin.pd.spec.ts @@ -180,36 +180,4 @@ test.describe("Proposal created with poll enabled (proposal auth)", () => { await expect(userProposalDetailsPage.pollYesBtn).not.toBeVisible(); await expect(userProposalDetailsPage.pollNoBtn).not.toBeVisible(); }); - - test("8U. Should navigate to the edit proposal page when 'goto data edit screen' is selected if data does not match the anchor URL", async () => { - const invalidMetadataAnchorUrl = "https://www.google.com"; - await ownerProposalDiscussionDetailsPage.submitAsGABtn.click(); - - const proposalSubmissionPage = new ProposalSubmissionPage(proposalPage); - await proposalPage.getByTestId("agree-checkbox").click(); - await proposalSubmissionPage.continueBtn.click(); - await proposalSubmissionPage.metadataUrlInput.fill( - invalidMetadataAnchorUrl - ); - await proposalSubmissionPage.submitBtn.click(); - - await expect( - proposalPage.getByTestId("data-not-match-modal") - ).toBeVisible(); - await expect( - proposalPage.getByTestId("data-not-match-modal-go-to-data-button") - ).toBeVisible(); - - await proposalPage - .getByTestId("data-not-match-modal-go-to-data-button") - .click(); - - await expect( - proposalPage.getByTestId("governance-action-type") - ).toBeVisible(); - await expect(proposalPage.getByTestId("title-input")).toBeVisible(); - await expect(proposalPage.getByTestId("abstract-input")).toBeVisible(); - await expect(proposalPage.getByTestId("motivation-input")).toBeVisible(); - await expect(proposalPage.getByTestId("rationale-input")).toBeVisible(); - }); }); diff --git a/tests/govtool-frontend/playwright/tests/proposal-submission.ga.auth.setup.ts b/tests/govtool-frontend/playwright/tests/proposal-submission.ga.auth.setup.ts new file mode 100644 index 000000000..171a2c20f --- /dev/null +++ b/tests/govtool-frontend/playwright/tests/proposal-submission.ga.auth.setup.ts @@ -0,0 +1,24 @@ +import { setAllureEpic, setAllureStory } from "@helpers/allure"; +import { test as setup } from "@fixtures/walletExtension"; +import { createAuthWithUserName } from "@helpers/auth"; +import walletManager from "lib/walletManager"; +import { proposalSubmissionAuthFile } from "@constants/auth"; + +setup.beforeEach(async () => { + await setAllureEpic("Setup"); + await setAllureStory("Authentication"); +}); + +setup( + `Create auth for proposal submission balance dependent test`, + async ({ page, context }) => { + const proposalSubmissionWallet = + await walletManager.getFirstWalletByPurpose("proposalSubmissionCopy"); + await createAuthWithUserName({ + page, + context, + wallet: proposalSubmissionWallet, + auth: proposalSubmissionAuthFile, + }); + } +); diff --git a/tests/govtool-frontend/playwright/tests/proposal.setup.ts b/tests/govtool-frontend/playwright/tests/proposal.setup.ts index d9511b483..4a44b621c 100644 --- a/tests/govtool-frontend/playwright/tests/proposal.setup.ts +++ b/tests/govtool-frontend/playwright/tests/proposal.setup.ts @@ -9,7 +9,7 @@ import walletManager from "lib/walletManager"; import { functionWaitedAssert } from "@helpers/waitedLoop"; import { getWalletConfigForFaucet } from "@helpers/index"; -const PROPOSAL_WALLETS_COUNT = 4; +const PROPOSAL_WALLETS_COUNT = 5; let govActionDeposit: number;