diff --git a/.github/workflows/pre-merge-e2e-pptr-tests.yml b/.github/workflows/pre-merge-e2e-pptr-tests.yml index a6f426a1..29b79deb 100644 --- a/.github/workflows/pre-merge-e2e-pptr-tests.yml +++ b/.github/workflows/pre-merge-e2e-pptr-tests.yml @@ -45,9 +45,18 @@ jobs: with: timeout_minutes: 120 retry_on: error - max_attempts: 5 + max_attempts: 3 command: yarn install - - name: Build devnet MSW - run: yarn build:devnet-msw - - name: Run Puppeteer tests + - name: Setup chrome + uses: browser-actions/setup-chrome@v1 + id: setup-chrome + with: + chrome-version: 128 + - name: Set Chrome Path + run: echo "CHROME_PATH=${{ steps.setup-chrome.outputs.chrome-path }}" >> $GITHUB_ENV + - name: Build sovereign msw + run: yarn build:sovereign-msw + - name: Run Puppeteer test + env: + CHROME_PATH: ${{ steps.setup-chrome.outputs.chrome-path }} run: yarn test:pptr-headless \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 398e2a1f..f77c6c25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- [Added faucet and issue token tests](https://github.com/multiversx/mx-lite-wallet-dapp/pull/57) - [Allow only tokens and collections with prefix to be registered](https://github.com/multiversx/mx-lite-wallet-dapp/pull/56) ## [[1.0.2](https://github.com/multiversx/mx-lite-wallet-dapp/pull/54)] - 2024-10-03 diff --git a/jest-puppeteer.config.js b/jest-puppeteer.config.js index c299c8ba..4e5e3b49 100644 --- a/jest-puppeteer.config.js +++ b/jest-puppeteer.config.js @@ -2,63 +2,84 @@ /* tslint:disable */ const fs = require('fs'); const path = require('path'); +const { execSync } = require('child_process'); -const getChromeExecutablePath = () => { - const chromeHeadlessShellPath = './chrome-headless-shell'; - const platform = process.platform; // Get the platform - - if (platform === 'linux') { - const dirs = fs.readdirSync(chromeHeadlessShellPath); - const chromeDirectory = dirs.find((dir) => dir.startsWith('linux-')); - - if (chromeDirectory) { - return path.resolve( - __dirname, - chromeHeadlessShellPath, - chromeDirectory, - 'chrome-headless-shell-linux64/chrome-headless-shell' - ); - } else { - throw new Error('Chrome headless shell directory not found'); +const isLinux = process.platform === 'linux'; +const isHeadless = process.env.HEADLESS !== 'false'; +const chromePath = process.env.CHROME_PATH; + +const findFile = (folderPath, fileName) => { + const files = fs.readdirSync(folderPath); + + for (const file of files) { + const filePath = path.join(folderPath, file); + const stats = fs.statSync(filePath); + + if (stats.isDirectory()) { + const found = findFile(filePath, fileName); + if (found) return found; + } else if (file === fileName) { + return filePath; + } + } + + return null; +}; + +const getLinuxChromiumPath = () => { + try { + // Try to get the path using 'which' command + try { + return execSync('which chromium-browser', { encoding: 'utf8' }).trim(); + } catch (e) { + // If 'which chromium-browser' fails, try 'which chromium' + try { + return execSync('which chromium', { encoding: 'utf8' }).trim(); + } catch (e) { + // If both fail, continue to next method + } } - } else if (platform === 'darwin') { - // macOS - const dirs = fs.readdirSync(chromeHeadlessShellPath); - const chromeDirectory = dirs.find((dir) => dir.startsWith('mac_arm-')); - - if (chromeDirectory) { - return path.resolve( - __dirname, - chromeHeadlessShellPath, - chromeDirectory, - 'chrome-headless-shell-mac-arm64/chrome-headless-shell' - ); - } else { - throw new Error('Chrome headless shell directory not found'); + + // Check common snap installation path + const snapPath = '/snap/bin/chromium'; + + if (fs.existsSync(snapPath)) { + return snapPath; } - } else { - throw new Error('Unsupported platform'); + + // Check another common installation path + const commonPath = '/usr/bin/chromium-browser'; + + if (fs.existsSync(commonPath)) { + return commonPath; + } + + // If all attempts fail, return null + return null; + } catch (error) { + console.error('Error finding Chromium path:', error); + return null; } }; -const isHeadless = process.env.HEADLESS !== 'false'; +const getChromeExecutablePath = () => { + if (chromePath) { + return chromePath; + } + + return !isHeadless && isLinux ? getLinuxChromiumPath() : undefined; +}; const args = [ + '--disable-gpu', + '--disable-dev-shm-usage', + '--no-sandbox', + '--disable-setuid-sandbox', '--start-maximized', // Required to start in full screen '--disable-web-security', // Required for iframe to work '--ignore-certificate-errors' // Required for HTTPS to work ]; -if (isHeadless) { - args.unshift( - '--disable-gpu', - '--disable-dev-shm-usage', - '--no-sandbox', - '--disable-setuid-sandbox', - `--headless=new` - ); -} - const config = { preset: 'jest-puppeteer', testMatch: ['**/src/**/*.e2e.ts'], @@ -66,15 +87,16 @@ const config = { roots: ['/src'], modulePaths: ['/src'], bail: 1, - workerIdleMemoryLimit: '512MB', // Memory used per worker. Required to prevent memory leaks - // maxWorkers: '50%', // Maximum tests ran in parallel. Required to prevent CPU usage at 100% + workerIdleMemoryLimit: '512MB', + maxWorkers: isHeadless ? '100%' : 1, launch: { - headless: false, + headless: isHeadless, + dumpio: false, // Enable to see machine logs product: 'chrome', - defaultViewport: { width: 1600, height: 800 }, + defaultViewport: isHeadless ? { width: 1600, height: 800 } : null, args, - executablePath: getChromeExecutablePath(), // optional locally, required on Git Action - devtools: !isHeadless + executablePath: getChromeExecutablePath(), + devtools: false // Enable to see browser console }, server: { command: 'vite preview' @@ -84,7 +106,7 @@ const config = { browserPerWorker: true }; -if (!isHeadless) { +if (!isHeadless && !isLinux && !chromePath) { delete config.launch.executablePath; } diff --git a/package.json b/package.json index fae3e537..1236a3b0 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "build": "tsc && npm run set-storage-persist && vite build", "build:devnet": "npm run copy:devnet-config && npm run build", "build:sovereign": "npm run copy:sovereign-config && npm run build", - "build:devnet-msw": "npm run copy:devnet-config & VITE_APP_MSW=true npm run build", + "build:sovereign-msw": "npm run copy:sovereign-config & VITE_APP_MSW=true npm run build", "build:testnet": "npm run copy:testnet-config & npm run build", "build:mainnet": "npm run copy:mainnet-config & npm run build", "postbuild": "node src/scripts/createVersionFile/index", @@ -26,7 +26,7 @@ "copy:testnet-config": "cp ./src/config/config.testnet.ts ./src/config/index.ts", "copy:mainnet-config": "cp ./src/config/config.mainnet.ts ./src/config/index.ts", "copy:sovereign-config": "cp ./src/config/config.sovereign.ts ./src/config/index.ts", - "test:pptr-headless": "npx @puppeteer/browsers install chrome-headless-shell@125.0.6420.0 && jest --config=jest-puppeteer.config.js", + "test:pptr-headless": "HEADLESS=true jest --config=jest-puppeteer.config.js", "test:pptr": "JEST_PPTR_RETRY_TIMES=0 HEADLESS=false jest --config=jest-puppeteer.config.js", "test": "jest", "preview": "vite preview" diff --git a/src/__mocks__/data/dappConfig.ts b/src/__mocks__/data/dappConfig.ts index e7438f33..9acbc0c6 100644 --- a/src/__mocks__/data/dappConfig.ts +++ b/src/__mocks__/data/dappConfig.ts @@ -1,7 +1,7 @@ export const dappConfig = { - id: 'devnet', - name: 'Devnet', - egldLabel: 'xEGLD', + id: 'sovereign', + name: 'Sovereign', + egldLabel: 'WEGLD', decimals: '4', egldDenomination: '18', gasPerDataByte: '1500', @@ -9,8 +9,9 @@ export const dappConfig = { walletConnectDeepLink: 'https://maiar.page.link/?apn=com.multiversx.maiar.wallet&isi=1519405832&ibi=com.multiversx.maiar.wallet&link=https://maiar.com/', walletConnectBridgeAddresses: ['https://bridge.walletconnect.org'], - walletAddress: 'https://devnet-wallet.multiversx.com', - apiAddress: 'https://devnet-api.multiversx.com', - explorerAddress: 'http://devnet-explorer.multiversx.com', - chainId: 'D' + walletAddress: 'https://wallet-sovereign-test.elrond.ro/', + apiAddress: 'https://api-sovereign-test.elrond.ro', + explorerAddress: + 'https://api-sovereign-test.internal-explorer.multiversx.com', + chainId: 'local-testnet' }; diff --git a/src/__mocks__/data/faucetSettings.ts b/src/__mocks__/data/faucetSettings.ts new file mode 100644 index 00000000..bed0fb4b --- /dev/null +++ b/src/__mocks__/data/faucetSettings.ts @@ -0,0 +1,5 @@ +export const faucetSettings = { + address: 'erd1xgzak3d6wcpyk83c3ne0n05khdz026e8p0rg8qu65dly706kfmxs0qecax', + amount: '40000000000000000000', + recaptchaBypass: true +}; diff --git a/src/__mocks__/data/index.ts b/src/__mocks__/data/index.ts index 1011d9ec..3c111a85 100644 --- a/src/__mocks__/data/index.ts +++ b/src/__mocks__/data/index.ts @@ -1,7 +1,9 @@ export * from './constants'; export * from './dappConfig'; export * from './emptyWallet'; +export * from './faucetSettings'; export * from './networkConfig'; export * from './testKeystoreWallet'; export * from './testNetwork'; export * from './testPemWallet'; +export * from './testPemWalletGuarded'; diff --git a/src/__mocks__/data/testNetwork.ts b/src/__mocks__/data/testNetwork.ts index 452dc9ce..2dde8931 100644 --- a/src/__mocks__/data/testNetwork.ts +++ b/src/__mocks__/data/testNetwork.ts @@ -1,3 +1,4 @@ export const testNetwork = { - apiAddress: 'https://devnet-api.multiversx.com' + apiAddress: 'https://api-sovereign-test.elrond.ro', + extrasApiAddress: 'https://extras-api-sovereign-test.elrond.ro' }; diff --git a/src/__mocks__/data/testPemWalletGuarded/account.pem b/src/__mocks__/data/testPemWalletGuarded/account.pem new file mode 100644 index 00000000..a8a693f2 --- /dev/null +++ b/src/__mocks__/data/testPemWalletGuarded/account.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY for erd1dc3yzxxeq69wvf583gw0h67td226gu2ahpk3k50qdgzzym8npltq7ndgha----- +YjMzODcyMjMzMjFjNTg3YzM1MTE5OGFkYzI1MzFjODIwYTM3OGQzNzQ4OTU2YjNk +YWUyZTBmNWExZGFhN2NhMTZlMjI0MTE4ZDkwNjhhZTYyNjg3OGExY2ZiZWJjYjZh +OTVhNDcxNWRiODZkMWI1MWUwNmEwNDIyNmNmMzBmZDY= +-----END PRIVATE KEY for erd1dc3yzxxeq69wvf583gw0h67td226gu2ahpk3k50qdgzzym8npltq7ndgha----- \ No newline at end of file diff --git a/src/__mocks__/data/testPemWalletGuarded/index.ts b/src/__mocks__/data/testPemWalletGuarded/index.ts new file mode 100644 index 00000000..9d3f4e03 --- /dev/null +++ b/src/__mocks__/data/testPemWalletGuarded/index.ts @@ -0,0 +1 @@ +export * from './pemAccountGuarded'; diff --git a/src/__mocks__/data/testPemWalletGuarded/pemAccountGuarded.ts b/src/__mocks__/data/testPemWalletGuarded/pemAccountGuarded.ts new file mode 100644 index 00000000..f44d51c1 --- /dev/null +++ b/src/__mocks__/data/testPemWalletGuarded/pemAccountGuarded.ts @@ -0,0 +1,18 @@ +import { emptyWalletAccount } from '../emptyWallet'; + +export const pemAccountGuarded = { + address: 'erd1dc3yzxxeq69wvf583gw0h67td226gu2ahpk3k50qdgzzym8npltq7ndgha', + balance: '4559443050404540691', + nonce: 71, + timestamp: 1685712294, + shard: 1, + rootHash: 'cB9GBtevo98yZf906jxVI++W6U68+V+22NnUJEpOs8c=', + txCount: 74, + scrCount: 64, + developerReward: '0', + activeGuardianActivationEpoch: 1119, + activeGuardianAddress: emptyWalletAccount.address, + activeGuardianServiceUid: 'MultiversXTCSService', + pendingGuardianAddress: undefined, + isGuarded: true +}; diff --git a/src/__mocks__/server.ts b/src/__mocks__/server.ts index 85e25ebb..153f8f29 100644 --- a/src/__mocks__/server.ts +++ b/src/__mocks__/server.ts @@ -10,7 +10,9 @@ import { pemWalletTokens, pemWalletNfts, dappConfig, - networkConfig + networkConfig, + pemAccountGuarded, + faucetSettings } from './data'; import { mockResponse } from './serverUtils'; @@ -43,6 +45,28 @@ export const handlers = [ http.get( `${testNetwork.apiAddress}/accounts/${pemAccount.address}/nfts`, mockResponse(pemWalletNfts) + ), + http.get( + `${testNetwork.apiAddress}/accounts/${pemAccountGuarded.address}`, + mockResponse(pemAccount) + ), + http.get( + `${testNetwork.apiAddress}/accounts/${pemAccountGuarded.address}/tokens`, + mockResponse(pemWalletTokens) + ), + http.get( + `${testNetwork.apiAddress}/accounts/${pemAccountGuarded.address}/nfts`, + mockResponse(pemWalletNfts) + ), + http.get( + `${testNetwork.extrasApiAddress}/faucet/settings`, + mockResponse(faucetSettings) + ), + http.post( + `${testNetwork.extrasApiAddress}/faucet`, + mockResponse({ + status: 'success' + }) ) ]; diff --git a/src/localConstants/dataTestIds.enum.ts b/src/localConstants/dataTestIds.enum.ts index 601a19c9..0910f6c7 100644 --- a/src/localConstants/dataTestIds.enum.ts +++ b/src/localConstants/dataTestIds.enum.ts @@ -28,6 +28,7 @@ export enum DataTestIdsEnum { dappModal = 'dappModal', dataInput = 'dataInput', disclaimerCheck = 'disclaimerCheck', + faucetBtn = 'faucetBtn', gasLimitError = 'gasLimitError', gasLimitInput = 'gasLimitInput', goToCheckMnemonic = 'goToCheckMnemonic', @@ -66,7 +67,7 @@ export enum DataTestIdsEnum { recoverWalletBtn = 'recoverWalletBtn', registerTokenBtn = 'registerTokenBtn', removeTokenBtn = 'removeTokenBtn', - requestTokensButton = 'requestTokensButton', + requestFundsButton = 'requestFundsButton', royaltiesError = 'royaltiesError', royaltiesInput = 'royaltiesInput', sendBtn = 'sendBtn', diff --git a/src/pages/Faucet/Faucet.tsx b/src/pages/Faucet/Faucet.tsx index cbdf23e4..7b47aa19 100644 --- a/src/pages/Faucet/Faucet.tsx +++ b/src/pages/Faucet/Faucet.tsx @@ -21,7 +21,7 @@ export const Faucet = () => { <>