Skip to content

Conversation

@TaprootFreak
Copy link
Collaborator

Summary

  • Add infrastructure for running E2E tests with a real MetaMask browser extension
  • Use Chrome 126 (last version with Manifest V2 support) to bypass Chrome 127+ MV2 deprecation
  • Custom Playwright fixtures that bypass Synpress's buggy cache system
  • Bilingual wallet setup automation (supports both English and German UI)
  • EIP-5792 gasless transaction test suite ready for testing

Changes

New Files

File Purpose
e2e/synpress/custom-fixtures.ts Playwright fixtures with Chrome 126 + MetaMask extension loading
e2e/synpress/eip5792-custom.spec.ts E2E tests for EIP-5792 wallet_sendCalls flow
e2e/synpress/metamask-setup-test.spec.ts Debug test for MetaMask wallet setup verification
playwright.synpress.config.ts Playwright config for MetaMask E2E tests
playwright.metamask-debug.config.ts Debug config without webserver dependency

NPM Scripts

npm run synpress:setup         # Install Chrome 126 + download MetaMask 11.9.1
npm run test:e2e:metamask      # Run E2E tests with real MetaMask

Technical Details

The main challenge was that Synpress v4.1.1 bundles MetaMask 11.9.1 (Manifest V2), but Chrome 127+ has deprecated Manifest V2 extensions.

Solution: Use @puppeteer/browsers to install Chrome 126 (last MV2-supporting version) and chromium.launchPersistentContext() with --load-extension flag to manually load the MetaMask extension.

The wallet setup automation handles both English and German MetaMask UI, making it work regardless of system locale.

Test plan

  • Verify Chrome 126 installs correctly via npm run synpress:setup
  • Verify MetaMask 11.9.1 downloads and extracts
  • Verify wallet setup automation completes successfully
  • Verify screenshots are captured at each step
  • Run full E2E tests with webserver (npm run test:e2e:metamask)

Add infrastructure for running E2E tests with a real MetaMask extension:

- Use Chrome 126 (last version with Manifest V2 support)
- Download MetaMask 11.9.1 extension automatically
- Custom Playwright fixtures that bypass Synpress cache issues
- Bilingual wallet setup (English + German UI support)
- EIP-5792 gasless transaction test suite

New files:
- e2e/synpress/custom-fixtures.ts: Chrome 126 + MetaMask fixtures
- e2e/synpress/eip5792-custom.spec.ts: EIP-5792 E2E tests
- e2e/synpress/metamask-setup-test.spec.ts: Debug test for wallet setup
- playwright.synpress.config.ts: Config for MetaMask tests
- playwright.metamask-debug.config.ts: Debug config without webserver

NPM scripts:
- npm run synpress:setup: Install Chrome 126 + download MetaMask
- npm run test:e2e:metamask: Run E2E tests with real MetaMask

This approach solves the Manifest V2 deprecation issue in Chrome 127+
by using Chrome 126 with launchPersistentContext() for extension loading.
@TaprootFreak TaprootFreak merged commit 2d8d21d into develop Jan 5, 2026
1 check passed
@TaprootFreak TaprootFreak deleted the feature/real-metamask-e2e-tests branch January 5, 2026 01:01
TaprootFreak added a commit that referenced this pull request Jan 6, 2026
* Handle optional remittanceInfo for buy-specific IBANs (#789)

* Handle optional remittanceInfo for buy-specific IBANs

- Conditionally show Reference row only when remittanceInfo is present
- Update info text to explain that unique IBAN requires no reference

* [NO-TASK] Added translations

---------

Co-authored-by: David May <david.leo.may@gmail.com>

* Auto-select bank account when only one exists (#798)

* refactor: Blockchain-Calls über DFX API (#797)

* refactor: use DFX API for blockchain balance and transaction operations

- Replace direct Tatum/Alchemy calls with DFX API endpoints
- Add blockchain-balance.hook.ts for balance queries via API
- Add blockchain-transaction.hook.ts for transaction creation via API
- Refactor solana.hook.ts to use API for TX creation and broadcasting
- Refactor tron.hook.ts to use API for TX creation and broadcasting
- Update wallet hooks (phantom, trust-sol, trust-trx, tronlink-trx) to broadcast via API
- Remove alchemy.hook.ts (no longer needed)
- Remove Tatum/Alchemy ENV variables from .env files

* fix: add proper Tron Transaction types for wallet signing

* Add local development documentation (#793)

* Add local development documentation and service worker fix

- Add Local Development section to README
- Copy custom-service-worker.js to public/ for local dev mode

* Move service worker to public/ for cleaner setup

- Remove src/custom-service-worker.js (duplicate)
- Keep only public/custom-service-worker.js (single source of truth)
- Remove cp commands from build scripts (public/ auto-copies to build/)

* Display bank account details on refund page (#788)

* Display bank account details on refund page

- Show name, address, city, country, IBAN, BIC fields
- Fields are conditionally rendered when available from API

* [NO-TASK] Updated package

---------

Co-authored-by: David May <david.leo.may@gmail.com>

* refactor: remove Sift fraud detection integration (#796)

- Delete sift.hook.ts and global.d.ts type declarations
- Remove useSift() from layout.tsx
- Remove Sift CDN script from index.html
- Remove REACT_APP_SIFT_BEACON_KEY from env files
- Remove Sift key replacement steps from CI workflows

* Remove deprecated my-dfx route and payment portal integration (#794)

* refactor: move static URLs from env to config (#795)

- Create src/config/urls.ts with static DFX URLs
- Remove REACT_APP_DFX_URL, REACT_APP_TNC_URL, REACT_APP_PPO_URL,
  REACT_APP_IMP_URL, REACT_APP_REF_URL, REACT_APP_TG_URL_DE,
  REACT_APP_TG_URL_EN from .env files
- Update all components and screens to use Urls config

* refactor: remove unused Alchemy and Tatum environment variables (#800)

- Remove REACT_APP_ALCHEMY_KEY from all env files
- Remove REACT_APP_TATUM_KEY from all env files
- These were replaced by DFX API calls in previous refactoring
- Keep REACT_APP_WC_PID as it's still used by WalletConnect

* Fix infinite loop in account screen (#799)

Remove session.role from useEffect dependencies as it was causing unnecessary re-renders when session object changed. The effect should only run when login status changes, not when session properties update.

* Move WalletConnect Project ID from env to config (#803)

- Hardcode WalletConnect Project ID in wagmi.config.ts
- Remove dependency on REACT_APP_WC_PID environment variable
- Update .env.loc template to remove WC_PID requirement
- Simplify configuration by centralizing Project ID

* Add version endpoint for services (#805)

- Add /version.json endpoint to expose version info
- Generate version.json with commit, branch, version, and build time
- Integrate version generation into build scripts

* Disable credit card payment option (#763)

- Remove credit card from available payment methods
- Remove payment method dropdown (only bank transfer available)
- Clean up unused imports and variables

* Centralize API configuration (#806)

* Centralize API configuration

- Create central API config file at src/config/api.ts
- Replace all process.env.REACT_APP_API_VERSION usages with Api.version
- Replace hardcoded /v1/ paths with Api.version
- Remove REACT_APP_API_VERSION from all .env files
- Consolidate API URL references to use Api.url

This improves maintainability by having a single source of truth for API configuration instead of mixing environment variables and hardcoded values.

* Remove unused REACT_APP_WC_PID from env files

The WalletConnect project ID is hardcoded in wagmi.config.ts and this environment variable is not referenced anywhere in the codebase.

* Fix local API URL to point to localhost instead of production

* Add E2E tests and unit tests for multi-blockchain trading (#807)

E2E Tests (Playwright):
- Buy/Sell/Swap API tests for EVM, Bitcoin, Solana, Tron
- Multi-blockchain authentication tests
- Visual regression and responsive design tests
- Navigation and accessibility tests
- Auth caching with mutex and exponential backoff to prevent rate limiting

Unit Tests (Jest):
- Hook tests: useChange, useIframe, useResizeObserver, etc.
- Utility tests: AbortError, TranslatedError, WalletSwitchError
- Config tests: labels, lnurl, evm, chart, stack

Configuration:
- playwright.config.ts with serial execution (single worker)
- e2e/tsconfig.json for Playwright
- Updated .eslintrc.js for e2e directory
- Added test dependencies

Coverage: ~95% by trading volume

* Fix open-crypto-pay test mocking for CI environment (#808)

* Update E2E snapshots and configuration (#810)

- Add .env.e2e for E2E test environment configuration
- Update sell-process.spec.ts test
- Regenerate Chromium snapshots for sell and swap pages
- Update playwright.config.ts
- Update dependencies in package.json

* Fix visual regression tests to use authentication (#811)

* Fix visual regression tests to use authentication

- Add auth for protected pages (buy, sell, swap, account, settings, kyc)
- Public pages (homepage, login, support) remain without auth
- Regenerate snapshots with correct authenticated content

* Remove snapshots from gitignore to version visual regression baselines

* Add default amount 0.1 ETH for sell/swap and Sepolia E2E tests (#812)

* Add default amount 0.1 for ETH on sell page

* Move test-results to e2e folder and add sell page snapshot

* Update sell page snapshot with default amount 0.1 ETH

* Fix responsive tests to use authentication for buy page

* Add default amount 0.1 for ETH on swap page

* Fix sell UI tests to use cached token and update snapshot

* Add Sepolia ETH sell tests (skipped if not available)

* Add real Sepolia ETH sell transaction test

* Add Sepolia USDT sell tests

* Add real Sepolia USDT sell transaction test

* Add EIP-7702 delegation support for gasless Sell and Swap transactions (#802)

Features:
- Add signEip7702Delegation in metamask.hook.ts for EIP-712 delegation + EIP-7702 authorization signing
- Add useEip7702 hook with isSupported check for supported blockchains
- Update tx-helper.hook.ts to detect depositTx.eip7702 and use delegation flow
- Update sell.screen.tsx and swap.screen.tsx to request depositTx only on button click (includeTx parameter)
- Add payment-info.tsx component with EIP-7702 transaction handling

E2E Tests:
- Refactor screenshot storage to single e2e/screenshots/ folder
- Add Sepolia ETH and USDT sell UI flow tests with wallet button interaction
- Consolidate redundant test files (removed visual-regression.spec.ts, homepage.spec.ts)

Code Quality:
- Import EIP-7702 types from @dfx.swiss/react (single source of truth)
- Remove duplicate type definitions from hooks

* Migrate API tests from Playwright to Jest (#813)

* Migrate API tests from Playwright to Jest

- Extract API integration tests from Playwright E2E tests into separate Jest test suite
- Add new Jest API tests: auth, buy, sell, swap (32 tests total)
- Restrict Playwright to Chromium only (remove Firefox, WebKit, mobile browsers)
- Keep only UI flow tests in Playwright files
- Add npm scripts: test:api, test:e2e, test:all

Benefits:
- API tests run once instead of 5x (per browser)
- No screenshots/traces generated for API tests
- Faster test execution (~10s for API tests)
- Reduced test artifacts

* Clean up Playwright tests and reduce artifacts

- Remove unused variables from Playwright test files
- Remove unused TestCredentials import
- Change trace/screenshot settings to 'retain-on-failure' to reduce artifacts
- Change video setting to 'retain-on-failure'

* Fix CI: add testPathIgnorePatterns for helper files

* Fix test timeouts for multi-asset/currency tests

* Fix ESLint warnings: remove non-null assertions

* Fix test timeouts: use third parameter instead of jest.setTimeout

* Add E2E tests for blockchain transaction confirmation (#815)

- Add sepolia-transaction.ts helper with TransactionRevertedError
  and TransactionTimeoutError for proper error handling
- Add blockchain-transactions.spec.ts with tests for:
  - Sending real ETH on Sepolia testnet
  - Verifying transaction confirmation on blockchain
  - Throwing TransactionRevertedError when receipt.status === 0
  - Throwing TransactionTimeoutError on confirmation timeout
- Tests fail properly when a transaction is reverted (not just confirmed)

* Fix E2E sell flow test to use real DFX deposit address (#816)

- Authenticate and get Sepolia ETH asset dynamically (not hardcoded ID)
- Create PaymentInfo via API to get real deposit address
- Send ETH to actual DFX deposit address instead of self
- Remove swap test (not possible on Sepolia - no buyable assets)
- All 8 tests now pass with real blockchain verification

* Fix gitignore pattern for test-results directory (#817)

Remove leading slash from test-results/ and playwright-report/
patterns to match files in subdirectories like e2e/test-results/

* Fix E2E test stability issues (#818)

* Fix E2E test stability issues

- Add missing blockchain parameter to trading flow URLs
- Skip unrealistic rapid navigation test
- Increase maxDiffPixels tolerance for visual regression tests
- Update screenshot baselines

* Remove unrealistic rapid navigation test

* Add missing blockchain parameter to responsive test URLs

* Add blockchain parameter to all E2E test URLs

- buy-process.spec.ts: Add &blockchain=Ethereum to all buy URLs
- sell-process.spec.ts: Add &blockchain=Ethereum to sell URLs (non-Sepolia tests)
- swap-process.spec.ts: Add &blockchain=Ethereum to all swap URLs
- login-process.spec.ts: Add &blockchain=Ethereum to buy URLs
- Update screenshot baselines for corrected URLs

* Fix swap-process test to check for actual page text content

The test was checking for ETH/USDT in page.textContent() but these
values are in input fields, not text nodes. Changed to check for
actual visible text like 'Du zahlst', 'Du erhältst', 'Swap'.

* Fix swap tests with correct asset-in/asset-out URL parameters

- Add asset-in=USDT and asset-out=ETH to all swap URLs
- Use amount-in instead of amountIn for URL parameter
- Update test assertions to verify assets are properly selected
- Regenerate swap screenshot baselines with correct asset selection

* Update all screenshot baselines

* Fix swap default amount bug and update tests

Feature fix:
- swap.screen.tsx: Set default amount for all assets, not just ETH
  - ETH/native tokens: 0.1 (like sell page)
  - Stablecoins (USDT, USDC, DAI, ZCHF, dEURO, XCHF): 100

Test updates:
- Use ETH as source asset (consistent with sell tests)
- Use USDT as target asset
- Verify default 0.1 amount is set automatically

* Update screenshot baselines

* Configure Playwright to always save screenshots, videos and traces

* Fix swap visual regression test to wait for exchange rate

Wait for 'Wechselkurs' element before taking screenshot to ensure
the quote has loaded (like sell page)

* Fix Sepolia USDT sell test to wait for exchange rate before screenshot

* Make swap tests resilient to slow API responses

- Add try-catch for Wechselkurs wait to handle API timeouts gracefully
- Increase timeout to 60s for trading-flows swap test
- Update screenshot baselines

* Skip flaky swap visual regression tests due to unreliable API

* fix: address race condition in buy/sell/swap screens

Add addressItems.length to useEffect dependencies to ensure setAddress()
is called after addressItems are loaded. This fixes a race condition
where the address form field was never set, preventing API calls from
being made.

Root cause: setAddress() was called before assets loaded, addressItems
was empty, so the address was never set in the form. Without a valid
address, validateData() returned undefined and receiveFor() was never
called.

Also re-enables previously skipped swap E2E tests that now pass.

* Fix E2E tests: add proper waiting for exchange rate before screenshots

- Add waitForSelector('text=Wechselkurs') to buy tests in responsive.spec.ts
- Add waitForSelector('text=Wechselkurs') to buy/sell visual regression tests in trading-flows.spec.ts
- Update buy-tablet and buy-flow-page screenshots with correct data

The screenshots were capturing incomplete loading states because tests
weren't waiting for the exchange rate data to load before taking screenshots.

* Fix transaction button throwing error when EIP-7702 not available (#819)

* Fix transaction button throwing error when EIP-7702 not available

The "Complete transaction in your wallet" button was throwing an
unhandled error when the EIP-7702 flow conditions were not met
(e.g., user has gas, no delegation data, or unsupported blockchain).

Instead of throwing an error, now calls closeServices() to pass
the payment info back to the user so they can complete the
transaction manually - consistent with existing behavior.

Also removes unused imports (UnsignedTx, Eip7702DelegationData).

* Fix transaction button throwing error when EIP-7702 not available

The "Complete transaction in your wallet" button was throwing an
unhandled error when the EIP-7702 flow conditions were not met.

Changes:
- Replace throw Error with closeServices() for graceful fallback
- Add userAddress check to EIP-7702 condition instead of throwing
- Remove unused imports (UnsignedTx, Eip7702DelegationData)

Now all edge cases fall back to closeServices(), letting the user
complete the transaction manually with the payment info.

* Fix sell screen showing completion on transaction failure (#822)

* Fix sell screen showing completion on transaction failure

Previously, when a transaction failed (e.g., user rejected in wallet or
network error), the sell screen would show the completion screen without
the deposit address, misleading users into thinking the transaction succeeded.

Changes:
- Move setTxDone(true) back into try block (only on success)
- Silently return when user rejects in wallet (error code 4001)
- Show error message for other failures so user can send manually
- Add translations for error message (DE, FR, IT)

* fix: improve error message to guide user to Retry button

The deposit address is hidden when errorMessage is set (due to JSX
condition !errorMessage). Changed message to tell user to click Retry
to see the deposit address, instead of referencing 'address above'
which isn't visible in error state.

* Remove console.error from tx-helper hook (#823)

The error is already handled gracefully by returning undefined.
No error tracking system is in use, so logging to console serves no purpose
and may expose internal details to end users in browser console.

* Fix EIP-7702 authorization nonce bug (#824)

* Fix EIP-7702 authorization nonce and add tests

- Use userNonce from API response instead of hardcoded 0
- Use delegatorAddress instead of delegationManagerAddress for authorization
- Update @dfx.swiss/react to 1.3.0-beta.225 (includes userNonce type)
- Add comprehensive unit tests for EIP-7702 signing logic

* Add comprehensive EIP-7702 test suite (51 tests)

Tests added:
- eip7702.hook.test.ts (14 tests): isSupported() blockchain validation, signEip7702Data wrapper
- eip7702-signing.test.ts (12 tests): userNonce usage, signature parsing, error handling
- tx-helper-eip7702.test.ts (18 tests): Sell/Swap with EIP-7702, error cases, transaction flow

Total EIP-7702 test coverage: 51 tests across 4 test files

* Add MetaMask RPC call parameter tests (5 additional tests)

Tests verify:
- Delegation sign request structure (eth_signTypedData_v4)
- Authorization sign request structure
- EIP-712 required fields for both requests
- Consistent chainId across domain and message

Total: 56 EIP-7702 tests

* Add UI state management tests for EIP-7702 flow

Adds 2 additional tests covering isProcessingTransaction state:
- Verify state is set to true before EIP-7702 signing
- Verify state is reset to false even when signing fails

Total EIP-7702 test coverage: 58 tests across 4 test files.

* Fix EIP-7702 authorization to use native format instead of EIP-712

BREAKING: Authorization signing now uses native EIP-7702 format.

The previous implementation incorrectly used eth_signTypedData_v4 (EIP-712)
for authorization signatures, which produces:
  sign(keccak256(0x1901 || domainSeparator || structHash))

EIP-7702 requires native format:
  sign(keccak256(0x05 || RLP([chainId, address, nonce])))

Changes:
- Use viem's toRlp, keccak256, concat for hash construction
- Use eth_sign instead of eth_signTypedData_v4 for authorization
- Add error handling for disabled eth_sign with helpful message
- Update tests to verify native EIP-7702 format

Note: Users must enable eth_sign in MetaMask settings for this to work:
Settings > Advanced > Eth_sign requests

* Disable EIP-7702 delegation for sell/swap transactions (#826)

The manual signing approach (eth_sign + eth_signTypedData_v4) doesn't work
because eth_sign is disabled by default in MetaMask. This needs to be
re-implemented using Pimlico's ERC-7677 paymaster service.

Changes:
- sendSellTransaction/sendSwapTransaction now always use normal closeServices flow
- tx-helper.hook.ts EIP-7702 block commented out

* feat: enable EIP-7702 gasless transaction flow (#827)

* feat: enable EIP-7702 gasless transaction flow

- Enable EIP-7702 flow in tx-helper.hook.ts for MetaMask
- Extend supported chains: add Optimism, BSC, Gnosis
- Add wallet capabilities detection (wallet_getCapabilities)
- Add proper null checks for confirmSell/confirmSwap results

When backend provides EIP-7702 data (user has no ETH for gas),
frontend signs delegation + authorization and sends to backend
for gasless execution via relayer.

* test: add tests for checkWalletCapabilities and isEthSignEnabled

- Add tests for EIP-5792 wallet_getCapabilities integration
- Add tests for isEthSignEnabled account checking
- Cover MetaMask detection, error handling, and edge cases

* feat: implement EIP-5792 wallet_sendCalls for gasless transactions

Replace EIP-7702 eth_sign approach with EIP-5792 wallet_sendCalls
that uses paymasterService capability for gasless transactions.

Changes:
- Add sendCallsWithPaymaster() and supportsEip5792Paymaster() to metamask.hook.ts
- Update tx-helper.hook.ts to use EIP-5792 flow when eip5792 data is present
- Remove eip7702.hook.ts and related eth_sign code
- Remove obsolete EIP-7702 tests
- Update @dfx.swiss/react to ^1.3.0-beta.227 for new EIP-5792 types

The new flow:
1. Check if transaction has eip5792 data (paymasterUrl, calls)
2. Use wallet_sendCalls with paymasterService capability
3. Wait for transaction confirmation via wallet_getCallsStatus
4. Confirm with backend using txHash

This avoids eth_sign which is disabled by default in MetaMask.

* chore: remove obsolete tx-helper-eip7702 test file

* test: add EIP-5792 wallet_sendCalls flow tests

- Test supportsEip5792Paymaster capability detection
- Test sendCallsWithPaymaster transaction flow
- Test wallet_getCallsStatus polling and confirmation
- Test different chain IDs (Ethereum, Optimism, Polygon, Arbitrum, Base)
- Test error handling (user rejection, pending request)
- Test EIP-5792 data structure validation

* test: add useMetaMask hook tests for wallet detection

- Test isInstalled for MetaMask, Rabby, CoinbaseWallet, Trust wallet
- Test getWalletType detection
- Test hook interface exposes EIP-5792 functions

Note: EIP-5792 flow logic is tested in eip5792-flow.test.ts with
isolated mocks due to Web3 mocking complexity with React hooks.

* test: add comprehensive EIP-5792 gasless flow tests

Add three types of tests for the EIP-5792 wallet_sendCalls flow:

1. E2E Tests (e2e/eip5792-gasless-sell.spec.ts)
   - Mock ethereum provider injection for Playwright
   - wallet_getCapabilities detection tests
   - wallet_sendCalls with paymasterService tests
   - Error handling (rejection, timeout, failure)
   - Multi-chain support (Ethereum, Optimism, Polygon, Arbitrum, Base)

2. Component Tests (src/__tests__/eip5792-component.test.ts)
   - Transaction flow logic verification
   - Sell and swap transaction handling
   - Multi-chain EIP-5792 support
   - Data validation (paymasterUrl, calls, chainId)
   - Error scenarios (user rejection, timeout, service unavailable)

3. Integration Tests (src/__tests__/eip5792-integration.test.ts)
   - Full Web3 provider mock
   - wallet_getCapabilities parsing
   - wallet_sendCalls execution
   - wallet_getCallsStatus polling
   - Complete gasless transaction flow simulation
   - ERC20 transfer encoding
   - Chain ID handling for all supported networks

Total: 57 passing tests for EIP-5792 gasless transactions

* feat: redirect users to specific KYC steps for trading errors (#829)

* feat: redirect users to specific KYC steps for trading errors

Handle new transaction errors from API:
- RECOMMENDATION_REQUIRED: redirect to RECOMMENDATION step
- EMAIL_REQUIRED: redirect to CONTACT_DATA step

Changes:
- quote-error-hint.tsx: Added hint texts and buttons for new error types
- order.hook.ts: Added new errors to KYC error handling
- buy.screen.tsx: Added new errors to KYC error handling
- sell.screen.tsx: Added new errors to KYC error handling
- swap.screen.tsx: Added new errors to KYC error handling
- buy-info.screen.tsx: Added new errors to KYC error handling
- sell-info.screen.tsx: Added new errors to KYC error handling
- Updated tests to accept new error messages

Instead of showing a generic error, users are now directed
to the specific KYC step they need to complete.

* chore: update @dfx.swiss/react to 1.3.0-beta.228

* feat: add Synpress E2E test infrastructure for real MetaMask testing (#830)

* feat: add Synpress E2E test infrastructure for real MetaMask testing

Add E2E test setup using Synpress for testing EIP-5792 gasless transactions
with real MetaMask wallet interactions.

Files added:
- playwright.synpress.config.ts: Separate Playwright config for Synpress tests
- e2e/synpress/eip5792-real-metamask.spec.ts: Real MetaMask E2E tests
- e2e/synpress/fixtures.ts: Reusable test fixtures
- e2e/wallet-setup/basic.setup.ts: MetaMask wallet setup configuration
- test/wallet-setup/basic.setup.ts: Default wallet setup location

Note: Synpress v4 currently has known issues:
- Cache hash mismatch (GitHub issue #1103)
- MetaMask 11.9.1 uses Manifest V2 (not supported in Chrome 127+)

These tests are prepared for when Synpress fixes these issues.

* test: add tests for RECOMMENDATION_REQUIRED and EMAIL_REQUIRED errors

Unit tests (9 passing):
- quote-error-hint.tsx: hint text, buttons, startStep calls
- Covers RECOMMENDATION_REQUIRED, EMAIL_REQUIRED, TRADING_NOT_ALLOWED
- Tests for BUY, SELL, SWAP transaction types

E2E tests:
- kyc-redirect.spec.ts: trading restriction flow
- Navigation to RECOMMENDATION and CONTACT_DATA KYC steps

* feat: add real MetaMask E2E tests with Chrome 126 (#831)

Add infrastructure for running E2E tests with a real MetaMask extension:

- Use Chrome 126 (last version with Manifest V2 support)
- Download MetaMask 11.9.1 extension automatically
- Custom Playwright fixtures that bypass Synpress cache issues
- Bilingual wallet setup (English + German UI support)
- EIP-5792 gasless transaction test suite

New files:
- e2e/synpress/custom-fixtures.ts: Chrome 126 + MetaMask fixtures
- e2e/synpress/eip5792-custom.spec.ts: EIP-5792 E2E tests
- e2e/synpress/metamask-setup-test.spec.ts: Debug test for wallet setup
- playwright.synpress.config.ts: Config for MetaMask tests
- playwright.metamask-debug.config.ts: Debug config without webserver

NPM scripts:
- npm run synpress:setup: Install Chrome 126 + download MetaMask
- npm run test:e2e:metamask: Run E2E tests with real MetaMask

This approach solves the Manifest V2 deprecation issue in Chrome 127+
by using Chrome 126 with launchPersistentContext() for extension loading.

* test: add real hook tests for EIP-5792 metamask.hook.ts (#828)

* test: add real hook tests for EIP-5792 with full coverage

Add tests that import and test the actual metamask.hook.ts code
using proper jest.mock() setup for all dependencies.

Coverage improvement for metamask.hook.ts:
- Statements: 14% → 43% (+29%)
- Branches: 23% → 38% (+15%)
- Functions: 16% → 38% (+22%)
- Lines: 13% → 45% (+32%)

EIP-5792 functions now have real test coverage:
- supportsEip5792Paymaster(): wallet_getCapabilities detection
- waitForCallsStatus(): polling for transaction confirmation
- sendCallsWithPaymaster(): complete gasless flow with paymaster

22 tests covering:
- Paymaster support detection on multiple chains (Ethereum, Optimism, Polygon)
- Successful transaction flow with txHash return
- Error handling (user rejection 4001, pending request -32002, failure)
- Transaction status polling until CONFIRMED
- wallet_sendCalls parameter formatting verification
- Wallet detection (MetaMask, Rabby)

* fix: remove unnecessary type annotations in test file

* feat: add creditor data input fields for bank refunds (#833)

- Add input fields for creditor data (name, address, zip, city, country)
  in the refund form for buy transactions
- Use setTransactionBankRefund API for buy refunds with creditor data
- Keep setTransactionRefundTarget for sell refunds (crypto address only)
- Update @dfx.swiss/react to 1.3.0-beta.229

Allows customers to provide creditor data when requesting refunds for
failed buy transactions via SEPA bank transfer.

* feat: add EIP-7702 gasless signing and transaction flow (#832)

- Add signEip7702Authorization() to metamask.hook.ts for signing
  EIP-7702 authorizations via eth_signTypedData_v4
- Add Eip7702AuthorizationData and SignedEip7702Authorization interfaces
- Update tx-helper.hook.ts to handle gasless transactions:
  - Check for gaslessAvailable and eip7702Authorization from backend
  - Sign authorization and call confirmSell/confirmSwap with signed data
  - Prioritize EIP-7702 flow over EIP-5792 fallback

This enables users with 0 ETH to sell tokens via gasless transactions
where DFX relayer pays the gas fees.

* feat: improve creditor form UX with country dropdown and better layout (#835)

- Replace country text input with searchable StyledSearchDropdown
- Group street/house and zip/city fields with StyledHorizontalStack
- Add autocomplete attributes for better browser autofill support
- Use consistent translation keys from screens/kyc
- Add smallLabel for compact display

* feat(e2e): add dual wallet tests for Sepolia sell flows

Add comprehensive E2E tests using two wallets derived from TEST_SEED:

Wallet 1 (0x482c8a...): Has ETH + USDT
- ETH sell test with gas
- USDT sell test with gas

Wallet 2 (0x6aCA95...): Has USDT only (no ETH)
- Gasless USDT sell via EIP-7702
- Gasless flow detection test

Changes:
- e2e/test-wallet.ts: Add createTestCredentialsWallet2(),
  getTestWalletAddresses(), EVM_DERIVATION_PATH_WALLET2
- e2e/helpers/auth-cache.ts: Add evm-wallet2 type, use localhost API
- e2e/sepolia-dual-wallet.spec.ts: New test suite for both wallets
- Add visual regression screenshots for all flows

* feat(e2e): add Synpress MetaMask tests for Sepolia USDT sell

- Update custom-fixtures.ts to use TEST_SEED from .env.test
- Add dual wallet support with derivation paths (Wallet 1 + Wallet 2)
- Add Sepolia network configuration and test network enabling
- Improve DFX wallet connection flow with login page detection
- Create sepolia-usdt-sell.spec.ts with comprehensive tests:
  - Wallet 1 tests (ETH + USDT with gas)
  - Wallet 2 tests (USDT only, gasless EIP-7702)
  - Integration tests for Sepolia network
  - EIP-7702 capability detection tests
- Update playwright.synpress.config.ts to include new test file

Test wallets:
- Wallet 1: 0x482c8a499c7ac19925a0D2aA3980E1f3C5F19120
- Wallet 2: 0x6aCA95eD0705bAbF3b91fA9212af495510bf8b74

* test(e2e): add tests for fixed IBAN and name display in refund flow (#838)

Add E2E tests that verify bank refunds show IBAN and name as fixed
(non-editable) values from the original bank transaction.

Tests verify:
- No 'Select...' dropdown for IBAN selection
- No 'Add bank account' option
- No input fields for creditor name/address
- REQUEST REFUND button is visible and enabled

* chore: ignore playwright-report-local directory

* chore: update @dfx.swiss/react to 1.3.0-beta.230

Includes fix for bank-refund endpoint URL.

* fix: use simple refund endpoint when IBAN is already fixed (#839)

When refundTarget is already set (fixed IBAN from bankTx), use the
simple /refund endpoint instead of /refund/bank which requires
creditor data that is no longer collected from the user.

* test(e2e): add complete visual regression tests for bank refund flow (#840)

* test(e2e): add complete visual regression tests for bank refund flow

Add 5 visual regression tests covering the entire refund process:

1. Transaction list with failed transaction
2. Transaction details page
3. Refund page with fixed IBAN and name (no editable fields)
4. State after refund submission
5. Transaction list showing "Refund pending" status

Tests verify:
- IBAN and name are displayed as fixed values (not dropdowns/inputs)
- REQUEST REFUND button is enabled when page loads
- Refund status correctly changes to "Refund pending" after submission

Baseline screenshots generated for Chromium on Darwin.

* feat: require address input for bank refunds while keeping IBAN/name fixed

Frontend changes (transaction.screen.tsx):
- Always show address input fields (street, house nr, zip, city, country) for bank refunds
- IBAN is fixed from original bank transaction (not editable)
- Name is fixed from bank transaction (not editable)
- Address data must be entered by user
- Update validation rules: IBAN/name only required if not already fixed
- Update onSubmit: always use bank refund endpoint with address data

E2E tests (refund-flow.spec.ts):
- Test 01: Transaction list with unassigned transaction
- Test 02: Transaction details expanded in list
- Test 03: Refund page showing fixed IBAN/name AND address input fields
- Test 04: Address fields filled with user data

This ensures customers provide complete creditor address information
while IBAN and name remain securely fixed from the original transaction.

* test(e2e): complete bank refund flow with 8 visual regression screenshots

Add comprehensive E2E test covering the entire bank refund process:

1. Transaction list view
2. Transaction details with REQUEST REFUND button
3. Refund page showing fixed IBAN/Name and empty address fields
4. Address fields filled (street, house nr, zip, city)
5. Country dropdown selected (Switzerland)
6. Form ready for submission
7. State after refund submission
8. Transaction list showing 'Refund pending' status

The test verifies that:
- IBAN and Name are displayed as fixed values (from original bank transaction)
- Address fields (street, house nr, zip, city, country) are input fields
- User must fill address data to request refund
- Status correctly changes to 'Refund pending' after submission

* chore: remove old screenshot files

* test(e2e): add BuyCrypto FAIL refund flow visual regression tests (#841)

* test(e2e): add BuyCrypto FAIL refund flow with 8 visual regression screenshots

Add comprehensive E2E test for FiatOutputType.BUY_CRYPTO_FAIL refund process:

1. Transaction list showing failed BuyCrypto transaction
2. Transaction details with CONFIRM REFUND button (not REQUEST REFUND)
3. Refund page showing fixed Name/IBAN and empty address fields
4. Address fields filled (Hauptstrasse 25, 3000 Bern)
5. Country dropdown selected (Switzerland)
6. Form ready for submission
7. State after refund submission
8. Transaction list with updated status

Key differences from BANK_TX_RETURN:
- Button text is 'CONFIRM REFUND' instead of 'REQUEST REFUND' for failed transactions
- FiatOutputType is BUY_CRYPTO_FAIL (failed buy crypto) vs BANK_TX_RETURN (unassigned bank tx)
- Both require address input from user while Name/IBAN are fixed from original bank transaction

* fix(e2e): fix BuyCrypto FAIL test with valid IBAN and proper selector

- Test BankTx had invalid IBAN (CH0000...) causing 'Refund iban not valid' error
- Updated test to use .first() for pending status check (handles multiple transactions)
- All 8 screenshots now show successful refund flow

* fix(e2e): update screenshots with correct transaction amounts

- BankTxReturn now shows '75 CHF' instead of just 'CHF'
- Both tests now pass with proper data display
- Fixed by setting txAmount in test BankTx (was NULL)

* feat(e2e): Add Synpress MetaMask E2E tests for Sepolia USDT sell flow (#842)

* feat(e2e): add Synpress MetaMask E2E test for Sepolia USDT sell flow

Add comprehensive E2E test using Synpress for real MetaMask integration:

- Full MetaMask 11.x wallet setup with seed phrase import
- Network switching to Sepolia testnet
- DFX login flow with MetaMask connect and signature
- KYC flow handling for new users
- USDT sell flow with asset selection and amount entry
- Transaction button click triggers MetaMask popup
- Assertions verify payment info, deposit address, IBAN, exchange rate

Test wallet: 0x482c8a499c7ac19925a0D2aA3980E1f3C5F19120 (Sepolia)

Note: Transaction confirmation in MetaMask popup still being stabilized

* fix(e2e): use waitForEvent and setTimeout to handle MetaMask popup reliably

- Use context.waitForEvent('page') BEFORE clicking transaction button
- Replace activeAppPage.waitForTimeout with setTimeout to avoid crash when page closes
- Add fallback polling if event listener doesn't catch the popup
- More resilient error handling in Step 10 and 11

* feat(e2e): add EIP-7702 gasless sell tests and fix debug screenshot paths (#843)

- Add EIP-7702 gasless sell test for users with USDT but no ETH
- Add eip7702-mock.ts helper with contract constants
- Move debug screenshots to dedicated e2e/screenshots/debug/ folder
- Update .gitignore to exclude debug screenshots and .pid files

* refactor(e2e): move baseline screenshots to dedicated folder (#844)

- Move visual regression baselines to e2e/screenshots/baseline/
- Update playwright.config.ts snapshotDir accordingly
- Structure: baseline/ (tracked), debug/ (gitignored)

* fix(e2e): update sepolia dual wallet screenshots with correct API data (#845)

* fix(e2e): update sepolia dual wallet screenshots with correct API data

Screenshots now correctly show ETH for Wallet 1 ETH sell tests.
Previous screenshots showed incorrect asset due to API_URL mismatch.

Note: .env.test needs API_URL=https://dev.api.dfx.swiss/v1 for tests
to authenticate against the same API as the frontend.

* docs(e2e): add API_URL to .env.test.example

Required for auth-cache to authenticate against the same API as the frontend.

* fix(e2e): add IBAN selection for Wallet 2 tests

- Add selectOrAddTestIban helper to enter test IBAN for new wallets
- Use Playwright-native isEnabled() polling instead of waitForFunction
- Update Wallet 2 screenshots to show selected IBAN
- Add two new screenshots for button click states

* chore: gitignore version.json (generated at build time) (#846)

* feat(e2e): add real blockchain transaction test for Sepolia USDT sell

- Add sepolia-real-tx.spec.ts with full MetaMask popup handling
- Use persistent user data directory for faster test runs
- Handle all MetaMask dialogs: connect, network switch, sign
- Fix USDT contract address in custom-fixtures.ts
- Add test to playwright.synpress.config.ts testMatch

WIP: Transaction button click works but tx hash extraction pending

* fix: improve refund form validation and error handling (#848)

* fix: improve refund form validation and error handling

- Fix address validation: only required for crypto refunds, not bank refunds
- Fix empty string handling for bankDetails.name with trim()
- Fix error navigation: navigate only on success, not in finally block

* fix: correct validation rules for different refund types

- Add isBankRefund flag to distinguish bank refunds from card/crypto refunds
- Make creditor address fields only required for bank refunds
- Fix iban/creditorName validation to only apply for bank refunds

* refactor(e2e): separate wallet setup from real transaction tests (#849)

Split Synpress MetaMask tests into setup and test phases:

- Add setup-wallet.ts: One-time script that imports wallet, connects
  to DFX, and saves state to persistent user data directory
- Simplify sepolia-real-tx.spec.ts: Now only unlocks MetaMask (no full
  setup), reducing test time and flakiness

Benefits:
- Tests run faster (skip wallet import/connect on each run)
- More reliable (fewer MetaMask popup interactions needed)
- Better separation of concerns
- State persists across test runs

Usage:
1. First time: npx ts-node e2e/synpress/setup-wallet.ts
2. Then run tests: npx playwright test --config=playwright.synpress.config.ts

* refactor(ci): remove dead code and optimize workflows (#850)

* refactor(ci): remove dead code and optimize workflows

Remove unused steps from CI/CD workflows:

1. Remove 3 Find-Replace steps (WC_PID, ALCHEMY_KEY, TATUM_KEY)
   - These placeholders don't exist in source code
   - WalletConnect ID is hardcoded in wagmi.config.ts
   - Alchemy/Tatum SDKs are not imported anywhere

2. Replace external npm-get-version-action with native jq
   - Removes dependency on third-party GitHub Action
   - Same functionality: `jq -r .version package.json`

3. Reorder lint before tests (all workflows)
   - Linter runs faster than tests
   - Fail fast on style issues

Impact: -48 lines, faster builds, fewer external dependencies

* perf(ci): add npm caching and optimize PR workflow order

1. Add npm caching to all workflows (setup-node cache: 'npm')
   - Reduces npm ci from ~50s to ~10s on cache hit
   - Cache is shared across workflows

2. Reorder PR workflow: lint → test → build
   - Lint (9s) and test (26s) run before build (2:18)
   - Fail fast on code issues before expensive build step

Expected improvement: ~40s faster on cache hit, ~2min faster on lint/test failures

* perf(ci): reorder dev/prd workflows to lint → test → build

Move lint and test steps before build in deploy workflows for consistency
with PR workflow. This saves ~2:20 on lint/test failures after merge.

* fix(sell/swap): disable includeTx=true due to slow RPC calls (#852)

The includeTx=true parameter causes 87+ second API delays on testnets
due to slow RPC calls in the backend's createDepositTx() method.

Changes:
- sell.screen.tsx: Use existing paymentInfo instead of fetching with includeTx
- swap.screen.tsx: Same fix for swap transactions
- sepolia-real-tx.spec.ts: Improved E2E test with proper login flow,
  popup handling (unlock, connect, sign, confirm), and partial hash detection
- api-timing-test.ts: Diagnostic script to measure API response times
- playwright.synpress.config.ts: Updated test configuration

The standard transaction flow still works correctly without gasless features.
TODO: Re-enable includeTx when backend RPC performance is improved.

* test(e2e): add comprehensive sell flow test with screenshots

Add sell-complete.spec.ts with full test coverage for USDT sell flow:
- Screenshots at every process step (login, wallet selection, amount entry,
  exchange rate, transaction confirmation, success, Etherscan verification)
- Robust MetaMask popup handling (unlock, connect, sign, confirm)
- Pending popup cleanup between test runs
- Gas estimation error handling ("proceed anyway" click)
- Network switch protection (prevents accidental Mainnet switch)

ETH test skipped due to app-side issue (attempts Mainnet switch on Sepolia).

Screenshots saved to: e2e/screenshots/sell-complete/

* Small fixes

* fix(screens): handle API errors as KYC errors in trading screens (#853)

* fix(screens): handle API errors as KYC errors in trading screens

When the API returns errors like EmailRequired, RecommendationRequired,
or KycRequired as HTTP exceptions instead of response fields, these were
previously shown as generic "Something went wrong" errors.

Now these errors are correctly mapped to TransactionError enum values
and displayed with proper hints and action buttons (e.g., "Enter email"
button for EmailRequired).

Changes:
- Add src/util/api-error.ts with getKycErrorFromMessage() helper
- Update buy.screen.tsx, sell.screen.tsx, swap.screen.tsx to use helper
- Add E2E tests for buy flow with second wallet (BIP-44 derived)
- Add baseline screenshots for wallet 2 tests

* feat(i18n): add translations for email and recommendation required errors

Add German, French and Italian translations for:
- To trade, please enter your email address.
- To trade, you need a recommendation from an existing DFX customer.
- Enter email
- Enter recommendation

* test(e2e): add visual regression test for sell flow (#855)

- Convert sell-complete.spec.ts to use toHaveScreenshot()
- Add 6 baseline screenshots for USDT sell flow
- Mask dynamic content (wallet addresses, exchange rates, TX hashes)
- Baselines committed, test artifacts go to gitignored folders

* Fix account screen loading

* test(e2e): add Etherscan verification to sell flow visual regression (#857)

- Capture TX hash by intercepting ethereum.request calls
- Navigate to Etherscan TX page with actual transaction hash
- Add 07-etherscan-verification baseline screenshot
- Mask dynamic content (TX hash, addresses, timestamps, gas values)
- Fallback to wallet address page if TX hash not captured

---------

Co-authored-by: David May <david.leo.may@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants