Skip to content

Commit

Permalink
Merge pull request #1966 from IntersectMBO/feat/test-conditions-hardfork
Browse files Browse the repository at this point in the history
Bootstrap Tests/Hardfork Conditions, and Update Tests for Recent Changes
  • Loading branch information
kneerose authored Sep 9, 2024
2 parents 9207337 + 2fc441b commit c7b24c6
Show file tree
Hide file tree
Showing 39 changed files with 1,608 additions and 2,662 deletions.
1 change: 1 addition & 0 deletions tests/govtool-frontend/playwright/lib/constants/docsUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export const GUIDES_DOC_URL = `${environments.docsUrl}`;
export const PRIVACY_POLICY = `${environments.docsUrl}/legal/privacy-policy`;
export const TERMS_AND_CONDITIONS = `${environments.docsUrl}/legal/terms-and-conditions`;
export const HELP_DOC_URL = `${environments.docsUrl}/support/get-help-in-discord`;
export const BOOTSTRAP_DOC_URL = `${environments.docsUrl}/about/bootstrapping-phase`;
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,21 @@ import {
} from "@cardanoapi/cardano-test-wallet/types";
import { ShelleyWallet } from "@helpers/crypto";
import { Page } from "@playwright/test";
import { StaticWallet } from "@types";

export default async function createWallet(
page: Page,
config?: CardanoTestWalletConfig
) {
const wallet = (await ShelleyWallet.generate()).json();
await updateWalletConfig(page, config, wallet);
}

export async function updateWalletConfig(
page: Page,
config?: CardanoTestWalletConfig,
wallet?: StaticWallet
) {
const initScriptArgs: {
wallet: CardanoTestWalletJson;
config: CardanoTestWalletConfig;
Expand Down
91 changes: 74 additions & 17 deletions tests/govtool-frontend/playwright/lib/forms/dRepForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,20 @@ const formErrors = {
"this-field-is-required-error",
"no-spaces-allowed-error",
],
linkDescription: "max-80-characters-error",
email: "invalid-email-address-error",
link: "invalid-url-error",
paymentAddress: "invalid-payment-address-error",
};

export default class DRepForm {
readonly continueBtn = this.form.getByTestId("continue-button");
readonly addLinkBtn = this.form.getByTestId("add-link-button");
readonly addIdentityReferenceBtn = this.form.getByTestId(
"add-identity-reference-button"
);
readonly addLinkReferenceBtn = this.form.getByTestId(
"add-link-reference-button"
);
readonly registerBtn = this.form.getByTestId("register-button");
readonly submitBtn = this.form.getByTestId("submit-button");
readonly metadataDownloadBtn = this.form.getByTestId(
Expand All @@ -28,12 +34,24 @@ export default class DRepForm {
readonly nameInput = this.form.getByTestId("name-input");
readonly emailInput = this.form.getByTestId("email-input");
readonly bioInput = this.form.getByTestId("bio-input");
readonly linkInput = this.form.getByTestId("link-1-input");
readonly linkRefrenceFirstUrlInput = this.form.getByTestId(
"link-reference-url-1-input"
);
readonly linkRefrenceFirstDescriptionInput = this.form.getByTestId(
"link-reference-description-1-input"
);
readonly identityReferenceFirstDescriptionInput = this.form.getByTestId(
"identity-reference-description-1-input"
);
readonly identityReferenceFirstUrlInput = this.form.getByTestId(
"identity-reference-url-1-input"
);
readonly metadataUrlInput = this.form.getByTestId("metadata-url-input");
readonly objectivesInput = this.form.getByTestId("objectives-input");
readonly motivationsInput = this.form.getByTestId("motivations-input");
readonly qualificationsInput = this.form.getByTestId("qualifications-input");
readonly paymentAddressInput = this.form.getByTestId("payment-address-input");
readonly doNotListCheckBox = this.form.getByRole("checkbox");

constructor(private readonly form: Page) {}

Expand All @@ -58,14 +76,37 @@ export default class DRepForm {
await this.paymentAddressInput.fill(dRepInfo.paymentAddress);
}

if (dRepInfo.extraContentLinks != null) {
for (let i = 0; i < dRepInfo.extraContentLinks.length; i++) {
if (dRepInfo.linksReferenceLinks != null) {
for (let i = 0; i < dRepInfo.linksReferenceLinks.length; i++) {
if (i > 0) {
await this.addLinkBtn.click();
await this.addLinkReferenceBtn.click();
}
await this.linkInput.nth(i).fill(dRepInfo.extraContentLinks[i]);
await this.form
.getByTestId(`link-reference-url-${i + 1}-input`)
.fill(dRepInfo.linksReferenceLinks[i].url);
await this.form
.getByTestId(`link-reference-description-${i + 1}-input`)
.fill(dRepInfo.linksReferenceLinks[i].description);
}
}

if (dRepInfo.identityReferenceLinks != null) {
for (let i = 0; i < dRepInfo.identityReferenceLinks.length; i++) {
if (i > 0) {
await this.addIdentityReferenceBtn.click();
}
await this.form
.getByTestId(`identity-reference-url-${i + 1}-input`)
.fill(dRepInfo.identityReferenceLinks[i].url);
await this.form
.getByTestId(`identity-reference-description-${i + 1}-input`)
.fill(dRepInfo.identityReferenceLinks[i].description);
}
}
if (dRepInfo.donNotList) {
await this.doNotListCheckBox.click();
}

await this.continueBtn.click();
await this.form.getByRole("checkbox").click();
await this.registerBtn.click();
Expand All @@ -86,13 +127,28 @@ export default class DRepForm {
return downloadMetadata(download);
}

async validateForm(dRepInfo: IDRepInfo) {
async fillupForm(dRepInfo: IDRepInfo) {
await this.nameInput.fill(dRepInfo.name);
await this.objectivesInput.fill(dRepInfo.objectives);
await this.motivationsInput.fill(dRepInfo.motivations);
await this.qualificationsInput.fill(dRepInfo.qualifications);
await this.paymentAddressInput.fill(dRepInfo.paymentAddress);
await this.linkInput.fill(dRepInfo.extraContentLinks[0]);
await this.linkRefrenceFirstUrlInput.fill(
dRepInfo.linksReferenceLinks[0].url
);
await this.linkRefrenceFirstDescriptionInput.fill(
dRepInfo.linksReferenceLinks[0].description
);
await this.identityReferenceFirstUrlInput.fill(
dRepInfo.identityReferenceLinks[0].url
);
await this.identityReferenceFirstDescriptionInput.fill(
dRepInfo.identityReferenceLinks[0].description
);
}

async validateForm(dRepInfo: IDRepInfo) {
await this.fillupForm(dRepInfo);

for (const err of formErrors.dRepName) {
await expect(this.form.getByTestId(err)).toBeHidden();
Expand All @@ -111,17 +167,11 @@ export default class DRepForm {

await expect(this.form.getByTestId(formErrors.link)).toBeHidden();
await expect(this.form.getByTestId(formErrors.paymentAddress)).toBeHidden();

await expect(this.continueBtn).toBeEnabled();
}

async inValidateForm(dRepInfo: IDRepInfo) {
await this.nameInput.fill(dRepInfo.name);
await this.objectivesInput.fill(dRepInfo.objectives);
await this.motivationsInput.fill(dRepInfo.motivations);
await this.qualificationsInput.fill(dRepInfo.qualifications);
await this.paymentAddressInput.fill(dRepInfo.paymentAddress);
await this.linkInput.fill(dRepInfo.extraContentLinks[0]);
await this.fillupForm(dRepInfo);

function convertTestIdToText(testId: string) {
let text = testId.replace("-error", "");
Expand All @@ -140,7 +190,7 @@ export default class DRepForm {
})
.all();

expect(nameErrors.length).toEqual(1);
expect(nameErrors.length).toBeGreaterThanOrEqual(1); // BUG duplicate test ids

await expect(
this.form.getByTestId(formErrors.paymentAddress)
Expand All @@ -156,7 +206,14 @@ export default class DRepForm {
dRepInfo.qualifications
);

await expect(this.form.getByTestId(formErrors.link)).toBeVisible();
await expect(this.form.getByTestId(formErrors.link).first()).toBeVisible(); // BUG duplicate test ids
await expect(
this.form.getByTestId(formErrors.linkDescription).first()
).toBeVisible(); // BUG duplicate test ids
await expect(this.form.getByTestId(formErrors.link).last()).toBeVisible(); // BUG duplicate test ids
await expect(
this.form.getByTestId(formErrors.linkDescription).last()
).toBeVisible(); // BUG duplicate test ids

await expect(this.continueBtn).toBeDisabled();
}
Expand Down
33 changes: 33 additions & 0 deletions tests/govtool-frontend/playwright/lib/helpers/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import LoginPage from "@pages/loginPage";
import ProposalDiscussionPage from "@pages/proposalDiscussionPage";
import { BrowserContext, Page } from "@playwright/test";
import { StaticWallet } from "@types";
import { ShelleyWallet } from "./crypto";
import convertBufferToHex from "./convertBufferToHex";
import { updateWalletConfig } from "@fixtures/createWallet";
import { adaHolder05Wallet } from "@constants/staticWallets";

interface CreateUserProps {
page: Page;
Expand Down Expand Up @@ -47,3 +51,32 @@ export async function createAuthWithUserName({

await context.storageState({ path: auth });
}

export async function createAuthWithMultipleStake({
page,
context,
auth,
wallet,
}) {
const extraPubStakeKey = convertBufferToHex(
ShelleyWallet.fromJson(adaHolder05Wallet).stakeKey.public
);
const extraRewardAddress = convertBufferToHex(
ShelleyWallet.fromJson(adaHolder05Wallet).rewardAddressRawBytes(0)
);

await updateWalletConfig(
page,
{
extraRegisteredPubStakeKeys: [extraPubStakeKey],
extraRewardAddresses: [extraRewardAddress],
},
wallet
);

const loginPage = new LoginPage(page);
await loginPage.login();
await loginPage.isLoggedIn();

await context.storageState({ path: auth });
}
35 changes: 35 additions & 0 deletions tests/govtool-frontend/playwright/lib/helpers/cardano.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import test, { expect } from "@playwright/test";
import kuberService from "@services/kuberService";
import { ProposalType, ProtocolParams } from "@types";
import { allure } from "allure-playwright";
import { bech32 } from "bech32";

export function lovelaceToAda(lovelace: number) {
Expand All @@ -10,3 +14,34 @@ export function generateWalletAddress() {
const randomBytes = new Uint8Array(10);
return bech32.encode("addr_test", randomBytes);
}

export async function getProtocolParamsMajorVersion() {
const protocolParameter: ProtocolParams =
await kuberService.queryProtocolParams();
return protocolParameter.protocolVersion.major;
}

export async function isBootStrapingPhase() {
const protocolParameterMajorVersion = await getProtocolParamsMajorVersion();
return protocolParameterMajorVersion === 9;
}

export async function skipIfTreasuryAndBootstrapping(type: ProposalType) {
const isBootStraping = await isBootStrapingPhase();
if (type === ProposalType.treasury && isBootStraping) {
await allure.description(
"This Features will be available only after hardfork."
);
test.skip();
}
}

export async function skipIfNotHardFork() {
const currentProtocolVersion = await getProtocolParamsMajorVersion();
if (currentProtocolVersion < 9) {
await allure.description(
"Govtool Features will be available after hardfork."
);
test.skip();
}
}
12 changes: 12 additions & 0 deletions tests/govtool-frontend/playwright/lib/pages/dRepDirectoryPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,16 @@ export default class DRepDirectoryPage {
.locator('[data-testid$="-drep-card"]')
.all();
}

async verifyDRepInList(dRepId: string) {
await this.goto();

await this.searchInput.fill(dRepId);

await this.page.waitForTimeout(5_000); // wait until the dRep list render properly

await expect(
this.page.getByTestId(`${dRepId}-drep-card`)
).not.toBeVisible();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { withTxConfirmation } from "lib/transaction.decorator";

export default class GovernanceActionDetailsPage {
readonly voteBtn = this.page.getByTestId("vote-button");
readonly backBtn = this.page.getByTestId("back-to-list-link");
readonly changeVoteBtn = this.page.getByTestId("change-vote");
readonly yesVoteRadio = this.page.getByTestId("yes-radio");
readonly noVoteRadio = this.page.getByTestId("no-radio");
Expand Down Expand Up @@ -80,6 +81,6 @@ export default class GovernanceActionDetailsPage {
@withTxConfirmation
async reVote() {
await this.noVoteRadio.click();
await this.changeVoteBtn.click();
await this.voteBtn.click();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import removeAllSpaces from "@helpers/removeAllSpaces";
import { Locator, Page, expect } from "@playwright/test";
import { FilterOption, IProposal } from "@types";
import { GrovernanceActionType, IProposal } from "@types";
import environments from "lib/constants/environments";
import GovernanceActionDetailsPage from "./governanceActionDetailsPage";
import { getEnumKeyByValue } from "@helpers/enum";
Expand Down Expand Up @@ -47,15 +47,28 @@ export default class GovernanceActionsPage {
return new GovernanceActionDetailsPage(this.page);
}

async viewFirstInfoProposal(): Promise<GovernanceActionDetailsPage> {
const treasuryWithdrawFirstCard = this.page
.getByTestId("govaction-InfoAction-card")
async viewFirstProposalByGovernanceAction(
governanceAction: GrovernanceActionType
): Promise<GovernanceActionDetailsPage> {
const proposalCard = this.page
.getByTestId(`govaction-${governanceAction}-card`)
.first();
await treasuryWithdrawFirstCard
.locator('[data-testid^="govaction-"][data-testid$="-view-detail"]')
.first()
.click();
return new GovernanceActionDetailsPage(this.page);

const isVisible = await proposalCard.isVisible();

if (isVisible) {
await proposalCard
.locator('[data-testid^="govaction-"][data-testid$="-view-detail"]')
.first()
.click();

return new GovernanceActionDetailsPage(this.page);
} else {
console.warn(
`Governance action details page for "${governanceAction}" was not found.`
);
return null;
}
}

async viewVotedProposal(
Expand Down Expand Up @@ -108,14 +121,16 @@ export default class GovernanceActionsPage {
async sortAndValidate(
sortOption: string,
validationFn: (p1: IProposal, p2: IProposal) => boolean,
filterKeys = Object.keys(FilterOption)
filterKeys = Object.keys(GrovernanceActionType)
) {
const responsesPromise = Promise.all(
filterKeys.map((filterKey) =>
this.page.waitForResponse((response) =>
response
.url()
.includes(`&type[]=${FilterOption[filterKey]}&sort=${sortOption}`)
.includes(
`&type[]=${GrovernanceActionType[filterKey]}&sort=${sortOption}`
)
)
)
);
Expand All @@ -142,13 +157,15 @@ export default class GovernanceActionsPage {
}
});

await this.page.waitForTimeout(4_000); // wait for proposals to render
await expect(
this.page.getByRole("progressbar").getByRole("img")
).toBeHidden({ timeout: 10_000 });

// Frontend validation
for (let dIdx = 0; dIdx <= proposalsByType.length - 1; dIdx++) {
const proposals = proposalsByType[0] as IProposal[];
const filterOptionKey = getEnumKeyByValue(
FilterOption,
GrovernanceActionType,
proposals[0].type
);

Expand Down
Loading

0 comments on commit c7b24c6

Please sign in to comment.