Skip to content
1 change: 1 addition & 0 deletions tests/govtool-frontend/playwright/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ lib/_mock/registerDRepCopyWallets.json
lib/_mock/registeredDRepCopyWallets.json
lib/_mock/wallets.json
lib/_mock/proposals.json
lib/_mock/protocolParameter.json
./lock_logs.txt
137 changes: 104 additions & 33 deletions tests/govtool-frontend/playwright/lib/forms/dRepForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const formErrors = {
linkDescription: "max-80-characters-error",
email: "invalid-email-address-error",
links: {
url:"link-reference-description-1-error",
url: "link-reference-description-1-error",
description: "link-reference-description-1-error",
},
identity: {
Expand Down Expand Up @@ -160,21 +160,52 @@ export default class DRepForm {
for (const err of formErrors.dRepName) {
await expect(this.form.getByTestId(err)).toBeHidden();
}
const objectivesInputText = await this.objectivesInput.textContent();
const motivationsInputText = await this.motivationsInput.textContent();
const qualificationsInputText =
await this.qualificationsInput.textContent();
const isReferenceLinkErrorVisible = await this.form
.getByTestId(formErrors.links.url)
.isVisible();
const isIdentityLinkErrorVisible = await this.form
.getByTestId(formErrors.identity.url)
.isVisible();
const isPaymentAddressErrorVisible = await this.form
.getByTestId(formErrors.paymentAddress)
.isVisible();

expect(await this.objectivesInput.textContent()).toEqual(
dRepInfo.objectives
);
expect(await this.objectivesInput.textContent(), {
message:
objectivesInputText !== dRepInfo.objectives &&
`${dRepInfo.objectives} is not equal to ${await this.objectivesInput.textContent()}`,
}).toEqual(dRepInfo.objectives);

expect(await this.motivationsInput.textContent()).toEqual(
dRepInfo.motivations
);
expect(await this.qualificationsInput.textContent()).toEqual(
dRepInfo.qualifications
);
expect(await this.motivationsInput.textContent(), {
message:
motivationsInputText !== dRepInfo.motivations &&
`${dRepInfo.motivations} is not equal to ${await this.motivationsInput.textContent()}`,
}).toEqual(dRepInfo.motivations);
expect(await this.qualificationsInput.textContent(), {
message:
qualificationsInputText !== dRepInfo.qualifications &&
`${dRepInfo.qualifications} is not equal to ${await this.qualificationsInput.textContent()}`,
}).toEqual(dRepInfo.qualifications);

await expect(this.form.getByTestId(formErrors.links.url)).toBeHidden();
await expect(this.form.getByTestId(formErrors.identity.url)).toBeHidden();
await expect(this.form.getByTestId(formErrors.paymentAddress)).toBeHidden();
await expect(this.form.getByTestId(formErrors.links.url), {
message:
isReferenceLinkErrorVisible &&
`${dRepInfo.linksReferenceLinks[0].url} is an invalid url`,
}).toBeHidden();
await expect(this.form.getByTestId(formErrors.identity.url), {
message:
isIdentityLinkErrorVisible &&
`${dRepInfo.identityReferenceLinks[0].url} is an invalid url`,
}).toBeHidden();
await expect(this.form.getByTestId(formErrors.paymentAddress), {
message:
isPaymentAddressErrorVisible &&
`${dRepInfo.paymentAddress} is an invalid paymentAddress`,
}).toBeHidden();
await expect(this.continueBtn).toBeEnabled();
}

Expand All @@ -200,28 +231,68 @@ export default class DRepForm {

expect(nameErrors.length).toBeGreaterThanOrEqual(1);

await expect(
this.form.getByTestId(formErrors.paymentAddress)
).toBeVisible();
const objectivesInputText = await this.objectivesInput.textContent();
const motivationsInputText = await this.motivationsInput.textContent();
const qualificationsInputText =
await this.qualificationsInput.textContent();
const isReferenceLinkErrorVisible = await this.form
.getByTestId(formErrors.links.url)
.isVisible();
const isReferenceLinkDescriptionErrorVisible = await this.form
.getByTestId(formErrors.links.description)
.isVisible();
const isIdentityLinkErrorVisible = await this.form
.getByTestId(formErrors.identity.url)
.isVisible();
const isIdentityLinkDescriptionErrorVisible = await this.form
.getByTestId(formErrors.identity.description)
.isVisible();
const isPaymentAddressErrorVisible = await this.form
.getByTestId(formErrors.paymentAddress)
.isVisible();

expect(await this.objectivesInput.textContent()).not.toEqual(
dRepInfo.objectives
);
expect(await this.motivationsInput.textContent()).not.toEqual(
dRepInfo.qualifications
);
expect(await this.qualificationsInput.textContent()).not.toEqual(
dRepInfo.qualifications
);
await expect(this.form.getByTestId(formErrors.paymentAddress), {
message:
!isPaymentAddressErrorVisible &&
`${dRepInfo.paymentAddress} is a valid paymentAddress`,
}).toBeVisible();

expect(await this.objectivesInput.textContent(), {
message:
objectivesInputText === dRepInfo.objectives &&
`${dRepInfo.objectives} is equal to ${await this.objectivesInput.textContent()}`,
}).not.toEqual(dRepInfo.objectives);
expect(await this.motivationsInput.textContent(), {
message:
motivationsInputText === dRepInfo.motivations &&
`${dRepInfo.motivations} is equal to ${await this.motivationsInput.textContent()}`,
}).not.toEqual(dRepInfo.qualifications);
expect(await this.qualificationsInput.textContent(), {
message:
qualificationsInputText === dRepInfo.qualifications &&
`${dRepInfo.qualifications} is equal to ${await this.qualificationsInput.textContent()}`,
}).not.toEqual(dRepInfo.qualifications);

await expect(this.form.getByTestId(formErrors.links.url)).toBeVisible();
await expect(
this.form.getByTestId(formErrors.links.description)
).toBeVisible();
await expect(this.form.getByTestId(formErrors.identity.url)).toBeVisible();
await expect(
this.form.getByTestId(formErrors.identity.description)
).toBeVisible();
await expect(this.form.getByTestId(formErrors.links.url), {
message:
!isReferenceLinkErrorVisible &&
`${dRepInfo.linksReferenceLinks[0].url} is a valid url`,
}).toBeVisible();
await expect(this.form.getByTestId(formErrors.links.description), {
message:
!isReferenceLinkDescriptionErrorVisible &&
`${dRepInfo.linksReferenceLinks[0].description} is a valid description`,
}).toBeVisible();
await expect(this.form.getByTestId(formErrors.identity.url), {
message:
!isIdentityLinkErrorVisible &&
`${dRepInfo.identityReferenceLinks[0].url} is a valid url`,
}).toBeVisible();
await expect(this.form.getByTestId(formErrors.identity.description), {
message:
!isIdentityLinkDescriptionErrorVisible &&
`${dRepInfo.identityReferenceLinks[0].description} is a valid description`,
}).toBeVisible();

await expect(this.continueBtn).toBeDisabled();
}
Expand Down
14 changes: 12 additions & 2 deletions tests/govtool-frontend/playwright/lib/helpers/cardano.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import kuberService from "@services/kuberService";
import { ProposalType, ProtocolParams } from "@types";
import { allure } from "allure-playwright";
import { bech32 } from "bech32";
import { functionWaitedAssert } from "./waitedLoop";
import { createFile, getFile } from "./file";

export function lovelaceToAda(lovelace: number) {
if (lovelace === 0) return 0;
Expand All @@ -17,8 +19,16 @@ export function generateWalletAddress() {
}

export async function getProtocolParamsMajorVersion() {
const protocolParameter: ProtocolParams =
await kuberService.queryProtocolParams();
let protocolParameter = await getFile("protocolParameter.json");
if (protocolParameter === undefined) {
await functionWaitedAssert(
async () => {
protocolParameter = await kuberService.queryProtocolParams();
await createFile("protocolParameter.json", protocolParameter);
},
{ name: "queryProtocolParams" }
);
}
return protocolParameter.protocolVersion.major;
}

Expand Down
19 changes: 18 additions & 1 deletion tests/govtool-frontend/playwright/lib/helpers/file.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { writeFile } from "fs";
import { readFile, writeFile } from "fs";
const path = require("path");

const baseFilePath = path.resolve(__dirname, "../_mock");
Expand All @@ -18,3 +18,20 @@ export async function createFile(fileName: string, data?: any) {
)
);
}

export async function getFile(fileName: string): Promise<any> {
const data: string = await new Promise((resolve, reject) =>
readFile(`${baseFilePath}/${fileName}`, "utf8", (err, data) => {
if (err) {
if (err.code === "ENOENT") {
resolve(undefined);
} else {
reject(err);
}
} else {
resolve(data);
}
})
);
return data ? JSON.parse(data) : undefined;
}
46 changes: 29 additions & 17 deletions tests/govtool-frontend/playwright/lib/pages/dRepDirectoryPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ export default class DRepDirectoryPage {
async filterDReps(filterOptions: string[]) {
for (const option of filterOptions) {
await this.page.getByTestId(`${option}-checkbox`).click();
if (option !== "Active" && filterOptions.length === 1) {
await this.page.getByTestId(`Active-checkbox`).click();
}
}
}

Expand Down Expand Up @@ -143,20 +140,28 @@ export default class DRepDirectoryPage {
const isValid = validationFn(dRepList[i], dRepList[i + 1]);
expect(isValid).toBe(true);
}
// Frontend validation
const cip105DRepListFE = await this.getAllListedCIP105DRepIds();
const cip129DRepListFE = await this.getAllListedCIP129DRepIds();

const cip129DRepListApi = dRepList.map((dRep) =>
convertDRepToCIP129(dRep.drepId, dRep.isScriptBased)
);
await functionWaitedAssert(
async () => {
// Frontend validation
const cip105DRepListFE = await this.getAllListedCIP105DRepIds();
const cip129DRepListFE = await this.getAllListedCIP129DRepIds();

for (let i = 0; i <= cip105DRepListFE.length - 1; i++) {
await expect(cip129DRepListFE[i]).toHaveText(cip129DRepListApi[i]);
await expect(cip105DRepListFE[i]).toHaveText(
`(CIP-105) ${dRepList[i].view}`
);
}
const cip129DRepListApi = dRepList.map((dRep) =>
convertDRepToCIP129(dRep.drepId, dRep.isScriptBased)
);

for (let i = 0; i <= cip105DRepListFE.length - 1; i++) {
await expect(cip129DRepListFE[i], {
message: `Cip129 dRep Id from Api:${cip129DRepListApi[i]} is not equal to ${await cip129DRepListFE[i].textContent()} on sort ${option}`,
}).toHaveText(cip129DRepListApi[i]);
await expect(cip105DRepListFE[i], {
message: `Cip105 dRep Id from Api:${dRepList[i].view} is not equal to ${await cip105DRepListFE[i].textContent()} on sort ${option}`,
}).toHaveText(`(CIP-105) ${dRepList[i].view}`);
}
},
{ name: `frontend sort validation of ${option}` }
);
}
getDRepCard(dRepId: string) {
return this.page.getByTestId(`${dRepId}-drep-card`);
Expand Down Expand Up @@ -194,8 +199,15 @@ export default class DRepDirectoryPage {
await this.goto();

await this.searchInput.fill(dRepId);

await expect(this.page.getByText("No DReps found")).toBeVisible({
const isEmptyContainerVisible = await this.page
.getByText("No DReps found")
.isVisible();

await expect(this.page.getByText("No DReps found"), {
message:
!isEmptyContainerVisible &&
`DRep with id ${dRepId} is found in the list`,
}).toBeVisible({
timeout: 20_000,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { GovernanceActionType, IProposal } from "@types";
import environments from "lib/constants/environments";
import GovernanceActionDetailsPage from "./governanceActionDetailsPage";
import { getEnumKeyByValue } from "@helpers/enum";
import { waitedLoop } from "@helpers/waitedLoop";
import { functionWaitedAssert, waitedLoop } from "@helpers/waitedLoop";

const MAX_SLIDES_DISPLAY_PER_TYPE = 6;

Expand Down Expand Up @@ -106,18 +106,20 @@ export default class GovernanceActionsPage {
}

async validateFilters(filters: string[]) {
const proposalCards = await this.getAllProposals();

for (const proposalCard of proposalCards) {
const hasFilter = await this._validateFiltersInProposalCard(
proposalCard,
filters
);
expect(
hasFilter,
"A proposal card does not contain any of the filters"
).toBe(true);
}
await functionWaitedAssert(async () => {
const proposalCards = await this.getAllProposals();

for (const proposalCard of proposalCards) {
const hasFilter = await this._validateFiltersInProposalCard(
proposalCard,
filters
);
expect(
hasFilter,
`A proposal card does not contain any of the ${filters}`
).toBe(true);
}
});
}

async sortProposal(option: string) {
Expand Down Expand Up @@ -167,29 +169,36 @@ export default class GovernanceActionsPage {
this.page.getByRole("progressbar").getByRole("img")
).toBeHidden({ timeout: 20_000 });

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

const slides = await this.page
.locator(`[data-testid="govaction-${filterOptionKey}-card"]`)
.all();

const actualSlidesInDisplay =
proposals.length > MAX_SLIDES_DISPLAY_PER_TYPE
? MAX_SLIDES_DISPLAY_PER_TYPE
: proposals.length;

expect(slides).toHaveLength(actualSlidesInDisplay);

for (let i = 0; i <= slides.length - 1; i++) {
await expect(slides[i]).toContainText(`${proposals[i].txHash}`);
await functionWaitedAssert(
async () => {
// Frontend validation
for (let dIdx = 0; dIdx <= proposalsByType.length - 1; dIdx++) {
const proposals = proposalsByType[0] as IProposal[];
const filterOptionKey = getEnumKeyByValue(
GovernanceActionType,
proposals[0].type
);

const slides = await this.page
.locator(`[data-testid="govaction-${filterOptionKey}-card"]`)
.all();

const actualSlidesInDisplay =
proposals.length > MAX_SLIDES_DISPLAY_PER_TYPE
? MAX_SLIDES_DISPLAY_PER_TYPE
: proposals.length;

expect(slides).toHaveLength(actualSlidesInDisplay);

for (let i = 0; i <= slides.length - 1; i++) {
await expect(slides[i]).toContainText(`${proposals[i].txHash}`);
}
}
},
{
name: `frontend sort validation of ${sortOption} and filter ${filterKeys}`,
}
}
);
}

async _validateFiltersInProposalCard(
Expand Down
Loading