diff --git a/.github/workflows/update-intersect-package.yml b/.github/workflows/update-intersect-package.yml new file mode 100644 index 000000000..e2fb1d680 --- /dev/null +++ b/.github/workflows/update-intersect-package.yml @@ -0,0 +1,67 @@ +name: "Update @intersect.mbo Package" + +on: + workflow_dispatch: + inputs: + package_name: + description: "Select the @intersect.mbo package to update" + required: true + type: choice + options: + - "@intersect.mbo/govtool-outcomes-pillar-ui" + - "@intersect.mbo/intersectmbo.org-icons-set" + - "@intersect.mbo/pdf-ui" + new_version: + description: "Enter the new version (e.g., 1.1.0)" + required: true + +jobs: + update_package: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + registry-url: "https://registry.npmjs.org/" + node-version-file: "./govtool/frontend/.nvmrc" + scope: "@intersect.mbo" + + - name: Update package version in frontend + run: | + PACKAGE_NAME="${{ github.event.inputs.package_name }}" + NEW_VERSION="${{ github.event.inputs.new_version }}" + PACKAGE_JSON_PATH="govtool/frontend/package.json" + + echo "Updating $PACKAGE_NAME to version $NEW_VERSION in $PACKAGE_JSON_PATH..." + + jq --arg pkg "$PACKAGE_NAME" --arg ver "$NEW_VERSION" \ + '.dependencies[$pkg] = $ver' "$PACKAGE_JSON_PATH" > package.tmp.json \ + && mv package.tmp.json "$PACKAGE_JSON_PATH" + + - name: Install dependencies in frontend + run: | + cd govtool/frontend + npm install + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.GITHUB_TOKEN }} + branch: "chore/${{ github.event.inputs.package_name }}-${{ github.event.inputs.new_version }}" + title: "Update ${{ github.event.inputs.package_name }} to ${{ github.event.inputs.new_version }}" + body: | + This PR updates `${{ github.event.inputs.package_name }}` to version `${{ github.event.inputs.new_version }}`. + + + Workflow executed by `@${{ github.actor }}`. + labels: "dependencies" + sign-commits: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b666031f..f802f639f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ changes. - Add metadata url and hash to drep details [Issue 2911](https://github.com/IntersectMBO/govtool/issues/2911) - Add CC votes percentages, not voted and Ratification threshold - Add support for submitting all 7 governance action types [Issue 2258](https://github.com/IntersectMBO/govtool/issues/2258) +- Add workflow to automatically update any of the @intersect.mbo package [Issue 2968](https://github.com/IntersectMBO/govtool/issues/2968) ### Fixed diff --git a/govtool/frontend/package-lock.json b/govtool/frontend/package-lock.json index 14051e68f..092c843ad 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.0.0", "@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8", - "@intersect.mbo/pdf-ui": "^0.6.0", + "@intersect.mbo/pdf-ui": "0.6.1", "@mui/icons-material": "^5.14.3", "@mui/material": "^5.14.4", "@rollup/plugin-babel": "^6.0.4", @@ -3397,9 +3397,9 @@ "license": "ISC" }, "node_modules/@intersect.mbo/pdf-ui": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.6.0.tgz", - "integrity": "sha512-4lNDqUp03UQEy5Fwu2kTewM8Jxfc5uNxk7h40wOWx4zNIIOos187kF1NsE8yW2/VXRSkklsxSbc1ckifEJJakw==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.6.1.tgz", + "integrity": "sha512-XtA5kGkOiZ8ydEOlgJbf98t6nL1yf97MAUgpiRalhAOg2IRQrrJMhr+egrovDthB/xwNJszwHwMuRKBgAsbdyA==", "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 f7b5d9175..e4054d741 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.0.0", "@intersect.mbo/intersectmbo.org-icons-set": "^1.0.8", - "@intersect.mbo/pdf-ui": "^0.6.0", + "@intersect.mbo/pdf-ui": "0.6.1", "@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 9dc9df1c6..50ade3185 100644 --- a/govtool/frontend/yarn.lock +++ b/govtool/frontend/yarn.lock @@ -1367,15 +1367,15 @@ resolved "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-asmjs/-/cardano-serialization-lib-asmjs-12.1.1.tgz" integrity sha512-K3f28QUfLDJ7seO6MtKfMYtRm5ccf36TQ5yxyTmZqX1TA85MkriEdxqpgV9KLiLEA95emwnlvU2/WmlHMRPg1A== -"@esbuild/darwin-arm64@0.21.5": +"@esbuild/linux-x64@0.21.5": version "0.21.5" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz" - integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== -"@esbuild/darwin-arm64@0.24.2": +"@esbuild/linux-x64@0.24.2": version "0.24.2" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz" - integrity sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA== + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz" + integrity sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.1" @@ -1505,10 +1505,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.6.0": - version "0.6.0" - resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.6.0.tgz" - integrity sha512-4lNDqUp03UQEy5Fwu2kTewM8Jxfc5uNxk7h40wOWx4zNIIOos187kF1NsE8yW2/VXRSkklsxSbc1ckifEJJakw== +"@intersect.mbo/pdf-ui@0.6.1": + version "0.6.1" + resolved "https://registry.npmjs.org/@intersect.mbo/pdf-ui/-/pdf-ui-0.6.1.tgz" + integrity sha512-XtA5kGkOiZ8ydEOlgJbf98t6nL1yf97MAUgpiRalhAOg2IRQrrJMhr+egrovDthB/xwNJszwHwMuRKBgAsbdyA== dependencies: "@emurgo/cardano-serialization-lib-asmjs" "^12.0.0-beta.2" "@fontsource/poppins" "^5.0.14" @@ -2166,10 +2166,15 @@ resolved "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz" integrity sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg== -"@parcel/watcher-darwin-arm64@2.5.0": +"@parcel/watcher-linux-x64-glibc@2.5.0": + version "2.5.0" + resolved "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz" + integrity sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw== + +"@parcel/watcher-linux-x64-musl@2.5.0": version "2.5.0" - resolved "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz" - integrity sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw== + resolved "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz" + integrity sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA== "@parcel/watcher@^2.4.1": version "2.5.0" @@ -2282,10 +2287,15 @@ estree-walker "^2.0.2" picomatch "^4.0.2" -"@rollup/rollup-darwin-arm64@4.27.4": +"@rollup/rollup-linux-x64-gnu@4.27.4": + version "4.27.4" + resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.27.4.tgz" + integrity sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q== + +"@rollup/rollup-linux-x64-musl@4.27.4": version "4.27.4" - resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.27.4.tgz" - integrity sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q== + resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.27.4.tgz" + integrity sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw== "@rtsao/scc@^1.1.0": version "1.1.0" @@ -2864,10 +2874,15 @@ "@svgr/plugin-svgo" "^5.5.0" loader-utils "^2.0.0" -"@swc/core-darwin-arm64@1.9.3": +"@swc/core-linux-x64-gnu@1.9.3": version "1.9.3" - resolved "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.9.3.tgz" - integrity sha512-hGfl/KTic/QY4tB9DkTbNuxy5cV4IeejpPD4zo+Lzt4iLlDWIeANL4Fkg67FiVceNJboqg48CUX+APhDHO5G1w== + resolved "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.9.3.tgz" + integrity sha512-ivXXBRDXDc9k4cdv10R21ccBmGebVOwKXT/UdH1PhxUn9m/h8erAWjz5pcELwjiMf27WokqPgaWVfaclDbgE+w== + +"@swc/core-linux-x64-musl@1.9.3": + version "1.9.3" + resolved "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.9.3.tgz" + integrity sha512-ILsGMgfnOz1HwdDz+ZgEuomIwkP1PHT6maigZxaCIuC6OPEhKE8uYna22uU63XvYcLQvZYDzpR3ms47WQPuNEg== "@swc/core@*", "@swc/core@^1.5.22", "@swc/core@^1.7.26": version "1.9.3" @@ -7173,16 +7188,6 @@ fs@^0.0.1-security: resolved "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz" integrity sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w== -fsevents@^2.3.2, fsevents@~2.3.2, fsevents@~2.3.3: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -fsevents@2.3.2: - version "2.3.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" diff --git a/tests/govtool-frontend/playwright/lib/_mock/index.ts b/tests/govtool-frontend/playwright/lib/_mock/index.ts index 3aff590cf..79214f128 100644 --- a/tests/govtool-frontend/playwright/lib/_mock/index.ts +++ b/tests/govtool-frontend/playwright/lib/_mock/index.ts @@ -80,6 +80,15 @@ export const invalid = { return " "; }, + constitutionUrl: () => { + const choice = faker.number.int({ min: 1, max: 2 }); + if (choice === 1) { + return invalid.url(); + } + // empty invalid + return " "; + }, + paragraph: (maxCharacter: number) => { const choice = faker.number.int({ min: 1, max: 2 }); if (choice === 1) { diff --git a/tests/govtool-frontend/playwright/lib/constants/index.ts b/tests/govtool-frontend/playwright/lib/constants/index.ts index ca9c527c4..fc15d0258 100644 --- a/tests/govtool-frontend/playwright/lib/constants/index.ts +++ b/tests/govtool-frontend/playwright/lib/constants/index.ts @@ -10,3 +10,12 @@ export const SECURITY_RELEVANT_PARAMS_MAP: Record = { govActionDeposit: "gov_action_deposit", minFeeRefScriptCostPerByte: "min_fee_ref_script_cost_per_byte", }; + +export const PROPOSAL_TYPE_FILTERS = [ + "Info Action", + "Treasury requests", + "Updates to the Constitution", +]; +export const BOOTSTRAP_PROPOSAL_TYPE_FILTERS = ["Info Action"]; + +export const PROPOSAL_STATUS_FILTER = ["Submitted for vote", "Active proposal"]; diff --git a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts index a88255a37..bd92184fb 100644 --- a/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts +++ b/tests/govtool-frontend/playwright/lib/constants/staticWallets.ts @@ -1,5 +1,6 @@ const staticWallets: StaticWallet[] = require("../_mock/wallets.json"); import { StaticWallet } from "@types"; +import { proposalFaucetWallet } from "./proposalFaucetWallet"; export const faucetWallet = staticWallets[0]; export const dRep01Wallet = staticWallets[1]; @@ -23,6 +24,7 @@ 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 adaHolderWallets = [ adaHolder01Wallet, @@ -37,4 +39,22 @@ export const userWallets = [user01Wallet]; export const dRepWallets = [dRep01Wallet, dRep02Wallet]; -export const proposalWallets = [proposal01Wallet]; +export const proposalWallets = [ + proposal01Wallet, + proposal02Wallet, + proposal03Wallet, + proposal04Wallet, + proposal05Wallet, + proposal06Wallet, + proposal07Wallet, + proposal08Wallet, +]; + +export const allStaticWallets = [ + ...dRepWallets, + ...adaHolderWallets, + user01Wallet, + ...proposalWallets, + faucetWallet, + proposalFaucetWallet, +]; diff --git a/tests/govtool-frontend/playwright/lib/helpers/cardano.ts b/tests/govtool-frontend/playwright/lib/helpers/cardano.ts index 37a06b2d1..b9c19ffff 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/cardano.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/cardano.ts @@ -27,9 +27,9 @@ export async function isBootStrapingPhase() { return protocolParameterMajorVersion === 9; } -export async function skipIfTreasuryAndBootstrapping(type: ProposalType) { +export async function skipIfNotInfoAndBootstrapping(type: ProposalType) { const isBootStraping = await isBootStrapingPhase(); - if (type === ProposalType.treasury && isBootStraping) { + if (type !== ProposalType.info && isBootStraping) { await allure.description( "This Features will be available only after hardfork." ); diff --git a/tests/govtool-frontend/playwright/lib/helpers/metadata.ts b/tests/govtool-frontend/playwright/lib/helpers/metadata.ts index f89b4f9aa..69e8802f2 100644 --- a/tests/govtool-frontend/playwright/lib/helpers/metadata.ts +++ b/tests/govtool-frontend/playwright/lib/helpers/metadata.ts @@ -21,6 +21,12 @@ export async function downloadMetadata(download: Download): Promise<{ return { name: download.suggestedFilename(), data: jsonData }; } +export function calculateHash(data: string) { + const buffer = Buffer.from(data, "utf8"); + const hexDigest = blake.blake2bHex(buffer, null, 32); + return hexDigest; +} + async function calculateMetadataHash() { try { const paymentAddress = (await ShelleyWallet.generate()).addressBech32( @@ -39,8 +45,7 @@ async function calculateMetadataHash() { 2 ); - const buffer = Buffer.from(data, "utf8"); - const hexDigest = blake.blake2bHex(buffer, null, 32); + const hexDigest = calculateHash(data); const jsonData = JSON.parse(data); return { hexDigest, jsonData }; diff --git a/tests/govtool-frontend/playwright/lib/pages/proposalDiscussionPage.ts b/tests/govtool-frontend/playwright/lib/pages/proposalDiscussionPage.ts index a8dbaaa12..4234f1b67 100644 --- a/tests/govtool-frontend/playwright/lib/pages/proposalDiscussionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/proposalDiscussionPage.ts @@ -1,11 +1,8 @@ -import { faker } from "@faker-js/faker"; -import { generateWalletAddress } from "@helpers/cardano"; -import { extractProposalIdFromUrl } from "@helpers/string"; import { expect, Locator, Page } from "@playwright/test"; import { ProposalCreateRequest, ProposedGovAction } from "@types"; import environments from "lib/constants/environments"; import ProposalDiscussionDetailsPage from "./proposalDiscussionDetailsPage"; -import { isMobile } from "@helpers/mobile"; +import { PROPOSAL_TYPE_FILTERS } from "@constants/index"; export default class ProposalDiscussionPage { // Buttons @@ -19,8 +16,10 @@ export default class ProposalDiscussionPage { readonly showAllBtn = this.page.getByTestId("show-all-button").first(); //this.page.getByTestId("show-all-button"); readonly verifyIdentityBtn = this.page.getByTestId("verify-identity-button"); readonly addLinkBtn = this.page.getByTestId("add-link-button"); - readonly infoRadio = this.page.getByTestId("Info-radio-wrapper"); - readonly treasuryRadio = this.page.getByTestId("Treasury-radio-wrapper"); + readonly infoRadio = this.page.getByTestId("info action-radio-wrapper"); + readonly treasuryRadio = this.page.getByTestId( + "treasury requests-radio-wrapper" + ); readonly activeProposalWrapper = this.page.getByTestId( "active-proposal-radio-wrapper" ); @@ -112,10 +111,10 @@ export default class ProposalDiscussionPage { async clickRadioButtonsByNames(names: string[]) { for (const name of names) { - const replaceSpaceWithUnderScore = name.toLowerCase().replace(/ /g, "-"); - await this.page - .getByTestId(`${replaceSpaceWithUnderScore}-radio`) - .click(); + const testId = PROPOSAL_TYPE_FILTERS.includes(name) + ? name.toLowerCase() + : name.toLowerCase().replace(/ /g, "-"); + await this.page.getByTestId(`${testId}-radio`).click(); } } diff --git a/tests/govtool-frontend/playwright/lib/pages/proposalSubmissionPage.ts b/tests/govtool-frontend/playwright/lib/pages/proposalSubmissionPage.ts index e60a76a9b..78ead7bcb 100644 --- a/tests/govtool-frontend/playwright/lib/pages/proposalSubmissionPage.ts +++ b/tests/govtool-frontend/playwright/lib/pages/proposalSubmissionPage.ts @@ -4,7 +4,7 @@ import { faker } from "@faker-js/faker"; import { isBootStrapingPhase } from "@helpers/cardano"; import { ShelleyWallet } from "@helpers/crypto"; import { expectWithInfo } from "@helpers/exceptionHandler"; -import { downloadMetadata } from "@helpers/metadata"; +import { calculateHash, downloadMetadata } from "@helpers/metadata"; import { extractProposalIdFromUrl } from "@helpers/string"; import { invalid } from "@mock/index"; import { Download, Locator, Page, expect } from "@playwright/test"; @@ -23,6 +23,8 @@ const formErrors = { rationale: "rationale-helper-error", receivingAddress: "receiving-address-0-text-error", amount: "amount-0-text-error", + constitutionalUrl: "prop=constitution-url-text-error", // BUG wrong test id + guardrailsScriptUrl: "prop-guardrails-script-url-input-error", link: "link-0-url-input-error", }; @@ -47,8 +49,11 @@ export default class ProposalSubmissionPage { readonly addWithdrawalAddressBtn = this.page.getByTestId( "add-withdrawal-link-button" ); - readonly infoBtn = this.page.getByTestId("info-button"); - readonly treasuryBtn = this.page.getByTestId("treasury-button"); + readonly infoBtn = this.page.getByTestId("info action-button"); + readonly treasuryBtn = this.page.getByTestId("treasury requests-button"); + readonly updateTheConstitutionBtn = this.page.getByTestId( + "updates to the constitution-button" + ); readonly editSubmissionButton = this.page.getByTestId( "edit-submission-button" ); @@ -61,6 +66,9 @@ export default class ProposalSubmissionPage { readonly createNewProposalBtn = this.page.getByTestId( "create-new-proposal-button" ); + readonly guardrailsScriptCheckbox = this.page.getByLabel( + "Do you want to provide new" + ); // BUG missing test id // input fields readonly titleInput = this.page.getByTestId("title-input"); @@ -72,6 +80,15 @@ export default class ProposalSubmissionPage { "receiving-address-0-text-input" ); readonly amountInput = this.page.getByTestId("amount-0-text-input"); + readonly constitutionUrlInput = this.page.getByTestId( + "prop_constitution_url" + ); + readonly guardrailsScriptUrlInput = this.page.getByTestId( + "prop-guardrails-script-url-input" + ); + readonly guardrailsScriptHashInput = this.page.getByTestId( + "prop-guardrails-script-hash-input" + ); readonly closeDraftSuccessModalBtn = this.page.getByTestId("close-button"); readonly linkTextInput = this.page.getByTestId("link-0-text-input"); readonly linkUrlInput = this.page.getByTestId("link-0-url-input"); @@ -88,6 +105,15 @@ export default class ProposalSubmissionPage { "receiving-address-0-content" ); readonly amountContent = this.page.getByTestId("amount-0-content"); + readonly constitutionUrlContent = this.page.getByTestId( + "new-constitution-url-content" + ); + readonly guardrailsScriptUrlContent = this.page.getByTestId( + "guardrails-script-url-content" + ); + readonly guardrailsScriptHashContent = this.page.getByTestId( + "guardrails-script-hash-content" + ); readonly linkTextContent = this.page.getByTestId("link-0-text-content"); readonly linkUrlContent = this.page.getByTestId("link-0-url-content"); @@ -128,6 +154,10 @@ export default class ProposalSubmissionPage { await this.fillTreasuryFields(governanceProposal); } + if (governanceProposal.gov_action_type_id === 2) { + await this.fillUpdateTheConstitutionFields(governanceProposal); + } + if (governanceProposal.proposal_links != null) { await this.fillProposalLinks(governanceProposal.proposal_links); } @@ -138,9 +168,13 @@ export default class ProposalSubmissionPage { if (governanceProposal.gov_action_type_id === 0) { await this.infoBtn.click(); - } else { + } else if (governanceProposal.gov_action_type_id === 1) { await this.treasuryBtn.click(); + } else { + await this.updateTheConstitutionBtn.click(); + await this.guardrailsScriptCheckbox.click(); } + await this.fillupFormWithTypeSelected(governanceProposal); } @@ -158,6 +192,21 @@ export default class ProposalSubmissionPage { await this.amountInput.fill(governanceProposal.prop_amount); } + async fillUpdateTheConstitutionFields( + governanceProposal: ProposalCreateRequest + ) { + await this.constitutionUrlInput.fill( + governanceProposal.prop_constitution_url + ); + + await this.guardrailsScriptUrlInput.fill( + governanceProposal.prop_guardrails_script_url + ); + await this.guardrailsScriptHashInput.fill( + governanceProposal.prop_guardrails_script_hash + ); + } + async fillProposalLinks(proposal_links: Array) { for (let i = 0; i < proposal_links.length; i++) { if (i > 0) { @@ -232,6 +281,16 @@ export default class ProposalSubmissionPage { } } + if (governanceProposal.gov_action_type_id === 2) { + await expect( + this.page.getByTestId(formErrors.constitutionalUrl) + ).toBeHidden(); + + await expect( + this.page.getByTestId(formErrors.guardrailsScriptUrl) + ).toBeHidden(); + } + await expect(this.page.getByTestId(formErrors.link)).toBeHidden(); await expect(this.continueBtn).toBeEnabled(); @@ -286,6 +345,16 @@ export default class ProposalSubmissionPage { await expect(this.page.getByTestId(formErrors.amount)).toBeVisible(); } + if (governanceProposal.gov_action_type_id === 2) { + await expect( + this.page.getByTestId(formErrors.constitutionalUrl) + ).toBeVisible(); + + await expect( + this.page.getByTestId(formErrors.guardrailsScriptUrl) + ).toBeVisible(); + } + await expect(this.continueBtn).toBeDisabled(); } @@ -306,7 +375,7 @@ export default class ProposalSubmissionPage { prop_link_text: faker.internet.domainWord(), }, ], - gov_action_type_id: proposalType === ProposalType.info ? 0 : 1, + gov_action_type_id: Object.values(ProposalType).indexOf(proposalType), is_draft: !!is_draft, }; @@ -316,6 +385,13 @@ export default class ProposalSubmissionPage { .int({ min: 100, max: 1000 }) .toString()); } + if (proposalType === ProposalType.updatesToTheConstitution) { + proposal.prop_constitution_url = faker.internet.url(); + proposal.prop_guardrails_script_url = faker.internet.url(); + proposal.prop_guardrails_script_hash = calculateHash( + faker.lorem.paragraph() + ); + } return proposal; } @@ -332,7 +408,7 @@ export default class ProposalSubmissionPage { prop_link_text: invalid.name(), }, ], - gov_action_type_id: proposalType === ProposalType.info ? 0 : 1, + gov_action_type_id: Object.values(ProposalType).indexOf(proposalType), is_draft: false, }; @@ -340,12 +416,20 @@ export default class ProposalSubmissionPage { (proposal.prop_receiving_address = faker.location.streetAddress()), (proposal.prop_amount = invalid.amount()); } + + if (proposalType === ProposalType.updatesToTheConstitution) { + proposal.prop_constitution_url = invalid.constitutionUrl(); + proposal.prop_guardrails_script_url = invalid.url(); + proposal.prop_guardrails_script_hash = faker.string.alphanumeric(64); + } return proposal; } async createProposal( wallet: StaticWallet, - proposalType: ProposalType = ProposalType.treasury + proposalType: ProposalType = Object.values(ProposalType)[ + Math.floor(Math.random() * Object.values(ProposalType).length) + ] ): Promise { await this.addLinkBtn.click(); const receivingAddr = ShelleyWallet.fromJson(wallet).rewardAddressBech32( diff --git a/tests/govtool-frontend/playwright/lib/services/kuberService.ts b/tests/govtool-frontend/playwright/lib/services/kuberService.ts index 8de48ce41..1a26b3561 100644 --- a/tests/govtool-frontend/playwright/lib/services/kuberService.ts +++ b/tests/govtool-frontend/playwright/lib/services/kuberService.ts @@ -12,6 +12,7 @@ import fetch, { BodyInit, RequestInit } from "node-fetch"; import { cborxEncoder } from "@helpers/encodeDecode"; import { Logger } from "@helpers/logger"; import { blockfrostSubmitTransaction } from "@services/blockfrostService"; +import { proposalFaucetWallet } from "@constants/proposalFaucetWallet"; type CertificateType = "registerstake" | "registerdrep" | "deregisterdrep"; @@ -161,6 +162,25 @@ const kuberService = { certificates, }); }, + mergeUtXos: (wallets: StaticWallet[]) => { + const kuber = new Kuber( + proposalFaucetWallet.address, + proposalFaucetWallet.payment.private + ); + const selections = wallets.map((wallet) => ({ + type: "PaymentSigningKeyShelley_ed25519", + description: "Payment Signing Key", + cborHex: "5820" + wallet.payment.private, + })); + + const inputs = wallets.map((wallet) => wallet.address); + return kuber.signAndSubmitTx({ + inputs, + selections, + changeAddress: proposalFaucetWallet.address, + }); + }, + transferADA: (receiverAddressList: string[], ADA = 20) => { const kuber = new Kuber(faucetWallet.address, faucetWallet.payment.private); const req = { diff --git a/tests/govtool-frontend/playwright/lib/types.ts b/tests/govtool-frontend/playwright/lib/types.ts index 338c54d1d..25d233055 100644 --- a/tests/govtool-frontend/playwright/lib/types.ts +++ b/tests/govtool-frontend/playwright/lib/types.ts @@ -70,8 +70,9 @@ export type LinkType = { }; export enum ProposalType { - info = "Info", - treasury = "Treasury", + info = "Info Action", + treasury = "Treasury requests", + updatesToTheConstitution = "Updates to the Constitution", } export enum BootstrapGovernanceActionType { @@ -159,6 +160,9 @@ export type ProposalCreateRequest = { prop_rationale: string; prop_receiving_address?: string; prop_amount?: string; + prop_constitution_url?: string; + prop_guardrails_script_url?: string; + prop_guardrails_script_hash?: string; is_draft: boolean; }; diff --git a/tests/govtool-frontend/playwright/package.json b/tests/govtool-frontend/playwright/package.json index b52c3e5f8..fa3c3d102 100644 --- a/tests/govtool-frontend/playwright/package.json +++ b/tests/govtool-frontend/playwright/package.json @@ -25,7 +25,7 @@ "allure:serve": "npx allure serve", "test": "npx playwright test", "format": "prettier . --write", - "generate-wallets": "ts-node ./generate_wallets.ts 17" + "generate-wallets": "ts-node ./generate_wallets.ts 18" }, "dependencies": { "@cardanoapi/cardano-test-wallet": "^3.0.0", diff --git a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.spec.ts b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.spec.ts index 9de7c222d..d573eadee 100644 --- a/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.spec.ts +++ b/tests/govtool-frontend/playwright/tests/4-proposal-visibility/proposalVisibility.spec.ts @@ -22,7 +22,7 @@ test("4A_2. Should access Governance Actions page without connecting wallet", as await page.goto("/"); await page.getByTestId("move-to-governance-actions-button").click(); - await expect(page.getByText(/Governance actions/i)).toHaveCount(2); + await expect(page.getByText(/Governance actions/i)).toHaveCount(1); }); test("4B_2. Should restrict voting for users who are not registered as DReps (without wallet connected)", async ({ diff --git a/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.loggedin.spec.ts b/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.loggedin.spec.ts index 908b3ba0b..af5cbeb47 100644 --- a/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.loggedin.spec.ts +++ b/tests/govtool-frontend/playwright/tests/7-proposal-submission/proposalSubmission.loggedin.spec.ts @@ -6,12 +6,13 @@ import { proposal05Wallet, proposal06Wallet, proposal07Wallet, + proposal08Wallet, } from "@constants/staticWallets"; import { faker } from "@faker-js/faker"; import { test } from "@fixtures/proposal"; import { setAllureEpic } from "@helpers/allure"; import { - skipIfTreasuryAndBootstrapping, + skipIfNotInfoAndBootstrapping, skipIfNotHardFork, isBootStrapingPhase, } from "@helpers/cardano"; @@ -42,7 +43,7 @@ test.describe("Proposal created logged state", () => { test(`7E_${index + 1}. Should accept valid data in ${type.toLowerCase()} proposal form`, async ({ page, }) => { - await skipIfTreasuryAndBootstrapping(type); + await skipIfNotInfoAndBootstrapping(type); test.slow(); // Brute-force testing with 50 random data @@ -54,6 +55,10 @@ test.describe("Proposal created logged state", () => { await page.getByTestId(`${type.toLocaleLowerCase()}-button`).click(); await proposalSubmissionPage.addLinkBtn.click(); + if (type === ProposalType.updatesToTheConstitution) { + await proposalSubmissionPage.guardrailsScriptCheckbox.click(); + } + for (let i = 0; i < 50; i++) { const rewardAddressBech32 = ( await ShelleyWallet.generate() @@ -95,7 +100,7 @@ test.describe("Proposal created logged state", () => { test(`7F_${index + 1}. Should reject invalid data in ${type.toLowerCase()} Proposal form`, async ({ page, }) => { - await skipIfTreasuryAndBootstrapping(type); + await skipIfNotInfoAndBootstrapping(type); test.slow(); // Brute-force testing with 50 random data @@ -106,6 +111,10 @@ test.describe("Proposal created logged state", () => { await page.getByTestId(`${type.toLocaleLowerCase()}-button`).click(); await proposalSubmissionPage.addLinkBtn.click(); + if (type === ProposalType.updatesToTheConstitution) { + await proposalSubmissionPage.guardrailsScriptCheckbox.click(); + } + for (let i = 0; i < 50; i++) { const formFields: ProposalCreateRequest = proposalSubmissionPage.generateInValidProposalFormFields(type); @@ -121,7 +130,7 @@ test.describe("Proposal created logged state", () => { page, wallet, }) => { - await skipIfTreasuryAndBootstrapping(type); + await skipIfNotInfoAndBootstrapping(type); const proposalSubmissionPage = new ProposalSubmissionPage(page); await proposalSubmissionPage.goto(); @@ -175,7 +184,7 @@ test.describe("Proposal created logged state", () => { test(`7I_${index + 1}. Should valid review submission in ${type.toLowerCase()} Proposal form`, async ({ page, }) => { - await skipIfTreasuryAndBootstrapping(type); + await skipIfNotInfoAndBootstrapping(type); const proposalSubmissionPage = new ProposalSubmissionPage(page); await proposalSubmissionPage.goto(); @@ -221,6 +230,18 @@ test.describe("Proposal created logged state", () => { proposal.prop_amount ); } + + if (type === ProposalType.updatesToTheConstitution) { + await expect( + proposalSubmissionPage.constitutionUrlContent + ).toHaveText(proposal.prop_constitution_url); + await expect( + proposalSubmissionPage.guardrailsScriptUrlContent + ).toHaveText(proposal.prop_guardrails_script_url); + await expect( + proposalSubmissionPage.guardrailsScriptHashContent + ).toHaveText(proposal.prop_guardrails_script_hash); + } }); }); }); @@ -230,7 +251,7 @@ test.describe("Proposal created logged state", () => { test(`7D_${index + 1}. Verify ${type.toLocaleLowerCase()} proposal form`, async ({ page, }) => { - await skipIfTreasuryAndBootstrapping(type); + await skipIfNotInfoAndBootstrapping(type); const proposalSubmissionPage = new ProposalSubmissionPage(page); await proposalSubmissionPage.goto(); @@ -250,6 +271,25 @@ test.describe("Proposal created logged state", () => { await expect(proposalSubmissionPage.amountInput).toBeVisible(); } + + if (type === ProposalType.updatesToTheConstitution) { + await expect( + proposalSubmissionPage.constitutionUrlInput + ).toBeVisible(); + + await expect( + proposalSubmissionPage.guardrailsScriptCheckbox + ).toBeVisible(); + + await proposalSubmissionPage.guardrailsScriptCheckbox.click(); + + await expect( + proposalSubmissionPage.guardrailsScriptUrlInput + ).toBeVisible(); + await expect( + proposalSubmissionPage.guardrailsScriptHashInput + ).toBeVisible(); + } }); }); }); @@ -468,7 +508,7 @@ test.describe("Treasury Proposal Draft", () => { test.use({ storageState: ".auth/proposal07.json", wallet: proposal07Wallet }); test("7M_2. Should edit a treasury proposal draft", async ({ page }) => { - await skipIfTreasuryAndBootstrapping(ProposalType.treasury); + await skipIfNotInfoAndBootstrapping(ProposalType.treasury); const proposalSubmissionPage = new ProposalSubmissionPage(page); const { proposalFormValue } = await proposalSubmissionPage.createDraft( @@ -505,3 +545,51 @@ test.describe("Treasury Proposal Draft", () => { ); }); }); + +test.describe("Update the constitution Proposal Draft", () => { + test.use({ storageState: ".auth/proposal08.json", wallet: proposal08Wallet }); + + test("7M_3. Should edit update the constitution proposal draft", async ({ + page, + }) => { + await skipIfNotInfoAndBootstrapping(ProposalType.updatesToTheConstitution); + + const proposalSubmissionPage = new ProposalSubmissionPage(page); + const { proposalFormValue } = await proposalSubmissionPage.createDraft( + ProposalType.updatesToTheConstitution + ); + + const newTitle = faker.lorem.sentence(6); + + await proposalSubmissionPage.viewFirstDraft(); + await proposalSubmissionPage.titleInput.fill(newTitle); + await proposalSubmissionPage.continueBtn.click(); + + await expect(proposalSubmissionPage.governanceActionTypeContent).toHaveText( + ProposalType.updatesToTheConstitution + ); + await expect(proposalSubmissionPage.titleContent).toHaveText(newTitle); + await expect(proposalSubmissionPage.abstractContent).toHaveText( + proposalFormValue.prop_abstract + ); + await expect(proposalSubmissionPage.motivationContent).toHaveText( + proposalFormValue.prop_motivation + ); + await expect(proposalSubmissionPage.rationaleContent).toHaveText( + proposalFormValue.prop_rationale + ); + await expect(proposalSubmissionPage.constitutionUrlContent).toHaveText( + proposalFormValue.prop_constitution_url + ); + await expect(proposalSubmissionPage.guardrailsScriptUrlContent).toHaveText( + proposalFormValue.prop_guardrails_script_url + ); + await expect(proposalSubmissionPage.guardrailsScriptHashContent).toHaveText( + proposalFormValue.prop_guardrails_script_hash + ); + + await expect(proposalSubmissionPage.linkTextContent).toHaveText( + proposalFormValue.proposal_links[0].prop_link_text + ); + }); +}); diff --git a/tests/govtool-frontend/playwright/tests/8-proposal-discussion/proposalDiscussion.spec.ts b/tests/govtool-frontend/playwright/tests/8-proposal-discussion/proposalDiscussion.spec.ts index c320cd668..28688e6ed 100644 --- a/tests/govtool-frontend/playwright/tests/8-proposal-discussion/proposalDiscussion.spec.ts +++ b/tests/govtool-frontend/playwright/tests/8-proposal-discussion/proposalDiscussion.spec.ts @@ -1,4 +1,9 @@ import environments from "@constants/environments"; +import { + BOOTSTRAP_PROPOSAL_TYPE_FILTERS, + PROPOSAL_STATUS_FILTER, + PROPOSAL_TYPE_FILTERS, +} from "@constants/index"; import { faker } from "@faker-js/faker"; import { test } from "@fixtures/proposal"; import { setAllureEpic } from "@helpers/allure"; @@ -14,11 +19,6 @@ const mockComments = require("../../lib/_mock/proposalComments.json"); const mockInfoProposedGA = require("../../lib/_mock/infoProposedGAs.json"); const mockTreasuryProposal = require("../../lib/_mock/treasuryProposedGAs.json"); -const PROPOSAL_TYPE_FILTERS = ["Info", "Treasury"]; -const BOOTSTRAP_PROPOSAL_TYPE_FILTERS = ["Info"]; - -const PROPOSAL_STATUS_FILTER = ["Submitted for vote", "Active proposal"]; - test.beforeEach(async () => { await setAllureEpic("8. Proposal Discussion Forum"); await skipIfNotHardFork(); diff --git a/tests/govtool-frontend/playwright/tests/auth.setup.ts b/tests/govtool-frontend/playwright/tests/auth.setup.ts index 64135bb27..834a67cbd 100644 --- a/tests/govtool-frontend/playwright/tests/auth.setup.ts +++ b/tests/govtool-frontend/playwright/tests/auth.setup.ts @@ -16,6 +16,7 @@ import { proposal05Wallet, proposal06Wallet, proposal07Wallet, + proposal08Wallet, user01Wallet, } from "@constants/staticWallets"; import { test as setup } from "@fixtures/walletExtension"; @@ -46,6 +47,7 @@ const proposal04AuthFile = ".auth/proposal04.json"; const proposal05AuthFile = ".auth/proposal05.json"; const proposal06AuthFile = ".auth/proposal06.json"; const proposal07AuthFile = ".auth/proposal07.json"; +const proposal08AuthFile = ".auth/proposal08.json"; setup.beforeEach(async () => { await setAllureEpic("Setup"); @@ -196,3 +198,12 @@ setup("Create Proposal 07 auth", async ({ page, context }) => { auth: proposal07AuthFile, }); }); + +setup("Create Proposal 08 auth", async ({ page, context }) => { + await createAuthWithUserName({ + page, + context, + wallet: proposal08Wallet, + auth: proposal08AuthFile, + }); +}); diff --git a/tests/govtool-frontend/playwright/tests/faucet.teardown.ts b/tests/govtool-frontend/playwright/tests/faucet.teardown.ts index f64398eeb..002e02157 100644 --- a/tests/govtool-frontend/playwright/tests/faucet.teardown.ts +++ b/tests/govtool-frontend/playwright/tests/faucet.teardown.ts @@ -1,10 +1,12 @@ import environments from "@constants/environments"; -import { faucetWallet } from "@constants/staticWallets"; +import { allStaticWallets } from "@constants/staticWallets"; import { setAllureEpic, setAllureStory } from "@helpers/allure"; import { skipIfMainnet } from "@helpers/cardano"; import { pollTransaction } from "@helpers/transaction"; import { test as cleanup, expect } from "@playwright/test"; import kuberService from "@services/kuberService"; +import { StaticWallet } from "@types"; +import walletManager from "lib/walletManager"; cleanup.describe.configure({ timeout: environments.txTimeOut }); cleanup.beforeEach(async () => { @@ -14,16 +16,16 @@ cleanup.beforeEach(async () => { }); cleanup("Refund faucet", async () => { + const registerDRepWallets: StaticWallet[] = + await walletManager.readWallets("registerDRepCopy"); + const registeredDRepWallets: StaticWallet[] = + await walletManager.readWallets("registeredDRepCopy"); try { - const faucetRemainingBalance = await kuberService.getBalance( - faucetWallet.address - ); - - const transferBalance = Math.floor(faucetRemainingBalance) - 3; - const { txId, lockInfo } = await kuberService.transferADA( - [environments.faucet.address], - transferBalance - ); + const { txId, lockInfo } = await kuberService.mergeUtXos([ + ...allStaticWallets, + ...registerDRepWallets, + ...registeredDRepWallets, + ]); await pollTransaction(txId, lockInfo); } catch (err) { console.log(err);