diff --git a/.github/actions/e2e-tests-contracts/action.yaml b/.github/actions/e2e-tests-contracts/action.yaml index 75025ac165..aae291d479 100644 --- a/.github/actions/e2e-tests-contracts/action.yaml +++ b/.github/actions/e2e-tests-contracts/action.yaml @@ -14,6 +14,10 @@ inputs: description: Browser to run tests on (chromium or chrome-beta) required: false default: chromium + shard: + description: Shard configuration for test parallelization (e.g. 1/4) + required: false + default: '' runs: using: 'composite' @@ -35,7 +39,7 @@ runs: - name: Run E2E Contract Tests shell: bash - run: xvfb-run --auto-servernum -- pnpm test:e2e:contracts --project=${{ inputs.browser }} + run: xvfb-run --auto-servernum -- pnpm test:e2e:contracts --project=${{ inputs.browser }} ${{ inputs.shard != '' && format('--shard {0}', inputs.shard) || '' }} env: PORT: 5173 VITE_FUEL_PROVIDER_URL: ${{ inputs.providerUrl }} diff --git a/.github/workflows/pr-tests-e2e-contracts.yml b/.github/workflows/pr-tests-e2e-contracts.yml index 08ba17de16..34ba71f46a 100644 --- a/.github/workflows/pr-tests-e2e-contracts.yml +++ b/.github/workflows/pr-tests-e2e-contracts.yml @@ -11,9 +11,13 @@ concurrency: jobs: tests-e2e-contracts: - name: Test (Chrome Stable) - runs-on: buildjet-8vcpu-ubuntu-2204 - timeout-minutes: 15 + name: Test (Chrome Stable) [Shard ${{ matrix.shard }}] + runs-on: buildjet-8vcpu-ubuntu-2204 + timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4] steps: - uses: actions/checkout@v4 - uses: FuelLabs/github-actions/setups/node@master @@ -40,7 +44,6 @@ jobs: - name: Build & Deploy Contracts run: pnpm deploy:contracts working-directory: ./packages/e2e-contract-tests - - name: Run E2E Contract Tests uses: ./.github/actions/e2e-tests-contracts with: @@ -48,19 +51,24 @@ jobs: masterMnemonic: ${{ secrets.VITE_MASTER_WALLET_MNEMONIC }} genesisSecret: "0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298" browser: 'chromium' + shard: ${{ matrix.shard }}/4 - uses: actions/upload-artifact@v4 if: always() with: - name: playwright-e2e-contract-tests-report + name: playwright-e2e-contract-tests-report-shard-${{ matrix.shard }} path: packages/e2e-contract-tests/playwright-results retention-days: 30 tests-e2e-contracts-beta: - name: Test (Chrome Beta) - runs-on: buildjet-8vcpu-ubuntu-2204 - timeout-minutes: 15 + name: Test (Chrome Beta) [Shard ${{ matrix.shard }}] + runs-on: buildjet-8vcpu-ubuntu-2204 + timeout-minutes: 20 continue-on-error: true + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4] steps: - uses: actions/checkout@v4 - uses: FuelLabs/github-actions/setups/node@master @@ -88,17 +96,19 @@ jobs: - name: Build & Deploy Contracts run: pnpm deploy:contracts working-directory: ./packages/e2e-contract-tests + - uses: ./.github/actions/e2e-tests-contracts with: providerUrl: "http://localhost:4000/v1/graphql" masterMnemonic: ${{ secrets.VITE_MASTER_WALLET_MNEMONIC }} genesisSecret: "0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298" browser: 'chrome-beta' + shard: ${{ matrix.shard }}/4 - uses: actions/upload-artifact@v4 if: always() with: - name: playwright-e2e-contract-tests-report-beta + name: playwright-e2e-contract-tests-report-beta-shard-${{ matrix.shard }} path: packages/e2e-contract-tests/playwright-results retention-days: 30 diff --git a/packages/e2e-contract-tests/playwright/e2e/DepositHalfEth.test.ts b/packages/e2e-contract-tests/playwright/e2e/DepositHalfEth.test.ts index 406076ab8f..689d79ac8c 100644 --- a/packages/e2e-contract-tests/playwright/e2e/DepositHalfEth.test.ts +++ b/packages/e2e-contract-tests/playwright/e2e/DepositHalfEth.test.ts @@ -57,19 +57,25 @@ test.describe('Deposit Half ETH', () => { const depositHalfButton = getButtonByText(page, 'Deposit Half ETH', true); await expectButtonToBeEnabled(depositHalfButton); + await page.waitForTimeout(1000); // Wait for slow VM await depositHalfButton.click(); + await page.waitForTimeout(1000); // Wait for slow VM const walletNotificationPage = await fuelWalletTestHelper.getWalletPopupPage(); // Test if asset name is defined (not unknown) - checkAriaLabelsContainsText( + await checkAriaLabelsContainsText( walletNotificationPage, 'Asset Name', 'Ethereum' ); // Test if sender name is defined (not unknown) - checkAriaLabelsContainsText(walletNotificationPage, 'Sender Name', ''); + await checkAriaLabelsContainsText( + walletNotificationPage, + 'Sender Name', + '' + ); // test forward asset name is shown await hasText(walletNotificationPage, 'Ethereum'); diff --git a/packages/e2e-contract-tests/playwright/e2e/ForwardAndMintMulticall.test.ts b/packages/e2e-contract-tests/playwright/e2e/ForwardAndMintMulticall.test.ts index dc186e133c..0b1a1302c6 100644 --- a/packages/e2e-contract-tests/playwright/e2e/ForwardAndMintMulticall.test.ts +++ b/packages/e2e-contract-tests/playwright/e2e/ForwardAndMintMulticall.test.ts @@ -66,19 +66,25 @@ test.describe('Forward and Mint Multicall', () => { 'Deposit And Mint Multicall' ); await expectButtonToBeEnabled(forwardHalfAndMintButton); + await page.waitForTimeout(1000); // Wait for slow VM await forwardHalfAndMintButton.click(); + await page.waitForTimeout(1000); // Wait for slow VM const walletNotificationPage = await fuelWalletTestHelper.getWalletPopupPage(); // Test if asset name is defined (not unknown) - checkAriaLabelsContainsText( + await checkAriaLabelsContainsText( walletNotificationPage, 'Asset Name', 'Ethereum' ); // Test if sender name is defined (not unknown) - checkAriaLabelsContainsText(walletNotificationPage, 'Sender Name', ''); + await checkAriaLabelsContainsText( + walletNotificationPage, + 'Sender Name', + '' + ); // test forward asset name is shown await hasText(walletNotificationPage, 'Ethereum'); diff --git a/packages/e2e-contract-tests/playwright/e2e/ForwardCustomAsset.test.ts b/packages/e2e-contract-tests/playwright/e2e/ForwardCustomAsset.test.ts index 6a927e2765..ec3667aab3 100644 --- a/packages/e2e-contract-tests/playwright/e2e/ForwardCustomAsset.test.ts +++ b/packages/e2e-contract-tests/playwright/e2e/ForwardCustomAsset.test.ts @@ -78,19 +78,25 @@ test.describe('Forward Custom Asset', () => { 'Forward Custom Asset' ); await expectButtonToBeEnabled(forwardCustomAssetButton); + await page.waitForTimeout(1000); // Wait for slow VM await forwardCustomAssetButton.click(); + await page.waitForTimeout(1000); // Wait for slow VM const walletNotificationPage = await fuelWalletTestHelper.getWalletPopupPage(); // Test if asset name is defined (not unknown) - checkAriaLabelsContainsText( + await checkAriaLabelsContainsText( walletNotificationPage, 'Asset Name', 'Ethereum' ); // Test if sender name is defined (not unknown) - checkAriaLabelsContainsText(walletNotificationPage, 'Sender Name', ''); + await checkAriaLabelsContainsText( + walletNotificationPage, + 'Sender Name', + '' + ); // test the asset name is shown await hasText(walletNotificationPage, 'Unknown', 0, 5000, true); diff --git a/packages/e2e-contract-tests/playwright/e2e/ForwardEth.test.ts b/packages/e2e-contract-tests/playwright/e2e/ForwardEth.test.ts index 946b6a6c08..8c7e46977b 100644 --- a/packages/e2e-contract-tests/playwright/e2e/ForwardEth.test.ts +++ b/packages/e2e-contract-tests/playwright/e2e/ForwardEth.test.ts @@ -56,30 +56,32 @@ test.describe('Forward Eth', () => { const forwardEthButton = getButtonByText(page, 'Forward ETH'); await expectButtonToBeEnabled(forwardEthButton); + await page.waitForTimeout(1000); // Wait for slow VM await forwardEthButton.click(); + await page.waitForTimeout(1000); // Wait for slow VM const walletNotificationPage = await fuelWalletTestHelper.getWalletPopupPage(); - // Test if asset name is defined (not unknown) - checkAriaLabelsContainsText( + await checkAriaLabelsContainsText( walletNotificationPage, 'Asset Name', 'Ethereum' ); // Test if sender name is defined (not unknown) - checkAriaLabelsContainsText(walletNotificationPage, 'Sender Name', ''); - - // test the asset name is shown + await checkAriaLabelsContainsText( + walletNotificationPage, + 'Sender Name', + '' + ); await hasText(walletNotificationPage, 'Ethereum'); // test asset id is correct - await hasText(walletNotificationPage, shortAddress(await getBaseAssetId())); + const baseAssetId = await getBaseAssetId(); + await hasText(walletNotificationPage, shortAddress(baseAssetId)); // test forward eth amount is correct await hasText(walletNotificationPage, `${forwardEthAmount} ETH`); - - // test gas fee is correct await hasText(walletNotificationPage, 'Fee (network)'); // test to and from addresses @@ -94,10 +96,13 @@ test.describe('Forward Eth', () => { await fuelWalletTestHelper.walletApprove(); await waitSuccessTransaction(page); const postDepositBalanceEth = await fuelWallet.getBalance(); - expect( - Number.parseFloat( - preDepositBalanceEth.sub(postDepositBalanceEth).format({ precision: 4 }) - ) - ).toBe(Number.parseFloat(forwardEthAmount)); + + const difference = preDepositBalanceEth + .sub(postDepositBalanceEth) + .format({ precision: 4 }); + + expect(Number.parseFloat(difference)).toBe( + Number.parseFloat(forwardEthAmount) + ); }); }); diff --git a/packages/e2e-contract-tests/playwright/e2e/ForwardHalfAndExternalMint.test.ts b/packages/e2e-contract-tests/playwright/e2e/ForwardHalfAndExternalMint.test.ts index 8d10363b03..c0eadc53a7 100644 --- a/packages/e2e-contract-tests/playwright/e2e/ForwardHalfAndExternalMint.test.ts +++ b/packages/e2e-contract-tests/playwright/e2e/ForwardHalfAndExternalMint.test.ts @@ -70,19 +70,25 @@ test.describe('Forward Half ETH and Mint External Custom Asset', () => { 'Forward Half And External Mint' ); await expectButtonToBeEnabled(forwardHalfAndMintButton); + await page.waitForTimeout(1000); // Wait for slow VM await forwardHalfAndMintButton.click(); + await page.waitForTimeout(1000); // Wait for slow VM const walletNotificationPage = await fuelWalletTestHelper.getWalletPopupPage(); // Test if asset name is defined (not unknown) - checkAriaLabelsContainsText( + await checkAriaLabelsContainsText( walletNotificationPage, 'Asset Name', 'Ethereum' ); // Test if sender name is defined (not unknown) - checkAriaLabelsContainsText(walletNotificationPage, 'Sender Name', ''); + await checkAriaLabelsContainsText( + walletNotificationPage, + 'Sender Name', + '' + ); // test forward asset name is shown await hasText(walletNotificationPage, 'Ethereum'); diff --git a/packages/e2e-contract-tests/playwright/e2e/ForwardHalfAndMint.test.ts b/packages/e2e-contract-tests/playwright/e2e/ForwardHalfAndMint.test.ts index cdd03e2ea0..7420e53780 100644 --- a/packages/e2e-contract-tests/playwright/e2e/ForwardHalfAndMint.test.ts +++ b/packages/e2e-contract-tests/playwright/e2e/ForwardHalfAndMint.test.ts @@ -67,19 +67,25 @@ test.describe('Forward Half ETH and Mint Custom Asset', () => { 'Forward Half And Mint' ); await expectButtonToBeEnabled(forwardHalfAndMintButton); + await page.waitForTimeout(1000); // Wait for slow VM await forwardHalfAndMintButton.click(); + await page.waitForTimeout(1000); // Wait for slow VM const walletNotificationPage = await fuelWalletTestHelper.getWalletPopupPage(); // Test if asset name is defined (not unknown) - checkAriaLabelsContainsText( + await checkAriaLabelsContainsText( walletNotificationPage, 'Asset Name', 'Ethereum' ); // Test if sender name is defined (not unknown) - checkAriaLabelsContainsText(walletNotificationPage, 'Sender Name', ''); + await checkAriaLabelsContainsText( + walletNotificationPage, + 'Sender Name', + '' + ); // test forward asset name is shown await hasText(walletNotificationPage, 'Ethereum'); diff --git a/packages/e2e-contract-tests/playwright/e2e/ForwardHalfCustomAsset.test.ts b/packages/e2e-contract-tests/playwright/e2e/ForwardHalfCustomAsset.test.ts index 4578206e2d..3f9d832b87 100644 --- a/packages/e2e-contract-tests/playwright/e2e/ForwardHalfCustomAsset.test.ts +++ b/packages/e2e-contract-tests/playwright/e2e/ForwardHalfCustomAsset.test.ts @@ -81,19 +81,25 @@ test.describe('Forward Half Custom Asset', () => { 'Forward Half Custom Asset' ); await expectButtonToBeEnabled(forwardHalfCustomAssetButton); + await page.waitForTimeout(1000); // Wait for slow VM await forwardHalfCustomAssetButton.click(); + await page.waitForTimeout(1000); // Wait for slow VM const walletNotificationPage = await fuelWalletTestHelper.getWalletPopupPage(); // Test if asset name is defined (not unknown) - checkAriaLabelsContainsText( + await checkAriaLabelsContainsText( walletNotificationPage, 'Asset Name', 'Ethereum' ); // Test if sender name is defined (not unknown) - checkAriaLabelsContainsText(walletNotificationPage, 'Sender Name', ''); + await checkAriaLabelsContainsText( + walletNotificationPage, + 'Sender Name', + '' + ); // test the forward asset name is shown await hasText(walletNotificationPage, 'Unknown', 0, 5000, true); // test forward asset id is correct diff --git a/packages/e2e-contract-tests/playwright/e2e/MintAsset.test.ts b/packages/e2e-contract-tests/playwright/e2e/MintAsset.test.ts index 4656ae4999..6b4306aa75 100644 --- a/packages/e2e-contract-tests/playwright/e2e/MintAsset.test.ts +++ b/packages/e2e-contract-tests/playwright/e2e/MintAsset.test.ts @@ -62,6 +62,8 @@ test.describe('Mint Assets', () => { // test asset is correct const assetId = calculateAssetId(MAIN_CONTRACT_ID, await getBaseAssetId()); + await page.waitForTimeout(10000); // Wait for slow VM + const walletNotificationPage = await fuelWalletTestHelper.getWalletPopupPage(); // short address function copied from app package @@ -126,20 +128,25 @@ test.describe('Mint Assets', () => { const mintButton = getButtonByText(page, 'Mint Asset configuration'); await expectButtonToBeEnabled(mintButton); + await page.waitForTimeout(1000); // Wait for slow VM await mintButton.click(); - + await page.waitForTimeout(1000); // Wait for slow VM // test asset is correct const walletNotificationPage = await fuelWalletTestHelper.getWalletPopupPage(); // Test if asset name is defined (not unknown) - checkAriaLabelsContainsText( + await checkAriaLabelsContainsText( walletNotificationPage, 'Asset Name', 'Ethereum' ); // Test if sender name is defined (not unknown) - checkAriaLabelsContainsText(walletNotificationPage, 'Sender Name', ''); + await checkAriaLabelsContainsText( + walletNotificationPage, + 'Sender Name', + '' + ); // scroll to bottom of page to ensure all text is visible await walletNotificationPage.evaluate(() => diff --git a/packages/e2e-contract-tests/playwright/e2e/utils/elements.ts b/packages/e2e-contract-tests/playwright/e2e/utils/elements.ts index c5dbeae4eb..11ec72c459 100644 --- a/packages/e2e-contract-tests/playwright/e2e/utils/elements.ts +++ b/packages/e2e-contract-tests/playwright/e2e/utils/elements.ts @@ -1,4 +1,4 @@ -import type { Page } from '@playwright/test'; +import { type Page, expect } from '@playwright/test'; export async function checkAriaLabelsContainsText( walletNotificationPage: Page, @@ -9,10 +9,11 @@ export async function checkAriaLabelsContainsText( const count = await locator.count(); for (let i = 0; i < count; i++) { + const innerHTML = await locator.nth(i).innerHTML(); if (text === '') { - expect(locator.nth(i).innerHTML()).not.toBe(''); + await expect(innerHTML).not.toBe(''); } else { - expect((await locator.nth(i).innerHTML()).includes(text)).toBeTruthy(); + await expect(innerHTML.includes(text)).toBeTruthy(); } } } diff --git a/packages/e2e-contract-tests/playwright/e2e/utils/transaction.ts b/packages/e2e-contract-tests/playwright/e2e/utils/transaction.ts index 922b83aadb..282c401c69 100644 --- a/packages/e2e-contract-tests/playwright/e2e/utils/transaction.ts +++ b/packages/e2e-contract-tests/playwright/e2e/utils/transaction.ts @@ -1,4 +1,5 @@ import { getByAriaLabel, hasText } from '@fuels/playwright-utils'; +import type { FuelWalletTestHelper } from '@fuels/playwright-utils'; import type { Page } from '@playwright/test'; import { expect } from '@playwright/test'; import type { BN } from 'fuels'; @@ -15,5 +16,13 @@ export const checkFee = async ( }; export const waitSuccessTransaction = async (page: Page) => { - await hasText(page, 'Transaction successful.', 0, 15000); + await expect + .poll( + () => + hasText(page, 'Transaction successful.') + .then(() => true) + .catch(() => false), + { timeout: 15000 } + ) + .toBeTruthy(); }; diff --git a/packages/playwright-utils/src/playwright-utils/fuelWalletTestHelper.ts b/packages/playwright-utils/src/playwright-utils/fuelWalletTestHelper.ts index ba6d63b972..2708c74901 100644 --- a/packages/playwright-utils/src/playwright-utils/fuelWalletTestHelper.ts +++ b/packages/playwright-utils/src/playwright-utils/fuelWalletTestHelper.ts @@ -1,4 +1,4 @@ -import type { BrowserContext, Locator } from '@playwright/test'; +import type { BrowserContext, Locator, Page } from '@playwright/test'; import { expect } from '../fixtures'; import { FUEL_MNEMONIC, FUEL_WALLET_PASSWORD } from '../mocks'; @@ -133,22 +133,47 @@ export class FuelWalletTestHelper { await approveButton.click(); } - async getWalletPopupPage() { + async getWalletPopupPage(): Promise { + console.log( + '🔍 Searching for existing wallet popup page in', + this.context.pages().map((page) => page.url()) + ); + console.log(`Timestamp: ${Date.now()}`); let walletNotificationPage = this.context.pages().find((page) => { const url = page.url(); return url.includes('/popup.html?'); }); if (!walletNotificationPage) { + console.log('⏳ No existing popup found, waiting for popup event...'); walletNotificationPage = await this.context.waitForEvent('page', { predicate: (page) => page.url().includes('/popup'), - timeout: 5000, + timeout: 30000, }); + console.log( + '🔍 Searching for existing wallet popup page in', + this.context.pages().map((page) => page.url()) + ); + console.log(`Timestamp: ${Date.now()}`); + // If the popup is not found, try to find it in the pages again + if (!walletNotificationPage) { + walletNotificationPage = this.context.pages().find((page) => { + const url = page.url(); + return url.includes('/popup.html?'); + }); + } } - if (!walletNotificationPage) { - throw new Error('Wallet popup not found!'); + console.log( + '🔍 No popup found in', + this.context.pages().map((page) => page.url()) + ); + throw new Error('No popup found'); } + console.log( + '🔍 Returning popup page with URL:', + walletNotificationPage?.url() + ); return walletNotificationPage; }