From 78ae80339bb798ff470fd99efaec350d8df2c6aa Mon Sep 17 00:00:00 2001 From: Nelito Junior Date: Thu, 5 Dec 2024 16:59:48 -0300 Subject: [PATCH] test(e2e): Fullset Solana tests FE-446 (#436) --- .github/workflows/pr-tests.yml | 24 +++--- e2e-tests/react-next/.env.example | 4 +- e2e-tests/react-next/src/app/page.tsx | 4 - e2e-tests/runner/.env.example | 13 +-- e2e-tests/runner/README.md | 83 +++++++++++++++++++ .../SolanaConnector/SolanaConnector.test.ts | 82 ++++++++++++------ .../SolanaConnector/phantom/phantom.ts | 7 ++ .../SolanaConnector/phantom/setup.ts | 4 +- .../WalletConnectConnector.test.ts | 1 - e2e-tests/runner/fuels.config.ts | 7 +- e2e-tests/runner/package.json | 2 +- e2e-tests/runner/playwright.config.ts | 2 +- examples/react-app/.env.example | 9 +- examples/react-next/.env.example | 4 +- packages/evm-predicates/.env.example | 2 + packages/evm-predicates/fuels.config.ts | 9 +- packages/evm-predicates/package.json | 1 + packages/solana-connector/.env.example | 2 + packages/solana-connector/fuels.config.ts | 10 ++- packages/solana-connector/package.json | 1 + pnpm-lock.yaml | 6 ++ 21 files changed, 208 insertions(+), 69 deletions(-) create mode 100644 e2e-tests/runner/README.md create mode 100644 e2e-tests/runner/examples/connectors/SolanaConnector/phantom/phantom.ts create mode 100644 packages/evm-predicates/.env.example create mode 100644 packages/solana-connector/.env.example diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml index c06918b4..9ccbdb6c 100644 --- a/.github/workflows/pr-tests.yml +++ b/.github/workflows/pr-tests.yml @@ -102,6 +102,15 @@ jobs: id: pnpm-cache run: pnpm install --frozen-lockfile + - name: Copy .env file for E2E Tests + run: cp e2e-tests/runner/.env.example e2e-tests/runner/.env + + - name: Copy .env file for React Next + run: cp e2e-tests/react-next/.env.example e2e-tests/react-next/.env + + - name: Copy .env file for React App + run: cp examples/react-app/.env.example examples/react-app/.env + - name: Run build:connectors run: pnpm build:connectors @@ -120,6 +129,10 @@ jobs: run: pnpm fuels build && pnpm fuels deploy working-directory: packages/evm-predicates + - name: Build & Deploy Solana Predicates + run: pnpm fuels build && pnpm fuels deploy + working-directory: packages/solana-connector + - name: Install Playwright Browsers run: pnpm exec playwright install --with-deps chromium working-directory: e2e-tests/runner @@ -132,14 +145,5 @@ jobs: if: ${{ github.event_name == 'pull_request' }} run: xvfb-run --auto-servernum -- pnpm --filter @e2e-tests/runner test:e2e env: - VITE_FUEL_PROVIDER_URL: "http://localhost:4000/v1/graphql" - NEXT_PUBLIC_PROVIDER_URL: "http://localhost:4000/v1/graphql" - NEXT_PUBLIC_WC_PROJECT_ID: e01471314fc69cc4efba6dce12dfd710 - NEXT_PUBLIC_CHAIN_ID_NAME: local - REACT_APP_PORT: 5173 - REACT_NEXT_PORT: 3002 - VITE_WALLET_SECRET: "0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298" VITE_MASTER_WALLET_MNEMONIC: ${{ secrets.VITE_MASTER_WALLET_MNEMONIC }} - VITE_APP_WC_PROJECT_ID: e01471314fc69cc4efba6dce12dfd710 - VITE_CHAIN_ID_NAME: local - PORT: 5173 + diff --git a/e2e-tests/react-next/.env.example b/e2e-tests/react-next/.env.example index b5ee1bbd..f351df57 100644 --- a/e2e-tests/react-next/.env.example +++ b/e2e-tests/react-next/.env.example @@ -1,2 +1,2 @@ -NEXT_PUBLIC_WC_PROJECT_ID= -NEXT_PUBLIC_PROVIDER_URL=https://testnet.fuel.network/v1/graphql \ No newline at end of file +NEXT_PUBLIC_WC_PROJECT_ID=e01471314fc69cc4efba6dce12dfd710 +NEXT_PUBLIC_PROVIDER_URL=http://localhost:4000/v1/graphql \ No newline at end of file diff --git a/e2e-tests/react-next/src/app/page.tsx b/e2e-tests/react-next/src/app/page.tsx index ae64a2ea..d3709a8a 100644 --- a/e2e-tests/react-next/src/app/page.tsx +++ b/e2e-tests/react-next/src/app/page.tsx @@ -77,10 +77,6 @@ const wagmiConfig = createConfig({ ], }); -if (!PROVIDER_URL) { - throw new Error(`PROVIDER_URL is not set: ${PROVIDER_URL}`); -} - const FUEL_CONFIG = { connectors: defaultConnectors({ devMode: true, diff --git a/e2e-tests/runner/.env.example b/e2e-tests/runner/.env.example index 29b4ef3d..8384266e 100644 --- a/e2e-tests/runner/.env.example +++ b/e2e-tests/runner/.env.example @@ -2,17 +2,10 @@ VITE_FUEL_PROVIDER_URL="http://localhost:4000/v1/graphql" NEXT_PUBLIC_PROVIDER_URL="http://localhost:4000/v1/graphql" -# Project and chain configuration -NEXT_PUBLIC_WC_PROJECT_ID="your_wc_project_id" -NEXT_PUBLIC_CHAIN_ID_NAME="testnet" -VITE_APP_WC_PROJECT_ID="your_wc_project_id" -VITE_CHAIN_ID_NAME="local" - # Wallet configuration -VITE_WALLET_SECRET="your_wallet_secret" -VITE_MASTER_WALLET_MNEMONIC="your_wallet_mnemonic" +VITE_WALLET_SECRET=0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298 +VITE_MASTER_WALLET_MNEMONIC=shuffle become fold deputy sick shove wolf olympic breeze antique ball broom # Port settings REACT_APP_PORT=5173 -REACT_NEXT_PORT=3002 -PORT=5173 \ No newline at end of file +REACT_NEXT_PORT=3002 \ No newline at end of file diff --git a/e2e-tests/runner/README.md b/e2e-tests/runner/README.md new file mode 100644 index 00000000..13151e5f --- /dev/null +++ b/e2e-tests/runner/README.md @@ -0,0 +1,83 @@ +# Running E2E Tests Locally + +## Prerequisites +- Node.js v20.11.0 +- PNPM v9.5.0 +- Rust toolchain with `forc` and `fuel-core` + +## Environment Setup +1. Copy `e2e-tests/runner/.env.example` to `e2e-tests/runner/.env`. They will have the required environment variables for local testing providing you have a local Fuel node running. +2. Copy `examples/react-app/.env.example` to `examples/react-app/.env`. +3. Copy `examples/react-next/.env.example` to `examples/react-next/.env`. + +## Steps to Run Tests + +1. **Start the Local Node** + ```bash + pnpm node:up + ``` + +2. **Install Dependencies** + ```bash + pnpm install --frozen-lockfile + ``` + +3. **Build Connectors** + ```bash + pnpm build:connectors + ``` + +4. **Build and Deploy Contracts** + ```bash + cd e2e-tests/runner/scripts + pnpm deploy:contracts + ``` + +5. **Build and Deploy EVM Predicates** + Copy `packages/evm-predicates/.env.example` to `packages/evm-predicates/.env`. + From the root directory: + ```bash + cd packages/evm-predicates + pnpm fuels build && pnpm fuels deploy + ``` + +6. **Build and Deploy Solana Predicates** + Copy `packages/solana-connector/.env.example` to `packages/solana-connector/.env`. + ```bash + cd packages/solana-connector + pnpm fuels build && pnpm fuels deploy + ``` + +7. **Install Playwright Browser** + ```bash + cd e2e-tests/runner + pnpm exec playwright install --with-deps chromium + ``` + +8. **Setup Synpress** + ```bash + cd e2e-tests/runner + pnpm synpress wallet-setup + ``` + +9. **Run the Tests** + ```bash + cd e2e-tests/runner + pnpm test:e2e + ``` + Or to run the Playwright UI and start the servers: + ```bash + cd e2e-tests/runner + pnpm test:e2e:dev + ``` + +## Environment Variables +- `VITE_FUEL_PROVIDER_URL`: URL for the local Fuel node (default: http://localhost:4000/v1/graphql) +- `NEXT_PUBLIC_WC_PROJECT_ID`: Your WalletConnect project ID +- `VITE_WALLET_SECRET`: Your wallet secret key +- `VITE_MASTER_WALLET_MNEMONIC`: Your wallet mnemonic phrase + +## Notes +- The tests require a local Fuel node to be running +- All commands should be run from the project root unless specified otherwise +- Make sure you have the correct Rust toolchain version installed with `forc` and `fuel-core` \ No newline at end of file diff --git a/e2e-tests/runner/examples/connectors/SolanaConnector/SolanaConnector.test.ts b/e2e-tests/runner/examples/connectors/SolanaConnector/SolanaConnector.test.ts index 12c690d1..9b12b41b 100644 --- a/e2e-tests/runner/examples/connectors/SolanaConnector/SolanaConnector.test.ts +++ b/e2e-tests/runner/examples/connectors/SolanaConnector/SolanaConnector.test.ts @@ -1,47 +1,77 @@ -import { - expect, - getButtonByText, - getByAriaLabel, -} from '@fuels/playwright-utils'; +import { getButtonByText, getByAriaLabel } from '@fuels/playwright-utils'; import type { Page } from '@playwright/test'; -import phantom from '../../../node_modules/@phantom/synpress/commands/phantom'; +import { + incrementTests, + sessionTests, + skipBridgeFunds, + transferTests, +} from '../../../common/common'; +import type { + ApproveTransferFunction, + ConnectFunction, +} from '../../../common/types'; +import { fundWallet } from '../setup'; +import phantomExtended from './phantom/phantom'; import { test } from './setup'; -phantom.confirmTransaction = async () => { - const notificationPage = - await phantom.playwright.switchToNotification('phantom'); - await phantom.playwright.waitAndClick( - 'phantom', - phantom.transactionPageElements.buttons.confirmTransaction, // Ensure this locator exists or define it - notificationPage, - { waitForEvent: 'close' }, - ); - return true; -}; - test.describe('SolanaConnector', () => { test.slow(); - const connect = async (page: Page) => { - await page.goto('/'); + const connect: ConnectFunction = async (page: Page) => { const connectButton = getButtonByText(page, 'Connect Wallet', true); await connectButton.click(); await getByAriaLabel(page, 'Connect to Solana Wallets', true).click(); await page.getByText('Proceed anyway').click(); await getButtonByText(page, 'Phantom').click(); - await phantom.acceptAccess(); - await page.waitForTimeout(3000); + try { + await phantomExtended.acceptAccess(); + } catch (error) { + // Phantom might not need to accept access if it already connected before + console.log('Error: ', error); + } }; - test('Fuel tests', async ({ page }) => { + const approveTransfer: ApproveTransferFunction = async () => { + await phantomExtended.confirmSignatureRequest(); + }; + + test.beforeEach(async ({ page }) => { + await page.goto('/'); + }); + + test('Solana tests', async ({ page }) => { + await test.step('Session tests', async () => { + await sessionTests(page, { connect, approveTransfer }); + }); + await connect(page); + await skipBridgeFunds(page); + const addressElement = await page.locator('#address'); - let address = null; + let address: string | null = null; if (addressElement) { address = await addressElement.getAttribute('data-address'); } - test.step('Check if address is not null', () => { - expect(address).not.toBeNull(); + + if (address) { + await fundWallet({ publicKey: address }); + } else { + throw new Error('Address is null'); + } + await test.step('Transfer tests', async () => { + await transferTests(page, { + connect, + approveTransfer, + keepSession: true, + }); + }); + + await test.step('Increment tests', async () => { + await incrementTests(page, { + connect, + approveTransfer, + keepSession: true, + }); }); }); }); diff --git a/e2e-tests/runner/examples/connectors/SolanaConnector/phantom/phantom.ts b/e2e-tests/runner/examples/connectors/SolanaConnector/phantom/phantom.ts new file mode 100644 index 00000000..3f06bf45 --- /dev/null +++ b/e2e-tests/runner/examples/connectors/SolanaConnector/phantom/phantom.ts @@ -0,0 +1,7 @@ +import phantomCommands from '../../../../node_modules/@phantom/synpress/commands/phantom'; + +export const phantomExtended = { + ...phantomCommands, +}; + +export default phantomExtended; diff --git a/e2e-tests/runner/examples/connectors/SolanaConnector/phantom/setup.ts b/e2e-tests/runner/examples/connectors/SolanaConnector/phantom/setup.ts index ece95c06..babfadf6 100644 --- a/e2e-tests/runner/examples/connectors/SolanaConnector/phantom/setup.ts +++ b/e2e-tests/runner/examples/connectors/SolanaConnector/phantom/setup.ts @@ -1,14 +1,14 @@ import type { BrowserContext } from '@playwright/test'; import { chromium } from '@playwright/test'; -import phantomCommands from '../../../../node_modules/@phantom/synpress/commands/phantom'; import phantomHelpers from '../../../../node_modules/@phantom/synpress/helpers'; import { PHANTOM_CONFIG } from './config'; +import phantomExtended from './phantom'; export async function phantomPath() { return await phantomHelpers.prepareProvider('phantom', 'latest'); } export async function setupPhantom(_context: BrowserContext) { - await phantomCommands.initialSetup(chromium, { + await phantomExtended.initialSetup(chromium, { secretWordsOrPrivateKey: PHANTOM_CONFIG.MNEMONIC, network: 'localhost', password: PHANTOM_CONFIG.WALLET_PASSWORD, diff --git a/e2e-tests/runner/examples/connectors/WalletConnectConnector/WalletConnectConnector.test.ts b/e2e-tests/runner/examples/connectors/WalletConnectConnector/WalletConnectConnector.test.ts index 94e3bd79..c58d7a63 100644 --- a/e2e-tests/runner/examples/connectors/WalletConnectConnector/WalletConnectConnector.test.ts +++ b/e2e-tests/runner/examples/connectors/WalletConnectConnector/WalletConnectConnector.test.ts @@ -73,7 +73,6 @@ test.describe('WalletConnectConnector', () => { } await transferTests(page, { connect, approveTransfer, keepSession: true }); - await incrementTests(page, { connect, approveTransfer, keepSession: true }); }); }); diff --git a/e2e-tests/runner/fuels.config.ts b/e2e-tests/runner/fuels.config.ts index d5b5f1c7..fa212dfd 100644 --- a/e2e-tests/runner/fuels.config.ts +++ b/e2e-tests/runner/fuels.config.ts @@ -1,14 +1,19 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; +import dotenv from 'dotenv'; import { createConfig } from 'fuels'; +dotenv.config({ + path: ['.env'], +}); + export default createConfig({ output: './src/contracts', contracts: ['./contracts/custom_asset'], forcBuildFlags: ['--release'], privateKey: '0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298', - providerUrl: 'http://localhost:4000/v1/graphql', + providerUrl: process.env.PROVIDER_URL || 'http://localhost:4000/v1/graphql', onDeploy: (_, contracts) => { const contractIdsPath = join(__dirname, './src/contract-ids.json'); let contractIds = {}; diff --git a/e2e-tests/runner/package.json b/e2e-tests/runner/package.json index 55932fcd..382e39ae 100644 --- a/e2e-tests/runner/package.json +++ b/e2e-tests/runner/package.json @@ -12,7 +12,7 @@ "test:react-app": "pnpm test:react-app:ci -- --ui", "test:react-app:ci": "playwright test e2e-tests/react-app --project=react-app", "test:react-next": "pnpm playwright test --project=react-next", - "test:e2e:dev": "pnpm --workspace-root node:up && pnpm run start:servers & pnpm playwright test --ui", + "test:e2e:dev": "pnpm run start:servers & pnpm playwright test --ui", "test:e2e:local": "pnpm run deploy:contracts && pnpm run test:e2e", "start:react-app": "pnpm --filter react-app dev", "start:react-next": "pnpm --filter @e2e-tests/react-next dev", diff --git a/e2e-tests/runner/playwright.config.ts b/e2e-tests/runner/playwright.config.ts index 6b2206b6..6db61c30 100644 --- a/e2e-tests/runner/playwright.config.ts +++ b/e2e-tests/runner/playwright.config.ts @@ -3,7 +3,7 @@ import { defineConfig, devices, } from '@playwright/test'; -import { synpressFixtures } from '@synthetixio/synpress'; +// import { synpressFixtures } from '@synthetixio/synpress'; import dotenv from 'dotenv'; dotenv.config(); diff --git a/examples/react-app/.env.example b/examples/react-app/.env.example index bf821efe..faea7a9f 100644 --- a/examples/react-app/.env.example +++ b/examples/react-app/.env.example @@ -1,6 +1,3 @@ -VITE_APP_WC_PROJECT_ID= -VITE_CHAIN_ID_NAME=testnet -VITE_FUEL_PROVIDER_URL=https://testnet.fuel.network/v1/graphql -VITE_WALLET_SECRET="0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298" -VITE_MASTER_WALLET_MNEMONIC="shuffle become fold deputy sick shove wolf olympic breeze antique ball broom" -PORT=5173 \ No newline at end of file +VITE_APP_WC_PROJECT_ID=e01471314fc69cc4efba6dce12dfd710 +VITE_CHAIN_ID_NAME=local +VITE_FUEL_PROVIDER_URL=http://localhost:4000/v1/graphql \ No newline at end of file diff --git a/examples/react-next/.env.example b/examples/react-next/.env.example index cfe4d9d5..d7d56d35 100644 --- a/examples/react-next/.env.example +++ b/examples/react-next/.env.example @@ -1 +1,3 @@ -NEXT_PUBLIC_WC_PROJECT_ID= \ No newline at end of file +NEXT_PUBLIC_WC_PROJECT_ID=e01471314fc69cc4efba6dce12dfd710 +NEXT_PUBLIC_CHAIN_ID_NAME=testnet +NEXT_PUBLIC_PROVIDER_URL=http://localhost:4000/v1/graphql \ No newline at end of file diff --git a/packages/evm-predicates/.env.example b/packages/evm-predicates/.env.example new file mode 100644 index 00000000..3ebb8936 --- /dev/null +++ b/packages/evm-predicates/.env.example @@ -0,0 +1,2 @@ +PRIVATE_KEY=0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298 +PROVIDER_URL=http://localhost:4000/v1/graphql \ No newline at end of file diff --git a/packages/evm-predicates/fuels.config.ts b/packages/evm-predicates/fuels.config.ts index 418b1edd..cf6da157 100644 --- a/packages/evm-predicates/fuels.config.ts +++ b/packages/evm-predicates/fuels.config.ts @@ -1,11 +1,16 @@ +import dotenv from 'dotenv'; import { createConfig } from 'fuels'; +dotenv.config({ + path: ['.env'], +}); + export default createConfig({ - providerUrl: 'http://localhost:4000/v1/graphql', + providerUrl: process.env.PROVIDER_URL || 'http://localhost:4000/v1/graphql', predicates: ['./predicate'], output: './src/generated/tmp', forcBuildFlags: ['--release'], // needs the private key to deploy the predicate privateKey: - '0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298', // genesis private key + '0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298', }); diff --git a/packages/evm-predicates/package.json b/packages/evm-predicates/package.json index 6f154cc0..257e75ef 100644 --- a/packages/evm-predicates/package.json +++ b/packages/evm-predicates/package.json @@ -15,6 +15,7 @@ }, "devDependencies": { "@fuel-connectors/common": "workspace:*", + "dotenv": "16.4.5", "fuels": "0.96.1", "tsx": "4.9.3", "typescript": "5.4.5" diff --git a/packages/solana-connector/.env.example b/packages/solana-connector/.env.example new file mode 100644 index 00000000..3ebb8936 --- /dev/null +++ b/packages/solana-connector/.env.example @@ -0,0 +1,2 @@ +PRIVATE_KEY=0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298 +PROVIDER_URL=http://localhost:4000/v1/graphql \ No newline at end of file diff --git a/packages/solana-connector/fuels.config.ts b/packages/solana-connector/fuels.config.ts index 1fe54f84..cf6da157 100644 --- a/packages/solana-connector/fuels.config.ts +++ b/packages/solana-connector/fuels.config.ts @@ -1,10 +1,16 @@ +import dotenv from 'dotenv'; import { createConfig } from 'fuels'; +dotenv.config({ + path: ['.env'], +}); + export default createConfig({ - providerUrl: 'https://testnet.fuel.network/v1/graphql', + providerUrl: process.env.PROVIDER_URL || 'http://localhost:4000/v1/graphql', predicates: ['./predicate'], output: './src/generated/tmp', forcBuildFlags: ['--release'], // needs the private key to deploy the predicate - privateKey: '0x', + privateKey: + '0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298', }); diff --git a/packages/solana-connector/package.json b/packages/solana-connector/package.json index dc8e0b3c..43023e92 100644 --- a/packages/solana-connector/package.json +++ b/packages/solana-connector/package.json @@ -38,6 +38,7 @@ "@fuel-connectors/common": "workspace:*", "@types/memoizee": "0.4.11", "@web3modal/core": "5.0.0", + "dotenv": "16.4.5", "fuels": "0.96.1", "jsdom": "24.0.0", "ts-loader": "9.5.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4cc39219..5978687f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -533,6 +533,9 @@ importers: '@fuel-connectors/common': specifier: workspace:* version: link:../common + dotenv: + specifier: 16.4.5 + version: 16.4.5 fuels: specifier: 0.96.1 version: 0.96.1 @@ -680,6 +683,9 @@ importers: '@web3modal/core': specifier: 5.0.0 version: 5.0.0(@types/react@18.3.1)(react@18.3.1) + dotenv: + specifier: 16.4.5 + version: 16.4.5 fuels: specifier: 0.96.1 version: 0.96.1