From 69a445a66403e0ac68069f12d63179ab0c777486 Mon Sep 17 00:00:00 2001 From: Federico Luzzi Date: Tue, 7 Nov 2023 12:55:41 +0000 Subject: [PATCH] feat(frontend): add e2e tests setup with playwright and synpress (#502) * feat(frontend): add e2e tests setup with playwright and synpress * chore(frontend): prepare fathom code before starting frontend in dev mode * chore: install playwright browsers in gh actions environment * chore: trigger ci * chore: prepare fathom before executing playwright * chore: fix test:e2e script * fix(frontend): fix playwright command * chore(frontend): increase timeout for web server start * chore: remove playwright tests from ci gh action --------- Co-authored-by: luzzifoss --- .gitignore | 12 +- package.json | 1 + packages/frontend/CONTRIBUTING.md | 13 + packages/frontend/e2e/fixtures.ts | 55 + .../frontend/e2e/tests/connect-wallet.test.ts | 34 + packages/frontend/e2e/tests/home-page.test.ts | 23 + packages/frontend/package.json | 4 +- packages/frontend/playwright.config.ts | 39 + .../src/components/connect-wallet/index.tsx | 2 + .../connect-wallet/popovers/account/index.tsx | 3 + .../connect-wallet/popovers/connect.tsx | 1 + .../connect-wallet/popovers/networks.tsx | 1 + turbo.json | 10 +- yarn.lock | 1902 ++++++++++++++++- 14 files changed, 2018 insertions(+), 82 deletions(-) create mode 100644 packages/frontend/e2e/fixtures.ts create mode 100644 packages/frontend/e2e/tests/connect-wallet.test.ts create mode 100644 packages/frontend/e2e/tests/home-page.test.ts create mode 100644 packages/frontend/playwright.config.ts diff --git a/.gitignore b/.gitignore index ef3bb62bb..2f7241830 100644 --- a/.gitignore +++ b/.gitignore @@ -180,4 +180,14 @@ target/ packages/ipfs-pinner/src/contracts -packages/subgraph/src/gen \ No newline at end of file +packages/subgraph/src/gen + +# Test results & reposts +test-results/ +playwright-report/ + +# Cache +playwright/.cache/ + +# Metamask +metamask-* \ No newline at end of file diff --git a/package.json b/package.json index d1b23040c..9726e5b78 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "format": "turbo run format", "start": "turbo run start", "test": "turbo run test", + "test:e2e": "turbo run test:e2e --filter @carrot-kpi/host-frontend", "size-limit": "turbo run size-limit", "commitlint": "commitlint -e", "prepare": "husky install" diff --git a/packages/frontend/CONTRIBUTING.md b/packages/frontend/CONTRIBUTING.md index cf15801af..8fd428778 100644 --- a/packages/frontend/CONTRIBUTING.md +++ b/packages/frontend/CONTRIBUTING.md @@ -189,3 +189,16 @@ following: augmented `global` namespace. 4. Update the `turbo.json` file at the root of the monorepo to add the env to the `globalEnv` key. + +## Running end to end tests + +End to end tests are executed using Playwright and Synpress. In order to execute +them locally, start by setting all the required envs that are needed to build +and run the frontend as described in the sections above, and after having done +that simply run the following command from the root of the monorepo (running +from the root of the monorepo ensures the latest monorepo linked packages are +used). + +``` +yarn test:e2e +``` diff --git a/packages/frontend/e2e/fixtures.ts b/packages/frontend/e2e/fixtures.ts new file mode 100644 index 000000000..3100e3221 --- /dev/null +++ b/packages/frontend/e2e/fixtures.ts @@ -0,0 +1,55 @@ +import { test as base, chromium, type BrowserContext } from "@playwright/test"; +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"; + +export const test = base.extend<{ + context: BrowserContext; +}>({ + context: async ({}, use) => { + // required for synpress as it shares same expect instance as playwright + await setExpectInstance(expect); + + // download metamask + const metamaskPath = await prepareMetamask( + process.env.METAMASK_VERSION || "10.25.0", + ); + + // prepare browser args + const browserArgs = [ + `--disable-extensions-except=${metamaskPath}`, + `--load-extension=${metamaskPath}`, + "--remote-debugging-port=9222", + ]; + + if (process.env.CI) browserArgs.push("--disable-gpu"); + if (process.env.HEADLESS_MODE) browserArgs.push("--headless=new"); + + // launch browser + const context = await chromium.launchPersistentContext("", { + headless: false, + args: browserArgs, + }); + + // wait for metamask + await context.pages()[0].waitForTimeout(3000); + + // setup metamask + await initialSetup(chromium, { + secretWordsOrPrivateKey: + "test test test test test test test test test test test junk", + network: "sepolia", + password: "Tester@1234", + enableAdvancedSettings: true, + }); + + await use(context); + + await context.close(); + + await resetState(); + }, +}); + +export const expect = test.expect; diff --git a/packages/frontend/e2e/tests/connect-wallet.test.ts b/packages/frontend/e2e/tests/connect-wallet.test.ts new file mode 100644 index 000000000..98f6af0d4 --- /dev/null +++ b/packages/frontend/e2e/tests/connect-wallet.test.ts @@ -0,0 +1,34 @@ +import { test, expect } from "../fixtures"; +import { acceptAccess } from "@synthetixio/synpress/commands/metamask"; + +test.beforeEach(async ({ page }) => { + await page.goto("/"); +}); + +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(); + }); + + await test.step("connect to metamask", async () => { + await acceptAccess(); + }); + + await test.step("verify wallet is connected", async () => { + await expect( + page.getByTestId("profile-avatar-button").nth(1), + ).toBeVisible(); + }); +}); diff --git a/packages/frontend/e2e/tests/home-page.test.ts b/packages/frontend/e2e/tests/home-page.test.ts new file mode 100644 index 000000000..48ff64573 --- /dev/null +++ b/packages/frontend/e2e/tests/home-page.test.ts @@ -0,0 +1,23 @@ +import { test } from "../fixtures"; + +test("home page", async ({ page }) => { + await test.step("navigate to home page", async () => { + await page.goto("/"); + }); + + await test.step("about visible", async () => { + await page.locator("div").getByText("About`").nth(1).isVisible(); + }); + + await test.step("campaigns visible", async () => { + await page.locator("div").getByText("Campaign").nth(1).isVisible(); + }); + + await test.step("connect wallet button visible", async () => { + await page + .locator("div") + .getByText("Connect wallet") + .nth(1) + .isVisible(); + }); +}); diff --git a/packages/frontend/package.json b/packages/frontend/package.json index e78b37008..37caea3e8 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -34,7 +34,8 @@ "prepare-fathom": "prepare-fathom", "config-react-env": "./scripts/config-react-env.js", "start:staging": "STAGING=true craco start", - "start": "craco start" + "start": "craco start", + "test:e2e": "yarn prepare-fathom && playwright test" }, "dependencies": { "@carrot-kpi/react": "*", @@ -68,6 +69,7 @@ "@commitlint/config-conventional": "^18.1.0", "@craco/craco": "^7.1.0", "@fontsource/ibm-plex-mono": "^5.0.3", + "@playwright/test": "^1.39.0", "@react-spring/web": "^9.7.3", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-image": "^3.0.3", diff --git a/packages/frontend/playwright.config.ts b/packages/frontend/playwright.config.ts new file mode 100644 index 000000000..86bd7e70a --- /dev/null +++ b/packages/frontend/playwright.config.ts @@ -0,0 +1,39 @@ +import { defineConfig, devices } from "@playwright/test"; + +export default defineConfig({ + timeout: 60_000, + testDir: "./e2e", + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : 1, + reporter: process.env.CI ? "dot" : "list", + use: { + headless: false, + baseURL: "http://localhost:3000/#/?chain=scroll+sepolia", + trace: "on-first-retry", + }, + projects: [ + { + name: "chromium", + use: { + ...devices["Desktop Chrome"], + viewport: { width: 1920, height: 1080 }, + }, + }, + { + name: "firefox", + use: { ...devices["Desktop Firefox"] }, + }, + { + name: "webkit", + use: { ...devices["Desktop Safari"] }, + }, + ], + webServer: { + command: "yarn start:staging", + timeout: 120 * 1_000, + url: "http://127.0.0.1:3000", + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/packages/frontend/src/components/connect-wallet/index.tsx b/packages/frontend/src/components/connect-wallet/index.tsx index bf526cebf..2eec19c9c 100644 --- a/packages/frontend/src/components/connect-wallet/index.tsx +++ b/packages/frontend/src/components/connect-wallet/index.tsx @@ -170,6 +170,7 @@ export const ConnectWallet = ({ )} {address ? (