Skip to content

Commit

Permalink
Merge pull request #2572 from IntersectMBO/refactor/test-structure
Browse files Browse the repository at this point in the history
Refactor test suite: Automated Testing Strategy for Mainnet with ADA-Free Scenarios
  • Loading branch information
kneerose authored Dec 23, 2024
2 parents 2d816f0 + 63b50c4 commit 88908ec
Show file tree
Hide file tree
Showing 30 changed files with 350 additions and 272 deletions.
17 changes: 13 additions & 4 deletions .github/workflows/test_integration_playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ on:
- "staging.govtool.byron.network"
- "govtool.cardanoapi.io"
- "preview.gov.tools"
- "gov.tools"

workflow_run:
workflows: ["Build and deploy GovTool to TEST server"]
Expand Down Expand Up @@ -54,18 +55,27 @@ jobs:
mkdir -p ./lib/_mock
chmod +w ./lib/_mock
npm run generate-wallets
if [[ "${{ env.NETWORK }}" == "preprod" ]]; then
# Set network variables based on deployment input and environment
if [[ "${{inputs.deployment}}" == "gov.tools" ]]; then
export NETWORK='mainnet'
else
export NETWORK="${{ vars.NETWORK }}"
fi
# Set API keys based on the network
if [[ "${{ vars.NETWORK }}" == "preprod" ]]; then
export FAUCET_API_KEY="${{ secrets.FAUCET_API_KEY_PREPROD }}"
export BLOCKFROST_API_KEY="${{ secrets.BLOCKFROST_API_KEY_PREPROD }}"
elif [[ "${{ env.NETWORK }}" == "sanchonet" ]]; then
elif [[ "${{ vars.NETWORK }}" == "sanchonet" ]]; then
export FAUCET_API_KEY="${{ secrets.FAUCET_API_KEY_SANCHONET }}"
export BLOCKFROST_API_KEY="${{ secrets.BLOCKFROST_API_KEY_SANCHONET }}"
else
export FAUCET_API_KEY="${{ secrets.FAUCET_API_KEY_PREVIEW }}"
export BLOCKFROST_API_KEY="${{ secrets.BLOCKFROST_API_KEY_PREVIEW }}"
fi
npm test
- name: Upload report
uses: actions/upload-artifact@v3
Expand All @@ -88,7 +98,6 @@ jobs:
KUBER_API_KEY: ${{secrets.KUBER_API_KEY}}
TEST_WORKERS: ${{vars.TEST_WORKERS}}
CI: ${{vars.CI}}
NETWORK: ${{vars.NETWORK}}
FAUCET_ADDRESS: ${{vars.FAUCET_ADDRESS}}
CARDANOAPI_METADATA_URL: ${{vars.CARDANOAPI_METADATA_URL}}
PROPOSAL_FAUCET_PAYMENT_PRIVATE: ${{secrets.PROPOSAL_FAUCET_PAYMENT_PRIVATE}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ const environments = {
apiUrl: `${SERVER_HOST_URL}/api`,
docsUrl: process.env.DOCS_URL || "https://docs.gov.tools/cardano-govtool",
pdfUrl: process.env.PDF_URL || "https://dev.api.pdf.gov.tools",
networkId: parseInt(process.env.NETWORK_ID) || 0,
networkId: NETWORK === "mainnet" ? 1 : 0,
faucet: {
apiUrl:`https://faucet.${NETWORK}.world.dev.cardano.org`,
apiUrl: `https://faucet.${NETWORK}.world.dev.cardano.org`,
apiKey: process.env.FAUCET_API_KEY || "",
address:
process.env.FAUCET_ADDRESS ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default async function loadDemosExtension(
let walletConfig: CardanoTestWalletConfig = {
enableStakeSigning,
kuberApiUrl: environments.kuber.apiUrl,
networkId: environments.networkId,
kuberApiKey: environments.kuber.apiKey,
blockfrostApiKey: environments.blockfrostApiKey,
blockfrostApiUrl: environments.blockfrostApiUrl,
Expand Down
2 changes: 1 addition & 1 deletion tests/govtool-frontend/playwright/lib/helpers/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export async function createAuthWithUserName({

const proposalDiscussionPage = new ProposalDiscussionPage(page);
await proposalDiscussionPage.goto();
await proposalDiscussionPage.verifyIdentityBtn.click();
await proposalDiscussionPage.verifyIdentityBtn.click({ timeout: 15_000 });

await proposalDiscussionPage.setUsername(mockValid.username());

Expand Down
12 changes: 11 additions & 1 deletion tests/govtool-frontend/playwright/lib/helpers/cardano.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import test, { expect } from "@playwright/test";
import environments from "@constants/environments";
import test from "@playwright/test";
import kuberService from "@services/kuberService";
import { ProposalType, ProtocolParams } from "@types";
import { allure } from "allure-playwright";
Expand Down Expand Up @@ -45,3 +46,12 @@ export async function skipIfNotHardFork() {
test.skip();
}
}

export async function skipIfMainnet() {
if (environments.networkId === 1) {
await allure.description(
"Ada spendable features are not available on mainnet."
);
test.skip();
}
}
39 changes: 39 additions & 0 deletions tests/govtool-frontend/playwright/lib/helpers/dRep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import DRepDirectoryPage from "@pages/dRepDirectoryPage";
import { Page } from "@playwright/test";

export async function fetchFirstActiveDRepDetails(page: Page) {
let dRepGivenName: string;
let dRepId: string;
let dRepDirectoryPage: DRepDirectoryPage;
await page.route(
"**/drep/list?page=0&pageSize=10&sort=Random&**",
async (route) => {
const response = await route.fetch();
const json = await response.json();
const elements = json["elements"].filter(
(element) => element["givenName"] != null
);
dRepGivenName =
elements[Math.floor(Math.random() * elements.length)]["givenName"];
dRepId = json["elements"][0]["view"];
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify(json),
});
}
);

const responsePromise = page.waitForResponse(
"**/drep/list?page=0&pageSize=10&sort=Random&**"
);

dRepDirectoryPage = new DRepDirectoryPage(page);
await dRepDirectoryPage.goto();
await dRepDirectoryPage.filterBtn.click();
await page.getByTestId("Active-checkbox").click();
await responsePromise;

await dRepDirectoryPage.searchInput.click();
return { dRepGivenName, dRepId, dRepDirectoryPage };
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,10 @@ export default class DRepDirectoryPage {
}

async getAllListedDReps() {
await this.page.waitForTimeout(5_000); // load until the dRep card load properly
// wait for the dRep list to render properly
await this.page.waitForTimeout(3_000);
// add assertion to wait until the search input is visible
await expect(this.searchInput).toBeVisible({ timeout: 10_000 });

return await this.page
.getByRole("list")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,7 @@ export default class ProposalDiscussionPage {

async goto() {
await this.page.goto(`${environments.frontendUrl}/proposal_discussion`);
// Temporary fix for blank proposals issue in proposal view during disconnected state
// This code handles the blank proposals error, which is causing failing tests.
// It will be removed once the underlying issue is resolved.
await this.page.getByTestId("logo-button").click();
if (isMobile(this.page)) {
await this.page.getByTestId("open-drawer-button").click();
}
await this.page.getByText("Proposals", { exact: true }).click();

// wait for the proposal cards to load
await this.page.waitForTimeout(2_000);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export default class ProposalSubmissionPage {

async getFirstDraft() {
await expect(
this.page.locator('[data-testid^="draft-"][data-testid$="-card"]')
this.page.locator('[data-testid^="draft-"][data-testid$="-card"]').first()
).toBeVisible({ timeout: 10_000 }); // slow rendering

return this.page
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import environments from "@constants/environments";
import createWallet from "@fixtures/createWallet";
import { test } from "@fixtures/walletExtension";
import { setAllureEpic } from "@helpers/allure";
Expand All @@ -17,29 +18,34 @@ test("1A. Should connect wallet and choose stake-key to use", async ({
const shellyWallet = await ShelleyWallet.generate();
const extraPubStakeKey = convertBufferToHex(shellyWallet.stakeKey.public);
const extraRewardAddress = convertBufferToHex(
shellyWallet.rewardAddressRawBytes(0)
shellyWallet.rewardAddressRawBytes(environments.networkId)
);

await createWallet(page, {
extraRegisteredPubStakeKeys: [extraPubStakeKey],
extraRewardAddresses: [extraRewardAddress],
networkId: environments.networkId,
});

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

test("1C. Should disconnect Wallet When connected", async ({ page }) => {
await createWallet(page);
await createWallet(page, {
networkId: environments.networkId,
});

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

await loginPage.logout();
});

test("1D. Should reject wallet connection in mainnet", async ({ page }) => {
const wrongNetworkId = 1; // mainnet network
test("1D. Should reject wallet connection if on different network", async ({
page,
}) => {
const wrongNetworkId = environments.networkId == 0 ? 1 : 0;
await createWallet(page, {
networkId: wrongNetworkId,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import environments from "@constants/environments";
import { dRep01Wallet, user01Wallet } from "@constants/staticWallets";
import { createTempDRepAuth } from "@datafactory/createAuth";
import { faker } from "@faker-js/faker";
import { test } from "@fixtures/walletExtension";
import { setAllureEpic } from "@helpers/allure";
import { skipIfNotHardFork } from "@helpers/cardano";
import { skipIfMainnet, skipIfNotHardFork } from "@helpers/cardano";
import { ShelleyWallet } from "@helpers/crypto";
import { isMobile, openDrawer } from "@helpers/mobile";
import { createNewPageWithWallet } from "@helpers/page";
import extractDRepFromWallet from "@helpers/shellyWallet";
import DRepDetailsPage from "@pages/dRepDetailsPage";
import DRepDirectoryPage from "@pages/dRepDirectoryPage";
import DRepRegistrationPage from "@pages/dRepRegistrationPage";
import { expect } from "@playwright/test";
import { LinkType } from "@types";
Expand All @@ -19,22 +14,7 @@ import walletManager from "lib/walletManager";
test.beforeEach(async () => {
await setAllureEpic("2. Delegation");
await skipIfNotHardFork();
});

test("2C. Should open wallet connection popup on delegate in disconnected state", async ({
page,
}) => {
await page.goto("/");
if (isMobile(page)) {
openDrawer(page);
}

await page.getByTestId("view-drep-directory-button").click();
await page.getByTestId("search-input").fill(dRep01Wallet.dRepId);
await page
.getByTestId(`${dRep01Wallet.dRepId}-connect-to-delegate-button`)
.click();
await expect(page.getByTestId("connect-your-wallet-modal")).toBeVisible();
await skipIfMainnet();
});

test("2N. Should show DRep information on details page", async ({
Expand Down Expand Up @@ -124,124 +104,3 @@ test("2N. Should show DRep information on details page", async ({
).toHaveText(link.url);
}
});

test("2P. Should enable sharing of DRep details", async ({ page, context }) => {
await context.grantPermissions(["clipboard-read", "clipboard-write"]);

const dRepDetailsPage = new DRepDetailsPage(page);
await dRepDetailsPage.goto(dRep01Wallet.dRepId);

await dRepDetailsPage.shareLink();
await expect(page.getByText("Copied to clipboard")).toBeVisible();

const copiedText = await page.evaluate(() => navigator.clipboard.readText());
expect(copiedText).toEqual(
`${environments.frontendUrl}/drep_directory/${dRep01Wallet.dRepId}`
);
});

test("2Q. Should include DRep status and voting power on the DRep card", async ({
page,
}) => {
const dRepDirectory = new DRepDirectoryPage(page);
await dRepDirectory.goto();

await dRepDirectory.searchInput.fill(dRep01Wallet.dRepId);
const dRepCard = dRepDirectory.getDRepCard(dRep01Wallet.dRepId);

await expect(
dRepCard.getByTestId(`${dRep01Wallet.dRepId}-voting-power`)
).toBeVisible();
await expect(
dRepCard.getByTestId(`${dRep01Wallet.dRepId}-Active-pill`)
).toBeVisible();
});

test.describe("Insufficient funds", () => {
test.use({ storageState: ".auth/user01.json", wallet: user01Wallet });

test("2T. Should show warning message on delegation when insufficient funds", async ({
page,
}) => {
const dRepDirectoryPage = new DRepDirectoryPage(page);
await dRepDirectoryPage.goto();

await dRepDirectoryPage.searchInput.fill(dRep01Wallet.dRepId);
const delegateBtn = page.getByTestId(
`${dRep01Wallet.dRepId}-delegate-button`
);
await expect(delegateBtn).toBeVisible();
await page.getByTestId(`${dRep01Wallet.dRepId}-delegate-button`).click();

await expect(dRepDirectoryPage.delegationErrorModal).toBeVisible({
timeout: 10_000,
});
});
});

test("2I. Should check validity of DRep Id", async ({ page }) => {
const dRepDirectory = new DRepDirectoryPage(page);
await dRepDirectory.goto();

await dRepDirectory.searchInput.fill(dRep01Wallet.dRepId);
await expect(dRepDirectory.getDRepCard(dRep01Wallet.dRepId)).toBeVisible();

const wallet = await ShelleyWallet.generate();
const invalidDRepId = extractDRepFromWallet(wallet);

await dRepDirectory.searchInput.fill(invalidDRepId);
await expect(dRepDirectory.getDRepCard(invalidDRepId)).not.toBeVisible();
});

test("2J. Should search by DRep id and DRep givenname", async ({ page }) => {
let dRepGivenName = "test";

await page.route(
"**/drep/list?page=0&pageSize=10&sort=Random",
async (route) => {
const response = await route.fetch();
const json = await response.json();
const elements = json["elements"].filter(
(element) => element["givenName"] != null
);
dRepGivenName =
elements[Math.floor(Math.random() * elements.length)]["givenName"];
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify(json),
});
}
);

const responsePromise = page.waitForResponse(
"**/drep/list?page=0&pageSize=10&sort=Random"
);

const dRepDirectory = new DRepDirectoryPage(page);
await dRepDirectory.goto();

await responsePromise;

// search by dRep Id
await dRepDirectory.searchInput.fill(dRep01Wallet.dRepId);
await expect(dRepDirectory.getDRepCard(dRep01Wallet.dRepId)).toBeVisible();

// search by dRep givenname
await dRepDirectory.searchInput.fill(dRepGivenName);
const searchDRepCards = await dRepDirectory.getAllListedDReps();

for (const dRepCard of searchDRepCards) {
expect((await dRepCard.innerText()).includes(dRepGivenName));
}
});

test("2M. Should access dRep directory page on disconnected state", async ({
page,
}) => {
const dRepDirectoryPage = new DRepDirectoryPage(page);
await dRepDirectoryPage.goto();

const dRepCards = await dRepDirectoryPage.getAllListedDReps();
expect(dRepCards.length).toBeGreaterThan(1);
});
Loading

0 comments on commit 88908ec

Please sign in to comment.