Skip to content

Commit

Permalink
chore: move e2e tests to a separate package
Browse files Browse the repository at this point in the history
- [x] Update synpress
- [x] Use module package for e2e tests
  • Loading branch information
0xmad committed Nov 7, 2024
1 parent 80bb50c commit 194789b
Show file tree
Hide file tree
Showing 22 changed files with 1,336 additions and 2,775 deletions.
5 changes: 2 additions & 3 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ typechain-types
commitlint.config.js
zkeys
packages/subgraph/generated
packages/interface/playwright/fixtures.ts
packages/interface/playwright.config.ts
packages/interface/playwright-report
packages/e2e/playwright.config.ts
packages/e2e/playwright-report
packages/interface/test-results
packages/interface/next.config.js
packages/interface/public/mockServiceWorker.js
Expand Down
33 changes: 25 additions & 8 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ jobs:
matrix:
node-version: [20]

timeout-minutes: 120
runs-on: ubuntu-22.04
timeout-minutes: 20
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
Expand All @@ -59,6 +59,7 @@ jobs:
~/.pnpm-store
node_modules
/home/runner/.cache/Cypress
packages/e2e/.cache-synpress
key: ${{ runner.os }}-node-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-node-
Expand All @@ -75,7 +76,12 @@ jobs:
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: |-
pnpm run install:chromium
working-directory: packages/interface
working-directory: packages/e2e

- name: Install linux dependencies
run: |
sudo apt-get install --no-install-recommends -y \
xvfb
- name: Copy .env.example to .env
run: |
Expand All @@ -85,16 +91,27 @@ jobs:
- name: Build
run: pnpm run build

- name: Run interface
run: pnpm run start &
working-directory: packages/interface

- name: Build cache
run: xvfb-run pnpm run build:cache
working-directory: packages/e2e

- name: Run Playwright tests
uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a
with:
run: pnpm run test:e2e
working-directory: packages/interface
run: xvfb-run pnpm run test:playwright:headful
working-directory: packages/e2e

- uses: actions/upload-artifact@v4
if: always()
continue-on-error: true
with:
name: playwright-report
path: ./playwright-report/
path: playwright-report
retention-days: 30
working-directory: packages/e2e

- name: Stop interface
if: always()
run: kill $(lsof -t -i:3000)
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"lerna": "^8.1.7",
"lint-staged": "^15.2.7",
"prettier": "^3.3.3",
"prettier-plugin-tailwindcss": "^0.5.14",
"solhint": "^5.0.3",
"typescript": "^5.5.4"
},
Expand Down
43 changes: 43 additions & 0 deletions packages/e2e/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const path = require("path");

module.exports = {
root: true,
env: {
node: true,
jest: true,
},
extends: ["../../.eslintrc.js", "plugin:playwright/playwright-test"],
parser: "@typescript-eslint/parser",
parserOptions: {
project: path.resolve(__dirname, "./tsconfig.json"),
sourceType: "module",
typescript: true,
ecmaVersion: 2022,
experimentalDecorators: true,
requireConfigFile: false,
ecmaFeatures: {
classes: true,
impliedStrict: true,
},
warnOnUnsupportedTypeScriptVersion: true,
},
overrides: [
{
files: ["./test/*.ts"],
rules: {
"playwright/prefer-lowercase-title": "error",
"playwright/prefer-to-be": "error",
"playwright/prefer-to-have-length": "error",
"playwright/prefer-strict-equal": "error",
"playwright/max-nested-describe": ["error", { max: 1 }],
"playwright/no-restricted-matchers": [
"error",
{
toBeFalsy: "Use `toBe(false)` instead.",
not: null,
},
],
},
},
],
};
1 change: 1 addition & 0 deletions packages/e2e/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.cache-synpress
27 changes: 27 additions & 0 deletions packages/e2e/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "maci-platform-interface-e2e",
"version": "0.0.1",
"private": true,
"type": "module",
"scripts": {
"build:cache": "synpress",
"build:cache:force": "synpress --force",
"build:cache:headless": "synpress --headless",
"types": "tsc -p tsconfig.json --noEmit",
"install:chromium": "playwright install chromium",
"test:playwright:headful": "playwright test",
"test:playwright:headless": "HEADLESS=true playwright test",
"test:playwright:headless:ui": "HEADLESS=true playwright test --ui"
},
"dependencies": {
"@playwright/test": "^1.48.2",
"@synthetixio/synpress": "^4.0.3",
"dotenv": "^16.4.5"
},
"devDependencies": {
"@synthetixio/synpress-tsconfig": "^0.0.4",
"eslint-plugin-playwright": "^2.0.1",
"@types/node": "^22.9.0",
"typescript": "^5.6.3"
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { defineConfig, devices } from "@playwright/test";
import dotenv from "dotenv";
import path from "path";

dotenv.config();

/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./e2e",
testDir: "./test",
timeout: process.env.CI ? 120_000 : 60_000,
expect: {
timeout: 15_000,
Expand All @@ -22,7 +23,6 @@ export default defineConfig({
baseURL: process.env.DEMO_URL || "http://localhost:3000",
trace: "on-first-retry",
screenshot: "only-on-failure",
headless: false,
},

projects: [
Expand All @@ -35,6 +35,7 @@ export default defineConfig({
? [
{
command: "pnpm run start",
cwd: path.resolve("../interface"),
url: "http://localhost:3000",
timeout: 120 * 1000,
reuseExistingServer: !process.env.CI,
Expand Down
33 changes: 33 additions & 0 deletions packages/e2e/test/connectWallet.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Import necessary Synpress modules and setup
import { testWithSynpress } from "@synthetixio/synpress";
import { MetaMask, metaMaskFixtures } from "@synthetixio/synpress/playwright";

import basicSetup from "./wallet-setup/basic.setup";

// Create a test instance with Synpress and BasicSetup
const test = testWithSynpress(metaMaskFixtures(basicSetup));

// Extract expect function from test
const { expect } = test;

// Define a basic test case
test("should connect wallet properly", async ({ context, page, extensionId }) => {
// Create a new MetaMask instance
const metamask = new MetaMask(context, page, basicSetup.walletPassword, extensionId);

// Navigate to the homepage
await page.goto("/");

// Click the connect button
await page.getByRole("button", { name: "Connect wallet" }).first().click();
await page.getByTestId("rk-wallet-option-io.metamask").click();

// Connect MetaMask to the dapp
await metamask.connectToDapp();
await metamask.confirmSignature();
await metamask.approveNewNetwork();
await metamask.approveSwitchNetwork();

// Verify the connected account address
await expect(page.getByText(/0xf3.+2266/)).toBeInViewport({ timeout: 20000 });
});
17 changes: 17 additions & 0 deletions packages/e2e/test/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import dotenv from "dotenv";

dotenv.config();

export const NETWORKS = {
optimismSepolia: {
chainId: 11155420,
name: "OP Sepolia",
rpcUrl: `https://opt-sepolia.g.alchemy.com/v2/${process.env.NEXT_PUBLIC_ALCHEMY_ID!}`,
symbol: "ETH",
},
};

// Define a test seed phrase and password
// Don't use it for production, only for e2e testing
export const SEED_PHRASE = process.env.TEST_MNEMONIC || "test test test test test test test test test test test junk";
export const PASSWORD = process.env.WALLET_PASSWORD || "Tester@1234";
13 changes: 13 additions & 0 deletions packages/e2e/test/wallet-setup/basic.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineWalletSetup } from "@synthetixio/synpress";
import { MetaMask } from "@synthetixio/synpress/playwright";

import { PASSWORD, SEED_PHRASE } from "../constants";

// Define the basic wallet setup
export default defineWalletSetup(PASSWORD, async (context, walletPage) => {
// Create a new MetaMask instance
const metamask = new MetaMask(context, walletPage, PASSWORD);

// Import the wallet using the seed phrase
await metamask.importWallet(SEED_PHRASE);
});
28 changes: 28 additions & 0 deletions packages/e2e/test/wallet-setup/connected.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { defineWalletSetup } from "@synthetixio/synpress";
import { MetaMask, getExtensionId } from "@synthetixio/synpress/playwright";
import "dotenv/config";

import { PASSWORD, SEED_PHRASE } from "../constants";

export default defineWalletSetup(PASSWORD, async (context, walletPage) => {
// This is a workaround for the fact that the MetaMask extension ID changes.
// This workaround won't be needed in the near future! 😁
const extensionId = await getExtensionId(context, "MetaMask");

const metamask = new MetaMask(context, walletPage, PASSWORD, extensionId);

await metamask.importWallet(SEED_PHRASE);

const page = await context.newPage();

// Go to a locally hosted MetaMask Test Dapp.
await page.goto(process.env.DEMO_URL || "http://localhost:3000");

await page.getByRole("button", { name: "Connect wallet" }).first().click();
await page.getByTestId("rk-wallet-option-io.metamask").click();

await metamask.connectToDapp(["Account 1"]);
await metamask.confirmSignature();
await metamask.approveNewNetwork();
await metamask.approveSwitchNetwork();
});
9 changes: 9 additions & 0 deletions packages/e2e/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "@synthetixio/synpress-tsconfig/base.json",
"compilerOptions": {
"rootDir": ".",
"esModuleInterop": true,
"sourceMap": false
},
"include": ["test"]
}
20 changes: 3 additions & 17 deletions packages/interface/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const isProduction = process.env.NODE_ENV === "production";

module.exports = {
root: true,
extends: ["../../.eslintrc.js", "plugin:react/recommended", "plugin:playwright/playwright-test"],
extends: ["../../.eslintrc.js", "plugin:react/recommended"],
plugins: ["json", "prettier", "unused-imports", "import", "@typescript-eslint", "react-hooks"],
parser: "@typescript-eslint/parser",
env: {
Expand All @@ -26,7 +26,7 @@ module.exports = {
},
node: {
extensions: [".ts", ".js", ".tsx", ".jsx"],
moduleDirectory: ["node_modules", "src", "playwright"],
moduleDirectory: ["node_modules", "src"],
},
},
},
Expand All @@ -52,10 +52,9 @@ module.exports = {
{
devDependencies: [
"**/*.test.ts",
"**/*.setup.ts",
"./src/test-setup.ts",
"./src/lib/eas/*.ts",
"./playwright/**/*.ts",
"./playwright.config.ts",
"./vitest.config.ts",
],
},
Expand Down Expand Up @@ -167,18 +166,5 @@ module.exports = {
],
"react/no-unused-prop-types": "error",
"react/function-component-definition": ["error", { namedComponents: ["arrow-function"] }],

"playwright/prefer-lowercase-title": "error",
"playwright/prefer-to-be": "error",
"playwright/prefer-to-have-length": "error",
"playwright/prefer-strict-equal": "error",
"playwright/max-nested-describe": ["error", { max: 1 }],
"playwright/no-restricted-matchers": [
"error",
{
toBeFalsy: "Use `toBe(false)` instead.",
not: null,
},
],
},
};
4 changes: 0 additions & 4 deletions packages/interface/.npmrc

This file was deleted.

32 changes: 0 additions & 32 deletions packages/interface/e2e/connectWallet.test.ts

This file was deleted.

Loading

0 comments on commit 194789b

Please sign in to comment.