diff --git a/packages/frontend/e2e/tests/connect-wallet.test.ts b/packages/frontend/e2e/tests/connect-wallet.test.ts index e6c7b3bb5..16e0100d5 100644 --- a/packages/frontend/e2e/tests/connect-wallet.test.ts +++ b/packages/frontend/e2e/tests/connect-wallet.test.ts @@ -1,34 +1,15 @@ -import { test, expect } from "../utils/fixtures"; -import { acceptAccess } from "@synthetixio/synpress/commands/metamask"; +import { test } from "../utils/fixtures"; +/** + *@description Basic connect wallet on Polygon Mumbai network -test.beforeEach(async ({ page }) => { - await page.goto("/"); +test.beforeEach(async ({ homePage }) => { + await homePage.goToHomePage(); }); - -test("connect with metamask", async ({ page }) => { - await test.step("select network drop down", async () => { - await page.locator("div").getByText("Network").nth(2).click(); - }); - - await test.step("click sepolia network", async () => { - await page.getByTestId("Sepolia-network-button").nth(1).click(); - }); - - await test.step("click connect wallet", async () => { - await page.getByTestId("connect-wallet-button").nth(1).click(); - }); - - await test.step("click metamask", async () => { - await page.getByTestId("metaMask-wallet-button").nth(1).click(); - }); - +test("connect with metamask", async ({ homePage }) => { await test.step("connect to metamask", async () => { - await acceptAccess(); + await homePage.connectWallet(); }); - await test.step("verify wallet is connected", async () => { - await expect( - page.getByTestId("profile-avatar-button").nth(1), - ).toBeVisible(); + await homePage.profileIconVisible(); }); }); diff --git a/packages/frontend/e2e/tests/create-campaign.test.ts b/packages/frontend/e2e/tests/create-campaign.test.ts new file mode 100644 index 000000000..19b79e701 --- /dev/null +++ b/packages/frontend/e2e/tests/create-campaign.test.ts @@ -0,0 +1,73 @@ +import { test } from "../utils/fixtures"; +import { campaignData } from "../utils/data"; +/** + *@description Create campaign test + */ + +test.beforeEach(async ({ homePage }) => { + await test.step("Navigate to Carrot Home page", async () => { + await homePage.goToHomePage(); + }); +}); +test("Create campaign", async ({ homePage, createCampaign, campaignPage }) => { + await test.step("Connect to Metamask", async () => { + await homePage.connectWallet(); + }); + await test.step("Verify wallet is connected", async () => { + await homePage.profileIconVisible(); + }); + await test.step("Click create campaign button", async () => { + await homePage.clickCreateCampaign(); + }); + await test.step("Check text on autorization modal", async () => { + await createCampaign.checkAuthenticateModalText(); + }); + await test.step("Click Sign on authorization modal", async () => { + await createCampaign.clickSign(); + }); + await test.step("Sign on Metamask notification", async () => { + await createCampaign.confirmSignatureOnMetamask(); + }); + // General step + await test.step("Enter general data", async () => { + await createCampaign.enterGeneralData(); + }); + await test.step("Click next on General step", async () => { + await createCampaign.clickNextOnStep("general"); + }); + // Rewards step + await test.step("Enter rewards data", async () => { + await createCampaign.enterRewardsData(); + }); + await test.step("Click Add to campaign", async () => { + await createCampaign.clickAddToCampaign(); + }); + await test.step("Click next on Rewards step", async () => { + await createCampaign.clickNextOnStep("rewards"); + }); + // Oracle step + await test.step("Enter oracle data", async () => { + await createCampaign.enterOracleData(); + }); + await test.step("Click next on Oracle step", async () => { + await createCampaign.clickNextOnStep("oracle"); + }); + await test.step("Click Approve selected token", async () => { + await createCampaign.clickApprove(); + }); + await test.step("Approve token on Metamask", async () => { + await createCampaign.approveTokenOnMetamask(); + }); + // Deploy step + await test.step("Click deploy your campaign", async () => { + await createCampaign.clickDeployYourCampaign(); + await homePage.pauseInSec(10); + }); + await test.step("Click go to campaign", async () => { + await createCampaign.clickGoToCampaign(); + await homePage.pauseInSec(10); + }); + await test.step("Assert new campaign title", async () => { + await campaignPage.checkCampaignTitle(campaignData.title); + }); +}); diff --git a/packages/frontend/e2e/utils/data.ts b/packages/frontend/e2e/utils/data.ts index 7d47c491a..2d398d931 100644 --- a/packages/frontend/e2e/utils/data.ts +++ b/packages/frontend/e2e/utils/data.ts @@ -1,3 +1,4 @@ +import { faker } from "@faker-js/faker"; /** * @exports different data used in tests */ @@ -37,9 +38,21 @@ export const textData = { footerCommunity: "Community", walletDisconnected: "Wallet disconnected", walletRequiredDescription: "A connected wallet is required to continue.", + welcomeToCarrot: "Welcome to Carrot", + authenticateDescription: + "In order to create campaigns it's necessary to sign a message. This request will not trigger a blockchain transaction or cost you any fees.", }; export const campaignData = { firstCampaign: "TS01 NOV13", + title: "Automatino Test Campaign", + description: faker.lorem.words(10), + tag: "Automation", + expiryDate: "", + tokenName: "Automation testing", + tokenSymbol: "ATST", + tokenSupply: "100", + rewardAmount: "100", + goalValue: "18", }; export const templateData = { erc20Title: "ERC20 KPI token", diff --git a/packages/frontend/e2e/utils/fixtures.ts b/packages/frontend/e2e/utils/fixtures.ts index 417dffc20..acdbd744e 100644 --- a/packages/frontend/e2e/utils/fixtures.ts +++ b/packages/frontend/e2e/utils/fixtures.ts @@ -3,7 +3,10 @@ import { initialSetup } from "@synthetixio/synpress/commands/metamask"; import { setExpectInstance } from "@synthetixio/synpress/commands/playwright"; import { resetState } from "@synthetixio/synpress/commands/synpress"; import { prepareMetamask } from "@synthetixio/synpress/helpers"; +// Page instances import { HomePage } from "../utils/pages/homePage"; +import { CreateCampaign } from "./pages/createCampaignPage"; +import { CampaignPage } from "./pages/campaignPage"; /** * @exports context fixture which sets up Metamask extension before test start @@ -12,10 +15,9 @@ import { HomePage } from "../utils/pages/homePage"; export const test = base.extend<{ context: BrowserContext; homePage: HomePage; + createCampaign: CreateCampaign; + campaignPage: CampaignPage; }>({ - homePage: async ({ page }, use) => { - await use(new HomePage(page)); - }, context: async ({}, use) => { // required for synpress as it shares same expect instance as playwright await setExpectInstance(expect); @@ -39,6 +41,7 @@ export const test = base.extend<{ const context = await chromium.launchPersistentContext("", { headless: false, args: browserArgs, + viewport: { width: 1920, height: 1080 }, }); // wait for metamask @@ -48,7 +51,7 @@ export const test = base.extend<{ await initialSetup(chromium, { secretWordsOrPrivateKey: "test test test test test test test test test test test junk", - network: "sepolia", + network: "Polygon Mumbai", password: "Tester@1234", enableAdvancedSettings: true, }); @@ -59,6 +62,15 @@ export const test = base.extend<{ await resetState(); }, + homePage: async ({ page }, use) => { + await use(new HomePage(page)); + }, + createCampaign: async ({ page }, use) => { + await use(new CreateCampaign(page)); + }, + campaignPage: async ({ page }, use) => { + await use(new CampaignPage(page)); + }, }); export const expect = test.expect; diff --git a/packages/frontend/e2e/utils/pages/basePage.ts b/packages/frontend/e2e/utils/pages/basePage.ts index 30cfa1c84..595b10467 100644 --- a/packages/frontend/e2e/utils/pages/basePage.ts +++ b/packages/frontend/e2e/utils/pages/basePage.ts @@ -41,8 +41,8 @@ export class BasePage { async hoverElement(selector: string) { await this.page.getByTestId(selector).hover(); } - async isVisible(selector: string) { - await expect(this.page.getByTestId(selector)).toBeVisible(); + async isVisible(selector: string, index: number) { + await expect(this.page.getByTestId(selector).nth(index)).toBeVisible(); } async isNotVisible(selector: string) { await expect(this.page.getByTestId(selector)).not.toBeVisible(); diff --git a/packages/frontend/e2e/utils/pages/campaignPage.ts b/packages/frontend/e2e/utils/pages/campaignPage.ts new file mode 100644 index 000000000..e62198b72 --- /dev/null +++ b/packages/frontend/e2e/utils/pages/campaignPage.ts @@ -0,0 +1,13 @@ +import { BasePage } from "./basePage"; +/** + * @exports Selectors and Methods for single Campaign page + */ + +export class CampaignPage extends BasePage { + //---Selectors + campaignTitle_Text = ""; + //---Methods + async checkCampaignTitle(title: string) { + await this.compareText(this.campaignTitle_Text, title, 0); + } +} diff --git a/packages/frontend/e2e/utils/pages/createCampaignPage.ts b/packages/frontend/e2e/utils/pages/createCampaignPage.ts new file mode 100644 index 000000000..6f32efb6d --- /dev/null +++ b/packages/frontend/e2e/utils/pages/createCampaignPage.ts @@ -0,0 +1,173 @@ +import { BasePage } from "./basePage"; +import { + confirmSignatureRequest, + confirmPermissionToApproveAll, +} from "@synthetixio/synpress/commands/metamask"; +import { campaignData, textData } from "../data"; +/** + * @exports Selectors and Methods for create Campaign stepper + */ + +export class CreateCampaign extends BasePage { + //---Selectors + welcomeToCarrot_Text = "welcome-to-carrot-title-text"; + createCampaignAuthParagraph_Text = "authenticate-description-text"; + cancel_Button = "authenticate-cancel-button"; + signMessage_Button = "authenticate-sign-button"; + campaingTitle_Field = "generic-data-step-title-input"; + campaignDescription_Field = "#:rt:"; + campaignTags_Field = "generic-data-step-tags-input"; + addTag_Button = + "#carrot-template-26833f329b2f1da18c9ce2a9c000ee9c button > div"; + generalNext_Button = "generic-data-step-next-button"; + tokenName_Field = "rewards-step-token-name-input"; + tokenSymbol_Field = "rewards-step-token-symbol-input"; + tokenSupply_Field = "rewards-step-token-supply-input"; + rewardPicker_Button = "rewards-step-open-rewards-picker-button"; + manageList_Button = ""; + carrotLabsDefault_Button = ""; + aaaToken_Button = ""; + tokenSearch_Field = "#token-search"; + rewardAmount_Field = "rewards-step-reward-amount-input"; + minimumPayout_Switch = "rewards-step-minimum-payout-switch"; + addToCampaign_Button = "rewards-step-add-reward-button"; + rewardsNext_Button = "rewards-step-next-button"; + metricDropdown_Button = "creation-form-metric-select-input"; + totalValueLocked_Option = ""; + expirationDate_Field = "creation-form-measurement-date-input"; + protocolDropdown_Button = "payload-form-protocol-select-input"; + lido_Option = ""; + greaterThan_Button = "creation-form-constraint-3"; + goalValue_Field = "single-value-form-value0-input"; + oracleNext_Button = "oracles-configuration-step-next-button"; + approve_Button = "approve-reward"; + deployYourCampaign_Button = "deploy-step-create-button"; + goToCampaign_Button = ""; + //---Methods + async checkAuthenticateModalText() { + await this.compareText( + this.welcomeToCarrot_Text, + textData.welcomeToCarrot, + 0, + ); + await this.compareText( + this.createCampaignAuthParagraph_Text, + textData.authenticateDescription, + 0, + ); + } + async confirmSignatureOnMetamask() { + await confirmSignatureRequest(); + } + async approveTokenOnMetamask() { + await confirmPermissionToApproveAll(); + } + // Clicks + async clickSign() { + await this.click(this.signMessage_Button); + } + async clickNextOnStep(step: string) { + switch (step) { + case "general": + this.click(this.generalNext_Button); + break; + case "rewards": + this.click(this.rewardsNext_Button); + break; + case "oracle": + this.click(this.generalNext_Button); + break; + case "deploy": + this.click(this.generalNext_Button); + break; + } + } + async clickAddToCampaign() { + await this.click(this.addToCampaign_Button); + } + async clickApprove() { + await this.click(this.approve_Button); + } + async clickDeployYourCampaign() { + await this.click(this.deployYourCampaign_Button); + } + async clickGoToCampaign() { + await this.click(this.goToCampaign_Button); + } + // General step + async enterTitle() { + await this.enterText(this.campaingTitle_Field, campaignData.title); + } + async enterDescription() { + await this.enterText( + this.campaignDescription_Field, + campaignData.description, + ); + } + async enterTag() { + await this.enterText(this.campaignTags_Field, campaignData.description); + await this.clickFirst(this.addTag_Button); + } + async enterExpiryDate() { + await this.click(this.expirationDate_Field); + // todo: figure out how to enter date + } + async enterGeneralData() { + await this.enterTitle(); + await this.enterDescription(); + await this.enterTag(); + } + // Rewards step + async enterTokenName() { + await this.enterText(this.tokenName_Field, campaignData.tokenName); + } + async enterTokenSymbol() { + await this.enterText(this.tokenSymbol_Field, campaignData.tokenSymbol); + } + async enterTokenSupply() { + await this.enterText(this.tokenSupply_Field, campaignData.tokenSupply); + } + // ATM carrot labs default; todo: improve to be able to select any token + async pickRewardToken() { + await this.click(this.rewardPicker_Button); + await this.click(this.manageList_Button); + await this.click(this.carrotLabsDefault_Button); + await this.click(this.aaaToken_Button); + } + async enterRewardAmount() { + await this.enterText( + this.rewardAmount_Field, + campaignData.rewardAmount, + ); + } + async enterRewardsData() { + await this.enterTokenName(); + await this.enterTokenSymbol(); + await this.enterTokenSupply(); + await this.pickRewardToken(); + await this.enterRewardAmount(); + } + // Oracle step + async selectTotalValueLockedMetric() { + await this.click(this.metricDropdown_Button); + await this.click(this.totalValueLocked_Option); + } + async selectProtocol() { + await this.click(this.protocolDropdown_Button); + await this.click(this.lido_Option); + } + // todo: improve to be able to select any goal + async selectGoal() { + await this.click(this.greaterThan_Button); + } + async enterGoalValue() { + await this.enterText(this.goalValue_Field, campaignData.goalValue); + } + async enterOracleData() { + await this.selectTotalValueLockedMetric(); + await this.enterExpiryDate(); + await this.selectProtocol(); + await this.selectGoal(); + await this.enterGoalValue(); + } +} diff --git a/packages/frontend/e2e/utils/pages/homePage.ts b/packages/frontend/e2e/utils/pages/homePage.ts index 3bbf15609..d2c649919 100644 --- a/packages/frontend/e2e/utils/pages/homePage.ts +++ b/packages/frontend/e2e/utils/pages/homePage.ts @@ -1,4 +1,5 @@ -import { BasePage } from "../pages/basePage"; +import { BasePage } from "./basePage"; +import { acceptAccess } from "@synthetixio/synpress/commands/metamask"; import { campaignData, urls, @@ -53,6 +54,7 @@ export class HomePage extends BasePage { footerDiscrod_Link = "footer-Discord-button"; footerTwitter_Link = "footer-Twitter-button"; footerCarrotInfoPage_Button = "footer-carrot-info-page-button"; + profileAvatar_Button = "profile-avatar-button"; // selectors on campaign page walletDisconnected_Text = "wallet-disconnected-text"; walletRequiredDescription_Text = "connect-wallet-required-text"; @@ -63,13 +65,6 @@ export class HomePage extends BasePage { async goBack() { await this.page.goBack(); } - async checkStagingBanner() { - await this.compareText( - this.stagingBanner_Text, - textData.stagingBannerText, - 0, - ); - } //---Clicks async clickAbout() { await this.click(this.about_Button); @@ -83,6 +78,9 @@ export class HomePage extends BasePage { async clickConnectWallet() { await this.clickSecond(this.connectWallet_Button); } + async clickMetamask() { + await this.clickSecond(this.metamask_Button); + } async clickSettings() { await this.click(this.settings_Button); } @@ -96,6 +94,13 @@ export class HomePage extends BasePage { await this.click(this.viewAllCampaigns_Button); } //--- Header assertions + async checkStagingBanner() { + await this.compareText( + this.stagingBanner_Text, + textData.stagingBannerText, + 0, + ); + } async checkAboutButtonRedirection() { await this.checkRedirectionToNewTab( this.about_Button, @@ -224,7 +229,7 @@ export class HomePage extends BasePage { } async checkHowItWorksPreview() { await this.clickHowItWorks(); - await this.isVisible(this.howItWorksVideo_Preview); + await this.isVisible(this.howItWorksVideo_Preview, 0); await this.clickAnyWhereToClose(); } // todo: this method should be on create campaign page @@ -292,4 +297,13 @@ export class HomePage extends BasePage { urls.carrotInfoPage, ); } + async profileIconVisible() { + await this.isVisible(this.profileAvatar_Button, 1); + } + //---Connect wallet + async connectWallet() { + await this.clickConnectWallet(); + await this.clickMetamask(); + await acceptAccess(); + } } diff --git a/packages/frontend/package.json b/packages/frontend/package.json index d59d8746f..8d90899aa 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -35,7 +35,8 @@ "config-react-env": "./scripts/config-react-env.js", "start:staging": "STAGING=true craco start", "start": "craco start", - "test:e2e": "yarn prepare-fathom && yarn playwright test" + "test:e2e": "yarn prepare-fathom && yarn playwright test", + "test:create-campaign": "yarn playwright test packages/frontend/e2e/tests/create-campaign.test.ts" }, "dependencies": { "@carrot-kpi/react": "*", @@ -69,6 +70,7 @@ "@commitlint/cli": "^18.4.1", "@commitlint/config-conventional": "^18.4.0", "@craco/craco": "^7.1.0", + "@faker-js/faker": "^8.3.1", "@fontsource/ibm-plex-mono": "^5.0.3", "@playwright/test": "^1.39.0", "@react-spring/web": "^9.7.3", diff --git a/packages/frontend/src/components/authenticate.tsx b/packages/frontend/src/components/authenticate.tsx index 29a2f81f5..284adcf2e 100644 --- a/packages/frontend/src/components/authenticate.tsx +++ b/packages/frontend/src/components/authenticate.tsx @@ -81,6 +81,7 @@ export const Authenticate = ({ onCancel }: AuthenticateProps) => { <> { {t("authenticate.title")} {