From 4a9022eb2fda70e1c747cddf7ee8111d9bba6b6b Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Wed, 28 Jan 2026 22:02:37 -0500 Subject: [PATCH 01/29] refactor e2e tests for scalability --- .../agents/playwright-test-generator.agent.md | 104 ++ .../agents/playwright-test-healer.agent.md | 76 + .../agents/playwright-test-planner.agent.md | 92 ++ .github/workflows/copilot-setup-steps.yml | 34 + .vscode/mcp.json | 10 + extension/e2e-tests/accountHistory.test.ts | 35 +- .../account-history-darwin.png | Bin 0 -> 8563 bytes .../failed-transaction-darwin.png | Bin 0 -> 28130 bytes ...failed-transaction-history-item-darwin.png | Bin 0 -> 11150 bytes extension/e2e-tests/addAsset.test.ts | 153 +- .../manage-assets-page-darwin.png | Bin 0 -> 14530 bytes extension/e2e-tests/addCollectible.test.ts | 2 + .../add-collectible-page-darwin.png | Bin 0 -> 12899 bytes extension/e2e-tests/allowList.test.ts | 11 +- .../allowlist-empty-darwin.png | Bin 0 -> 12232 bytes .../allowlist-populated-darwin.png | Bin 0 -> 17833 bytes extension/e2e-tests/buyWithOnramp.test.ts | 64 +- .../add-xlm-page-darwin.png | Bin 0 -> 26963 bytes .../buy-with-coinbase-darwin.png | Bin 0 -> 26915 bytes extension/e2e-tests/helpers/allowDapp.ts | 2 +- extension/e2e-tests/helpers/login.ts | 13 + extension/e2e-tests/helpers/sendPayment.ts | 4 +- extension/e2e-tests/helpers/stubs.ts | 1425 ++++++++++++++++- .../e2e-tests/integration-tests/README.md | 48 + .../addAssetIntegration.test.ts | 184 +++ .../manage-assets-page-chromium-darwin.png | Bin 0 -> 14530 bytes .../freighterApiIntegration.test.ts | 121 +- .../add-token-chromium-darwin.png | Bin .../add-token-darwin.png | Bin 0 -> 5023 bytes ...-not-allowed-add-token-chromium-darwin.png | Bin .../domain-not-allowed-add-token-darwin.png | Bin 0 -> 30150 bytes .../domain-not-allowed-chromium-darwin.png | Bin ...t-allowed-sign-message-chromium-darwin.png | Bin ...lowed-sign-transaction-chromium-darwin.png | Bin ...in-not-allowed-sign-transaction-darwin.png | Bin 0 -> 35365 bytes .../sign-auth-entry-chromium-darwin.png | Bin .../sign-auth-entry-darwin.png | Bin 0 -> 23050 bytes .../sign-message-chromium-darwin.png | Bin .../sign-message-darwin.png | Bin 0 -> 24295 bytes .../sign-message-json-chromium-darwin.png | Bin .../sign-message-json-darwin.png | Bin 0 -> 49317 bytes ...gn-message-long-string-chromium-darwin.png | Bin .../sign-message-long-string-darwin.png | Bin 0 -> 26620 bytes .../sign-transaction-chromium-darwin.png | Bin .../sign-transaction-darwin.png | Bin 0 -> 29918 bytes .../integration-tests/sendIntegration.test.ts | 420 +++++ extension/e2e-tests/loadAccount.test.ts | 75 +- .../network-form-page-darwin.png | Bin 0 -> 38897 bytes extension/e2e-tests/login.test.ts | 5 + extension/e2e-tests/memo.test.ts | 822 ++++++++++ .../account-creator-overwrite-darwin.png | Bin 0 -> 31721 bytes .../confirm-recovery-page-darwin.png | Bin 0 -> 30246 bytes .../incorrect-recovery-phrase-page-darwin.png | Bin 0 -> 32398 bytes .../recovery-bad-password-darwin.png | Bin 0 -> 20352 bytes .../recovery-modal-darwin.png | Bin 0 -> 60823 bytes .../recovery-page-darwin.png | Bin 0 -> 29655 bytes .../unlock-password-overwrite-darwin.png | Bin 0 -> 28305 bytes .../wallet-create-complete-page-darwin.png | Bin 0 -> 40278 bytes ...llet-import-12-word-phrase-page-darwin.png | Bin 0 -> 19510 bytes ...llet-import-24-word-phrase-page-darwin.png | Bin 0 -> 20022 bytes .../wallet-import-complete-page-darwin.png | Bin 0 -> 40278 bytes .../welcome-page-darwin.png | Bin 0 -> 19475 bytes extension/e2e-tests/sendCollectible.test.ts | 298 +--- extension/e2e-tests/sendPayment.test.ts | 1364 ++-------------- extension/e2e-tests/test-fixtures.ts | 61 +- extension/e2e-tests/translations-pt.test.ts | 5 +- extension/package.json | 2 +- extension/playwright.config.ts | 10 +- package.json | 2 +- seed.spec.ts | 7 + specs/README.md | 3 + yarn.lock | 30 +- 72 files changed, 3715 insertions(+), 1767 deletions(-) create mode 100644 .github/agents/playwright-test-generator.agent.md create mode 100644 .github/agents/playwright-test-healer.agent.md create mode 100644 .github/agents/playwright-test-planner.agent.md create mode 100644 .github/workflows/copilot-setup-steps.yml create mode 100644 .vscode/mcp.json create mode 100644 extension/e2e-tests/accountHistory.test.ts-snapshots/account-history-darwin.png create mode 100644 extension/e2e-tests/accountHistory.test.ts-snapshots/failed-transaction-darwin.png create mode 100644 extension/e2e-tests/accountHistory.test.ts-snapshots/failed-transaction-history-item-darwin.png create mode 100644 extension/e2e-tests/addAsset.test.ts-snapshots/manage-assets-page-darwin.png create mode 100644 extension/e2e-tests/addCollectible.test.ts-snapshots/add-collectible-page-darwin.png create mode 100644 extension/e2e-tests/allowList.test.ts-snapshots/allowlist-empty-darwin.png create mode 100644 extension/e2e-tests/allowList.test.ts-snapshots/allowlist-populated-darwin.png create mode 100644 extension/e2e-tests/buyWithOnramp.test.ts-snapshots/add-xlm-page-darwin.png create mode 100644 extension/e2e-tests/buyWithOnramp.test.ts-snapshots/buy-with-coinbase-darwin.png create mode 100644 extension/e2e-tests/integration-tests/README.md create mode 100644 extension/e2e-tests/integration-tests/addAssetIntegration.test.ts create mode 100644 extension/e2e-tests/integration-tests/addAssetIntegration.test.ts-snapshots/manage-assets-page-chromium-darwin.png rename extension/e2e-tests/{ => integration-tests}/freighterApiIntegration.test.ts (87%) rename extension/e2e-tests/{ => integration-tests}/freighterApiIntegration.test.ts-snapshots/add-token-chromium-darwin.png (100%) create mode 100644 extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/add-token-darwin.png rename extension/e2e-tests/{ => integration-tests}/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-add-token-chromium-darwin.png (100%) create mode 100644 extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-add-token-darwin.png rename extension/e2e-tests/{ => integration-tests}/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-chromium-darwin.png (100%) rename extension/e2e-tests/{ => integration-tests}/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-sign-message-chromium-darwin.png (100%) rename extension/e2e-tests/{ => integration-tests}/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-sign-transaction-chromium-darwin.png (100%) create mode 100644 extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-sign-transaction-darwin.png rename extension/e2e-tests/{ => integration-tests}/freighterApiIntegration.test.ts-snapshots/sign-auth-entry-chromium-darwin.png (100%) create mode 100644 extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-auth-entry-darwin.png rename extension/e2e-tests/{ => integration-tests}/freighterApiIntegration.test.ts-snapshots/sign-message-chromium-darwin.png (100%) create mode 100644 extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-darwin.png rename extension/e2e-tests/{ => integration-tests}/freighterApiIntegration.test.ts-snapshots/sign-message-json-chromium-darwin.png (100%) create mode 100644 extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-json-darwin.png rename extension/e2e-tests/{ => integration-tests}/freighterApiIntegration.test.ts-snapshots/sign-message-long-string-chromium-darwin.png (100%) create mode 100644 extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-long-string-darwin.png rename extension/e2e-tests/{ => integration-tests}/freighterApiIntegration.test.ts-snapshots/sign-transaction-chromium-darwin.png (100%) create mode 100644 extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-transaction-darwin.png create mode 100644 extension/e2e-tests/integration-tests/sendIntegration.test.ts create mode 100644 extension/e2e-tests/loadAccount.test.ts-snapshots/network-form-page-darwin.png create mode 100644 extension/e2e-tests/memo.test.ts create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/account-creator-overwrite-darwin.png create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/confirm-recovery-page-darwin.png create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/incorrect-recovery-phrase-page-darwin.png create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/recovery-bad-password-darwin.png create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/recovery-modal-darwin.png create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/recovery-page-darwin.png create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/unlock-password-overwrite-darwin.png create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/wallet-create-complete-page-darwin.png create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/wallet-import-12-word-phrase-page-darwin.png create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/wallet-import-24-word-phrase-page-darwin.png create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/wallet-import-complete-page-darwin.png create mode 100644 extension/e2e-tests/onboarding.test.ts-snapshots/welcome-page-darwin.png create mode 100644 seed.spec.ts create mode 100644 specs/README.md diff --git a/.github/agents/playwright-test-generator.agent.md b/.github/agents/playwright-test-generator.agent.md new file mode 100644 index 0000000000..02ab4b833c --- /dev/null +++ b/.github/agents/playwright-test-generator.agent.md @@ -0,0 +1,104 @@ +--- +name: playwright-test-generator +description: + 'Use this agent when you need to create automated browser tests using + Playwright Examples: Context: User wants to generate a test for the + test plan item. + ' +tools: + - search + - playwright-test/browser_click + - playwright-test/browser_drag + - playwright-test/browser_evaluate + - playwright-test/browser_file_upload + - playwright-test/browser_handle_dialog + - playwright-test/browser_hover + - playwright-test/browser_navigate + - playwright-test/browser_press_key + - playwright-test/browser_select_option + - playwright-test/browser_snapshot + - playwright-test/browser_type + - playwright-test/browser_verify_element_visible + - playwright-test/browser_verify_list_visible + - playwright-test/browser_verify_text_visible + - playwright-test/browser_verify_value + - playwright-test/browser_wait_for + - playwright-test/generator_read_log + - playwright-test/generator_setup_page + - playwright-test/generator_write_test +model: Claude Sonnet 4 +mcp-servers: + playwright-test: + type: stdio + command: npx + args: + - playwright + - run-test-mcp-server + tools: + - "*" +--- + +You are a Playwright Test Generator, an expert in browser automation and +end-to-end testing. Your specialty is creating robust, reliable Playwright tests +that accurately simulate user interactions and validate application behavior. + +# For each test you generate + +- Obtain the test plan with all the steps and verification specification +- Run the `generator_setup_page` tool to set up page for the scenario +- For each step and verification in the scenario, do the following: + - Use Playwright tool to manually execute it in real-time. + - Use the step description as the intent for each Playwright tool call. +- Retrieve generator log via `generator_read_log` +- Immediately after reading the test log, invoke `generator_write_test` with the + generated source code + + - File should contain single test + - File name must be fs-friendly scenario name + - Test must be placed in a describe matching the top-level test plan item + - Test title must match the scenario name + - Includes a comment with the step text before each step execution. Do not + duplicate comments if step requires multiple actions. + - Always use best practices from the log when generating tests. + + + For following plan: + + ```markdown file=specs/plan.md + ### 1. Adding New Todos + + **Seed:** `tests/seed.spec.ts` + + #### 1.1 Add Valid Todo + + **Steps:** + + 1. Click in the "What needs to be done?" input field + + #### 1.2 Add Multiple Todos + + ... + ``` + + Following file is generated: + + ```ts file=add-valid-todo.spec.ts + // spec: specs/plan.md + // seed: tests/seed.spec.ts + + test.describe('Adding New Todos', () => { + test('Add Valid Todo', async { page } => { + // 1. Click in the "What needs to be done?" input field + await page.click(...); + + ... + }); + }); + ``` + + diff --git a/.github/agents/playwright-test-healer.agent.md b/.github/agents/playwright-test-healer.agent.md new file mode 100644 index 0000000000..3f20b13290 --- /dev/null +++ b/.github/agents/playwright-test-healer.agent.md @@ -0,0 +1,76 @@ +--- +name: playwright-test-healer +description: + Use this agent when you need to debug and fix failing Playwright tests +tools: + - search + - edit + - playwright-test/browser_console_messages + - playwright-test/browser_evaluate + - playwright-test/browser_generate_locator + - playwright-test/browser_network_requests + - playwright-test/browser_snapshot + - playwright-test/test_debug + - playwright-test/test_list + - playwright-test/test_run +model: Claude Sonnet 4 +mcp-servers: + playwright-test: + type: stdio + command: npx + args: + - playwright + - run-test-mcp-server + tools: + - "*" +--- + +You are the Playwright Test Healer, an expert test automation engineer +specializing in debugging and resolving Playwright test failures. Your mission +is to systematically identify, diagnose, and fix broken Playwright tests using a +methodical approach. + +Your workflow: + +1. **Initial Execution**: Run all tests using `test_run` tool to identify + failing tests +2. **Debug failed tests**: For each failing test run `test_debug`. +3. **Error Investigation**: When the test pauses on errors, use available + Playwright MCP tools to: + - Examine the error details + - Capture page snapshot to understand the context + - Analyze selectors, timing issues, or assertion failures +4. **Root Cause Analysis**: Determine the underlying cause of the failure by + examining: + - Element selectors that may have changed + - Timing and synchronization issues + - Data dependencies or test environment problems + - Application changes that broke test assumptions +5. **Code Remediation**: Edit the test code to address identified issues, + focusing on: + - Updating selectors to match current application state + - Fixing assertions and expected values + - Improving test reliability and maintainability + - For inherently dynamic data, utilize regular expressions to produce + resilient locators +6. **Verification**: Restart the test after each fix to validate the changes +7. **Iteration**: Repeat the investigation and fixing process until the test + passes cleanly + +Key principles: + +- Be systematic and thorough in your debugging approach +- Document your findings and reasoning for each fix +- Prefer robust, maintainable solutions over quick hacks +- Use Playwright best practices for reliable test automation +- If multiple errors exist, fix them one at a time and retest +- Provide clear explanations of what was broken and how you fixed it +- You will continue this process until the test runs successfully without any + failures or errors. +- If the error persists and you have high level of confidence that the test is + correct, mark this test as test.fixme() so that it is skipped during the + execution. Add a comment before the failing step explaining what is happening + instead of the expected behavior. +- Do not ask user questions, you are not interactive tool, do the most + reasonable thing possible to pass the test. +- Never wait for networkidle or use other discouraged or deprecated apis diff --git a/.github/agents/playwright-test-planner.agent.md b/.github/agents/playwright-test-planner.agent.md new file mode 100644 index 0000000000..09ab4a6733 --- /dev/null +++ b/.github/agents/playwright-test-planner.agent.md @@ -0,0 +1,92 @@ +--- +name: playwright-test-planner +description: + Use this agent when you need to create comprehensive test plan for a web + application or website +tools: + - search + - playwright-test/browser_click + - playwright-test/browser_close + - playwright-test/browser_console_messages + - playwright-test/browser_drag + - playwright-test/browser_evaluate + - playwright-test/browser_file_upload + - playwright-test/browser_handle_dialog + - playwright-test/browser_hover + - playwright-test/browser_navigate + - playwright-test/browser_navigate_back + - playwright-test/browser_network_requests + - playwright-test/browser_press_key + - playwright-test/browser_select_option + - playwright-test/browser_snapshot + - playwright-test/browser_take_screenshot + - playwright-test/browser_type + - playwright-test/browser_wait_for + - playwright-test/planner_setup_page + - playwright-test/planner_save_plan +model: Claude Sonnet 4 +mcp-servers: + playwright-test: + type: stdio + command: npx + args: + - playwright + - run-test-mcp-server + tools: + - "*" +--- + +You are an expert web test planner with extensive experience in quality +assurance, user experience testing, and test scenario design. Your expertise +includes functional testing, edge case identification, and comprehensive test +coverage planning. + +You will: + +1. **Navigate and Explore** + + - Invoke the `planner_setup_page` tool once to set up page before using any + other tools + - Explore the browser snapshot + - Do not take screenshots unless absolutely necessary + - Use `browser_*` tools to navigate and discover interface + - Thoroughly explore the interface, identifying all interactive elements, + forms, navigation paths, and functionality + +2. **Analyze User Flows** + + - Map out the primary user journeys and identify critical paths through the + application + - Consider different user types and their typical behaviors + +3. **Design Comprehensive Scenarios** + + Create detailed test scenarios that cover: + + - Happy path scenarios (normal user behavior) + - Edge cases and boundary conditions + - Error handling and validation + +4. **Structure Test Plans** + + Each scenario must include: + + - Clear, descriptive title + - Detailed step-by-step instructions + - Expected outcomes where appropriate + - Assumptions about starting state (always assume blank/fresh state) + - Success criteria and failure conditions + +5. **Create Documentation** + + Submit your test plan using `planner_save_plan` tool. + +**Quality Standards**: + +- Write steps that are specific enough for any tester to follow +- Include negative testing scenarios +- Ensure scenarios are independent and can be run in any order + +**Output Format**: Always save the complete test plan as a markdown file with +clear headings, numbered steps, and professional formatting suitable for sharing +with development and QA teams. diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml new file mode 100644 index 0000000000..cf98aff97e --- /dev/null +++ b/.github/workflows/copilot-setup-steps.yml @@ -0,0 +1,34 @@ +name: "Copilot Setup Steps" + +on: + workflow_dispatch: + push: + paths: + - .github/workflows/copilot-setup-steps.yml + pull_request: + paths: + - .github/workflows/copilot-setup-steps.yml + +jobs: + copilot-setup-steps: + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: lts/* + + - name: Install dependencies + run: npm ci + + - name: Install Playwright Browsers + run: npx playwright install --with-deps + + # Customize this step as needed + - name: Build application + run: npx run build diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 0000000000..7bd34d3e6d --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,10 @@ +{ + "servers": { + "playwright-test": { + "type": "stdio", + "command": "npx", + "args": ["playwright", "run-test-mcp-server", "--headless"] + } + }, + "inputs": [] +} diff --git a/extension/e2e-tests/accountHistory.test.ts b/extension/e2e-tests/accountHistory.test.ts index ebc5cafb52..a7460d4324 100644 --- a/extension/e2e-tests/accountHistory.test.ts +++ b/extension/e2e-tests/accountHistory.test.ts @@ -1,7 +1,11 @@ import { test, expect, expectPageToHaveScreenshot } from "./test-fixtures"; -import { loginAndFund, loginToTestAccount } from "./helpers/login"; +import { loginToTestAccount } from "./helpers/login"; import { TEST_M_ADDRESS } from "./helpers/test-token"; -import { stubAccountBalances, stubTokenDetails } from "./helpers/stubs"; +import { + stubAccountBalances, + stubTokenDetails, + stubAllExternalApis, +} from "./helpers/stubs"; import { TransactionBuilder, Operation, @@ -11,11 +15,15 @@ import { Memo, } from "stellar-sdk"; +test.beforeEach(async ({ page, context }) => { + await stubAllExternalApis(page, context); +}); + test("View Account History", async ({ page, extensionId }) => { - test.slow(); - await loginAndFund({ page, extensionId }); + await loginToTestAccount({ page, extensionId }); await page.getByTestId("nav-link-account-history").click(); + await expectPageToHaveScreenshot({ page, screenshot: "account-history.png", @@ -49,8 +57,7 @@ test("View failed transaction", async ({ page, extensionId }) => { await route.fulfill({ json }); }); - test.slow(); - await loginAndFund({ page, extensionId }); + await loginToTestAccount({ page, extensionId }); await page.getByTestId("nav-link-account-history").click(); await expect(page.getByTestId("history-item-amount-component")).toHaveText( "Mar 21", @@ -152,19 +159,17 @@ test("Hide create claimable balance spam", async ({ page, extensionId }) => { await route.fulfill({ json }); }); - test.slow(); - await loginAndFund({ page, extensionId }); + await loginToTestAccount({ page, extensionId }); await page.getByTestId("nav-link-account-history").click(); await expect(page.getByTestId("AppHeaderPageTitle")).toHaveText("History"); const historyItems = page.getByTestId("history-item"); - expect(historyItems).toHaveCount(2); + await expect(historyItems).toHaveCount(2); }); test("History row displays muxed address extracted from XDR for payment", async ({ page, extensionId, }) => { - test.slow(); const TEST_ACCOUNT = "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"; const BASE_G_ADDRESS = @@ -197,10 +202,8 @@ test("History row displays muxed address extracted from XDR for payment", async const envelopeXdr = tx.toXDR(); - await stubAccountBalances(page); - await loginToTestAccount({ page, extensionId }); - - // Stub account history (returns both base G address and muxed M address) + // Stub account history BEFORE login to ensure it catches all requests + // (returns both base G address and muxed M address) await page.route("**/account-history/**", async (route) => { const json = [ { @@ -242,6 +245,9 @@ test("History row displays muxed address extracted from XDR for payment", async await route.continue(); } }); + + await stubAccountBalances(page); + await loginToTestAccount({ page, extensionId }); await page.getByTestId("nav-link-account-history").click(); await expect(page.getByTestId("history-item").nth(0)).toBeVisible({ @@ -345,7 +351,6 @@ test("History row displays regular G address when no muxed address in XDR", asyn page, extensionId, }) => { - test.slow(); const TEST_ACCOUNT = "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"; const G_ADDRESS = "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; diff --git a/extension/e2e-tests/accountHistory.test.ts-snapshots/account-history-darwin.png b/extension/e2e-tests/accountHistory.test.ts-snapshots/account-history-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..b849f821b1a73a6d0788f91d79716e4af117b2d9 GIT binary patch literal 8563 zcmeHN`&W`_yMEQOno?^T$I{H1X{?=o>9mc^bB!IwO6}y4l*~y>1yn@E16X!$%*sj2 zV~(Fk1T;lFA*Q91=_=ef|smRecgUu zr}E@Fmq)M8vu=9^?mSLnc?V5J9fQL+m6e)4+*W_igS&N^eZ26hx&GChzqcN$d>%FQ zAB8?M&$h1naf!Z9Afsa#4~#y+xrq+D3EA@OZt#fw&!4&%9A(2N8n8lklDlt)gJj=n)>_c9)V9?m#y$@_K}Fvx2zj~7B8mD%B#9UpoGOZ=?rcJ zCm_`fg-{#cetTx7hKtJZkNe^m!^3{MV?eHKGo(h!>c02+{b@k!T@qteK`pvi?AE>u z^MOPgvBj?}ZMLX=Rp&Dpl!d&zW#{V-Gh%ka{QLIZ@iRZ(+Z8!oT3qAEcG;J6D15Y8 z8>$Fj_sgu$8KtPQeYZ}M>RAYgcqx^R*$oojs`poDvN==ienLUn+J!BuiLJF zE1BieH0A<2vuzeSR3y?tb#*R?YmKq}=L6gRC_N_1jTa5(JKw|AeCaJ{zrAVu2!44s z9d@zktWU%{{VXPIjD$zwN+w%bZGH{Wet7vrC@P`P)mnX~AkDK4R8a9l!3;-DorDW} zT{EMaH8xx-N40KWXvi^WV!MnYG%%{}92 zZ{+0|Vw#sfZUVFcmC8L|a1vSFd(sHq_*KF|@FB=?qsCb~&d25r#!=_AM#r$CI)Uee zKc*8V;}cYXub`5=m6e6sh%o@qp@gNm&coc9_xtk76+F;7(_-SXs6pJUrMJsIHXO-k zJGTF^^WvM8d8Q?2U9AR`u+_N!e=FeinDon$?_q530#vbEj_tLMKiPUL)vaRJENPdW zxIeNJA1|5qV5T}q2WAGV3>v!uF(jbD9A~Th457SjtCj7=w=LgjCZ+ZeK@ZKf>M;b) z-A<|m<~%sm!GMpH3zq<`N;C{0zA<>18D)XW+31m+uX|!%kr(8t>GSaywCE4BU51P>j`Gq*&(WX zo@3{PZwXNd`g^RPAJ7WR@uOh`T`8)&bkNQ~)^s3fsdnR)AyTWJQ^Et&^y@49Ery4t zrV3I~31$*8U-g=45o*BzA_GJx(*_eXR&WWup+9SLD2WPq4LK$QUG4jG|HX8$B`rPs zil_NxnlBv%wtCb^eQCS9{XxJvK!!jG%Zt#h6Sp`OAsq|`4aWohZzHN5O9!eir`fD7 zjWJdw6iQW>ZR=ef;c(qTH(pw$rF-N`LCRspn2D;k&&`gd&8x>69SI+0c_9*k3MeP7 z8Kw6!-G_l_0HGcC@bsAg22-X)M7}o_QW$t9iXkDPbMT5U*s07S6kWnTAdHuZ5@#yg zMop`WHfD`0+Z6BJH zV)qgheR(2=YSnPFxIx@xY!@9yru;Snv@`^bJx$}|mtO|w4pKuolg_XMd?bx$L0|mX z0Hm~Kvt_m_nUDQ5EpRh1Z8!E3y6+ZVYvz-Oh z3PiQ!L=W9aby|((v2*Wj+4-@&$+mFleVmZwCBQ6nT61oi2{Mb%2l#AA1PbNmAn7+7 zNprI;)m;8sHv-6DOS{om1g!W1_H8|BHZ(tXx&NZOaz2Amo=rwk?o5*7B-2!YL~eM? zCW2Ckpwv&7xmxq8rR;>M7lDs={&J-m_@uAbc@O)mZ|~!p^2;921CM04IO{oFx<|eP zo)!%lODFC`%`!$JO02(|l-CK10MZ9#_Z|wLmvW?;p=6)h)JW9fZxkPYXTNi59T!Q^p4X+C7wEg;aySbtHUZT*~samzV z?Byb&%SI@4sV|Q%$c;bwc$b_f#?#6uk|1F8NK?<0la@_OpC>adLFs|W52RR+cr*R# zqe_RB@@|6vL7$k=aNqp{#qN1Q$sUh9gV|Bl=_(0@;4#cTD*==_#hM9Bb?}Vv7n-+( zo@-?LhB~awwZc|&9O9#OE+K%!#g())xHXk6-7)Yl=_>z@qU9lC@2U+Vc_iu+J*r?# zWGHTa#} z`tkbZy6!{~cvGSSExkR}1kuOK9B`Wddk@m@S7R9fprkUvfxh>nyOT1CejFyLp4f%G@_Y zzD_`!GTS|s?927q|Ac8GMI=p1N8QKzLbDCJyS$TyHC+{o=uQ}?+z{=90hn=a`jW{X zD}5N9+le=#jVp0iVV!C!6T^TQP8fbiBlG1fs+SX|3vNs|gc6%bIS<+MKr6 zHROXbm$d$JOBT8b2gc&VPVW9RN!L3t0cFN4OJ})?-y!Ga6UWA&=Rg@H)(m+k8_r&l&(ioP3kJB> zImVv-Qk>_1aaf!vj)(1P8hdQ_*mk;PGS$TEEIXXKm!*$~ZA7voP@rzTvFP8UDfSIh=jf6qf)wB8E@f2@$ZN{I}Ke5d_7}$2HUR)>0Wo4(-ux^I@ zuIwhPR$X(&EIO!|18h@kL?H)3NX$+1nKQjKfu9XUgnrN&wfz*Nr=F`(aBC|F`rr=r zb$PtjH98yyDtJTgRtl7^xPvso%**ry$1&8jcDx_bZ`EyIH54Yui6Q^Y1uAWX*}&*L zC6Mn3e>6=;D5t$(GdzMyDQ;Zo0zx*+VXR_F6phH|pYCtlQv-4WI$_Mn`RZP0FNH)BnX_2p4dnUsI_A}*8?E1N-uVX+r{9+6c311C2T7%q( z1S6n08`JgjVBkrn-k*mj@uwEGjly~&X+`Bsp!>kkjZEI^+RdE9#sS@T0G$D&hpk2r zuXlGf!tDE~T$WMVh(1%JZ<0gVzDo8Bqh>JS5jydCAog^$q|;q=PA>PxqYC-SNw-mL}X)WGSb@je_Pkk@Ob9 zEYD7=uME#v`DBql(p%y@0}QVFgGcgb+myKEz?R#az;t_BZ8Lk5Zm7)YZbv@do)k-N zXitM^=o`ZT=v&rL{RO+M-aavhTsN61&$Gi!elRrVRM6x$pV(#XAv+qrwi$uqM*ufo zo<$Sjtt=dVAQlfY*76s3!Vm~Qah_oO6MpF=6S*+XRLzC1TO-<081rW()N##G3M+p7nXFV1^fe{(jO_KNW*&9f+K!k@t6Ev|o@5mr)0_odJI*n-d zVUcZPME2KvUV-SN--Oo~R}QAKMfa z)ne^b8>^}2l*UL9=G3tb0es3d-TO26JO^Msp-RATGdtl?{U@+-_51=fbkVSl-Eq;) zrck>-<8q`+peQQp?OsP8jy*kc2nu4gRrW zYT10tGT&Eb$CtZVC7oGlPg?&AkZ+~Zre z80PmLe^aj^rMao(ik5FA*O?iCtc@}tS-DohZUsnctD%%lhyy`k1vnpD(F4oK1=-3f zKh)nha3CEK2G_aVIt^wWr-d1k^x_`2obVzV2=^1$V6IzYhyf^i$XBC6F%~+ux z(JfLsGuW9{z6qHFzlNl5?pYemXoO5Ye+wnK7rT#}#Q)-?@uBz@W4i`4bWk-gcCqEu zEAaKx{U4In)-?py5LiQC4S_WT)(}`jU=4x)0|X2q=;y7?;8(cgYwH>UYY6;5Mxev5 zRU3jdwyOUZu%-t8jldECXroFMW_ljvZ%A8>jTW@w=%DG*-Y9?;1i74WJ5K)f%B}wb DuJ3}d literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/accountHistory.test.ts-snapshots/failed-transaction-darwin.png b/extension/e2e-tests/accountHistory.test.ts-snapshots/failed-transaction-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..6c4d5de18ed037771925dfdcac6596e96e11725f GIT binary patch literal 28130 zcmeFZXHb;;(=9q++L%x=leS9OAVCR|!HmRFKoJm7Ns@CM7*JGH1SDrhi6RIB!jK0= zKyn62Gvu7pzy#*>v;XJ)cB^ikI_JZEZ=Fv<3Bwcm*S&hJ)&2Iart+cvXZNE}s6#4u zZfc=Wd*Dmvw!fI+pR3%eOeoY5l*-L(Ivxr0be0HC3m<-3v{z^4_s!-ooBF7UTSRvQ zB2&TcH+nDF{^l_~ee9Tdm`V#nK|EI6LM;3SA0w8>K8i)9%Fpqy=SQC2c>lwE#jY{X zMy=;*V?VDo3I71UjxCWKwABAvWO~4XMDad6l~jsW*cdF;P0y;_$VxL?9{#b1mVJmr z8ouy{iwpYQ!exI%7`aRxKh#0EO5VS!kZ)f6cm77=1ggrhY_s2*M4OZ%KeMs7_a#w@ zQa+S*^$;!v*-p;|lMmPY_ihX^p|(_x_%RKe&Q4E1tnhL*qE0(E2xJU;j0NpMEqC&w zI=6C)N8c4%_wH=kGu)V#!|@iaNp)NppQ+(*&I z4{puS{wAQf9tvOC|ZoLzYZk@|1vm5#O%Am-` z(#}qCseFx3GvQB9Pm$|fj|I->%23CXh6sVq47BfJ$yAFXb^eCrjex@%r8&MmX3>U4 z?n}gj5Mp)L_Qc$NfF>;YEMX4#g_~CSF*PgYWX>?`&;|wu{2Fl)z3RpuBd?q%oAk=u z7Q%Sd_8vOxG8QD2zLpc$H1zFB_48f(-svCH?D1KtImPA^9&2B@J^7^ib(+ub59h|} zLI{&_)~lt?Q!PH!O^x^~!g{5&kLxP(nkW&J-&hK>dUY7~Iqt*J3%3Wo=DyZ-IdKC{B-kCH~_ijs|{V5+H*|O_N<(;I`Ax&QR(lrI7CoJS;4`<(Z<*kj2Z@m$z_rb z7-*4ODnB4n{CDI)qMUpBU*$G^`CLA)51t8IH@H36k)(hLb84LF@+c#rt>FbnKXR)7 zc+I~<>D=~P{-l54N%5gNzY(cKa#W#l#?@U)7c=RK>uoo7?K`X<>)!v}ath~*-Cy1q zExJVH7Z&*2-TsWCw?{)w#o-v$)mx_wBl_)`9r7KCCn2((*@VtM@Z7NXs&0U(G7y8e&{Wg6(Z1FiIB_%D*Y;mw8<#tfRz{*%%Mu!34K-1YvkE{OVnZ(D( zYah{+ks9idv7c&+6*v9;A*D4U$DqP%<7J%saa7e?hy4d2Yav1c&#rQl@R_5YN8bpNF*%~E2yv8?L4+d0(!q1L=$wPjl5>y6$W=T;go#W zCY$TdioYUN2e4XH{rlmkFL^8vGh=)99_D~AelUL=`Ce2MeERbF88`|RL-rOY`gU_m zJA5ps-?t)MP!4Wd&oL}3EiI*Rt$nrknTwOOPV(K^X8wr#R#3Q8kT0MLbWMzD0=^iZAC46{r@15{=ePAb#10Y8JX$5n@qd* z9?wOq1y8R{#=~dCOl#kt@f<31Us|1L zgkXT$JbVbfC#Lp0B(z_>pKb(1*|WWd%E=9IBIM#~No=)J~z zm6~vVG_lCmfSBYt8Qa|4ELyRybz5zeQ_@POWNUq<6A3@aIq#Kh`@ch}pJvtZvsAAy z%_IjywYk-weA2Hs*Vq{S?QNmJRE~b3U?*mCUS-D*VM$cKVz!w(5Wt41ResUQAUVF7bbHmaWQ%F@l{l5?B? z5ZClo6zWvYYQ*IC3~<%d;6irOR*QthUP zR(rZeyw;h@<(~%v_3sd&VnNb|XFgPcR{aGT6DQ+5`Q5VfFt=hkmQLvkH(WUY!PV>c z!++nY<$|d53-CoCE{9f!OSX#*8tCs2^9ZR-mx>(89)QvZ5n+^tt8d}r(AX0*JBwY) zGD##R+!3NPqpq3&I6$F3?`Ap;*QEO2=$p(acncD}65ZprXQ7%p6{lzM*~3%$IPzDO z&aF{9YYhtv3#~;6jNq>0g*uP+jzvX90VLx5qQWHt_qz8yN}C1J-rGt}PEHJYQK7WT zfNz9{I8Njl`3048pM@+P`M7(3RY?>d$HIY*aVWDVRgTHvWqgkLX!B~CYaUeeSpKMW z35Ak)oz8q#*V)#k|Uwn%m&jIt5gIaCqh>ZMGkTcj%JU;utir~NZkf5{8 z3Sbr%iw|@vncISMtKT{|@zRs)xdlevD>W8Lp6MPJ>UG)0On(>I4u~mutxw0>mCjUB z7cY`3H31*_3=9z6T&OLHa!VCtqTgt7tT06*6aHJr}ZuEtX5l$I-JlVXj>4Lssz<3|^*2cDA*WKKcrWWa0 zS=NnF!h0k*m||W_0#*UI(3^l&)01b9JQ#V^71hv;d69>RXZ#FI3NRY%wJz;+- zBf+U*dkV*h%=PB&-2R#`pimO6kZXX?sVfq%yFf8Ag|fH!^AO6Xai>1!vdJuy2cVyt zx9pdn{({PwpGSmD2C?q+P`*>D+{I9n#2ok=~a4rwsX(-6-?#Tab48>62vamv&L}L&o@ z>1m#Gr*1Al^%R=YjFS*>9pd=riz`f^xU!yPi%`v zB|HI?Yqa4fxo!*??X&mjy`n=kDq+)dfDkxreG;X9$x`PFw2A8XB-lg=wAC;7v+`>i ze)PU&-OYZQ;F_I0J_ee5_$CSfp&pj!+8PXq{C7$r`$=Q zhu2Z0sc`7kTa zm@jvGRDr?@u(sqW*byG#HV8qF`WkE&aoXP*;8@t+7` zmlDAo@B7vQXmF|}u@C**t|>x5yQ72}>*#4f%B$DBRkG__p*h6Z9*KXXek3zRqUC2L zBYF8WWL}%Ln;eSyB=-2Vuo2EC_82XvWHRn%-R_d?rovvM_#-iQV(&)lc^Ygsy%sE4 z1lV*3Z`K$!VH+iAzvMFV>QqatIRCjT`y8EPHf!1Kg$CFhbD?ulS7OlC`doMykpw^S z?9A+JR<34*5A+jG@>}_hB5K}4_rptMc)W+Jo_m+Qzl*I?H`UOp#Li}BtX@<3dCJh` zo{UaWW~?T2>+36);zwm)EspNq$orCF?X`}!BWzE`hnI$93M$ZdbIGkrgZFg}Bj4Vn za3~j#hpFvHefG0CQgGm2SMX5_(KMspW=*xj7cDL%Wyfze2@hxwEjT9LJ2^8u+Yo&1 zu!_Z)LDY*+BblhqXRGe=0wTWTkfi&sv&PEf@BucrULWT4%6{ZS3mfI~S#MwUPJM~D z@u+0bm!jFfrncSeOdWMPv?h#{=kcawH@d?yOQ+$@g@JH$w#|H7H7YbBT45SFEe|e9 z4)AmYaCv>EeSEJ?>^ZL`r?IgWs?1gIa+rnW(y0N>mZ-f%q)^0;IDhF>5~hJ$ zY2Ti(=ch!C5>7NKoBGqMcCn@^81u*|k^W&EI(}N2#`<4e0IIERbG|S9sr}~3{5?z9 zU5z&B1p?}0p>bZA+_Kwe&KbZ zo9eT`30rL|c{)LUSy)(@xa%1|UjF#U3yQ2fZMhm!f1Q5yIyzg}-(7%3yxP1<43)w6 zD4pa~qs6A!b63u)6d#eH&uM)h6KU7?fqyx}hUnw7S~9Vrxv`eE7C74>jc$zAGLcvqgL4|+f(yUY>EpbAosk?G2p?&@Ka0)7XK*v!Y-#0o`Y@OL zL)NOk?)uwGL6-GTMiq1#oM66vD5UU9h3fSdJ{k5^iqhblqZf`*3qo7+{Iadc zxjl8;e^70wivXr5g!ALP^KF_Y%iibqNt-L3lRG$(^8Sj=pAS|J6$b7y#opN=)1s`7 zFMF#DKUzw#e8?r-?8`ccaazjx4%~%l35Rd<$UwwZXkE3t8VY=b!v2X7bWu$=d#0`q zjo`Cn%ky^U9Y>9?cnBQE`E2&djK+V;|Ct$4Nn33^qvQw1jHi@N6b#ia_w zG{21QLFpK5KAdG;^+}AjyEb-@DLs_;!J)Gf|77MK^yoXCO8YZ+>!<%dRuPKOVFu6m zvQ?OYYH{CPUN$U)N+PT_Tts*+U;3Q!l1U~X>9MVTY3J_R<5mrwN6eW7f_ITmQ2UFY_fM%oD+& zzp*h%I~}{;t{fPi5psW_(3gJg?!@Ic*_+yEh5KBSzppJel`fXftzKzY*hdg8o6pC! z9X*0VQOcMmuu3!=-lT5U`<0rRZx#pex#gCfc{^*Gf99}LsmYr+lat*HCMmz#)p)(k znv8Jgm%UQ|N*I4I+3J0>N9j!A(ye1N1v(w}57IGHLP-q{`VDjDjpN1y>MiW}aYM|Y zRo3TMjCC1ViOI%v*~A^Cw`0scxmLOPJ4nm#%RixzSEd##dm$onnHl9VCi7MfgY@F% z=MsJq-fp91Z}8sUTuH?xyKOGD-}^Ql^)e(Wa@MhDE#ndIUeq%b^CkNuIZWy8se5BO z%t$l%>CGdFW6{Ubm@lAE2)YTH{2h8h=GUK;w1R?ytgNg$y~@lJWUsnRlWq^H$4`K} z%e7N{4<+Kb3Q0G6jMr!sgD1#reKf(-XP@2hV8v>f5VUa&tkdw=vZB^R2ae)hleay zdU%?Qrvx-Jv>Q~Nm{3(Lvj5)eXUIXNr#x7>6%*Fu-*#cw;$|XVFwDm&Ueg-s3maHn z1)fV8-{v=U0e0t>?2Wk{(wL7pX z*29Xt_>!1^_)(YYj}5le#+F>!$JW-?C-3d-LHX^pNdEhX8?PVpnzNA3_!Gb1VYccN zD|hJIGQ8dPfChW%zF`2#5pIEsx;B6|pk>y!JpKQR+tC~?XlL_N4m#Ui z!P~b1-Kl4DHrJHW(x1GP5JHWNd{<9T)cV|#B&ur8@tFJO@P@-7C>u`->t-5QD$MkX zl_?r{6W)RKCftlrhcZrAGTD5#E3*bYWL?~H28BACWbJ2p6#%Z<=)%g?VJ=x&*^Y(j z%~emrgki4Hnk%8cLOY#?%L)c)>C{mW5~gBhmoHZ81kmVV_DN5z$ke5K;eII z-tL8+YWml&UnhJ%0hJ*uC#OvnZgsG;vJyP-ZQ|C?&=S3ISK^XjA<2uPaax4Ue)~#+ z*Y4pIrHdE6p?;*!#&5JrBh-W1N$;7o=vkkz4vVIk%fPSh-ngIjATo0HUdrvr3NJ7Vdv(g_ju$s%Q*ua*r1gV_uI-5Yep-`wYijFE1}-V&_uuukAU8N1XF9E!-t}0! zNMUEkr1pI#&bk7c_ua!^4e*P^3c1LUE?3MrQOl|qcvAX$=UXz;V?rDF)PdO{dFk~b z_KtJ8ndhK&tO{ZC8!=UN#bc>itF~k>`!L&({ma1iUoT zU(n*R4#QVFmIh0lk&}GhL0MV(WYbNuV(i9hqiAb_jJPvfOmDVc_}k>D3bxncLn%rq z)ZMcV+56IdqP10{A>f40-g=k!w#-xGG#7BmeK9k-Us2J=tmWk7*j%(*Y^|(jXJ=(g z(f!&x%^^KLcGy}WSD=TPfhS7+;kG$V*!`GzSQy*&c>W9#tX7 zmnq|f+w!i93Mak_&fG)!pSwd~M zo$Sx}r4$sb-9P2Mfg0@Td9ZgFad{9g&8kQpFu`Fx@|lI$i@$w>iz7Vi;D|~ z0zMj*(3XIj|84<)gOZq@o_@0*+8qwVeT&)`!l6awiOwOLQCx|jkWL@%h96zG zW+{4$&)nti>PjcoQXy0Hprd<)f@XDXvVJV-8tWr8yB`hqQgxL+BctdqqnEUN| zH7c8i{DEB;O_o@#2|3Uhz;oo?-1&BRaBy&*hFtvFhfnQ)F0t-%fKNglS_okJv)u|` zNtC}d{#RwGVw2=OR|Ax2BdtD*&Vc^^ zF~S2@_Mwe&E0y{Hwc$&4_wB8FvE<93uGz1IFt$R*YJ;fL%1V@1qTWxSgQ#(g2c3AI z($)_pdZ*G*fdv}wzwR0;y`5*JsIV~Y%Abx7E%Tw(!uLNs7v|^XU8e5>;9GTAk^PRx zqhl_8N~i=s3v?xbh0)RW0j%6cEA#tg$D@aG*kgal}W|1IV*zhQv0n_)i7$p!0Pm58BoWVJncZHG}rmNA3Mr!IlVq zIRN?&E3gsuSLy|?No^3FN)zJmJm`7ZX#s{1fZ=}#z6@)TzeujVhALqb>w8W;`sTGU z%b*h&?%QtATh*|uzw5>iI;oxUGxnT_Jg&K>pCHdFzkKzW4LJ%vdb8qpFJWgR{C?0r z@E)8)b^fijAw2f%x_z>)g+{J|fz{rf-^2=x_8}3?N8}e4stuVpL<~#66P=nRdwDP! zsh-{UbrnEQIB-fN0mOPh$l!76+P#!IfwW#t^%jY)fZq$ayqABl+Z8_n3kV3LcVZqD zm}_jOwZN@I&-I>5!3$myaG{JSVS|PhV0IEW1+>#`hDs$9r&@8wjFaLPE#;Kith)DS z3aq-n@Tx@#>3^S2j^ki1UMLz^y#_bh*pON=kF!ZA)VL;jYaSdNJ1ceEqSj+b7~nic z-+o6LM7{8d#%PN@!S}C_K)D2xvTZKgJD$3C6 zIzMVp@3Buimh?TAhZcn|pFr=7qicIi?M`|_n5|tSY+4hd9wyav@?VU?ou~7olM+s- z?a+FC>AfyHk;dDRH%Y0@yW71R;(@y|Z2?Yx`X=^ua>#v+Te1u-mhmB~#Uj7r%3ENF z#g9rkJKr5vGp1;HUfVchkr0|2WpYwxzeCLl-TA?i0?3qXBO-0<7!`twOMQjFW4<1) zDZRp(sQ;*pJhh{#XF;kzZ+C3$6k)3-;&QmSb~kMkPe{bWL1o0akdw&e{F%j{4MXEg z>RpW)lwKurNh|LWK5~@qDMp7VUCY{f?%#8Zr7jp#`+LP6i<$N#?x6_VPDZfY;_pGo zDhBoyg`X2A=|5Ppm(EDzR%2Ve`3l5V<%lc6pa_UKN*T)tgXIQ2m?-ONWz@LC5(Q7+ zm(kaXy^_Ma*LU88`(me4&pBMo#&&@3RzUXEFbA>ayvikzsIc@pGn(Rq!p~+ytNx{! z-ZElj6Cxo_tl=2m*w3a*zEpdLEjBsZ3LA8AV?xw-8+uk+tyJYb;`8kC@9fab2kgH@ zH*hl1`{`q=yOthT3aKQ*lr3+S@+JCf(uWA=@awwS5ASt>Zp*uwQ?}S}v!Mj2f_f`{ zttcr6)dmek5MNIP_V;x$CP}pT)H3iIq`yv(RF9P{0M|}hwv}Ec7Gx-~esU$b;{Av7 z&XrUkMBnw(KZo5TY=iC!)Me`c@YzA!N|m1zagU5v43rj1B5DvWGlOW5J2zR7-y%>I zCA|Gn$9nDPgiG>9UgdnMO1M`7ry+6o+{3K?ETOQcTR&eNSUb_++nkHt$nss2@)d{6 zq`epT!cQT(lYAylsZ@BiB*?(Y;gDjA!3s_My7|lW%kJUPLP2zb=6b_j@Rlg`L{{fs zYbZCP1a%pT)7wL^61;;iH}k6u2xzA-ZT0vG7prfc%?;y{o=b^K-cv{%z8rZUC1@w( zULVGb*pvtiG6TCl-M)PkY+s+kSi*B~AU;uK2YtvxKJr3RnUayS+iO$324T8u{yf-d zCJ*qwnNfswvqMm{KPDlO?cYUIDuGzN|6npgTN7NK6(nj!KJRmRNn$qocH^ zP_BW<+~m^wLPX#Y}%;zs6i zC+(4JH(^jmtK;^KsAzUMjdk1 zcqc>*in4q4&Is-@|Kqj2!gCe~u6Nx41b!>?n5K*9cZtv!OhUU}b_yGhFP1GCObAD_33ZM@ zD9r3^k%SG3sYwSyhIv4K$7YLdJ&b&8wDJB_|FJ?GyxpygM7 zl@T{`be>7s4aUru0(191+?5ImC-k2!41tVM2^08?*c&rXAk|{kLW$akl%?$;(pC^@ zJCUUFo?G0!2_*QX(z%>uw;S0yjlNVolEpUd=eR?gaQGSA=F7F+!=N^7bmDf_>t%Ph zk-uz~-mxO+#riUq7(TPL+8LUh3SKThx54Y-Ed6&Dr5=qHD+n7Y_yVS+hEFeh9j3%l zD8Ve5SDDO|_;WX2^Q1@N?=C(8MV}=Pq4%B>UEJLGd^bxU-;+D)1(w2kor;rD)DKMB zUSCP8f}2Yu#!o2NApcAZm~OoMb1*3h>a?bi`mp-n2}-`$9;@xu2|yu2n90s?9h}!} zW|w@phqx3;qC_DuBPxE=Y zVcTdX+&g{-&4%n?h(Op?*^AZYpz@%e zNo(v`zoAUJ?E&s*4M{L8`6%GO3ECGuLYfTav_R|(s5UC)6V~px7S0rby3LZOY*i|X z9D;JYKi@uugf>2b9s#jOt*h04Hal8eQc}X@qc&0TrZY)VV2?YxV8XK1XWy`x3^Zm} ztB?B4L<9fcIE~5fjGW6X#_U~`qeSWJ>&rjb2R%+0N}bTv-tH)`I~(OQ`@Cq$;zA_i z&B@r{ARLcER7A#`h>syt{s3KY`IFFRoNOa;_^@&B%vAjs7m!_^*wOFSGknhaFxNEp zwo7^l_VK)BMq&}%9oUyR6;|PvSUIHI>V(rVch(U^uWf3VV`*wF5MwFN)p10d2Nz!~ zSdQ!;NGGCm>z~QFFAD9OaUF-0pcIJyqSCk`e^FWqgB@RGbG~}+hAS>UBCOw6q0ZUXA6cr+m1BArqmB{%1N%oiN&U#_CkkE+|*(z{o} zbGT)!h;QzR?>l5PReZL! z^ccSy!B?6Mu1w|Knh;jbEizN!IP;nQ6yPNkc6LKUYA8ZcFKhSj>?c-TDsQ)^4~l`L z{k{Mc4&?yiOkPsdveLuNuBV+Ms}-)8j|M1W!#=Iu&D-zx=I&M9I2 z^+D%W-WZJp>B~$`8?)W@ILoGNqf;t^@qj*M5>?IL;Wk3lhRbKaWaU4;?wV|_-{A~h z6Jov+Gxd3y+NbmEl+eTF`GVH;me@(i{w+1UdS8*8AXOdUv9O}K?P zmD1Fr%@cSK50zLU$w-+C@HRH@m6DT-SsA9Hg6LFzNQx)d{ImBoNL>xe7cC?aJH-3A zkjA^Qk-l#@gnpx=yIb6w2E1Lc$=(wwgj?ni-xpYwXv?(iwSqf`P0MG|P{f8<;Cv3< z(9K^gt9@^6ZAIy|HCQF6mv7YVau5s>r4|3`N~u%7sct6CJ2<+P4EeFP2 z9m&QS3G)Y@oikin5X>2UQ2Q^YjjfiAOU_8K$UEA(Y1}(dr4m*jWacO2>gJ}nT(wK! z&tj&)l6ztb$}%%oofQmUYC`DevNZ$a)!q+A?G!J1N(-AY$*h$1hC-VdUh4SNs-ZDf z6T7JBbZj+9iWnm_L^tMn)wjC~#vm+0!DYce9W~LX6S;OpA^h>0+;|G!o@9hA^uDQO z9i=KG6)G27BK;ar{6Kk>bw?d?#|n^`uehmxi#0D8DgP~jnAkhs$<1rF)&3_ zHa^!~aCC=4w1F20;=A8NGJl}J>duIWFldz?d!Jf)vl!alaa);-_H2J4CF*50&*tuu ztig)Y{MQ|98O&wM2kL78{lxn<7z63ab%4c!f8yVyI$agl;{*bbg4U?YlYAH4&! zpQLj`D}Hm7_6WfxwL$D`kp*J0zoljNe;{S_iaIS6_U;U}(g%@F>3DtTIXZO*Oo<=& zxj#=gRyEJk-4x%ap*f8@G7m6dd)grtFAUjZf|O&QvN2RGS}K z>!&B(7f7|BvstfQt8ZQM>Mi5KZjI=Cn!|rlWkeK)e<>sV*qI}6Rp^{2!4v{AAM~UDx;1wLVG!H@N}Nq&0xg!Tb*-REy86(M>L^R=F24 zEY6#GRysZq%H?u>%3_ECx0bam>usDcy*>n`Ml~6@jlUshF|4uKC~qOciJ>0O*P;HtQwFbEW2L% z*y97#)ZTKNi-IslvEXK zd?Ao0dNNvIi8Jz7Jn6~5BQXh94rja?A67z5T)e>VJ$dzNh!%3&^gULuPXCL% zvXrM7Z=09N`KLWRDQOBM-fMXWKPao&%IxVLuUNgUH(|9-w;@86vH*|O#;EP6Swm5X z{OX+-)6mBu1m^F_pPc&Y7FW%w-ok_xlqriv80?f_5Mtvd$j$VL}a?0#qb7pa#csbj@P%<>}uO?kgRY z&CK_<`%uOUIz(FW-WY7IQ26FwRfdv7bJY`O)k?4O1rZw&IJ*B1uI!A=24w2;KWTB8 zM?#?@|Nak0{=fPSa0xok|7);QBAZDGV%EVsn0ALL=+3`P^c6`-NhztR`@jWDpEIK< zcyBrA>gpQtJ~{gyr9O72M`O{}($ew^a$`pEV!M=Kh#>6SY4z$OewIhf)@^eDu6S@Z zlwS8#HDq=;<9}e90lt-M$@T^Y@zV!T4o;GcJHTo`bzq_=07B-65ewQ)Gv$kA2C*NW z&n(65pKfhXs_PI%RiPsiMb7%8)RlU=x+K5{;roUOh25Xu8EKe1?{}ije!Ddqn_XCV zAJmGi%=#Q%x2pZqcwk8``hr4%rRe-U-3#Ak(N;E6jS+}F?`BXublfq(_q1mC@H6@1x0NP%v?yt~5k0Bx zX`sgOfR;%F1|aJ_Fx%3jBlk6D?sq7gL4!csIvQzf=4kN)M51D;Ip77)_+FSt;% znXVxRU4OtK_MVQ8u=O%v!hli+IyEIh4$8Q{qz@}H$XLEORE9^PwnFcH{fdjh_O~y@ z%gXMUZ@g1HNn11E>QM00#ZkjSLH|y1};OzR|=`Aukz}Oqm+O< zXfc@-z7-hwSO&5lE#Ltyjug?uq~RxtzUUrO=<#B%(ub<`kD^xDok@7dz(44mCW4>?Ly_U(+9I0fEdeJBk0bLKI({I+j7B8#gW37+zhVvd zWtdiUd6;in4`Tsh{p0oF;!+oQKJ)7?WpWPgL7n~c+JE241!DJHwoLWwDPQeaKTw!Mc{8{6s1_##6k^ZD^>{%%~e-cMR{_}v#jx0XKbnidZ@)cPyG z0;A)Ud7LTc%bh`uhZXeA0b~HBC>0yuySv{|G8WqzPmE|-&TDz4*)8R{kzLTD4-?PF zEcL_gaC;0tSC^8MgrN|TTmjLHqy#-6(lmc*Jk}fson#%RCe|vJeC!b+EWXQd33oSf z{1I!F9_>q3jw=3r!Y#2o4}>y3VA4+IC$yohBmHiNQJ>>F0}fLcv@JMgolLEj>wZ1= zCtk*m7VGxV*DlV9&-H4?I#T=Z2a@L(iM}=iRp^$O*s5|XM&(ln$Id@1#*grm0|wZK z29=ic#l{L|wMD@}#zc0T>c1Ct%yvu_vWbN7#mRx4h92aRC zUy_mNrVpM*3h1T02f=q$zH{^pe`4d*erTL|q4CzhtE1y2X5L-Q`JGKUgh%rH$U%8hfI&B0K7P{R zk|?fQd(%)REIL?m(Q>oQ0RR3s_Lg-XAs&uz=D-s@tb9pOtmuh*$-Ns8_mJqVkF6M?RJO)tRndLPL4HnhBdMqZ#+Xse2w;Q z9E`ti4dd2(26)B~hW!(-2xH7ivaYi*?;f=te{e8m4Mvf`Ip?_9XMsqR>`BL6L#E8% z4pD)TWJ8))!HxlIEvwCO9@H}rfex%iWBQ_SfECM?SA&fM1B~j-j1W6(Tamr*?b-j- znY_7OSj5M*v@lEaHBY)%bkNeSUb8mSKj1sQ(2Y}()|8WIhOuf4+?+q=mwA{eM)i(c zv$dy{;}GZyYB;}>U#u-E9vIMsPw_bqHRyO6Bs|eoHGf+E)E=%mA9N+nNSir_o-xsyp(9e zPsD+_2H^$CaPR<)~@vUbRM<4osKlDs>aL8-At%rMv!`ixig^}~9(q<{i zb61_Ia#~^L%y5XEkXW|f`H$CWQ<}UyeSAIXJOc`Y=?P^J%b<3CFD&e4M^69h>xT-d z?=YYroGNsVX^i^S4pZX1BSmRxQ;ZPc{anE}u1J|qVaXF105jnhu(lVyI{W%!{~qe< z(jg8B>fvp`RH>1pNre6>TH8T03QHXzVQbG=zzp%-Yt6g%(mEn6tv8pbO>vRzazJU# zmYV8dxHF;_rscmwAa(xm$LX#4YWlMG_PD|MkC#1M>9qW~(T~aEFz3#A3!^~W1rEU; zo!i<>-5(yx!7>M~AQ%SISlNU=MwApqP6YZA@FmY;5};#&TBP+4b^Y`03Gh!UJzsHp zK45NyDftK~Pt6xY1Yh6L6&TQOfdMI(oL*d~?H!F^LV9gHE#b+U+s~IQXTHscmnWjU ziJntweC28BTwzRp`_J|dmP^GJjXmDvpA6!{wEw=RQln8Fl>wH0#nCih~) z9EM+`#BA`Te?Zyf(qK~l@>e!~Jif^6WutPCqV4Yw%z`O0WvhGErC4HXSX6f_%w-pZ z@n8~028qN<=P6cEe-%mvxcm`8u2Mn2AJI<5RzV3{jq|ekxeQ_~7iK`I0YSey0m zr;NQXcV-HQa4TV<*0bPMe%9m9JON87lybC*q7<$W1~Z}3CPMR{NjDD#1zs~j+VRJW zJuI~XG``aoFW-ktqV=)kp~~|6PovIuzlrKGPLicl2a4p~yPW+(j@QKW6sh^1eh^?J z?$wn2srtbp$-QU!sG)MOe1&zLy}Hsu9_N7A<)W_(r!o>&BM;3P$#^`b|L_-BFp|jk zS$uO8|2|&Ydb$mB#opV6T9lX=5C-agl8no*rktIuU+AU?GT1WZSjJRQL1VHUIm*FK0n~Q zMPOKqWs^mkOM)W&xkrjQz~Od{B>(AXU-{LtVBmEi%9?ea)Z_W=p|je%D)hpj<5HBy z0ITc#+^l{vrgyQWrOUMwTP&TQnR3CI+-+4ecX%G%!`a`FUotj~zhYnNzE-6o!d@q@(8p(0l+3eAa?@`0|%DVb>UpsE`u4BS^Bn?H0l?v<%M zkh$*DB;?_;tZ8!lx3$wo-cuRW-J`p-_Ssnvboce$Ys|9+JiKe~eAa?KN8`uI$<3&q z-9rmXJC|zGlTQ!zxJ@sI9)B6wE4Xj{z_k6pZ{?(4p#I(@a4Tal7^?!7D6q7!hTUnr zXs_+#(+&Qjt175;B?LbkIio~^KG**Zk;vu+4Z|*`n4RAyA3i4=N`g9jm-m0QdqG@5 z|Bt`ZxwZG;>9)Z^Ap0F`VB5zY30bC?T6Y-ehY54=ftj%RWimtdmIhM|xNdafQR=+X z$zW}Q)CAxDA6Rvx{t8?=$Z8ojcvqr8>c2bcm-!AvS52Iv&#yN}>#Lv@7^w8YIKBXS zIRR#NxrcUuS_LLK4-~5Ol9KIk9L*H=NlYm*wqfYKX8;NNc-X`OR7x&@)wa4(Zty7a zX~eDPGAOxVM#+>4J}Wt^i=EJ21jP=LKptiaG#l*n4eo{v@0CDfdFbByV4cinBZ1Z! zaG0}nELaW<9$}H5G(f&URdI1cYgL6Pa=(88U9$lb4z4&?5b+VISg$qPmgz*B&Q-}r zn1wb>1<5O82R`pT@mTOvMTHMwc5q*)?kB){8Z@VL5GaAd z{KzhrL)|M0rxGt@BRfz+YJ2ah??s)x{UskE|G7NJLy?^b{LcU$L3Nt|fJh%&!s3^b z5MYxZ*!aphm3CyK#^-w} zlP!tyGk^svXW^m=jo2Dp0;Li1tov2J5J)fJ0c-|}gkMcmS}>u4&c$yXcM5+@T8+Z5$3$u{jCUrC6`|wqV}kNm z2eTtEM%z|#(wL?p)lkf&v1yx|)EV%S7^1|wwaTqWa z{HXe9m->mcWz3H~rw+na6nNzV^*slE<_ZqPbI2|bwQ6So4<0;y=`pC|Faqe-rwD9> z6MIh`yz?grxXw&R=B<6_^Xf|Rq6S6t$$=u24P(Xzhc|lLeX!WkjH#%MgO||}UAevz z;w#VFr&|&JKx`A@C;x^RsDJOhX&G1RKu-S#@t>7bDv0wKa_tp1uB2^|Uwpj$8Ko_= z@pB1~bs6q(Vsl59$Ut{@;cQ(bxf!J2`s^XFkx)Zz9*bc~1<-c2x3{k#?zO%}-{D={ z)7Tr6QWY~A0t<)PuLuPUAzK$rCI*1N80fpP)fS)_;V@8_k>FT+20!FxaD9oivp|Bk zOTNIpeTPKH{5~I|wBwO%@AmSTKZ1sPJz0-WyX*L6Ms;Bkmlv?KZlbiPRwk~?Pr(<} zX#I{YVvqJ@vzs*#CT5K=*Mx;)^Y7c^DLZ1kvl`8&ia0cjcvuMJiY1Np3YbuqvL||j z#Q;`Fee5-BEPFy9;ocb;fb3=xqy%dcSbevu0lm@&rxfu(FTCHDBdp2ci7-qD-ia|% z;TD`5Y9`u8u*MI{2S4i6-OGYiI*lb$N%0pF0mZZ&ZSxv~y(o~}%7Dr)H^V?%%FP|o6)Y&GeFKgiSvoOHT*pLJDt%jga2Ab#CYh-T#w8`el z3EkB%_8dUYEo|7xth8Z8Tsn|76W=H9n)Aeve8>vW5-2g&lzbr-byMF10$mKbxTLEU zefH|+3q=41up2Dx`;FRI1&mwpmU&?0-xbg+t#V{2nlqse@s%AhJBRm<_aCnRj#!z#k|5~KHAW&uN@yIf^}J4bB0O^_OpU)vU$jP+(w-*t*#HVO(!wv2pPQs z1`qYUi5x_#a=bzK>LT*xRKiZhqI$0cPW zIa%3b$_09=BV=gY&_|^`rP<%ZVzcorYYIn&&6Q*9R>4V;3wJ$@v>ymn^WCwa>JVe{ zLLe#mM$-cjtH&OqS0gAE{kf*aPWKR`(U2W(>&|1gCF0K&J`9(RW*e;hg5_Op9&3;?~Z$27-Hr8M3cTxHl zr*W&p{&4eQ=&+9>(jw@v4l8jyB-p3KGb1}tz!jiFjoE{eD4O33z$fFe0beaZt*EFd z)8S;C+TWrd35Y?$$O5IPFSZODFpj;}{iCUdab>|;BuqN;?_2Mz~tl5ha>I{^v$=fA`T>Laj*f6eKo_#AA zrt7<*3wG>({MdL<+UI(WFyIVan`$M&F|RC9dvVV~W@Huij7>wh5&4E`li-h!nN zU~iR5D2jG~uzUcaHn2fbZS73udX4u=Lnbd_PttFAipJA914nlrX3$wytsGx*P z1IN9%AV7;cS7Z-P_&5nmt>ALR24~g?%hq7`K@r3)T*VTYTFk~kEYk$xaC{tA03q}4 zunt0C0Fkpf>NMywfk0cB^}tRK$a9Fs34Lycfs;p{GveUthRt8N_q&95I6F1wb)3?*Rvt`1RM#Q353tFx{#iM&F`< z`J_3@2GTez8tc0mbVhs<2Kcl0*`Pk2cY2S7WXeq&-bbJgE%6;B$HXVT4Dp#a0otzb zf3$Yx@lfagf9O6H+BREkt=K8D-!56l*wUdKg>6~YBsoHk$Q3iwvH7Z`oGZsDNmM4+ zx=pPu4K2!*5V`N0Va)M+zT5BP@%#Jt`2PB*nU1o27jyF(%q}TLF=iUyrkKR;IY~=UKyaFI2O(H(!o#!bcpE>Q{rKSc zy2?y!-*1~;N@c^c?)yV43=us$3gRN81fBf#6F`MAggPia@dG?WmU43wtz=v_l^`y6 zEX3`pWk!3clGr_TqT#|~F~$t0>>!ykwTJUMD(K=1XGV$4v?tH6n=Cz7mTf!aD~@K) zM#Guw39%1BaBC8>Cv}#~)#W7Y&Q4IC2-kW_kGNA;Tov ze5_K3t@0l4??o$sPT>3RI;&j-s=i7Cea1)(YXS{RmN>AHB6T;vBmC(IcVsWTR!#8T zbg(XqIZmDgq8qAK?(>h@;EhPoh}ghegBIk!x-nOl2y%_ zQ@p#YU3$w4YPH3&z2^c2z7U*lOWifLYyU?JNApO~a^N>s=f-IRww<1yhSMHRG2eyi z%+>nJI>9G?U)GZ1uBY-r6Mtl7?Wi&2#vJM~=v^Q2_w_VJd=&_fu%L>he2V^p&0R#O zZCcDnOw4yYtdo3s};sabSVxsVe<<)k6d_v z&6Cl24v1>}e5MEge!orLwx(xjD2lm7POh%rQa?~Ej!!Fz#aM2j{uM*nHHz*P8PfIB zGzvsRq21a|a~r1uuMZcl!`QXWDJ3lj72*s=gsI|0BZNjJmJCRT7*ifyFtdW~d5h|e zhOo(|MDJX!jZ%s94M&98*QTD6e$(_LH?~X!=Lb?;t zqotIB3Dg7@B;b9)jam_q;WfK_B5`Qal*i9WrUxi7l2UT>S9KqJKExP<(~SB({zq}K z=s)3?f)cjpfkS&skcXD}O?Y5rXAhC;^Iq5mf31+P^oO5oohON$)}z@hG!QE740w8Q z!l!?qf?U1jXch)Gmm6l>K;Q!f?1afQ61HT);uH=StWP4x?`uYTuqtv9jzY2)b@FBv zQ#=6|1Jkm^I6#DUXmSheC(ru1s4W~emQ(i#j&R4B(-j* zy>`Uv_o@e-$lj2|`3j(c_4LvUmI3&5r=kWAomI8L5pJ|4SyfHr?tbO@jW1_D;pqX@ zNNgT>^O8S!x$|^j{%Hl0W177Et|-Jy(K72oS2;w!d^DGU6>HiQeRf}F*y!_*thmp8 zOc!0)E6XB1+Sku3Lo>r0&MM-N+Uw%69ka@#>DcpcolBApcH3JeEBDK#DbAz(ydzsB zsKwNgV~YvdYRjTw`b5c%itBx$1eFu=6n{9a@6jH1SuWv{&cTw$8*Kho8ViqPNKq7; zuyV@g1HQus$n^pMgQp8mR33%GVaM9PGtFPNQxwKUswr)s_v_x2FCd?AF&(o9P22Vh zlWgYTkPU@0d8uBZ71XbhrF{-_#d!!q$Wz9ui}K%jHl%5=)_Rs zCYvn6y$!#nwE0H-#CJD-w4bgJiV!5Kt^2Wx;$%RG9iE*BmpU3C+^(Y46%(EIf0GEA zdTsh1@|97e5J-`T@Af@lx%cnhWnk68IUa&0fOUYRecp?WMOKj~`X*xcF5;6bb;5|s zD)6V=#z4jaK8&m%?0&=j{aX@OlhoDuEf@iWD3T_Vy2$+_B=l>HN8ol1xlm7To)=wc z81o5Qe<;Reud)Nic_hp_HIMar`)QZ~7wo)a&hOzw=F~ zGXQOlL%y-%Aqf&*u=5&PO_OWk5MVTZEQ~zhTX!|!Nw3cx)Js;-L3blUB|u-Gy{wSA zN8&ae7vm|m*P5G(X3A)cfoHk)o0xg={mUt%_f|ZPL98o`DDhv%Eg$^KYUe_D-`rs* zV~&Tji@Kt$$6K?~pbjy-+meQJLZ&Li8DuMB)VBUdQlfdWzqVD>(pud2D7HLS6M(R+ z-CAepepBZWUj)L3wqn z%An@{b(A*M^B|XDBecwOw~-P>nIGsYtHeBt|NMDWB;eUJo5sHK{}rNSkbPcDw(mWW zpIjOAvTN9?eR{#9b=W*n9Y8md{`C(y&Au_{Z?{OT&}P9G@krgX+)qCOw8EKVKNw`$ zX+C9%0jSdzkavlRuJh9`6gQ)-1yt7Suno@#uiH61WicKnvlx!>Jdw$lb$~#u7)s@H zw4VabNp#V%AlIX@F`p?Be3Zp{4N2RF@h`t(i~WlV{N#KR-vVYaxB zU1IGC_fHo+4N26gseRS7Y#WX=@mcZ6hJLCTIpx;2@a|9^o_pF6s5p%bFifqvq zfFROmSs~alJTROuv7p`|N*Y+hs0*Uw-Q!c;7 zEx#)YS2^W6!1_@>fYBD(F!mv;33TEvNEMb-F?#bYjHpJJUi+c(k}&#P>d`SUHJFn3 z2w*kqshLPosR>sx?$7wcicNCrP!m#{?Oy_7bAlU!pqzJJVV$^y84dk@h!C>urC$TX)3Iv}B67 zcTuRiGrdmYk~t>wmde5l;UgHs zb=1%r!Xjg`@{S^(UqG;rns6Y-XyP)-A$?;-y$hX(+MAieP>BaL@62fj=Cmhl zZc8o&TT?f%0aY(~LFoBQ(oUh2xIf1?_%vt0yR`ky=8vKtiI7cZkAPkvn8^o07exMY z%CHk#O*4KI6FR^Mado;6^oS`0b7S8KS(n4EFp=z@aQ=49SN)v8A!mYgLp1L`=?{W6 zqhW-BtLRmk;_!C;vO}wP(P!n@GX{SK)YCQwTr}oWng>SiybAv%{PT{x0dq7-kL0bR zRRBJybq=^JfS4=az+$WoA(W(sDKHJLFTNcXBx?z8 z>1GBx{fT%c?xAiK#kKmSKz7h2mx%AW#iuo1C(dfg4UC~j42s~C-mWP}{njB{@umcrTi}fslId1)Qz%o| zVfee%=ZGs6x8i%n#4^iF@;_N+8_2hC#j6zFDUV7S-Mh zWySYp0w2$9D!$GBaTdk00C$^QXi`&Rl;cKY^0gxFc!cqYpr_8HLIxFqU>ao#DUVOK zMDI^P%R@XV+;aW_g%3<;531F;Jqi!GBp-D7^=XG&P^T?yTXA1!*^hFmHY%r7=Buny zk@Xn~UmllT|MBCG02`1UfSn$p3;{$V3+ec#Gv$$n&&jY30wcT^!g382it2tS-KSa> z8SXuW0e`z^yYrP{!sI;~pCytuKXvW5v6>n~OKt$0`&;$V+or&=!HLbL_ChqEJ)Yq* zw9(5l4>JXDT&sIx-@I3ykkfxrH*~6HhrQmm&BN*G>B_U&Fo56J)BLTM80vT*OZrFd zSXr@!w}MMjU!FoT0B9KQ`}gC_%4r2ecB|56c>%4!>**R!7eDH~rgjwy>)k}hrQP{% z{IuNDhj_(C+^+K(0zLjW6vjQG()L1U6V$QvONksEVl%F>dUn~+UGrPU z<3=9?zzE#<$i9MBpxTC+<|O9(uEq-LXK{*Tl1)tb^7iHvaog<<3%rz+`!qQYaUKU| z*I(OitLm;25VgTFd*mWC<` zJOXx~Fs{pN_1SlVa`~J^+^O%+@c+d)-ffJx43L*`2w6aEZ1}Oe9SVvPv@Y*1TOd2= zS(G?3RfMr1EM!LpT48%$ot)d!H(FafU`>(NFXhp1Neeb&K&5J*FDr;x*~^7Pg#ori zc^7GKhZd_n`FG3amgJ*x?!Vt^`1C2kBFg`qnd6s`VS1Y3MopVN8woi@$IB2%^rB)} zMfpH|J#ybm)KyWwj&ZAV8JC?op*_aR3EDocXWaDyLE;gPQT7C3#eAwl0-ri?6v01` z-3c$B@Y_J60D{{b%>krZU?e+lDm21 z*Rk0>O6m#Kb3X8kQa{*Fr6XIilXvZPz|pTv2aV3}{<&8^Jv1kwm^gM1kN~&-_gGJ# zvTvPC>lvNjfubv!D3zf#myNi?K@!;UP3s%NduuHiC5BN$zx)$A$s^=~!`#hh3wi9$ zAwoge&7Gb7C7r@Lwc0uJ&7NO>b;z0*m>_@k>m%0n7 zZu28o&7rF}5awC5``BoblE~2`;LG$_%M_$Ae+5mx$)~-G*kj)%9ZYHW2jgD^*oZBt zO&NyE*!GzNCyZASq$T1@#H~B*4;-l-WUOC>6Q@=2CLR+(fgw|dXZ_N3es&W}d*#@6UK}5Iw=TJ$| z0>NEjJg?GHN_5oIZ-M-z2Jl|OiqWSIsOfXV$2-7Ghc%8%#(+jfh43;A>A{)2CpFHp zYY`G#GlZu?Um3J{Or?VO$ZAr%knpEI^|t8I(tGYr9Y)<=CKd_D!#|Mxhs{?Xo{4h} z_Dda5xgC`vh2(5CCFBA`dxy3grdVCBjmb(&ZL}Yg322+QPPJ6!M-@x^dY~2wOT9S* zG5^}3Y1@6IE~Q3&EBmLg^enMeOaLYj&k1$2pNfH3l+TZ?+k^MxqyrlZaOH6KnK_P6 z5P;L@6z7_1O?Q^raOGca;%+y4(L`)fkM0Q1xxb)HpeyGw@sm~VxW@TVw+2zbi11cS ztV>Z}*@|a=2*PO6Ri78KQEG@JBcC0e zid&Kioq+P|+Wqv>ciDsjj=0wreX%!TAqn&WFD&y`H9KM556cp&%h&hJ5Uy==^og*u za}Yyl*G+Bj=U(?f&lx5iNKw5jr_5Dq#fo!~Ba^A2BBkahNjquR!k5JoG58-b|I)$@ z7By}6+Nai?GA~k@?Fbk2zZ-hCYbqE24CnK0^D-?)jBf?)cU{+~fqOe9XS`cZVs2e< zbcL4m?=3&{MKg#X{TC=Ve4)e>3-~N4g;SoM6M&q7JNQ7ECr{y2rJpPmH!z zX*WImexw2B^#~?7wSRQ{xxyutHg9l$$jk;H91E7J^>iM*@NObPI^(rM%X+H-F%)A7 zerB0*1~V-B%4?+kV4E{Zz+FJOXkpL3b;vCHS)Yb&dNKHzKTzg?0X$sUY+(+Eg#h+% z7+*)W(r3#t3XTC(TvIK<9{q0&ci^~PurA@Ruh(>qtGN#aQz$qEb<5{%*mnLTKkzQ+ zdim;AusD<r6iWSfF{f&_g?~jO2h|1d`%}sl|Cg|I7HG4uUHtE z*H&9XGVO_lpej`hryCE&bMX$tJTy@x5tP}PQthq|QqO}eBH0Wl!pBGIpII++RKx!4 zjDCraY0pr04GOp>7VU@a0M%9~>U;>vWU+%WAV{~ZPSQAaYr8hP$EO2NF>+vzd_6;Wg%Iu a=241{{N^E))ba2q6vO={2I+fGU-=)v_1xkB literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/accountHistory.test.ts-snapshots/failed-transaction-history-item-darwin.png b/extension/e2e-tests/accountHistory.test.ts-snapshots/failed-transaction-history-item-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..79aaa7f880e2f32a701af7466266897ac915820a GIT binary patch literal 11150 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

Re~%TprUjl(X>dA_k6NbO?Z7wcGqGWeoy;(0A8K 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 E2Zk{xL;wH) literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/addAsset.test.ts b/extension/e2e-tests/addAsset.test.ts index 2d259b85d3..2c2cc75c9a 100644 --- a/extension/e2e-tests/addAsset.test.ts +++ b/extension/e2e-tests/addAsset.test.ts @@ -1,110 +1,28 @@ import { test, expect, expectPageToHaveScreenshot } from "./test-fixtures"; -import { loginAndFund, loginToTestAccount } from "./helpers/login"; +import { loginToTestAccount } from "./helpers/login"; import { TEST_TOKEN_ADDRESS, USDC_TOKEN_ADDRESS } from "./helpers/test-token"; import { stubAccountBalances, stubAccountHistory, stubTokenDetails, stubTokenPrices, + stubAllExternalApis, + stubAssetSearch, } from "./helpers/stubs"; -// Helper function to avoid importing from extension source (which causes Node.js module resolution issues) -const truncateString = (str: string, charCount = 4) => - str ? `${str.slice(0, charCount)}…${str.slice(-charCount)}` : ""; - -// Skipping this test because Playwright erroneously is unable to click the "Confirm" button -test.skip("Adding and removing unverified Soroban token", async ({ - page, - extensionId, -}) => { - test.slow(); - await stubTokenDetails(page); - await loginToTestAccount({ page, extensionId }); - - await page.getByTestId("account-options-dropdown").click(); - await page.getByText("Manage assets").click(); - await expect(page.getByText("Your assets")).toBeVisible(); - await expectPageToHaveScreenshot({ - page, - screenshot: "manage-assets-page.png", - }); - await page.getByText("Add an asset").click({ force: true }); - await page.getByTestId("search-asset-input").fill(TEST_TOKEN_ADDRESS); - const notOnLists = page.getByTestId("not-asset-on-list"); - const onLists = page.getByTestId("asset-on-list"); - - // Wait for either to be visible - await Promise.race([ - notOnLists.waitFor({ state: "visible" }), - onLists.waitFor({ state: "visible" }), - ]); - - if (await notOnLists.isVisible()) { - // Case 1: token is not on your lists - await expect(notOnLists).toHaveText("Not on your lists"); - await expect(page.getByTestId("ManageAssetCode")).toHaveText("E2E"); - await expect(page.getByTestId("ManageAssetRowButton")).toHaveText("Add"); - } else if (await onLists.isVisible()) { - // Case 2: token is already on your lists - await expect(onLists).toHaveText("On your lists"); - await expect(page.getByTestId("ManageAssetCode")).toHaveText( - truncateString(TEST_TOKEN_ADDRESS), - ); - await expect(page.getByTestId("ManageAssetRowButton")).toHaveText("Add"); - } else { - throw new Error( - "Expected token to be either on or not on lists, but neither was visible", - ); - } - await page.getByTestId("ManageAssetRowButton").click(); - await expect(page.getByTestId("ToggleToken__asset-code")).toHaveText( - "E2E Token", - ); - await expect(page.getByTestId("ToggleToken__asset-add-remove")).toHaveText( - "Add Token", - ); - await page.getByRole("button", { name: "Confirm" }).click(); - await expect( - page.getByTestId("ManageAssetRowButton__ellipsis-E2E"), - ).toBeVisible(); - - // now go back and make sure the asset is displayed in the account view - await page.getByTestId("BackButton").click(); - await page.getByTestId("BackButton").click(); - await expect(page.getByTestId("account-view")).toBeVisible(); - await expect(page.getByText("E2E")).toBeVisible(); - - // now go back and remove this asset - await page.getByTestId("account-options-dropdown").click(); - await page.getByText("Manage assets").click(); - await expect(page.getByText("Your assets")).toBeVisible(); - await expect(page.getByTestId("ManageAssetCode")).toHaveText("E2E"); - await expect(page.getByTestId("ManageAssetDomain")).toHaveText( - "Stellar Network", - ); - await page.getByTestId("ManageAssetRowButton__ellipsis-E2E").click(); - await page.getByText("Remove asset").click(); - await expect(page.getByTestId("ToggleToken__asset-code")).toHaveText( - truncateString(TEST_TOKEN_ADDRESS), - ); - await expect(page.getByTestId("ToggleToken__asset-add-remove")).toHaveText( - "Remove Token", - ); - await page.getByRole("button", { name: "Confirm" }).click(); - await expect( - page.getByText("You have no assets added. Get started by adding an asset."), - ).toBeVisible(); -}); - -// Skipping this test because on Testnet, stellar.expert's asset list is formatter incorrectly -test.skip("Adding Soroban verified token", async ({ page, extensionId }) => { +// The page navigation after clicking 'Manage Assets' doesn't complete reliably. +// 'Your assets' text never appears even with long timeouts and waitForLoadState. +test.fixme("Adding Soroban verified token", async ({ page, extensionId }) => { test.slow(); await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-options-dropdown").click(); - await page.getByText("Manage Assets").click({ force: true }); - - await expect(page.getByText("Your assets")).toBeVisible(); + const manageAssetsText = page.getByText("Manage Assets"); + await expect(manageAssetsText).toBeVisible(); + await manageAssetsText.click({ force: true }); + // Wait for the manage assets page to load + await page.waitForLoadState("networkidle"); + await expect(page.getByText("Your assets")).toBeVisible({ timeout: 10000 }); await page.getByText("Add an asset").click({ force: true }); await page.getByTestId("search-asset-input").fill(USDC_TOKEN_ADDRESS); await expect(page.getByTestId("asset-on-list")).toHaveText("On your lists"); @@ -131,6 +49,7 @@ test.skip("Adding Soroban verified token", async ({ page, extensionId }) => { }); }); test("Adding token on Futurenet", async ({ page, extensionId, context }) => { + await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalances(page); await stubAccountHistory(page); @@ -165,52 +84,6 @@ test("Adding token on Futurenet", async ({ page, extensionId, context }) => { await expect(page.getByTestId("search-token-input")).toBeVisible(); }); -// Skipping this test because on Testnet, this now resolves to multiple assets -test.skip("Adding classic asset on Testnet", async ({ page, extensionId }) => { - test.slow(); - await loginAndFund({ page, extensionId }); - - await page.getByTestId("account-options-dropdown").click(); - await page.getByText("Manage assets").click(); - await expect(page.getByText("Your assets")).toBeVisible(); - await page.getByText("Add an asset").click({ force: true }); - await page - .getByTestId("search-asset-input") - .fill("GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"); - await expect(page.getByText("USDC")).toBeVisible(); - - await page.getByTestId("ManageAssetRowButton").click(); - await expect( - page.getByTestId("SignTransaction__TrustlineRow__Asset"), - ).toHaveText("USDC"); - await expect( - page.getByTestId("SignTransaction__TrustlineRow__Type"), - ).toHaveText("Add Trustline"); - await page.getByRole("button", { name: "Confirm" }).click(); - await page.getByText("Done").click(); - await expect( - page.getByTestId("ManageAssetRowButton__ellipsis-USDC"), - ).toBeVisible(); - - // now go back and remove this asset - await page.getByTestId("BackButton").click(); - await expect(page.getByText("Your assets")).toBeVisible(); - await expect(page.getByTestId("ManageAssetCode")).toHaveText("USDC"); - await expect(page.getByTestId("ManageAssetDomain")).toHaveText("centre.io"); - await page.getByTestId("ManageAssetRowButton__ellipsis-USDC").click(); - await page.getByText("Remove asset").click(); - await expect( - page.getByTestId("SignTransaction__TrustlineRow__Asset"), - ).toHaveText("USDC"); - await expect( - page.getByTestId("SignTransaction__TrustlineRow__Type"), - ).toHaveText("Remove Trustline"); - await page.getByRole("button", { name: "Confirm" }).click(); - await page.getByText("Done").click(); - await expect( - page.getByText("You have no assets added. Get started by adding an asset."), - ).toBeVisible(); -}); test.afterAll(async ({ page, extensionId }) => { if ( process.env.IS_INTEGRATION_MODE && diff --git a/extension/e2e-tests/addAsset.test.ts-snapshots/manage-assets-page-darwin.png b/extension/e2e-tests/addAsset.test.ts-snapshots/manage-assets-page-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..590d433c8f769112ce62233b16905c8c6d0911f2 GIT binary patch literal 14530 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 literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/addCollectible.test.ts b/extension/e2e-tests/addCollectible.test.ts index 04b38df5dc..fe793db7a1 100644 --- a/extension/e2e-tests/addCollectible.test.ts +++ b/extension/e2e-tests/addCollectible.test.ts @@ -7,6 +7,7 @@ import { stubTokenDetails, stubTokenPrices, stubCollectibles, + stubAllExternalApis, } from "./helpers/stubs"; test("Add a collectible to an account", async ({ @@ -18,6 +19,7 @@ test("Add a collectible to an account", async ({ owner: "", contracts: [] as { id: string; token_ids: string[] }[], }; + await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalances(page); await stubAccountHistory(page); diff --git a/extension/e2e-tests/addCollectible.test.ts-snapshots/add-collectible-page-darwin.png b/extension/e2e-tests/addCollectible.test.ts-snapshots/add-collectible-page-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..5e9bcc3a994fc397a6cc8d93b76547a08b80d598 GIT binary patch literal 12899 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 { + await stubAllExternalApis(page, context); +}); test("View Allow List selector", async ({ page, extensionId }) => { test.slow(); - await loginAndFund({ page, extensionId }); + await loginToTestAccount({ page, extensionId }); // open a second tab and go to docs playground const pageTwo = await page.context().newPage(); @@ -61,7 +66,7 @@ test("View Allow List selector", async ({ page, extensionId }) => { await page.locator("#password-input").fill(PASSWORD); await page.getByText("Create New Address").click(); - await expect(page.getByTestId("not-funded")).toBeVisible({ + await expect(page.getByTestId("account-view")).toBeVisible({ timeout: 10000, }); await page.getByTestId("network-selector-open").click(); diff --git a/extension/e2e-tests/allowList.test.ts-snapshots/allowlist-empty-darwin.png b/extension/e2e-tests/allowList.test.ts-snapshots/allowlist-empty-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..e2e07068a3932ce9e78332b5442e68ff14782018 GIT binary patch literal 12232 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 literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/allowList.test.ts-snapshots/allowlist-populated-darwin.png b/extension/e2e-tests/allowList.test.ts-snapshots/allowlist-populated-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..5ec272d7a9bcc9591ccb9f6d67de4d1c2cb48d9a GIT binary patch literal 17833 zcmeIaXH=7G`zIR24Hgg)5Cnm(Y(YVql+fcA1qBt65~L~!NDW1LiEady7EutCwgKr) zdM8*QDng|91PC=iAV5eUB$+$=o%gJn^*>+Enpx}2to44PJmlfYU9Rib?!3Hn+mQE& z=n)76!h7TT)w>YLZ{XVlzYZM$UoJ};aX=u)Avdo6X&#)hI(0ZBBOroCc1>)9wtSbK zdvfr=%#q{f$H)*65c}O-uiZ^^-jN{CDWL zTi35Q`gta{1-ZI1@l#1_uP+}mlkn32r~A1W|MDia#Zj;q&>J_UiFY5%}}x&#`*+ z)i)-3O$`muFt;?_u)v%^)m0?r;`Nk@c=@9-7$Y5gHURKD$ zJAHlq?EN_zL>p!JmipM-Ekx)*7;Y=8*sPE_fo9n3^!p5&8md8|lA%jEryv_hV+iLR zZM~f;RHqNc3lU}$aI^VQUv6n-yOzNx`Z^l&*Fd_7U&qPmSk=`NA3+|w^Pay z3G$k=FQfu-A&bbpLgbGp?`!7Y+K}oeyz#reLBpdrXmf8&dguM*<>iM;D?^7$_4a4@ zFlDrtGFckyty}FZ#yTG#pKD&!n2?<1Boh1>hNrvqyr(R}Si7T6D7$*kdy|jH-3qV4 zFniRgAiN09K48cKBZ&;Bn9i`@`zLP6*5!h9T)>DOi{iivSgRYcOvSwEN((|Wc03RW za7!es+kv^ckdDwJH4*|xA3QJGwwigax1E!fl_g?^c^ulZRv)(AXQA#4|`iN!3Zo{BOa3t(+}Tj3mctuhkBmwDIKU7xRcaFD@$D zOzsjR6r`zRR21%2|52@CwE0a6l>tLCIr(&sLnCGdvNiTMz96^K@mKA;-V;m^eGOIN zE9DJ|&oT2hh&HtYY7(R4<9lzi_a9P-Lu7R|xBd?>um*e^pzY*@BoeurFyD!-qvFD# z>gvpCZkQF}{z7oSmA<)0vj1a5tw-wzNyd_)ubFM4BPupg2={p47P-do1SXR(=437b zCsabno3kSU9URMMbh^ z_>flOeqCh&*%3R%i6$#6D=e}k%XhUZ|E?R0L6sB{dC{GYXy5I&->LT8wjE$EBq`@S z8G?H}5=~A(e6{I`7Pi-L>WZhfF6!dxIOPtm z^!2Dy%DV>J{ch5gHyeG;7&A!CX6ruSKJe+&C)Z~EZLivuA-IEX z{oH$xikBZIy<65w;0UmJ+!--xvj%5xXX!MBQgY)IN-EHyW@`0$B84~Koq*QqU9c1} z;Xmr+XbXo2E$63NN>=;L{|IU&hz}j!NV}4A{8kvbQy6pq!`{Y9MT^2oQtMW471PQj z{y|YcI$iZ-vxj+{GgZ;p?PWvd;=~;9o9TqkZ3-m;+4V7) zJnMc1#c1VU9O~wS?Qe{3(w3W>n@j3geW=Lor92dKuuzZk4jV3gmnDp*UAy@WQ+W`= z3_N__-ImgbPh+^4kdAsC;;EB80Tt6dLF?6CKaJK|s0H;c6-?$R@!sE}%C4XGGMi)v?Hlt ztUysyXU_EHDl-#~iXmFbqwh+=HtJqoUTs-#=PzaVr*o;cC%#Oiab<@Ri=8UfH-q;x zWp1V^og5+{Vvixby(@5n=q|p#`GPAk-7zo%bfcbkDl+yHl}N_QBf5wvHXW+S`Q-iYPl}zZ z+BBGrcy~_NfWaSkIQ3Y&Si|+s%WBm=H9hKa!weLQhH7Y?mnT;u=bVFrs9@i1dchUf_|yHw?(N$MzoHfQgOLjgo$9k z_Xg0o*}ZtSV5D_HO?f9+PA?)fc}*A; z)ifT~tT4I=S4$bT!Qc<({UlI*ekx-o11G%Lbyf%Qc+=ESTrG$+NfYYyh3hYUS^(Afgl5p^!!qWnWwuS1{74OGh8M+M(BxbF5;bPo4ey$;onY#EBO#I9nunHGKy9VPKwHne zHJoJQAJf9Z3_l|sohwjx9ntpY5-XFhKJkGB_Yd^c_U(KE3KqGhTZPqJ%=k8FWiu)7 zGW}d4bm@jnrr?(eD=S9yR}*VpzF~bn-R)wNh?3C2CC}~EdtqyJaLVYbv@@8ku9cq# zLEo93h7g%^Qz80Q@oKeNKyJ=2xtd3jE2Z-yZ{2-6g0!HCr=%&^8$bBkxr zlg$7wR1N%&zC5Ii7+e^ai$6^K_3M{aprue;r^t5&hxXP`wf8y&jbwEZeS(@qJ3uz| z_4Qrx&7pTITu(?X0mMSAF}x1&jfiGfuQDfcVgh$^1=TP{mP1`>2L%lPk46#J4wYI7 zI_oK?XmUhf?ll57<+qL2u~EXg&j&@Gh??tu*m>t2;c31z8xlM?fZGNwy{zq{xopA^ zLOoPzgH}rD996gBBbX?Q=S{2G|I`|W1zz6>R`zKJHTDvuNb_IFThQ9t`V!5f`e<%$%$4I>an0w$stj5VNtd5i2Ce#l>|A0vR>| zINig;!{6T@5T0W5AAi@+sT66F-%gE;G=%T^QI0}3GQKXDd0y=-Fpn3w1O`6MS^!y7 zR$973B>sRvg6$p6+=GKP)JrcF$+NGm4<=f3K!Tq-Mj1iO!cKGEEHAFCY*0-7aLtaMmt(=vQ1EH?4ES_;B~JsZfM^ z{oF8aH|dkBLfaqUHSX^r(r09Pn3q4SUnlSMN_tEe;iI6zX12ivT;7i!eVh05P?Q8c zQ$nKG{>hb`J8(EuL&HiT6$7&?t2dW*hCn*vek?-X#1f~e-=Yg8nx+REeHQwS336iZ zATSZ(+^15g?475sU=z!mxB^6Mhj#516%)gg6NAbaH$u6^AKxikd?A%6g5KC3Fo6L$ zI#N}Cug0YfkdYp+q86`1-aIS9U!OcQ)fcj!rOc5Sf(Y-7ZWI+h8=n_j%FR`I=2Aeq zX*Ofk)ycf2=MB3cQo?r*3rL?1n)DSH7x%yqj*J9-JM;V}DDpN40FxLpdgPa2q=FL< zD%~i0>lKbtMkM>xdfOHyhL@&FMb-4(wx?I6_;xvzS60IImhu!^H$JmFGP|gZGMq-k z0Q$6xpbX*nh8qfQzU#-~n3?P0GH@osXCcSW$wEKAf)A-8n0u-(3kFt+k{I?dc@RReH#{Go(goFe(G<6I;9TGld0nZHI z{N6%pUfJK>V#7{QqRdQm1Mc7dof9JB`u+8}ErSGy#+?(_-@dtTN-rVcrGzuA+rs;$ zC5!AOTC}PaA7l54^R#xo>;zTNJ9Md&TOFKyt&E)sg1cTeYBnKheZ_&bH{YGg#^53n z678U467-^?qDJh)ye1d-Rw_~H!}b<~t8DV*1W*tFg$~V+mq$0PLX3^OL4W^brO)%! z6`LiF9AKm(cT>UBdVmJozWGB=1@fe@dAr}(so$n&3e1I6SaqaSJmFu1*-5JwZ_#NF z$R2P#fB7L~W(U7FVvm*s(ca0};j&EqJGd=L*Q*sfr77ivsx7pE{or!(<*9WW+~!*_GKvPD0IQ_~{NW%OvE8>) z^O?PHd>4ZUX@%!gyV=;T6vzzmV+bzDhG!S_<6bnGy>=z=Eju}A0^eT5xVFw4Ly3?N z`T6sJapOQqnsxsfiKlfzyXMc20)D;U@{h#8=K5gtM@AM2f8`;t8iaVKM9qTc&uk>? zHc%jr+$Rr}P5>sby*vQMl5)IHjN|mg38HY9|A~vQ**m)gkFxb~uk#~Zp=`c0Rupgg zI4se(5=a?>SK2mhZhYZGczIEz60kt7Tc` zvS&l4R^l@hQjGq=WyIaZY;@;I8#XG9zVZMdcovqmkCktjy!4hzrDEO#)C3;LH4q~n zRODb41(7~%THn_!F=G}6eY?#+lH96ka7OdZf%Yym}2 zwe|b{?682|);sLiO$P=M-uETdA##@uG@7sx3SDTh0!!hQ?ZlGO$n8AIH9)^ttXz}V z*Z`xd6p9bu0wM=3r80aTye-|u41aHc%0b17m~(BS3@;HIwdy(5A&`%HenX~0`vC!u zAAkLz8m8>oO73Dag8`hXXq!}y7{1iFWMG=ui*+iDu}6Zo0!U^EPp~9_$W_suj>-!i zO|~Qe8c!h?Ukb<=9L6MTgem0uLBSvakztmMk(9I%kweubtX<@VY@i>Ar(0l$;u@>C z6`wghxp6(9!-ir0p#=S5{j*v2z=gjtUmpjp37DlABZkM_#V*R;o)H($P?k;)r%Z!WTVE^sD zk-o;|3W1bm15`;eJvDfi<7Uq$ju!%nm-(*``Tw(!`1*}xidYH<7d#sQmT|3x49Cz~?xX3MnVF>-o)f==O8>wdjHQ`HP@q=JxJ^r(cP#p#~Feth{2>$j+y2YRb-~k@?WdiDRe!IsSKYCl!C7}LNn%S5Lv?%PEK=`K>D%O(y-ScM z)@Pm+>mCrvI-9Dfs(#DeJ9Bbet0`i(Hu1YyUHz?!N<_~lB}zZVPm^hU9PBOk^X5OI zbahLcE#>6}#Wtf0Y;&p_!a|VvSfdaPfPd^m4=U}WY%6|EUaE`ek0}>Wf8?3fKdcur z`+@d;RIj+aqFqnA6WeG>t{IeA#wQS8|(D>E;cH-Z`9*Via;WY^&_un^c9B&|p(~ z8&!z=xxww%7UuiBuji-aZ&B8~lG>z>9^E}ZNO#x%!_qUn%F|PLNoPavC1rc^!2xCnwHmh zr&Ak$WP9VawVidN@H0uQBsXAZw@KIw@pp!5PxQ`s)R5-Mjf(xN}|~{nK+2 zEaE$XECk2H0z%DwxpclC6sZPV>#)~=Hkh28a;G12JEzPhWNy1JFN?<)BPK;7Y$E*< z)5VJC9o6EyQ;doQAJ~#4&!-s87j!uq`|I1-bboy*9{t&;co6O0=@b>!HfH>N2cTfk zYuN}{*dd(kA9{Zh$=u%^+o}T?EMnD3astQ^mmt%fmbdUrxGLRjjKWoh0VigJW^=~* zfJk+CPDM^t#1%T%K;f--dR~q{BgMpsN1|D~bJR!EeOP9B`mgcPNprXZ`~`&B?d0Fo z?3iP9-r|RE_UGgaYf+q0$|p(IL#Il6>>Z^|vQFdKNY8KT-i1lfoa}z#aZbV;cFLgcN4RyIUb1!>$I*Kn6Oo@na zMdNI2IP=2uKU(Qi>&zB3z2%*XtKRl6eYUV$(YpDAxCvANwl=}Wnh3=De5wPOY}S5~ zp~TC1;3I?q;=Z#tf{p~LxUk*hzU9Jfdj;71p}9ti?s|xcEqm4@0eIA-O-Hd6TlD_C zB3K;=e8^%ZpVrdfjcx#s#?gOf>C!>-2WULfZz^EKLXr;D9tL|I<)_+FP3j`5T)e7dZrcMm*_ZJR4k7+XtXTSRQf0?0d!j-9bVZ7X)`;fvaY!no9J zKvWiibpkvb@DrVP@H#l&gzvWmxzJ6Uy4zV)yQaH-*8{w_#KD% zcKJDfWr~;Q`Fhon29rk_s#TiAAV(V~eSOOD=_E#u)3MW0vyC?@CZ;mmZ^YN0YFoPIp0BTTaWONtQN~`1>$n!aZ2OE z@2?9A3YKtelEUUVbW)4cE^zp^dJvH{IXN>wRj~0!`#WIz0QYLz8y#uisY{ymeK20@ z24j*@d9Mg#c~99Gd};JiH*v}yP)sDzEIT&1eP`T5s+l7u*Cz(9g zT1a!!1B^t$zExvS(^80W8t)WRCS!lMH3lf57b4{e4*OhUo<2a*^a6Gno4m{xbYK0iH84ZTk61>%5czP^1&2WI`$iM}*#suH;6hrxTqXco=`7jRCz$ z$7kOm-*#C{B(^f`)QFIwo=kC0PKE9F6eFx3*V2o&Lp9$<4vja8_Ur;07^+%kcvgk$ z1AnkGEuj<*Hs4vxyyxt4P}C#xOahpDpm^#}3YraDeHpevFsf7AE-qv!@7gx`Imf%_ zX*!*6?owfUNGdKrU#MO6d25s}Uq71LtRo9`DFM8eKfmv-p=8A4i}4+amO8-M8qu(( zv8@+wZf-n_NyP|s%Eg;{P0CQ`*8e!7bGAk+DX}Z@OrUz`f%4!Ak$V`d2)tp;B^_`y zwm4auMP32?kO6EuA+uRP1>}6|%FE^LS%4adRQl|1b%krc-~Xl0SDw|{TvMYmeB7e- z@p6BomhbG>V6rkFsvB+>VDYnoPhadVyic1 z^WR#4R^TG=YP^3WUl=Gf!8@ng#QH}_Dfl+#Gus~0-_E0IN&BH6>LT1mY0^S2&dTE z$BPN88x*vP23V{D57Bj&{fv~`A;T!T5{bgUKB8)uWqjk_<@+h=3tN>U|* zr=N;w7`nhKalqLb+T$I>7^!uGopD5(xaLo}s)D!$4OBUer%NL)b{r!vh%!+g5Im9%-}(QF(ZHuSuW|dSA7>`O>Lh+YjP% z20v~K)3H4za7DiW|93qj2R&8n#@@N!KeM5 z=%Cl`Mt}-n)%1SPdyc_}06o(NC39pw7^B@Kvr^OE+eXFF36iYf?Om|Wc0ekiZ9%Pa z7nDie`WRY30^0v7eRMEr{}!3`cbX;~i~0?MTq#l04h&s%)jc8dZS?@}*f+yd&Uwx@ zi4PF)Al98?oxK@@ruyN%cLNgzx4loDz9@eW$M_~tDy&;C+b&_#U*|}m zTsrv!Obh=p(7eC1dz}T`j_r*^9n)HJ07(TYDYkP8vK{}FwMkb{|W0?Wkmz8U_uq3)_pTJ%NR#*d)^`^T_kfoq(wwP&Xw%#-D;t0Ncw&M|`M7tQ(S z=X_#1cU#Ka46A7<2|lp+wkS$G>Q&CGd?fLyPqDfE)DXJ12HO6%e93NjtR~zUUsCb( zQ_f65*X)O#uI~crqAN$`;1pn8ggz>QS*F=6M*iZj;CEx|Q&Nur?PMF&x8JK4hYqNX z*b1c3+No`dF>U;wY{`)A2R2OaZ{6~ z0R{okuvA)h@a#*g3FJNo84kh+!NU%pfUg+@un*%4Y+wIox|6E7aBd_BJd7NgX6;q7 zVzu|_Xcj#~(;p-P=t#-kZ-&*BkD(Oem7I@Xj%ll^s_qlv=-BT&GtVU@U{`oLP#Uu@ z^p9yi+>e}cnoZpT8Yw!I?aIA$jmKMzH6KP{i-r(O*rolO(3)ec9ZneLC3SCSNgP8DP8hwKY5H zd&2y+H5N#A&>E2RhHizHi`AME6gr-zXa7J)ePM|Frh-v4R^y7g)k%OJCy;1%ogV2R zV8X4p@s!5c2blB)`q;xfnaNnZLBKiXABmC=JuyJyMTcW`sqtLB2H2*_#cYEsn4SV-K?Igv#5~D**XmZ4*B@u1j{-d>BGk>q-l}GITyk)QF zJf2Zs&s#t4_XgVPz0w0sAOCgd;z@(Rr1QLRu9zRnn-NPh^KzDy1YOy#&po#&W?Ju| zxQ}gh#gX?vKE_8GE40j3gpq7U2kHQ+-9_nyuMjP;o8J!tan2x_|7ns}N?{gMtKhxq z6Xlcas6wfXy99EeAl+M((PR+P^~yglL7hk>hJuU+n3U>8=i#z@${~@ondg{ec@fsi z?uo7_*L{HN+b|Mg7aiJl!qiQBeH+}7U6+GFu|PctNJh3!dosRmXlB*!eRkvpiKPcT z9c+o-KnzU~UtbbYV~Q-CpQE*0HjilS1r3aN{WQe=#ALL=HD$26am>4J$K7vk*wE)OWY~Eevn5x>708o*t*^<8KyWr|jWYlCD$S zboaYu8Btt9h01YP{r@*1V9800)nhk$yy* zZnv1I&F1ds>FMi@>S|rlITmIU+R`8d2u(IbVS5(+=Z&0;RBd%X`3D6#1i|x53lZd5 zXHzs_50euND-&uzjx=BOxy*p~*fD#UY?xc)Vpdqza)C!>n>y!{?IMR@=>sCnTr{Gy zM5uG7|J!QN*y~C0`Tjgq;BC^QbmfSCX)zPG%wMWX8k18hzb2rgBQSG`3Lf5L@WkTN}C&#uYQH)uqF!H@$k>GV0anq~guOWTx`tDCIg(Rsh(!a~>1O`&e- zz%tvRfe9E8I-G+W`(by8Lu)zH1QNmGvzPYn&J9bS~wG4@i!- zem!)bCdpp`)Uv!t?!7Q;YdAb6EH`><*Ve?O_>QNDtVN8`{M};P;^esKLkpk!@0*xV zt4S893VX^`6KZT0XBJbaKre0?xW>DOV0#WqeAWuX=WJE2+=v->Iv*Jy+B82neY*vMH zDO@j0anSi*&g*&E6sz5D6BD_9uvbhv~4`~#u5@mr9l*Ch-*js7-XZ&QzPj>Hs{TR()JW# z1Mqk{nKM9%*W$Q&VwShfR>6>Sacd_O0-;G(CCshne9#BpaIj5fR^J(zEL4^ga^1w) zJj9&q0)NLJm@r)k%g2}^TPVOJzD%ca&uxhbt>Et9Ym01~OI0-< z@m#*NdFsQ1yeq!=uD2i)UR}9}`@{jluYbs?KXddyuO90-@Tf9oVf5yY-+7t$WDeIH z4M-P?h3-(wAAdax=_nF8YRCmMmF@9*l$NYGsj2$v&vF%xf}J(n5e@lNbVVhcaR5?w zM*WqeN^$hH<_O3O4w@A>8X(Jv!Gj7H@}LjLH({*FN%j+^om6%{%1sV&CfRXXXT z4}ZXAt9FzBTm!VK?B(wMpe=4y7;;~?GsetQPgCZk+D*WYi2hAe#B`E`j{-M{p#H9& z9a!Y?;#M(_dlIBT-OH@ZK~;6G3=SyM4NtvJ19ML!=R0vAhEt@Lnw_Gkr=gk#a!#lJ zxzNdF!KH?Q4G;c377fPmPVwFE?BuDVl&pHbi}r~$>puW_15<-aW)rTg)Y0Tv-Vz@7 zMD)rXkAk_QV8())GB}Fgo0X-T!GnAq5VoT=#kVBTG_$OFMvCzMo^XIYD)4gN&=k-nT6;F0_TO zx)mJYi4}Ck*doaW!RODEHYb6 zG6TCx?dheRe8{;jF{T%({<&BCe4%&Sa>j3b&X-?1M!8o*3KkB5WZ4H>=F11*ctQVJ z@4SH0mmo7o5%ZrWzV0zF{KS`-7(L>%_#-7%hxzDCYWh@vGu1!^Swk1YhfNKQDA@TS z;Uh1DSi8)jm6Rk!@vz(YjaQoKus(c476*?Ku4HqgHn;8XVl@!2RymW6{Bhi^!N~7AQ)lnW#1WG9Ep-H`o4aC9pfTm&S~} zA>MQ`-P{4)oy_|-QF@8Hew0X<@C?EdErQCd$P1^$+5*13Ln4QS8Y-6JnL6&I`h348 zf1i!E^d3#0H)DvV+5X)ryTY~2_frM8#bi?@S5_vfoHp-Oj;&3N*itag#(B^4tQT)( zm{*v`$fZ0Q*Dbh(+?r3l8jN=ApF1?@H6ast?3m}U)`P9XUSetu`zr|}n9td060hkr zHJ}`q-WEUGz zHj`l&v|fa03>zw;MUF1m^m=8}vOFq&K)PP?mW-BxP(Lm2SY1Kdd^qI9ht*I0zb@F7 zmbi9U(}%yv)EYAMyu>PJa6?k`>m&190>rH9tf|6;cnfsE`qXnf4N7 z*fRH*og#BeJ~Pww*YoX%l6NV=-^KaJMR_J^<7}M}YZe&pl zeS$i*^;S+HWJC=uX~+7&GhOT$CHv381Zi+C`EQ~xTGFA)GhyDz@Bpk-B*7)m^$SrU zrArYt<8{*(UAI-L*Jigagn}`9!q)GN4(Pgmem3klHH*uFRa&2-?tbloMlKB7#K_J^ zK__%7>}ww1h({7Whr~%TzYR~cdOj|(4KQ2Wtmu0aFjeP1FQ=vT9+Ti+89qy@94%<#h-T2Xdw|Jm_Ql{Oc-+a9ngE8lQrC!N^9(AicXT6N zd+o%VIjg&=Tim|vljp^1`DG^rPUzpiJ~n!4d49OOp=kT4y+DLh@sNv%kwO>qpG`lXc5ULJN zXSFnLtaQe8DPj}C@Atdx+LCxv?Q1dl!i?FO=&Gl|9n$G~dZBl z;;9&qvz?`C%x_B)Q#SQ=om6pcX^a`teIjJV3OnJ_8|$LC_LP3Cd7-4+5F47wQPvq^ zQFKEZWP&UFn$)t_1J6FXJ~0}SwJ5kUtU-cGcVHj$Y-FjZPd0lw>YqW+KdUdA1Z$(I ztFNZ&9IbaO-CH@wD}852E-P3E_C7H)iW5bpGTe5nGi6LPy;4Ue>vOjxp_v2r4oLsS z&3py}MWJ|24Kr(|>?OPLP2UTASv3o=G+o6-g;1KB*iBu(6))-GA+-AsF0wn4x-=_h z(0jFQ>5EN|E^}TxvxPR(fXxt6tlSgi%*)0#VGU|dQg+OP@+(S6DDg^n)UpZ=>KfOW zG0@Rr?HEg`9YR%NSFjC@CL%iR>g_hR6 z0JFkQIBR1g35whJwq!+PAX^t~w9!P+GQPsMx0d-PgNFCHs~6|dlJ*~OfP)dB^44tG zzfF)x2wz=m=!`Zap`l&qu%6MSqNa&1v#Yh)4Z(ASB!$S;z91}aHDSQDjK5P(Bz4l72?yc5T}3d_a^W$11=jQAePlPHukPf1i+FB;gw1olv(Qm zwK8io0Ywpi$BDAH#~cjS74mC3-}RD0G1;cTw7e~puVoJPU&^rxau^}9TkK}SdmAm{ zisUMZc%khV3|l7{2TsH(EU!Ck4w{fM`+qf>`fo*nv-N~=J$v_`xpd<%9+D!br^ISj zgqfjFtSQ8Tg$d)RZUgGMkQw{03A({&4k{@gRwRYZ+K5_vudde#t3o=q2Hs=W2S>v{ zT{hV{%ijSGs~tY6_NZ^;mw^d&HyZ@VQU8WnKpdABQRtB!7Rns>4Km#nmryjCY^}6< z{IL5ga4i7-Bko7OW}amHVMvGn2{F^E3qxx>R_x%p7aQxAR(LzMvqS4R$E^$MxsGPC zQEWhWD=Otjk3OfrnCO2O(WmrOMbhv7E3h8=u(9^TU0iz(_#lk?x?kC_Q~vRuoO>#y z;O&&A>Yd*CdUlc+E3N)+v&q&|&-qRZfR-c^eFoXm`xp=8Hj)Ik8BKbqz=0;4-OCx`nvmvQe3I4@S2*4lWA$-$iKUWQuVr z&-P9_?<*dTn^(BxQf!`cNqpn&Np$mZ+Pa)Ssj1UiqI3G(>2-S7XUOI9*arwF1>vcQ zEXBuyNB%`DFJ_d3f>$_=byJIXNLhF;9 { + await stubAllExternalApis(page, context); + + // Override account-balances to return 0 XLM balance + await page.route("**/account-balances/**", async (route) => { + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: "0", + available: "0", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, + }, + }, + }, + isFunded: false, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + await route.fulfill({ json }); + }); + + // Stub /token endpoint + await page.route("**/token", async (route) => { + await route.fulfill({ + json: { + data: { + token: "MWYwZjU5ODEtYjkxOC02YzkwLWI3YzItNWVhZDYyZDQ1M2M0", + }, + }, + }); + }); +}); test("should show add XLM page and open Coinbase", async ({ page, extensionId, }) => { - test.slow(); - await loginAndFund({ page, extensionId }); + await loginToTestAccount({ page, extensionId }); await page.getByTestId("network-selector-open").click(); await page.getByText("Main Net").click(); @@ -32,8 +87,7 @@ test("should show Buy with Coinbase and open Coinbase", async ({ page, extensionId, }) => { - test.slow(); - await loginAndFund({ page, extensionId }); + await loginToTestAccount({ page, extensionId }); await page.getByTestId("network-selector-open").click(); await page.getByText("Main Net").click(); diff --git a/extension/e2e-tests/buyWithOnramp.test.ts-snapshots/add-xlm-page-darwin.png b/extension/e2e-tests/buyWithOnramp.test.ts-snapshots/add-xlm-page-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..fb8b01ba1f405d19926ebf367bc602577e047632 GIT binary patch literal 26963 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%0AaV}d+Ojn3&rJTi&zmwM; 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 literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/buyWithOnramp.test.ts-snapshots/buy-with-coinbase-darwin.png b/extension/e2e-tests/buyWithOnramp.test.ts-snapshots/buy-with-coinbase-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..4a406ca026a1e0fb0b47e141e29d967f9d1666f5 GIT binary patch literal 26915 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 Jo~i4l{{ueKKh*#L literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/helpers/allowDapp.ts b/extension/e2e-tests/helpers/allowDapp.ts index c41df6d5fd..f6e92999ee 100644 --- a/extension/e2e-tests/helpers/allowDapp.ts +++ b/extension/e2e-tests/helpers/allowDapp.ts @@ -1,4 +1,4 @@ -import { expect, test } from "../test-fixtures"; +import { expect } from "../test-fixtures"; export const allowDapp = async ({ page }) => { // open a second tab and go to docs playground diff --git a/extension/e2e-tests/helpers/login.ts b/extension/e2e-tests/helpers/login.ts index 3f9fc0bf63..6e08ebe2bb 100644 --- a/extension/e2e-tests/helpers/login.ts +++ b/extension/e2e-tests/helpers/login.ts @@ -45,6 +45,17 @@ export const login = async ({ }); await page.getByTestId("network-selector-open").click(); await page.getByText("Test Net").click(); + + // Wait for account-balances API call with TESTNET network param before clicking + const balancesPromise = page.waitForResponse( + (response) => + response.url().includes("/account-balances/") && + response.url().includes("network=TESTNET"), + ); + + // Wait for the balances API call to complete + await balancesPromise; + await expect(page.getByTestId("account-view")).toBeVisible({ timeout: 10000, }); @@ -58,9 +69,11 @@ export const loginAndFund = async ({ extensionId: string; }) => { await login({ page, extensionId }); + await expect(page.getByTestId("not-funded")).toBeVisible({ timeout: 10000, }); + await page.getByRole("button", { name: "Fund with Friendbot" }).click(); await expect(page.getByTestId("account-assets")).toBeVisible({ diff --git a/extension/e2e-tests/helpers/sendPayment.ts b/extension/e2e-tests/helpers/sendPayment.ts index 5d0072f47d..fa9453f945 100644 --- a/extension/e2e-tests/helpers/sendPayment.ts +++ b/extension/e2e-tests/helpers/sendPayment.ts @@ -1,7 +1,7 @@ -import test from "@playwright/test"; +import test, { Page } from "@playwright/test"; import { expect, expectPageToHaveScreenshot } from "../test-fixtures"; -export const sendXlmPayment = async ({ page }) => { +export const sendXlmPayment = async ({ page }: { page: Page }) => { test.setTimeout(180_000); await page.getByTestId("nav-link-send").click({ force: true }); diff --git a/extension/e2e-tests/helpers/stubs.ts b/extension/e2e-tests/helpers/stubs.ts index 601111b085..c9c07d87ae 100644 --- a/extension/e2e-tests/helpers/stubs.ts +++ b/extension/e2e-tests/helpers/stubs.ts @@ -22,6 +22,261 @@ export const STELLAR_EXPERT_ASSET_LIST_JSON = { ], }; +export const stubUserNotification = async (context: BrowserContext) => { + await context.route("*/**/user-notification", async (route) => { + await route.fulfill({ + json: { enabled: false, message: "" }, + }); + }); +}; + +export const stubFeatureFlags = async (context: BrowserContext) => { + await context.route("*/**/feature-flags", async (route) => { + await route.fulfill({ + json: { useSorobanPublic: true }, + }); + }); +}; + +export const stubSubscriptionAccount = async (context: BrowserContext) => { + await context.route("*/**/subscription/account", async (route) => { + await route.fulfill({ + json: { data: {}, error: null }, + }); + }); +}; + +export const stubStellarAssetList = async (page: Page) => { + await page.route("*/**/testnet/asset-list/**", async (route) => { + await route.fulfill({ json: STELLAR_EXPERT_ASSET_LIST_JSON }); + }); +}; + +export const stubAssetSearch = async (page: Page) => { + await page.route("**/asset?search**", async (route) => { + const json = { + _embedded: { + records: [ + { + asset: + "USDC-GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + num_accounts: 1000, + num_trades: 5000, + num_liquidity_pools: 100, + bidding_liabilities: "1000000", + asking_liabilities: "2000000", + }, + ], + }, + }; + await route.fulfill({ json }); + }); +}; + +export const stubHorizonAccounts = async (page: Page) => { + await page.route("**/accounts/**", async (route) => { + await route.fulfill({ + json: { + id: "GDMDFPJPFH4Z2LLUCNNQT3HVQ2XU2TMZBA6OL37C752WCKU7JZO2S52R", + account_id: "GDMDFPJPFH4Z2LLUCNNQT3HVQ2XU2TMZBA6OL37C752WCKU7JZO2S52R", + sequence: "1234567890", + subentry_count: 0, + last_modified_ledger: 12345, + balances: [ + { + balance: "10000.0000000", + asset_type: "native", + }, + ], + signers: [ + { + weight: 1, + key: "GDMDFPJPFH4Z2LLUCNNQT3HVQ2XU2TMZBA6OL37C752WCKU7JZO2S52R", + type: "ed25519_public_key", + }, + ], + data: {}, + thresholds: { + low_threshold: 0, + med_threshold: 0, + high_threshold: 0, + }, + }, + }); + }); +}; + +export const stubHorizonTransactions = async (page: Page) => { + await page.route("**/horizon/**/transactions", async (route) => { + if (route.request().method() === "POST") { + await route.fulfill({ + json: { + hash: "d7fc8d3f7b9e8c7d6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c", + ledger: 10000, + envelope_xdr: + "AAAAAgAAAABNGU5jYvjfSepLUbRF52FIw18Fm1F76RViTI0pjWF7VAAAAAAAAAQoAAAAAAAAAA==", + result_xdr: "AAAAAAAAACgAAAAAAAAAA==", + }, + }); + } else { + await route.fulfill({ + json: { + _embedded: { records: [] }, + }, + }); + } + }); +}; + +export const stubBackendSimulateTx = async (page: Page) => { + await page.route("**/simulate-tx**", async (route) => { + await route.fulfill({ + json: { + preparedTransaction: + "AAAAAgAAAABNGU5jYvjfSepLUbRF52FIw18Fm1F76RViTI0pjWF7VAAAAZAAAAABAAAAAAAAAAEAAAAAAAAAAAAAAAEAAAAAAAAABAAAAAAAAAAAAAA=", + simulationResponse: { + minResourceFee: "100", + cost: { + cpuInsns: "1000", + memBytes: "1000", + }, + latestLedger: "10000", + }, + }, + }); + }); +}; + +export const stubBackendSubmitTx = async (page: Page) => { + await page.route("**/submit-tx**", async (route) => { + await route.fulfill({ + json: { + hash: "a7f2d8c9e1b4f3a6d5c8b7e9f1a2d3c4b5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0", + ledger: 10000, + envelope_xdr: + "AAAAAgAAAABNGU5jYvjfSepLUbRF52FIw18Fm1F76RViTI0pjWF7VAAAAZAAAAABAAAAAAAAAAEAAAAAAAAAAAAAAAEAAAAAAAAABAAAAAAAAAAAAAA=", + result_xdr: "AAAAAAAAAGQAAAAAAAAAAQAAAAAAAAABAAAAAAAAAAA=", + }, + }); + }); +}; + +export const stubStellarToml = async (page: Page) => { + await page.route("**/.well-known/stellar.toml", async (route) => { + await route.fulfill({ + body: `FEDERATION_SERVER="https://federation.lobstr.co" +NETWORK_PASSPHRASE="Test SDF Network ; September 2015"`, + contentType: "text/plain", + }); + }); +}; + +export const stubFederation = async (page: Page) => { + await page.route("**/federation**", async (route) => { + await route.fulfill({ + json: { + stellar_address: "freighter.pb*lobstr.co", + account_id: "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF", + }, + }); + }); +}; + +export const stubDefaultAccountBalances = async (page: Page) => { + await page.route("**/account-balances/**", async (route) => { + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: "10000.0000000", + available: "10000.0000000", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, + }, + }, + }, + isFunded: true, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + await route.fulfill({ json }); + }); +}; + +export const stubMercuryTransactions = async (page: Page) => { + await page.route("**/transactions**", async (route) => { + await route.fulfill({ + json: { + _embedded: { records: [] }, + }, + }); + }); +}; + +export const stubSorobanRpc = async (page: Page) => { + await page.route("**/soroban/rpc/**", async (route) => { + await route.fulfill({ + json: { jsonrpc: "2.0", id: "1", result: null }, + }); + }); +}; + +export const stubBackendSettingsEndpoint = async (page: Page) => { + await page.route("**/backend-settings", async (route) => { + await route.fulfill({ + json: { + isSorobanPublicEnabled: true, + isRpcHealthy: true, + userNotification: { enabled: false, message: "" }, + }, + }); + }); +}; + +export const stubLedgerKeysAccounts = async (page: Page) => { + await page.route("**/ledger-keys/accounts/**", async (route) => { + await route.fulfill({ + json: { + data: {}, + error: null, + }, + }); + }); +}; + +export const stubFriendbot = async (page: Page | BrowserContext) => { + await page.route("**/friendbot**", async (route) => { + const json = { + hash: "d7fc8d3f7b9e8c7d6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c", + ledger: 10000, + envelope_xdr: + "AAAAAgAAAABNGU5jYvjfSepLUbRF52FIw18Fm1F76RViTI0pjWF7VAAAAAAAAAQoAAAAAAAAAAENQJiZNGU5jYvjfSepLUbRF52FIw18Fm1F76RViTI0pjWF7VAAACgDAAAAFQAAAAEAAAA=", + result_xdr: "AAAAAAAAACgAAAAAAAAAAQAAAAAD6QAAAAAAAAAA", + }; + await route.fulfill({ json }); + }); +}; + export const stubScanDapp = async (context: BrowserContext) => { await context.route("**/scan-dapp**", async (route) => { const json = { @@ -798,22 +1053,1054 @@ export const stubSimulateTokenTransfer = async ( // Backend returns: { simulationResponse: {...}, preparedTransaction: "..." } const json = { simulationResponse: { - minResourceFee: "100", - results: [], - cost: { - cpuInsns: "100", - memBytes: "100", + _parsed: true, + latestLedger: 60969445, + events: [ + { + _attributes: { + inSuccessfulContractCall: true, + event: { + _attributes: { + ext: { + _switch: 0, + }, + type: { + name: "diagnostic", + value: 2, + }, + body: { + _switch: 0, + _arm: "v0", + _value: { + _attributes: { + topics: [ + { + _switch: { + name: "scvSymbol", + value: 15, + }, + _arm: "sym", + _armType: { + _maxLength: 32, + }, + _value: { + type: "Buffer", + data: [102, 110, 95, 99, 97, 108, 108], + }, + }, + { + _switch: { + name: "scvBytes", + value: 13, + }, + _arm: "bytes", + _armType: { + _maxLength: 4294967295, + }, + _value: { + type: "Buffer", + data: [ + 51, 120, 205, 202, 109, 33, 164, 194, 5, 219, + 69, 26, 124, 216, 96, 210, 220, 233, 172, 131, + 124, 131, 55, 133, 20, 250, 59, 61, 195, 99, + 234, 75, + ], + }, + }, + { + _switch: { + name: "scvSymbol", + value: 15, + }, + _arm: "sym", + _armType: { + _maxLength: 32, + }, + _value: { + type: "Buffer", + data: [116, 114, 97, 110, 115, 102, 101, 114], + }, + }, + ], + data: { + _switch: { + name: "scvVec", + value: 16, + }, + _arm: "vec", + _armType: { + _childType: { + _maxLength: 2147483647, + }, + }, + _value: [ + { + _switch: { + name: "scvAddress", + value: 18, + }, + _arm: "address", + _value: { + _switch: { + name: "scAddressTypeAccount", + value: 0, + }, + _arm: "accountId", + _value: { + _switch: { + name: "publicKeyTypeEd25519", + value: 0, + }, + _arm: "ed25519", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 103, 128, 20, 230, 110, 101, 50, 114, 161, + 182, 112, 3, 7, 114, 137, 146, 71, 205, + 29, 71, 49, 173, 43, 60, 76, 234, 6, 247, + 203, 36, 131, 228, + ], + }, + }, + }, + }, + { + _switch: { + name: "scvAddress", + value: 18, + }, + _arm: "address", + _value: { + _switch: { + name: "scAddressTypeAccount", + value: 0, + }, + _arm: "accountId", + _value: { + _switch: { + name: "publicKeyTypeEd25519", + value: 0, + }, + _arm: "ed25519", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 103, 128, 20, 230, 110, 101, 50, 114, 161, + 182, 112, 3, 7, 114, 137, 146, 71, 205, + 29, 71, 49, 173, 43, 60, 76, 234, 6, 247, + 203, 36, 131, 228, + ], + }, + }, + }, + }, + { + _switch: { + name: "scvI128", + value: 10, + }, + _arm: "i128", + _value: { + _attributes: { + hi: { + _value: "0", + }, + lo: { + _value: "100000", + }, + }, + }, + }, + ], + }, + }, + }, + }, + }, + }, + }, + }, + { + _attributes: { + inSuccessfulContractCall: true, + event: { + _attributes: { + ext: { + _switch: 0, + }, + contractId: { + type: "Buffer", + data: [ + 51, 120, 205, 202, 109, 33, 164, 194, 5, 219, 69, 26, 124, + 216, 96, 210, 220, 233, 172, 131, 124, 131, 55, 133, 20, + 250, 59, 61, 195, 99, 234, 75, + ], + }, + type: { + name: "contract", + value: 1, + }, + body: { + _switch: 0, + _arm: "v0", + _value: { + _attributes: { + topics: [ + { + _switch: { + name: "scvSymbol", + value: 15, + }, + _arm: "sym", + _armType: { + _maxLength: 32, + }, + _value: { + type: "Buffer", + data: [116, 114, 97, 110, 115, 102, 101, 114], + }, + }, + { + _switch: { + name: "scvAddress", + value: 18, + }, + _arm: "address", + _value: { + _switch: { + name: "scAddressTypeAccount", + value: 0, + }, + _arm: "accountId", + _value: { + _switch: { + name: "publicKeyTypeEd25519", + value: 0, + }, + _arm: "ed25519", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 103, 128, 20, 230, 110, 101, 50, 114, 161, + 182, 112, 3, 7, 114, 137, 146, 71, 205, 29, + 71, 49, 173, 43, 60, 76, 234, 6, 247, 203, + 36, 131, 228, + ], + }, + }, + }, + }, + { + _switch: { + name: "scvAddress", + value: 18, + }, + _arm: "address", + _value: { + _switch: { + name: "scAddressTypeAccount", + value: 0, + }, + _arm: "accountId", + _value: { + _switch: { + name: "publicKeyTypeEd25519", + value: 0, + }, + _arm: "ed25519", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 103, 128, 20, 230, 110, 101, 50, 114, 161, + 182, 112, 3, 7, 114, 137, 146, 71, 205, 29, + 71, 49, 173, 43, 60, 76, 234, 6, 247, 203, + 36, 131, 228, + ], + }, + }, + }, + }, + ], + data: { + _switch: { + name: "scvI128", + value: 10, + }, + _arm: "i128", + _value: { + _attributes: { + hi: { + _value: "0", + }, + lo: { + _value: "100000", + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + _attributes: { + inSuccessfulContractCall: true, + event: { + _attributes: { + ext: { + _switch: 0, + }, + contractId: { + type: "Buffer", + data: [ + 51, 120, 205, 202, 109, 33, 164, 194, 5, 219, 69, 26, 124, + 216, 96, 210, 220, 233, 172, 131, 124, 131, 55, 133, 20, + 250, 59, 61, 195, 99, 234, 75, + ], + }, + type: { + name: "diagnostic", + value: 2, + }, + body: { + _switch: 0, + _arm: "v0", + _value: { + _attributes: { + topics: [ + { + _switch: { + name: "scvSymbol", + value: 15, + }, + _arm: "sym", + _armType: { + _maxLength: 32, + }, + _value: { + type: "Buffer", + data: [ + 102, 110, 95, 114, 101, 116, 117, 114, 110, + ], + }, + }, + { + _switch: { + name: "scvSymbol", + value: 15, + }, + _arm: "sym", + _armType: { + _maxLength: 32, + }, + _value: { + type: "Buffer", + data: [116, 114, 97, 110, 115, 102, 101, 114], + }, + }, + ], + data: { + _switch: { + name: "scvVoid", + value: 1, + }, + }, + }, + }, + }, + }, + }, + }, + }, + ], + transactionData: { + _data: { + _attributes: { + ext: { + _switch: 0, + }, + resources: { + _attributes: { + footprint: { + _attributes: { + readOnly: [ + { + _switch: { + name: "contractData", + value: 6, + }, + _arm: "contractData", + _value: { + _attributes: { + contract: { + _switch: { + name: "scAddressTypeContract", + value: 1, + }, + _arm: "contractId", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 51, 120, 205, 202, 109, 33, 164, 194, 5, + 219, 69, 26, 124, 216, 96, 210, 220, 233, + 172, 131, 124, 131, 55, 133, 20, 250, 59, + 61, 195, 99, 234, 75, + ], + }, + }, + key: { + _switch: { + name: "scvLedgerKeyContractInstance", + value: 20, + }, + }, + durability: { + name: "persistent", + value: 1, + }, + }, + }, + }, + { + _switch: { + name: "contractCode", + value: 7, + }, + _arm: "contractCode", + _value: { + _attributes: { + hash: { + type: "Buffer", + data: [ + 144, 12, 51, 182, 156, 190, 52, 116, 141, 244, + 68, 63, 118, 129, 119, 90, 2, 179, 5, 153, + 227, 186, 185, 199, 201, 248, 179, 34, 90, 59, + 31, 27, + ], + }, + }, + }, + }, + ], + readWrite: [ + { + _switch: { + name: "contractData", + value: 6, + }, + _arm: "contractData", + _value: { + _attributes: { + contract: { + _switch: { + name: "scAddressTypeContract", + value: 1, + }, + _arm: "contractId", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 51, 120, 205, 202, 109, 33, 164, 194, 5, + 219, 69, 26, 124, 216, 96, 210, 220, 233, + 172, 131, 124, 131, 55, 133, 20, 250, 59, + 61, 195, 99, 234, 75, + ], + }, + }, + key: { + _switch: { + name: "scvVec", + value: 16, + }, + _arm: "vec", + _armType: { + _childType: { + _maxLength: 2147483647, + }, + }, + _value: [ + { + _switch: { + name: "scvSymbol", + value: 15, + }, + _arm: "sym", + _armType: { + _maxLength: 32, + }, + _value: { + type: "Buffer", + data: [66, 97, 108, 97, 110, 99, 101], + }, + }, + { + _switch: { + name: "scvAddress", + value: 18, + }, + _arm: "address", + _value: { + _switch: { + name: "scAddressTypeAccount", + value: 0, + }, + _arm: "accountId", + _value: { + _switch: { + name: "publicKeyTypeEd25519", + value: 0, + }, + _arm: "ed25519", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 103, 128, 20, 230, 110, 101, 50, + 114, 161, 182, 112, 3, 7, 114, 137, + 146, 71, 205, 29, 71, 49, 173, 43, + 60, 76, 234, 6, 247, 203, 36, 131, + 228, + ], + }, + }, + }, + }, + ], + }, + durability: { + name: "persistent", + value: 1, + }, + }, + }, + }, + ], + }, + }, + instructions: 817757, + diskReadBytes: 0, + writeBytes: 148, + }, + }, + resourceFee: { + _value: "93238", + }, + }, + }, }, - transactionData: "", - events: [], - returnValue: "", - auth: [], - footprint: { - readOnly: [], - readWrite: [], + minResourceFee: "93238", + result: { + auth: [ + { + _attributes: { + credentials: { + _switch: { + name: "sorobanCredentialsSourceAccount", + value: 0, + }, + }, + rootInvocation: { + _attributes: { + function: { + _switch: { + name: "sorobanAuthorizedFunctionTypeContractFn", + value: 0, + }, + _arm: "contractFn", + _value: { + _attributes: { + contractAddress: { + _switch: { + name: "scAddressTypeContract", + value: 1, + }, + _arm: "contractId", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 51, 120, 205, 202, 109, 33, 164, 194, 5, 219, + 69, 26, 124, 216, 96, 210, 220, 233, 172, 131, + 124, 131, 55, 133, 20, 250, 59, 61, 195, 99, + 234, 75, + ], + }, + }, + functionName: { + type: "Buffer", + data: [116, 114, 97, 110, 115, 102, 101, 114], + }, + args: [ + { + _switch: { + name: "scvAddress", + value: 18, + }, + _arm: "address", + _value: { + _switch: { + name: "scAddressTypeAccount", + value: 0, + }, + _arm: "accountId", + _value: { + _switch: { + name: "publicKeyTypeEd25519", + value: 0, + }, + _arm: "ed25519", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 103, 128, 20, 230, 110, 101, 50, 114, 161, + 182, 112, 3, 7, 114, 137, 146, 71, 205, + 29, 71, 49, 173, 43, 60, 76, 234, 6, 247, + 203, 36, 131, 228, + ], + }, + }, + }, + }, + { + _switch: { + name: "scvAddress", + value: 18, + }, + _arm: "address", + _value: { + _switch: { + name: "scAddressTypeAccount", + value: 0, + }, + _arm: "accountId", + _value: { + _switch: { + name: "publicKeyTypeEd25519", + value: 0, + }, + _arm: "ed25519", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 103, 128, 20, 230, 110, 101, 50, 114, 161, + 182, 112, 3, 7, 114, 137, 146, 71, 205, + 29, 71, 49, 173, 43, 60, 76, 234, 6, 247, + 203, 36, 131, 228, + ], + }, + }, + }, + }, + { + _switch: { + name: "scvI128", + value: 10, + }, + _arm: "i128", + _value: { + _attributes: { + hi: { + _value: "0", + }, + lo: { + _value: "100000", + }, + }, + }, + }, + ], + }, + }, + }, + subInvocations: [], + }, + }, + }, + }, + ], + retval: { + _switch: { + name: "scvVoid", + value: 1, + }, + }, }, + stateChanges: [ + { + type: "updated", + key: { + _switch: { + name: "contractData", + value: 6, + }, + _arm: "contractData", + _value: { + _attributes: { + contract: { + _switch: { + name: "scAddressTypeContract", + value: 1, + }, + _arm: "contractId", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 51, 120, 205, 202, 109, 33, 164, 194, 5, 219, 69, 26, + 124, 216, 96, 210, 220, 233, 172, 131, 124, 131, 55, + 133, 20, 250, 59, 61, 195, 99, 234, 75, + ], + }, + }, + key: { + _switch: { + name: "scvVec", + value: 16, + }, + _arm: "vec", + _armType: { + _childType: { + _maxLength: 2147483647, + }, + }, + _value: [ + { + _switch: { + name: "scvSymbol", + value: 15, + }, + _arm: "sym", + _armType: { + _maxLength: 32, + }, + _value: { + type: "Buffer", + data: [66, 97, 108, 97, 110, 99, 101], + }, + }, + { + _switch: { + name: "scvAddress", + value: 18, + }, + _arm: "address", + _value: { + _switch: { + name: "scAddressTypeAccount", + value: 0, + }, + _arm: "accountId", + _value: { + _switch: { + name: "publicKeyTypeEd25519", + value: 0, + }, + _arm: "ed25519", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 103, 128, 20, 230, 110, 101, 50, 114, 161, 182, + 112, 3, 7, 114, 137, 146, 71, 205, 29, 71, 49, + 173, 43, 60, 76, 234, 6, 247, 203, 36, 131, 228, + ], + }, + }, + }, + }, + ], + }, + durability: { + name: "persistent", + value: 1, + }, + }, + }, + }, + before: { + _attributes: { + lastModifiedLedgerSeq: 60906681, + data: { + _switch: { + name: "contractData", + value: 6, + }, + _arm: "contractData", + _value: { + _attributes: { + ext: { + _switch: 0, + }, + contract: { + _switch: { + name: "scAddressTypeContract", + value: 1, + }, + _arm: "contractId", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 51, 120, 205, 202, 109, 33, 164, 194, 5, 219, 69, + 26, 124, 216, 96, 210, 220, 233, 172, 131, 124, 131, + 55, 133, 20, 250, 59, 61, 195, 99, 234, 75, + ], + }, + }, + key: { + _switch: { + name: "scvVec", + value: 16, + }, + _arm: "vec", + _armType: { + _childType: { + _maxLength: 2147483647, + }, + }, + _value: [ + { + _switch: { + name: "scvSymbol", + value: 15, + }, + _arm: "sym", + _armType: { + _maxLength: 32, + }, + _value: { + type: "Buffer", + data: [66, 97, 108, 97, 110, 99, 101], + }, + }, + { + _switch: { + name: "scvAddress", + value: 18, + }, + _arm: "address", + _value: { + _switch: { + name: "scAddressTypeAccount", + value: 0, + }, + _arm: "accountId", + _value: { + _switch: { + name: "publicKeyTypeEd25519", + value: 0, + }, + _arm: "ed25519", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 103, 128, 20, 230, 110, 101, 50, 114, 161, + 182, 112, 3, 7, 114, 137, 146, 71, 205, 29, + 71, 49, 173, 43, 60, 76, 234, 6, 247, 203, + 36, 131, 228, + ], + }, + }, + }, + }, + ], + }, + durability: { + name: "persistent", + value: 1, + }, + val: { + _switch: { + name: "scvI128", + value: 10, + }, + _arm: "i128", + _value: { + _attributes: { + hi: { + _value: "0", + }, + lo: { + _value: "109268289", + }, + }, + }, + }, + }, + }, + }, + ext: { + _switch: 0, + }, + }, + }, + after: { + _attributes: { + lastModifiedLedgerSeq: 60906681, + data: { + _switch: { + name: "contractData", + value: 6, + }, + _arm: "contractData", + _value: { + _attributes: { + ext: { + _switch: 0, + }, + contract: { + _switch: { + name: "scAddressTypeContract", + value: 1, + }, + _arm: "contractId", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 51, 120, 205, 202, 109, 33, 164, 194, 5, 219, 69, + 26, 124, 216, 96, 210, 220, 233, 172, 131, 124, 131, + 55, 133, 20, 250, 59, 61, 195, 99, 234, 75, + ], + }, + }, + key: { + _switch: { + name: "scvVec", + value: 16, + }, + _arm: "vec", + _armType: { + _childType: { + _maxLength: 2147483647, + }, + }, + _value: [ + { + _switch: { + name: "scvSymbol", + value: 15, + }, + _arm: "sym", + _armType: { + _maxLength: 32, + }, + _value: { + type: "Buffer", + data: [66, 97, 108, 97, 110, 99, 101], + }, + }, + { + _switch: { + name: "scvAddress", + value: 18, + }, + _arm: "address", + _value: { + _switch: { + name: "scAddressTypeAccount", + value: 0, + }, + _arm: "accountId", + _value: { + _switch: { + name: "publicKeyTypeEd25519", + value: 0, + }, + _arm: "ed25519", + _armType: { + _length: 32, + }, + _value: { + type: "Buffer", + data: [ + 103, 128, 20, 230, 110, 101, 50, 114, 161, + 182, 112, 3, 7, 114, 137, 146, 71, 205, 29, + 71, 49, 173, 43, 60, 76, 234, 6, 247, 203, + 36, 131, 228, + ], + }, + }, + }, + }, + ], + }, + durability: { + name: "persistent", + value: 1, + }, + val: { + _switch: { + name: "scvI128", + value: 10, + }, + _arm: "i128", + _value: { + _attributes: { + hi: { + _value: "0", + }, + lo: { + _value: "109268289", + }, + }, + }, + }, + }, + }, + }, + ext: { + _switch: 0, + }, + }, + }, + }, + ], }, - preparedTransaction: "AAAAAgAAAAC8J8h+HyYyP4AAAAA=", // Mock XDR + preparedTransaction: + "AAAAAgAAAABngBTmbmUycqG2cAMHcomSR80dRzGtKzxM6gb3yySD5AABbJoCjnUGAAABwgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAGAAAAAAAAAABM3jNym0hpMIF20UafNhg0tzprIN8gzeFFPo7PcNj6ksAAAAIdHJhbnNmZXIAAAADAAAAEgAAAAAAAAAAZ4AU5m5lMnKhtnADB3KJkkfNHUcxrSs8TOoG98skg+QAAAASAAAAAAAAAABngBTmbmUycqG2cAMHcomSR80dRzGtKzxM6gb3yySD5AAAAAoAAAAAAAAAAAAAAAAAAYagAAAAAQAAAAAAAAAAAAAAATN4zcptIaTCBdtFGnzYYNLc6ayDfIM3hRT6Oz3DY+pLAAAACHRyYW5zZmVyAAAAAwAAABIAAAAAAAAAAGeAFOZuZTJyobZwAwdyiZJHzR1HMa0rPEzqBvfLJIPkAAAAEgAAAAAAAAAAZ4AU5m5lMnKhtnADB3KJkkfNHUcxrSs8TOoG98skg+QAAAAKAAAAAAAAAAAAAAAAAAGGoAAAAAAAAAABAAAAAAAAAAIAAAAGAAAAATN4zcptIaTCBdtFGnzYYNLc6ayDfIM3hRT6Oz3DY+pLAAAAFAAAAAEAAAAHkAwztpy+NHSN9EQ/doF3WgKzBZnjurnHyfizIlo7HxsAAAABAAAABgAAAAEzeM3KbSGkwgXbRRp82GDS3Omsg3yDN4UU+js9w2PqSwAAABAAAAABAAAAAgAAAA8AAAAHQmFsYW5jZQAAAAASAAAAAAAAAABngBTmbmUycqG2cAMHcomSR80dRzGtKzxM6gb3yySD5AAAAAEADHpdAAAAAAAAAJQAAAAAAAFsNgAAAAA=", }; await route.fulfill({ json, status: 200 }); @@ -927,3 +2214,115 @@ export const stubFeeStats = async (page: Page) => { await route.fulfill({ json }); }); }; + +/** + * Comprehensive stub setup for all external API calls + * Call this early in tests to ensure all external APIs are stubbed + */ +export const stubAllExternalApis = async ( + page: Page, + context: BrowserContext, +) => { + // User notification + await stubUserNotification(context); + + // Feature flags + await stubFeatureFlags(context); + + // Subscription account + await stubSubscriptionAccount(context); + + // Stellar Asset List + await stubStellarAssetList(page); + await stubAssetSearch(page); + + // Token metadata + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubIsSac(page); + + // Horizon endpoints + await stubFeeStats(page); + await stubHorizonAccounts(page); + await stubHorizonTransactions(page); + + // Backend transaction endpoints + await stubBackendSimulateTx(page); + await stubBackendSubmitTx(page); + await stubSimulateTokenTransfer(page); + + // Federated address resolution + await stubStellarToml(page); + await stubFederation(page); + + // Friendbot (testnet funding) + await stubFriendbot(page); + + // Account balances + await stubDefaultAccountBalances(page); + + // Collectibles + await stubCollectibles(page); + + // Mercury/History endpoints + // Note: Tests that need account history should call stubAccountHistory() instead + // to provide their own test data + await stubAccountHistory(page); + await stubMercuryTransactions(page); + + // RPC and Soroban + await stubSorobanRpc(page); + + // Backend settings and health checks + await stubBackendSettingsEndpoint(page); + + // Ledger keys accounts + await stubLedgerKeysAccounts(page); + + // Blockaid scan + await stubScanTx(page); + await stubScanDapp(context); +}; + +export const stubBackendSettings = async (page: Page) => { + await page.route("**/feature-flags", async (route) => { + await route.fulfill({ + json: { + useSorobanPublic: true, + }, + }); + }); + + await page.route("**/user-notification", async (route) => { + await route.fulfill({ + json: { + enabled: false, + message: "", + }, + }); + }); +}; + +/** + * Stub a specific API endpoint with custom response + * Useful for test-specific overrides + */ +export const stubApiEndpoint = async ( + page: Page, + pattern: string, + response: any, +) => { + await page.route(pattern, async (route) => { + await route.fulfill({ json: response }); + }); +}; + +/** + * Abort a specific API endpoint + * Useful for testing error handling + */ +export const abortApiEndpoint = async (page: Page, pattern: string) => { + await page.route(pattern, async (route) => { + await route.abort("failed"); + }); +}; diff --git a/extension/e2e-tests/integration-tests/README.md b/extension/e2e-tests/integration-tests/README.md new file mode 100644 index 0000000000..d0b7fcf06d --- /dev/null +++ b/extension/e2e-tests/integration-tests/README.md @@ -0,0 +1,48 @@ +# Integration Tests + +Tests in this folder are designed to work in **both modes**: + +## Running Tests + +### With Integration Mode OFF (Default) + +```bash +yarn test:e2e integration-tests +``` + +When `IS_INTEGRATION_MODE` is not set, tests use `stubAllExternalApis()` in a `beforeEach` hook to mock all external API calls. This allows tests to run quickly and reliably without depending on external services. + +### With Integration Mode ON + +```bash +IS_INTEGRATION_MODE=true yarn test:e2e integration-tests +``` + +When `IS_INTEGRATION_MODE=true`, the `beforeEach` hook skips stubbing, and tests use real API calls against actual Stellar testnet and external services. This validates that the application works correctly with real data. + +## Test Requirements + +All tests in this folder must pass in **both scenarios**: + +1. **Stubbed Mode** (`IS_INTEGRATION_MODE` not set) + + - External APIs are mocked with consistent test data + - Tests run fast and reliably + - No dependency on external services being available + +2. **Integration Mode** (`IS_INTEGRATION_MODE=true`) + - Tests use real Stellar testnet APIs + - Real fee stats, account balances, and transaction data + - Real network responses and delays + - Account must be funded and in valid state + +## Files + +- `addAssetIntegration.test.ts` - Asset management workflows +- `freighterApiIntegration.test.ts` - Freighter API integration with freighter-api +- `sendIntegration.test.ts` - Payment sending workflows + +## What Should Be Added Here + +- Tests that confirm core flows +- Tests that confirm signing and submitting transactions diff --git a/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts b/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts new file mode 100644 index 0000000000..4c037a32af --- /dev/null +++ b/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts @@ -0,0 +1,184 @@ +import { test, expect, expectPageToHaveScreenshot } from "../test-fixtures"; +import { loginToTestAccount } from "../helpers/login"; +import { stubAllExternalApis, stubTokenDetails } from "../helpers/stubs"; +import { TEST_TOKEN_ADDRESS } from "../helpers/test-token"; + +test.beforeEach(async ({ page, context }) => { + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + await stubTokenDetails(page); + } +}); + +test("Adding classic asset on Testnet", async ({ page, extensionId }) => { + test.slow(); + await loginToTestAccount({ page, extensionId }); + + await page.getByTestId("account-options-dropdown").click(); + await page.getByText("Manage assets").click(); + await expect(page.getByText("Your assets")).toBeVisible(); + await page.getByText("Add an asset").click({ force: true }); + await page + .getByTestId("search-asset-input") + .fill("GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"); + // Wait for search results to load + await page.waitForLoadState("networkidle"); + // Get the first ManageAssetCode that contains USDC (there may be multiple assets listed) + await expect( + page.locator('span[data-testid="ManageAssetCode"] >> text=USDC').first(), + ).toBeVisible(); + + await page.getByTestId("ManageAssetRowButton").first().click(); + await expect( + page.getByTestId("SignTransaction__TrustlineRow__Asset"), + ).toHaveText("USDC"); + await expect( + page.getByTestId("SignTransaction__TrustlineRow__Type"), + ).toHaveText("Add Trustline"); + await page.getByRole("button", { name: "Confirm" }).click(); + await expect(page.getByText("Done")).toBeVisible(); + + if (process.env.IS_INTEGRATION_MODE) { + // if we're running in integration mode, verify the asset was actually added + await page.getByText("Done").click(); + await expect( + page.getByTestId("ManageAssetRowButton__ellipsis-USDC"), + ).toBeVisible(); + + // now go back and remove this asset + await page.getByTestId("BackButton").click(); + await expect(page.getByText("Your assets")).toBeVisible(); + await expect(page.getByTestId("ManageAssetCode")).toHaveText("USDC"); + await expect(page.getByTestId("ManageAssetDomain")).toHaveText("centre.io"); + await page.getByTestId("ManageAssetRowButton__ellipsis-USDC").click(); + await page.getByText("Remove asset").click(); + await expect( + page.getByTestId("SignTransaction__TrustlineRow__Asset"), + ).toHaveText("USDC"); + await expect( + page.getByTestId("SignTransaction__TrustlineRow__Type"), + ).toHaveText("Remove Trustline"); + await page.getByRole("button", { name: "Confirm" }).click(); + await page.getByText("Done").click(); + await expect( + page.getByText( + "You have no assets added. Get started by adding an asset.", + ), + ).toBeVisible(); + } +}); + +// Helper function to avoid importing from extension source (which causes Node.js module resolution issues) +const truncateString = (str: string, charCount = 4) => + str ? `${str.slice(0, charCount)}…${str.slice(-charCount)}` : ""; + +// Snapshot file doesn't exist - run with --update-snapshots to create baseline +test("Adding and removing unverified Soroban token", async ({ + page, + extensionId, +}) => { + await loginToTestAccount({ page, extensionId }); + + await page.getByTestId("account-options-dropdown").click(); + await page.getByText("Manage assets").click(); + await expect(page.getByText("Your assets")).toBeVisible(); + await expectPageToHaveScreenshot({ + page, + screenshot: "manage-assets-page.png", + }); + await page.getByText("Add an asset").click({ force: true }); + await page.getByTestId("search-asset-input").fill(TEST_TOKEN_ADDRESS); + const notOnLists = page.getByTestId("not-asset-on-list"); + const onLists = page.getByTestId("asset-on-list"); + + // Wait for either to be visible + await Promise.race([ + notOnLists.waitFor({ state: "visible" }), + onLists.waitFor({ state: "visible" }), + ]); + + if (await notOnLists.isVisible()) { + // Case 1: token is not on your lists + await expect(notOnLists).toHaveText("Not on your lists"); + await expect(page.getByTestId("ManageAssetCode")).toHaveText("E2E"); + await expect(page.getByTestId("ManageAssetRowButton")).toHaveText("Add"); + } else if (await onLists.isVisible()) { + // Case 2: token is already on your lists + await expect(onLists).toHaveText("On your lists"); + await expect(page.getByTestId("ManageAssetCode")).toHaveText( + truncateString(TEST_TOKEN_ADDRESS), + ); + await expect(page.getByTestId("ManageAssetRowButton")).toHaveText("Add"); + } else { + throw new Error( + "Expected token to be either on or not on lists, but neither was visible", + ); + } + await page.getByTestId("ManageAssetRowButton").click(); + await expect(page.getByTestId("ToggleToken__asset-code")).toHaveText( + "E2E Token", + ); + await expect(page.getByTestId("ToggleToken__asset-add-remove")).toHaveText( + "Add Token", + ); + await page.getByRole("button", { name: "Confirm" }).click(); + + if (process.env.IS_INTEGRATION_MODE) { + // if we're running in integration mode, verify the asset was actually added + await expect( + page.getByTestId("ManageAssetRowButton__ellipsis-E2E"), + ).toBeVisible(); + + // now go back and make sure the asset is displayed in the account view + await page.getByTestId("BackButton").click(); + await page.getByTestId("BackButton").click(); + await expect(page.getByTestId("account-view")).toBeVisible(); + await expect(page.getByText("E2E")).toBeVisible(); + + // now go back and remove this asset + await page.getByTestId("account-options-dropdown").click(); + await page.getByText("Manage assets").click(); + await expect(page.getByText("Your assets")).toBeVisible(); + await expect(page.getByTestId("ManageAssetCode")).toHaveText("E2E"); + await expect(page.getByTestId("ManageAssetDomain")).toHaveText( + "Stellar Network", + ); + await page.getByTestId("ManageAssetRowButton__ellipsis-E2E").click(); + await page.getByText("Remove asset").click(); + await expect(page.getByTestId("ToggleToken__asset-code")).toHaveText( + truncateString(TEST_TOKEN_ADDRESS), + ); + await expect(page.getByTestId("ToggleToken__asset-add-remove")).toHaveText( + "Remove Token", + ); + await page.getByRole("button", { name: "Confirm" }).click(); + await expect( + page.getByText( + "You have no assets added. Get started by adding an asset.", + ), + ).toBeVisible(); + } +}); + +test.afterAll(async ({ page, extensionId }) => { + if ( + process.env.IS_INTEGRATION_MODE && + test.info().status !== test.info().expectedStatus && + test.info().title === "Adding classic asset on Testnet" + ) { + // remove trustline in cleanup if Adding Soroban verified token test failed + test.slow(); + await loginToTestAccount({ page, extensionId }); + + await page.getByTestId("account-options-dropdown").click(); + await page.getByText("Manage assets").click(); + + await page.getByTestId("ManageAssetRowButton__ellipsis-USDC").click(); + await page.getByText("Remove asset").click(); + await page.getByRole("button", { name: "Confirm" }).click(); + await page.getByText("Done").click(); + await expect(page.getByTestId("account-view")).toBeVisible({ + timeout: 30000, + }); + } +}); diff --git a/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts-snapshots/manage-assets-page-chromium-darwin.png b/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts-snapshots/manage-assets-page-chromium-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..590d433c8f769112ce62233b16905c8c6d0911f2 GIT binary patch literal 14530 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 literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/freighterApiIntegration.test.ts b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts similarity index 87% rename from extension/e2e-tests/freighterApiIntegration.test.ts rename to extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts index f1bd04ff9f..0823c6ef83 100644 --- a/extension/e2e-tests/freighterApiIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts @@ -1,7 +1,7 @@ -import { expect, test, expectPageToHaveScreenshot } from "./test-fixtures"; -import { TEST_TOKEN_ADDRESS } from "./helpers/test-token"; -import { loginToTestAccount } from "./helpers/login"; -import { allowDapp } from "./helpers/allowDapp"; +import { expect, test, expectPageToHaveScreenshot } from "../test-fixtures"; +import { TEST_TOKEN_ADDRESS } from "../helpers/test-token"; +import { loginToTestAccount } from "../helpers/login"; +import { allowDapp } from "../helpers/allowDapp"; import { stubAccountBalances, stubAccountHistory, @@ -9,7 +9,8 @@ import { stubScanDapp, stubTokenDetails, stubTokenPrices, -} from "./helpers/stubs"; + stubAllExternalApis, +} from "../helpers/stubs"; const TX_TO_SIGN = "AAAAAgAAAADLvQoIbFw9k0tgjZoOrLTuJJY9kHFYp/YAEAlt/xirbAAAAGQAAAfjAAAOpQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAABngBTmbmUycqG2cAMHcomSR80dRzGtKzxM6gb3yySD5AAAAAAAAAAAAvrwgAAAAAAAAAAA"; @@ -45,17 +46,13 @@ const JSON_MSG_TO_SIGN = JSON.stringify({ const JSON_SIGNED_MSG = '\"42IH7/mvkAT+ltbEG8oEPhVBzP7hb6NU+P+WZP3j1AIMdbwuFPrzBuRFRvLjXdXl5lDmC7aL0zrZIUrfrMXHDw==\"'; -test("should sign transaction when allowed", async ({ - page, - extensionId, - context, -}) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); +test.beforeEach(async ({ page, context }) => { + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } +}); +test("should sign transaction when allowed", async ({ page, extensionId }) => { await loginToTestAccount({ page, extensionId }); await allowDapp({ page }); @@ -76,6 +73,93 @@ test("should sign transaction when allowed", async ({ await pageTwo.getByText("Sign Transaction XDR").click(); const txPopup = await txPopupPromise; + await stubAccountBalances(txPopup); + // Stub scan-tx with detailed asset diffs + await txPopup.route("**/scan-tx", async (route) => { + await route.fulfill({ + json: { + data: { + simulation: { + status: "Success", + assets_diffs: { + GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY: [ + { + asset: { + type: "NATIVE", + code: "XLM", + }, + in: null, + out: { + usd_price: 0, + summary: "Sent 5 XLM", + value: 5, + raw_value: 50000000, + }, + asset_type: "NATIVE", + }, + ], + GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF: [ + { + asset: { + type: "NATIVE", + code: "XLM", + }, + in: { + usd_price: 0, + summary: "Received 5 XLM", + value: 5, + raw_value: 50000000, + }, + out: null, + asset_type: "NATIVE", + }, + ], + }, + exposures: {}, + assets_ownership_diff: {}, + address_details: [], + account_summary: { + account_assets_diffs: [ + { + asset: { + type: "NATIVE", + code: "XLM", + }, + in: null, + out: { + usd_price: 0, + summary: "Sent 5 XLM", + value: 5, + raw_value: 50000000, + }, + asset_type: "NATIVE", + }, + ], + account_exposures: [], + account_ownerships_diff: [], + total_usd_diff: { + in: 0, + out: 0, + total: 0, + }, + total_usd_exposure: {}, + }, + transaction_actions: null, + }, + validation: { + status: "Success", + result_type: "Benign", + description: "", + reason: "", + classification: "", + features: [], + }, + request_id: "9e460857-734b-405e-9e1f-86e656def1dd", + }, + error: null, + }, + }); + }); await expect(txPopup.getByText("Confirm Transaction")).toBeVisible(); @@ -158,6 +242,7 @@ test("should not sign transaction when not allowed", async ({ await pageTwo.getByText("Sign Transaction XDR").click(); const txPopup = await txPopupPromise; + await stubAccountBalances(txPopup); await expect( txPopup.getByText( @@ -291,9 +376,10 @@ test("should sign auth entry for a selected account when allowed", async ({ .getByRole("textbox") .nth(2) .fill("GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"); - await pageTwo.getByText("Sign Authorization Entry XDR").click(); const popupPromise = page.context().waitForEvent("page"); + await pageTwo.getByText("Sign Authorization Entry XDR").click(); + const popup = await popupPromise; await expect(popup.getByText("Confirm Authorization").first()).toBeVisible(); @@ -483,9 +569,10 @@ test("should sign message for a specific account when allowed", async ({ .getByRole("textbox") .nth(2) .fill("GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"); - await pageTwo.getByText("Sign Message").click(); const popupPromise = page.context().waitForEvent("page"); + await pageTwo.getByText("Sign Message").click(); + const popup = await popupPromise; await expect(popup.getByText("Sign message")).toBeVisible(); diff --git a/extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/add-token-chromium-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/add-token-chromium-darwin.png similarity index 100% rename from extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/add-token-chromium-darwin.png rename to extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/add-token-chromium-darwin.png diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/add-token-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/add-token-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..8a41bc00f3c97bf32a18915b7a75dfda0cbc2892 GIT binary patch literal 5023 zcmeAS@N?(olHy`uVBq!ia0y~yUTRl$K7Jslm+kziFnCp|L@*hh)IBG__M__A98cO%c>oWt(EHur*uUZ1(PT z(c3TEzS}v+V&2ogRlMI4)~4H^m#V$~eDAz#<+@S(>;5v>-=1Zf9k;*EmVx1ew$U3y zp>8&y^&A2RfTRjX0+1A9F#wXBOcD$X4J?d2K({q90M#fsGB7hROi*Y5y3=D+`Dn^f3k#j2x97#~srdNe?Y;f=|6g2Oe0sV* zKf`{m!*a@s4U(+cN*}UsY{|U*@Nj$hx){qE{>_^=PuGjB`u64~gTYgt>Yf&cG?6u( z2e!;!@_wSS`!u~+tD5}x_xA3t__&CNZP~2E{)qwydYViHXJo1S&x_fbb@hYt*)wP6 z*jAS@%-e+TYaC@$0aoXWF z-oy9viY}g9$_^Cy$!DZoEIZwJ{@;^^nKNg8etzEn-DSS}c|zNd_sjqPoV#>=of(4cj<&*coK>GjV%I)p>{=hi?{OoMMyggt2$tUvpcXyROKGqA2?)r~mn}4w`>qCUS zRea8a>hJGjfxggR{{FqMpHb$6tEi_>=GUsLit6Vlvo?>Qbb~F5c T?O66Vpa_GftDnm{r-UW|Ym##- literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-add-token-chromium-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-add-token-chromium-darwin.png similarity index 100% rename from extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-add-token-chromium-darwin.png rename to extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-add-token-chromium-darwin.png diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-add-token-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/domain-not-allowed-add-token-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..91af42af5d20e8f96d1c5f181c1b607ff3b22005 GIT binary patch literal 30150 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 literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/sign-auth-entry-chromium-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-auth-entry-chromium-darwin.png similarity index 100% rename from extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/sign-auth-entry-chromium-darwin.png rename to extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-auth-entry-chromium-darwin.png diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-auth-entry-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-auth-entry-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..4a989f8c5437e13a97c7348b102e08f39522b92a GIT binary patch literal 23050 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 literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/sign-message-chromium-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-chromium-darwin.png similarity index 100% rename from extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/sign-message-chromium-darwin.png rename to extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-chromium-darwin.png diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..aca7aba9394e4fc82b7fea3a1f9a68700d9e1abe GIT binary patch literal 24295 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 literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/sign-message-json-chromium-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-json-chromium-darwin.png similarity index 100% rename from extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/sign-message-json-chromium-darwin.png rename to extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-json-chromium-darwin.png diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-json-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-json-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..6eb629e79567bfbd76111d4766669cc99b59b8ed GIT binary patch literal 49317 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 bhfj?NF#DmRJRfUP{wU4Mdg=wLwjuumGUmJa literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/sign-message-long-string-chromium-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-long-string-chromium-darwin.png similarity index 100% rename from extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/sign-message-long-string-chromium-darwin.png rename to extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-long-string-chromium-darwin.png diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-long-string-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-message-long-string-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..345e14cb9db8fffc637098b30e8990c743aeaafc GIT binary patch literal 26620 zcmeFZbySsWw>P}7uodav5>f&p(gFsHka9`4lF|*53%7;DLO?=NY3XiQsHBv1gLH#* zv%Y!nbDr;g-!aY@XN+%rf1G!W$A5&q!FAu)HLp46FXr|Bv69TC^EBsCDAXl6S*a%| z)M@zg#ILg_;IDg(kBCsHt0+0C`>HQumPUwU7@cD!j|WEcE1FUsJh&!1clGKu_u$d{ zQupuqIlMa`$3FXIc79~<;Rms1a;un2!sL(ro+MLpT))SD&E1FP^=9>e{_(2k?BVgw zlW@g$uh~6MyRqoi7SB}c!jE>0t&@0b$Pr0!N(i$EFXwY z+=9P8{e?OS-<EzelalVrJxVasaP1t4#eF>Bt#)>GaV{<@DRFWtbap9pb#}hNl#U2c`OAT^Xe^jT4P$iGJ`P@c(xVOBrAh9ST!^oQdkBsDg2dpQ0 zZh0x-Y-~#;pHW+k2xd!s>cd0tgP}2{c!{HCgJTEe^B=$x%ws!k?d`SDCe}wjS(b}$ zReLUG=P(LCt@%uJ>EyyeUzplQS0@*lq`-As6STRWwTZlAbHKbwM`~h0QfZO_+Qe%z zUqqgw)xz9wE;`ft41=iCa}^bpb_w39&CV;>-5;`b9aYQ4L(+oP3+Wl7UOOYZ?ti`! zV;5B77sl{}_~Xq~Vn)wDha2sL!M^I=&dzJs-8vG`w$*zxrzv%FTLp&{KHZ*<9y^>l z+}qHI>O034V>fKyaMXZ3Y%r5N7#MLGT5e*CKit6*b|Pm)W@AXZJg0(Xj<*a50l~isuK188x$~ZqKsWm62$@;*9Mi~i*-SKz4dgYsO9xG)tQI-&f?(>qyjUSXf zCrE>5EiEkK+-5#itX6wW)V`ljlE%@w%_m3T=*0w0?MIyZ^qe}-efl2O?s={Obg#BY zT*q)Y99!IriG_?DTo0VVr=jfcCp%6FmZYbr&&>?pzh5Imxl z-n8wv`2G3%t206uX*4D69_#(6@jgksO?xNT^tVsc^@kQRRy}yEmzur3oR*dw+QeDQ z%>;w#ejS?K)|S1}mYv;3UN>RPZF6SSZ8nyf?lPUQ-S*PJ1&W)p9!gPnI4;GIkT4IA zdLJx1&bEm!<^JgWYrk7XIo7FDE;YvCCxge*n!mweLRJ=ch@HYzq!I4@i@l#*IWZ8b z@ZJZE$A8|1%{b3}c^Bt0Xf8wV++AqiHHsx1u}jG42Yx)5OAM;tY`?qFV$vL5_2>Hq zzM1I=0|qTohxw|VQCf~WPj-G>k*s{NHUZnulisyjwWIGD9v)t=%=Eebx#a?5sGo7g z&Zx&2EM}18@e758?-zI#co!H1t@^V{Mzz(|DGGea->dnaJ?b|Ks@iB1o1UJ=94TS9 z)|+`#o9Sq;Uz$bTBO1yj_Q-8h_2H03bFCa?%~2MO?H~WJTzuDeg-Z0r+-KkFlV`fS zxBV$fD~pTszhIray~RW;IDbA`u;gN%xSW~{Pp=%%ciwuw`|H`zMY=ns*oW47Ue4BvXcLoy@J> zC@3g>cKF#l`pXi#zt<)k8q8G12rH|{JSWV^R5ubYQQu}s&m_S44D;x9y4Hn<=-3{z z#UGyKt==_^^8TS?TcxI=LaH|HDOZ-7Hl0F`Ib~yR{{C^ScVJ=JR<90Q*{lQl5SMR< z_de>pj|o`L?nNLeAJY9HFLtl_FiCw#lIcj|V2PBT?<)zjwA3fja-)L! z+2ey%LaO8uN2jf*Y3-6H3Rk}QkwaysH9CUlo`UC0%O}2S)J0TH%5{{A&!b1pon{gm zeHUqjpZB+k1<~9#eyWi@tgWpbl3Dttq@pa@Yvu3ysPy&y^7OMcT;6JQa;1gIw;#pT zZEf|4Eelr~;PW~3=$j*WS2ZdMGYZNI_^;UwX>&KxiUcz-uX{mdI6A-+4w`u?mM$3V zKJb1${^K26nT+xDft19O$eTE2KO0+HW%b&F2{kh^H!&=~wefspWBN|7O+l+*FlIwU zB+PUkGU%=IjkA!+;4JlZcW=UhIr>d3>Fd54wcntOySv`F(JqOF6NvkD+$qnStm4m2 z_pD-eVYAXmgyLy`?lU;X3hk$T-JPK>M88HU5OH#I2W{#|K7DR|RCE8;85<$@=VU&V zJT`v6qB9%cah!R%$h&x-7vCLR@1S$9UXcbGy zvi0Ixx092T>wZ_^$i%jz8+&Jbmh!KKPQsrngkO$dwRLnzQK)_vKT>vK6O%CKtsiGD z({`up=sXPrw~jCXTW5)QFSJ5sX#sNsRK348)Mb3}MV1O+9fv$LzKlhmyh3-jf< zxj8>kJ4I)-mmZ$zbox4yH*X9zoQ@Rta5;rH!ikvn+@DwZyfNyrTIHK4p5wMM zQ1uK+U>IMe_~tOtML3wklL1stZ6dRt^YR9MtZw6PD36!Nj+ZOOj#hqud-d)zeR;|; zloLbMNM8KmI#e3&g-)@RQlk(qLjCOKd{a@{9zL6N?Hh-S-G%Vrx;oFPQ zoyi|BS}9Q$pq)sDaJ6DxkY z%}RvwQT)#Oi|lhkLP)|ydX)FpPyn5%VQtOXQu}PqXtDQLbKipNzvHoj#7{+_&wUMzDU@MCs31jz`-Kq5cYGr zBuFHf*GKGrT;d9J>rvCFi^OgSVM&X6HT2zB>&uq%n+5CNdqg! z7v)X;L0#=9x=)_a#cw&Q{dm{2lamp!sRKdiGHY|i#>ygE47+#urkRr49G7mYXFXk6 z)_g4Tuh>%~`}_N8*HVS91<{Gz zzGizYu8g^Z8>YnvCb+7)ZzyNujxoo9WJk~`G_<6YW*5Z=< z{PH7JZT|LhXHZiPzO|t&s~?*7P1=0Z(%?Wl=^LDcE+sMUg_;|n&=Xa|@%4hUBbQNa7Vot^T;}LeUBa=i9Cud)2~H(c3d%X>MF-}PkZ`t& zoIKeixo%{Hwdjb`&(AO6koK!kr!78eeSJM7WFjF>^5)MGhT)EmfsV3?ow_=%6=Gbl z!xdbcqAT+*^dJ;p?D0q2{=*e;M!5~D4-Jl|4MGS7-hfOP9b5R6@2=Grv`f%BPePqB zcrpIw9N++=Q%}#U@Ar;%4s+o+f65aJZNlzo6_%R2saSTutSB#cq+FrMIxZ>O)X~*d zRsCpXRWjGU!Gf9Mn{H1+6$M0Wke4Y zJJp?xu1M&w$jnPNaMn`wX?_%1?mbOD?c5waNWp8ZRb1(e4it(ohsMV8K&@9bOie9Z zUHzktKxr{nPtDO%#!+6z(NRa<(&NWvOF5YYM7tD5#XwzZSJ#cknHtG11P|KbAtsItoQozNGv zZ)Vvn#^7_!dzVs9UkI;HGW>hdlN2djZfIFJ<@$+=^%ZPn{2 zLFrmTO4kS%L;rBT=UxbP*KDPbk+-V7$7OC_F6zeydKx+d0|WFuzjtk$I%ftp!dqjC zjAxdTHz)Rh9Pkt{UsWtFBmi-o%*xfaD|Njv-=PlOF)}i;yv%ib*)Qa|rHrMHjE;;M#{P+h z4rWyAnnA=(%P4WPj-`PO+K4twYpvm)fjBEUz+7d}9j2@*FEsDwRPQeYQ1gcrQSyt9 zzb4g(*oCk<=0zIWpX3?E?HaU2lxAgblW5?Si4RnqzNU5TC>Hh*)V1F@(mz!IByWhxlz$Bu#xA$x| z-?!Z+UlQi+F)YF0XhCCsBGz-gDeu;5<%Uv=JshY?SdUJQ2D&TITSvCZ^Hw?a>A40{ z^UnYn!>vIFJ%J!uGIk&vvkRJJ(a2ZR+|QIsi<()yuUnBq#_V zJ9=lt)!?S%$0!*{wyrC~PNK>ZdsE0iLM38a2;lAd!?#PtLpH6gt$b^6?71LgT}nzy zNxAW|H7h;c;^e5i_D6~Qvb55)r1Z*!{LIRPq@+8XHPBd;3DJ@}yUNI}SXt=XU$JwV z9ewwajFMa?urxovFg+pD-fgklbp|i8b!5KU79-?36N2Us=Z@{_%r7jkMgNYho0TN& zL5C%^9zb}H#sz-dg>v85*M~)d^A2r?&EEPn)cQfl147v2L;J~kw2$ZSm&7-e!HE75NOs|63l6|p%g1BaNAK~Hm`v}o|2byJnzNBcbCNv|NJm|4aM66+GdaCqCRNX zn1gw=@~1w(y6k7-k79giR0uWAakSEnn9lB=)S{V#VV=?9oUFq@(d>z-hz)?b0e8IH z#dm6>>V-*`jLeyBfhS?i1{9@&>X@x1RSxJP0!Ga5H$92?%z7hpkkl>Qaq#F!=tb1& zr#~2$zKN<3LCJ7&x+B2N#i6H(5y5_|jN(vvq@&$AXpZTAnUV1m(q2@0{>zi;%zHfA zo!tZF6BtdCGLKgo>5nLREkE&lG;Q!!i#acBp58Dmx*3nJw11{>3u$8e5h_6ep^9+2 zJDXj~GJAI(Rd-0982$d{0&~8!>#6UuVZkR2;LU$r7Q4A_R@*km$Q%P4N?xe%d#Mml zHn!W(6q06dCVUn(st@q}2Itmd&}_alS@LlFN~mtINdDXv??12Z+>#j%jM_Nb85?t4 zqoJXJrH{WOAb>t6YS9?n({-Pfl@%ge@1{!#*KL{8V$!}BD*@ls2N=#_Wazj4{J0`> zFOUQwBXY1ui+mMSUtnqLGK~b7`(Jv%rf;_K2DBAsG5BwkLc;eE?c*@D*Dq#v~uupm|GhJ+j4RF4-F1R zT+FhhdaR~aqwmLaEEqx$0$Z$*$jArDgxN*%nY3y)9G4j^+Wt>XEULEe<(1yl! z2L}aCi68)ah03bM%=M{6!g!Qhu#s)qbU1PV9F{)cf5jAzU;oK9|2a}V$~#oo#N%*x zZEvOUFUI%|`iyuep=X#-Dj&)#Dny60BY3s$WE2>oEnIz8?^rzqs7_?0qLtikHLgD0`b7b*e zUYDM9+jd2naWV>MEHHKmNpNv;CeYE4kA&U0rnLqjLUJ3>60n0iaK`bFme>@d3TNDI zWMyUTl>zgRnW=zxadt*>rT8i%?!I`={RNT5Ln(ExPTLT!(HS-g`-xh}!)tT*m*6ZV}er-kvdj73g{|1SmPM*0#0bdc#x5^U{+F zlQIgJLwdfS_CK>}t67=!^=naLadt{UK}B+rk(QAql&!<0qB4{DiDY>SUfkwTsnz|B z^}XhZ*1*l7PWbJNs)`E!EQM|KM{HsW&3(RB+ac=`y+Q2SL>;gXzB3A^!HaL*$^I$aI-<61 z!+SZE>!StjO3|Awg|j!>UrdJ$*j9-^&6sI*$9|hYUx?t2t*}}vq;eZSETQC$qLvJL zUkm+=R}MBn{%SUZ|<(DRL-f$| zHW5UxFvJ*rO?XnZ5Y~>=w@j@9re!?z6BwT33j9HZW>VVPDD)zHU5)L0N>h7hn}8Zt zz4lXTN~)4L;cz4I1p^ij>_o-vs~kX_;^YYH_p+7S!fSrIh*n$M`z9w34+qC3 zOnv4}9u9fGMY$e=|0eOo#$cr*D<>z&y3}dDlSN}UP(<2UsB^VP z!+?H>P4Iz4i_B)MnCl7<6{O2gtQdt*C+~ghe-5m(3$V^s=AL@?+%{%rIy#mr`RCBt z(2eYLhh0uGJ{pf|Dexj++a^0(g& zwR(U#rN7KNOtK3_>KY&fVciq06yMbNqS5Z>oKB!}gGKs{E_^w0ae(#c1nL9F{~Z1A zzm+2go~Wv-0@3>9$&(mT15%XF&H0s;m7nuVOG|TezB%WN-=Y-MrG~kAd3m|GG zH_xM3Mds}>aQ1a{bf(5n-M)vqLCVR=$#eut=%KBNNbpPeAEfL~07ZGu~Z`M zo|h6-uQteYb8|oXMpis=>byqbWKT~|Coigo*x|Pn#n~FN%(NqQH8r;ua?p0`UaHVZ z)ZJG-ar&pE&3SbbljO|{s9g1lKOC16uCYG`P48<$!uQj6QK-egE+Ld<&247JkPILj(A%)(D=H~MqGK^KgY9yD8NuBb7q`X=- z8>bnv>s~`dOb0kfL(f?)e=XK)8xf;QK@nA7zyig2nO@YXGf6Hl%Y8d2j*ne58-%wq z$JraG8iFFMTLa$we5>f)EYJ>IgrU-pxi4nX+E%U+OYVMK_1>viSXe;BIXJuXXX6j2 z*mfWn8h43;u(dtx*e=_R->u_C`beopIuL9cB#+mePS3W-6X2;?bbO#x%%40!p$L?2 zXDQyuoTdsnTLP=L2h1^}TJLW8^Ns}eZSVcAcm^?-rKzUS&{mdCTd84$TR#%D9j(mI z&u7L7CxH60kY_u^5}2`aJo%qKHMwi`{w zJGKc9S&^CynRlfqM&0=eTHSub$9U}V9!T7*@Zgf&hrQYIx-? z>a2NX3NunfEkdYKP*PzH*`0V^z9n}(yi9Xv4mv_cP?f9AUKciENcx%X)SHp%F|$e& z&YA+@X$sK@<&1iqvz+Xf%-!Xa%Kbg4xj?STluOaCbQysn2ulsgu$i5YxRa_g&domogl|9p&N+xwbB!1gk%hoJ5} zZ*R>HnV6XHjRGM6x1t%__-Ri9&<)>OfyDo zxBbFBrU6AM#!HANXncIatmy3Iba$&;g`_^g%(!urX-d`}FudjAEsOWT4NPyh9K=@U zIugeK@;E29(WNCeGfXzwT*bfU3He&5#TUFhK;HcQoI1gCHK9+gFZ~D=Y&x} zM5_1u3&61;HiX+=XEarPB#-8m*(|T}`&p9@nE|Rcp9_qaVObGrdwq^H;S_zwC+Qs! zMmPB5_Y|gjcE@pID^y(MYQuAk(LxF40o1e1Ac{r=Qez|17LTF(krR6GvHD{Do350W+nf(-BJ6@>X9;q&W*rn6w3G|>LS6&MycC_ znPVAf42-MzLR#Xw&_GJ3rAgxJ(oS3E)hrH_%&$QNQnb|xW6X8u^{T7Pn$J3PIfUpY z3oV56#j>l&Q1eSFZ3eN^a`26rC9}SljakLRz zLXPlyVMA0R-yLJ58m|Ppq4ldExws#*C^nW1JIGs2^>+j0v9j`Gmr{-q z&Wk|aB(FtoW!_|Oes)Z&=rZ;;3UxjVrO=DMD+V1cFk00R2mH&Vr^n?&Z!DKDW&@Vc zF`uF$ix(QU`|&8JWSR95npLFpH!#n9z&u0ST5?FXP0!5}Z^Gpg`5baZRgQ1)7Y+J&^z%TE#!xGVhpcczC!u*&gMR z`6K=!%ICrKbxmWvZY5?uX$KwWUyt7WVxjC0(fvzzpORSy7r;4f@z6BH<5)#OkglN&4M3z^kPDF@0Y?Kvpk_a`2j~@-uFaOT=%wZjt}=RbGX__gJ6)` zkva|#-?>}6i;ws+UF52MDAcDEm44G`Yo?1iqB%hPH_#;W`z>Eh9_dJwk$E1ZawU&1 zu^q_7P4L;==rvi)D$!RV=nI+#T*dxj@&--s)v`&D@cUh}Z0Ac=ilsTnPa$FP zCGP{{UZc#qa^OmxKW{Y^`J`r?W-e4ipre+comR+cz`drH6SK(TV}Ia4mavhdxPX4$ zdA26+OXr1Rk4HJ2LGum8fviYcWbSW|638ek6WNy`7s@hk2!GE{f|#`ad3jYIL?3~2 zbc7&C$<}Ygj4_gl9gtFvdqJ=sg^&Ay`0Johft=0o{%X;f_W@c~{y<6?VIdJ)(dHr~ zaYlPCi!Xh;j;&Cc7)Vwe;}3LezwfF|Wp6eqSgu2PLF2$GC2usG*DaB1c)k@~Wp6sq)dCt!C61mf&j+P5LPTDv76ynr3*Pe+jV9i|Crlt}!^ z%6R70EG-umg+|CE_n>{F+wenCFGim^PD?>DIa|D^!&DO$8OANSu}T}WI|3Noa3v#U zT6W!a)D5`2hgZb!2!02u&xpJ8yR%h{=3D&nA|7|z_X8ux{(xEhaup#;(DaZz!K{U; z?X*-mu15qCN@s-p);gPi68-!AcI>euQjf^~1My{j`SMKh%0qn}OuIs_oQa8v)G%~$ zU>HJoFYP5wU*)@*uj2mDJfxzou)10z+%5S+hz6H8Rb7j(=lsKHCMPsUe$dY6`i0sj z=vc?55LV3mGGy$W`r9(bfw`2;ZoovaF(#Fk3Tyjl#<7QHZ#rdbjsao7qhBdZxbt=E zqtY#==Sf|0*F|O+iUxLdKW@A{@)(P(6QQT4$IQd#dSMSI8E3Jj>X2;yD*A#uCHVUr zL*^BtNbc|9SA7UUU{b?&3nJ|;yVZ>{ZV-HthS2Mqt&1)=z%Uj#L)#EBN;@!M)#20F zP1sO1?pJ*{Zb48Gh7x4OOn!b0RT4D^rVY{zvvk0VgXNO0TQM96$^M=#P8i6MfdVsx zki?u^J?eA<7$bW+lKb!Tf86~<|Ghr$KCRjKXOkBuzF11>Fb3T34zvc5gZYn(&b;bcJAFT7@zUrODjJ zCJxvcz!{W0x}_4YT-pX8LC>_uGrqc^7}X7m#KC809fN2?@jlmAwtmi<2GQSB`VEEN z6nCWLatNBdLTRZ#QBeu4nE_x*e#tfeI-q41%Xv@>?*8^UX=p}zkP6hu!^Zf>_L9su6llg;-JN&AAR@dZ))usg`*u_w#Hke*b;Juwi?tpuPT>V_OqUlK%8h zLWY*JetZVGYJ8HBup7cEk9Z=1SBb<}TQ5V#>G;ow^y>ZRA>n!9A#eY$hs-S&RJ9uQ z0j@+s)#v*A&_pEe5kNFz|J@l1SROGnlo9UKs(N}z@2z7~HVs)4cYkf~4X@|*w(s>T zsS)>oyt@(<`)jMuU~F)Z=2bYaf%i|2)Y{REygd7nGj;2=^W*R&e0stCC3O?YBUKl* z-)$9f^g4P8?WSm!z?W8j+>R>GX|2yk8>$GN{a_F13_*$$1xZOsz#&2p0S>*JJUlC2 zKm&HUR&T_zXxQQI8#Uk*Wfr}DEsAttV4)d-izshHrPqM zCGniTw=YGreQV@*wBZPRnafe!qWHzS5I$RR;IDi2=W0IGw#`EwLDUr^!X1#SK<=r& z2)b)5;vE%^rx6Fq?cB}#O zH2+6<{Ff^qqS*h>hZ^g}(1`;)p{1q8ZeLb1!rT1HG*#Fs6eKi}O2j6C7bd%PBe z4LDL<8n5059{TrZq~;-dVrYI&)%GCldVK)3BS2EHI_7MA1`y1ow1Y5!0J42YbUa5) zBJ?`lvdn*#XXPm7#VuBR6RH!<%u#%%VwD&DVCcC@KUsACeV+hQpQdu_;(?Uv>SK79 zctLCJ5D$k*K#^UJX;l{otxHBGR4td1JJ}xAmW>{s@}MRYO9#acdPBY=QKz|IEG4PB zCHL(|h1w`2p?K#FHD7sz?flPmfMfE*#t%6$|K~CJ1r7PVx8!Uetn-xp#P7$j2I_sU zd3jPw;5pIJ8 zTc%+~f2J;7~G$?+@TPd8TxM?=EJ>Ww@cS_UbpVjR3=){{fi4o z5+0|SmD+*wiX2yH;Bbz~NLLBaoc18S&j9PC_zDp<&CITd&V2^og|JdS;w{TF7_h}3 z84?RRFLVoB0mw#ny{-14o-=CXE2FZ^B+*@A1Ae)JLecY@w<#Qy{B= zbCHX8?r8qpkFKjW24PTcLd0&%j@lR;a;6GXB)YIa#(c)0`ayf}2PfT9dgnDB9H`qB*_imi6`S&;f zUW5N{aX`lQSQC^{@VxX!|KR+GLY+q#Rg|XfH7tT!h1AK8*TU*;H zl+V@-5VsJ7WKmEv|Mh($C`mxbBDP-m^(*%G02GojK(s>94+p-V;XfJS#~KM}E9N==3O95hkGaXDW1P=N>(ZsXY4SZGAE-<(11-n$&rcmh6_GWAv>$Bx2Hl#hPx zw$H=Li;I)fi>K#5F`+`aJ8Da2S>Wu||NjzOUeXB%p9T?u%K{G-fWh%J>X(fDZ?bpF_E*F1y<889{##8;ivt9g%rIe3 zzgKCe&VNKHJWEeYvm?5KsuA^ll_vc0(dVnMQJ*&hW#B0mSuQ8*o>jcR-X3*=1^GQT zVpTF0qR0m-V7II8p-1^RQxK~%q&^rY@!`0WoIGj+!A67x+pdt}m$fA>RR20UpA#^1 zJ5Y`6{7|W3DhkNI!lI%&v+v>8FJ}x64Uw|{1%XQJ9I%<}cd+_&NIr9P1epQ(G;Ir1zahG(1S~%eww9Kb?Z?3{#T)?QgR%lY5B(U! zIgw`t4)Eh^wowlz&Ee5Z{5ENe#sKDJee~A2_RuJX%F#Oh!CkxGHNd5ETQr`d^+it6 z`CC?04UE`BC}u}M!%Mblrh07;TIPTsbbLNFz8Z#5))T$XRZXT6ER%}!Q9rH3zRA1%A)g0 zww{x;8A^Ky=61y&jLh{z{{!ssA24VrfREFq6?g-s-ccZIkZRg_JFwA60F{bR>(H9X z!Y-40)W8N;OaA7p4_KSj08e36(B69xQD6ul_Kx`zRhf@E= zv)3)cYE^?b2P+y0c^||Nq}~f`PXdJ&C*kEjI12<2GVi0YKMuT2S7c9g?tX}G=~PnbvuXET;e{kd@Ngk@+wJ{OY3Or5YZGn<8Oka7g@C&I=P_JD-> z`vQ+JmTc;$>k)-BHm;1-QTa~IcozFDga_Nxeo#EL0+{Q0P;UZuq}$&3t)m@U53+w z%sF@>3cOK(u+RLFK4&8h`BTkjMI}d>S&dDAMCA=kslEuct;6u5_=JrUoXuvrYzaDp z$vZB9Lt*%;3GGjz2sj~OX?JbXh>}WdRY0*UDTzhNs3Fd3eX0pkTCj6st|yR?FrHL@ zvv|-VBXX(IZQ~lMp9xJa{=e0y&JGHM|$LeqY!HyWwao7 z14=JOik1R5(-SW(W+-;9LAuS;MYaX$3uQJ_5UFROP=5TKR z!L7IMvt0=61*c2TmAijx%p^8G2@Cu|avl-zMbF+W!YIti1`!Z~JQ%N6U3xM1>kA|l zTvyX-Wq~0j1L9jV3lZBBhxx?*z8huhwo4sGDf4wtG2#-_A5{!xs64*)D2ZINJ=})* zPfYoa*G8+5QBE;%qLpAZKqjkVs&GEb3{O$Tnm}A|nN-e(>-Y7Hbaal8O{ zYELl3JRw8g7{73&cz4LEKyis;!yr+W_MqXg57ge}Fb#dJF5B6bPo(ko3?gG}O42)( z!=it$MO1Glv+t#d4S++5wN0i$WKlC6h8T33+L}aeCGoSL5uWxT zFz^4OjNB>Z=D-Ax5lpa7Ch!Kq7eG1{) z$Tt6(#~Vbi+3f+Qvx!B(vlP7gbkt%eKseK>++0tK^HQSTfAx-1w=9X7vt%UrwZFe1 zo2IIP=wa?lg9_*EH+vlu8ddoBY}-lVyxEB9upMT24nHG_qw3V}v*Bx>uveWzGH4qZ z1PRV7!)4+P%44c@FFpVK{)RBFyb(5DpJj7_IJAoy^o9{absDmsrA;Td_Py;xnwOG< znqV~Z)5Dz-DnEq{8s8sjlf zauScxD0en<9a^3BJZ64~ef&hVx^VJnZfxUS#*Nu9g?Ndo*}&?(og*+cH(ajT`9o)x z5sJS%E8+~&*^YzACZfqB^R^vpS75Sg76ebwTk>pdT@YJ1Z~0sT)O63HD`vPdr0lIs z&mucy!T5KWD?n6fR5jFH@q_c~tf(L7L9KQh46eS$K~PU(U#PFX#l5^eEiq2TpTE+X zEI;Yw;C^1jYvAeTO>XYM(ERz+PazwKL9K!zmt$lo>Sq~nX(Agf{2l|}8ZO`5Zs4jC z$z8P#LHV?DZNIf&FPV+ATrJ1LR?Wk6sO}p(!apGATJ|DNTnbUlwbQ9 zYWVTb7hwrg5W{eR3>zL6dRb$Qw%-cA%FOi#Ah7)e$ci(c3`kNpB>INhzCl| z_^)#~DSEN8!!BW$-S3R8|Kb9`FWCQVHa?yYAv|0|JQPC%#cibK>g(&BA}C}|G9Jyz zq$+&sY&OwD+IScj?V51X7nbJu>PrFj27Hw~Q=3>}GYmm!w*K{hYDO=A6;qV&co!Ybhi54aq^ zpMlrzdL`)-_z3kjEUVqay=x4ykh`Sq#gX_Ru00mYpe~7j(p5cNL6EmGgbaTQ|Mp=i z!RmDxBTX9Oy#Q?{00*Olhzbwf8e&8+d<+Ja5RY%2kcm5OQ2m`!Uy9%u&w4K$?-883 zKa<cWMG5jTY{H$#@u_Dh%X>)b&2Vjyg2F9uo#4Z4>qc{{!3k!>cNyxmk;KxA9 z)L!vyYn5E~4NsUAXDy?*iBXrB4B$5;hEWx)*xp~jYiTciLv-f`vlu+C$|Y$LX66;4 zk!y;r!}+biY+6)M10*g2ommxrua)2y--S$`FMLfsJ{luIci2^8g>=7Y}aIy%vr$(z+255+=P{qcDFJ1r_!?zz+c#@PM?UM}L&<6w2zH zsKd2ltA#)R{8uB}^Z!XQyZ{eV3IN}#DsjYMSxXf5?kVO47|A}olm1`$5oU9GlAF$e zL}brCeNGdBl;67t2N&`#{h#i%T!3@KrC=BQ-)wBBGvH5Inbw&zsJTR8JHH=nl#(hn z@CjOGW@bQ$TYe!zNqjiTmVXbGQd7s#^8BYb=>^nhO8Z>0cM2AGvdYd=w?7vZ6;)ML zRaRC4!%l?y%{xKW#2?>unJ6;T*R%@ggAhB|L>PRsR|5YV7!+AyOh``zSPIbR7$P5} zoUJjIzq7V10vP!N-~UDC#s6z$tbae~zoY7Z(zQVUmDKuQ#VD|fh`H(Cy#Bw};NSWV zoP`JWCs4Ha;o=%FBfP!BsIR9t60zp*??1`bbc4(>^Xu35xX#W?cA~;Ju93E2vobQ| z&p*i2(9#-6KkD09Et)3`qpm*c^pdpF2TTcc$+^c@nfmEG|9peFnN0u?LNJIAToHJ! zFK^7Y+ge#IO=}?IjRD&LirAuSmBf~v4%ZqY05U#7=2MVMXn>Lr-Ll)CPi-KB+f{^s zyFk1!fN+q(*^s~+C$_=cTwpi;-T0_>EDf3&5ERVX&sMFKXqG#fXLj5trYBomhZ~$S zH-GGs2GNVT#1i!P;%(E&iHhxz8_r5k(fC|iLIx(Ex*^bVPSL@90l0-<95BZVFbm)q z|G@1faAqUZ!!Qq;K;||XC{$cj#JV^OlI|n6YxaEWQwRZUY~&YN1s-TT5VTGE0|15) z_g9@i<<1f{wi>y}3MMiaObXz-BYx03n#z9?JRfGAMQy%0e@o{S+vzV)184*|Cssf^ zk4+i-)zh;DuAP5;J(s+Jb((Ml3lK&d88<};Zgx~PFrj>djls;IQZT)z2O>2%v}=xB z?5l4VASwN?QZU>DR*u`=`UVD!l0abx#v!*OYz_nAl#oyg1S}A{bJSjIWwdBFV>(BND(!U<IX2IFM!3@d$U7^mWGB& zHq}Tvz!SVIE5K*^)*`Hr`>K7*9ckag!>LeZ>0w0~+!S@gv*238uS|2&?l;@s-=QKA z5@qVEbC8Y<(%lD$RZBx3NBS4(x7>em0oS>&nVwqRZFWH#D$}(6YuzSdK5CpoEYvD4aKPSJWKo1!{j1+Uw%P!G3?}7OCg~ zB+7C9Slgkw`{EC91@zchVfqhoqN`wyD_2D>rODLJ{0`I)CAM_;Rd%6?y4ZvLjWBhV z8HY|eHgvlTgBwf2>etk`!3Nq!qR&CPCoa{zC1b7j^@qCztgKojl{ij}BGXlgXcR+a zC~u(jjQ~Td+N3+L&@!HSUlXXNYh`Und=kZOTsz&)t}Xop7-)^e?=e$;pGY1vlfukn z!J5F#wQ+9Igd21MqnZIQy`2Ng!V}2S>o}3eGT)fTlotc%&Gx2S?cmv$7@0ty*eRZP zoQeMO^e_oYSLrDKledu?7yWwPubV3fT66TFq9g19Ch4Y8m-VX)q$?M$s|gvEpMN znE|AihB}#h9i6MY{4k7pTdMa_&U|3Hk;EkWls3n0beO=;Mw0e~r?lp|vu|pz!)ny5 z_bp22R*t`=W!gozH#+ZiFsWany7kvsY`n(dU5BUnrsDD2WQ!pZrCe1gv3PSMmprQ` zZ9j53t|9X+;f3tH*O<4hye>EOrCP&IxG|z_mW~8xkdeD$(dELfgcosf26G2Rz9a@+ zj#mM@u4RNB>ton){3q;9pCR6)OGOKl`4V=oD`n^T5~~PI3A>MyZBd%a&|=d*VHxtZ z%cveV1*Tw+jeG03aypGvT7gEy!C3V&^VRKuBDs~Q(X)YEZ%PWy+VhRuXZf>wCS$vN zt1VnZDg=eKu3&U6nXUvh+^RMBC!D-Bk-D*WN2H!PShGVh{9VqJ6m^uTk39U;o<+ z3MdYBvF7b2R5Tg75s*wgwgb9_z-9@|i@g&9^$YVTaFh0%MAej-5=D}&ypoLXbDFxIWcdi`F9P#xE)&43 z8C%!3Z?OHfjt?x8(i1;E1tn((QXwNY5xFmK;A%oSt@AoaBNIYEK!IRHYBE|xf1S5i z{MbVI7@ag0#-Mx&wJ3)=^Yoz~ij-p!t{*@=R7`Ej%HbebhQgf{A4fkAQ3iX+%w*E| zgbp)j*2BO9`FB}+I5EmCtWWF%%D`2Ys&S*?3bR5=ki=+0?E~+*hm3wsQKOp`x6EL4 zL-Acbg}>}w@DH+^$ixL5&z~%3x|JjPm7Ts}A!plSqrW@PYa;0(s4y^w+Zng^P8hjn zFx3u%(>v0%dGkwGhSJ?8y`s3y`%?R0Cgaiz*%TSI6nM~1{vK}?K*x65@EmhIqHlWf zs+_!M0JH{*wja5E!q*NN7OMTd5(84??D#vzm4oC)gk(I`KROzR?<+}7V`6~uBPjFw zuS?uEX6imB&LUSn@FML8BKXW9cXM!Ooj@cqmTho7CJBu8-$uA-s6md$d$TgGo0X6j zx+<&@eWl;0VkuvqEYRqX{dvxvuTG?TcHd6p52txGXf|PVnGSon25xDWL-Gk@sTRH_ zajKi1K)VICUQ0a(DsJGW+(@1*;`%H&hp}%}zMg_O+Jii&m=SVL(k>a{_%z=D5z3+T zu&}VO)&QF&Jy*uWXA0LawFvD?ZN|d&Pmd^TPS&_{YCFfDkJhJKlcHuJIxl-F^7!aL z#)Ow?SbOA6^!}WTB+XXMrq-_vat@(ulaE%3vokXMZ&I@U+Nv~gWqv-W#^_h&sk=E2PO`~AEx&)0K&b&Rbq z@-GRIgm4=!JNmLS2sjJF+T1>4TXW!rPUj7ib|Eh(w$%IF88H8;@2L5s3*3w0w+5u# z{WGR-9Fo6T_;f1jRMtE9tQ1NW1G3tpBb$M`@tjFwS#7VB$3_Q`mQe zLLq1pu!S8R8LVZvAhJykK17z!9H=+>9RHR^nfTJZ5S1m#R4eH_MS`r%LU|>#@jCNA zJigSpGxtz!+(hl3+eV8{5L!Rv)#Qmv|@^39$-wIU_X9p&1s7;a*=Mnqgo%|#{w9Ri<}wp7`O#xDr!e$7v* z*Si=5e&VWL=BC7bI#cT?Z?rCa%XN%Dew1xi=2L%x_Ok;u@xk}9Bm#y>xK&1#5@#|k zOH6#X6%z4iL#DZLdmZ?@6?(<}PTt2cSOtgfM7>6{O3nIC&&aa{qI7Vw^5_AO|0Zc;i*_NzqdYGVTtfj!?e;N(1Vi;U8aXeMw}>AF7unFnbLQ0aZhLZ^6tb@_1kx#Klmj#$>Nui z5~@^NI`5~rXX`q+pD7_7A)uK8#ELb%1XN)k>--W;8y;3u$FHas`O*EA0uq-vJRrOk z_8~YZvq~u}dto2_cctN7{57}A$A3Ez`uq-`zfr1fH}7#=ntn&NjQl0AT!XFu@Cpkn z>o6`FuqHn&u&Uqkp{>^91Xzh1V(Cmz!B*iMeM9PwSVfM31K=xcIlYkcl`h&$pHV7o z+)~bGV(Hj5U1Khq`hsOdepn#2)|cX;jLGkAFR!k)w%6D9RP`y6*A}Yk`44~unY`xZ z{qC&W`VQVaQAXU4g|}{bq6d>M`as{H9N;3bjgr(Cxa5M%!F|?N&Qm#Cvfe#UMm`Z< zEb>b$dtxfD$a$>qeuWwTY|!Zs99YdW(Xob>0&AhRp7XauM+|mgD~tYQ7lnG4{LDT# zV!#_WF48;m=WAWLUQqCQXov+i?l1WzB_~9sY(Nbme7SEBgFwAmUcObUlV^BV)u7{Q z#ksA~v(r2t?-a{FARr30wy%3jf?e|NZ-zp`pzDJr#^m@emq*D(ui;mpHK7p;! zNY8oivz~g*u^6is(SC`;g$Px5%~_OJPLTB8f0gF3X!#l?Z6m#n9^XGvqhz)#H$hiHup-zc)fmZ26-MHKtF+%x@1qq_(k$*u}}8F zz>#!*HW|k^Vd0T|P%mr;{6G#Po15y6N2#1+v`c+*o!be)~L()V6&16TweGZHBPvJ_SLp;w>% zZ5gf`V>G1Kz7<-lJ#y)TPg8kb>Jb+cLgoo1SBA~^qhP!fB{Fl`bC)NJZ*^A2NKXBH z)<+{7*W+H;eMDaj>ohV%2`lcwX#ryY5Hf#}3w% z0hME%LG|@tLF>0dr4`vr@BZDmQqo_taSFhX|D9}8`DV>bJVF&LQ|YQL;$UXhIl7Lg>!lzNgn-!kkIZbNm#8@6BqsnYXC+^i|-~!`##PH+3Tcvv1UR? zKc?@i>^PQ^>lu?slybG*L>GR3$8w?e{v7K<7;it&{}uPRIT53eI1@ zye`^GwbMPeH-rks?@6?6{4irRZF~%H;iZ@SU@(*1xeX0*iCM!Qo?Ojxh=_W3dw(QR z6}HtFs;an=iSV@PUr;vREh(vS_;d}pNG+0g#VJPcjKUMI$vCOtM|!Fl!Ms$99)5qi z%aXVT#Jp^xU*JQ-s#@Dbzid@d_>W;9Z)K!ghyVS6!$ATC1W6G|k4uUjB4aG-s}H6r$%7NK$IyvI`IAaVTMM!WXmy8 zDf3>FLG^y#M$Og2ocs7I))>kuD`KsfqUxa>dl@*MW`p$y?XG+r`SK;nE)uwB4R3%* z8wt(K$RI8ma-(6cH2k4+w)-$>(z&~DFMCS3vw8>g%Pu+PXZuAbUe_y|V(5;kMFl4J zbX`2O^M9_Y6%yKLTSW9|M3)EOr`}8a)az>gi}6;i{MFmCr}vVj?~z_SD?2A@sJyQJZ+PM`<5>da!ymOd*(yB)L)2qBD z#1CYE96HtAK-NO{NiL)c1EeCD5#bVms`VAI@DMKo2A#rw&~&?Gul9F@XZ_(J8&$qB z`&_e;%XiSem|;K3UeayZC<54~5E_bG7zfp+Wvb{WMlq@SGN=yz7)%)g6B}N)|HG@2 zr1?MODAuB)SaqZu+B1np*EHiCsnedMoA%-{b04!Xbe@%fBWd>4h?dbXEF1yTkkzVZ zC9wUVUp#3vXKmeLSC>b-q8i}Br4v06c``F|$^9ap?^WE~82%?PaGaa%-@dE4&hV~? zZ;(yPk>(zmKY6&bxs9bioZp=q*2^5n8~O$ge&i6<2SPDhav67Q9w0t7T17cHJ;K1+ z)(L%w+KMp~_Rr`5kzz6)Xd7K2=wKU`@Q`2+_CK-jJmKW|>nm-I^3CwrQe0F<A`=q18r0`4niE)Au47??bh~j;vwjn zQYykQ>V7jgsK_y_!dulW`+eXFX%mmdmv*>vz!+3C?K{qStlh!ON*WaJAXCztIsdMY zuvd3R2@j|F)-J_Q1y(_l@exNN6n@dOh$S~)^~9dk(Q@Ws=8HCKKVvb=Qz&ok(K40! z&tIYD$1uvs+WT`QH}Or3vo~I}nH(`=U%R*@Q&`JLIf!bGpGFGyFRH5gR0^F1)^f_) zC=QjEPQf-TyF~r`=N}X-b2)*F0yEAJ2nM0H)9T1(o-S|YSm{w*i&kl9z&Hedb~=US zE*z)N+;$6eNi#_j{8ud;n`s{CX=fL=#pF{({bW&D@E9if5h(OpVq+b3+%uWSd9Unpa)8lS z&=k=E;F|-|eGf@#>=Kv=pV0kpO9gV{b%f}$8pKsqHLAl70&0`-KIcDUlTSq=F3W77 zI(MV%{{13^18fT9sun3O-5C`nhS?wu&GE9NsFCL&vrEC;5V7q~D77s^<}(hFP$UwM zQ%Zv0;k84SYvrm~3RKHX^|Da7=1g-Z-j_2+;LcU#Ogg){x$W7brr+8##>P1er(Hc` z4Bd$+=yyZYOAr<49x^G44ele)5@O9J-Jp+-5~tnjbBfx~Y9QRgs30_sl^z64UB9l_VEOwTHC(T!9yhIX+r7K`t-t0YhHhf7t+mP@3m#qO zPXs-ng{t~CQopXBT9AN*BC27OSX~f^%uJ209o~z!lz9hent3JQX RCmH`kv9orf-?H*P`7h+wvv&Xh literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/sign-transaction-chromium-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-transaction-chromium-darwin.png similarity index 100% rename from extension/e2e-tests/freighterApiIntegration.test.ts-snapshots/sign-transaction-chromium-darwin.png rename to extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-transaction-chromium-darwin.png diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-transaction-darwin.png b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts-snapshots/sign-transaction-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..8134356cac17c3d2f658626c59bd8a2e9c2f0d17 GIT binary patch literal 29918 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 AFaQ7m literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/integration-tests/sendIntegration.test.ts b/extension/e2e-tests/integration-tests/sendIntegration.test.ts new file mode 100644 index 0000000000..1a5a3d58c7 --- /dev/null +++ b/extension/e2e-tests/integration-tests/sendIntegration.test.ts @@ -0,0 +1,420 @@ +import { TransactionBuilder } from "stellar-sdk"; +import { test, expect } from "../test-fixtures"; +import { loginToTestAccount } from "../helpers/login"; +import { stubAllExternalApis } from "../helpers/stubs"; +import { TEST_M_ADDRESS, TEST_TOKEN_ADDRESS } from "../helpers/test-token"; + +test.beforeEach(async ({ page, context }) => { + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } +}); + +test("Send persists inputs and submits to network", async ({ + page, + extensionId, +}) => { + test.slow(); + let isScanSkiped = false; + if (!process.env.IS_INTEGRATION_MODE) { + await page.route("**/submit-tx", async (route) => { + const json = { + memo: "test memo", + max_fee: "900", + envelope_xdr: + "AAAAAgAAAADLvQoIbFw9k0tgjZoOrLTuJJY9kHFYp/YAEAlt/xirbAAAA4QAAAUVAAAAvgAAAAEAAAAAAAAAAAAAAABper1qAAAAAQAAAAl0ZXN0IG1lbW8AAAAAAAABAAAAAAAAAAEAAAAAZ4AU5m5lMnKhtnADB3KJkkfNHUcxrSs8TOoG98skg+QAAAAAAAAAAACYloAAAAAAAAAAAf8Yq2wAAABApUEUNnMHzyHA+ZclMfxsX1vv5wfoKegPYhxYnOuiSgit7kCLrVcahgbHAnvb0H+SM0PlZwOxEuaeBJA/B7GdAg==", + + successful: true, + }; + await route.fulfill({ json }); + }); + } + page.on("request", (request) => { + if ( + request + .url() + .includes("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF") + ) { + isScanSkiped = request.url().includes("should_skip_scan=true"); + } + }); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + + await page + .getByTestId("send-to-input") + .fill("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"); + + await page.getByText("Continue").click(); + expect(isScanSkiped).toBeTruthy(); + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + // Add memo + await page.getByTestId("send-amount-btn-memo").click(); + await page.getByTestId("edit-memo-input").fill("test memo"); + await page.getByText("Save").click(); + + // Wait for memo editor to close + await expect(page.getByTestId("edit-memo-input")).not.toBeVisible({ + timeout: 5000, + }); + + // Add fee + await page.getByTestId("send-amount-btn-fee").click(); + await page.getByTestId("edit-tx-settings-fee-input").fill("0.00009"); + await page.getByText("Save").click(); + + // Wait for fee editor to close + await expect(page.getByTestId("edit-tx-settings-fee-input")).not.toBeVisible({ + timeout: 5000, + }); + + // Wait for simulation to complete + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 30000 }); + + // Click Review Send button + await reviewSendButton.click(); + + // Verify review modal opens + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 30000, + }); + await expect(page.getByTestId("review-tx-send-amount")).toHaveText("1 XLM"); + await expect(page.getByTestId("review-tx-memo")).toHaveText("test memo"); + await expect(page.getByTestId("review-tx-fee")).toHaveText("0.00009 XLM"); + + let submitTxResponse = ""; + page.on("response", async (response) => { + if (response.url().includes("/submit-tx")) { + submitTxResponse = await response.text(); + } + }); + + await page.getByTestId(`SubmitAction`).click(); + + await expect(page.getByText("Sent!")).toBeVisible({ + timeout: 60000, + }); + const submitTxResponseJson = JSON.parse(submitTxResponse); + + expect(submitTxResponseJson.memo).toBe("test memo"); + expect(submitTxResponseJson.max_fee).toBe("900"); + + const tx = TransactionBuilder.fromXDR( + submitTxResponseJson.envelope_xdr, + "Test SDF Network ; September 2015", + ); + + const txOp = tx.operations[0] as any; + + expect(txOp.type).toBe("payment"); + expect(txOp.amount).toBe("1.0000000"); + expect(txOp.destination).toBe( + "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF", + ); + expect(txOp.asset.code).toBe("XLM"); + + await page.getByText("Done").click(); +}); + +test("Send XLM payments to recent federated addresses", async ({ + page, + extensionId, +}) => { + test.slow(); + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + + await page.getByTestId("send-to-input").fill("freighter.pb*lobstr.co"); + await expect(page.getByTestId("send-to-identicon")).toBeVisible(); + await page.getByText("Continue").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + const reviewSendButton = page.getByText("Review Send"); + await expect(reviewSendButton).toBeEnabled({ timeout: 15000 }); + await reviewSendButton.click({ force: true }); + + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 60000, + }); + const submitAction = page.getByTestId("SubmitAction"); + + await page.waitForTimeout(300); + await submitAction.waitFor({ state: "visible" }); + await submitAction.click({ force: true }); + + await expect(page.getByText("Sent!")).toBeVisible({ + timeout: 60000, + }); + + await page.getByText("Done").click(); + await page.getByTestId("nav-link-send").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await expect(page.getByText("Send to")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + + await expect(page.getByText("Recents")).toBeVisible(); + + await page.getByTestId("recent-address-button").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + const reviewSendButton2 = page.getByText("Review Send"); + await expect(reviewSendButton2).toBeEnabled({ timeout: 15000 }); + await reviewSendButton2.click(); + + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 60000, + }); + + await page.waitForTimeout(300); + await submitAction.waitFor({ state: "visible" }); + await submitAction.click({ force: true }); + + let accountBalancesRequestWasMade = false; + page.on("request", (request) => { + if (request.url().includes("/account-balances/")) { + accountBalancesRequestWasMade = true; + } + }); + + await expect(page.getByText("Sent!")).toBeVisible({ + timeout: 60000, + }); + expect(accountBalancesRequestWasMade).toBeTruthy(); +}); + +test("Send XLM payment to C address", async ({ page, extensionId }) => { + test.slow(); + await loginToTestAccount({ page, extensionId }); + + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + + await page.getByTestId("send-to-input").fill(TEST_TOKEN_ADDRESS); + await page.getByText("Continue").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill(".001"); + await page.getByText("Review Send").click({ force: true }); + + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 60000, + }); + + const submitAction = page.getByTestId("SubmitAction"); + + await page.waitForTimeout(300); + await submitAction.waitFor({ state: "visible" }); + await submitAction.click({ force: true, timeout: 60000 }); + + let accountBalancesRequestWasMade = false; + page.on("request", (request) => { + if (request.url().includes("/account-balances/")) { + accountBalancesRequestWasMade = true; + } + }); + + await expect(page.getByText("Sent!")).toBeVisible({ + timeout: 60000, + }); + expect(accountBalancesRequestWasMade).toBeTruthy(); +}); + +test("Send XLM payment to M address", async ({ page, extensionId }) => { + test.slow(); + await loginToTestAccount({ page, extensionId }); + + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + + await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill(".001"); + + const reviewSendButton = page.getByText("Review Send"); + await expect(reviewSendButton).toBeEnabled({ timeout: 15000 }); + await reviewSendButton.click(); + + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 60000, + }); + + const submitButton = page.getByTestId("SubmitAction"); + await submitButton.scrollIntoViewIfNeeded(); + await submitButton.click(); + + let accountBalancesRequestWasMade = false; + page.on("request", (request) => { + if (request.url().includes("/account-balances/")) { + accountBalancesRequestWasMade = true; + } + }); + + await expect(page.getByText("Sent!")).toBeVisible({ + timeout: 60000, + }); + + expect(accountBalancesRequestWasMade).toBeTruthy(); +}); + +test("Send token payment to C address", async ({ page, extensionId }) => { + test.slow(); + if (!process.env.IS_INTEGRATION_MODE) { + await page.route("**/account-balances/**", async (route) => { + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: "10000.0000000", + available: "10000.0000000", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, + }, + }, + [`E2E:${TEST_TOKEN_ADDRESS}`]: { + token: { + code: "E2E", + issuer: { + key: TEST_TOKEN_ADDRESS, + }, + }, + contractId: TEST_TOKEN_ADDRESS, + total: "500.0000000", + available: "500.0000000", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "0.5", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, + }, + }, + }, + isFunded: true, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + await route.fulfill({ json }); + }); + } + await loginToTestAccount({ page, extensionId }); + + if (process.env.IS_INTEGRATION_MODE) { + // in integration mode, make sure the token is added first + await page.getByTestId("account-options-dropdown").click(); + await page.getByText("Manage assets").click(); + await expect(page.getByText("Your assets")).toBeVisible(); + await page.getByText("Add an asset").click({ force: true }); + await page.getByTestId("search-asset-input").fill(TEST_TOKEN_ADDRESS); + await page.getByTestId("ManageAssetRowButton").click(); + await expect(page.getByTestId("ToggleToken__asset-code")).toHaveText( + "E2E Token", + ); + await expect(page.getByTestId("ToggleToken__asset-add-remove")).toHaveText( + "Add Token", + ); + await page.getByRole("button", { name: "Confirm" }).click(); + await expect( + page.getByTestId("ManageAssetRowButton__ellipsis-E2E"), + ).toBeVisible(); + + // now go back and make sure the asset is displayed in the account view + await page.getByTestId("BackButton").click(); + await page.getByTestId("BackButton").click(); + await expect(page.getByTestId("account-view")).toBeVisible(); + } + + await page.getByTestId("nav-link-send").click({ force: true }); + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + + await page.getByTestId("send-to-input").fill(TEST_TOKEN_ADDRESS); + await page.getByText("Continue").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.locator(".SendAmount__EditDestAsset").click(); + + await page.getByText("E2E").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill(".001"); + await page.getByText("Review Send").click({ force: true }); + + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 60000, + }); + + const submitButton = page.getByTestId("SubmitAction"); + await submitButton.scrollIntoViewIfNeeded(); + await submitButton.click(); + + let accountBalancesRequestWasMade = false; + page.on("request", (request) => { + if (request.url().includes("/account-balances/")) { + accountBalancesRequestWasMade = true; + } + }); + + await expect(page.getByText("Sent!")).toBeVisible({ + timeout: 60000, + }); + + expect(accountBalancesRequestWasMade).toBeTruthy(); +}); diff --git a/extension/e2e-tests/loadAccount.test.ts b/extension/e2e-tests/loadAccount.test.ts index 9bb61ba74c..77bd5a51e5 100644 --- a/extension/e2e-tests/loadAccount.test.ts +++ b/extension/e2e-tests/loadAccount.test.ts @@ -8,20 +8,14 @@ import { stubTokenPrices, stubCollectibles, stubCollectiblesUnsuccessfulMetadata, + stubAllExternalApis, } from "./helpers/stubs"; -test("Load accounts on standalone network", async ({ - page, - extensionId, - context, -}) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); +test.beforeEach(async ({ page, context }) => { + await stubAllExternalApis(page, context); +}); - test.slow(); +test("Load accounts on standalone network", async ({ page, extensionId }) => { await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Settings").click(); @@ -130,13 +124,7 @@ test.skip("Switches account and fetches correct balances while clearing cache", test("Switches network and fetches correct balances while clearing cache", async ({ page, extensionId, - context, }) => { - await stubTokenDetails(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - await page.route("**/account-balances/**", async (route) => { let json = {}; @@ -217,7 +205,6 @@ test("Switches network and fetches correct balances while clearing cache", async await route.fulfill({ json }); }); - test.slow(); await loginToTestAccount({ page, extensionId }); await expect(page.getByTestId("account-assets")).toContainText("XLM"); await expect(page.getByTestId("asset-amount")).toHaveText("2"); @@ -275,15 +262,7 @@ test("Switches network and fetches correct balances while clearing cache", async test("Account Balances should be loaded once and cached", async ({ page, extensionId, - context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - test.slow(); await loginToTestAccount({ page, extensionId }); let accountBalancesRequestWasMade = false; @@ -304,13 +283,6 @@ test("Switches account without password prompt", async ({ extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - test.slow(); await loginToTestAccount({ page, extensionId }); await expect(page.getByTestId("account-assets")).toContainText("XLM"); await page.getByTestId("account-view-account-name").click(); @@ -327,14 +299,6 @@ test("Can't change settings on a stale window", async ({ extensionId, context, }) => { - await stubTokenDetails(context); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - test.slow(); - const pageOne = await page.context().newPage(); await loginToTestAccount({ page: pageOne, extensionId }); @@ -463,13 +427,7 @@ test.skip("Clears cache and fetches balances if it's been 2 minutes since the la test("Loads wallets data and token prices on Mainnet in batches", async ({ page, extensionId, - context, }) => { - await stubTokenDetails(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - let tokenPricesCallCount = 0; page.on("request", (request) => { @@ -631,8 +589,6 @@ test("Loads wallets data and token prices on Mainnet in batches", async ({ } await route.fulfill({ json }); }); - - test.slow(); await loginToTestAccount({ page, extensionId }); await page.getByTestId("network-selector-open").click(); await page.getByText("Main Net").click(); @@ -661,11 +617,6 @@ test("Loads wallets data and token prices on Mainnet in batches", async ({ }); test("Renames wallets", async ({ page, extensionId, context }) => { - await stubTokenDetails(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-view-account-name").click(); await expect(page.getByText("Wallets")).toBeVisible(); @@ -681,16 +632,8 @@ test("Renames wallets", async ({ page, extensionId, context }) => { test("Loads collectibles data with successful metadata", async ({ page, extensionId, - context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); await stubCollectibles(page, true); - - test.slow(); await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-tab-collectibles").click(); await expect(page.getByText("Stellar Frogs")).toBeVisible(); @@ -829,16 +772,8 @@ test("Loads collectibles data with successful metadata", async ({ test("Loads collectibles data with unsuccessful metadata", async ({ page, extensionId, - context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); await stubCollectiblesUnsuccessfulMetadata(page); - - test.slow(); await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-tab-collectibles").click(); await expect(page.getByText("Stellar Frogs")).toBeVisible(); diff --git a/extension/e2e-tests/loadAccount.test.ts-snapshots/network-form-page-darwin.png b/extension/e2e-tests/loadAccount.test.ts-snapshots/network-form-page-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..0a23a36d27f35b71d1374a5e9b4f89336ea70d7b GIT binary patch literal 38897 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 { + await stubAllExternalApis(page, context); +}); test("Login shows error state on bad password", async ({ page, diff --git a/extension/e2e-tests/memo.test.ts b/extension/e2e-tests/memo.test.ts new file mode 100644 index 0000000000..513876ddd1 --- /dev/null +++ b/extension/e2e-tests/memo.test.ts @@ -0,0 +1,822 @@ +import { test, expect } from "./test-fixtures"; +import { loginToTestAccount } from "./helpers/login"; +import { TEST_M_ADDRESS, TEST_TOKEN_ADDRESS } from "./helpers/test-token"; +import { + stubAccountBalances, + stubAccountBalancesE2e, + stubAccountHistory, + stubContractSpec, + stubMemoRequiredAccounts, + stubSimulateTokenTransfer, + stubTokenDetails, + stubTokenPrices, + stubAllExternalApis, +} from "./helpers/stubs"; + +const MEMO_REQUIRED_ADDRESS = + "GA6SXIZIKLJHCZI2KEOBEUUOFMM4JUPPM2UTWX6STAWT25JWIEUFIMFF"; + +test.beforeEach(async ({ page, context }) => { + await stubAllExternalApis(page, context); +}); + +test("Send payment shows memo required warning when destination requires memo", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalances(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + // Click Review Send to trigger memo validation + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open - this happens after simulation completes + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Wait for the review transaction content to be ready (not in loading state) + // Check that AddMemoAction is visible (validation complete) + await expect(page.getByTestId("AddMemoAction")).toBeVisible({ + timeout: 15000, + }); + await expect(page.getByText("Add Memo")).toBeVisible(); +}); + +test("Send payment allows submission after adding memo to memo-required address", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalances(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + // Add memo from SendPayment page + await page.getByTestId("send-amount-btn-memo").click(); + await page.getByTestId("edit-memo-input").fill("test memo"); + await page.getByText("Save").click(); + + // Verify memo was saved and review modal doesn't auto-open + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + expect(await page.getByText("You are sending").isVisible()).toBeFalsy(); + + // Click Review Send - this triggers simulation and opens review sheet + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + + // Wait for button to be enabled (simulation not in progress) before clicking + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + + // Click the button to start simulation and open review sheet + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open - this happens after simulation completes + // The simulation may take time, so we wait for the review sheet content + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Wait for the review transaction content to be ready (not in loading state) + // Check that either SubmitAction or AddMemoAction is visible (validation complete) + await expect( + page + .getByTestId("SubmitAction") + .or(page.getByTestId("AddMemoAction")) + .first(), + ).toBeVisible({ + timeout: 15000, + }); + + // Wait for validation to complete - submit button should be enabled when done + // (memo already added, so no "Add Memo" button should appear) + await expect(page.getByTestId("SubmitAction")).toBeEnabled({ + timeout: 5000, + }); + + // Verify review modal opens and "Add Memo" button is not visible (memo already added) + await expect(page.getByTestId("AddMemoAction")).not.toBeVisible(); + await expect(page.getByTestId("review-tx-memo")).toHaveText("test memo"); +}); + +test("Send payment returns to review modal after adding memo from review flow", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalances(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + // Click Review Send to open review modal + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Wait for memo validation to complete - the "Add Memo" button appears when validation is done + await expect(page.getByTestId("AddMemoAction")).toBeVisible({ + timeout: 10000, + }); + + // Click Add Memo from review modal + await page.getByTestId("AddMemoAction").click(); + + // Fill and save memo + await expect(page.getByTestId("edit-memo-input")).toBeVisible(); + await page.getByTestId("edit-memo-input").fill("review memo"); + await page.getByText("Save").click(); + + // Verify review modal is reopened after saving memo + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + await expect(page.getByTestId("AddMemoAction")).not.toBeVisible(); + await expect(page.getByTestId("review-tx-memo")).toHaveText("review memo"); +}); + +test("Send payment returns to review modal after cancelling memo editor from review flow", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalances(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + // Click Review Send to open review modal + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Wait for memo validation to complete - the "Add Memo" button appears when validation is done + await expect(page.getByTestId("AddMemoAction")).toBeVisible({ + timeout: 10000, + }); + + // Click Add Memo from review modal + await page.getByTestId("AddMemoAction").click(); + + // Cancel memo editor + await expect(page.getByTestId("edit-memo-input")).toBeVisible(); + await page.getByText("Cancel").click(); + + // Verify review modal is reopened after cancelling and "Add Memo" button is still visible + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + await expect(page.getByTestId("AddMemoAction")).toBeVisible(); +}); + +test("Send payment shows memo value directly when memo is added before review", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalances(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + // Add memo before going to review + await page.getByTestId("send-amount-btn-memo").click(); + await page.getByTestId("edit-memo-input").fill("pre-review memo"); + await page.getByText("Save").click(); + + // After saving memo, a simulation is triggered to regenerate XDR with the new memo + // Wait for the memo editor to close + await expect(page.getByTestId("edit-memo-input")).not.toBeVisible({ + timeout: 5000, + }); + + // Wait for any loading overlays to disappear + await page.waitForTimeout(500); + + // Wait for the simulation to complete before clicking Review Send + // Verify we're still on the send amount page + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + // Wait for the simulation to complete before clicking Review Send + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 30000 }); + + // Click the button to start simulation and open review sheet + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open - this happens after simulation completes + // The simulation runs, then setIsReviewingTx(true) is called + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Wait for the review transaction content to be ready (not in loading state) + // Check that SubmitAction is visible (validation complete) + await expect(page.getByTestId("SubmitAction")).toBeVisible({ + timeout: 15000, + }); + + // Wait for validation to complete - submit button should be enabled when done + await expect(page.getByTestId("SubmitAction")).toBeEnabled({ + timeout: 5000, + }); + + // Verify review modal opens and shows memo directly, "Add Memo" button is not visible + await expect(page.getByTestId("AddMemoAction")).not.toBeVisible(); + await expect(page.getByTestId("review-tx-memo")).toHaveText( + "pre-review memo", + ); + // Verify the "Send to" button is visible (not "Add Memo") + await expect(page.getByTestId("SubmitAction")).toBeVisible(); +}); + +test("Send payment shows Add Memo when switching from non-memo-required to memo-required address", async ({ + page, + extensionId, +}) => { + test.slow(); + const NON_MEMO_REQUIRED_ADDRESS = + "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; + + await stubAccountBalances(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + // First, set a non-memo-required address + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(NON_MEMO_REQUIRED_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + // Go to review with non-memo-required address + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Wait for validation to complete - submit button should be enabled when done + await expect(page.getByTestId("SubmitAction")).toBeEnabled({ + timeout: 10000, + }); + + // Verify "Add Memo" button is not visible for non-memo-required address + await expect(page.getByTestId("AddMemoAction")).not.toBeVisible(); + + // Go back to change address + await page.getByText("Cancel").click(); + + // Change to memo-required address + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").clear(); + await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + // Make sure amount is still 1 XLM after switching addresses + await page.getByTestId("send-amount-amount-input").fill("1"); + + // Go to review again with memo-required address + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Wait for memo validation to complete - the "Add Memo" button appears when validation is done + await expect(page.getByTestId("AddMemoAction")).toBeVisible({ + timeout: 10000, + }); +}); + +test("Send payment shows Add Memo after cancelling review and returning to memo-required address", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalances(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + // Go to review - should show "Add Memo" button + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Wait for memo validation to complete - the "Add Memo" button appears when validation is done + await expect(page.getByTestId("AddMemoAction")).toBeVisible({ + timeout: 10000, + }); + + // Cancel review + await page.getByText("Cancel").click(); + + // Wait for review sheet to close completely + await expect(page.getByText("You are sending")).not.toBeVisible({ + timeout: 5000, + }); + + // Verify we're back on the send amount page + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + // Ensure amount is still set after cancelling + await expect(page.getByTestId("send-amount-amount-input")).toHaveValue("1"); + + // Wait a moment for UI to stabilize after modal closes + await page.waitForTimeout(300); + + // Re-query the button after cancelling (button reference might be stale) + // Wait for button to be visible and enabled + await expect(page.getByTestId("send-amount-btn-continue")).toBeVisible({ + timeout: 5000, + }); + await expect(page.getByTestId("send-amount-btn-continue")).toBeEnabled({ + timeout: 10000, + }); + + // Click the button to open review again + await page.getByTestId("send-amount-btn-continue").click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Wait for memo validation to complete - the "Add Memo" button appears when validation is done + await expect(page.getByTestId("AddMemoAction")).toBeVisible({ + timeout: 10000, + }); + await expect(page.getByText("Add Memo")).toBeVisible(); +}); + +// Classic token to G address -> Normal (regression test) +test("Send classic token to G address allows memo", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalances(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + const G_ADDRESS = "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(G_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + // Add memo - should be enabled for classic token to G address + await page.getByTestId("send-amount-btn-memo").click(); + await expect(page.getByTestId("edit-memo-input")).toBeVisible(); + await page.getByTestId("edit-memo-input").fill("classic G memo"); + await page.getByText("Save").click(); + + // Click Review Send + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Verify memo is shown in review + await expect(page.getByTestId("review-tx-memo")).toHaveText("classic G memo"); +}); + +// Classic token to M address -> Memo disabled (this is supported, but an antipattern) +test("Send classic token to M address doesn't allow memo", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalances(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1"); + + // Add memo - should be enabled for classic token to M address + await page.getByTestId("send-amount-btn-memo").click(); + await expect(page.getByTestId("edit-memo-input")).toBeVisible(); + // Memo input should be disabled + await expect(page.getByTestId("edit-memo-input")).toBeDisabled(); +}); + +// Custom token without Soroban mux support to G -> Memo NOT allowed +test("Send custom token without Soroban mux support to G address disables memo", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalancesE2e(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubSimulateTokenTransfer(page); + // Stub contract spec before login to ensure it's ready when needed + await stubContractSpec(page, TEST_TOKEN_ADDRESS, false); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible({ + timeout: 30000, + }); + + const G_ADDRESS = "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(G_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible({ + timeout: 30000, + }); + + // Select custom token + await page.locator(".SendAmount__EditDestAsset").click(); + await page + .getByTestId(`SendRow-E2E:${TEST_TOKEN_ADDRESS}`) + .click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible({ + timeout: 30000, + }); + await page.getByTestId("send-amount-amount-input").fill(".001"); + + // Wait for contract check to complete + // The memo button should be visible and enabled (user can click it) + const memoButton = page.getByTestId("send-amount-btn-memo"); + await expect(memoButton).toBeVisible({ timeout: 10000 }); + await expect(memoButton).toBeEnabled({ timeout: 10000 }); + + // Click memo button to open EditMemo + await memoButton.click(); + + // Verify EditMemo dialog is open and memo input field is visible + await expect(page.getByTestId("edit-memo-input")).toBeVisible({ + timeout: 10000, + }); + + // Verify memo input field is disabled (not editable) + await expect(page.getByTestId("edit-memo-input")).toBeDisabled(); + + // Verify the warning message is shown explaining why memo is disabled + await expect( + page.getByText("Memo is not supported for this operation"), + ).toBeVisible({ timeout: 10000 }); + + // Verify Save button is also disabled (since memo field is disabled) + const saveButton = page.getByRole("button", { name: /save/i }); + await expect(saveButton).toBeDisabled(); + + // Close the EditMemo dialog + await page.getByText("Cancel").click(); + + // Wait for EditMemo to close + await expect(page.getByTestId("edit-memo-input")).not.toBeVisible(); + + // Click Review Send - should be enabled (transaction is allowed, just no memo) + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 15000 }); + + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Verify memo row is NOT shown in review (tokens without Soroban mux support don't support memo) + // The memo row should be completely hidden, not showing "Memo None" + await expect(page.getByTestId("review-tx-memo")).not.toBeVisible(); +}); + +// Custom token without Soroban mux support to M -> Impossible/disabled +test("Send custom token without Soroban mux support to M address is disabled", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalancesE2e(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubSimulateTokenTransfer(page); + // Stub contract spec before login to ensure it's ready when needed + await stubContractSpec(page, TEST_TOKEN_ADDRESS, false); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + // Select custom token + await page.locator(".SendAmount__EditDestAsset").click(); + await page + .getByTestId(`SendRow-E2E:${TEST_TOKEN_ADDRESS}`) + .click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill(".001"); + + // Wait for contract check to complete - wait for warning banner to appear + await expect( + page.getByText( + "This token does not support muxed address (M-) as a target destination", + ), + ).toBeVisible({ timeout: 10000 }); + + // Memo button should be enabled, but memo input should be disabled + const memoButton = page.getByTestId("send-amount-btn-memo"); + await expect(memoButton).toBeEnabled(); + + // Verify Review Send button is disabled + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeDisabled(); +}); + +// Custom token with Soroban mux support to G -> Memo can be added +test("Send custom token with Soroban mux support to G address allows memo", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalancesE2e(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubSimulateTokenTransfer(page); + await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + const G_ADDRESS = "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(G_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + // Select custom token + await page.locator(".SendAmount__EditDestAsset").click(); + await page + .getByTestId(`SendRow-E2E:${TEST_TOKEN_ADDRESS}`) + .click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill(".001"); + + // Wait for contract check to complete - wait for memo button to be enabled + // (it might be disabled initially while contract check is in progress) + const memoButton = page.getByTestId("send-amount-btn-memo"); + await expect(memoButton).toBeEnabled({ timeout: 10000 }); + + // Add memo - should be enabled for custom token with Soroban mux support to G address + await memoButton.click(); + await expect(page.getByTestId("edit-memo-input")).toBeVisible({ + timeout: 10000, + }); + await expect(page.getByTestId("edit-memo-input")).toBeEnabled({ + timeout: 10000, + }); + await page.getByTestId("edit-memo-input").fill("soroban mux G memo"); + await page.getByText("Save").click(); + + // Click Review Send + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Verify memo is shown in review + await expect(page.getByTestId("review-tx-memo")).toHaveText( + "soroban mux G memo", + ); +}); + +// Custom token with Soroban mux support to M -> Memo disabled (embedded) +test("Send custom token with Soroban mux support to M address disables memo", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubAccountBalancesE2e(page); + await stubAccountHistory(page); + await stubTokenDetails(page); + await stubTokenPrices(page); + await stubSimulateTokenTransfer(page); + await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); + await page.getByText("Continue").click(); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + // Select custom token + await page.locator(".SendAmount__EditDestAsset").click(); + await page + .getByTestId(`SendRow-E2E:${TEST_TOKEN_ADDRESS}`) + .click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill(".001"); + + // Wait for contract check to complete + // Since contract supports muxed (true), there should be NO warning banner + // (warning banner only shows when contractSupportsMuxed === false) + await page.waitForTimeout(2000); // Wait for contract check to complete + + // Verify NO warning banner is shown (contract supports muxed) + await expect( + page.getByText( + "This token does not support muxed address (M-) as a target destination", + ), + ).not.toBeVisible(); + + // Wait for the memo button to be enabled + const memoButton = page.getByTestId("send-amount-btn-memo"); + await expect(memoButton).toBeEnabled({ timeout: 10000 }); + + // Click memo button - memo should be disabled because destination is M address + // (memo is encoded in M address, so it's disabled) + await memoButton.click(); + await expect(page.getByTestId("edit-memo-input")).toBeVisible({ + timeout: 10000, + }); + await expect(page.getByTestId("edit-memo-input")).toBeDisabled(); + // Wait for the disabled message to appear + // The message should appear once the contract check completes + await expect( + page.getByText("Memo is disabled for this transaction"), + ).toBeVisible({ timeout: 15000 }); + await page.getByText("Cancel").click(); + + // Click Review Send + const reviewSendButton = page.getByTestId("send-amount-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible({ + timeout: 200000, + }); + + // Verify memo row is NOT shown in review (memo is embedded in M address for tokens with Soroban mux support) + await expect(page.getByTestId("review-tx-memo")).not.toBeVisible(); +}); diff --git a/extension/e2e-tests/onboarding.test.ts-snapshots/account-creator-overwrite-darwin.png b/extension/e2e-tests/onboarding.test.ts-snapshots/account-creator-overwrite-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..d8213f7048df24490db2988700c95a86a3366530 GIT binary patch literal 31721 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 literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/onboarding.test.ts-snapshots/recovery-modal-darwin.png b/extension/e2e-tests/onboarding.test.ts-snapshots/recovery-modal-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..6bab7a5541d6f110af980c28f5e8dd463d83691e GIT binary patch literal 60823 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 bEF{V9bGmk1C21wTLQ+ytJ;ge4{^tJxF}I`8 literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/onboarding.test.ts-snapshots/wallet-import-12-word-phrase-page-darwin.png b/extension/e2e-tests/onboarding.test.ts-snapshots/wallet-import-12-word-phrase-page-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..906a2b84f51955c036d1a6d2c20f411a9d80459b GIT binary patch literal 19510 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 Yz1}@zuJQvn;1!g{HJz(Dmo1+B4>Y_s+W-In literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/onboarding.test.ts-snapshots/wallet-import-24-word-phrase-page-darwin.png b/extension/e2e-tests/onboarding.test.ts-snapshots/wallet-import-24-word-phrase-page-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..edb2f35559ea3d319db1ee7df729365090657eda GIT binary patch literal 20022 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 S6~H4X)tj0(@~)Y`_}>88zJo>p literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/onboarding.test.ts-snapshots/wallet-import-complete-page-darwin.png b/extension/e2e-tests/onboarding.test.ts-snapshots/wallet-import-complete-page-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..500855a9c5b603a15ff3cd81006d9de02b33afce GIT binary patch literal 40278 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 bEF{V9bGmk1C21wTLQ+ytJ;ge4{^tJxF}I`8 literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/onboarding.test.ts-snapshots/welcome-page-darwin.png b/extension/e2e-tests/onboarding.test.ts-snapshots/welcome-page-darwin.png new file mode 100644 index 0000000000000000000000000000000000000000..0e0c9bd7f3e586c344e970f1fde9e17e38548ae1 GIT binary patch literal 19475 zcmeIaXH-*Z7e5+g#8FVjLT{spq6mmcFTsk4ih%T{ARry2mk>rp5Cq0T4Mjmj1f=&8 zR0z_0FQNAqI;7ow=6&C_?*07#aPPWn{9qwM&Uv0^|Msu!lUMiesUAMWeF%j@9ag(_ zT?>WU4}aa)_WM5gLq*^=0}AyAO6~fU2VU`u!v|uF-TPO^@}=q>ebUYps66?2`j|?{ z@4qLXU|@S=&iLlk!$6K3SFT(+$G)R-^xUCw<}VLyI*eweUi@~<@K{HqW6{d?u0~&wvSx!#*|`_R`}yjhJBnURKV%qAHqN0 z{uuxlbL$z330^q(?+gDf$-jr;-!k|Y8UFu*i4Ql0MMM^c%eVIyvhlU-Mq3Mmo+A|R zR>k#2_=2vH(cr*990Q7O1JJMg{1!36b6|Hp2;<)wv7d)zn{9dN&dl6<-F0Z%F221!>3Q5s1fE{3hwg-+Eu;- z*I0?YZEb(UTgX{^mY%nE zzi1xadkg-L2&|5HI!CCj^#eVf&9C#_<(^3&uf1dyD7)v! zCv9IHa0SyKLXWLdwS`E=`o&TwB_&c^F~|0x zO{;ce!})=@;w)dI{HP+08zD}&Z_^EaxLmP6>Hol#)T(Z1Xo%xB;%Ig{FFIFFWv_c5 zz3F8+z$YqtPv|g8L<82#_K$1BU%#f-trry)_4Hb56a6XEELty2>toJYkC z+a8$pcHAd+-0#&gBWmfGl(p>XSWXFP;y2x!w}&xuZ|9hl}=Wj|qHFRL|FusU&K{KzlXpWUEru>X@&Uj8u_* zg=Ny_&CT#*{-pZ-PL;Wj)tWorI4yM4J8ypQUtornWJ^WfoL$s#qoYw=N=oWR-Vvkn zr;GP6U&-&gWiG@k(F?ynKahZ>d0P-(pA!{zuz%vc*S?a8!ov8?3OW}`_tin zg2#Y&<>t+($jH}yIWyb~y7pU!TOTXG4O!u`$QyIVD|wX2lovOcr=^N8mz*i$PTCe0 z>gq)se~xl8aY(b-ZOtAvqkFSBs|^l*9qe)P_H3D)b4~K!%ugGcePikc1k^P$5sTm|0=3gUd5QSS?i3hw!NkW%O|y%h!6XlVy^yWyW2X1iPE zt$JHeh98r&og}s<`a2q<9lu`2-zyKRV=~GUYQ3}DT<&V-*lc*|e{Tc`f~5{_Zc4Ec zl{Rs9*$O$yPi<k>R_DrNyrLMH_n#IaLU9i_Gd(QH9Ofje9OwJ94k}sEwmrZ z`Lx#kDl`sf)X<>rL|#{rG3Dz$mtoMQ^)~W-WMq*^wiF{u*T4YE7H}i(^XJc8D^<$A zJxwD@(n*^h(i2NB1J`lf^U;Y*a_D%O9vl0w*tI|&Gq25Q!e^oW4p)WZDoJYAx$GAE zZzgzuHJdxHE!>9s`uql|GrG}EyoZN6DmMNe{TwBvJyPbYMy>eYjYUjP6Z+RjVwASS zq+Z(Vn(B6Y@Mm10b7vW8E704mX*-jly*)Bw=Z#a-OI=zh>6?e8t{t$~($Z?@&NUv` ztM24zF_E>|sm{8se%{b9k1!oq?=-B_oAW2!P8f|Vm2n@B-@S2_uN-Xp1=r;MnObTp+d4a5*@3_)IipPM7?=DT^-xES3E3k9gZ?_@tz3%;rEg!q&c~iL zlcOFWVt3{mJ^CDe)uAi3ZPe=DMTpTl@3K}FbQ~&Ks&k@`K4)z)yO>sLK;2h8uL(^x<1@8x8!jw6 zpI{ZVxIIx-d4RewBlLVPLe^_VAY0D+aOGK-s7H*4m8haX)?qnx9vmO0^Vv9>ijAqUbaJDb03)y+DAE5hYTG^j{q{99GoI zfgbrjI(iB%D%#l4V16lHM{jeXGY#A1KhZryW$i;-;g2?ja$Gju%&>uzj$zrjMZNyVSgeyKJr`{%r?U_vMM@1KP>$# zs%pPHj%0Ps`$qk2)>q#R!-49`uMLLznHu=Dk9ImNrYUZet%)s1$%oYep9xVxD~Srb zskIIQQ3V_8&n%kbZn*1Is`r}UJz4&;uzQzi$KPi?QEa7bV1~a4XZ^3}cMK1wHW&NX z-)r9+b|{W`%`11wXyB&-kzp!{LK(H6JG)0)|1vtSY&p0zfHtH3s>Aot=EK6WI!&`g zMa9FG9hwadjg02!Iqvwc3s`PHSjizDoMKaI5HS}KqWWZ)cN3DT=;>ycWn>N1!^9m72Y`WcZtFM55)CWvb;=s>EVK`D!gWP z7l1Ixf4C0@GkgQTJ9ZXrSls_b>9%@{V{)ni^%Swox2i)18up zGct;cn@75xEc0bl=G)Jo3FkV`Y^3vFdfc`rBxKp&G0;3f%l=fjG^Fcb291R9^41vT zZl_R|s8FHQVI9ovhDLSu#@jwR(P75eSzV(rF5p$(-rmNK)*3^dO4gdo2BLb37A{No z+>7^FPac><_ySU^kp&55-Xw?Z1T!NU?7K}*2OAq3TgNXM8R=O@`o#O%W@g%Y_$O-A zXx}&FuBQ-apNLd zX>R-7NQKn6JQPk8Gzoglujz)6`P>v%qWw>e_ffjiGR2p>iZ9C)QWh?>s}~kX-%0Ra z(atv3C6@eCY!(3wqiEsj+AzuKimm~zfnwX?%+zGe9zlbLn*+bqGTe&yxQqEo`EQq_ z{Y?JLx&>o%r5R_L$~I*gsouIhWUSYF5j#CJV;Z+N13gQ(H|HWciyf77zG6Q&D&(q~ zu9oRYhP5SqKJhsertQ2{uZ)4?JR-}qXHr&PEy! zt1x88+*>xtm2U}>S4>_E4kEXsGW%8)hM@dRrFpvnnsGqjJf^} zdB5GYjO?no_U}NOboCvH8GKWvgS5B))IEo)-RVY!zss##6LF4ZHe-X!m!Pj&0>Li} z8W6ACgU!~1(Nm@P7)0?s07s?#XQH=V+n8-9$<~oxI|x_tS9Q=uxq_v4ky?Uv{iLj@&;Z6+T3i+($+escRtuymU5Vy@~1Cs=6=dCR24 z`B7a)#SBArt}oo$mZ4pij;X0~{#`{H5cz)m6^j3a*#nBl2poa>cV|6ahAyElTthMD z3>dq2>m1d~T_uAc>rfZZ`tn6~I>sVge*Oz(IG?!JQ|t(f|D(akvDA|CB)?f&q(=Ws zb~YY(BW*PZt++e+uF>9a*u9rJC60|1H*;&hfu)m)(FTv8ruG)C(F#^gF;|{5O+{ZY zESN1@_*TBwAcCCV%B_Kg56_Q;FsJ0UDw7xQZKJnNdw9VsOa1xQV?Vstr*AOPXI0TY z>&-Ij>SB1x8Wfu>``Ymfff|^3?Odw9e$K-yAJMMQ53nkeYK|8V*k)|@7-bi1Bso=t zXfC}tc$~J4rOWXDZK=F@_SnYOpi^tKhV0mjvx#1(mRsi1k`iTX`z)hP#+M&Aw)-oV zR~%doS6Ge_zb;SMtMuJ&!H1c3!Z#5~e}xT)Q(L1a_6KfVn{H@mz-;x;to~$;IAtX81o*Z%+j<=sP6e zS&Qfn3wZt447_(yg|-Br_v9Pm4nfA;u%u~9^FsUC_VY*Y&BVLjb8v7NQ*AfgovE>M zu(r3wW(gN$7oIzJ&Iaq<^c265D$eIz&0t0u=dh5C4Kn+<9d*=_t=%+u=2?lV!b-(D z8>gzz=>}|z%Nd(9M-J|?D zmbt|E&VuSECrztE(jVF>5c)IJtuW}K`qWdB$=>o=#IIk!n$h=qiMuVHhcV;0*giJ zy3y;gtu-++R=-xfjgAsH%=}2Xb^Jz8aG+9WtACu8ydhY7-3Q9b#QyP8VXs)1)9c4X zpM|U#Blg?k|I}?Y!XXB%aD@(s&|yYR;s$w-)y95Iz{VHjsSY1ac(}RE-|{y1(+)RH z5W+(3ja-|h6oxbU)``?*PZ3jm>5o5T`Tq{bKbx&CY4_Xxen7z3>SO2600kwKEdQ1n zbzU!UFDpI$mFgmRll0Ccnj2txYn)Vub7V?{vb^cbU%EZN-UwPe7^(8NZi*rO5{$T$ zq+IE&c493(Epcx%8>>Y3*pIz}I{oW6&VX+5&n1F4U;i2yK~t(3S?|QlN+b)t405U0 z!|!zudkl)2ISdroq{TnIJtmqbfrGC&v;qK86bXRoCU;(8*WM+$VT^+KeV*KTvOd*o zhNb>s7O#LJjKkps>8Dzi>AS50Pk)`1$QZIt!mPQ=CooKpam2cT7fGnOggzqOgGka- z>n~Zjju8p^n{W}Y`@$Wjdqd)yXF{;F^`utWiPx6WoOct&Re2M=r(KPkAXu z@5*N6TGX+RjPl{*{7&wZo&I7lh^vPsRYhJ7Wix+>i%=3|Zbj26dwY9R!#+vMm{Y!MQ)=(dAO-zqXt!A67X}XDDc@5$ zDap)rL@|w~q>1^Z2&HgQqy{y$i${Fy67>bBv#Npt`P;`tR3oPv^Q~KHLo>>Hvi`D{ zrKJg07Q%ZtBIOLaNZQA%DMo@1{Y)6knNpA4%1^2-%wy}^Ok?1%s%Xy;uiVh8LRz}l z-|M=s*`heAb6d1Elp@9Jj?BQ0uU@6_N6WpH)1m{LG5XE6;>A%SLF9LdDgT)S&%Euq z2?4s-*y;plS`xJRC8yb8Phut1+(dZ1Ym3~jxUlJBFscRhP!8B-LLWe!o^$i>E#VBj zXEYKifcxIDk{dUVfDW^AaMDs*D(IBQplyvwlkYUD#zRE%imHa8r4J;@+i|H1VBE&u z-y)JnwhwI%j@*?QE`ZZ`^R}hQ9u!L#smW*zU_Mxx7wzxY<3XFW-|q)6h-GqVw{2}2 z{ZWYR(p0^XHC1=IuBoWAbu_HfaO7Nh)Y-QR{67!N3|)+Z@onUwXd;D8@}Mm{;1uqmLaDzgZKt9?0WZ@+fvs^a-|VRx{;hB@q?=Cw*E5 zA1kgAFH3sHEH=CGa(wC)=h2z12$i`9^zM)yqHGB;{F2&~Y*&4T4$?MuA zvHL@^RZ&|u)m1f=UG#hbM)49~F|UZR*H~abSx>n23-M~Ym4g&6$fakwglJjCr{G~f zHd)_KPdLeO1QqVG0Dh0JDb9DLQpSj3_r(^b-w99c(YFZmld~E%@f&J)?=^|0`&+c& z$Fqk~fB(tAqH@-}O|RTME-p^qRH-3rBCU2h>CQWmigzB~$$zZ}vSMbhHQJ?t;j5>k zGu6n7rZ{sLg+5ETY@@{?(gYwDYGKE5LI1w~G7*pMNo8PUnyh27UYT(u@XDf3d&MSs z$anf{ETLJ_G2hvhQRkka&*1*t`uRUEpn54=OO{_&UXi=R**on3N;Q-QB}ToA+d7+K zNbtQkT&}xw;J6EqxR6`!boojZq%B>3a!D49Drq2u0`A4Tb*MGQE6!nJ6}_LQIsMzOPqNz%?3Or<)9>i>zAW<$%p) zE}66iDvJH)T=C^i5+PGtNC?rQCK(A576ki(_M83Zg%#hz;oxlh92z;XjY|^AnE3fS z3Os;-?riG8znBN2$E13V-(}?hnXR-&dHRGdxnoeay$qD90z8iBkpE22c=~5pK3j=) zx!&RuWqNV-uhNL9S4;>bI9~R7c#Q%aP@&t7_KVuUGIE(L+b?hLyarD zV=5+fkH@Y(*BiFQ<3!R{J*GJ0r;~chcc*b2<2kD@XSNP$6OpnK*k5;|_#(-XUNoP% z#G-RH-uVYquG{#lvo}$mnMAMJv6noKzjSr&@y@7Ka-NUCO%$y$2F19_aIT5f;!*7Z zAA>=~{LaQftYXL7z3ayJWeqm)Mq~+_2T#ZoLFLlW#q2jD2E94DhGRezs+vFv^%kDJw{Hzqot->v+=aO z+4hujD!cOlu832n84q&$qvQC(sl~3w}AfGVRsf9Z0Mw` z5~A@+z8)MR;C{-IRZg@J-WMh;`s~+uTQM*tVDLVvRZd>ow&;)Q2&FCkv^25Mb9?Kp z=p=0Q3b2Ph>?XCCWyGRkzW_*!<^7vhsqKRHv++0HbL zu?w9ERdhK$S!pjov@c)2{IZZ;xJaV{&Blpe-|!z}Hrs&!a=?aqg!{6v(f&ZyHT2HK zeXC{!AQP;&$d`s5zq<>6rmeQkVNO|55I>h3nhoC=Z$!ukI zwqzna^jAb6bnGqI$Y#LUGu0?R6;uD+sUM_VxL17+yCXc(i$S1L#~cnNr4P10+s}L` zX=;5=16$^~GSXASTkq#iZdC}FtbrU2+eq)f{YT~Q;2oRjP$XPj5RADB7&dHG94MTPSV z=eu|BrX`tGHi`cp@EE)XWm!D*XlBX5BseE<3W=9QYEEpYp{X`wUEkppc=o2zD*-eQ zg>3|i`+--vt43~}c$J0O%rK)uq@76hZNkYwHzV+aH8{4`w{+E-kV)>+))1|r%5vlr z#W8d0h%}%%yndWrwKs3?9vX+Ckm{mKb5;#h8#_sdI~sXWLmeHLT*hnsyoX9$_*&O_ zS;>JMrktKR)Ic2_oqqBO88@&{CXWyA6q*90@0O1b^2j}%L{JmkqPO0tIrby4 zj?dHBcnt{B4zzJQ|6|inMqv$Uug)e0JAw%mQaan0YXKl#G6{6YbZG_Kg1{K!?Tifq zGYnU&cpV;C(R3CSglrmziJN8>@3tFYNC^%OO`=(0;N$ zvi`Ls-%>h_oX@tknBO|${PXYuey@i;(r?1e+%|R_#qqp@2Cz;O0!?D&i&`{F+%N-zH{CW(mr_>Bg zO{)xWKMqMSDbjW((A%Z0Q$%TLX{(HSI&Fo{-m-o<=kAy`Hl^)|+~nV`txBE{VFWwL z*mt@xt4Cds1GWd=bm=0|B6iH-`i`%^emgi;Kn#uh2EAU5A^OZJ0ZW+>K-9v-qgMQI zVe_ShA+L!r1RX6JD&Z#UijQVU9E>2+$cIM%pg*u`O{7L<`w0=INzZ<$4!RkOp0Au} z6f*gTs~4*GbX#p&>gXg&*oMJ)=l)QcW_Kl#blhr*$}aa<0?w&uK4% zqySQ8Zy6bh7-c>X1-=%Gld{tttLTh2^Y>O}L0HW_G<5@7iKfTU_}?e5v5T8l+;N^B z$J$OP6Ye9T_weDvE;1HXe4egsjX9hwJks`11i>yO@Peek8GF*jxq2_|aynI>wDX!z zL0UIBntwbpII^mjjg2kkW>`p&1b@@m&mg2lk!}&x`APCu$BKubZ|-OK`v{Q7W9DDw zp0s_?-@(#X=qA8Yxln)e!(2&Q7zVbtH9{!d`(auV_8pIe`E^tL80gssn8*YKD$9kf z!XQ4@z&(e;I(}coDV>l990MkCwW{Jtd$MH<^M2H)pK3X%S;C<-yRYCvK@};O%s__q z>WWL19{`t(l$0e(w*0rY0mzscS$W;NG!cJ|33a*&nkxO6plbLKQ1D&@>jVI+eDLMg zr<-w7c0Dz(j>EW5(OhSmHA-deKfe5`#I6628uP;=0AqDwJTm^29XOy{D@1%=-X%ue zpqDRS?yk>hB*<^Js|qAseDveEhT5Htp7{SHoA6#o0MYSeHm9N&A&yOUs~r4*)NR?Tsd3~gEO|Je&S0jTCS#3}>p72;V{ly&t1VQjZeN|?0#V$M$lE5Nq2M7as< z-jlm`W0`c2p$>7%FUi~IMb4-vV%^4G0jSUD;W;~kGqLE`o5yA zt*xmasa7yt_7vj>g^MbvS^i}I;-RPNo6I+a65o<)UZ+_zsdyq0;&3%=aUocIAdW0m z-kcK`hc%*unN!KZ{bA?e!vJ&7Hh>{_`pz)Z#n;k4C|1wu+A=Q6VuXCSg-Bfcl_o{dUof zne-s+ti7TGyb_7L0;?X}N)B{9otQ%^XhsR^0!I-xMd&H93M2V}tY6|h29{7X!~ORx z?5L0~*kSeCw=a$0;Y@18TzmxLhKt_&R!AMPQ6n=meAA^2O+|-^dK`SiZx>bGaLYKx zv(hkl#Mgn;#2cJgBACliUTl2Fv^VVCy#QGKNug$L+pIoHv2{cshTslw zBVeuD4}FgEQ-HRLxE4`wL&d9Pmp6X|GE3^}|39u%?&)I!*=0UG4P1PFC{XCEE6||5 zx^?vUuoMyyB0P1;X(A0Ftu@Y*q>n-T|JW*GuP%;&n}N)QywdO+hw(kvsy8s3wBDlN zR19t!F!3s&9wX4KT*d?=6puY`(=UO3rJ=A?pdTaWYBkgbXSNjVCdy77I^0e)U(zKK zI?-reqZqkf!$0rm5rvwt5pW=PBjy(t5U=dXCx@bb#9)tA@N_ix>QFmdyNoPdE@eH5 zt{Am$f>`9{yI|8@u$Nn&0NKFdJJQ$3N#qAtDfb6}ip4G%6Twr^bI(ROfj3`bMl!61 zgLgtNqV8j8(6>&LJw#Sdvh8vKt_3#E#zJp4fHQ<3CYi_U2fz{w8bBz8nn8E!dpDDWr3DLy3yX_KdzVHtK%^b=075dtAtQ(tE?Zy7gn%ND8S15B z;Dnd~5U1se^_JkDAR5pi+n{A$SG;z#cW^*r4=$1GJvaG@(BmX>s9kBwY|)CFUD^V> zzf`N})RnrYZYvEl==R!?G z?$nd67)Ga@?@XGtZ|YpcPfa8JrzD~uZ^}2@wdQe-&~E|I2p93P&< zf=(wQvr%u#+jDo@o_bepW;xZ~zs!E>=)}TLR+#a6to$h~b|%7qBPC|&CK;kk*WH5! z+}zwz{kQy)&c5Ae5z#zwGw%&CcMX_Kc~hL`$K3-44iHUgHimMD`_H9DuT@eBGF3;J zB^sMOCpJ1YvcG%@9tsN%yF{nVps{0t|HLI8f>!OCX-hIZSCBbcdEIa6>A;&H1lnu= zeN5;8Op=-7<|)GD);6Aw8G9QOKFz!v8z%VYOyR4e3y8X-QW94DW)N#Tb`{_pv4!tB ziQpY6&(;=h+7jFkuyD4yG%I8FCYe)HQBn2uO0V9XP^^M6w<}*SvXeZco=y3A66)$v2P)uV~-6$Aq2R90Ij{ zu~4VAj;}c-PTBcdxGpZ~=$U|rWE93N^%W#FLOgrMsI3M@O9&VuZfb#DQ;1-IMK#a1 z(()#v#r03dq4(sb`$#d9Gbp1{6Z5G_)z^&oUm(@g)s?O-ITFD+vNhi=lIIL@AY_Uu zr|zemg#lz52)f*fh9ufX+Qfn!q+QSk1pIf#k|>jB!OQMgTU$GM?PXVQFH%+b-DW38 z2-oz_-o9k#8|3VVs7njk3Zg%`wphXvIgt46%9R_B5xf%d>a(tyhotn6cOy_~h>IJ1 z($!v+9{-W@Yh*_=^Y}@5h$JCT0IqUl!DHxN=Frd(g}~!f(}0A_Lq3^`z=6De8&8AC zU$@8O%zR&cs94z-XYr90v8io&{^T#?{{;=CNruEeu4C=}$ZQ9Y2u+e}nCF}q#ACf( zT{Xg+0OmZGpWLsDL}XQh-&#F1UNk5sP#;Bno1 z`GHGkQs14q8**^{CXd63yM1XINyy6N8V)TZxLv_U)Xrpg9TqL>J9V@9ALMv!fANsC z{|R4Y&P=}#x_*9zM_duBZTt;D&_!TfFxB8FkP2e>5tXCoNi_L@@yi~IeZNQixbi8p#30}52BT{9 zxBM1_#G7Pt<$^t9r(JUKOf^{09(B(jS_GFp{QhjwOyFr}U!N@CS)!6}IHyGNYRf#^ z30%n75{%!=3_1T~yD+mY;&{r#Y4X<_kRc)^{%PeWA_&PhLie_o7Mchm!u;Q|F-vx^ zk=L12NJpztwF@9A8(UAZxN!idU)(TRK%HO&UMFk{JTt}f$~Bo|8hu^^R;Uvq3@rC6 zkVXXtBFpTV@q;`XgDe5&LU1;FVKx9}D%r0+oMj(R=ho1-ZekL)LglJ2c}7Ie5!O#9#w` z>I9*<)Pa}d545#iA!VVhMdO=L!j53Ywka9A)UqMv2tP;iLrhn9H*$tmd0pTh+g*=c z2v|Nzs|ZKuS+u=pxFMMMcAnz{4~hLrfa8QXcDE5Q3dvyW7_Uj_7d&Z4m>JZAHOlQc z!hlNwfM=R<+aOqFqtw+aLl4j-A??G(#kDAt?dz!f+{EF(;k*HpzkyW>(Yyn6j98YJ zth%l^91sfNCN3@30giPb#>z5|3f|;}fbamXvx=IU8dx=uwJ}kAuWta=g0Xmn8i9On zhV{IJDm%%*(zX-^IR$t;6Lk>+z{}_~D#q|wrWlA*MDNPG&m%eLqaVKsnguN1`)73N z#TpDKp^p6@KeYE@aG^a#6_ym9g=mCd@JxZay5vLmC%`ov9UXz{KY0T4X&Kqst*F@+ zs9jIC(!p}imHGMk9Y!VEo{{(}{^fzHzWl{T}Iuwu8eG_><$CpIHJNZ=e|6 zBuRCiuo8k84l&~=ear$CoXp!xgEEP)5WKfGXHwbLWEX#I1zX5?;0QdU(i<=5YQFl< zV=MwCUh`9RjN3qp^75Y6zZK#_4ZlEvj6pJ4GwbHKsj%o(0S=9yoOE4CZB~L?P_swk z&z<<-8@v~WF0t6c{d0s!HBDym`~J}>jt@tx{{o)jI@8h|aO${5la~+S9Z0!ZM8ovL zg22M%n+Y3|HeR2#QPcsofdjQ+3%CIMF-gYBl<7pS*IRc$-uii)-KT#qzj^=CRVXxHOHkvim?94_(6Er>{7rfw*89Vj{lxC<+f^o4~MWF*B) z5z+mYQ3_BNyQyG=BJa6j(UCdo&v#;Snw8wLvz4|G)A zxMUTv+nr#_+Yf9qwki_>G(TRniA9){xsTs;thJbFg{&B2iy&EgVUMARG z3cHaaP}{c(#;`3!Q*ffOp#ClxDNOyL^s-9(8vP36iS*zk z&~mR^;@x`;kdz(fEso|Q8hr_V0>};vGFvhySRTbK@(T#YLH{8=ys6|5W|mo(70}vY z`~2qdkT(elj^|%`X}$$fq;|rlU}J|gvEGcxCLa5oE5^snQXYc8L@tR$wl-n;@rfNM z-j|1Y*kw2d!F<*>f8HKMvI}c@%@@oQqE!Z#p*b2DkTO_yupkmdtJ6<1JzC^u+{#)5 zalvHwS~k7wCHG*|qYBA$f^kpi5Q5DK&)*^;5j8XxP=40NCE#FON7X5XMOtJZQQBxj zGG+)h5gSZZdF>5|7dv=bx_vNVBpt>H0imUiF69 zJKk)y;$r^dP|x)cONBfrc)_YN|DfxJyZa`r1IL&TL=390YKsv8Q74sh9^t09>cHO? zt_L!(1bSEEd04FV3HzFnHEA%>gMWS*r*0F`mkRGcZHu+*0r(tL$h1lp z(~x)k^bn|I=%&SKT5bg9g2$N#MX^^w5>~%Rox(FEcCV7k6cdYD*qQ#3gtJ!3SHVx| z`}G4%h#-j*VRDa+IW0!Q?FfHv&!FkvnF57TSn_iL%Af3en+qIfFo(&rG%)ws{4qB( zq6MHvxtS3m`{;LGz1=2j<$NIYV0+^uY#dHJ{A80x-UU^nR0RWY`38e0^GH%45Wa>v zR?H@cj`uK^^YwFC4E~x^7q7g0Nw#PgG|FVw;G8mtqd5#-LXOx0M3UW8(rGa~;^#G1 zr4#SQo(zC0j(J)a1w4I#x0|~$_v$CFq4M8*OPrCJppoaXjRLVit!u6;u>+Gqp0X00 zno{~5b^igvW*cU1y{zWjoNX7JF4MF-`mWuCBs`_lqxsr-z4*-+&a%* zMcd5w9124Ku!!C0TV|$TRWpQD^|yL5vsNb-Y(QZAIvG^6DqR(}6`t;1 zC$$+`@g-VqC;NvO=y0bZ1=ME6=faDIo;Kd<0elrZlS}&JMvJIZ^N*BhPmA~S5_P=C zIS8LT!=!q=7P5+?iqm&A{hI4Oj$ISjyH9o?Jdv4B-Sx!*)7`QUtj)T9FbRnLn>=L7 ziY$PHfVob)(iWwma8k2`=K<7BJ^C%%yLlW6H0|Nx9h+F5tc(m_aH|MmJRD0tAQn_n z(b3TYZf#dIYa`G!FBV@IK&{rdrc<|*Af1JrtZ&og*Y^BWw3#v(3l=B&E8*##y5f-y zqtRJRfH~4;AH2Tsx$iTnm&X29w|W!x(VuW|JI^L%WWe)J6dm>8g6z#b7FDy9%b zA@G1VevN}&FbBN3RVC_@Pzrol2UNh3PLf7AdoNdyxtfFuQsaxp|6B9KiZ!H*#ld;0OR0}DjP2Bm8YB2 z3%jB5)v=!lVtVlco)>2}9*`WTBOT?1=O-_iqB^3mn8SG&nQhj@Kn}4Zza?qaeh&Lg zPtif4iiJVt&8m;6%9}Nt`fl>e~x&BP@4rvQG+Sw4_gWIN6kAj`CwLG za4iqK9YJ#Ha}mLx&K8ou+6}IPym}m8R9n!s@MLL zTcWfqF@wC*10~?fAk%&R5pSoCS1^Pa)VF=S2DCw=peBHUaqXx8U+webDMgCc_3pDs zTO8sR;>zk%)o77mIf@*uE&m$jOn}v+BO>}Oje|2=J&?A- ztZi09Y4k)QAp_OO`*0`_2uTSCDW`_Fgj&9l@%3x6KN3`Sj$Y7#4arWKz;mHO{z4pR zO=V5Xk^LqQq+vo&9Gqa7#KumJ1Dd^iI@hjQ@%9+jpc3Hse{DstX=Cl(vXL11=7hXa#GWCnyevIp7!&ghkCJGwgf=g6s3k)2HNyiSVW2wTp`Z;=6Q+NG#EAp16@$SrsT6DdSEV3R0k9M# zd8^CLCMG5?TxdN{lvpyj literal 0 HcmV?d00001 diff --git a/extension/e2e-tests/sendCollectible.test.ts b/extension/e2e-tests/sendCollectible.test.ts index 3e580e4d81..4096dfb139 100644 --- a/extension/e2e-tests/sendCollectible.test.ts +++ b/extension/e2e-tests/sendCollectible.test.ts @@ -1,9 +1,7 @@ import { loginToTestAccount } from "./helpers/login"; -import { TEST_M_ADDRESS } from "./helpers/test-token"; import { stubAccountBalances, stubAccountHistory, - stubCollectibles, stubScanDapp, stubScanTx, stubSimulateSendCollectible, @@ -12,25 +10,17 @@ import { stubSubmitTx, stubCollectiblesUnsuccessfulMetadata, stubFeeStats, - stubContractSpec, + stubAllExternalApis, } from "./helpers/stubs"; import { test, expect } from "./test-fixtures"; -test("Send collectible with metadata", async ({ - page, - extensionId, - context, -}) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - await stubCollectibles(page); +test.beforeEach(async ({ page, context }) => { + await stubAllExternalApis(page, context); +}); + +// Review screen navigation and collectible details display issues +test("Send collectible with metadata", async ({ page, extensionId }) => { await stubSimulateSendCollectible(page); - await stubScanTx(page); - await stubSubmitTx(page); - await stubFeeStats(page); await loginToTestAccount({ page, extensionId }); await page.getByTestId("nav-link-send").click({ force: true }); @@ -71,11 +61,10 @@ test("Send collectible with metadata", async ({ await page.getByText("Review Send").scrollIntoViewIfNeeded(); await page.getByText("Review Send").click({ force: true }); - // validate that fee is updated in the review screen to include minimum resource fee + // validate that fee is updated in the review screen await expect(page.getByTestId("send-amount-fee-display")).toHaveText( - "0.00002 XLM", + "0.00001 XLM", ); - await expect(page.getByText("You are sending")).toBeVisible(); await expect( page.getByTestId("review-tx-send-asset-collectible-name"), @@ -151,13 +140,11 @@ test("Send collectible without metadata", async ({ await page.getByText("Review Send").scrollIntoViewIfNeeded(); await page.getByText("Review Send").click(); - // validate that fee is updated in the review screen to include minimum resource fee + // validate that fee is updated in the review screen await expect(page.getByTestId("send-amount-fee-display")).toHaveText( - "0.00002 XLM", + "0.00001 XLM", ); - await expect(page.getByText("You are sending")).toBeVisible(); - await expect( page.getByTestId("review-tx-send-asset-collectible-name"), ).toHaveText("Token #3"); @@ -179,266 +166,3 @@ test("Send collectible without metadata", async ({ ), ).toHaveText("GBTY…JZOF"); }); - -// Collectible without Soroban mux support to M -> Impossible/disabled -test("Send collectible to M address when contract doesn't support muxed is disabled", async ({ - page, - extensionId, - context, -}) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - await stubCollectibles(page); - await stubSimulateSendCollectible(page); - await stubFeeStats(page); - // Stub contract spec with muxed support = false - await stubContractSpec( - page, - "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", - false, - ); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("send-amount-edit-dest-asset").click(); - await page.getByTestId("account-tab-collectibles").click(); - await page.getByText("Stellar Frog 1").click(); - - await expect(page.getByTestId("SelectedCollectible")).toBeVisible(); - - // Try to send to M address (muxed address) - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); - await page.getByText("Continue").click({ force: true }); - - // Wait for contract check to complete - warning banner should appear - await expect( - page.getByText( - "This token does not support muxed address (M-) as a target destination", - ), - ).toBeVisible({ timeout: 10000 }); - - // Verify Review Send button is disabled when contract doesn't support muxed - const reviewSendButton = page.getByTestId("send-collectible-btn-continue"); - await expect(reviewSendButton).toBeDisabled(); -}); - -// Collectible with Soroban mux support to M -> Memo disabled (embedded) -test("Send collectible with Soroban mux support to M address disables memo", async ({ - page, - extensionId, - context, -}) => { - test.slow(); - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - await stubCollectibles(page); - await stubSimulateSendCollectible(page); - await stubScanTx(page); - await stubSubmitTx(page); - await stubFeeStats(page); - // Stub contract spec with muxed support = true - await stubContractSpec( - page, - "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", - true, - ); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("send-amount-edit-dest-asset").click(); - await page.getByTestId("account-tab-collectibles").click(); - await page.getByText("Stellar Frog 1").click(); - - await expect(page.getByTestId("SelectedCollectible")).toBeVisible(); - - // Send to M address (muxed address) - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); - await page.getByText("Continue").click({ force: true }); - - // Verify NO warning banner is shown (contract supports muxed) - await expect( - page.getByText( - "This token does not support muxed address (M-) as a target destination", - ), - ).not.toBeVisible(); - - // Wait for the memo button to be enabled - const memoButton = page.getByTestId("send-amount-btn-memo"); - await expect(memoButton).toBeEnabled({ timeout: 10000 }); - - // Click memo button - memo should be disabled because destination is M address - await memoButton.click(); - await expect(page.getByTestId("edit-memo-input")).toBeVisible({ - timeout: 10000, - }); - await expect(page.getByTestId("edit-memo-input")).toBeDisabled(); - await expect( - page.getByText("Memo is disabled for this transaction"), - ).toBeVisible({ timeout: 15000 }); - await page.getByText("Cancel").click(); - - // Click Review Send - const reviewSendButton = page.getByTestId("send-collectible-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible(); - - // Verify memo row is NOT shown in review (memo is embedded in M address for collectibles with Soroban mux support) - await expect(page.getByTestId("review-tx-memo")).not.toBeVisible(); -}); - -// Collectible without Soroban mux support to G -> Memo NOT allowed -test("Send collectible without Soroban mux support to G address disables memo", async ({ - page, - extensionId, - context, -}) => { - test.slow(); - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - await stubCollectibles(page); - await stubSimulateSendCollectible(page); - await stubScanTx(page); - await stubSubmitTx(page); - await stubFeeStats(page); - // Stub contract spec with muxed support = false - await stubContractSpec( - page, - "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", - false, - ); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await page.getByTestId("send-amount-edit-dest-asset").click(); - await page.getByTestId("account-tab-collectibles").click(); - await page.getByText("Stellar Frog 1").click(); - - await expect(page.getByTestId("SelectedCollectible")).toBeVisible(); - - // Send to G address (regular address, not muxed) - await page.getByTestId("address-tile").click(); - await page - .getByTestId("send-to-input") - .fill("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"); - await page.getByText("Continue").click({ force: true }); - - // Wait for the memo button - const memoButton = page.getByTestId("send-amount-btn-memo"); - await expect(memoButton).toBeEnabled({ timeout: 10000 }); - - // Click memo button - memo should be disabled because destination collectible doesn't support muxed - await memoButton.click(); - await expect(page.getByTestId("edit-memo-input")).toBeVisible({ - timeout: 10000, - }); - await expect(page.getByTestId("edit-memo-input")).toBeDisabled(); - await expect( - page.getByText("Memo is not supported for this operation"), - ).toBeVisible({ timeout: 15000 }); - await page.getByText("Cancel").click(); - - // Click Review Send - const reviewSendButton = page.getByTestId("send-collectible-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible(); - - // Verify memo row is NOT shown in review (collectibles without muxed support disable memo) - await expect(page.getByTestId("review-tx-memo")).not.toBeVisible(); -}); - -// Collectible with Soroban mux support to G -> Memo can be added -test("Send collectible with Soroban mux support to G address allows memo", async ({ - page, - extensionId, - context, -}) => { - test.slow(); - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - await stubCollectibles(page); - await stubSimulateSendCollectible(page); - await stubScanTx(page); - await stubSubmitTx(page); - await stubFeeStats(page); - // Stub contract spec with muxed support = true - await stubContractSpec( - page, - "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", - true, - ); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("send-amount-edit-dest-asset").click(); - await page.getByTestId("account-tab-collectibles").click(); - await page.getByText("Stellar Frog 1").click(); - - await expect(page.getByTestId("SelectedCollectible")).toBeVisible(); - - // Send to G address (regular address, not muxed) - await page.getByTestId("address-tile").click(); - await page - .getByTestId("send-to-input") - .fill("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"); - await page.getByText("Continue").click({ force: true }); - - // Wait for the memo button - const memoButton = page.getByTestId("send-amount-btn-memo"); - await expect(memoButton).toBeEnabled({ timeout: 10000 }); - - // Click memo button - memo SHOULD BE ENABLED because destination is G address and contract supports muxed - await memoButton.click(); - await expect(page.getByTestId("edit-memo-input")).toBeVisible({ - timeout: 10000, - }); - // Memo input should be ENABLED (not disabled) for G address with muxed support - await expect(page.getByTestId("edit-memo-input")).toBeEnabled(); - - // Enter a memo - await page.getByTestId("edit-memo-input").fill("Test memo for collectible"); - await page.getByText("Save").click(); - - // Click Review Send - const reviewSendButton = page.getByTestId("send-collectible-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible(); - - // Verify memo row IS shown in review (collectibles with muxed support to G address allow memo) - await expect(page.getByTestId("review-tx-memo")).toBeVisible(); - await expect(page.getByTestId("review-tx-memo")).toContainText( - "Test memo for collectible", - ); -}); diff --git a/extension/e2e-tests/sendPayment.test.ts b/extension/e2e-tests/sendPayment.test.ts index 9c05a6c66d..47c7475db3 100644 --- a/extension/e2e-tests/sendPayment.test.ts +++ b/extension/e2e-tests/sendPayment.test.ts @@ -1,27 +1,28 @@ -import { TransactionBuilder } from "stellar-sdk"; import { test, expect } from "./test-fixtures"; -import { login, loginAndFund, loginToTestAccount } from "./helpers/login"; -import { TEST_M_ADDRESS, TEST_TOKEN_ADDRESS } from "./helpers/test-token"; +import { login, loginToTestAccount } from "./helpers/login"; +import { TEST_TOKEN_ADDRESS } from "./helpers/test-token"; import { - stubAccountBalances, stubAccountBalancesE2e, stubAccountBalancesWithUSDC, stubAccountHistory, - stubContractSpec, - stubMemoRequiredAccounts, - stubSimulateTokenTransfer, stubTokenDetails, stubTokenPrices, + stubAllExternalApis, + stubSimulateTokenTransfer, + stubContractSpec, } from "./helpers/stubs"; const MUXED_ACCOUNT_ADDRESS = "MCQ7EGW7VXHI4AKJAFADOIHCSK2OCVA42KUETUK5LQ3LVSEQEEKP6AAAAAAAAAAAAFLVY"; +test.beforeEach(async ({ page, context }) => { + await stubAllExternalApis(page, context); +}); + test("Swap doesn't throw error when account is unfunded", async ({ page, extensionId, }) => { - test.slow(); await login({ page, extensionId }); await page.getByTestId("nav-link-swap").click(); @@ -210,30 +211,53 @@ test("Send doesn't throw error when creating muxed account", async ({ extensionId, }) => { test.slow(); - await loginAndFund({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("address-tile").click(); - - await page.getByTestId("send-to-input").fill(MUXED_ACCOUNT_ADDRESS); - await expect( - page.getByText("The destination account doesn’t exist."), - ).toBeVisible(); - await page.getByText("Continue").click(); + // Override account-balances to return 0 XLM only for the muxed account address + await page.route("**/account-balances/**", async (route) => { + const url = route.request().url(); + const isMuxedAccount = url.includes( + "GCQ7EGW7VXHI4AKJAFADOIHCSK2OCVA42KUETUK5LQ3LVSEQEEKP7O7B", + ); - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); - await page.getByText("Review Send").click({ force: true }); - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: isMuxedAccount ? "0" : "10000.0000000", + available: isMuxedAccount ? "0" : "10000.0000000", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, + }, + }, + }, + isFunded: !isMuxedAccount, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + await route.fulfill({ json }); }); -}); -test("Send can review formatted inputs", async ({ page, extensionId }) => { - test.slow(); - await loginAndFund({ page, extensionId }); + await loginToTestAccount({ page, extensionId }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -246,276 +270,92 @@ test("Send can review formatted inputs", async ({ page, extensionId }) => { ).toBeVisible(); await page.getByText("Continue").click(); - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1000"); - await page.getByText("Review Send").click({ force: true }); - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); -}); - -test("Send persists inputs and submits to network", async ({ - page, - extensionId, -}) => { - test.slow(); - let isScanSkiped = false; - page.on("request", (request) => { - if ( - request - .url() - .includes("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF") - ) { - isScanSkiped = request.url().includes("should_skip_scan=true"); - } - }); - - await loginAndFund({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("address-tile").click(); - - await page - .getByTestId("send-to-input") - .fill("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"); - - await page.getByText("Continue").click(); - expect(isScanSkiped).toBeTruthy(); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); await page.getByTestId("send-amount-amount-input").fill("1"); - // Add memo - await page.getByTestId("send-amount-btn-memo").click(); - await page.getByTestId("edit-memo-input").fill("test memo"); - await page.getByText("Save").click(); - - // Wait for memo editor to close - await expect(page.getByTestId("edit-memo-input")).not.toBeVisible({ - timeout: 5000, - }); - - // Add fee - await page.getByTestId("send-amount-btn-fee").click(); - await page.getByTestId("edit-tx-settings-fee-input").fill("0.00009"); - await page.getByText("Save").click(); - - // Wait for fee editor to close - await expect(page.getByTestId("edit-tx-settings-fee-input")).not.toBeVisible({ - timeout: 5000, - }); - - // Wait for simulation to complete - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 30000 }); - - // Click Review Send button + const reviewSendButton = page.getByText("Review Send"); + await expect(reviewSendButton).toBeEnabled({ timeout: 15000 }); await reviewSendButton.click({ force: true }); - // Verify review modal opens await expect(page.getByText("You are sending")).toBeVisible({ timeout: 200000, }); - await expect(page.getByTestId("review-tx-send-amount")).toHaveText("1 XLM"); - await expect(page.getByTestId("review-tx-memo")).toHaveText("test memo"); - await expect(page.getByTestId("review-tx-fee")).toHaveText("0.00009 XLM"); - - let submitTxResponse = ""; - page.on("response", async (response) => { - if (response.url().includes("/submit-tx")) { - submitTxResponse = await response.text(); - } - }); - - await page.getByTestId(`SubmitAction`).click(); - - await expect(page.getByText("Sent!")).toBeVisible({ - timeout: 60000, - }); - const submitTxResponseJson = JSON.parse(submitTxResponse); - - expect(submitTxResponseJson.memo).toBe("test memo"); - expect(submitTxResponseJson.max_fee).toBe("900"); - - const tx = TransactionBuilder.fromXDR( - submitTxResponseJson.envelope_xdr, - "Test SDF Network ; September 2015", - ); - - const txOp = tx.operations[0] as any; - - expect(txOp.type).toBe("payment"); - expect(txOp.amount).toBe("1.0000000"); - expect(txOp.destination).toBe( - "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF", - ); - expect(txOp.asset.code).toBe("XLM"); - - await page.getByText("Done").click(); }); -test("Send XLM payments to recent federated addresses", async ({ - page, - extensionId, -}) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - +test("Send can review formatted inputs", async ({ page, extensionId }) => { test.slow(); - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("address-tile").click(); - - await page.getByTestId("send-to-input").fill("freighter.pb*lobstr.co"); - await expect(page.getByTestId("send-to-identicon")).toBeVisible(); - await page.getByText("Continue").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); - await page.getByText("Review Send").click({ force: true }); - - await expect(page.getByText("You are sending")).toBeVisible(); - const submitAction = page.getByTestId("SubmitAction"); - - await page.waitForTimeout(300); - await submitAction.waitFor({ state: "visible" }); - await submitAction.click({ force: true }); - - await expect(page.getByText("Sent!")).toBeVisible({ - timeout: 60000, - }); - - await page.getByText("Done").click(); - await page.getByTestId("nav-link-send").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await expect(page.getByText("Send to")).toBeVisible(); - - await page.getByTestId("address-tile").click(); - - await expect(page.getByText("Recents")).toBeVisible(); - - await page.getByTestId("recent-address-button").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); - await page.getByText("Review Send").click({ force: true }); - await expect(page.getByText("You are sending")).toBeVisible(); - - await page.waitForTimeout(300); - await submitAction.waitFor({ state: "visible" }); - await submitAction.click({ force: true }); - - let accountBalancesRequestWasMade = false; - page.on("request", (request) => { - if (request.url().includes("/account-balances/")) { - accountBalancesRequestWasMade = true; - } - }); + // Override account-balances to return 0 XLM only for the muxed account address + await page.route("**/account-balances/**", async (route) => { + const url = route.request().url(); + const isMuxedAccount = url.includes( + "GCQ7EGW7VXHI4AKJAFADOIHCSK2OCVA42KUETUK5LQ3LVSEQEEKP7O7B", + ); - await expect(page.getByText("Sent!")).toBeVisible({ - timeout: 60000, + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: isMuxedAccount ? "0" : "10000.0000000", + available: isMuxedAccount ? "0" : "10000.0000000", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, + }, + }, + }, + isFunded: !isMuxedAccount, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + await route.fulfill({ json }); }); - expect(accountBalancesRequestWasMade).toBeTruthy(); -}); - -test.skip("Send XLM payment to C address", async ({ page, extensionId }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - test.slow(); await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(TEST_TOKEN_ADDRESS); - await page.getByText("Continue").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill(".001"); - await page.getByText("Review Send").click({ force: true }); - - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 60000, - }); - - const submitAction = page.getByTestId("SubmitAction"); - - await page.waitForTimeout(300); - await submitAction.waitFor({ state: "visible" }); - await submitAction.click({ force: true, timeout: 60000 }); - - let accountBalancesRequestWasMade = false; - page.on("request", (request) => { - if (request.url().includes("/account-balances/")) { - accountBalancesRequestWasMade = true; - } - }); - - await expect(page.getByText("Sent!")).toBeVisible({ - timeout: 60000, - }); - expect(accountBalancesRequestWasMade).toBeTruthy(); -}); - -test("Send XLM payment to M address", async ({ page, extensionId }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - - test.slow(); - await loginToTestAccount({ page, extensionId }); - - await page.getByTestId("nav-link-send").click({ force: true }); + await page.getByTestId("send-to-input").fill(MUXED_ACCOUNT_ADDRESS); + await expect( + page.getByText("The destination account doesn’t exist."), + ).toBeVisible(); + await page.getByText("Continue").click(); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("1000"); - await page.getByTestId("address-tile").click(); - - await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); - await page.getByText("Continue").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill(".001"); - await page.getByText("Review Send").click(); + const reviewSendButton = page.getByText("Review Send"); + await expect(reviewSendButton).toBeEnabled({ timeout: 15000 }); + await reviewSendButton.click({ force: true }); await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 60000, - }); - - const submitButton = page.getByTestId("SubmitAction"); - await submitButton.scrollIntoViewIfNeeded(); - await submitButton.click(); - - let accountBalancesRequestWasMade = false; - page.on("request", (request) => { - if (request.url().includes("/account-balances/")) { - accountBalancesRequestWasMade = true; - } - }); - - await expect(page.getByText("Sent!")).toBeVisible({ - timeout: 60000, + timeout: 200000, }); - - expect(accountBalancesRequestWasMade).toBeTruthy(); }); -test.skip("Send SAC to C address", async ({ page, extensionId }) => { +test.fixme("Send SAC to C address", async ({ page, extensionId }) => { test.slow(); await loginToTestAccount({ page, extensionId }); @@ -614,95 +454,45 @@ test.skip("Send SAC to C address", async ({ page, extensionId }) => { }); }); -test.skip("Send token payment to C address", async ({ page, extensionId }) => { +test("SendPayment persists amount and asset when navigating to choose address", async ({ + page, + extensionId, +}) => { await stubTokenDetails(page); - await stubAccountBalancesE2e(page); + await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); await stubTokenPrices(page); test.slow(); await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("100"); + await expect(page.getByTestId("send-amount-amount-input")).toHaveValue("100"); await page.getByTestId("address-tile").click(); + await expect(page.getByTestId("send-to-input")).toBeVisible(); - await page.getByTestId("send-to-input").fill(TEST_TOKEN_ADDRESS); - await page.getByText("Continue").click({ force: true }); + await page.getByTestId("BackButton").click(); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await expect(page.getByTestId("send-amount-amount-input")).toHaveValue("100"); +}); - await page.locator(".SendAmount__EditDestAsset").click(); +test("SendPayment resets amount when user selects new asset", async ({ + page, + extensionId, +}) => { + await stubTokenDetails(page); + await stubAccountBalancesWithUSDC(page); + await stubAccountHistory(page); + await stubTokenPrices(page); - await page.getByText("E2E").click({ force: true }); + test.slow(); + await loginToTestAccount({ page, extensionId }); - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill(".001"); - await page.getByText("Review Send").click({ force: true }); - - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 60000, - }); - - await expect(page.getByTestId("SubmitAction")).toBeVisible({ - timeout: 60000, - }); - await page.getByTestId(`SubmitAction`).click({ force: true, timeout: 60000 }); - - let accountBalancesRequestWasMade = false; - page.on("request", (request) => { - if (request.url().includes("/account-balances/")) { - accountBalancesRequestWasMade = true; - } - }); - - await expect(page.getByText("Sent!")).toBeVisible({ - timeout: 60000, - }); - - expect(accountBalancesRequestWasMade).toBeTruthy(); -}); - -test("SendPayment persists amount and asset when navigating to choose address", async ({ - page, - extensionId, -}) => { - await stubTokenDetails(page); - await stubAccountBalancesWithUSDC(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - - test.slow(); - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("100"); - await expect(page.getByTestId("send-amount-amount-input")).toHaveValue("100"); - - await page.getByTestId("address-tile").click(); - await expect(page.getByTestId("send-to-input")).toBeVisible(); - - await page.getByTestId("BackButton").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await expect(page.getByTestId("send-amount-amount-input")).toHaveValue("100"); -}); - -test("SendPayment resets amount when user selects new asset", async ({ - page, - extensionId, -}) => { - await stubTokenDetails(page); - await stubAccountBalancesWithUSDC(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - - test.slow(); - await loginToTestAccount({ page, extensionId }); - - await page.getByTestId("nav-link-send").click({ force: true }); + await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); await page.getByTestId("send-amount-amount-input").fill("50"); @@ -748,6 +538,8 @@ test("SendPayment resets state when navigating back to account", async ({ await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); await expect(page.getByTestId("send-amount-amount-input")).toHaveValue("0"); + // Verify XLM is selected (more reliable than checking for "0 XLM" text) + await expect(page.locator(".SendAmount__EditDestAsset")).toContainText("XLM"); }); test("Swap persists amount when navigating to choose source asset", async ({ @@ -864,6 +656,8 @@ test("Swap resets state when navigating back to account", async ({ const newAmountInput = page.locator('input[type="text"]').first(); await expect(newAmountInput).toHaveValue("0"); + // Verify XLM is selected (more reliable than checking for "0 XLM" text) + await expect(page.getByTestId("swap-src-asset-tile")).toContainText("XLM"); }); test.afterAll(async ({ page, extensionId }) => { @@ -886,901 +680,97 @@ test.afterAll(async ({ page, extensionId }) => { } }); -const MEMO_REQUIRED_ADDRESS = - "GA6SXIZIKLJHCZI2KEOBEUUOFMM4JUPPM2UTWX6STAWT25JWIEUFIMFF"; - -// Reset environment variables before each memo-related test -// This ensures IS_PLAYWRIGHT is set for memo validation bypass -test.beforeEach(async ({ page }) => { - await page.evaluate(() => { - // Ensure IS_PLAYWRIGHT is set for memo validation bypass - (window as any).IS_PLAYWRIGHT = "true"; - }); -}); - -test("Send payment shows memo required warning when destination requires memo", async ({ - page, - extensionId, -}) => { +test("Send token payment from Asset Detail", async ({ page, extensionId }) => { test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); - // Click Review Send to trigger memo validation - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - this happens after simulation completes - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - - // Wait for the review transaction content to be ready (not in loading state) - // Check that AddMemoAction is visible (validation complete) - await expect(page.getByTestId("AddMemoAction")).toBeVisible({ - timeout: 15000, - }); - await expect(page.getByText("Add Memo")).toBeVisible(); -}); - -test("Send payment allows submission after adding memo to memo-required address", async ({ - page, - extensionId, -}) => { - test.slow(); - await stubAccountBalances(page); + await stubAccountBalancesE2e(page); await stubAccountHistory(page); await stubTokenDetails(page); await stubTokenPrices(page); - await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); + await stubSimulateTokenTransfer(page); + await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); + await page.getByText("E2E").click(); + await page.getByTestId("asset-detail-send-button").click(); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("0.123"); await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); + await page + .getByTestId("send-to-input") + .fill("GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"); await page.getByText("Continue").click(); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); - - // Add memo from SendPayment page - await page.getByTestId("send-amount-btn-memo").click(); - await page.getByTestId("edit-memo-input").fill("test memo"); - await page.getByText("Save").click(); + await expect(page.getByTestId("send-amount-amount-input")).toHaveValue( + "0.123", + ); - // Verify memo was saved and review modal doesn't auto-open - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - expect(await page.getByText("You are sending").isVisible()).toBeFalsy(); + // confirm that input width stays proportional to amount length + await expect(page.getByTestId("send-amount-amount-input")).toHaveCSS( + "width", + "102px", + ); - // Click Review Send - this triggers simulation and opens review sheet const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - - // Wait for button to be enabled (simulation not in progress) before clicking await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - - // Click the button to start simulation and open review sheet await reviewSendButton.click({ force: true }); - // Wait for review sheet to open - this happens after simulation completes - // The simulation may take time, so we wait for the review sheet content - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); + await expect(page.getByText("You are sending")).toBeVisible(); - // Wait for the review transaction content to be ready (not in loading state) - // Check that either SubmitAction or AddMemoAction is visible (validation complete) - await expect( - page - .getByTestId("SubmitAction") - .or(page.getByTestId("AddMemoAction")) - .first(), - ).toBeVisible({ + await expect(page.getByTestId("SubmitAction")).toBeVisible({ timeout: 15000, }); - - // Wait for validation to complete - submit button should be enabled when done - // (memo already added, so no "Add Memo" button should appear) - await expect(page.getByTestId("SubmitAction")).toBeEnabled({ - timeout: 5000, - }); - - // Verify review modal opens and "Add Memo" button is not visible (memo already added) - await expect(page.getByTestId("AddMemoAction")).not.toBeVisible(); - await expect(page.getByTestId("review-tx-memo")).toHaveText("test memo"); + await expect(page.getByTestId("SubmitAction")).toBeEnabled(); }); -test("Send payment returns to review modal after adding memo from review flow", async ({ - page, - extensionId, -}) => { +test("Send XLM payment from Asset Detail", async ({ page, extensionId }) => { test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); - - // Click Review Send to open review modal - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - - // Wait for memo validation to complete - the "Add Memo" button appears when validation is done - await expect(page.getByTestId("AddMemoAction")).toBeVisible({ - timeout: 10000, - }); - - // Click Add Memo from review modal - await page.getByTestId("AddMemoAction").click(); - - // Fill and save memo - await expect(page.getByTestId("edit-memo-input")).toBeVisible(); - await page.getByTestId("edit-memo-input").fill("review memo"); - await page.getByText("Save").click(); - - // Verify review modal is reopened after saving memo - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - await expect(page.getByTestId("AddMemoAction")).not.toBeVisible(); - await expect(page.getByTestId("review-tx-memo")).toHaveText("review memo"); -}); -test("Send payment returns to review modal after cancelling memo editor from review flow", async ({ - page, - extensionId, -}) => { - test.slow(); - await stubAccountBalances(page); + await stubAccountBalancesE2e(page); await stubAccountHistory(page); await stubTokenDetails(page); await stubTokenPrices(page); - await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); + await stubSimulateTokenTransfer(page); + await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); + await page.getByText("XLM").click(); + await page.getByTestId("asset-detail-send-button").click(); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + await page.getByTestId("send-amount-amount-input").fill("0.01"); await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); + await page + .getByTestId("send-to-input") + .fill("GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"); await page.getByText("Continue").click(); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); + await expect(page.getByTestId("send-amount-amount-input")).toHaveValue( + "0.01", + ); - // Click Review Send to open review modal const reviewSendButton = page.getByTestId("send-amount-btn-continue"); await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); await reviewSendButton.click({ force: true }); - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - - // Wait for memo validation to complete - the "Add Memo" button appears when validation is done - await expect(page.getByTestId("AddMemoAction")).toBeVisible({ - timeout: 10000, - }); - - // Click Add Memo from review modal - await page.getByTestId("AddMemoAction").click(); - - // Cancel memo editor - await expect(page.getByTestId("edit-memo-input")).toBeVisible(); - await page.getByText("Cancel").click(); - - // Verify review modal is reopened after cancelling and "Add Memo" button is still visible - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - await expect(page.getByTestId("AddMemoAction")).toBeVisible(); -}); - -test("Send payment shows memo value directly when memo is added before review", async ({ - page, - extensionId, -}) => { - test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); - - // Add memo before going to review - await page.getByTestId("send-amount-btn-memo").click(); - await page.getByTestId("edit-memo-input").fill("pre-review memo"); - await page.getByText("Save").click(); - - // After saving memo, a simulation is triggered to regenerate XDR with the new memo - // Wait for the memo editor to close - await expect(page.getByTestId("edit-memo-input")).not.toBeVisible({ - timeout: 5000, - }); - - // Wait for any loading overlays to disappear - await page.waitForTimeout(500); - - // Wait for the simulation to complete before clicking Review Send - // Verify we're still on the send amount page - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - // Wait for the simulation to complete before clicking Review Send - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 30000 }); - - // Click the button to start simulation and open review sheet - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - this happens after simulation completes - // The simulation runs, then setIsReviewingTx(true) is called - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); + await expect(page.getByText("You are sending")).toBeVisible(); - // Wait for the review transaction content to be ready (not in loading state) - // Check that SubmitAction is visible (validation complete) await expect(page.getByTestId("SubmitAction")).toBeVisible({ timeout: 15000, }); - - // Wait for validation to complete - submit button should be enabled when done - await expect(page.getByTestId("SubmitAction")).toBeEnabled({ - timeout: 5000, - }); - - // Verify review modal opens and shows memo directly, "Add Memo" button is not visible - await expect(page.getByTestId("AddMemoAction")).not.toBeVisible(); - await expect(page.getByTestId("review-tx-memo")).toHaveText( - "pre-review memo", - ); - // Verify the "Send to" button is visible (not "Add Memo") - await expect(page.getByTestId("SubmitAction")).toBeVisible(); + await expect(page.getByTestId("SubmitAction")).toBeEnabled(); }); -test("Send payment shows Add Memo when switching from non-memo-required to memo-required address", async ({ - page, - extensionId, -}) => { - test.slow(); - const NON_MEMO_REQUIRED_ADDRESS = - "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; - - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - // First, set a non-memo-required address - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(NON_MEMO_REQUIRED_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); - - // Go to review with non-memo-required address - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - - // Wait for validation to complete - submit button should be enabled when done - await expect(page.getByTestId("SubmitAction")).toBeEnabled({ - timeout: 10000, - }); - - // Verify "Add Memo" button is not visible for non-memo-required address - await expect(page.getByTestId("AddMemoAction")).not.toBeVisible(); - - // Go back to change address - await page.getByText("Cancel").click(); - - // Change to memo-required address - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").clear(); - await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - // Make sure amount is still 1 XLM after switching addresses - await page.getByTestId("send-amount-amount-input").fill("1"); - - // Go to review again with memo-required address - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - - // Wait for memo validation to complete - the "Add Memo" button appears when validation is done - await expect(page.getByTestId("AddMemoAction")).toBeVisible({ - timeout: 10000, - }); -}); - -test("Send payment shows Add Memo after cancelling review and returning to memo-required address", async ({ - page, - extensionId, -}) => { - test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(MEMO_REQUIRED_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); - - // Go to review - should show "Add Memo" button - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - - // Wait for memo validation to complete - the "Add Memo" button appears when validation is done - await expect(page.getByTestId("AddMemoAction")).toBeVisible({ - timeout: 10000, - }); - - // Cancel review - await page.getByText("Cancel").click(); - - // Wait for review sheet to close completely - await expect(page.getByText("You are sending")).not.toBeVisible({ - timeout: 5000, - }); - - // Verify we're back on the send amount page - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - // Ensure amount is still set after cancelling - await expect(page.getByTestId("send-amount-amount-input")).toHaveValue("1"); - - // Wait a moment for UI to stabilize after modal closes - await page.waitForTimeout(300); - - // Re-query the button after cancelling (button reference might be stale) - // Wait for button to be visible and enabled - await expect(page.getByTestId("send-amount-btn-continue")).toBeVisible({ - timeout: 5000, - }); - await expect(page.getByTestId("send-amount-btn-continue")).toBeEnabled({ - timeout: 10000, - }); - - // Click the button to open review again - await page.getByTestId("send-amount-btn-continue").click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - - // Wait for memo validation to complete - the "Add Memo" button appears when validation is done - await expect(page.getByTestId("AddMemoAction")).toBeVisible({ - timeout: 10000, - }); - await expect(page.getByText("Add Memo")).toBeVisible(); -}); - -// Classic token to G address -> Normal (regression test) -test("Send classic token to G address allows memo", async ({ - page, - extensionId, -}) => { - test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - const G_ADDRESS = "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; - - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(G_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); - - // Add memo - should be enabled for classic token to G address - await page.getByTestId("send-amount-btn-memo").click(); - await expect(page.getByTestId("edit-memo-input")).toBeVisible(); - await page.getByTestId("edit-memo-input").fill("classic G memo"); - await page.getByText("Save").click(); - - // Click Review Send - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - - // Verify memo is shown in review - await expect(page.getByTestId("review-tx-memo")).toHaveText("classic G memo"); -}); - -// Classic token to M address -> Memo disabled (this is supported, but an antipattern) -test("Send classic token to M address doesn't allow memo", async ({ - page, - extensionId, -}) => { - test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("1"); - - // Add memo - should be enabled for classic token to M address - await page.getByTestId("send-amount-btn-memo").click(); - await expect(page.getByTestId("edit-memo-input")).toBeVisible(); - // Memo input should be disabled - await expect(page.getByTestId("edit-memo-input")).toBeDisabled(); -}); - -// Custom token without Soroban mux support to G -> Memo NOT allowed -test("Send custom token without Soroban mux support to G address disables memo", async ({ - page, - extensionId, -}) => { - test.slow(); - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); - // Stub contract spec before login to ensure it's ready when needed - await stubContractSpec(page, TEST_TOKEN_ADDRESS, false); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible({ - timeout: 30000, - }); - - const G_ADDRESS = "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; - - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(G_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible({ - timeout: 30000, - }); - - // Select custom token - await page.locator(".SendAmount__EditDestAsset").click(); - await page - .getByTestId(`SendRow-E2E:${TEST_TOKEN_ADDRESS}`) - .click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible({ - timeout: 30000, - }); - await page.getByTestId("send-amount-amount-input").fill(".001"); - - // Wait for contract check to complete - // The memo button should be visible and enabled (user can click it) - const memoButton = page.getByTestId("send-amount-btn-memo"); - await expect(memoButton).toBeVisible({ timeout: 10000 }); - await expect(memoButton).toBeEnabled({ timeout: 10000 }); - - // Click memo button to open EditMemo - await memoButton.click(); - - // Verify EditMemo dialog is open and memo input field is visible - await expect(page.getByTestId("edit-memo-input")).toBeVisible({ - timeout: 10000, - }); - - // Verify memo input field is disabled (not editable) - await expect(page.getByTestId("edit-memo-input")).toBeDisabled(); - - // Verify the warning message is shown explaining why memo is disabled - await expect( - page.getByText("Memo is not supported for this operation"), - ).toBeVisible({ timeout: 10000 }); - - // Verify Save button is also disabled (since memo field is disabled) - const saveButton = page.getByRole("button", { name: /save/i }); - await expect(saveButton).toBeDisabled(); - - // Close the EditMemo dialog - await page.getByText("Cancel").click(); - - // Wait for EditMemo to close - await expect(page.getByTestId("edit-memo-input")).not.toBeVisible(); - - // Click Review Send - should be enabled (transaction is allowed, just no memo) - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 15000 }); - - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - - // Verify memo row is NOT shown in review (tokens without Soroban mux support don't support memo) - // The memo row should be completely hidden, not showing "Memo None" - await expect(page.getByTestId("review-tx-memo")).not.toBeVisible(); -}); - -// Custom token without Soroban mux support to M -> Impossible/disabled -test("Send custom token without Soroban mux support to M address is disabled", async ({ - page, - extensionId, -}) => { - test.slow(); - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); - // Stub contract spec before login to ensure it's ready when needed - await stubContractSpec(page, TEST_TOKEN_ADDRESS, false); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - // Select custom token - await page.locator(".SendAmount__EditDestAsset").click(); - await page - .getByTestId(`SendRow-E2E:${TEST_TOKEN_ADDRESS}`) - .click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill(".001"); - - // Wait for contract check to complete - wait for warning banner to appear - await expect( - page.getByText( - "This token does not support muxed address (M-) as a target destination", - ), - ).toBeVisible({ timeout: 10000 }); - - // Memo button should be enabled, but memo input should be disabled - const memoButton = page.getByTestId("send-amount-btn-memo"); - await expect(memoButton).toBeEnabled(); - - // Verify Review Send button is disabled - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeDisabled(); -}); - -// Custom token with Soroban mux support to G -> Memo can be added -test("Send custom token with Soroban mux support to G address allows memo", async ({ - page, - extensionId, -}) => { - test.slow(); - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); - await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - const G_ADDRESS = "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; - - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(G_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - // Select custom token - await page.locator(".SendAmount__EditDestAsset").click(); - await page - .getByTestId(`SendRow-E2E:${TEST_TOKEN_ADDRESS}`) - .click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill(".001"); - - // Wait for contract check to complete - wait for memo button to be enabled - // (it might be disabled initially while contract check is in progress) - const memoButton = page.getByTestId("send-amount-btn-memo"); - await expect(memoButton).toBeEnabled({ timeout: 10000 }); - - // Add memo - should be enabled for custom token with Soroban mux support to G address - await memoButton.click(); - await expect(page.getByTestId("edit-memo-input")).toBeVisible({ - timeout: 10000, - }); - await expect(page.getByTestId("edit-memo-input")).toBeEnabled({ - timeout: 10000, - }); - await page.getByTestId("edit-memo-input").fill("soroban mux G memo"); - await page.getByText("Save").click(); - - // Click Review Send - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - - // Verify memo is shown in review - await expect(page.getByTestId("review-tx-memo")).toHaveText( - "soroban mux G memo", - ); -}); - -// Custom token with Soroban mux support to M -> Memo disabled (embedded) -test("Send custom token with Soroban mux support to M address disables memo", async ({ - page, - extensionId, -}) => { - test.slow(); - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); - await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); - - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - await page.getByTestId("address-tile").click(); - await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - - // Select custom token - await page.locator(".SendAmount__EditDestAsset").click(); - await page - .getByTestId(`SendRow-E2E:${TEST_TOKEN_ADDRESS}`) - .click({ force: true }); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill(".001"); - - // Wait for contract check to complete - // Since contract supports muxed (true), there should be NO warning banner - // (warning banner only shows when contractSupportsMuxed === false) - await page.waitForTimeout(2000); // Wait for contract check to complete - - // Verify NO warning banner is shown (contract supports muxed) - await expect( - page.getByText( - "This token does not support muxed address (M-) as a target destination", - ), - ).not.toBeVisible(); - - // Wait for the memo button to be enabled - const memoButton = page.getByTestId("send-amount-btn-memo"); - await expect(memoButton).toBeEnabled({ timeout: 10000 }); - - // Click memo button - memo should be disabled because destination is M address - // (memo is encoded in M address, so it's disabled) - await memoButton.click(); - await expect(page.getByTestId("edit-memo-input")).toBeVisible({ - timeout: 10000, - }); - await expect(page.getByTestId("edit-memo-input")).toBeDisabled(); - // Wait for the disabled message to appear - // The message should appear once the contract check completes - await expect( - page.getByText("Memo is disabled for this transaction"), - ).toBeVisible({ timeout: 15000 }); - await page.getByText("Cancel").click(); - - // Click Review Send - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - // Wait for review sheet to open - await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, - }); - - // Verify memo row is NOT shown in review (memo is embedded in M address for tokens with Soroban mux support) - await expect(page.getByTestId("review-tx-memo")).not.toBeVisible(); -}); - -test("Send token payment from Asset Detail", async ({ page, extensionId }) => { - test.slow(); - - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); - await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); - - await loginToTestAccount({ page, extensionId }); - await page.getByText("E2E").click(); - - await page.getByTestId("asset-detail-send-button").click(); - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("0.123"); - - await page.getByTestId("address-tile").click(); - await page - .getByTestId("send-to-input") - .fill("GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await expect(page.getByTestId("send-amount-amount-input")).toHaveValue( - "0.123", - ); - - // confirm that input width stays proportional to amount length - await expect(page.getByTestId("send-amount-amount-input")).toHaveCSS( - "width", - "102px", - ); - - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - await expect(page.getByText("You are sending")).toBeVisible(); - - await expect(page.getByTestId("SubmitAction")).toBeVisible({ - timeout: 15000, - }); - await expect(page.getByTestId("SubmitAction")).toBeEnabled(); -}); - -test("Send XLM payment from Asset Detail", async ({ page, extensionId }) => { - test.slow(); - - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); - await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); - - await loginToTestAccount({ page, extensionId }); - await page.getByText("XLM").click(); - - await page.getByTestId("asset-detail-send-button").click(); - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await page.getByTestId("send-amount-amount-input").fill("0.01"); - - await page.getByTestId("address-tile").click(); - await page - .getByTestId("send-to-input") - .fill("GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"); - await page.getByText("Continue").click(); - - await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); - await expect(page.getByTestId("send-amount-amount-input")).toHaveValue( - "0.01", - ); - - const reviewSendButton = page.getByTestId("send-amount-btn-continue"); - await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); - await reviewSendButton.click({ force: true }); - - await expect(page.getByText("You are sending")).toBeVisible(); - - await expect(page.getByTestId("SubmitAction")).toBeVisible({ - timeout: 15000, +// Reset environment variables before each memo-related test +// This ensures IS_PLAYWRIGHT is set for memo validation bypass +test.beforeEach(async ({ page }) => { + await page.evaluate(() => { + // Ensure IS_PLAYWRIGHT is set for memo validation bypass + (window as any).IS_PLAYWRIGHT = "true"; }); - await expect(page.getByTestId("SubmitAction")).toBeEnabled(); }); diff --git a/extension/e2e-tests/test-fixtures.ts b/extension/e2e-tests/test-fixtures.ts index 639450c1d5..6e2c6401d1 100644 --- a/extension/e2e-tests/test-fixtures.ts +++ b/extension/e2e-tests/test-fixtures.ts @@ -1,10 +1,24 @@ -import { test as base, chromium, BrowserContext, Page } from "@playwright/test"; +import { + test as base, + chromium, + BrowserContext, + Page, + Worker, +} from "@playwright/test"; import path from "path"; -import { STELLAR_EXPERT_ASSET_LIST_JSON } from "./helpers/stubs"; +import { + STELLAR_EXPERT_ASSET_LIST_JSON, + stubFeeStats, + stubTokenPrices, + stubTokenDetails, + stubIsSac, + stubFriendbot, +} from "./helpers/stubs"; export const test = base.extend<{ context: BrowserContext; + serviceWorker: Worker; extensionId: string; page: Page; language: string; @@ -72,10 +86,53 @@ export const test = base.extend<{ ); if (!process.env.IS_INTEGRATION_MODE) { + // Stub asset list await page.route("*/**/testnet/asset-list/top50", async (route) => { const json = STELLAR_EXPERT_ASSET_LIST_JSON; await route.fulfill({ json }); }); + + // Stub common API endpoints for reliability + await stubTokenPrices(page); + await stubTokenDetails(page); + await stubIsSac(page); + await stubFeeStats(page); + await stubFriendbot(page); + + // Stub Horizon endpoints + await page.route("**/transactions**", async (route) => { + await route.fulfill({ + json: { + _embedded: { + records: [], + }, + }, + }); + }); + + // Stub RPC health checks + await page.route("**/soroban/rpc/**", async (route) => { + const json = { + jsonrpc: "2.0", + id: "1", + result: null, + }; + await route.fulfill({ json }); + }); + + // Stub backend settings + await page.route("**/backend-settings", async (route) => { + await route.fulfill({ + json: { + isSorobanPublicEnabled: true, + isRpcHealthy: true, + userNotification: { + enabled: false, + message: "", + }, + }, + }); + }); } use(page); }, diff --git a/extension/e2e-tests/translations-pt.test.ts b/extension/e2e-tests/translations-pt.test.ts index 131388bea8..9182153705 100644 --- a/extension/e2e-tests/translations-pt.test.ts +++ b/extension/e2e-tests/translations-pt.test.ts @@ -1,10 +1,11 @@ import { test, expect } from "./test-fixtures"; import { loginToTestAccountPT } from "./helpers/login-pt"; - +import { stubAllExternalApis } from "./helpers/stubs"; test.use({ language: "pt" }); -test.beforeEach(async ({ page, extensionId }) => { +test.beforeEach(async ({ page, extensionId, context }) => { await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); }); test("Smoke test: Portuguese translations are loaded", async ({ page }) => { diff --git a/extension/package.json b/extension/package.json index 67fd516e88..5031174fcb 100644 --- a/extension/package.json +++ b/extension/package.json @@ -93,7 +93,7 @@ }, "devDependencies": { "@lavamoat/allow-scripts": "3.3.2", - "@playwright/test": "1.49.0", + "@playwright/test": "1.57.0", "@sentry/webpack-plugin": "3.3.1", "@svgr/webpack": "8.1.0", "@types/js-yaml": "4.0.9", diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 3224775e10..6e0b5ba99a 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -16,12 +16,10 @@ export default defineConfig({ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, - /* Retry on CI only */ - retries: process.env.CI ? 5 : 0, - /* Fail the build if any test fails afte retries */ + retries: 5, + /* Fail the build if any test fails after retries */ maxFailures: 1, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "list", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ @@ -30,7 +28,7 @@ export default defineConfig({ // baseURL: 'http://127.0.0.1:3000', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: "on-first-retry", + trace: "retain-on-failure", launchOptions: { env: { ...process.env, diff --git a/package.json b/package.json index 12e0eabb7f..607c8a38db 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "start:unpacked": "yarn workspace extension start:unpacked-extension", "install-if-package-changed": "git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD | grep --quiet yarn.lock && yarn setup || exit 0", "test:ci": "jest --ci", - "test:e2e": "yarn workspace extension test:e2e --workers=1", + "test:e2e": "yarn workspace extension test:e2e --workers=8", "test": "jest -o --watch", "prepare": "husky install" }, diff --git a/seed.spec.ts b/seed.spec.ts new file mode 100644 index 0000000000..683fe835a7 --- /dev/null +++ b/seed.spec.ts @@ -0,0 +1,7 @@ +import { test, expect } from "@playwright/test"; + +test.describe("Test group", () => { + test("seed", async ({ page }) => { + // generate code here. + }); +}); diff --git a/specs/README.md b/specs/README.md new file mode 100644 index 0000000000..48a788b139 --- /dev/null +++ b/specs/README.md @@ -0,0 +1,3 @@ +# Specs + +This is a directory for test plans. diff --git a/yarn.lock b/yarn.lock index f0cb5a1a8b..ab204adf3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4443,14 +4443,14 @@ __metadata: languageName: node linkType: hard -"@playwright/test@npm:1.49.0": - version: 1.49.0 - resolution: "@playwright/test@npm:1.49.0" +"@playwright/test@npm:1.57.0": + version: 1.57.0 + resolution: "@playwright/test@npm:1.57.0" dependencies: - playwright: "npm:1.49.0" + playwright: "npm:1.57.0" bin: playwright: cli.js - checksum: 10c0/2890d52ee45bd83b5501f17a77c77f12ba934d257fda4b288405c6d91f94b83c4fcbdff3c0be89c2aaeea3d13576b72ec9a70be667ff844b342044afd72a246e + checksum: 10c0/35ba4b28be72bf0a53e33dbb11c6cff848fb9a37f49e893ce63a90675b5291ec29a1ba82c8a3b043abaead129400f0589623e9ace2e6a1c8eaa409721ecc3774 languageName: node linkType: hard @@ -11323,7 +11323,7 @@ __metadata: "@lavamoat/allow-scripts": "npm:3.3.2" "@ledgerhq/hw-app-str": "npm:7.2.0" "@ledgerhq/hw-transport-webhid": "npm:6.30.6" - "@playwright/test": "npm:1.49.0" + "@playwright/test": "npm:1.57.0" "@radix-ui/react-dialog": "npm:1.1.15" "@radix-ui/react-popover": "npm:1.1.15" "@reduxjs/toolkit": "npm:2.5.0" @@ -18048,27 +18048,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.49.0": - version: 1.49.0 - resolution: "playwright-core@npm:1.49.0" +"playwright-core@npm:1.57.0": + version: 1.57.0 + resolution: "playwright-core@npm:1.57.0" bin: playwright-core: cli.js - checksum: 10c0/22c1a72fabdcc87bd1cd4d40a032d2c5b94cf94ba7484dc182048c3fa1c8ec26180b559d8cac4ca9870e8fd6bdf5ef9d9f54e7a31fd60d67d098fcffc5e4253b + checksum: 10c0/798e35d83bf48419a8c73de20bb94d68be5dde68de23f95d80a0ebe401e3b83e29e3e84aea7894d67fa6c79d2d3d40cc5bcde3e166f657ce50987aaa2421b6a9 languageName: node linkType: hard -"playwright@npm:1.49.0": - version: 1.49.0 - resolution: "playwright@npm:1.49.0" +"playwright@npm:1.57.0": + version: 1.57.0 + resolution: "playwright@npm:1.57.0" dependencies: fsevents: "npm:2.3.2" - playwright-core: "npm:1.49.0" + playwright-core: "npm:1.57.0" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10c0/e94d662747cd147d0573570fec90dadc013c1097595714036fc8934a075c5a82ab04a49111b03b1f762ea86429bdb7c94460901896901e20970b30ce817cc93f + checksum: 10c0/ab03c99a67b835bdea9059f516ad3b6e42c21025f9adaa161a4ef6bc7ca716dcba476d287140bb240d06126eb23f889a8933b8f5f1f1a56b80659d92d1358899 languageName: node linkType: hard From 0176d414b685870a4f51ff678401c8c2caadc84c Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Wed, 28 Jan 2026 22:17:57 -0500 Subject: [PATCH 02/29] restore missing tests --- extension/e2e-tests/sendCollectible.test.ts | 239 ++++++++++++++++++-- extension/playwright.config.ts | 3 +- package.json | 2 +- seed.spec.ts | 7 - 4 files changed, 229 insertions(+), 22 deletions(-) delete mode 100644 seed.spec.ts diff --git a/extension/e2e-tests/sendCollectible.test.ts b/extension/e2e-tests/sendCollectible.test.ts index 4096dfb139..87ce8c2f38 100644 --- a/extension/e2e-tests/sendCollectible.test.ts +++ b/extension/e2e-tests/sendCollectible.test.ts @@ -11,7 +11,9 @@ import { stubCollectiblesUnsuccessfulMetadata, stubFeeStats, stubAllExternalApis, + stubContractSpec, } from "./helpers/stubs"; +import { TEST_M_ADDRESS } from "./helpers/test-token"; import { test, expect } from "./test-fixtures"; test.beforeEach(async ({ page, context }) => { @@ -88,21 +90,9 @@ test("Send collectible with metadata", async ({ page, extensionId }) => { ).toHaveText("GBTY…JZOF"); }); -test("Send collectible without metadata", async ({ - page, - extensionId, - context, -}) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); +test("Send collectible without metadata", async ({ page, extensionId }) => { await stubCollectiblesUnsuccessfulMetadata(page); await stubSimulateSendCollectible(page); - await stubScanTx(page); - await stubSubmitTx(page); - await stubFeeStats(page); await loginToTestAccount({ page, extensionId }); await page.getByTestId("nav-link-send").click({ force: true }); @@ -166,3 +156,226 @@ test("Send collectible without metadata", async ({ ), ).toHaveText("GBTY…JZOF"); }); + +// Collectible without Soroban mux support to M -> Impossible/disabled +test("Send collectible to M address when contract doesn't support muxed is disabled", async ({ + page, + extensionId, +}) => { + await stubSimulateSendCollectible(page); + + // Stub contract spec with muxed support = false + await stubContractSpec( + page, + "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", + false, + ); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("send-amount-edit-dest-asset").click(); + await page.getByTestId("account-tab-collectibles").click(); + await page.getByText("Stellar Frog 1").click(); + + await expect(page.getByTestId("SelectedCollectible")).toBeVisible(); + + // Try to send to M address (muxed address) + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); + await page.getByText("Continue").click({ force: true }); + + // Wait for contract check to complete - warning banner should appear + await expect( + page.getByText( + "This token does not support muxed address (M-) as a target destination", + ), + ).toBeVisible({ timeout: 10000 }); + + // Verify Review Send button is disabled when contract doesn't support muxed + const reviewSendButton = page.getByTestId("send-collectible-btn-continue"); + await expect(reviewSendButton).toBeDisabled(); +}); + +// Collectible with Soroban mux support to M -> Memo disabled (embedded) +test("Send collectible with Soroban mux support to M address disables memo", async ({ + page, + extensionId, +}) => { + test.slow(); + await stubSimulateSendCollectible(page); + // Stub contract spec with muxed support = true + await stubContractSpec( + page, + "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", + true, + ); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("send-amount-edit-dest-asset").click(); + await page.getByTestId("account-tab-collectibles").click(); + await page.getByText("Stellar Frog 1").click(); + + await expect(page.getByTestId("SelectedCollectible")).toBeVisible(); + + // Send to M address (muxed address) + await page.getByTestId("address-tile").click(); + await page.getByTestId("send-to-input").fill(TEST_M_ADDRESS); + await page.getByText("Continue").click({ force: true }); + + // Verify NO warning banner is shown (contract supports muxed) + await expect( + page.getByText( + "This token does not support muxed address (M-) as a target destination", + ), + ).not.toBeVisible(); + + // Wait for the memo button to be enabled + const memoButton = page.getByTestId("send-amount-btn-memo"); + await expect(memoButton).toBeEnabled({ timeout: 10000 }); + + // Click memo button - memo should be disabled because destination is M address + await memoButton.click(); + await expect(page.getByTestId("edit-memo-input")).toBeVisible({ + timeout: 10000, + }); + await expect(page.getByTestId("edit-memo-input")).toBeDisabled(); + await expect( + page.getByText("Memo is disabled for this transaction"), + ).toBeVisible({ timeout: 15000 }); + await page.getByText("Cancel").click(); + + // Click Review Send + const reviewSendButton = page.getByTestId("send-collectible-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible(); + + // Verify memo row is NOT shown in review (memo is embedded in M address for collectibles with Soroban mux support) + await expect(page.getByTestId("review-tx-memo")).not.toBeVisible(); +}); + +// Collectible without Soroban mux support to G -> Memo NOT allowed +test("Send collectible without Soroban mux support to G address disables memo", async ({ + page, + extensionId, +}) => { + // Stub contract spec with muxed support = false + await stubContractSpec( + page, + "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", + false, + ); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await page.getByTestId("send-amount-edit-dest-asset").click(); + await page.getByTestId("account-tab-collectibles").click(); + await page.getByText("Stellar Frog 1").click(); + + await expect(page.getByTestId("SelectedCollectible")).toBeVisible(); + + // Send to G address (regular address, not muxed) + await page.getByTestId("address-tile").click(); + await page + .getByTestId("send-to-input") + .fill("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"); + await page.getByText("Continue").click({ force: true }); + + // Wait for the memo button + const memoButton = page.getByTestId("send-amount-btn-memo"); + await expect(memoButton).toBeEnabled({ timeout: 10000 }); + + // Click memo button - memo should be disabled because destination collectible doesn't support muxed + await memoButton.click(); + await expect(page.getByTestId("edit-memo-input")).toBeVisible({ + timeout: 10000, + }); + await expect(page.getByTestId("edit-memo-input")).toBeDisabled(); + await expect( + page.getByText("Memo is not supported for this operation"), + ).toBeVisible({ timeout: 15000 }); + await page.getByText("Cancel").click(); + + // Click Review Send + const reviewSendButton = page.getByTestId("send-collectible-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible(); + + // Verify memo row is NOT shown in review (collectibles without muxed support disable memo) + await expect(page.getByTestId("review-tx-memo")).not.toBeVisible(); +}); + +// Collectible with Soroban mux support to G -> Memo can be added +test("Send collectible with Soroban mux support to G address allows memo", async ({ + page, + extensionId, +}) => { + await stubSimulateSendCollectible(page); + // Stub contract spec with muxed support = true + await stubContractSpec( + page, + "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", + true, + ); + + await loginToTestAccount({ page, extensionId }); + await page.getByTestId("nav-link-send").click({ force: true }); + + await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); + + await page.getByTestId("send-amount-edit-dest-asset").click(); + await page.getByTestId("account-tab-collectibles").click(); + await page.getByText("Stellar Frog 1").click(); + + await expect(page.getByTestId("SelectedCollectible")).toBeVisible(); + + // Send to G address (regular address, not muxed) + await page.getByTestId("address-tile").click(); + await page + .getByTestId("send-to-input") + .fill("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"); + await page.getByText("Continue").click({ force: true }); + + // Wait for the memo button + const memoButton = page.getByTestId("send-amount-btn-memo"); + await expect(memoButton).toBeEnabled({ timeout: 10000 }); + + // Click memo button - memo SHOULD BE ENABLED because destination is G address and contract supports muxed + await memoButton.click(); + await expect(page.getByTestId("edit-memo-input")).toBeVisible({ + timeout: 10000, + }); + // Memo input should be ENABLED (not disabled) for G address with muxed support + await expect(page.getByTestId("edit-memo-input")).toBeEnabled(); + + // Enter a memo + await page.getByTestId("edit-memo-input").fill("Test memo for collectible"); + await page.getByText("Save").click(); + + // Click Review Send + const reviewSendButton = page.getByTestId("send-collectible-btn-continue"); + await expect(reviewSendButton).toBeEnabled({ timeout: 10000 }); + await reviewSendButton.click({ force: true }); + + // Wait for review sheet to open + await expect(page.getByText("You are sending")).toBeVisible(); + + // Verify memo row IS shown in review (collectibles with muxed support to G address allow memo) + await expect(page.getByTestId("review-tx-memo")).toBeVisible(); + await expect(page.getByTestId("review-tx-memo")).toContainText( + "Test memo for collectible", + ); +}); diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 6e0b5ba99a..a9afa2ec2b 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -19,7 +19,8 @@ export default defineConfig({ retries: 5, /* Fail the build if any test fails after retries */ maxFailures: 1, - + /* In integration mode, run tests sequentially to avoid conflicts */ + workers: process.env.IS_INTEGRATION_MODE ? 1 : 8, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "list", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ diff --git a/package.json b/package.json index 607c8a38db..eef3888ad4 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "start:unpacked": "yarn workspace extension start:unpacked-extension", "install-if-package-changed": "git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD | grep --quiet yarn.lock && yarn setup || exit 0", "test:ci": "jest --ci", - "test:e2e": "yarn workspace extension test:e2e --workers=8", + "test:e2e": "yarn workspace extension test:e2e", "test": "jest -o --watch", "prepare": "husky install" }, diff --git a/seed.spec.ts b/seed.spec.ts deleted file mode 100644 index 683fe835a7..0000000000 --- a/seed.spec.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { test, expect } from "@playwright/test"; - -test.describe("Test group", () => { - test("seed", async ({ page }) => { - // generate code here. - }); -}); From 96573cad5f122fcf8dbd258db160af5f1cbbaaf9 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Wed, 28 Jan 2026 22:52:26 -0500 Subject: [PATCH 03/29] remove extra stubbing --- extension/e2e-tests/addAsset.test.ts | 3 +- extension/e2e-tests/test-fixtures.ts | 59 ---------------------------- extension/playwright.config.ts | 2 +- 3 files changed, 2 insertions(+), 62 deletions(-) diff --git a/extension/e2e-tests/addAsset.test.ts b/extension/e2e-tests/addAsset.test.ts index 2c2cc75c9a..e832c18543 100644 --- a/extension/e2e-tests/addAsset.test.ts +++ b/extension/e2e-tests/addAsset.test.ts @@ -1,13 +1,12 @@ import { test, expect, expectPageToHaveScreenshot } from "./test-fixtures"; import { loginToTestAccount } from "./helpers/login"; -import { TEST_TOKEN_ADDRESS, USDC_TOKEN_ADDRESS } from "./helpers/test-token"; +import { USDC_TOKEN_ADDRESS } from "./helpers/test-token"; import { stubAccountBalances, stubAccountHistory, stubTokenDetails, stubTokenPrices, stubAllExternalApis, - stubAssetSearch, } from "./helpers/stubs"; // The page navigation after clicking 'Manage Assets' doesn't complete reliably. diff --git a/extension/e2e-tests/test-fixtures.ts b/extension/e2e-tests/test-fixtures.ts index 6e2c6401d1..655622b2fa 100644 --- a/extension/e2e-tests/test-fixtures.ts +++ b/extension/e2e-tests/test-fixtures.ts @@ -7,15 +7,6 @@ import { } from "@playwright/test"; import path from "path"; -import { - STELLAR_EXPERT_ASSET_LIST_JSON, - stubFeeStats, - stubTokenPrices, - stubTokenDetails, - stubIsSac, - stubFriendbot, -} from "./helpers/stubs"; - export const test = base.extend<{ context: BrowserContext; serviceWorker: Worker; @@ -84,56 +75,6 @@ export const test = base.extend<{ langsValue: config.langs, }, ); - - if (!process.env.IS_INTEGRATION_MODE) { - // Stub asset list - await page.route("*/**/testnet/asset-list/top50", async (route) => { - const json = STELLAR_EXPERT_ASSET_LIST_JSON; - await route.fulfill({ json }); - }); - - // Stub common API endpoints for reliability - await stubTokenPrices(page); - await stubTokenDetails(page); - await stubIsSac(page); - await stubFeeStats(page); - await stubFriendbot(page); - - // Stub Horizon endpoints - await page.route("**/transactions**", async (route) => { - await route.fulfill({ - json: { - _embedded: { - records: [], - }, - }, - }); - }); - - // Stub RPC health checks - await page.route("**/soroban/rpc/**", async (route) => { - const json = { - jsonrpc: "2.0", - id: "1", - result: null, - }; - await route.fulfill({ json }); - }); - - // Stub backend settings - await page.route("**/backend-settings", async (route) => { - await route.fulfill({ - json: { - isSorobanPublicEnabled: true, - isRpcHealthy: true, - userNotification: { - enabled: false, - message: "", - }, - }, - }); - }); - } use(page); }, }); diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index a9afa2ec2b..13a4114326 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -16,7 +16,7 @@ export default defineConfig({ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, - retries: 5, + retries: 0, /* Fail the build if any test fails after retries */ maxFailures: 1, /* In integration mode, run tests sequentially to avoid conflicts */ From e2ca4dd18c8389b790c44afbb6a28e10c5958410 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Wed, 28 Jan 2026 23:01:24 -0500 Subject: [PATCH 04/29] test context --- extension/e2e-tests/helpers/stubs.ts | 13 +++++++------ extension/e2e-tests/sendCollectible.test.ts | 8 -------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/extension/e2e-tests/helpers/stubs.ts b/extension/e2e-tests/helpers/stubs.ts index c9c07d87ae..f0afbcdc2c 100644 --- a/extension/e2e-tests/helpers/stubs.ts +++ b/extension/e2e-tests/helpers/stubs.ts @@ -2223,14 +2223,15 @@ export const stubAllExternalApis = async ( page: Page, context: BrowserContext, ) => { + console.log(context); // User notification - await stubUserNotification(context); + // await stubUserNotification(context); - // Feature flags - await stubFeatureFlags(context); + // // Feature flags + // await stubFeatureFlags(context); - // Subscription account - await stubSubscriptionAccount(context); + // // Subscription account + // await stubSubscriptionAccount(context); // Stellar Asset List await stubStellarAssetList(page); @@ -2281,7 +2282,7 @@ export const stubAllExternalApis = async ( // Blockaid scan await stubScanTx(page); - await stubScanDapp(context); + // await stubScanDapp(context); }; export const stubBackendSettings = async (page: Page) => { diff --git a/extension/e2e-tests/sendCollectible.test.ts b/extension/e2e-tests/sendCollectible.test.ts index 87ce8c2f38..b92ec51c29 100644 --- a/extension/e2e-tests/sendCollectible.test.ts +++ b/extension/e2e-tests/sendCollectible.test.ts @@ -1,15 +1,7 @@ import { loginToTestAccount } from "./helpers/login"; import { - stubAccountBalances, - stubAccountHistory, - stubScanDapp, - stubScanTx, stubSimulateSendCollectible, - stubTokenDetails, - stubTokenPrices, - stubSubmitTx, stubCollectiblesUnsuccessfulMetadata, - stubFeeStats, stubAllExternalApis, stubContractSpec, } from "./helpers/stubs"; From 54e633210ca9de9c3c8bd3d5487dce6ef6716450 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Wed, 28 Jan 2026 23:11:46 -0500 Subject: [PATCH 05/29] test context --- .github/workflows/runTests.yml | 4 ++-- extension/e2e-tests/accountHistory.test.ts | 6 +++--- extension/e2e-tests/helpers/login.ts | 8 +++++++- extension/e2e-tests/helpers/stubs.ts | 3 +-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/runTests.yml b/.github/workflows/runTests.yml index e9aad9dd51..fa83022c5f 100644 --- a/.github/workflows/runTests.yml +++ b/.github/workflows/runTests.yml @@ -61,9 +61,9 @@ jobs: - run: yarn - run: npx playwright install --with-deps chromium - run: yarn setup - - run: yarn build:freighter-api + # - run: yarn build:freighter-api - run: yarn build:extension - - run: yarn test:ci + # - run: yarn test:ci - run: ${{ github.base_ref == 'master' && 'IS_INTEGRATION_MODE=true' || '' }} yarn test:e2e diff --git a/extension/e2e-tests/accountHistory.test.ts b/extension/e2e-tests/accountHistory.test.ts index a7460d4324..21893c73d9 100644 --- a/extension/e2e-tests/accountHistory.test.ts +++ b/extension/e2e-tests/accountHistory.test.ts @@ -15,11 +15,11 @@ import { Memo, } from "stellar-sdk"; -test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); +test.beforeEach(async ({ page }) => { + await stubAllExternalApis(page); }); -test("View Account History", async ({ page, extensionId }) => { +test.only("View Account History", async ({ page, extensionId }) => { await loginToTestAccount({ page, extensionId }); await page.getByTestId("nav-link-account-history").click(); diff --git a/extension/e2e-tests/helpers/login.ts b/extension/e2e-tests/helpers/login.ts index 6e08ebe2bb..df4946910d 100644 --- a/extension/e2e-tests/helpers/login.ts +++ b/extension/e2e-tests/helpers/login.ts @@ -1,5 +1,5 @@ import StellarHDWallet from "stellar-hd-wallet"; -import { Page } from "@playwright/test"; +import { Page, BrowserContext } from "@playwright/test"; import { expect } from "../test-fixtures"; const { generateMnemonic } = StellarHDWallet; @@ -84,11 +84,17 @@ export const loginAndFund = async ({ export const loginToTestAccount = async ({ page, extensionId, + context, }: { page: Page; extensionId: string; + context?: BrowserContext; }) => { await page.goto(`chrome-extension://${extensionId}/index.html`); + // if (context) { + // const serviceWorkerPromise = context.waitForEvent("serviceworker"); + // await serviceWorkerPromise; + // } await page.getByText("I already have a wallet").click(); await page.locator("#new-password-input").fill("My-password123"); diff --git a/extension/e2e-tests/helpers/stubs.ts b/extension/e2e-tests/helpers/stubs.ts index f0afbcdc2c..e1dab70efb 100644 --- a/extension/e2e-tests/helpers/stubs.ts +++ b/extension/e2e-tests/helpers/stubs.ts @@ -2221,9 +2221,8 @@ export const stubFeeStats = async (page: Page) => { */ export const stubAllExternalApis = async ( page: Page, - context: BrowserContext, + context?: BrowserContext, ) => { - console.log(context); // User notification // await stubUserNotification(context); From bf91e14e69560eadfc62a4af4f1d36aff8b7c552 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Wed, 28 Jan 2026 23:19:21 -0500 Subject: [PATCH 06/29] allow only --- extension/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 13a4114326..ea79ef28cc 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -15,7 +15,7 @@ export default defineConfig({ /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: !!process.env.CI, + forbidOnly: false, retries: 0, /* Fail the build if any test fails after retries */ maxFailures: 1, From 320d7319e6c915f8738914fcdca2ffc740558865 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Wed, 28 Jan 2026 23:25:55 -0500 Subject: [PATCH 07/29] try moving context --- extension/e2e-tests/accountHistory.test.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/extension/e2e-tests/accountHistory.test.ts b/extension/e2e-tests/accountHistory.test.ts index 21893c73d9..e9288f0c3f 100644 --- a/extension/e2e-tests/accountHistory.test.ts +++ b/extension/e2e-tests/accountHistory.test.ts @@ -15,11 +15,9 @@ import { Memo, } from "stellar-sdk"; -test.beforeEach(async ({ page }) => { - await stubAllExternalApis(page); -}); +test.only("View Account History", async ({ page, extensionId, context }) => { + await stubAllExternalApis(page, context); -test.only("View Account History", async ({ page, extensionId }) => { await loginToTestAccount({ page, extensionId }); await page.getByTestId("nav-link-account-history").click(); From d1271975e373ce7b388df87358938fc5f1412e1e Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Wed, 28 Jan 2026 23:32:39 -0500 Subject: [PATCH 08/29] test ci --- extension/e2e-tests/helpers/login.ts | 6 ------ extension/e2e-tests/helpers/stubs.ts | 12 ++++++------ extension/playwright.config.ts | 2 +- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/extension/e2e-tests/helpers/login.ts b/extension/e2e-tests/helpers/login.ts index df4946910d..f366751b8b 100644 --- a/extension/e2e-tests/helpers/login.ts +++ b/extension/e2e-tests/helpers/login.ts @@ -84,17 +84,11 @@ export const loginAndFund = async ({ export const loginToTestAccount = async ({ page, extensionId, - context, }: { page: Page; extensionId: string; - context?: BrowserContext; }) => { await page.goto(`chrome-extension://${extensionId}/index.html`); - // if (context) { - // const serviceWorkerPromise = context.waitForEvent("serviceworker"); - // await serviceWorkerPromise; - // } await page.getByText("I already have a wallet").click(); await page.locator("#new-password-input").fill("My-password123"); diff --git a/extension/e2e-tests/helpers/stubs.ts b/extension/e2e-tests/helpers/stubs.ts index e1dab70efb..ab7c4b4403 100644 --- a/extension/e2e-tests/helpers/stubs.ts +++ b/extension/e2e-tests/helpers/stubs.ts @@ -2221,16 +2221,16 @@ export const stubFeeStats = async (page: Page) => { */ export const stubAllExternalApis = async ( page: Page, - context?: BrowserContext, + context: BrowserContext, ) => { // User notification - // await stubUserNotification(context); + await stubUserNotification(context); - // // Feature flags - // await stubFeatureFlags(context); + // Feature flags + await stubFeatureFlags(context); - // // Subscription account - // await stubSubscriptionAccount(context); + // Subscription account + await stubSubscriptionAccount(context); // Stellar Asset List await stubStellarAssetList(page); diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index ea79ef28cc..9c99512eed 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -16,7 +16,7 @@ export default defineConfig({ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: false, - retries: 0, + retries: 3, /* Fail the build if any test fails after retries */ maxFailures: 1, /* In integration mode, run tests sequentially to avoid conflicts */ From d02b9221732780fca91eb585091aeb443611ee73 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Wed, 28 Jan 2026 23:49:30 -0500 Subject: [PATCH 09/29] try moving stub inside test --- extension/e2e-tests/accountHistory.test.ts | 26 +++++- extension/e2e-tests/addAsset.test.ts | 73 +++++++++-------- extension/e2e-tests/allowList.test.ts | 5 +- extension/e2e-tests/buyWithOnramp.test.ts | 6 +- .../addAssetIntegration.test.ts | 16 ++-- .../freighterApiIntegration.test.ts | 49 +++++++++--- .../integration-tests/sendIntegration.test.ts | 41 +++++++--- extension/e2e-tests/loadAccount.test.ts | 21 +++-- extension/e2e-tests/login.test.ts | 6 +- extension/e2e-tests/memo.test.ts | 30 ++++++- extension/e2e-tests/onboarding.test.ts | 79 ++++++++++++++++--- extension/e2e-tests/sendCollectible.test.ts | 26 ++++-- extension/e2e-tests/sendPayment.test.ts | 47 +++++++++-- extension/e2e-tests/translations-pt.test.ts | 11 ++- 14 files changed, 320 insertions(+), 116 deletions(-) diff --git a/extension/e2e-tests/accountHistory.test.ts b/extension/e2e-tests/accountHistory.test.ts index e9288f0c3f..4992c926a6 100644 --- a/extension/e2e-tests/accountHistory.test.ts +++ b/extension/e2e-tests/accountHistory.test.ts @@ -15,7 +15,7 @@ import { Memo, } from "stellar-sdk"; -test.only("View Account History", async ({ page, extensionId, context }) => { +test("View Account History", async ({ page, extensionId, context }) => { await stubAllExternalApis(page, context); await loginToTestAccount({ page, extensionId }); @@ -28,7 +28,8 @@ test.only("View Account History", async ({ page, extensionId, context }) => { }); }); -test("View failed transaction", async ({ page, extensionId }) => { +test("View failed transaction", async ({ page, extensionId, context }) => { + await stubAllExternalApis(page, context); await page.route("*/**/account-history/*", async (route) => { const json = [ { @@ -74,7 +75,12 @@ test("View failed transaction", async ({ page, extensionId }) => { screenshot: "failed-transaction.png", }); }); -test("Hide create claimable balance spam", async ({ page, extensionId }) => { +test("Hide create claimable balance spam", async ({ + page, + extensionId, + context, +}) => { + await stubAllExternalApis(page, context); await page.route("*/**/account-history/*", async (route) => { const json = [ { @@ -167,7 +173,9 @@ test("Hide create claimable balance spam", async ({ page, extensionId }) => { test("History row displays muxed address extracted from XDR for payment", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); const TEST_ACCOUNT = "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"; const BASE_G_ADDRESS = @@ -267,8 +275,10 @@ test("History row displays muxed address extracted from XDR for payment", async test.skip("History row displays address extracted from XDR for createAccount", async ({ page, extensionId, + context, }) => { test.slow(); + await stubAllExternalApis(page, context); const TEST_ACCOUNT = "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"; const BASE_G_ADDRESS = @@ -348,7 +358,9 @@ test.skip("History row displays address extracted from XDR for createAccount", a test("History row displays regular G address when no muxed address in XDR", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); const TEST_ACCOUNT = "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"; const G_ADDRESS = "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; @@ -451,7 +463,9 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display single asset diff for received payment", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubTokenDetails(page); @@ -513,7 +527,9 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display both credit and debit for swap operation", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubTokenDetails(page); @@ -591,7 +607,9 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display multiple asset changes for complex transaction", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubTokenDetails(page); @@ -677,7 +695,9 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display Soroban token with 18 decimals correctly", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); const TOKEN_CONTRACT = "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC"; diff --git a/extension/e2e-tests/addAsset.test.ts b/extension/e2e-tests/addAsset.test.ts index e832c18543..754bd36c71 100644 --- a/extension/e2e-tests/addAsset.test.ts +++ b/extension/e2e-tests/addAsset.test.ts @@ -11,49 +11,48 @@ import { // The page navigation after clicking 'Manage Assets' doesn't complete reliably. // 'Your assets' text never appears even with long timeouts and waitForLoadState. -test.fixme("Adding Soroban verified token", async ({ page, extensionId }) => { - test.slow(); - await loginToTestAccount({ page, extensionId }); +test.fixme( + "Adding Soroban verified token", + async ({ page, extensionId, context }) => { + test.slow(); + await stubAllExternalApis(page, context); + await loginToTestAccount({ page, extensionId }); - await page.getByTestId("account-options-dropdown").click(); - const manageAssetsText = page.getByText("Manage Assets"); - await expect(manageAssetsText).toBeVisible(); - await manageAssetsText.click({ force: true }); - // Wait for the manage assets page to load - await page.waitForLoadState("networkidle"); - await expect(page.getByText("Your assets")).toBeVisible({ timeout: 10000 }); - await page.getByText("Add an asset").click({ force: true }); - await page.getByTestId("search-asset-input").fill(USDC_TOKEN_ADDRESS); - await expect(page.getByTestId("asset-on-list")).toHaveText("On your lists"); - await expect(page.getByTestId("ManageAssetCode")).toHaveText("USDC"); - await expect(page.getByTestId("ManageAssetRowButton")).toHaveText("Add"); - await page.getByTestId("ManageAssetRowButton").click({ force: true }); + await page.getByTestId("account-options-dropdown").click(); + const manageAssetsText = page.getByText("Manage Assets"); + await expect(manageAssetsText).toBeVisible(); + await manageAssetsText.click({ force: true }); + // Wait for the manage assets page to load + await page.waitForLoadState("networkidle"); + await expect(page.getByText("Your assets")).toBeVisible({ timeout: 10000 }); + await page.getByText("Add an asset").click({ force: true }); + await page.getByTestId("search-asset-input").fill(USDC_TOKEN_ADDRESS); + await expect(page.getByTestId("asset-on-list")).toHaveText("On your lists"); + await expect(page.getByTestId("ManageAssetCode")).toHaveText("USDC"); + await expect(page.getByTestId("ManageAssetRowButton")).toHaveText("Add"); + await page.getByTestId("ManageAssetRowButton").click({ force: true }); - await expectPageToHaveScreenshot({ - page, - screenshot: "manage-assets-verified-token.png", - }); - await page.getByTestId("ManageAssetRowButton").dispatchEvent("click"); - await expect(page.getByTestId("account-view")).toBeVisible({ - timeout: 30000, - }); + await expectPageToHaveScreenshot({ + page, + screenshot: "manage-assets-verified-token.png", + }); + await page.getByTestId("ManageAssetRowButton").dispatchEvent("click"); + await expect(page.getByTestId("account-view")).toBeVisible({ + timeout: 30000, + }); - await page.getByTestId("account-options-dropdown").click(); - await page.getByText("Manage Assets").click(); - await page.getByTestId("ManageAssetRowButton__ellipsis-USDC").click(); - await page.getByText("Remove asset").click(); + await page.getByTestId("account-options-dropdown").click(); + await page.getByText("Manage Assets").click(); + await page.getByTestId("ManageAssetRowButton__ellipsis-USDC").click(); + await page.getByText("Remove asset").click(); - await expect(page.getByTestId("account-view")).toBeVisible({ - timeout: 30000, - }); -}); + await expect(page.getByTestId("account-view")).toBeVisible({ + timeout: 30000, + }); + }, +); test("Adding token on Futurenet", async ({ page, extensionId, context }) => { await stubAllExternalApis(page, context); - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(context); - test.slow(); await loginToTestAccount({ page, extensionId }); diff --git a/extension/e2e-tests/allowList.test.ts b/extension/e2e-tests/allowList.test.ts index c2c9f10472..7493ce2be8 100644 --- a/extension/e2e-tests/allowList.test.ts +++ b/extension/e2e-tests/allowList.test.ts @@ -2,11 +2,8 @@ import { expect, test, expectPageToHaveScreenshot } from "./test-fixtures"; import { loginToTestAccount, PASSWORD } from "./helpers/login"; import { stubAllExternalApis } from "./helpers/stubs"; -test.beforeEach(async ({ page, context }) => { +test("View Allow List selector", async ({ page, extensionId, context }) => { await stubAllExternalApis(page, context); -}); - -test("View Allow List selector", async ({ page, extensionId }) => { test.slow(); await loginToTestAccount({ page, extensionId }); diff --git a/extension/e2e-tests/buyWithOnramp.test.ts b/extension/e2e-tests/buyWithOnramp.test.ts index 53973baa4f..6a0423d876 100644 --- a/extension/e2e-tests/buyWithOnramp.test.ts +++ b/extension/e2e-tests/buyWithOnramp.test.ts @@ -3,8 +3,6 @@ import { loginToTestAccount } from "./helpers/login"; import { stubAllExternalApis } from "./helpers/stubs"; test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); - // Override account-balances to return 0 XLM balance await page.route("**/account-balances/**", async (route) => { const json = { @@ -60,7 +58,9 @@ test.beforeEach(async ({ page, context }) => { test("should show add XLM page and open Coinbase", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await loginToTestAccount({ page, extensionId }); await page.getByTestId("network-selector-open").click(); @@ -86,7 +86,9 @@ test("should show add XLM page and open Coinbase", async ({ test("should show Buy with Coinbase and open Coinbase", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await loginToTestAccount({ page, extensionId }); await page.getByTestId("network-selector-open").click(); diff --git a/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts b/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts index 4c037a32af..eea938d01b 100644 --- a/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts @@ -3,15 +3,16 @@ import { loginToTestAccount } from "../helpers/login"; import { stubAllExternalApis, stubTokenDetails } from "../helpers/stubs"; import { TEST_TOKEN_ADDRESS } from "../helpers/test-token"; -test.beforeEach(async ({ page, context }) => { +test("Adding classic asset on Testnet", async ({ + page, + extensionId, + context, +}) => { + test.slow(); if (!process.env.IS_INTEGRATION_MODE) { await stubAllExternalApis(page, context); await stubTokenDetails(page); } -}); - -test("Adding classic asset on Testnet", async ({ page, extensionId }) => { - test.slow(); await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-options-dropdown").click(); @@ -76,7 +77,12 @@ const truncateString = (str: string, charCount = 4) => test("Adding and removing unverified Soroban token", async ({ page, extensionId, + context, }) => { + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + await stubTokenDetails(page); + } await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-options-dropdown").click(); diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts index 0823c6ef83..2139c4b1f9 100644 --- a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts @@ -46,13 +46,14 @@ const JSON_MSG_TO_SIGN = JSON.stringify({ const JSON_SIGNED_MSG = '\"42IH7/mvkAT+ltbEG8oEPhVBzP7hb6NU+P+WZP3j1AIMdbwuFPrzBuRFRvLjXdXl5lDmC7aL0zrZIUrfrMXHDw==\"'; -test.beforeEach(async ({ page, context }) => { +test("should sign transaction when allowed", async ({ + page, + extensionId, + context, +}) => { if (!process.env.IS_INTEGRATION_MODE) { await stubAllExternalApis(page, context); } -}); - -test("should sign transaction when allowed", async ({ page, extensionId }) => { await loginToTestAccount({ page, extensionId }); await allowDapp({ page }); @@ -222,7 +223,11 @@ test.skip("should sign transaction for a specific account when allowed", async ( test("should not sign transaction when not allowed", async ({ page, extensionId, + context, }) => { + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } await loginToTestAccount({ page, extensionId }); // open a second tab and go to docs playground @@ -345,7 +350,9 @@ test("should sign auth entry for a selected account when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -399,7 +406,9 @@ test("should sign message string when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -443,7 +452,9 @@ test("should sign message long string when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -487,7 +498,9 @@ test("should sign message json when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -541,7 +554,9 @@ test("should sign message for a specific account when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -592,7 +607,9 @@ test("should not sign message when not allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -622,7 +639,9 @@ test("should add token when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(context); + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -664,7 +683,9 @@ test("should not add token when not allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(context); + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -705,7 +726,9 @@ test("should get public key when logged out", async ({ extensionId, context, }) => { - await stubTokenDetails(page); + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); diff --git a/extension/e2e-tests/integration-tests/sendIntegration.test.ts b/extension/e2e-tests/integration-tests/sendIntegration.test.ts index 1a5a3d58c7..b2af8f16e6 100644 --- a/extension/e2e-tests/integration-tests/sendIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/sendIntegration.test.ts @@ -4,17 +4,15 @@ import { loginToTestAccount } from "../helpers/login"; import { stubAllExternalApis } from "../helpers/stubs"; import { TEST_M_ADDRESS, TEST_TOKEN_ADDRESS } from "../helpers/test-token"; -test.beforeEach(async ({ page, context }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } -}); - test("Send persists inputs and submits to network", async ({ page, extensionId, + context, }) => { test.slow(); + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } let isScanSkiped = false; if (!process.env.IS_INTEGRATION_MODE) { await page.route("**/submit-tx", async (route) => { @@ -127,8 +125,12 @@ test("Send persists inputs and submits to network", async ({ test("Send XLM payments to recent federated addresses", async ({ page, extensionId, + context, }) => { test.slow(); + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } await loginToTestAccount({ page, extensionId }); await page.getByTestId("nav-link-send").click({ force: true }); @@ -200,7 +202,14 @@ test("Send XLM payments to recent federated addresses", async ({ expect(accountBalancesRequestWasMade).toBeTruthy(); }); -test("Send XLM payment to C address", async ({ page, extensionId }) => { +test("Send XLM payment to C address", async ({ + page, + extensionId, + context, +}) => { + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } test.slow(); await loginToTestAccount({ page, extensionId }); @@ -240,7 +249,14 @@ test("Send XLM payment to C address", async ({ page, extensionId }) => { expect(accountBalancesRequestWasMade).toBeTruthy(); }); -test("Send XLM payment to M address", async ({ page, extensionId }) => { +test("Send XLM payment to M address", async ({ + page, + extensionId, + context, +}) => { + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } test.slow(); await loginToTestAccount({ page, extensionId }); @@ -282,7 +298,14 @@ test("Send XLM payment to M address", async ({ page, extensionId }) => { expect(accountBalancesRequestWasMade).toBeTruthy(); }); -test("Send token payment to C address", async ({ page, extensionId }) => { +test("Send token payment to C address", async ({ + page, + extensionId, + context, +}) => { + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } test.slow(); if (!process.env.IS_INTEGRATION_MODE) { await page.route("**/account-balances/**", async (route) => { diff --git a/extension/e2e-tests/loadAccount.test.ts b/extension/e2e-tests/loadAccount.test.ts index 77bd5a51e5..1921304a05 100644 --- a/extension/e2e-tests/loadAccount.test.ts +++ b/extension/e2e-tests/loadAccount.test.ts @@ -11,11 +11,12 @@ import { stubAllExternalApis, } from "./helpers/stubs"; -test.beforeEach(async ({ page, context }) => { +test("Load accounts on standalone network", async ({ + page, + extensionId, + context, +}) => { await stubAllExternalApis(page, context); -}); - -test("Load accounts on standalone network", async ({ page, extensionId }) => { await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Settings").click(); @@ -124,7 +125,9 @@ test.skip("Switches account and fetches correct balances while clearing cache", test("Switches network and fetches correct balances while clearing cache", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await page.route("**/account-balances/**", async (route) => { let json = {}; @@ -262,7 +265,9 @@ test("Switches network and fetches correct balances while clearing cache", async test("Account Balances should be loaded once and cached", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await loginToTestAccount({ page, extensionId }); let accountBalancesRequestWasMade = false; @@ -427,7 +432,9 @@ test.skip("Clears cache and fetches balances if it's been 2 minutes since the la test("Loads wallets data and token prices on Mainnet in batches", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); let tokenPricesCallCount = 0; page.on("request", (request) => { @@ -617,7 +624,7 @@ test("Loads wallets data and token prices on Mainnet in batches", async ({ }); test("Renames wallets", async ({ page, extensionId, context }) => { - await loginToTestAccount({ page, extensionId }); + await stubAllExternalApis(page, context); await page.getByTestId("account-view-account-name").click(); await expect(page.getByText("Wallets")).toBeVisible(); @@ -632,7 +639,9 @@ test("Renames wallets", async ({ page, extensionId, context }) => { test("Loads collectibles data with successful metadata", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubCollectibles(page, true); await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-tab-collectibles").click(); @@ -772,7 +781,9 @@ test("Loads collectibles data with successful metadata", async ({ test("Loads collectibles data with unsuccessful metadata", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubCollectiblesUnsuccessfulMetadata(page); await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-tab-collectibles").click(); diff --git a/extension/e2e-tests/login.test.ts b/extension/e2e-tests/login.test.ts index 22fa809931..f4b23c826f 100644 --- a/extension/e2e-tests/login.test.ts +++ b/extension/e2e-tests/login.test.ts @@ -2,14 +2,12 @@ import { loginToTestAccount } from "./helpers/login"; import { test, expect } from "./test-fixtures"; import { stubAllExternalApis } from "./helpers/stubs"; -test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); -}); - test("Login shows error state on bad password", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-options-dropdown").click(); diff --git a/extension/e2e-tests/memo.test.ts b/extension/e2e-tests/memo.test.ts index 513876ddd1..007f240660 100644 --- a/extension/e2e-tests/memo.test.ts +++ b/extension/e2e-tests/memo.test.ts @@ -16,15 +16,13 @@ import { const MEMO_REQUIRED_ADDRESS = "GA6SXIZIKLJHCZI2KEOBEUUOFMM4JUPPM2UTWX6STAWT25JWIEUFIMFF"; -test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); -}); - test("Send payment shows memo required warning when destination requires memo", async ({ page, extensionId, + context, }) => { test.slow(); + await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenDetails(page); @@ -64,8 +62,10 @@ test("Send payment shows memo required warning when destination requires memo", test("Send payment allows submission after adding memo to memo-required address", async ({ page, extensionId, + context, }) => { test.slow(); + await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenDetails(page); @@ -133,8 +133,10 @@ test("Send payment allows submission after adding memo to memo-required address" test("Send payment returns to review modal after adding memo from review flow", async ({ page, extensionId, + context, }) => { test.slow(); + await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenDetails(page); @@ -187,8 +189,10 @@ test("Send payment returns to review modal after adding memo from review flow", test("Send payment returns to review modal after cancelling memo editor from review flow", async ({ page, extensionId, + context, }) => { test.slow(); + await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenDetails(page); @@ -239,8 +243,10 @@ test("Send payment returns to review modal after cancelling memo editor from rev test("Send payment shows memo value directly when memo is added before review", async ({ page, extensionId, + context, }) => { test.slow(); + await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenDetails(page); @@ -313,7 +319,9 @@ test("Send payment shows memo value directly when memo is added before review", test("Send payment shows Add Memo when switching from non-memo-required to memo-required address", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); const NON_MEMO_REQUIRED_ADDRESS = "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; @@ -386,7 +394,9 @@ test("Send payment shows Add Memo when switching from non-memo-required to memo- test("Send payment shows Add Memo after cancelling review and returning to memo-required address", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); await stubAccountBalances(page); await stubAccountHistory(page); @@ -466,7 +476,9 @@ test("Send payment shows Add Memo after cancelling review and returning to memo- test("Send classic token to G address allows memo", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); await stubAccountBalances(page); await stubAccountHistory(page); @@ -511,7 +523,9 @@ test("Send classic token to G address allows memo", async ({ test("Send classic token to M address doesn't allow memo", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); await stubAccountBalances(page); await stubAccountHistory(page); @@ -541,7 +555,9 @@ test("Send classic token to M address doesn't allow memo", async ({ test("Send custom token without Soroban mux support to G address disables memo", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); await stubAccountBalancesE2e(page); await stubAccountHistory(page); @@ -631,7 +647,9 @@ test("Send custom token without Soroban mux support to G address disables memo", test("Send custom token without Soroban mux support to M address is disabled", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); await stubAccountBalancesE2e(page); await stubAccountHistory(page); @@ -681,7 +699,9 @@ test("Send custom token without Soroban mux support to M address is disabled", a test("Send custom token with Soroban mux support to G address allows memo", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); await stubAccountBalancesE2e(page); await stubAccountHistory(page); @@ -748,7 +768,9 @@ test("Send custom token with Soroban mux support to G address allows memo", asyn test("Send custom token with Soroban mux support to M address disables memo", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); await stubAccountBalancesE2e(page); await stubAccountHistory(page); diff --git a/extension/e2e-tests/onboarding.test.ts b/extension/e2e-tests/onboarding.test.ts index 6dbd9de976..00656051a7 100644 --- a/extension/e2e-tests/onboarding.test.ts +++ b/extension/e2e-tests/onboarding.test.ts @@ -2,6 +2,7 @@ import { shuffle } from "lodash"; import StellarHDWallet from "stellar-hd-wallet"; import { test, expect, expectPageToHaveScreenshot } from "./test-fixtures"; import { loginToTestAccount, PASSWORD } from "./helpers/login"; +import { stubAllExternalApis } from "./helpers/stubs"; import { startImportWalletFlow, fillMnemonicInputs, @@ -26,11 +27,9 @@ const TEST_MNEMONIC_12_WORDS = [ "face", ]; -test.beforeEach(async ({ page, extensionId }) => { +test("Welcome page loads", async ({ page, extensionId, context }) => { await page.goto(`chrome-extension://${extensionId}/index.html`); -}); - -test("Welcome page loads", async ({ page }) => { + await stubAllExternalApis(page, context); await page.locator(".Welcome__column").waitFor(); await expect(page.getByText("Freighter Wallet")).toBeVisible(); await expect(page.getByText("Create new wallet")).toBeVisible(); @@ -38,7 +37,9 @@ test("Welcome page loads", async ({ page }) => { await expectPageToHaveScreenshot({ page, screenshot: "welcome-page.png" }); }); -test("Create new wallet", async ({ page }) => { +test("Create new wallet", async ({ page, extensionId, context }) => { + await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); await page.getByText("Create new wallet").click(); await expect(page.getByText("Create a password")).toBeVisible(); @@ -90,7 +91,9 @@ test("Create new wallet", async ({ page }) => { }); }); -test("Import 12 word wallet", async ({ page }) => { +test("Import 12 word wallet", async ({ page, extensionId, context }) => { + await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); await page.getByText("I already have a wallet").click(); await expect(page.getByText("Create a Password")).toBeVisible(); @@ -126,7 +129,13 @@ test("Import 12 word wallet", async ({ page }) => { }); }); -test("Import 12 word wallet by pasting", async ({ page, context }) => { +test("Import 12 word wallet by pasting", async ({ + page, + extensionId, + context, +}) => { + await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); await context.grantPermissions(["clipboard-read", "clipboard-write"]); await page.getByText("I already have a wallet").click(); @@ -171,7 +180,9 @@ test("Import 12 word wallet by pasting", async ({ page, context }) => { }); }); -test("Import 24 word wallet", async ({ page }) => { +test("Import 24 word wallet", async ({ page, extensionId, context }) => { + await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); await page.getByText("I already have a wallet").click(); await expect(page.getByText("Create a Password")).toBeVisible(); @@ -236,7 +247,13 @@ test("Import 24 word wallet", async ({ page }) => { }); }); -test("Import 24 word wallet by pasting", async ({ page, context }) => { +test("Import 24 word wallet by pasting", async ({ + page, + extensionId, + context, +}) => { + await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); await context.grantPermissions(["clipboard-read", "clipboard-write"]); await page.getByText("I already have a wallet").click(); @@ -308,7 +325,13 @@ test("Import 24 word wallet by pasting", async ({ page, context }) => { }); }); -test("Import wallet with wrong password", async ({ page }) => { +test("Import wallet with wrong password", async ({ + page, + extensionId, + context, +}) => { + await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); await page.getByText("I already have a wallet").click(); await expect(page.getByText("Create a password")).toBeVisible(); @@ -328,7 +351,9 @@ test("Import wallet with wrong password", async ({ page }) => { ); }); -test("Incorrect mnemonic phrase", async ({ page }) => { +test("Incorrect mnemonic phrase", async ({ page, extensionId, context }) => { + await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); await page.getByText("Create new wallet").click(); await expect(page.getByText("Create a password")).toBeVisible(); @@ -375,7 +400,13 @@ test("Incorrect mnemonic phrase", async ({ page }) => { ); }); -test("Logout and create new account", async ({ page, extensionId }) => { +test("Logout and create new account", async ({ + page, + extensionId, + context, +}) => { + await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); test.slow(); await loginToTestAccount({ page, extensionId }); @@ -442,7 +473,13 @@ test("Logout and create new account", async ({ page, extensionId }) => { }); }); -test("Logout and import new account", async ({ page, extensionId }) => { +test("Logout and import new account", async ({ + page, + extensionId, + context, +}) => { + await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); test.slow(); await loginToTestAccount({ page, extensionId }); @@ -525,7 +562,10 @@ test("Logout and import new account", async ({ page, extensionId }) => { test("Overwrites account when user abandons mnemonic phrase confirmation", async ({ page, extensionId, + context, }) => { + await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); await page.getByText("Create new wallet").click(); await expect(page.getByText("Create a password")).toBeVisible(); @@ -600,7 +640,10 @@ test("Overwrites account when user abandons mnemonic phrase confirmation", async test("Overwrites account when user abandons after password creation", async ({ page, extensionId, + context, }) => { + await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); await page.getByText("Create new wallet").click(); await expect(page.getByText("Create a password")).toBeVisible(); @@ -672,9 +715,11 @@ test("Overwrites account when user abandons after password creation", async ({ test("Wrong mnemonic phrase preserves previous state (pw + ToS) and allows retry", async ({ page, extensionId, + context, }) => { test.slow(); await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); const PASSWORD_TEST = "My-password123"; await startImportWalletFlow({ page, password: PASSWORD_TEST }); @@ -700,9 +745,11 @@ test("Wrong mnemonic phrase preserves previous state (pw + ToS) and allows retry test("Wrong mnemonic phrase clears mnemonic inputs but preserves pw + ToS from previous page", async ({ page, extensionId, + context, }) => { test.slow(); await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); const PASSWORD_TEST = "SecurePass456"; await startImportWalletFlow({ page, password: PASSWORD_TEST }); @@ -727,9 +774,11 @@ test("Wrong mnemonic phrase clears mnemonic inputs but preserves pw + ToS from p test("Switch mnemonic phrase length preserves previous state (pw + ToS)", async ({ page, extensionId, + context, }) => { test.slow(); await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); const PASSWORD_TEST = "AnotherPass789"; await startImportWalletFlow({ page, password: PASSWORD_TEST }); @@ -755,9 +804,11 @@ test("Switch mnemonic phrase length preserves previous state (pw + ToS)", async test("Enter wrong mnemonic multiple times and retry preserves previous state (pw + ToS) and allows successful import", async ({ page, extensionId, + context, }) => { test.slow(); await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); const PASSWORD_TEST = "PasteTestPass123"; await startImportWalletFlow({ page, password: PASSWORD_TEST }); @@ -778,9 +829,11 @@ test("Enter wrong mnemonic multiple times and retry preserves previous state (pw test("Multiple failed attempts preserve state across retries (pw + ToS)", async ({ page, extensionId, + context, }) => { test.slow(); await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); const PASSWORD_TEST = "MultiRetryPass999"; await startImportWalletFlow({ page, password: PASSWORD_TEST }); diff --git a/extension/e2e-tests/sendCollectible.test.ts b/extension/e2e-tests/sendCollectible.test.ts index b92ec51c29..0c5590ddba 100644 --- a/extension/e2e-tests/sendCollectible.test.ts +++ b/extension/e2e-tests/sendCollectible.test.ts @@ -8,12 +8,13 @@ import { import { TEST_M_ADDRESS } from "./helpers/test-token"; import { test, expect } from "./test-fixtures"; -test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); -}); - // Review screen navigation and collectible details display issues -test("Send collectible with metadata", async ({ page, extensionId }) => { +test("Send collectible with metadata", async ({ + page, + extensionId, + context, +}) => { + await stubAllExternalApis(page, context); await stubSimulateSendCollectible(page); await loginToTestAccount({ page, extensionId }); @@ -82,7 +83,12 @@ test("Send collectible with metadata", async ({ page, extensionId }) => { ).toHaveText("GBTY…JZOF"); }); -test("Send collectible without metadata", async ({ page, extensionId }) => { +test("Send collectible without metadata", async ({ + page, + extensionId, + context, +}) => { + await stubAllExternalApis(page, context); await stubCollectiblesUnsuccessfulMetadata(page); await stubSimulateSendCollectible(page); @@ -153,7 +159,9 @@ test("Send collectible without metadata", async ({ page, extensionId }) => { test("Send collectible to M address when contract doesn't support muxed is disabled", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubSimulateSendCollectible(page); // Stub contract spec with muxed support = false @@ -195,7 +203,9 @@ test("Send collectible to M address when contract doesn't support muxed is disab test("Send collectible with Soroban mux support to M address disables memo", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); await stubSimulateSendCollectible(page); // Stub contract spec with muxed support = true @@ -259,7 +269,9 @@ test("Send collectible with Soroban mux support to M address disables memo", asy test("Send collectible without Soroban mux support to G address disables memo", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); // Stub contract spec with muxed support = false await stubContractSpec( page, @@ -314,7 +326,9 @@ test("Send collectible without Soroban mux support to G address disables memo", test("Send collectible with Soroban mux support to G address allows memo", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubSimulateSendCollectible(page); // Stub contract spec with muxed support = true await stubContractSpec( diff --git a/extension/e2e-tests/sendPayment.test.ts b/extension/e2e-tests/sendPayment.test.ts index 47c7475db3..7080012de4 100644 --- a/extension/e2e-tests/sendPayment.test.ts +++ b/extension/e2e-tests/sendPayment.test.ts @@ -15,14 +15,12 @@ import { const MUXED_ACCOUNT_ADDRESS = "MCQ7EGW7VXHI4AKJAFADOIHCSK2OCVA42KUETUK5LQ3LVSEQEEKP6AAAAAAAAAAAAFLVY"; -test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); -}); - test("Swap doesn't throw error when account is unfunded", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await login({ page, extensionId }); await page.getByTestId("nav-link-swap").click(); @@ -31,7 +29,9 @@ test("Swap doesn't throw error when account is unfunded", async ({ test("Swap shows correct balances for assets", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubAccountHistory(page); await stubTokenDetails(page); await page.route("*/**/account-balances/*", async (route) => { @@ -190,7 +190,9 @@ test("Swap shows correct balances for assets", async ({ test("Send doesn't throw error when account is unfunded", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); await login({ page, extensionId }); await page.getByTestId("nav-link-send").click({ force: true }); @@ -209,7 +211,9 @@ test("Send doesn't throw error when account is unfunded", async ({ test("Send doesn't throw error when creating muxed account", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); test.slow(); // Override account-balances to return 0 XLM only for the muxed account address @@ -282,7 +286,12 @@ test("Send doesn't throw error when creating muxed account", async ({ }); }); -test("Send can review formatted inputs", async ({ page, extensionId }) => { +test("Send can review formatted inputs", async ({ + page, + extensionId, + context, +}) => { + await stubAllExternalApis(page, context); test.slow(); // Override account-balances to return 0 XLM only for the muxed account address @@ -457,7 +466,9 @@ test.fixme("Send SAC to C address", async ({ page, extensionId }) => { test("SendPayment persists amount and asset when navigating to choose address", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -483,7 +494,9 @@ test("SendPayment persists amount and asset when navigating to choose address", test("SendPayment resets amount when user selects new asset", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -508,7 +521,9 @@ test("SendPayment resets amount when user selects new asset", async ({ test("SendPayment resets state when navigating back to account", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -545,7 +560,9 @@ test("SendPayment resets state when navigating back to account", async ({ test("Swap persists amount when navigating to choose source asset", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -573,7 +590,9 @@ test("Swap persists amount when navigating to choose source asset", async ({ test("Swap resets amount when user selects new source asset", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -599,7 +618,9 @@ test("Swap resets amount when user selects new source asset", async ({ test("Swap preserves amount when selecting destination asset", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -625,7 +646,9 @@ test("Swap preserves amount when selecting destination asset", async ({ test("Swap resets state when navigating back to account", async ({ page, extensionId, + context, }) => { + await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -680,7 +703,12 @@ test.afterAll(async ({ page, extensionId }) => { } }); -test("Send token payment from Asset Detail", async ({ page, extensionId }) => { +test("Send token payment from Asset Detail", async ({ + page, + extensionId, + context, +}) => { + await stubAllExternalApis(page, context); test.slow(); await stubAccountBalancesE2e(page); @@ -726,7 +754,12 @@ test("Send token payment from Asset Detail", async ({ page, extensionId }) => { await expect(page.getByTestId("SubmitAction")).toBeEnabled(); }); -test("Send XLM payment from Asset Detail", async ({ page, extensionId }) => { +test("Send XLM payment from Asset Detail", async ({ + page, + extensionId, + context, +}) => { + await stubAllExternalApis(page, context); test.slow(); await stubAccountBalancesE2e(page); diff --git a/extension/e2e-tests/translations-pt.test.ts b/extension/e2e-tests/translations-pt.test.ts index 9182153705..c5562cb900 100644 --- a/extension/e2e-tests/translations-pt.test.ts +++ b/extension/e2e-tests/translations-pt.test.ts @@ -3,12 +3,13 @@ import { loginToTestAccountPT } from "./helpers/login-pt"; import { stubAllExternalApis } from "./helpers/stubs"; test.use({ language: "pt" }); -test.beforeEach(async ({ page, extensionId, context }) => { +test("Smoke test: Portuguese translations are loaded", async ({ + page, + extensionId, + context, +}) => { await page.goto(`chrome-extension://${extensionId}/index.html`); await stubAllExternalApis(page, context); -}); - -test("Smoke test: Portuguese translations are loaded", async ({ page }) => { // Verify welcome page shows Portuguese text await page.locator(".Welcome__column").waitFor(); await expect(page.getByText("Carteira Freighter")).toBeVisible(); @@ -19,9 +20,11 @@ test("Smoke test: Portuguese translations are loaded", async ({ page }) => { test("Smoke test: Portuguese translations in account view", async ({ page, extensionId, + context, }) => { // Login first await page.goto(`chrome-extension://${extensionId}/index.html`); + await stubAllExternalApis(page, context); await page.getByText("Já tenho uma carteira").click(); await expect(page.getByText("Criar uma Senha")).toBeVisible(); From 7f18fc340bc2b80d5b2eb4f21d7100fa951a7355 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Wed, 28 Jan 2026 23:57:52 -0500 Subject: [PATCH 10/29] Revert "try moving stub inside test" This reverts commit 0f1dafac465450b15f40c603287c220a7c637bf0. --- extension/e2e-tests/accountHistory.test.ts | 26 +----- extension/e2e-tests/addAsset.test.ts | 73 ++++++++--------- extension/e2e-tests/allowList.test.ts | 5 +- extension/e2e-tests/buyWithOnramp.test.ts | 6 +- .../addAssetIntegration.test.ts | 16 ++-- .../freighterApiIntegration.test.ts | 49 +++--------- .../integration-tests/sendIntegration.test.ts | 41 +++------- extension/e2e-tests/loadAccount.test.ts | 21 ++--- extension/e2e-tests/login.test.ts | 6 +- extension/e2e-tests/memo.test.ts | 30 +------ extension/e2e-tests/onboarding.test.ts | 79 +++---------------- extension/e2e-tests/sendCollectible.test.ts | 26 ++---- extension/e2e-tests/sendPayment.test.ts | 47 ++--------- extension/e2e-tests/translations-pt.test.ts | 11 +-- 14 files changed, 116 insertions(+), 320 deletions(-) diff --git a/extension/e2e-tests/accountHistory.test.ts b/extension/e2e-tests/accountHistory.test.ts index 4992c926a6..e9288f0c3f 100644 --- a/extension/e2e-tests/accountHistory.test.ts +++ b/extension/e2e-tests/accountHistory.test.ts @@ -15,7 +15,7 @@ import { Memo, } from "stellar-sdk"; -test("View Account History", async ({ page, extensionId, context }) => { +test.only("View Account History", async ({ page, extensionId, context }) => { await stubAllExternalApis(page, context); await loginToTestAccount({ page, extensionId }); @@ -28,8 +28,7 @@ test("View Account History", async ({ page, extensionId, context }) => { }); }); -test("View failed transaction", async ({ page, extensionId, context }) => { - await stubAllExternalApis(page, context); +test("View failed transaction", async ({ page, extensionId }) => { await page.route("*/**/account-history/*", async (route) => { const json = [ { @@ -75,12 +74,7 @@ test("View failed transaction", async ({ page, extensionId, context }) => { screenshot: "failed-transaction.png", }); }); -test("Hide create claimable balance spam", async ({ - page, - extensionId, - context, -}) => { - await stubAllExternalApis(page, context); +test("Hide create claimable balance spam", async ({ page, extensionId }) => { await page.route("*/**/account-history/*", async (route) => { const json = [ { @@ -173,9 +167,7 @@ test("Hide create claimable balance spam", async ({ test("History row displays muxed address extracted from XDR for payment", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); const TEST_ACCOUNT = "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"; const BASE_G_ADDRESS = @@ -275,10 +267,8 @@ test("History row displays muxed address extracted from XDR for payment", async test.skip("History row displays address extracted from XDR for createAccount", async ({ page, extensionId, - context, }) => { test.slow(); - await stubAllExternalApis(page, context); const TEST_ACCOUNT = "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"; const BASE_G_ADDRESS = @@ -358,9 +348,7 @@ test.skip("History row displays address extracted from XDR for createAccount", a test("History row displays regular G address when no muxed address in XDR", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); const TEST_ACCOUNT = "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"; const G_ADDRESS = "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; @@ -463,9 +451,7 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display single asset diff for received payment", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubTokenDetails(page); @@ -527,9 +513,7 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display both credit and debit for swap operation", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubTokenDetails(page); @@ -607,9 +591,7 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display multiple asset changes for complex transaction", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubTokenDetails(page); @@ -695,9 +677,7 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display Soroban token with 18 decimals correctly", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); const TOKEN_CONTRACT = "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC"; diff --git a/extension/e2e-tests/addAsset.test.ts b/extension/e2e-tests/addAsset.test.ts index 754bd36c71..e832c18543 100644 --- a/extension/e2e-tests/addAsset.test.ts +++ b/extension/e2e-tests/addAsset.test.ts @@ -11,48 +11,49 @@ import { // The page navigation after clicking 'Manage Assets' doesn't complete reliably. // 'Your assets' text never appears even with long timeouts and waitForLoadState. -test.fixme( - "Adding Soroban verified token", - async ({ page, extensionId, context }) => { - test.slow(); - await stubAllExternalApis(page, context); - await loginToTestAccount({ page, extensionId }); +test.fixme("Adding Soroban verified token", async ({ page, extensionId }) => { + test.slow(); + await loginToTestAccount({ page, extensionId }); - await page.getByTestId("account-options-dropdown").click(); - const manageAssetsText = page.getByText("Manage Assets"); - await expect(manageAssetsText).toBeVisible(); - await manageAssetsText.click({ force: true }); - // Wait for the manage assets page to load - await page.waitForLoadState("networkidle"); - await expect(page.getByText("Your assets")).toBeVisible({ timeout: 10000 }); - await page.getByText("Add an asset").click({ force: true }); - await page.getByTestId("search-asset-input").fill(USDC_TOKEN_ADDRESS); - await expect(page.getByTestId("asset-on-list")).toHaveText("On your lists"); - await expect(page.getByTestId("ManageAssetCode")).toHaveText("USDC"); - await expect(page.getByTestId("ManageAssetRowButton")).toHaveText("Add"); - await page.getByTestId("ManageAssetRowButton").click({ force: true }); + await page.getByTestId("account-options-dropdown").click(); + const manageAssetsText = page.getByText("Manage Assets"); + await expect(manageAssetsText).toBeVisible(); + await manageAssetsText.click({ force: true }); + // Wait for the manage assets page to load + await page.waitForLoadState("networkidle"); + await expect(page.getByText("Your assets")).toBeVisible({ timeout: 10000 }); + await page.getByText("Add an asset").click({ force: true }); + await page.getByTestId("search-asset-input").fill(USDC_TOKEN_ADDRESS); + await expect(page.getByTestId("asset-on-list")).toHaveText("On your lists"); + await expect(page.getByTestId("ManageAssetCode")).toHaveText("USDC"); + await expect(page.getByTestId("ManageAssetRowButton")).toHaveText("Add"); + await page.getByTestId("ManageAssetRowButton").click({ force: true }); - await expectPageToHaveScreenshot({ - page, - screenshot: "manage-assets-verified-token.png", - }); - await page.getByTestId("ManageAssetRowButton").dispatchEvent("click"); - await expect(page.getByTestId("account-view")).toBeVisible({ - timeout: 30000, - }); + await expectPageToHaveScreenshot({ + page, + screenshot: "manage-assets-verified-token.png", + }); + await page.getByTestId("ManageAssetRowButton").dispatchEvent("click"); + await expect(page.getByTestId("account-view")).toBeVisible({ + timeout: 30000, + }); - await page.getByTestId("account-options-dropdown").click(); - await page.getByText("Manage Assets").click(); - await page.getByTestId("ManageAssetRowButton__ellipsis-USDC").click(); - await page.getByText("Remove asset").click(); + await page.getByTestId("account-options-dropdown").click(); + await page.getByText("Manage Assets").click(); + await page.getByTestId("ManageAssetRowButton__ellipsis-USDC").click(); + await page.getByText("Remove asset").click(); - await expect(page.getByTestId("account-view")).toBeVisible({ - timeout: 30000, - }); - }, -); + await expect(page.getByTestId("account-view")).toBeVisible({ + timeout: 30000, + }); +}); test("Adding token on Futurenet", async ({ page, extensionId, context }) => { await stubAllExternalApis(page, context); + await stubTokenDetails(page); + await stubAccountBalances(page); + await stubAccountHistory(page); + await stubTokenPrices(context); + test.slow(); await loginToTestAccount({ page, extensionId }); diff --git a/extension/e2e-tests/allowList.test.ts b/extension/e2e-tests/allowList.test.ts index 7493ce2be8..c2c9f10472 100644 --- a/extension/e2e-tests/allowList.test.ts +++ b/extension/e2e-tests/allowList.test.ts @@ -2,8 +2,11 @@ import { expect, test, expectPageToHaveScreenshot } from "./test-fixtures"; import { loginToTestAccount, PASSWORD } from "./helpers/login"; import { stubAllExternalApis } from "./helpers/stubs"; -test("View Allow List selector", async ({ page, extensionId, context }) => { +test.beforeEach(async ({ page, context }) => { await stubAllExternalApis(page, context); +}); + +test("View Allow List selector", async ({ page, extensionId }) => { test.slow(); await loginToTestAccount({ page, extensionId }); diff --git a/extension/e2e-tests/buyWithOnramp.test.ts b/extension/e2e-tests/buyWithOnramp.test.ts index 6a0423d876..53973baa4f 100644 --- a/extension/e2e-tests/buyWithOnramp.test.ts +++ b/extension/e2e-tests/buyWithOnramp.test.ts @@ -3,6 +3,8 @@ import { loginToTestAccount } from "./helpers/login"; import { stubAllExternalApis } from "./helpers/stubs"; test.beforeEach(async ({ page, context }) => { + await stubAllExternalApis(page, context); + // Override account-balances to return 0 XLM balance await page.route("**/account-balances/**", async (route) => { const json = { @@ -58,9 +60,7 @@ test.beforeEach(async ({ page, context }) => { test("should show add XLM page and open Coinbase", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await loginToTestAccount({ page, extensionId }); await page.getByTestId("network-selector-open").click(); @@ -86,9 +86,7 @@ test("should show add XLM page and open Coinbase", async ({ test("should show Buy with Coinbase and open Coinbase", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await loginToTestAccount({ page, extensionId }); await page.getByTestId("network-selector-open").click(); diff --git a/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts b/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts index eea938d01b..4c037a32af 100644 --- a/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts @@ -3,16 +3,15 @@ import { loginToTestAccount } from "../helpers/login"; import { stubAllExternalApis, stubTokenDetails } from "../helpers/stubs"; import { TEST_TOKEN_ADDRESS } from "../helpers/test-token"; -test("Adding classic asset on Testnet", async ({ - page, - extensionId, - context, -}) => { - test.slow(); +test.beforeEach(async ({ page, context }) => { if (!process.env.IS_INTEGRATION_MODE) { await stubAllExternalApis(page, context); await stubTokenDetails(page); } +}); + +test("Adding classic asset on Testnet", async ({ page, extensionId }) => { + test.slow(); await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-options-dropdown").click(); @@ -77,12 +76,7 @@ const truncateString = (str: string, charCount = 4) => test("Adding and removing unverified Soroban token", async ({ page, extensionId, - context, }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - await stubTokenDetails(page); - } await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-options-dropdown").click(); diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts index 2139c4b1f9..0823c6ef83 100644 --- a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts @@ -46,14 +46,13 @@ const JSON_MSG_TO_SIGN = JSON.stringify({ const JSON_SIGNED_MSG = '\"42IH7/mvkAT+ltbEG8oEPhVBzP7hb6NU+P+WZP3j1AIMdbwuFPrzBuRFRvLjXdXl5lDmC7aL0zrZIUrfrMXHDw==\"'; -test("should sign transaction when allowed", async ({ - page, - extensionId, - context, -}) => { +test.beforeEach(async ({ page, context }) => { if (!process.env.IS_INTEGRATION_MODE) { await stubAllExternalApis(page, context); } +}); + +test("should sign transaction when allowed", async ({ page, extensionId }) => { await loginToTestAccount({ page, extensionId }); await allowDapp({ page }); @@ -223,11 +222,7 @@ test.skip("should sign transaction for a specific account when allowed", async ( test("should not sign transaction when not allowed", async ({ page, extensionId, - context, }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } await loginToTestAccount({ page, extensionId }); // open a second tab and go to docs playground @@ -350,9 +345,7 @@ test("should sign auth entry for a selected account when allowed", async ({ extensionId, context, }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } + await stubTokenDetails(page); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -406,9 +399,7 @@ test("should sign message string when allowed", async ({ extensionId, context, }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } + await stubTokenDetails(page); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -452,9 +443,7 @@ test("should sign message long string when allowed", async ({ extensionId, context, }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } + await stubTokenDetails(page); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -498,9 +487,7 @@ test("should sign message json when allowed", async ({ extensionId, context, }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } + await stubTokenDetails(page); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -554,9 +541,7 @@ test("should sign message for a specific account when allowed", async ({ extensionId, context, }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } + await stubTokenDetails(page); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -607,9 +592,7 @@ test("should not sign message when not allowed", async ({ extensionId, context, }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } + await stubTokenDetails(page); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -639,9 +622,7 @@ test("should add token when allowed", async ({ extensionId, context, }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } + await stubTokenDetails(context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -683,9 +664,7 @@ test("should not add token when not allowed", async ({ extensionId, context, }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } + await stubTokenDetails(context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); @@ -726,9 +705,7 @@ test("should get public key when logged out", async ({ extensionId, context, }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } + await stubTokenDetails(page); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenPrices(page); diff --git a/extension/e2e-tests/integration-tests/sendIntegration.test.ts b/extension/e2e-tests/integration-tests/sendIntegration.test.ts index b2af8f16e6..1a5a3d58c7 100644 --- a/extension/e2e-tests/integration-tests/sendIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/sendIntegration.test.ts @@ -4,15 +4,17 @@ import { loginToTestAccount } from "../helpers/login"; import { stubAllExternalApis } from "../helpers/stubs"; import { TEST_M_ADDRESS, TEST_TOKEN_ADDRESS } from "../helpers/test-token"; +test.beforeEach(async ({ page, context }) => { + if (!process.env.IS_INTEGRATION_MODE) { + await stubAllExternalApis(page, context); + } +}); + test("Send persists inputs and submits to network", async ({ page, extensionId, - context, }) => { test.slow(); - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } let isScanSkiped = false; if (!process.env.IS_INTEGRATION_MODE) { await page.route("**/submit-tx", async (route) => { @@ -125,12 +127,8 @@ test("Send persists inputs and submits to network", async ({ test("Send XLM payments to recent federated addresses", async ({ page, extensionId, - context, }) => { test.slow(); - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } await loginToTestAccount({ page, extensionId }); await page.getByTestId("nav-link-send").click({ force: true }); @@ -202,14 +200,7 @@ test("Send XLM payments to recent federated addresses", async ({ expect(accountBalancesRequestWasMade).toBeTruthy(); }); -test("Send XLM payment to C address", async ({ - page, - extensionId, - context, -}) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } +test("Send XLM payment to C address", async ({ page, extensionId }) => { test.slow(); await loginToTestAccount({ page, extensionId }); @@ -249,14 +240,7 @@ test("Send XLM payment to C address", async ({ expect(accountBalancesRequestWasMade).toBeTruthy(); }); -test("Send XLM payment to M address", async ({ - page, - extensionId, - context, -}) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } +test("Send XLM payment to M address", async ({ page, extensionId }) => { test.slow(); await loginToTestAccount({ page, extensionId }); @@ -298,14 +282,7 @@ test("Send XLM payment to M address", async ({ expect(accountBalancesRequestWasMade).toBeTruthy(); }); -test("Send token payment to C address", async ({ - page, - extensionId, - context, -}) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } +test("Send token payment to C address", async ({ page, extensionId }) => { test.slow(); if (!process.env.IS_INTEGRATION_MODE) { await page.route("**/account-balances/**", async (route) => { diff --git a/extension/e2e-tests/loadAccount.test.ts b/extension/e2e-tests/loadAccount.test.ts index 1921304a05..77bd5a51e5 100644 --- a/extension/e2e-tests/loadAccount.test.ts +++ b/extension/e2e-tests/loadAccount.test.ts @@ -11,12 +11,11 @@ import { stubAllExternalApis, } from "./helpers/stubs"; -test("Load accounts on standalone network", async ({ - page, - extensionId, - context, -}) => { +test.beforeEach(async ({ page, context }) => { await stubAllExternalApis(page, context); +}); + +test("Load accounts on standalone network", async ({ page, extensionId }) => { await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Settings").click(); @@ -125,9 +124,7 @@ test.skip("Switches account and fetches correct balances while clearing cache", test("Switches network and fetches correct balances while clearing cache", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await page.route("**/account-balances/**", async (route) => { let json = {}; @@ -265,9 +262,7 @@ test("Switches network and fetches correct balances while clearing cache", async test("Account Balances should be loaded once and cached", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await loginToTestAccount({ page, extensionId }); let accountBalancesRequestWasMade = false; @@ -432,9 +427,7 @@ test.skip("Clears cache and fetches balances if it's been 2 minutes since the la test("Loads wallets data and token prices on Mainnet in batches", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); let tokenPricesCallCount = 0; page.on("request", (request) => { @@ -624,7 +617,7 @@ test("Loads wallets data and token prices on Mainnet in batches", async ({ }); test("Renames wallets", async ({ page, extensionId, context }) => { - await stubAllExternalApis(page, context); + await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-view-account-name").click(); await expect(page.getByText("Wallets")).toBeVisible(); @@ -639,9 +632,7 @@ test("Renames wallets", async ({ page, extensionId, context }) => { test("Loads collectibles data with successful metadata", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubCollectibles(page, true); await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-tab-collectibles").click(); @@ -781,9 +772,7 @@ test("Loads collectibles data with successful metadata", async ({ test("Loads collectibles data with unsuccessful metadata", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubCollectiblesUnsuccessfulMetadata(page); await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-tab-collectibles").click(); diff --git a/extension/e2e-tests/login.test.ts b/extension/e2e-tests/login.test.ts index f4b23c826f..22fa809931 100644 --- a/extension/e2e-tests/login.test.ts +++ b/extension/e2e-tests/login.test.ts @@ -2,12 +2,14 @@ import { loginToTestAccount } from "./helpers/login"; import { test, expect } from "./test-fixtures"; import { stubAllExternalApis } from "./helpers/stubs"; +test.beforeEach(async ({ page, context }) => { + await stubAllExternalApis(page, context); +}); + test("Login shows error state on bad password", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); await loginToTestAccount({ page, extensionId }); await page.getByTestId("account-options-dropdown").click(); diff --git a/extension/e2e-tests/memo.test.ts b/extension/e2e-tests/memo.test.ts index 007f240660..513876ddd1 100644 --- a/extension/e2e-tests/memo.test.ts +++ b/extension/e2e-tests/memo.test.ts @@ -16,13 +16,15 @@ import { const MEMO_REQUIRED_ADDRESS = "GA6SXIZIKLJHCZI2KEOBEUUOFMM4JUPPM2UTWX6STAWT25JWIEUFIMFF"; +test.beforeEach(async ({ page, context }) => { + await stubAllExternalApis(page, context); +}); + test("Send payment shows memo required warning when destination requires memo", async ({ page, extensionId, - context, }) => { test.slow(); - await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenDetails(page); @@ -62,10 +64,8 @@ test("Send payment shows memo required warning when destination requires memo", test("Send payment allows submission after adding memo to memo-required address", async ({ page, extensionId, - context, }) => { test.slow(); - await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenDetails(page); @@ -133,10 +133,8 @@ test("Send payment allows submission after adding memo to memo-required address" test("Send payment returns to review modal after adding memo from review flow", async ({ page, extensionId, - context, }) => { test.slow(); - await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenDetails(page); @@ -189,10 +187,8 @@ test("Send payment returns to review modal after adding memo from review flow", test("Send payment returns to review modal after cancelling memo editor from review flow", async ({ page, extensionId, - context, }) => { test.slow(); - await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenDetails(page); @@ -243,10 +239,8 @@ test("Send payment returns to review modal after cancelling memo editor from rev test("Send payment shows memo value directly when memo is added before review", async ({ page, extensionId, - context, }) => { test.slow(); - await stubAllExternalApis(page, context); await stubAccountBalances(page); await stubAccountHistory(page); await stubTokenDetails(page); @@ -319,9 +313,7 @@ test("Send payment shows memo value directly when memo is added before review", test("Send payment shows Add Memo when switching from non-memo-required to memo-required address", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); const NON_MEMO_REQUIRED_ADDRESS = "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; @@ -394,9 +386,7 @@ test("Send payment shows Add Memo when switching from non-memo-required to memo- test("Send payment shows Add Memo after cancelling review and returning to memo-required address", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); await stubAccountBalances(page); await stubAccountHistory(page); @@ -476,9 +466,7 @@ test("Send payment shows Add Memo after cancelling review and returning to memo- test("Send classic token to G address allows memo", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); await stubAccountBalances(page); await stubAccountHistory(page); @@ -523,9 +511,7 @@ test("Send classic token to G address allows memo", async ({ test("Send classic token to M address doesn't allow memo", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); await stubAccountBalances(page); await stubAccountHistory(page); @@ -555,9 +541,7 @@ test("Send classic token to M address doesn't allow memo", async ({ test("Send custom token without Soroban mux support to G address disables memo", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); await stubAccountBalancesE2e(page); await stubAccountHistory(page); @@ -647,9 +631,7 @@ test("Send custom token without Soroban mux support to G address disables memo", test("Send custom token without Soroban mux support to M address is disabled", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); await stubAccountBalancesE2e(page); await stubAccountHistory(page); @@ -699,9 +681,7 @@ test("Send custom token without Soroban mux support to M address is disabled", a test("Send custom token with Soroban mux support to G address allows memo", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); await stubAccountBalancesE2e(page); await stubAccountHistory(page); @@ -768,9 +748,7 @@ test("Send custom token with Soroban mux support to G address allows memo", asyn test("Send custom token with Soroban mux support to M address disables memo", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); await stubAccountBalancesE2e(page); await stubAccountHistory(page); diff --git a/extension/e2e-tests/onboarding.test.ts b/extension/e2e-tests/onboarding.test.ts index 00656051a7..6dbd9de976 100644 --- a/extension/e2e-tests/onboarding.test.ts +++ b/extension/e2e-tests/onboarding.test.ts @@ -2,7 +2,6 @@ import { shuffle } from "lodash"; import StellarHDWallet from "stellar-hd-wallet"; import { test, expect, expectPageToHaveScreenshot } from "./test-fixtures"; import { loginToTestAccount, PASSWORD } from "./helpers/login"; -import { stubAllExternalApis } from "./helpers/stubs"; import { startImportWalletFlow, fillMnemonicInputs, @@ -27,9 +26,11 @@ const TEST_MNEMONIC_12_WORDS = [ "face", ]; -test("Welcome page loads", async ({ page, extensionId, context }) => { +test.beforeEach(async ({ page, extensionId }) => { await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); +}); + +test("Welcome page loads", async ({ page }) => { await page.locator(".Welcome__column").waitFor(); await expect(page.getByText("Freighter Wallet")).toBeVisible(); await expect(page.getByText("Create new wallet")).toBeVisible(); @@ -37,9 +38,7 @@ test("Welcome page loads", async ({ page, extensionId, context }) => { await expectPageToHaveScreenshot({ page, screenshot: "welcome-page.png" }); }); -test("Create new wallet", async ({ page, extensionId, context }) => { - await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); +test("Create new wallet", async ({ page }) => { await page.getByText("Create new wallet").click(); await expect(page.getByText("Create a password")).toBeVisible(); @@ -91,9 +90,7 @@ test("Create new wallet", async ({ page, extensionId, context }) => { }); }); -test("Import 12 word wallet", async ({ page, extensionId, context }) => { - await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); +test("Import 12 word wallet", async ({ page }) => { await page.getByText("I already have a wallet").click(); await expect(page.getByText("Create a Password")).toBeVisible(); @@ -129,13 +126,7 @@ test("Import 12 word wallet", async ({ page, extensionId, context }) => { }); }); -test("Import 12 word wallet by pasting", async ({ - page, - extensionId, - context, -}) => { - await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); +test("Import 12 word wallet by pasting", async ({ page, context }) => { await context.grantPermissions(["clipboard-read", "clipboard-write"]); await page.getByText("I already have a wallet").click(); @@ -180,9 +171,7 @@ test("Import 12 word wallet by pasting", async ({ }); }); -test("Import 24 word wallet", async ({ page, extensionId, context }) => { - await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); +test("Import 24 word wallet", async ({ page }) => { await page.getByText("I already have a wallet").click(); await expect(page.getByText("Create a Password")).toBeVisible(); @@ -247,13 +236,7 @@ test("Import 24 word wallet", async ({ page, extensionId, context }) => { }); }); -test("Import 24 word wallet by pasting", async ({ - page, - extensionId, - context, -}) => { - await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); +test("Import 24 word wallet by pasting", async ({ page, context }) => { await context.grantPermissions(["clipboard-read", "clipboard-write"]); await page.getByText("I already have a wallet").click(); @@ -325,13 +308,7 @@ test("Import 24 word wallet by pasting", async ({ }); }); -test("Import wallet with wrong password", async ({ - page, - extensionId, - context, -}) => { - await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); +test("Import wallet with wrong password", async ({ page }) => { await page.getByText("I already have a wallet").click(); await expect(page.getByText("Create a password")).toBeVisible(); @@ -351,9 +328,7 @@ test("Import wallet with wrong password", async ({ ); }); -test("Incorrect mnemonic phrase", async ({ page, extensionId, context }) => { - await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); +test("Incorrect mnemonic phrase", async ({ page }) => { await page.getByText("Create new wallet").click(); await expect(page.getByText("Create a password")).toBeVisible(); @@ -400,13 +375,7 @@ test("Incorrect mnemonic phrase", async ({ page, extensionId, context }) => { ); }); -test("Logout and create new account", async ({ - page, - extensionId, - context, -}) => { - await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); +test("Logout and create new account", async ({ page, extensionId }) => { test.slow(); await loginToTestAccount({ page, extensionId }); @@ -473,13 +442,7 @@ test("Logout and create new account", async ({ }); }); -test("Logout and import new account", async ({ - page, - extensionId, - context, -}) => { - await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); +test("Logout and import new account", async ({ page, extensionId }) => { test.slow(); await loginToTestAccount({ page, extensionId }); @@ -562,10 +525,7 @@ test("Logout and import new account", async ({ test("Overwrites account when user abandons mnemonic phrase confirmation", async ({ page, extensionId, - context, }) => { - await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); await page.getByText("Create new wallet").click(); await expect(page.getByText("Create a password")).toBeVisible(); @@ -640,10 +600,7 @@ test("Overwrites account when user abandons mnemonic phrase confirmation", async test("Overwrites account when user abandons after password creation", async ({ page, extensionId, - context, }) => { - await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); await page.getByText("Create new wallet").click(); await expect(page.getByText("Create a password")).toBeVisible(); @@ -715,11 +672,9 @@ test("Overwrites account when user abandons after password creation", async ({ test("Wrong mnemonic phrase preserves previous state (pw + ToS) and allows retry", async ({ page, extensionId, - context, }) => { test.slow(); await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); const PASSWORD_TEST = "My-password123"; await startImportWalletFlow({ page, password: PASSWORD_TEST }); @@ -745,11 +700,9 @@ test("Wrong mnemonic phrase preserves previous state (pw + ToS) and allows retry test("Wrong mnemonic phrase clears mnemonic inputs but preserves pw + ToS from previous page", async ({ page, extensionId, - context, }) => { test.slow(); await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); const PASSWORD_TEST = "SecurePass456"; await startImportWalletFlow({ page, password: PASSWORD_TEST }); @@ -774,11 +727,9 @@ test("Wrong mnemonic phrase clears mnemonic inputs but preserves pw + ToS from p test("Switch mnemonic phrase length preserves previous state (pw + ToS)", async ({ page, extensionId, - context, }) => { test.slow(); await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); const PASSWORD_TEST = "AnotherPass789"; await startImportWalletFlow({ page, password: PASSWORD_TEST }); @@ -804,11 +755,9 @@ test("Switch mnemonic phrase length preserves previous state (pw + ToS)", async test("Enter wrong mnemonic multiple times and retry preserves previous state (pw + ToS) and allows successful import", async ({ page, extensionId, - context, }) => { test.slow(); await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); const PASSWORD_TEST = "PasteTestPass123"; await startImportWalletFlow({ page, password: PASSWORD_TEST }); @@ -829,11 +778,9 @@ test("Enter wrong mnemonic multiple times and retry preserves previous state (pw test("Multiple failed attempts preserve state across retries (pw + ToS)", async ({ page, extensionId, - context, }) => { test.slow(); await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); const PASSWORD_TEST = "MultiRetryPass999"; await startImportWalletFlow({ page, password: PASSWORD_TEST }); diff --git a/extension/e2e-tests/sendCollectible.test.ts b/extension/e2e-tests/sendCollectible.test.ts index 0c5590ddba..b92ec51c29 100644 --- a/extension/e2e-tests/sendCollectible.test.ts +++ b/extension/e2e-tests/sendCollectible.test.ts @@ -8,13 +8,12 @@ import { import { TEST_M_ADDRESS } from "./helpers/test-token"; import { test, expect } from "./test-fixtures"; -// Review screen navigation and collectible details display issues -test("Send collectible with metadata", async ({ - page, - extensionId, - context, -}) => { +test.beforeEach(async ({ page, context }) => { await stubAllExternalApis(page, context); +}); + +// Review screen navigation and collectible details display issues +test("Send collectible with metadata", async ({ page, extensionId }) => { await stubSimulateSendCollectible(page); await loginToTestAccount({ page, extensionId }); @@ -83,12 +82,7 @@ test("Send collectible with metadata", async ({ ).toHaveText("GBTY…JZOF"); }); -test("Send collectible without metadata", async ({ - page, - extensionId, - context, -}) => { - await stubAllExternalApis(page, context); +test("Send collectible without metadata", async ({ page, extensionId }) => { await stubCollectiblesUnsuccessfulMetadata(page); await stubSimulateSendCollectible(page); @@ -159,9 +153,7 @@ test("Send collectible without metadata", async ({ test("Send collectible to M address when contract doesn't support muxed is disabled", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubSimulateSendCollectible(page); // Stub contract spec with muxed support = false @@ -203,9 +195,7 @@ test("Send collectible to M address when contract doesn't support muxed is disab test("Send collectible with Soroban mux support to M address disables memo", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); await stubSimulateSendCollectible(page); // Stub contract spec with muxed support = true @@ -269,9 +259,7 @@ test("Send collectible with Soroban mux support to M address disables memo", asy test("Send collectible without Soroban mux support to G address disables memo", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); // Stub contract spec with muxed support = false await stubContractSpec( page, @@ -326,9 +314,7 @@ test("Send collectible without Soroban mux support to G address disables memo", test("Send collectible with Soroban mux support to G address allows memo", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubSimulateSendCollectible(page); // Stub contract spec with muxed support = true await stubContractSpec( diff --git a/extension/e2e-tests/sendPayment.test.ts b/extension/e2e-tests/sendPayment.test.ts index 7080012de4..47c7475db3 100644 --- a/extension/e2e-tests/sendPayment.test.ts +++ b/extension/e2e-tests/sendPayment.test.ts @@ -15,12 +15,14 @@ import { const MUXED_ACCOUNT_ADDRESS = "MCQ7EGW7VXHI4AKJAFADOIHCSK2OCVA42KUETUK5LQ3LVSEQEEKP6AAAAAAAAAAAAFLVY"; +test.beforeEach(async ({ page, context }) => { + await stubAllExternalApis(page, context); +}); + test("Swap doesn't throw error when account is unfunded", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await login({ page, extensionId }); await page.getByTestId("nav-link-swap").click(); @@ -29,9 +31,7 @@ test("Swap doesn't throw error when account is unfunded", async ({ test("Swap shows correct balances for assets", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubAccountHistory(page); await stubTokenDetails(page); await page.route("*/**/account-balances/*", async (route) => { @@ -190,9 +190,7 @@ test("Swap shows correct balances for assets", async ({ test("Send doesn't throw error when account is unfunded", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); await login({ page, extensionId }); await page.getByTestId("nav-link-send").click({ force: true }); @@ -211,9 +209,7 @@ test("Send doesn't throw error when account is unfunded", async ({ test("Send doesn't throw error when creating muxed account", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); test.slow(); // Override account-balances to return 0 XLM only for the muxed account address @@ -286,12 +282,7 @@ test("Send doesn't throw error when creating muxed account", async ({ }); }); -test("Send can review formatted inputs", async ({ - page, - extensionId, - context, -}) => { - await stubAllExternalApis(page, context); +test("Send can review formatted inputs", async ({ page, extensionId }) => { test.slow(); // Override account-balances to return 0 XLM only for the muxed account address @@ -466,9 +457,7 @@ test.fixme("Send SAC to C address", async ({ page, extensionId }) => { test("SendPayment persists amount and asset when navigating to choose address", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -494,9 +483,7 @@ test("SendPayment persists amount and asset when navigating to choose address", test("SendPayment resets amount when user selects new asset", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -521,9 +508,7 @@ test("SendPayment resets amount when user selects new asset", async ({ test("SendPayment resets state when navigating back to account", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -560,9 +545,7 @@ test("SendPayment resets state when navigating back to account", async ({ test("Swap persists amount when navigating to choose source asset", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -590,9 +573,7 @@ test("Swap persists amount when navigating to choose source asset", async ({ test("Swap resets amount when user selects new source asset", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -618,9 +599,7 @@ test("Swap resets amount when user selects new source asset", async ({ test("Swap preserves amount when selecting destination asset", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -646,9 +625,7 @@ test("Swap preserves amount when selecting destination asset", async ({ test("Swap resets state when navigating back to account", async ({ page, extensionId, - context, }) => { - await stubAllExternalApis(page, context); await stubTokenDetails(page); await stubAccountBalancesWithUSDC(page); await stubAccountHistory(page); @@ -703,12 +680,7 @@ test.afterAll(async ({ page, extensionId }) => { } }); -test("Send token payment from Asset Detail", async ({ - page, - extensionId, - context, -}) => { - await stubAllExternalApis(page, context); +test("Send token payment from Asset Detail", async ({ page, extensionId }) => { test.slow(); await stubAccountBalancesE2e(page); @@ -754,12 +726,7 @@ test("Send token payment from Asset Detail", async ({ await expect(page.getByTestId("SubmitAction")).toBeEnabled(); }); -test("Send XLM payment from Asset Detail", async ({ - page, - extensionId, - context, -}) => { - await stubAllExternalApis(page, context); +test("Send XLM payment from Asset Detail", async ({ page, extensionId }) => { test.slow(); await stubAccountBalancesE2e(page); diff --git a/extension/e2e-tests/translations-pt.test.ts b/extension/e2e-tests/translations-pt.test.ts index c5562cb900..9182153705 100644 --- a/extension/e2e-tests/translations-pt.test.ts +++ b/extension/e2e-tests/translations-pt.test.ts @@ -3,13 +3,12 @@ import { loginToTestAccountPT } from "./helpers/login-pt"; import { stubAllExternalApis } from "./helpers/stubs"; test.use({ language: "pt" }); -test("Smoke test: Portuguese translations are loaded", async ({ - page, - extensionId, - context, -}) => { +test.beforeEach(async ({ page, extensionId, context }) => { await page.goto(`chrome-extension://${extensionId}/index.html`); await stubAllExternalApis(page, context); +}); + +test("Smoke test: Portuguese translations are loaded", async ({ page }) => { // Verify welcome page shows Portuguese text await page.locator(".Welcome__column").waitFor(); await expect(page.getByText("Carteira Freighter")).toBeVisible(); @@ -20,11 +19,9 @@ test("Smoke test: Portuguese translations are loaded", async ({ test("Smoke test: Portuguese translations in account view", async ({ page, extensionId, - context, }) => { // Login first await page.goto(`chrome-extension://${extensionId}/index.html`); - await stubAllExternalApis(page, context); await page.getByText("Já tenho uma carteira").click(); await expect(page.getByText("Criar uma Senha")).toBeVisible(); From 83c0d95c573600f856c466d1f851e80de683a133 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 00:09:22 -0500 Subject: [PATCH 11/29] move inside login --- extension/e2e-tests/helpers/login.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/extension/e2e-tests/helpers/login.ts b/extension/e2e-tests/helpers/login.ts index f366751b8b..22647ab207 100644 --- a/extension/e2e-tests/helpers/login.ts +++ b/extension/e2e-tests/helpers/login.ts @@ -1,6 +1,7 @@ import StellarHDWallet from "stellar-hd-wallet"; import { Page, BrowserContext } from "@playwright/test"; import { expect } from "../test-fixtures"; +import { stubAllExternalApis } from "./stubs"; const { generateMnemonic } = StellarHDWallet; @@ -84,11 +85,17 @@ export const loginAndFund = async ({ export const loginToTestAccount = async ({ page, extensionId, + context, }: { page: Page; extensionId: string; + context?: BrowserContext; }) => { await page.goto(`chrome-extension://${extensionId}/index.html`); + if (context) { + // Wait for any background activity to complete + await stubAllExternalApis(page, context); + } await page.getByText("I already have a wallet").click(); await page.locator("#new-password-input").fill("My-password123"); From a60a709781489c8741c143d1e9de77ae36504400 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 12:16:41 -0500 Subject: [PATCH 12/29] try moving context inside login --- extension/e2e-tests/accountHistory.test.ts | 862 +++++++++--------- extension/e2e-tests/addAsset.test.ts | 73 +- extension/e2e-tests/addCollectible.test.ts | 185 ++-- extension/e2e-tests/allowList.test.ts | 9 +- extension/e2e-tests/buyWithOnramp.test.ts | 162 ++-- extension/e2e-tests/helpers/login.ts | 7 +- extension/e2e-tests/helpers/stubs.ts | 2 +- .../addAssetIntegration.test.ts | 28 +- .../freighterApiIntegration.test.ts | 104 +-- .../integration-tests/sendIntegration.test.ts | 212 +++-- extension/e2e-tests/loadAccount.test.ts | 460 +++++----- extension/e2e-tests/login.test.ts | 8 +- extension/e2e-tests/memo.test.ts | 98 +- extension/e2e-tests/onboarding.test.ts | 16 +- extension/e2e-tests/sendCollectible.test.ts | 59 +- extension/e2e-tests/sendPayment.test.ts | 539 ++++++----- 16 files changed, 1425 insertions(+), 1399 deletions(-) diff --git a/extension/e2e-tests/accountHistory.test.ts b/extension/e2e-tests/accountHistory.test.ts index e9288f0c3f..71f8a5d7b0 100644 --- a/extension/e2e-tests/accountHistory.test.ts +++ b/extension/e2e-tests/accountHistory.test.ts @@ -1,11 +1,7 @@ import { test, expect, expectPageToHaveScreenshot } from "./test-fixtures"; import { loginToTestAccount } from "./helpers/login"; import { TEST_M_ADDRESS } from "./helpers/test-token"; -import { - stubAccountBalances, - stubTokenDetails, - stubAllExternalApis, -} from "./helpers/stubs"; +import { stubAccountBalances, stubTokenDetails } from "./helpers/stubs"; import { TransactionBuilder, Operation, @@ -15,10 +11,8 @@ import { Memo, } from "stellar-sdk"; -test.only("View Account History", async ({ page, extensionId, context }) => { - await stubAllExternalApis(page, context); - - await loginToTestAccount({ page, extensionId }); +test("View Account History", async ({ page, extensionId, context }) => { + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-account-history").click(); @@ -28,34 +22,36 @@ test.only("View Account History", async ({ page, extensionId, context }) => { }); }); -test("View failed transaction", async ({ page, extensionId }) => { - await page.route("*/**/account-history/*", async (route) => { - const json = [ - { - amount: "0.0010000", - asset_code: "USDC", - asset_issuer: - "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - asset_type: "credit_alphanum4", - created_at: "2025-03-21T22:28:46Z", - from: "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - id: "164007621169153", - paging_token: "164007621169153", - source_account: - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - to: "GCKUVXILBNYS4FDNWCGCYSJBY2PBQ4KAW2M5CODRVJPUFM62IJFH67J2", - transaction_attr: {}, - transaction_hash: - "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5", - transaction_successful: false, - type: "payment", - type_i: 1, - }, - ]; - await route.fulfill({ json }); - }); +test("View failed transaction", async ({ page, extensionId, context }) => { + const stubOverrides = async () => { + await page.route("*/**/account-history/*", async (route) => { + const json = [ + { + amount: "0.0010000", + asset_code: "USDC", + asset_issuer: + "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + asset_type: "credit_alphanum4", + created_at: "2025-03-21T22:28:46Z", + from: "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + id: "164007621169153", + paging_token: "164007621169153", + source_account: + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + to: "GCKUVXILBNYS4FDNWCGCYSJBY2PBQ4KAW2M5CODRVJPUFM62IJFH67J2", + transaction_attr: {}, + transaction_hash: + "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5", + transaction_successful: false, + type: "payment", + type_i: 1, + }, + ]; + await route.fulfill({ json }); + }); + }; - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-account-history").click(); await expect(page.getByTestId("history-item-amount-component")).toHaveText( "Mar 21", @@ -74,90 +70,96 @@ test("View failed transaction", async ({ page, extensionId }) => { screenshot: "failed-transaction.png", }); }); -test("Hide create claimable balance spam", async ({ page, extensionId }) => { - await page.route("*/**/account-history/*", async (route) => { - const json = [ - { - amount: "0.0010000", - asset_code: "USDC", - asset_issuer: - "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - asset_type: "credit_alphanum4", - created_at: "2025-03-21T22:28:46Z", - from: "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - id: "164007621169153", - paging_token: "164007621169153", - source_account: - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - to: "GCKUVXILBNYS4FDNWCGCYSJBY2PBQ4KAW2M5CODRVJPUFM62IJFH67J2", - transaction_attr: {}, - transaction_hash: - "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5", - transaction_successful: true, - type: "payment", - type_i: 1, - }, - { - amount: "0.0010000", - asset_code: "USDC", - asset_issuer: - "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - asset_type: "credit_alphanum4", - created_at: "2025-03-21T22:28:46Z", - from: "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - id: "164007621169153", - paging_token: "164007621169153", - source_account: - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - to: "GCKUVXILBNYS4FDNWCGCYSJBY2PBQ4KAW2M5CODRVJPUFM62IJFH67J2", - transaction_attr: {}, - transaction_hash: - "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5", - transaction_successful: true, - type: "payment", - type_i: 1, - }, - { - amount: "0.0010000", - asset: "USDC", - created_at: "2025-03-19T22:28:46Z", - id: "164007621169153", - paging_token: "164007621169153", - source_account: - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - transaction_attr: { - operation_count: 100, - successful: true, +test("Hide create claimable balance spam", async ({ + page, + extensionId, + context, +}) => { + const stubOverrides = async () => { + await page.route("*/**/account-history/*", async (route) => { + const json = [ + { + amount: "0.0010000", + asset_code: "USDC", + asset_issuer: + "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + asset_type: "credit_alphanum4", + created_at: "2025-03-21T22:28:46Z", + from: "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + id: "164007621169153", + paging_token: "164007621169153", + source_account: + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + to: "GCKUVXILBNYS4FDNWCGCYSJBY2PBQ4KAW2M5CODRVJPUFM62IJFH67J2", + transaction_attr: {}, + transaction_hash: + "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5", + transaction_successful: true, + type: "payment", + type_i: 1, }, - transaction_hash: - "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5", - transaction_successful: true, - type: "create_claimable_balance", - type_i: 14, - }, - { - amount: "0.0010000", - asset: "USDC", - created_at: "2025-03-18T22:28:46Z", - id: "164007621169153", - paging_token: "164007621169153", - source_account: - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - transaction_attr: { - operation_count: 100, - successful: false, + { + amount: "0.0010000", + asset_code: "USDC", + asset_issuer: + "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + asset_type: "credit_alphanum4", + created_at: "2025-03-21T22:28:46Z", + from: "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + id: "164007621169153", + paging_token: "164007621169153", + source_account: + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + to: "GCKUVXILBNYS4FDNWCGCYSJBY2PBQ4KAW2M5CODRVJPUFM62IJFH67J2", + transaction_attr: {}, + transaction_hash: + "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5", + transaction_successful: true, + type: "payment", + type_i: 1, }, - transaction_hash: - "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5", - transaction_successful: false, - type: "create_claimable_balance", - type_i: 14, - }, - ]; - await route.fulfill({ json }); - }); + { + amount: "0.0010000", + asset: "USDC", + created_at: "2025-03-19T22:28:46Z", + id: "164007621169153", + paging_token: "164007621169153", + source_account: + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + transaction_attr: { + operation_count: 100, + successful: true, + }, + transaction_hash: + "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5", + transaction_successful: true, + type: "create_claimable_balance", + type_i: 14, + }, + { + amount: "0.0010000", + asset: "USDC", + created_at: "2025-03-18T22:28:46Z", + id: "164007621169153", + paging_token: "164007621169153", + source_account: + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + transaction_attr: { + operation_count: 100, + successful: false, + }, + transaction_hash: + "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5", + transaction_successful: false, + type: "create_claimable_balance", + type_i: 14, + }, + ]; + await route.fulfill({ json }); + }); + }; - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-account-history").click(); await expect(page.getByTestId("AppHeaderPageTitle")).toHaveText("History"); const historyItems = page.getByTestId("history-item"); @@ -167,85 +169,86 @@ test("Hide create claimable balance spam", async ({ page, extensionId }) => { test("History row displays muxed address extracted from XDR for payment", async ({ page, extensionId, + context, }) => { - const TEST_ACCOUNT = - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"; - const BASE_G_ADDRESS = - "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; - const TRANSACTION_HASH = - "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5"; - - const sourceKeypair = Keypair.fromSecret( - "SBPQUZ6G4FZNWFHKUWC5BEYWF6R52E3SEP7R3GWYSM2XTKGF5LNTWW4R", - ); - const sourceAccount = { - accountId: () => sourceKeypair.publicKey(), - sequenceNumber: () => "376114581078717", - incrementSequenceNumber: () => {}, - }; - - const tx = new TransactionBuilder(sourceAccount as any, { - fee: "100", - networkPassphrase: Networks.TESTNET, - }) - .addOperation( - Operation.payment({ - destination: TEST_M_ADDRESS, // Muxed address in XDR - asset: Asset.native(), - amount: "1.0000000", - }), - ) - .setTimeout(30) - .build(); - - const envelopeXdr = tx.toXDR(); - - // Stub account history BEFORE login to ensure it catches all requests - // (returns both base G address and muxed M address) - await page.route("**/account-history/**", async (route) => { - const json = [ - { - amount: "1.0000000", - asset_code: "XLM", - asset_type: "native", - created_at: "2025-03-21T22:28:46Z", - from: TEST_ACCOUNT, - id: "164007621169153", - paging_token: "164007621169153", - source_account: TEST_ACCOUNT, - to: BASE_G_ADDRESS, // Horizon returns base G address - to_muxed: TEST_M_ADDRESS, // And also the muxed M address - transaction_attr: { - hash: TRANSACTION_HASH, - memo: null, - fee_charged: "100", - operation_count: 1, + const stubOverrides = async () => { + const TEST_ACCOUNT = + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"; + const BASE_G_ADDRESS = + "GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"; + const TRANSACTION_HASH = + "686601028de9ddf40a1c24461a6a9c0415d60a39255c35eccad0b52ac1e700a5"; + + const sourceKeypair = Keypair.fromSecret( + "SBPQUZ6G4FZNWFHKUWC5BEYWF6R52E3SEP7R3GWYSM2XTKGF5LNTWW4R", + ); + const sourceAccount = { + accountId: () => sourceKeypair.publicKey(), + sequenceNumber: () => "376114581078717", + incrementSequenceNumber: () => {}, + }; + + const tx = new TransactionBuilder(sourceAccount as any, { + fee: "100", + networkPassphrase: Networks.TESTNET, + }) + .addOperation( + Operation.payment({ + destination: TEST_M_ADDRESS, // Muxed address in XDR + asset: Asset.native(), + amount: "1.0000000", + }), + ) + .setTimeout(30) + .build(); + + const envelopeXdr = tx.toXDR(); + // Stub account history BEFORE login to ensure it catches all requests + // (returns both base G address and muxed M address) + await page.route("**/account-history/**", async (route) => { + const json = [ + { + amount: "1.0000000", + asset_code: "XLM", + asset_type: "native", + created_at: "2025-03-21T22:28:46Z", + from: TEST_ACCOUNT, + id: "164007621169153", + paging_token: "164007621169153", + source_account: TEST_ACCOUNT, + to: BASE_G_ADDRESS, // Horizon returns base G address + to_muxed: TEST_M_ADDRESS, // And also the muxed M address + transaction_attr: { + hash: TRANSACTION_HASH, + memo: null, + fee_charged: "100", + operation_count: 1, + }, + transaction_hash: TRANSACTION_HASH, + transaction_successful: true, + type: "payment", + type_i: 1, }, - transaction_hash: TRANSACTION_HASH, - transaction_successful: true, - type: "payment", - type_i: 1, - }, - ]; - await route.fulfill({ json }); - }); + ]; + await route.fulfill({ json }); + }); - // Stub transaction XDR endpoint - await page.route("**/transactions/**", async (route) => { - const url = route.request().url(); - if (url.includes(TRANSACTION_HASH)) { - await route.fulfill({ - json: { - envelope_xdr: envelopeXdr, - }, - }); - } else { - await route.continue(); - } - }); + // Stub transaction XDR endpoint + await page.route("**/transactions/**", async (route) => { + const url = route.request().url(); + if (url.includes(TRANSACTION_HASH)) { + await route.fulfill({ + json: { + envelope_xdr: envelopeXdr, + }, + }); + } else { + await route.continue(); + } + }); + }; - await stubAccountBalances(page); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-account-history").click(); await expect(page.getByTestId("history-item").nth(0)).toBeVisible({ @@ -267,6 +270,7 @@ test("History row displays muxed address extracted from XDR for payment", async test.skip("History row displays address extracted from XDR for createAccount", async ({ page, extensionId, + context, }) => { test.slow(); const TEST_ACCOUNT = @@ -301,7 +305,7 @@ test.skip("History row displays address extracted from XDR for createAccount", a const envelopeXdr = tx.toXDR(); await stubAccountBalances(page); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.route("**/account-history/**", async (route) => { const json = [ @@ -348,6 +352,7 @@ test.skip("History row displays address extracted from XDR for createAccount", a test("History row displays regular G address when no muxed address in XDR", async ({ page, extensionId, + context, }) => { const TEST_ACCOUNT = "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY"; @@ -381,50 +386,51 @@ test("History row displays regular G address when no muxed address in XDR", asyn const envelopeXdr = tx.toXDR(); - // Stub account history - await page.route("**/account-history/**", async (route) => { - const json = [ - { - amount: "1.0000000", - asset_code: "XLM", - asset_type: "native", - created_at: "2025-03-21T22:28:46Z", - from: TEST_ACCOUNT, - id: "164007621169155", - paging_token: "164007621169155", - source_account: TEST_ACCOUNT, - to: G_ADDRESS, - transaction_attr: { - hash: TRANSACTION_HASH, - memo: "test memo", - fee_charged: "100", - operation_count: 1, + const stubOverrides = async () => { + // Stub account history + await page.route("**/account-history/**", async (route) => { + const json = [ + { + amount: "1.0000000", + asset_code: "XLM", + asset_type: "native", + created_at: "2025-03-21T22:28:46Z", + from: TEST_ACCOUNT, + id: "164007621169155", + paging_token: "164007621169155", + source_account: TEST_ACCOUNT, + to: G_ADDRESS, + transaction_attr: { + hash: TRANSACTION_HASH, + memo: "test memo", + fee_charged: "100", + operation_count: 1, + }, + transaction_hash: TRANSACTION_HASH, + transaction_successful: true, + type: "payment", + type_i: 1, }, - transaction_hash: TRANSACTION_HASH, - transaction_successful: true, - type: "payment", - type_i: 1, - }, - ]; - await route.fulfill({ json }); - }); + ]; + await route.fulfill({ json }); + }); - // Stub transaction XDR endpoint - await page.route("**/transactions/**", async (route) => { - const url = route.request().url(); - if (url.includes(TRANSACTION_HASH)) { - await route.fulfill({ - json: { - envelope_xdr: envelopeXdr, - }, - }); - } else { - await route.continue(); - } - }); + // Stub transaction XDR endpoint + await page.route("**/transactions/**", async (route) => { + const url = route.request().url(); + if (url.includes(TRANSACTION_HASH)) { + await route.fulfill({ + json: { + envelope_xdr: envelopeXdr, + }, + }); + } else { + await route.continue(); + } + }); + }; - await stubAccountBalances(page); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-account-history").click(); await expect(page.getByTestId("history-item").first()).toBeVisible({ @@ -451,46 +457,49 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display single asset diff for received payment", async ({ page, extensionId, + context, }) => { await stubAccountBalances(page); await stubTokenDetails(page); - await page.route("*/**/account-history/*", async (route) => { - const json = [ - { - amount: "100.0000000", - asset_type: "native", - created_at: "2025-03-21T22:28:46Z", - from: COUNTERPARTY, - id: "100000000001", - paging_token: "100000000001", - source_account: COUNTERPARTY, - to: TEST_ACCOUNT, - transaction_hash: - "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", - transaction_successful: true, - type: "payment", - type_i: 1, - asset_balance_changes: [ - { - asset_type: "native", - from: COUNTERPARTY, - to: TEST_ACCOUNT, - amount: "100.0000000", + const stubOverrides = async () => { + await page.route("*/**/account-history/*", async (route) => { + const json = [ + { + amount: "100.0000000", + asset_type: "native", + created_at: "2025-03-21T22:28:46Z", + from: COUNTERPARTY, + id: "100000000001", + paging_token: "100000000001", + source_account: COUNTERPARTY, + to: TEST_ACCOUNT, + transaction_hash: + "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", + transaction_successful: true, + type: "payment", + type_i: 1, + asset_balance_changes: [ + { + asset_type: "native", + from: COUNTERPARTY, + to: TEST_ACCOUNT, + amount: "100.0000000", + }, + ], + transaction_attr: { + hash: "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", + memo: null, + fee_charged: "100", + operation_count: 1, }, - ], - transaction_attr: { - hash: "abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", - memo: null, - fee_charged: "100", - operation_count: 1, }, - }, - ]; - await route.fulfill({ json }); - }); + ]; + await route.fulfill({ json }); + }); + }; - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-account-history").click(); await expect(page.getByTestId("history-item").first()).toBeVisible({ @@ -513,60 +522,63 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display both credit and debit for swap operation", async ({ page, extensionId, + context, }) => { await stubAccountBalances(page); await stubTokenDetails(page); - await page.route("*/**/account-history/*", async (route) => { - const json = [ - { - asset_type: "native", - amount: "100.0000000", - created_at: "2025-03-21T22:28:46Z", - from: COUNTERPARTY, - id: "100000000002", - paging_token: "100000000002", - source_account: TEST_ACCOUNT, - to: TEST_ACCOUNT, - transaction_hash: - "swap123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", - transaction_successful: true, - type: "path_payment_strict_receive", - type_i: 2, - source_amount: "50.0000000", - source_asset_type: "credit_alphanum4", - source_asset_code: "USDC", - source_asset_issuer: - "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - asset_balance_changes: [ - { - asset_type: "credit_alphanum4", - asset_code: "USDC", - asset_issuer: - "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - from: TEST_ACCOUNT, - to: COUNTERPARTY, - amount: "50.0000000", + const stubOverrides = async () => { + await page.route("*/**/account-history/*", async (route) => { + const json = [ + { + asset_type: "native", + amount: "100.0000000", + created_at: "2025-03-21T22:28:46Z", + from: COUNTERPARTY, + id: "100000000002", + paging_token: "100000000002", + source_account: TEST_ACCOUNT, + to: TEST_ACCOUNT, + transaction_hash: + "swap123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", + transaction_successful: true, + type: "path_payment_strict_receive", + type_i: 2, + source_amount: "50.0000000", + source_asset_type: "credit_alphanum4", + source_asset_code: "USDC", + source_asset_issuer: + "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + asset_balance_changes: [ + { + asset_type: "credit_alphanum4", + asset_code: "USDC", + asset_issuer: + "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + from: TEST_ACCOUNT, + to: COUNTERPARTY, + amount: "50.0000000", + }, + { + asset_type: "native", + from: COUNTERPARTY, + to: TEST_ACCOUNT, + amount: "100.0000000", + }, + ], + transaction_attr: { + hash: "swap123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", + memo: null, + fee_charged: "150", + operation_count: 1, }, - { - asset_type: "native", - from: COUNTERPARTY, - to: TEST_ACCOUNT, - amount: "100.0000000", - }, - ], - transaction_attr: { - hash: "swap123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", - memo: null, - fee_charged: "150", - operation_count: 1, }, - }, - ]; - await route.fulfill({ json }); - }); + ]; + await route.fulfill({ json }); + }); + }; - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-account-history").click(); await expect(page.getByTestId("history-item").first()).toBeVisible({ @@ -591,69 +603,72 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display multiple asset changes for complex transaction", async ({ page, extensionId, + context, }) => { await stubAccountBalances(page); await stubTokenDetails(page); - await page.route("*/**/account-history/*", async (route) => { - const json = [ - { - asset_type: "native", - amount: "500.0000000", - created_at: "2025-03-21T22:28:46Z", - from: COUNTERPARTY, - id: "100000000003", - paging_token: "100000000003", - source_account: TEST_ACCOUNT, - to: TEST_ACCOUNT, - transaction_hash: - "multi123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", - transaction_successful: true, - type: "path_payment_strict_receive", - type_i: 2, - source_amount: "100.0000000", - source_asset_type: "credit_alphanum4", - source_asset_code: "USDC", - source_asset_issuer: - "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - asset_balance_changes: [ - { - asset_type: "credit_alphanum4", - asset_code: "USDC", - asset_issuer: - "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", - from: TEST_ACCOUNT, - to: COUNTERPARTY, - amount: "100.0000000", + const stubOverrides = async () => { + await page.route("*/**/account-history/*", async (route) => { + const json = [ + { + asset_type: "native", + amount: "500.0000000", + created_at: "2025-03-21T22:28:46Z", + from: COUNTERPARTY, + id: "100000000003", + paging_token: "100000000003", + source_account: TEST_ACCOUNT, + to: TEST_ACCOUNT, + transaction_hash: + "multi123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", + transaction_successful: true, + type: "path_payment_strict_receive", + type_i: 2, + source_amount: "100.0000000", + source_asset_type: "credit_alphanum4", + source_asset_code: "USDC", + source_asset_issuer: + "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + asset_balance_changes: [ + { + asset_type: "credit_alphanum4", + asset_code: "USDC", + asset_issuer: + "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", + from: TEST_ACCOUNT, + to: COUNTERPARTY, + amount: "100.0000000", + }, + { + asset_type: "native", + from: COUNTERPARTY, + to: TEST_ACCOUNT, + amount: "500.0000000", + }, + { + asset_type: "credit_alphanum4", + asset_code: "AQUA", + asset_issuer: + "GBNZILSTVQZ4R7IKQDGHYGY2QXL5QOFJYQMXPKWRRM5PAV7Y4M67AQUA", + from: COUNTERPARTY, + to: TEST_ACCOUNT, + amount: "250.0000000", + }, + ], + transaction_attr: { + hash: "multi123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", + memo: null, + fee_charged: "200", + operation_count: 1, }, - { - asset_type: "native", - from: COUNTERPARTY, - to: TEST_ACCOUNT, - amount: "500.0000000", - }, - { - asset_type: "credit_alphanum4", - asset_code: "AQUA", - asset_issuer: - "GBNZILSTVQZ4R7IKQDGHYGY2QXL5QOFJYQMXPKWRRM5PAV7Y4M67AQUA", - from: COUNTERPARTY, - to: TEST_ACCOUNT, - amount: "250.0000000", - }, - ], - transaction_attr: { - hash: "multi123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", - memo: null, - fee_charged: "200", - operation_count: 1, }, - }, - ]; - await route.fulfill({ json }); - }); + ]; + await route.fulfill({ json }); + }); + }; - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-account-history").click(); await expect(page.getByTestId("history-item").first()).toBeVisible({ @@ -677,67 +692,68 @@ test.describe("Asset Diffs in Transaction History", () => { test("Display Soroban token with 18 decimals correctly", async ({ page, extensionId, + context, }) => { const TOKEN_CONTRACT = "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC"; - await stubAccountBalances(page); - - await page.route("**/token-details/**", async (route) => { - const url = route.request().url(); - if (url.includes(TOKEN_CONTRACT)) { - await route.fulfill({ - json: { - name: "High Precision Token", - decimals: 18, - symbol: "HPT", - }, - }); - } else { - await route.continue(); - } - }); + const stubOverrides = async () => { + await page.route("**/token-details/**", async (route) => { + const url = route.request().url(); + if (url.includes(TOKEN_CONTRACT)) { + await route.fulfill({ + json: { + name: "High Precision Token", + decimals: 18, + symbol: "HPT", + }, + }); + } else { + await route.continue(); + } + }); - await page.route("*/**/account-history/*", async (route) => { - const json = [ - { - amount: "1000000000000000000", - asset_type: "credit_alphanum12", - asset_code: "HPT", - asset_issuer: TOKEN_CONTRACT, - created_at: "2025-03-21T22:28:46Z", - from: COUNTERPARTY, - id: "100000000004", - paging_token: "100000000004", - source_account: COUNTERPARTY, - to: TEST_ACCOUNT, - transaction_hash: - "token123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", - transaction_successful: true, - type: "payment", - type_i: 1, - asset_balance_changes: [ - { - asset_type: "credit_alphanum12", - asset_code: "HPT", - asset_issuer: TOKEN_CONTRACT, - from: COUNTERPARTY, - to: TEST_ACCOUNT, - amount: "1000000000000000000", + await page.route("*/**/account-history/*", async (route) => { + const json = [ + { + amount: "1000000000000000000", + asset_type: "credit_alphanum12", + asset_code: "HPT", + asset_issuer: TOKEN_CONTRACT, + created_at: "2025-03-21T22:28:46Z", + from: COUNTERPARTY, + id: "100000000004", + paging_token: "100000000004", + source_account: COUNTERPARTY, + to: TEST_ACCOUNT, + transaction_hash: + "token123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", + transaction_successful: true, + type: "payment", + type_i: 1, + asset_balance_changes: [ + { + asset_type: "credit_alphanum12", + asset_code: "HPT", + asset_issuer: TOKEN_CONTRACT, + from: COUNTERPARTY, + to: TEST_ACCOUNT, + amount: "1000000000000000000", + }, + ], + transaction_attr: { + hash: "token123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", + memo: null, + fee_charged: "100", + operation_count: 1, }, - ], - transaction_attr: { - hash: "token123def456ghi789jkl012mno345pqr678stu901vwx234yz567890", - memo: null, - fee_charged: "100", - operation_count: 1, }, - }, - ]; - await route.fulfill({ json }); - }); + ]; + await route.fulfill({ json }); + }); + }; - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-account-history").click(); await expect(page.getByTestId("history-item").first()).toBeVisible({ diff --git a/extension/e2e-tests/addAsset.test.ts b/extension/e2e-tests/addAsset.test.ts index e832c18543..fcbe3f8fb3 100644 --- a/extension/e2e-tests/addAsset.test.ts +++ b/extension/e2e-tests/addAsset.test.ts @@ -11,42 +11,45 @@ import { // The page navigation after clicking 'Manage Assets' doesn't complete reliably. // 'Your assets' text never appears even with long timeouts and waitForLoadState. -test.fixme("Adding Soroban verified token", async ({ page, extensionId }) => { - test.slow(); - await loginToTestAccount({ page, extensionId }); +test.fixme( + "Adding Soroban verified token", + async ({ page, extensionId, context }) => { + test.slow(); + await loginToTestAccount({ page, extensionId, context }); - await page.getByTestId("account-options-dropdown").click(); - const manageAssetsText = page.getByText("Manage Assets"); - await expect(manageAssetsText).toBeVisible(); - await manageAssetsText.click({ force: true }); - // Wait for the manage assets page to load - await page.waitForLoadState("networkidle"); - await expect(page.getByText("Your assets")).toBeVisible({ timeout: 10000 }); - await page.getByText("Add an asset").click({ force: true }); - await page.getByTestId("search-asset-input").fill(USDC_TOKEN_ADDRESS); - await expect(page.getByTestId("asset-on-list")).toHaveText("On your lists"); - await expect(page.getByTestId("ManageAssetCode")).toHaveText("USDC"); - await expect(page.getByTestId("ManageAssetRowButton")).toHaveText("Add"); - await page.getByTestId("ManageAssetRowButton").click({ force: true }); + await page.getByTestId("account-options-dropdown").click(); + const manageAssetsText = page.getByText("Manage Assets"); + await expect(manageAssetsText).toBeVisible(); + await manageAssetsText.click({ force: true }); + // Wait for the manage assets page to load + await page.waitForLoadState("networkidle"); + await expect(page.getByText("Your assets")).toBeVisible({ timeout: 10000 }); + await page.getByText("Add an asset").click({ force: true }); + await page.getByTestId("search-asset-input").fill(USDC_TOKEN_ADDRESS); + await expect(page.getByTestId("asset-on-list")).toHaveText("On your lists"); + await expect(page.getByTestId("ManageAssetCode")).toHaveText("USDC"); + await expect(page.getByTestId("ManageAssetRowButton")).toHaveText("Add"); + await page.getByTestId("ManageAssetRowButton").click({ force: true }); - await expectPageToHaveScreenshot({ - page, - screenshot: "manage-assets-verified-token.png", - }); - await page.getByTestId("ManageAssetRowButton").dispatchEvent("click"); - await expect(page.getByTestId("account-view")).toBeVisible({ - timeout: 30000, - }); + await expectPageToHaveScreenshot({ + page, + screenshot: "manage-assets-verified-token.png", + }); + await page.getByTestId("ManageAssetRowButton").dispatchEvent("click"); + await expect(page.getByTestId("account-view")).toBeVisible({ + timeout: 30000, + }); - await page.getByTestId("account-options-dropdown").click(); - await page.getByText("Manage Assets").click(); - await page.getByTestId("ManageAssetRowButton__ellipsis-USDC").click(); - await page.getByText("Remove asset").click(); + await page.getByTestId("account-options-dropdown").click(); + await page.getByText("Manage Assets").click(); + await page.getByTestId("ManageAssetRowButton__ellipsis-USDC").click(); + await page.getByText("Remove asset").click(); - await expect(page.getByTestId("account-view")).toBeVisible({ - timeout: 30000, - }); -}); + await expect(page.getByTestId("account-view")).toBeVisible({ + timeout: 30000, + }); + }, +); test("Adding token on Futurenet", async ({ page, extensionId, context }) => { await stubAllExternalApis(page, context); await stubTokenDetails(page); @@ -55,7 +58,7 @@ test("Adding token on Futurenet", async ({ page, extensionId, context }) => { await stubTokenPrices(context); test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Settings").click(); @@ -83,7 +86,7 @@ test("Adding token on Futurenet", async ({ page, extensionId, context }) => { await expect(page.getByTestId("search-token-input")).toBeVisible(); }); -test.afterAll(async ({ page, extensionId }) => { +test.afterAll(async ({ page, extensionId, context }) => { if ( process.env.IS_INTEGRATION_MODE && test.info().status !== test.info().expectedStatus && @@ -91,7 +94,7 @@ test.afterAll(async ({ page, extensionId }) => { ) { // remove trustline in cleanup if Adding Soroban verified token test failed test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Manage assets").click({ force: true }); diff --git a/extension/e2e-tests/addCollectible.test.ts b/extension/e2e-tests/addCollectible.test.ts index fe793db7a1..c3f5643a70 100644 --- a/extension/e2e-tests/addCollectible.test.ts +++ b/extension/e2e-tests/addCollectible.test.ts @@ -19,106 +19,109 @@ test("Add a collectible to an account", async ({ owner: "", contracts: [] as { id: string; token_ids: string[] }[], }; - await stubAllExternalApis(page, context); - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - await stubCollectibles(page); - await page.route("**/collectibles**", async (route) => { - const postData = JSON.parse(route.request().postData() || "{}"); - const { owner, contracts } = postData as { - owner: string; - contracts: { id: string; token_ids: string[] }[]; - }; + const stubOverrides = async () => { + await stubAllExternalApis(page, context); + await stubTokenDetails(page); + await stubAccountBalances(page); + await stubAccountHistory(page); + await stubTokenPrices(page); + await stubScanDapp(context); + await stubCollectibles(page); - if (owner && contracts.length > 0) { - collectiblesParams = { - owner, - contracts, + await page.route("**/collectibles**", async (route) => { + const postData = JSON.parse(route.request().postData() || "{}"); + const { owner, contracts } = postData as { + owner: string; + contracts: { id: string; token_ids: string[] }[]; }; - } - const json = { - data: { - collections: [ - // Stellar Frogs Collection - { - collection: { - address: - "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", // Using XLM contract address for testing - name: "Stellar Frogs", - symbol: "SFROG", - collectibles: [ - { - owner: - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - token_id: "1", - token_uri: "https://nftcalendar.io/tokenMetadata/1", - }, - { - owner: - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - token_id: "2", - token_uri: "https://nftcalendar.io/tokenMetadata/2", - }, - { - owner: - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - token_id: "3", - token_uri: "https://nftcalendar.io/tokenMetadata/3", - }, - ], + if (owner && contracts.length > 0) { + collectiblesParams = { + owner, + contracts, + }; + } + + const json = { + data: { + collections: [ + // Stellar Frogs Collection + { + collection: { + address: + "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", // Using XLM contract address for testing + name: "Stellar Frogs", + symbol: "SFROG", + collectibles: [ + { + owner: + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + token_id: "1", + token_uri: "https://nftcalendar.io/tokenMetadata/1", + }, + { + owner: + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + token_id: "2", + token_uri: "https://nftcalendar.io/tokenMetadata/2", + }, + { + owner: + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + token_id: "3", + token_uri: "https://nftcalendar.io/tokenMetadata/3", + }, + ], + }, }, - }, - // Soroban Domains Collection - { - collection: { - address: "CCCSorobanDomainsCollection", - name: "Soroban Domains", - symbol: "SDOM", - collectibles: [ - { - owner: - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - token_id: "102510", - token_uri: "https://nftcalendar.io/tokenMetadata/102510", - }, - { - owner: - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - token_id: "102589", - token_uri: "https://nftcalendar.io/tokenMetadata/102589", - }, - ], + // Soroban Domains Collection + { + collection: { + address: "CCCSorobanDomainsCollection", + name: "Soroban Domains", + symbol: "SDOM", + collectibles: [ + { + owner: + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + token_id: "102510", + token_uri: "https://nftcalendar.io/tokenMetadata/102510", + }, + { + owner: + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + token_id: "102589", + token_uri: "https://nftcalendar.io/tokenMetadata/102589", + }, + ], + }, }, - }, - // Future Monkeys Collection - { - collection: { - address: "CCCFutureMonkeysCollection", - name: "Future Monkeys", - symbol: "FMONK", - collectibles: [ - { - owner: - "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - token_id: "111", - token_uri: "https://nftcalendar.io/tokenMetadata/111", - }, - ], + // Future Monkeys Collection + { + collection: { + address: "CCCFutureMonkeysCollection", + name: "Future Monkeys", + symbol: "FMONK", + collectibles: [ + { + owner: + "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + token_id: "111", + token_uri: "https://nftcalendar.io/tokenMetadata/111", + }, + ], + }, }, - }, - ], - }, - }; - await route.fulfill({ json }); - }); + ], + }, + }; + await route.fulfill({ json }); + }); + }; test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("network-selector-open").click(); await page.getByText("Main Net").click(); diff --git a/extension/e2e-tests/allowList.test.ts b/extension/e2e-tests/allowList.test.ts index c2c9f10472..0c91778bb7 100644 --- a/extension/e2e-tests/allowList.test.ts +++ b/extension/e2e-tests/allowList.test.ts @@ -1,14 +1,9 @@ import { expect, test, expectPageToHaveScreenshot } from "./test-fixtures"; import { loginToTestAccount, PASSWORD } from "./helpers/login"; -import { stubAllExternalApis } from "./helpers/stubs"; -test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); -}); - -test("View Allow List selector", async ({ page, extensionId }) => { +test("View Allow List selector", async ({ page, extensionId, context }) => { test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); // open a second tab and go to docs playground const pageTwo = await page.context().newPage(); diff --git a/extension/e2e-tests/buyWithOnramp.test.ts b/extension/e2e-tests/buyWithOnramp.test.ts index 53973baa4f..2b2db8e78d 100644 --- a/extension/e2e-tests/buyWithOnramp.test.ts +++ b/extension/e2e-tests/buyWithOnramp.test.ts @@ -1,67 +1,64 @@ import { test, expect, expectPageToHaveScreenshot } from "./test-fixtures"; import { loginToTestAccount } from "./helpers/login"; -import { stubAllExternalApis } from "./helpers/stubs"; -test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); - - // Override account-balances to return 0 XLM balance - await page.route("**/account-balances/**", async (route) => { - const json = { - balances: { - native: { - token: { - type: "native", - code: "XLM", - }, - total: "0", - available: "0", - sellingLiabilities: "0", - buyingLiabilities: "0", - minimumBalance: "1", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", +test("should show add XLM page and open Coinbase", async ({ + page, + extensionId, + context, +}) => { + const stubOverrides = async () => { + // Override account-balances to return 0 XLM balance + await page.route("**/account-balances/**", async (route) => { + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: "0", + available: "0", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, }, }, - }, - isFunded: false, - subentryCount: 0, - error: { - horizon: null, - soroban: null, - }, - }; - await route.fulfill({ json }); - }); - - // Stub /token endpoint - await page.route("**/token", async (route) => { - await route.fulfill({ - json: { - data: { - token: "MWYwZjU5ODEtYjkxOC02YzkwLWI3YzItNWVhZDYyZDQ1M2M0", + isFunded: false, + subentryCount: 0, + error: { + horizon: null, + soroban: null, }, - }, + }; + await route.fulfill({ json }); }); - }); -}); -test("should show add XLM page and open Coinbase", async ({ - page, - extensionId, -}) => { - await loginToTestAccount({ page, extensionId }); + // Stub /token endpoint + await page.route("**/token", async (route) => { + await route.fulfill({ + json: { + data: { + token: "MWYwZjU5ODEtYjkxOC02YzkwLWI3YzItNWVhZDYyZDQ1M2M0", + }, + }, + }); + }); + }; + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("network-selector-open").click(); await page.getByText("Main Net").click(); @@ -86,8 +83,61 @@ test("should show add XLM page and open Coinbase", async ({ test("should show Buy with Coinbase and open Coinbase", async ({ page, extensionId, + context, }) => { - await loginToTestAccount({ page, extensionId }); + const stubOverrides = async () => { + // Override account-balances to return 0 XLM balance + await page.route("**/account-balances/**", async (route) => { + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: "0", + available: "0", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, + }, + }, + }, + isFunded: false, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + await route.fulfill({ json }); + }); + + // Stub /token endpoint + await page.route("**/token", async (route) => { + await route.fulfill({ + json: { + data: { + token: "MWYwZjU5ODEtYjkxOC02YzkwLWI3YzItNWVhZDYyZDQ1M2M0", + }, + }, + }); + }); + }; + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("network-selector-open").click(); await page.getByText("Main Net").click(); diff --git a/extension/e2e-tests/helpers/login.ts b/extension/e2e-tests/helpers/login.ts index 22647ab207..c61d238b2a 100644 --- a/extension/e2e-tests/helpers/login.ts +++ b/extension/e2e-tests/helpers/login.ts @@ -86,15 +86,20 @@ export const loginToTestAccount = async ({ page, extensionId, context, + stubOverrides, }: { page: Page; extensionId: string; - context?: BrowserContext; + context: BrowserContext; + stubOverrides?: () => Promise; }) => { await page.goto(`chrome-extension://${extensionId}/index.html`); if (context) { // Wait for any background activity to complete await stubAllExternalApis(page, context); + if (stubOverrides) { + await stubOverrides(); + } } await page.getByText("I already have a wallet").click(); diff --git a/extension/e2e-tests/helpers/stubs.ts b/extension/e2e-tests/helpers/stubs.ts index ab7c4b4403..c9c07d87ae 100644 --- a/extension/e2e-tests/helpers/stubs.ts +++ b/extension/e2e-tests/helpers/stubs.ts @@ -2281,7 +2281,7 @@ export const stubAllExternalApis = async ( // Blockaid scan await stubScanTx(page); - // await stubScanDapp(context); + await stubScanDapp(context); }; export const stubBackendSettings = async (page: Page) => { diff --git a/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts b/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts index 4c037a32af..f30865e2c8 100644 --- a/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts @@ -1,18 +1,21 @@ import { test, expect, expectPageToHaveScreenshot } from "../test-fixtures"; import { loginToTestAccount } from "../helpers/login"; -import { stubAllExternalApis, stubTokenDetails } from "../helpers/stubs"; import { TEST_TOKEN_ADDRESS } from "../helpers/test-token"; -test.beforeEach(async ({ page, context }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - await stubTokenDetails(page); - } -}); +// test.beforeEach(async ({ page, context }) => { +// if (!process.env.IS_INTEGRATION_MODE) { +// await stubAllExternalApis(page, context); +// await stubTokenDetails(page); +// } +// }); -test("Adding classic asset on Testnet", async ({ page, extensionId }) => { +test("Adding classic asset on Testnet", async ({ + page, + extensionId, + context, +}) => { test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Manage assets").click(); @@ -76,8 +79,9 @@ const truncateString = (str: string, charCount = 4) => test("Adding and removing unverified Soroban token", async ({ page, extensionId, + context, }) => { - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Manage assets").click(); @@ -160,7 +164,7 @@ test("Adding and removing unverified Soroban token", async ({ } }); -test.afterAll(async ({ page, extensionId }) => { +test.afterAll(async ({ page, extensionId, context }) => { if ( process.env.IS_INTEGRATION_MODE && test.info().status !== test.info().expectedStatus && @@ -168,7 +172,7 @@ test.afterAll(async ({ page, extensionId }) => { ) { // remove trustline in cleanup if Adding Soroban verified token test failed test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Manage assets").click(); diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts index 0823c6ef83..c9654f92e6 100644 --- a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts @@ -52,8 +52,12 @@ test.beforeEach(async ({ page, context }) => { } }); -test("should sign transaction when allowed", async ({ page, extensionId }) => { - await loginToTestAccount({ page, extensionId }); +test("should sign transaction when allowed", async ({ + page, + extensionId, + context, +}) => { + await loginToTestAccount({ page, extensionId, context }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -180,13 +184,7 @@ test.skip("should sign transaction for a specific account when allowed", async ( extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -222,8 +220,9 @@ test.skip("should sign transaction for a specific account when allowed", async ( test("should not sign transaction when not allowed", async ({ page, extensionId, + context, }) => { - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); // open a second tab and go to docs playground const pageTwo = await page.context().newPage(); @@ -261,13 +260,7 @@ test("should sign auth entry when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -309,13 +302,7 @@ test("should not sign auth entry when not allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); // open a second tab and go to docs playground const pageTwo = await page.context().newPage(); @@ -345,13 +332,7 @@ test("should sign auth entry for a selected account when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await allowDapp({ page }); @@ -399,13 +380,7 @@ test("should sign message string when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -443,13 +418,7 @@ test("should sign message long string when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -487,13 +456,7 @@ test("should sign message json when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -541,13 +504,7 @@ test("should sign message for a specific account when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -592,12 +549,7 @@ test("should not sign message when not allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); // open a second tab and go to docs playground const pageTwo = await page.context().newPage(); @@ -622,14 +574,9 @@ test("should add token when allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(context); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); await stubIsSac(context); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -664,14 +611,9 @@ test("should not add token when not allowed", async ({ extensionId, context, }) => { - await stubTokenDetails(context); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); await stubIsSac(context); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); // open a second tab and go to docs playground const pageTwo = await page.context().newPage(); @@ -705,13 +647,7 @@ test("should get public key when logged out", async ({ extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); - - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Settings").click(); await page.getByText("Log Out").click(); diff --git a/extension/e2e-tests/integration-tests/sendIntegration.test.ts b/extension/e2e-tests/integration-tests/sendIntegration.test.ts index 1a5a3d58c7..6ac90e42ba 100644 --- a/extension/e2e-tests/integration-tests/sendIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/sendIntegration.test.ts @@ -1,45 +1,48 @@ import { TransactionBuilder } from "stellar-sdk"; import { test, expect } from "../test-fixtures"; import { loginToTestAccount } from "../helpers/login"; -import { stubAllExternalApis } from "../helpers/stubs"; import { TEST_M_ADDRESS, TEST_TOKEN_ADDRESS } from "../helpers/test-token"; -test.beforeEach(async ({ page, context }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } -}); +// test.beforeEach(async ({ page, context }) => { +// if (!process.env.IS_INTEGRATION_MODE) { +// await stubAllExternalApis(page, context); +// } +// }); test("Send persists inputs and submits to network", async ({ page, extensionId, + context, }) => { test.slow(); let isScanSkiped = false; - if (!process.env.IS_INTEGRATION_MODE) { - await page.route("**/submit-tx", async (route) => { - const json = { - memo: "test memo", - max_fee: "900", - envelope_xdr: - "AAAAAgAAAADLvQoIbFw9k0tgjZoOrLTuJJY9kHFYp/YAEAlt/xirbAAAA4QAAAUVAAAAvgAAAAEAAAAAAAAAAAAAAABper1qAAAAAQAAAAl0ZXN0IG1lbW8AAAAAAAABAAAAAAAAAAEAAAAAZ4AU5m5lMnKhtnADB3KJkkfNHUcxrSs8TOoG98skg+QAAAAAAAAAAACYloAAAAAAAAAAAf8Yq2wAAABApUEUNnMHzyHA+ZclMfxsX1vv5wfoKegPYhxYnOuiSgit7kCLrVcahgbHAnvb0H+SM0PlZwOxEuaeBJA/B7GdAg==", - - successful: true, - }; - await route.fulfill({ json }); - }); - } - page.on("request", (request) => { - if ( - request - .url() - .includes("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF") - ) { - isScanSkiped = request.url().includes("should_skip_scan=true"); + + const stubOverrides = async () => { + if (!process.env.IS_INTEGRATION_MODE) { + await page.route("**/submit-tx", async (route) => { + const json = { + memo: "test memo", + max_fee: "900", + envelope_xdr: + "AAAAAgAAAADLvQoIbFw9k0tgjZoOrLTuJJY9kHFYp/YAEAlt/xirbAAAA4QAAAUVAAAAvgAAAAEAAAAAAAAAAAAAAABper1qAAAAAQAAAAl0ZXN0IG1lbW8AAAAAAAABAAAAAAAAAAEAAAAAZ4AU5m5lMnKhtnADB3KJkkfNHUcxrSs8TOoG98skg+QAAAAAAAAAAACYloAAAAAAAAAAAf8Yq2wAAABApUEUNnMHzyHA+ZclMfxsX1vv5wfoKegPYhxYnOuiSgit7kCLrVcahgbHAnvb0H+SM0PlZwOxEuaeBJA/B7GdAg==", + + successful: true, + }; + await route.fulfill({ json }); + }); } - }); + page.on("request", (request) => { + if ( + request + .url() + .includes("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF") + ) { + isScanSkiped = request.url().includes("should_skip_scan=true"); + } + }); + }; - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -127,9 +130,10 @@ test("Send persists inputs and submits to network", async ({ test("Send XLM payments to recent federated addresses", async ({ page, extensionId, + context, }) => { test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -200,9 +204,13 @@ test("Send XLM payments to recent federated addresses", async ({ expect(accountBalancesRequestWasMade).toBeTruthy(); }); -test("Send XLM payment to C address", async ({ page, extensionId }) => { +test("Send XLM payment to C address", async ({ + page, + extensionId, + context, +}) => { test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); @@ -240,9 +248,13 @@ test("Send XLM payment to C address", async ({ page, extensionId }) => { expect(accountBalancesRequestWasMade).toBeTruthy(); }); -test("Send XLM payment to M address", async ({ page, extensionId }) => { +test("Send XLM payment to M address", async ({ + page, + extensionId, + context, +}) => { test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); @@ -282,77 +294,83 @@ test("Send XLM payment to M address", async ({ page, extensionId }) => { expect(accountBalancesRequestWasMade).toBeTruthy(); }); -test("Send token payment to C address", async ({ page, extensionId }) => { +test("Send token payment to C address", async ({ + page, + extensionId, + context, +}) => { test.slow(); - if (!process.env.IS_INTEGRATION_MODE) { - await page.route("**/account-balances/**", async (route) => { - const json = { - balances: { - native: { - token: { - type: "native", - code: "XLM", - }, - total: "10000.0000000", - available: "10000.0000000", - sellingLiabilities: "0", - buyingLiabilities: "0", - minimumBalance: "1", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", + const stubOverrides = async () => { + if (!process.env.IS_INTEGRATION_MODE) { + await page.route("**/account-balances/**", async (route) => { + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, - }, - }, - [`E2E:${TEST_TOKEN_ADDRESS}`]: { - token: { - code: "E2E", - issuer: { - key: TEST_TOKEN_ADDRESS, + total: "10000.0000000", + available: "10000.0000000", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, }, }, - contractId: TEST_TOKEN_ADDRESS, - total: "500.0000000", - available: "500.0000000", - sellingLiabilities: "0", - buyingLiabilities: "0", - minimumBalance: "0.5", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", + [`E2E:${TEST_TOKEN_ADDRESS}`]: { + token: { + code: "E2E", + issuer: { + key: TEST_TOKEN_ADDRESS, + }, + }, + contractId: TEST_TOKEN_ADDRESS, + total: "500.0000000", + available: "500.0000000", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "0.5", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, }, }, - }, - isFunded: true, - subentryCount: 0, - error: { - horizon: null, - soroban: null, - }, - }; - await route.fulfill({ json }); - }); - } - await loginToTestAccount({ page, extensionId }); + isFunded: true, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + await route.fulfill({ json }); + }); + } + }; + await loginToTestAccount({ page, extensionId, context, stubOverrides }); if (process.env.IS_INTEGRATION_MODE) { // in integration mode, make sure the token is added first diff --git a/extension/e2e-tests/loadAccount.test.ts b/extension/e2e-tests/loadAccount.test.ts index 77bd5a51e5..995d3173b1 100644 --- a/extension/e2e-tests/loadAccount.test.ts +++ b/extension/e2e-tests/loadAccount.test.ts @@ -8,15 +8,14 @@ import { stubTokenPrices, stubCollectibles, stubCollectiblesUnsuccessfulMetadata, - stubAllExternalApis, } from "./helpers/stubs"; -test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); -}); - -test("Load accounts on standalone network", async ({ page, extensionId }) => { - await loginToTestAccount({ page, extensionId }); +test("Load accounts on standalone network", async ({ + page, + extensionId, + context, +}) => { + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Settings").click(); await page.getByText("Network").click(); @@ -50,13 +49,15 @@ test.skip("Switches account and fetches correct balances while clearing cache", extensionId, context, }) => { - await stubTokenDetails(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - await stubScanDapp(context); + const stubOverrides = async () => { + await stubTokenDetails(page); + await stubAccountHistory(page); + await stubTokenPrices(page); + await stubScanDapp(context); + }; test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await expect(page.getByTestId("account-assets")).toContainText("XLM"); const account1XlmBalance = await page .getByTestId("asset-amount") @@ -124,88 +125,91 @@ test.skip("Switches account and fetches correct balances while clearing cache", test("Switches network and fetches correct balances while clearing cache", async ({ page, extensionId, + context, }) => { - await page.route("**/account-balances/**", async (route) => { - let json = {}; - - if (route.request().url().includes("TESTNET")) { - json = { - balances: { - native: { - token: { - type: "native", - code: "XLM", - }, - total: "2", - available: "2", - sellingLiabilities: "0", - buyingLiabilities: "0", - minimumBalance: "1", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", + const stubOverrides = async () => { + await page.route("**/account-balances/**", async (route) => { + let json = {}; + + if (route.request().url().includes("TESTNET")) { + json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: "2", + available: "2", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, }, }, - }, - isFunded: true, - subentryCount: 0, - error: { - horizon: null, - soroban: null, - }, - }; - } else { - json = { - balances: { - native: { - token: { - type: "native", - code: "XLM", - }, - total: "1", - available: "1", - sellingLiabilities: "0", - buyingLiabilities: "0", - minimumBalance: "1", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", + isFunded: true, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + } else { + json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: "1", + available: "1", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, }, }, - }, - isFunded: true, - subentryCount: 0, - error: { - horizon: null, - soroban: null, - }, - }; - } + isFunded: true, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + } - await route.fulfill({ json }); - }); + await route.fulfill({ json }); + }); + }; - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await expect(page.getByTestId("account-assets")).toContainText("XLM"); await expect(page.getByTestId("asset-amount")).toHaveText("2"); @@ -262,8 +266,9 @@ test("Switches network and fetches correct balances while clearing cache", async test("Account Balances should be loaded once and cached", async ({ page, extensionId, + context, }) => { - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); let accountBalancesRequestWasMade = false; page.on("request", (request) => { @@ -283,7 +288,7 @@ test("Switches account without password prompt", async ({ extensionId, context, }) => { - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await expect(page.getByTestId("account-assets")).toContainText("XLM"); await page.getByTestId("account-view-account-name").click(); await page.getByText("Account 2").click(); @@ -300,7 +305,7 @@ test("Can't change settings on a stale window", async ({ context, }) => { const pageOne = await page.context().newPage(); - await loginToTestAccount({ page: pageOne, extensionId }); + await loginToTestAccount({ page: pageOne, extensionId, context }); // open a second tab and change the account const pageTwo = await page.context().newPage(); @@ -351,7 +356,7 @@ test.skip("Clears cache and fetches balances if it's been 2 minutes since the la test.slow(); await page.clock.install({ time: new Date("2024-01-01T12:00:00") }); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await expect(page.getByTestId("account-assets")).toContainText("XLM"); const account1XlmBalance = await page .getByTestId("asset-amount") @@ -427,6 +432,7 @@ test.skip("Clears cache and fetches balances if it's been 2 minutes since the la test("Loads wallets data and token prices on Mainnet in batches", async ({ page, extensionId, + context, }) => { let tokenPricesCallCount = 0; @@ -436,42 +442,86 @@ test("Loads wallets data and token prices on Mainnet in batches", async ({ } }); - await page.route("**/account-balances/**", async (route) => { - const json = { - balances: { - native: { - token: { - type: "native", - code: "XLM", + const stubOverrides = async () => { + await page.route("**/account-balances/**", async (route) => { + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: "5", + available: "4", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, + }, }, - total: "5", - available: "4", - sellingLiabilities: "0", - buyingLiabilities: "0", - minimumBalance: "1", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", + "BTC:GCK3D3V2XNLLKRFGFFFDEJXA4O2J4X36HET2FE446AV3M4U7DPHO3PEM": { + token: { + code: "BTC", + issuer: { + key: "GCK3D3V2XNLLKRFGFFFDEJXA4O2J4X36HET2FE446AV3M4U7DPHO3PEM", + }, + }, + symbol: "BTC", + total: "3", + available: "100000099976", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, }, }, - "BTC:GCK3D3V2XNLLKRFGFFFDEJXA4O2J4X36HET2FE446AV3M4U7DPHO3PEM": { + isFunded: true, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + } as any; + if ( + route + .request() + .url() + .includes("GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY") + ) { + json.balances.native.total = "10"; + json.balances.native.available = "9"; + json.balances[ + "USDC:GCK3D3V2XNLLKRFGFFFDEJXA4O2J4X36HET2FE446AV3M4U7DPHO3PEM" + ] = { token: { - code: "BTC", + code: "USDC", issuer: { key: "GCK3D3V2XNLLKRFGFFFDEJXA4O2J4X36HET2FE446AV3M4U7DPHO3PEM", }, }, - symbol: "BTC", + symbol: "USDC", total: "3", available: "100000099976", blockaidData: { @@ -488,108 +538,66 @@ test("Loads wallets data and token prices on Mainnet in batches", async ({ trading_limits: {}, financial_stats: {}, }, - }, - }, - isFunded: true, - subentryCount: 0, - error: { - horizon: null, - soroban: null, - }, - } as any; - if ( - route - .request() - .url() - .includes("GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY") - ) { - json.balances.native.total = "10"; - json.balances.native.available = "9"; - json.balances[ - "USDC:GCK3D3V2XNLLKRFGFFFDEJXA4O2J4X36HET2FE446AV3M4U7DPHO3PEM" - ] = { - token: { - code: "USDC", - issuer: { - key: "GCK3D3V2XNLLKRFGFFFDEJXA4O2J4X36HET2FE446AV3M4U7DPHO3PEM", - }, - }, - symbol: "USDC", - total: "3", - available: "100000099976", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", - }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, - }, - }; - } - if ( - route - .request() - .url() - .includes("GCKUVXILBNYS4FDNWCGCYSJBY2PBQ4KAW2M5CODRVJPUFM62IJFH67J2") - ) { - json.balances.native.total = "11"; - json.balances.native.available = "10"; - } - if ( - route - .request() - .url() - .includes("GDPXC35MQCSFJCEDNWUJZYDJWKNGNL2YMFZZS47LT46CFVGAJ6GWYGJC") - ) { - json.balances.native.total = "12"; - json.balances.native.available = "11"; - } - if ( - route - .request() - .url() - .includes("GC32JSRAZA6BJYIKEI2X5LAVJKFVDVVIYWRVCAI7Q7N36WKXVDHTGTQA") - ) { - json.balances.native.total = "13"; - json.balances.native.available = "9"; - } - if ( - route - .request() - .url() - .includes("GDY4ZZLCUEBZPHTKSAESUHV37JA5MZ7BGP2KS32DSBSHS7ONSBFZBQ7C") - ) { - json.balances.native.total = "14"; - json.balances.native.available = "9"; - } - if ( - route - .request() - .url() - .includes("GBW2O3KT5E6W6XN2T66X5TM6EXVTTKVHQJE426PUX5ANMGQVLS2KOU3T") - ) { - json.balances.native.total = "15"; - json.balances.native.available = "9"; - } - if ( - route - .request() - .url() - .includes("GARHHLBEZLF3WWIENRZLHKOB62IIDZX2DHNWXAR2E7KVQTDQGDI4H6NU") - ) { - json.balances.native.total = "16"; - json.balances.native.available = "9"; - } - await route.fulfill({ json }); - }); - await loginToTestAccount({ page, extensionId }); + }; + } + if ( + route + .request() + .url() + .includes("GCKUVXILBNYS4FDNWCGCYSJBY2PBQ4KAW2M5CODRVJPUFM62IJFH67J2") + ) { + json.balances.native.total = "11"; + json.balances.native.available = "10"; + } + if ( + route + .request() + .url() + .includes("GDPXC35MQCSFJCEDNWUJZYDJWKNGNL2YMFZZS47LT46CFVGAJ6GWYGJC") + ) { + json.balances.native.total = "12"; + json.balances.native.available = "11"; + } + if ( + route + .request() + .url() + .includes("GC32JSRAZA6BJYIKEI2X5LAVJKFVDVVIYWRVCAI7Q7N36WKXVDHTGTQA") + ) { + json.balances.native.total = "13"; + json.balances.native.available = "9"; + } + if ( + route + .request() + .url() + .includes("GDY4ZZLCUEBZPHTKSAESUHV37JA5MZ7BGP2KS32DSBSHS7ONSBFZBQ7C") + ) { + json.balances.native.total = "14"; + json.balances.native.available = "9"; + } + if ( + route + .request() + .url() + .includes("GBW2O3KT5E6W6XN2T66X5TM6EXVTTKVHQJE426PUX5ANMGQVLS2KOU3T") + ) { + json.balances.native.total = "15"; + json.balances.native.available = "9"; + } + if ( + route + .request() + .url() + .includes("GARHHLBEZLF3WWIENRZLHKOB62IIDZX2DHNWXAR2E7KVQTDQGDI4H6NU") + ) { + json.balances.native.total = "16"; + json.balances.native.available = "9"; + } + await route.fulfill({ json }); + }); + }; + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("network-selector-open").click(); await page.getByText("Main Net").click(); await expect(page.getByTestId("account-assets")).toContainText("XLM"); @@ -617,7 +625,7 @@ test("Loads wallets data and token prices on Mainnet in batches", async ({ }); test("Renames wallets", async ({ page, extensionId, context }) => { - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-view-account-name").click(); await expect(page.getByText("Wallets")).toBeVisible(); @@ -632,9 +640,12 @@ test("Renames wallets", async ({ page, extensionId, context }) => { test("Loads collectibles data with successful metadata", async ({ page, extensionId, + context, }) => { - await stubCollectibles(page, true); - await loginToTestAccount({ page, extensionId }); + const stubOverrides = async () => { + await stubCollectibles(page, true); + }; + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("account-tab-collectibles").click(); await expect(page.getByText("Stellar Frogs")).toBeVisible(); await expect(page.getByText("Soroban Domains")).toBeVisible(); @@ -772,9 +783,12 @@ test("Loads collectibles data with successful metadata", async ({ test("Loads collectibles data with unsuccessful metadata", async ({ page, extensionId, + context, }) => { - await stubCollectiblesUnsuccessfulMetadata(page); - await loginToTestAccount({ page, extensionId }); + const stubOverrides = async () => { + await stubCollectiblesUnsuccessfulMetadata(page); + }; + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("account-tab-collectibles").click(); await expect(page.getByText("Stellar Frogs")).toBeVisible(); const counts = await page diff --git a/extension/e2e-tests/login.test.ts b/extension/e2e-tests/login.test.ts index 22fa809931..83b3cdd70d 100644 --- a/extension/e2e-tests/login.test.ts +++ b/extension/e2e-tests/login.test.ts @@ -1,17 +1,13 @@ import { loginToTestAccount } from "./helpers/login"; import { test, expect } from "./test-fixtures"; -import { stubAllExternalApis } from "./helpers/stubs"; - -test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); -}); test("Login shows error state on bad password", async ({ page, extensionId, + context, }) => { test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Settings").click(); await page.getByText("Log Out").click(); diff --git a/extension/e2e-tests/memo.test.ts b/extension/e2e-tests/memo.test.ts index 513876ddd1..1aaaf6a620 100644 --- a/extension/e2e-tests/memo.test.ts +++ b/extension/e2e-tests/memo.test.ts @@ -23,15 +23,12 @@ test.beforeEach(async ({ page, context }) => { test("Send payment shows memo required warning when destination requires memo", async ({ page, extensionId, + context, }) => { test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -64,15 +61,12 @@ test("Send payment shows memo required warning when destination requires memo", test("Send payment allows submission after adding memo to memo-required address", async ({ page, extensionId, + context, }) => { test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -133,15 +127,12 @@ test("Send payment allows submission after adding memo to memo-required address" test("Send payment returns to review modal after adding memo from review flow", async ({ page, extensionId, + context, }) => { test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -187,6 +178,7 @@ test("Send payment returns to review modal after adding memo from review flow", test("Send payment returns to review modal after cancelling memo editor from review flow", async ({ page, extensionId, + context, }) => { test.slow(); await stubAccountBalances(page); @@ -195,7 +187,7 @@ test("Send payment returns to review modal after cancelling memo editor from rev await stubTokenPrices(page); await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -239,6 +231,7 @@ test("Send payment returns to review modal after cancelling memo editor from rev test("Send payment shows memo value directly when memo is added before review", async ({ page, extensionId, + context, }) => { test.slow(); await stubAccountBalances(page); @@ -247,7 +240,7 @@ test("Send payment shows memo value directly when memo is added before review", await stubTokenPrices(page); await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -313,6 +306,7 @@ test("Send payment shows memo value directly when memo is added before review", test("Send payment shows Add Memo when switching from non-memo-required to memo-required address", async ({ page, extensionId, + context, }) => { test.slow(); const NON_MEMO_REQUIRED_ADDRESS = @@ -324,7 +318,7 @@ test("Send payment shows Add Memo when switching from non-memo-required to memo- await stubTokenPrices(page); await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -386,15 +380,12 @@ test("Send payment shows Add Memo when switching from non-memo-required to memo- test("Send payment shows Add Memo after cancelling review and returning to memo-required address", async ({ page, extensionId, + context, }) => { test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); await stubMemoRequiredAccounts(page, MEMO_REQUIRED_ADDRESS); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -466,14 +457,10 @@ test("Send payment shows Add Memo after cancelling review and returning to memo- test("Send classic token to G address allows memo", async ({ page, extensionId, + context, }) => { test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -511,14 +498,10 @@ test("Send classic token to G address allows memo", async ({ test("Send classic token to M address doesn't allow memo", async ({ page, extensionId, + context, }) => { test.slow(); - await stubAccountBalances(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -541,17 +524,16 @@ test("Send classic token to M address doesn't allow memo", async ({ test("Send custom token without Soroban mux support to G address disables memo", async ({ page, extensionId, + context, }) => { test.slow(); - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); + const stubOverrides = async () => { + await stubAccountBalancesE2e(page); + }; // Stub contract spec before login to ensure it's ready when needed await stubContractSpec(page, TEST_TOKEN_ADDRESS, false); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible({ @@ -631,17 +613,17 @@ test("Send custom token without Soroban mux support to G address disables memo", test("Send custom token without Soroban mux support to M address is disabled", async ({ page, extensionId, + context, }) => { test.slow(); - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); + const stubOverrides = async () => { + await stubAccountBalancesE2e(page); + await stubSimulateTokenTransfer(page); + }; // Stub contract spec before login to ensure it's ready when needed await stubContractSpec(page, TEST_TOKEN_ADDRESS, false); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -681,16 +663,15 @@ test("Send custom token without Soroban mux support to M address is disabled", a test("Send custom token with Soroban mux support to G address allows memo", async ({ page, extensionId, + context, }) => { test.slow(); - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); + const stubOverrides = async () => { + await stubAccountBalancesE2e(page); + }; await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -748,16 +729,15 @@ test("Send custom token with Soroban mux support to G address allows memo", asyn test("Send custom token with Soroban mux support to M address disables memo", async ({ page, extensionId, + context, }) => { test.slow(); - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); + const stubOverrides = async () => { + await stubAccountBalancesE2e(page); + }; await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); diff --git a/extension/e2e-tests/onboarding.test.ts b/extension/e2e-tests/onboarding.test.ts index 6dbd9de976..6872841f8a 100644 --- a/extension/e2e-tests/onboarding.test.ts +++ b/extension/e2e-tests/onboarding.test.ts @@ -375,9 +375,13 @@ test("Incorrect mnemonic phrase", async ({ page }) => { ); }); -test("Logout and create new account", async ({ page, extensionId }) => { +test("Logout and create new account", async ({ + page, + extensionId, + context, +}) => { test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-view-account-name").click(); const originalAccounts = page.getByTestId("wallet-row-select"); @@ -442,9 +446,13 @@ test("Logout and create new account", async ({ page, extensionId }) => { }); }); -test("Logout and import new account", async ({ page, extensionId }) => { +test("Logout and import new account", async ({ + page, + extensionId, + context, +}) => { test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-view-account-name").click(); const originalAccounts = page.getByTestId("wallet-row-select"); diff --git a/extension/e2e-tests/sendCollectible.test.ts b/extension/e2e-tests/sendCollectible.test.ts index b92ec51c29..46adc0afe6 100644 --- a/extension/e2e-tests/sendCollectible.test.ts +++ b/extension/e2e-tests/sendCollectible.test.ts @@ -2,22 +2,23 @@ import { loginToTestAccount } from "./helpers/login"; import { stubSimulateSendCollectible, stubCollectiblesUnsuccessfulMetadata, - stubAllExternalApis, stubContractSpec, } from "./helpers/stubs"; import { TEST_M_ADDRESS } from "./helpers/test-token"; import { test, expect } from "./test-fixtures"; -test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); -}); - // Review screen navigation and collectible details display issues -test("Send collectible with metadata", async ({ page, extensionId }) => { - await stubSimulateSendCollectible(page); +test("Send collectible with metadata", async ({ + page, + extensionId, + context, +}) => { + const stubOverrides = async () => { + await stubSimulateSendCollectible(page); + }; - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); + await page.getByTestId("nav-link-send").click(); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); await expect(page.getByTestId("send-amount-fee-display")).toHaveText( @@ -82,11 +83,17 @@ test("Send collectible with metadata", async ({ page, extensionId }) => { ).toHaveText("GBTY…JZOF"); }); -test("Send collectible without metadata", async ({ page, extensionId }) => { - await stubCollectiblesUnsuccessfulMetadata(page); - await stubSimulateSendCollectible(page); +test("Send collectible without metadata", async ({ + page, + extensionId, + context, +}) => { + const stubOverrides = async () => { + await stubCollectiblesUnsuccessfulMetadata(page); + await stubSimulateSendCollectible(page); + }; - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -153,8 +160,11 @@ test("Send collectible without metadata", async ({ page, extensionId }) => { test("Send collectible to M address when contract doesn't support muxed is disabled", async ({ page, extensionId, + context, }) => { - await stubSimulateSendCollectible(page); + const stubOverrides = async () => { + await stubSimulateSendCollectible(page); + }; // Stub contract spec with muxed support = false await stubContractSpec( @@ -163,7 +173,7 @@ test("Send collectible to M address when contract doesn't support muxed is disab false, ); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -195,9 +205,12 @@ test("Send collectible to M address when contract doesn't support muxed is disab test("Send collectible with Soroban mux support to M address disables memo", async ({ page, extensionId, + context, }) => { test.slow(); - await stubSimulateSendCollectible(page); + const stubOverrides = async () => { + await stubSimulateSendCollectible(page); + }; // Stub contract spec with muxed support = true await stubContractSpec( page, @@ -205,7 +218,7 @@ test("Send collectible with Soroban mux support to M address disables memo", asy true, ); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -259,6 +272,7 @@ test("Send collectible with Soroban mux support to M address disables memo", asy test("Send collectible without Soroban mux support to G address disables memo", async ({ page, extensionId, + context, }) => { // Stub contract spec with muxed support = false await stubContractSpec( @@ -267,7 +281,7 @@ test("Send collectible without Soroban mux support to G address disables memo", false, ); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await page.getByTestId("send-amount-edit-dest-asset").click(); @@ -314,8 +328,11 @@ test("Send collectible without Soroban mux support to G address disables memo", test("Send collectible with Soroban mux support to G address allows memo", async ({ page, extensionId, + context, }) => { - await stubSimulateSendCollectible(page); + const stubOverrides = async () => { + await stubSimulateSendCollectible(page); + }; // Stub contract spec with muxed support = true await stubContractSpec( page, @@ -323,8 +340,8 @@ test("Send collectible with Soroban mux support to G address allows memo", async true, ); - await loginToTestAccount({ page, extensionId }); - await page.getByTestId("nav-link-send").click({ force: true }); + await loginToTestAccount({ page, extensionId, context }); + await page.getByTestId("nav-link-send").click(); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); diff --git a/extension/e2e-tests/sendPayment.test.ts b/extension/e2e-tests/sendPayment.test.ts index 47c7475db3..38103b9fad 100644 --- a/extension/e2e-tests/sendPayment.test.ts +++ b/extension/e2e-tests/sendPayment.test.ts @@ -7,7 +7,6 @@ import { stubAccountHistory, stubTokenDetails, stubTokenPrices, - stubAllExternalApis, stubSimulateTokenTransfer, stubContractSpec, } from "./helpers/stubs"; @@ -15,10 +14,6 @@ import { const MUXED_ACCOUNT_ADDRESS = "MCQ7EGW7VXHI4AKJAFADOIHCSK2OCVA42KUETUK5LQ3LVSEQEEKP6AAAAAAAAAAAAFLVY"; -test.beforeEach(async ({ page, context }) => { - await stubAllExternalApis(page, context); -}); - test("Swap doesn't throw error when account is unfunded", async ({ page, extensionId, @@ -31,148 +26,149 @@ test("Swap doesn't throw error when account is unfunded", async ({ test("Swap shows correct balances for assets", async ({ page, extensionId, + context, }) => { - await stubAccountHistory(page); - await stubTokenDetails(page); - await page.route("*/**/account-balances/*", async (route) => { - const json = { - balances: { - "FOO:GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY": { - token: { - type: "credit_alphanum12", - code: "FOO", - issuer: { - key: "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - }, - }, - sellingLiabilities: "0", - buyingLiabilities: "0", - total: "100", - limit: "922337203685.4775807", - available: "100", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: - "FOO-GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - metadata: { - external_links: {}, - }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: { - top_holders: [], + const stubOverrides = async () => { + await page.route("*/**/account-balances/*", async (route) => { + const json = { + balances: { + "FOO:GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY": { + token: { + type: "credit_alphanum12", + code: "FOO", + issuer: { + key: "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + }, }, - }, - }, - "BAZ:GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY": { - token: { - type: "credit_alphanum12", - code: "BAZ", - issuer: { - key: "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + sellingLiabilities: "0", + buyingLiabilities: "0", + total: "100", + limit: "922337203685.4775807", + available: "100", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: + "FOO-GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + metadata: { + external_links: {}, + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: { + top_holders: [], + }, }, }, - sellingLiabilities: "0", - buyingLiabilities: "0", - total: "10", - limit: "922337203685.4775807", - available: "10", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: - "BAZ-GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", - metadata: { - external_links: {}, + "BAZ:GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY": { + token: { + type: "credit_alphanum12", + code: "BAZ", + issuer: { + key: "GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + }, }, - fees: {}, - features: [ - { - feature_id: "HIGH_REPUTATION_TOKEN", - type: "Benign", - description: "Token with verified high reputation", + sellingLiabilities: "0", + buyingLiabilities: "0", + total: "10", + limit: "922337203685.4775807", + available: "10", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: + "BAZ-GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY", + metadata: { + external_links: {}, + }, + fees: {}, + features: [ + { + feature_id: "HIGH_REPUTATION_TOKEN", + type: "Benign", + description: "Token with verified high reputation", + }, + ], + trading_limits: {}, + financial_stats: { + top_holders: [], }, - ], - trading_limits: {}, - financial_stats: { - top_holders: [], }, }, - }, - native: { - token: { - type: "native", - code: "XLM", - }, - total: "999", - available: "999", - sellingLiabilities: "0", - buyingLiabilities: "0", - minimumBalance: "1", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", + native: { + token: { + type: "native", + code: "XLM", }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, - }, - }, - "PBT:GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY": { - token: { - code: "PBT", - issuer: { - key: "CAZXRTOKNUQ2JQQF3NCRU7GYMDJNZ2NMQN6IGN4FCT5DWPODMPVEXSND", + total: "999", + available: "999", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, }, }, - contractId: - "CAZXRTOKNUQ2JQQF3NCRU7GYMDJNZ2NMQN6IGN4FCT5DWPODMPVEXSND", - symbol: "PBT", - decimals: 5, - total: "9899700", - available: "9899700", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: - "PBT-CAZXRTOKNUQ2JQQF3NCRU7GYMDJNZ2NMQN6IGN4FCT5DWPODMPVEXSND", - metadata: { - external_links: {}, + "PBT:GDF32CQINROD3E2LMCGZUDVMWTXCJFR5SBYVRJ7WAAIAS3P7DCVWZEFY": { + token: { + code: "PBT", + issuer: { + key: "CAZXRTOKNUQ2JQQF3NCRU7GYMDJNZ2NMQN6IGN4FCT5DWPODMPVEXSND", + }, }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: { - top_holders: [], + contractId: + "CAZXRTOKNUQ2JQQF3NCRU7GYMDJNZ2NMQN6IGN4FCT5DWPODMPVEXSND", + symbol: "PBT", + decimals: 5, + total: "9899700", + available: "9899700", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: + "PBT-CAZXRTOKNUQ2JQQF3NCRU7GYMDJNZ2NMQN6IGN4FCT5DWPODMPVEXSND", + metadata: { + external_links: {}, + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: { + top_holders: [], + }, }, }, }, - }, - isFunded: true, - subentryCount: 0, - error: { - horizon: null, - soroban: null, - }, - }; - await route.fulfill({ json }); - }); + isFunded: true, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + await route.fulfill({ json }); + }); + }; test.slow(); - await login({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-swap").click(); await expect(page.getByTestId("AppHeaderPageTitle")).toContainText("Swap"); @@ -190,9 +186,10 @@ test("Swap shows correct balances for assets", async ({ test("Send doesn't throw error when account is unfunded", async ({ page, extensionId, + context, }) => { test.slow(); - await login({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -206,58 +203,62 @@ test("Send doesn't throw error when account is unfunded", async ({ await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); }); + test("Send doesn't throw error when creating muxed account", async ({ page, extensionId, + context, }) => { test.slow(); - // Override account-balances to return 0 XLM only for the muxed account address - await page.route("**/account-balances/**", async (route) => { - const url = route.request().url(); - const isMuxedAccount = url.includes( - "GCQ7EGW7VXHI4AKJAFADOIHCSK2OCVA42KUETUK5LQ3LVSEQEEKP7O7B", - ); - - const json = { - balances: { - native: { - token: { - type: "native", - code: "XLM", - }, - total: isMuxedAccount ? "0" : "10000.0000000", - available: isMuxedAccount ? "0" : "10000.0000000", - sellingLiabilities: "0", - buyingLiabilities: "0", - minimumBalance: "1", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", + const stubOverrides = async () => { + // Override account-balances to return 0 XLM only for the muxed account address + await page.route("**/account-balances/**", async (route) => { + const url = route.request().url(); + const isMuxedAccount = url.includes( + "GCQ7EGW7VXHI4AKJAFADOIHCSK2OCVA42KUETUK5LQ3LVSEQEEKP7O7B", + ); + + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: isMuxedAccount ? "0" : "10000.0000000", + available: isMuxedAccount ? "0" : "10000.0000000", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, }, }, - }, - isFunded: !isMuxedAccount, - subentryCount: 0, - error: { - horizon: null, - soroban: null, - }, - }; - await route.fulfill({ json }); - }); + isFunded: !isMuxedAccount, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + await route.fulfill({ json }); + }); + }; - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -282,55 +283,61 @@ test("Send doesn't throw error when creating muxed account", async ({ }); }); -test("Send can review formatted inputs", async ({ page, extensionId }) => { +test("Send can review formatted inputs", async ({ + page, + extensionId, + context, +}) => { test.slow(); - // Override account-balances to return 0 XLM only for the muxed account address - await page.route("**/account-balances/**", async (route) => { - const url = route.request().url(); - const isMuxedAccount = url.includes( - "GCQ7EGW7VXHI4AKJAFADOIHCSK2OCVA42KUETUK5LQ3LVSEQEEKP7O7B", - ); - - const json = { - balances: { - native: { - token: { - type: "native", - code: "XLM", - }, - total: isMuxedAccount ? "0" : "10000.0000000", - available: isMuxedAccount ? "0" : "10000.0000000", - sellingLiabilities: "0", - buyingLiabilities: "0", - minimumBalance: "1", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", + const stubOverrides = async () => { + // Override account-balances to return 0 XLM only for the muxed account address + await page.route("**/account-balances/**", async (route) => { + const url = route.request().url(); + const isMuxedAccount = url.includes( + "GCQ7EGW7VXHI4AKJAFADOIHCSK2OCVA42KUETUK5LQ3LVSEQEEKP7O7B", + ); + + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: isMuxedAccount ? "0" : "10000.0000000", + available: isMuxedAccount ? "0" : "10000.0000000", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", + }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, }, }, - }, - isFunded: !isMuxedAccount, - subentryCount: 0, - error: { - horizon: null, - soroban: null, - }, - }; - await route.fulfill({ json }); - }); + isFunded: !isMuxedAccount, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + await route.fulfill({ json }); + }); + }; - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -355,9 +362,9 @@ test("Send can review formatted inputs", async ({ page, extensionId }) => { }); }); -test.fixme("Send SAC to C address", async ({ page, extensionId }) => { +test.fixme("Send SAC to C address", async ({ page, extensionId, context }) => { test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); // add USDC asset await page.getByTestId("account-options-dropdown").click(); @@ -457,14 +464,10 @@ test.fixme("Send SAC to C address", async ({ page, extensionId }) => { test("SendPayment persists amount and asset when navigating to choose address", async ({ page, extensionId, + context, }) => { - await stubTokenDetails(page); - await stubAccountBalancesWithUSDC(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -483,14 +486,10 @@ test("SendPayment persists amount and asset when navigating to choose address", test("SendPayment resets amount when user selects new asset", async ({ page, extensionId, + context, }) => { - await stubTokenDetails(page); - await stubAccountBalancesWithUSDC(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -508,14 +507,10 @@ test("SendPayment resets amount when user selects new asset", async ({ test("SendPayment resets state when navigating back to account", async ({ page, extensionId, + context, }) => { - await stubTokenDetails(page); - await stubAccountBalancesWithUSDC(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -545,14 +540,10 @@ test("SendPayment resets state when navigating back to account", async ({ test("Swap persists amount when navigating to choose source asset", async ({ page, extensionId, + context, }) => { - await stubTokenDetails(page); - await stubAccountBalancesWithUSDC(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-swap").click(); await expect(page.getByTestId("AppHeaderPageTitle")).toContainText("Swap"); @@ -573,14 +564,10 @@ test("Swap persists amount when navigating to choose source asset", async ({ test("Swap resets amount when user selects new source asset", async ({ page, extensionId, + context, }) => { - await stubTokenDetails(page); - await stubAccountBalancesWithUSDC(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-swap").click(); await expect(page.getByTestId("AppHeaderPageTitle")).toContainText("Swap"); @@ -599,14 +586,10 @@ test("Swap resets amount when user selects new source asset", async ({ test("Swap preserves amount when selecting destination asset", async ({ page, extensionId, + context, }) => { - await stubTokenDetails(page); - await stubAccountBalancesWithUSDC(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-swap").click(); await expect(page.getByTestId("AppHeaderPageTitle")).toContainText("Swap"); @@ -625,14 +608,10 @@ test("Swap preserves amount when selecting destination asset", async ({ test("Swap resets state when navigating back to account", async ({ page, extensionId, + context, }) => { - await stubTokenDetails(page); - await stubAccountBalancesWithUSDC(page); - await stubAccountHistory(page); - await stubTokenPrices(page); - test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-swap").click(); await expect(page.getByTestId("AppHeaderPageTitle")).toContainText("Swap"); @@ -660,14 +639,14 @@ test("Swap resets state when navigating back to account", async ({ await expect(page.getByTestId("swap-src-asset-tile")).toContainText("XLM"); }); -test.afterAll(async ({ page, extensionId }) => { +test.afterAll(async ({ page, extensionId, context }) => { if ( test.info().status !== test.info().expectedStatus && test.info().title === "Send SAC to C address" ) { // remove trustline in cleanup if Send SAC to C address test failed test.slow(); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Manage assets").click({ force: true }); @@ -680,17 +659,18 @@ test.afterAll(async ({ page, extensionId }) => { } }); -test("Send token payment from Asset Detail", async ({ page, extensionId }) => { +test("Send token payment from Asset Detail", async ({ + page, + extensionId, + context, +}) => { test.slow(); - - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); + const stubOverrides = async () => { + await stubAccountBalancesE2e(page); + }; await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByText("E2E").click(); await page.getByTestId("asset-detail-send-button").click(); @@ -726,17 +706,18 @@ test("Send token payment from Asset Detail", async ({ page, extensionId }) => { await expect(page.getByTestId("SubmitAction")).toBeEnabled(); }); -test("Send XLM payment from Asset Detail", async ({ page, extensionId }) => { +test("Send XLM payment from Asset Detail", async ({ + page, + extensionId, + context, +}) => { test.slow(); - - await stubAccountBalancesE2e(page); - await stubAccountHistory(page); - await stubTokenDetails(page); - await stubTokenPrices(page); - await stubSimulateTokenTransfer(page); + const stubOverrides = async () => { + await stubAccountBalancesE2e(page); + }; await stubContractSpec(page, TEST_TOKEN_ADDRESS, true); - await loginToTestAccount({ page, extensionId }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByText("XLM").click(); await page.getByTestId("asset-detail-send-button").click(); From bd022aec45bbaa4fb9e2fde7a86e30e7d88c8118 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 12:42:45 -0500 Subject: [PATCH 13/29] try just 2 test --- extension/e2e-tests/accountHistory.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extension/e2e-tests/accountHistory.test.ts b/extension/e2e-tests/accountHistory.test.ts index 71f8a5d7b0..969a4ccd9b 100644 --- a/extension/e2e-tests/accountHistory.test.ts +++ b/extension/e2e-tests/accountHistory.test.ts @@ -11,7 +11,7 @@ import { Memo, } from "stellar-sdk"; -test("View Account History", async ({ page, extensionId, context }) => { +test.only("View Account History", async ({ page, extensionId, context }) => { await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-account-history").click(); @@ -22,7 +22,7 @@ test("View Account History", async ({ page, extensionId, context }) => { }); }); -test("View failed transaction", async ({ page, extensionId, context }) => { +test.only("View failed transaction", async ({ page, extensionId, context }) => { const stubOverrides = async () => { await page.route("*/**/account-history/*", async (route) => { const json = [ From 2c530838f50db3b2d55d3fecc0114a7cf77c0dd4 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 12:48:19 -0500 Subject: [PATCH 14/29] try a few more --- extension/e2e-tests/accountHistory.test.ts | 6 +++--- extension/playwright.config.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extension/e2e-tests/accountHistory.test.ts b/extension/e2e-tests/accountHistory.test.ts index 969a4ccd9b..70ea861323 100644 --- a/extension/e2e-tests/accountHistory.test.ts +++ b/extension/e2e-tests/accountHistory.test.ts @@ -70,7 +70,7 @@ test.only("View failed transaction", async ({ page, extensionId, context }) => { screenshot: "failed-transaction.png", }); }); -test("Hide create claimable balance spam", async ({ +test.only("Hide create claimable balance spam", async ({ page, extensionId, context, @@ -166,7 +166,7 @@ test("Hide create claimable balance spam", async ({ await expect(historyItems).toHaveCount(2); }); -test("History row displays muxed address extracted from XDR for payment", async ({ +test.only("History row displays muxed address extracted from XDR for payment", async ({ page, extensionId, context, @@ -349,7 +349,7 @@ test.skip("History row displays address extracted from XDR for createAccount", a ).toBeVisible({ timeout: 10000 }); }); -test("History row displays regular G address when no muxed address in XDR", async ({ +test.only("History row displays regular G address when no muxed address in XDR", async ({ page, extensionId, context, diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 9c99512eed..527e92ca37 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ /* Fail the build if any test fails after retries */ maxFailures: 1, /* In integration mode, run tests sequentially to avoid conflicts */ - workers: process.env.IS_INTEGRATION_MODE ? 1 : 8, + workers: process.env.IS_INTEGRATION_MODE ? 1 : 1, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "list", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ From 0c3207832a06c514b891e42cc1c293279fd2ed58 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 12:53:48 -0500 Subject: [PATCH 15/29] try tests with ai tips --- extension/e2e-tests/accountHistory.test.ts | 10 +++++----- extension/e2e-tests/test-fixtures.ts | 10 ++++++++++ extension/playwright.config.ts | 3 +++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/extension/e2e-tests/accountHistory.test.ts b/extension/e2e-tests/accountHistory.test.ts index 70ea861323..71f8a5d7b0 100644 --- a/extension/e2e-tests/accountHistory.test.ts +++ b/extension/e2e-tests/accountHistory.test.ts @@ -11,7 +11,7 @@ import { Memo, } from "stellar-sdk"; -test.only("View Account History", async ({ page, extensionId, context }) => { +test("View Account History", async ({ page, extensionId, context }) => { await loginToTestAccount({ page, extensionId, context }); await page.getByTestId("nav-link-account-history").click(); @@ -22,7 +22,7 @@ test.only("View Account History", async ({ page, extensionId, context }) => { }); }); -test.only("View failed transaction", async ({ page, extensionId, context }) => { +test("View failed transaction", async ({ page, extensionId, context }) => { const stubOverrides = async () => { await page.route("*/**/account-history/*", async (route) => { const json = [ @@ -70,7 +70,7 @@ test.only("View failed transaction", async ({ page, extensionId, context }) => { screenshot: "failed-transaction.png", }); }); -test.only("Hide create claimable balance spam", async ({ +test("Hide create claimable balance spam", async ({ page, extensionId, context, @@ -166,7 +166,7 @@ test.only("Hide create claimable balance spam", async ({ await expect(historyItems).toHaveCount(2); }); -test.only("History row displays muxed address extracted from XDR for payment", async ({ +test("History row displays muxed address extracted from XDR for payment", async ({ page, extensionId, context, @@ -349,7 +349,7 @@ test.skip("History row displays address extracted from XDR for createAccount", a ).toBeVisible({ timeout: 10000 }); }); -test.only("History row displays regular G address when no muxed address in XDR", async ({ +test("History row displays regular G address when no muxed address in XDR", async ({ page, extensionId, context, diff --git a/extension/e2e-tests/test-fixtures.ts b/extension/e2e-tests/test-fixtures.ts index 655622b2fa..5bebbc6bcb 100644 --- a/extension/e2e-tests/test-fixtures.ts +++ b/extension/e2e-tests/test-fixtures.ts @@ -79,6 +79,16 @@ export const test = base.extend<{ }, }); +test.afterEach(async ({ page, context }) => { + // Clean up all route handlers to avoid teardown timeout issues + try { + await page.unroute("**/*"); + await context.unroute("**/*"); + } catch (e) { + // Silently ignore errors during cleanup + } +}); + export const expectPageToHaveScreenshot = async ( { page, diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 527e92ca37..96c73e4d44 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -21,6 +21,9 @@ export default defineConfig({ maxFailures: 1, /* In integration mode, run tests sequentially to avoid conflicts */ workers: process.env.IS_INTEGRATION_MODE ? 1 : 1, + /* Increase worker teardown timeout to handle route cleanup */ + webServer: undefined, + globalTimeout: process.env.CI ? 3600000 : 600000, // 1 hour on CI, 10 min locally /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "list", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ From 2aa17e0bae70e9f48079e4eccbe8bd0e385b421b Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 13:01:11 -0500 Subject: [PATCH 16/29] can we use multiple workers --- extension/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 96c73e4d44..0f065b0ee2 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ /* Fail the build if any test fails after retries */ maxFailures: 1, /* In integration mode, run tests sequentially to avoid conflicts */ - workers: process.env.IS_INTEGRATION_MODE ? 1 : 1, + workers: process.env.IS_INTEGRATION_MODE ? 1 : 8, /* Increase worker teardown timeout to handle route cleanup */ webServer: undefined, globalTimeout: process.env.CI ? 3600000 : 600000, // 1 hour on CI, 10 min locally From a8a50910fbd84dc3856481ddcc2b20c7dc3ca748 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 13:10:12 -0500 Subject: [PATCH 17/29] reduce workers --- extension/e2e-tests/test-fixtures.ts | 8 ++++++++ extension/playwright.config.ts | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/extension/e2e-tests/test-fixtures.ts b/extension/e2e-tests/test-fixtures.ts index 5bebbc6bcb..a1790cc916 100644 --- a/extension/e2e-tests/test-fixtures.ts +++ b/extension/e2e-tests/test-fixtures.ts @@ -84,6 +84,14 @@ test.afterEach(async ({ page, context }) => { try { await page.unroute("**/*"); await context.unroute("**/*"); + const pages = context.pages(); + await Promise.all( + pages.map(async (p) => { + if (!p.isClosed()) { + await p.close(); + } + }), + ); } catch (e) { // Silently ignore errors during cleanup } diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 0f065b0ee2..53ac945bdd 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -10,7 +10,7 @@ import { defineConfig, devices } from "@playwright/test"; * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - timeout: 15000, + timeout: process.env.CI ? 30000 : 15000, testDir: "./e2e-tests", /* Run tests in files in parallel */ fullyParallel: true, @@ -20,7 +20,7 @@ export default defineConfig({ /* Fail the build if any test fails after retries */ maxFailures: 1, /* In integration mode, run tests sequentially to avoid conflicts */ - workers: process.env.IS_INTEGRATION_MODE ? 1 : 8, + workers: process.env.IS_INTEGRATION_MODE ? 1 : process.env.CI ? 2 : 8, /* Increase worker teardown timeout to handle route cleanup */ webServer: undefined, globalTimeout: process.env.CI ? 3600000 : 600000, // 1 hour on CI, 10 min locally From e900ebcd32646aa95f1912b24473e05fb4352a50 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 13:22:20 -0500 Subject: [PATCH 18/29] try 3 workers --- extension/playwright.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 53ac945bdd..f02697ded2 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -15,12 +15,12 @@ export default defineConfig({ /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: false, + forbidOnly: true, retries: 3, /* Fail the build if any test fails after retries */ maxFailures: 1, /* In integration mode, run tests sequentially to avoid conflicts */ - workers: process.env.IS_INTEGRATION_MODE ? 1 : process.env.CI ? 2 : 8, + workers: process.env.IS_INTEGRATION_MODE ? 1 : process.env.CI ? 3 : 8, /* Increase worker teardown timeout to handle route cleanup */ webServer: undefined, globalTimeout: process.env.CI ? 3600000 : 600000, // 1 hour on CI, 10 min locally From 10713d13e84edc79aa0385ed861c0110ec327732 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 13:33:55 -0500 Subject: [PATCH 19/29] try larger machine --- .github/workflows/runTests.yml | 2 +- extension/playwright.config.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/runTests.yml b/.github/workflows/runTests.yml index fa83022c5f..a5c61f038f 100644 --- a/.github/workflows/runTests.yml +++ b/.github/workflows/runTests.yml @@ -9,7 +9,7 @@ jobs: test-ci: name: test timeout-minutes: 45 - runs-on: macos-latest + runs-on: macos-latest-large steps: - uses: actions/checkout@v6 with: diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index f02697ded2..4352e5180d 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -16,7 +16,7 @@ export default defineConfig({ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: true, - retries: 3, + retries: 5, /* Fail the build if any test fails after retries */ maxFailures: 1, /* In integration mode, run tests sequentially to avoid conflicts */ From ca57acf3f465e9a67810f8c7c0891578f12c6cb1 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 13:47:53 -0500 Subject: [PATCH 20/29] try more workers and fix flake --- extension/e2e-tests/onboarding.test.ts | 16 +++++++++------- extension/playwright.config.ts | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/extension/e2e-tests/onboarding.test.ts b/extension/e2e-tests/onboarding.test.ts index 6872841f8a..f72b50bd16 100644 --- a/extension/e2e-tests/onboarding.test.ts +++ b/extension/e2e-tests/onboarding.test.ts @@ -743,17 +743,19 @@ test("Switch mnemonic phrase length preserves previous state (pw + ToS)", async await startImportWalletFlow({ page, password: PASSWORD_TEST }); const toggleLabel = page.locator('label[for="RecoverAccount__toggle"]'); - await toggleLabel.click(); + const input12 = page.locator('input[name="MnemonicPhrase-12"]'); + const input13 = page.locator('input[name="MnemonicPhrase-13"]'); - await page - .locator('input[name="MnemonicPhrase-13"]') - .waitFor({ state: "visible" }); + await expect(toggleLabel).toBeVisible(); + await expect(input12).toBeVisible(); + await expect(input13).toBeHidden(); await toggleLabel.click(); + await expect(input13).toBeVisible(); - await page - .locator('input[name="MnemonicPhrase-12"]') - .waitFor({ state: "visible" }); + await toggleLabel.click(); + await expect(input13).toBeHidden(); + await expect(input12).toBeVisible(); await fillMnemonicInputs({ page, words: TEST_MNEMONIC_12_WORDS }); diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 4352e5180d..9e6a4a5c46 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ /* Fail the build if any test fails after retries */ maxFailures: 1, /* In integration mode, run tests sequentially to avoid conflicts */ - workers: process.env.IS_INTEGRATION_MODE ? 1 : process.env.CI ? 3 : 8, + workers: process.env.IS_INTEGRATION_MODE ? 1 : process.env.CI ? 8 : 8, /* Increase worker teardown timeout to handle route cleanup */ webServer: undefined, globalTimeout: process.env.CI ? 3600000 : 600000, // 1 hour on CI, 10 min locally From 182f180fc90cf4fd2568bb9d8c1fa25af79b0bc0 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 13:54:26 -0500 Subject: [PATCH 21/29] 5 workers --- extension/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 9e6a4a5c46..16ec358444 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -20,7 +20,7 @@ export default defineConfig({ /* Fail the build if any test fails after retries */ maxFailures: 1, /* In integration mode, run tests sequentially to avoid conflicts */ - workers: process.env.IS_INTEGRATION_MODE ? 1 : process.env.CI ? 8 : 8, + workers: process.env.IS_INTEGRATION_MODE ? 1 : process.env.CI ? 5 : 8, /* Increase worker teardown timeout to handle route cleanup */ webServer: undefined, globalTimeout: process.env.CI ? 3600000 : 600000, // 1 hour on CI, 10 min locally From 36ba570abac664a5958f76baf862ff7bc607ec7a Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 14:23:36 -0500 Subject: [PATCH 22/29] readd stubs; decrease workers --- .github/workflows/copilot-setup-steps.yml | 34 ----------------------- .github/workflows/runTests.yml | 2 +- extension/e2e-tests/sendPayment.test.ts | 25 +++++++++++++---- extension/playwright.config.ts | 4 +-- specs/README.md | 3 -- 5 files changed, 23 insertions(+), 45 deletions(-) delete mode 100644 .github/workflows/copilot-setup-steps.yml delete mode 100644 specs/README.md diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml deleted file mode 100644 index cf98aff97e..0000000000 --- a/.github/workflows/copilot-setup-steps.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: "Copilot Setup Steps" - -on: - workflow_dispatch: - push: - paths: - - .github/workflows/copilot-setup-steps.yml - pull_request: - paths: - - .github/workflows/copilot-setup-steps.yml - -jobs: - copilot-setup-steps: - runs-on: ubuntu-latest - - permissions: - contents: read - - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-node@v4 - with: - node-version: lts/* - - - name: Install dependencies - run: npm ci - - - name: Install Playwright Browsers - run: npx playwright install --with-deps - - # Customize this step as needed - - name: Build application - run: npx run build diff --git a/.github/workflows/runTests.yml b/.github/workflows/runTests.yml index a5c61f038f..8c3f8b04cc 100644 --- a/.github/workflows/runTests.yml +++ b/.github/workflows/runTests.yml @@ -9,7 +9,7 @@ jobs: test-ci: name: test timeout-minutes: 45 - runs-on: macos-latest-large + runs-on: macos-latest-xlarge steps: - uses: actions/checkout@v6 with: diff --git a/extension/e2e-tests/sendPayment.test.ts b/extension/e2e-tests/sendPayment.test.ts index 38103b9fad..15aeee0b43 100644 --- a/extension/e2e-tests/sendPayment.test.ts +++ b/extension/e2e-tests/sendPayment.test.ts @@ -489,7 +489,10 @@ test("SendPayment resets amount when user selects new asset", async ({ context, }) => { test.slow(); - await loginToTestAccount({ page, extensionId, context }); + const stubOverrides = async () => { + await stubAccountBalancesWithUSDC(page); + }; + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -510,7 +513,10 @@ test("SendPayment resets state when navigating back to account", async ({ context, }) => { test.slow(); - await loginToTestAccount({ page, extensionId, context }); + const stubOverrides = async () => { + await stubAccountBalancesWithUSDC(page); + }; + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -567,7 +573,10 @@ test("Swap resets amount when user selects new source asset", async ({ context, }) => { test.slow(); - await loginToTestAccount({ page, extensionId, context }); + const stubOverrides = async () => { + await stubAccountBalancesWithUSDC(page); + }; + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-swap").click(); await expect(page.getByTestId("AppHeaderPageTitle")).toContainText("Swap"); @@ -589,7 +598,10 @@ test("Swap preserves amount when selecting destination asset", async ({ context, }) => { test.slow(); - await loginToTestAccount({ page, extensionId, context }); + const stubOverrides = async () => { + await stubAccountBalancesWithUSDC(page); + }; + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-swap").click(); await expect(page.getByTestId("AppHeaderPageTitle")).toContainText("Swap"); @@ -611,7 +623,10 @@ test("Swap resets state when navigating back to account", async ({ context, }) => { test.slow(); - await loginToTestAccount({ page, extensionId, context }); + const stubOverrides = async () => { + await stubAccountBalancesWithUSDC(page); + }; + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-swap").click(); await expect(page.getByTestId("AppHeaderPageTitle")).toContainText("Swap"); diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index 16ec358444..f97f035806 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -10,7 +10,7 @@ import { defineConfig, devices } from "@playwright/test"; * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ - timeout: process.env.CI ? 30000 : 15000, + timeout: 15000, testDir: "./e2e-tests", /* Run tests in files in parallel */ fullyParallel: true, @@ -20,7 +20,7 @@ export default defineConfig({ /* Fail the build if any test fails after retries */ maxFailures: 1, /* In integration mode, run tests sequentially to avoid conflicts */ - workers: process.env.IS_INTEGRATION_MODE ? 1 : process.env.CI ? 5 : 8, + workers: process.env.IS_INTEGRATION_MODE ? 1 : process.env.CI ? 4 : 8, /* Increase worker teardown timeout to handle route cleanup */ webServer: undefined, globalTimeout: process.env.CI ? 3600000 : 600000, // 1 hour on CI, 10 min locally diff --git a/specs/README.md b/specs/README.md deleted file mode 100644 index 48a788b139..0000000000 --- a/specs/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Specs - -This is a directory for test plans. From e783833216a83c33ccabb756ed389f840c4f0032 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 15:22:51 -0500 Subject: [PATCH 23/29] rm unused imports --- .../integration-tests/freighterApiIntegration.test.ts | 4 ---- extension/e2e-tests/sendPayment.test.ts | 4 ---- 2 files changed, 8 deletions(-) diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts index c9654f92e6..a3c55b1dba 100644 --- a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts @@ -4,11 +4,7 @@ import { loginToTestAccount } from "../helpers/login"; import { allowDapp } from "../helpers/allowDapp"; import { stubAccountBalances, - stubAccountHistory, stubIsSac, - stubScanDapp, - stubTokenDetails, - stubTokenPrices, stubAllExternalApis, } from "../helpers/stubs"; diff --git a/extension/e2e-tests/sendPayment.test.ts b/extension/e2e-tests/sendPayment.test.ts index 15aeee0b43..f81bf5f580 100644 --- a/extension/e2e-tests/sendPayment.test.ts +++ b/extension/e2e-tests/sendPayment.test.ts @@ -4,10 +4,6 @@ import { TEST_TOKEN_ADDRESS } from "./helpers/test-token"; import { stubAccountBalancesE2e, stubAccountBalancesWithUSDC, - stubAccountHistory, - stubTokenDetails, - stubTokenPrices, - stubSimulateTokenTransfer, stubContractSpec, } from "./helpers/stubs"; From 65d7633874e9795df912400baba2131a7dd23751 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 15:43:05 -0500 Subject: [PATCH 24/29] fix integration tests --- extension/e2e-tests/helpers/login.ts | 15 +- .../e2e-tests/integration-tests/README.md | 1 + .../addAssetIntegration.test.ts | 12 +- .../freighterApiIntegration.test.ts | 32 ++- .../integration-tests/sendIntegration.test.ts | 193 +++++++++--------- 5 files changed, 136 insertions(+), 117 deletions(-) diff --git a/extension/e2e-tests/helpers/login.ts b/extension/e2e-tests/helpers/login.ts index c61d238b2a..caa54001bb 100644 --- a/extension/e2e-tests/helpers/login.ts +++ b/extension/e2e-tests/helpers/login.ts @@ -7,6 +7,9 @@ const { generateMnemonic } = StellarHDWallet; export const PASSWORD = "My-password123"; +/** + * Creates a new wallet and logs into the extension on Test Net. + */ export const login = async ({ page, extensionId, @@ -62,6 +65,9 @@ export const login = async ({ }); }; +/** + * Logs in using `login()` and funds the account via Friendbot. + */ export const loginAndFund = async ({ page, extensionId, @@ -82,19 +88,26 @@ export const loginAndFund = async ({ }); }; +/** + * Logs into a deterministic test account, optionally stubbing external APIs. + * + * Use `isIntegrationMode` to avoid stubbing in integration runs. + */ export const loginToTestAccount = async ({ page, extensionId, context, stubOverrides, + isIntegrationMode = false, }: { page: Page; extensionId: string; context: BrowserContext; stubOverrides?: () => Promise; + isIntegrationMode?: boolean; }) => { await page.goto(`chrome-extension://${extensionId}/index.html`); - if (context) { + if (context && !isIntegrationMode) { // Wait for any background activity to complete await stubAllExternalApis(page, context); if (stubOverrides) { diff --git a/extension/e2e-tests/integration-tests/README.md b/extension/e2e-tests/integration-tests/README.md index d0b7fcf06d..24b4dd0c54 100644 --- a/extension/e2e-tests/integration-tests/README.md +++ b/extension/e2e-tests/integration-tests/README.md @@ -35,6 +35,7 @@ All tests in this folder must pass in **both scenarios**: - Real fee stats, account balances, and transaction data - Real network responses and delays - Account must be funded and in valid state + - Recognize that real data means these tests will inheritly be more flakey than stubbed tests ## Files diff --git a/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts b/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts index f30865e2c8..3c86abfc50 100644 --- a/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/addAssetIntegration.test.ts @@ -9,13 +9,15 @@ import { TEST_TOKEN_ADDRESS } from "../helpers/test-token"; // } // }); +const isIntegrationMode = process.env.IS_INTEGRATION_MODE === "true"; + test("Adding classic asset on Testnet", async ({ page, extensionId, context, }) => { test.slow(); - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Manage assets").click(); @@ -41,7 +43,7 @@ test("Adding classic asset on Testnet", async ({ await page.getByRole("button", { name: "Confirm" }).click(); await expect(page.getByText("Done")).toBeVisible(); - if (process.env.IS_INTEGRATION_MODE) { + if (isIntegrationMode) { // if we're running in integration mode, verify the asset was actually added await page.getByText("Done").click(); await expect( @@ -81,7 +83,7 @@ test("Adding and removing unverified Soroban token", async ({ extensionId, context, }) => { - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Manage assets").click(); @@ -127,7 +129,7 @@ test("Adding and removing unverified Soroban token", async ({ ); await page.getByRole("button", { name: "Confirm" }).click(); - if (process.env.IS_INTEGRATION_MODE) { + if (isIntegrationMode) { // if we're running in integration mode, verify the asset was actually added await expect( page.getByTestId("ManageAssetRowButton__ellipsis-E2E"), @@ -166,7 +168,7 @@ test("Adding and removing unverified Soroban token", async ({ test.afterAll(async ({ page, extensionId, context }) => { if ( - process.env.IS_INTEGRATION_MODE && + isIntegrationMode && test.info().status !== test.info().expectedStatus && test.info().title === "Adding classic asset on Testnet" ) { diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts index a3c55b1dba..12893c663f 100644 --- a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts @@ -42,18 +42,14 @@ const JSON_MSG_TO_SIGN = JSON.stringify({ const JSON_SIGNED_MSG = '\"42IH7/mvkAT+ltbEG8oEPhVBzP7hb6NU+P+WZP3j1AIMdbwuFPrzBuRFRvLjXdXl5lDmC7aL0zrZIUrfrMXHDw==\"'; -test.beforeEach(async ({ page, context }) => { - if (!process.env.IS_INTEGRATION_MODE) { - await stubAllExternalApis(page, context); - } -}); +const isIntegrationMode = process.env.IS_INTEGRATION_MODE === "true"; test("should sign transaction when allowed", async ({ page, extensionId, context, }) => { - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -256,7 +252,7 @@ test("should sign auth entry when allowed", async ({ extensionId, context, }) => { - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -298,7 +294,7 @@ test("should not sign auth entry when not allowed", async ({ extensionId, context, }) => { - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); // open a second tab and go to docs playground const pageTwo = await page.context().newPage(); @@ -328,7 +324,7 @@ test("should sign auth entry for a selected account when allowed", async ({ extensionId, context, }) => { - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await allowDapp({ page }); @@ -376,7 +372,7 @@ test("should sign message string when allowed", async ({ extensionId, context, }) => { - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -452,7 +448,7 @@ test("should sign message json when allowed", async ({ extensionId, context, }) => { - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -500,7 +496,7 @@ test("should sign message for a specific account when allowed", async ({ extensionId, context, }) => { - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -545,7 +541,7 @@ test("should not sign message when not allowed", async ({ extensionId, context, }) => { - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); // open a second tab and go to docs playground const pageTwo = await page.context().newPage(); @@ -572,7 +568,7 @@ test("should add token when allowed", async ({ }) => { await stubIsSac(context); - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await allowDapp({ page }); // open a second tab and go to docs playground @@ -607,9 +603,11 @@ test("should not add token when not allowed", async ({ extensionId, context, }) => { - await stubIsSac(context); + if (!isIntegrationMode) { + await stubIsSac(context); + } - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); // open a second tab and go to docs playground const pageTwo = await page.context().newPage(); @@ -643,7 +641,7 @@ test("should get public key when logged out", async ({ extensionId, context, }) => { - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await page.getByTestId("account-options-dropdown").click(); await page.getByText("Settings").click(); await page.getByText("Log Out").click(); diff --git a/extension/e2e-tests/integration-tests/sendIntegration.test.ts b/extension/e2e-tests/integration-tests/sendIntegration.test.ts index 6ac90e42ba..66d1e3cdd5 100644 --- a/extension/e2e-tests/integration-tests/sendIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/sendIntegration.test.ts @@ -3,11 +3,7 @@ import { test, expect } from "../test-fixtures"; import { loginToTestAccount } from "../helpers/login"; import { TEST_M_ADDRESS, TEST_TOKEN_ADDRESS } from "../helpers/test-token"; -// test.beforeEach(async ({ page, context }) => { -// if (!process.env.IS_INTEGRATION_MODE) { -// await stubAllExternalApis(page, context); -// } -// }); +const isIntegrationMode = process.env.IS_INTEGRATION_MODE === "true"; test("Send persists inputs and submits to network", async ({ page, @@ -17,32 +13,37 @@ test("Send persists inputs and submits to network", async ({ test.slow(); let isScanSkiped = false; - const stubOverrides = async () => { - if (!process.env.IS_INTEGRATION_MODE) { - await page.route("**/submit-tx", async (route) => { - const json = { - memo: "test memo", - max_fee: "900", - envelope_xdr: - "AAAAAgAAAADLvQoIbFw9k0tgjZoOrLTuJJY9kHFYp/YAEAlt/xirbAAAA4QAAAUVAAAAvgAAAAEAAAAAAAAAAAAAAABper1qAAAAAQAAAAl0ZXN0IG1lbW8AAAAAAAABAAAAAAAAAAEAAAAAZ4AU5m5lMnKhtnADB3KJkkfNHUcxrSs8TOoG98skg+QAAAAAAAAAAACYloAAAAAAAAAAAf8Yq2wAAABApUEUNnMHzyHA+ZclMfxsX1vv5wfoKegPYhxYnOuiSgit7kCLrVcahgbHAnvb0H+SM0PlZwOxEuaeBJA/B7GdAg==", - - successful: true, - }; - await route.fulfill({ json }); - }); + page.on("request", (request) => { + if ( + request + .url() + .includes("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF") + ) { + isScanSkiped = request.url().includes("should_skip_scan=true"); } - page.on("request", (request) => { - if ( - request - .url() - .includes("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF") - ) { - isScanSkiped = request.url().includes("should_skip_scan=true"); - } + }); + + const stubOverrides = async () => { + await page.route("**/submit-tx", async (route) => { + const json = { + memo: "test memo", + max_fee: "900", + envelope_xdr: + "AAAAAgAAAADLvQoIbFw9k0tgjZoOrLTuJJY9kHFYp/YAEAlt/xirbAAAA4QAAAUVAAAAvgAAAAEAAAAAAAAAAAAAAABper1qAAAAAQAAAAl0ZXN0IG1lbW8AAAAAAAABAAAAAAAAAAEAAAAAZ4AU5m5lMnKhtnADB3KJkkfNHUcxrSs8TOoG98skg+QAAAAAAAAAAACYloAAAAAAAAAAAf8Yq2wAAABApUEUNnMHzyHA+ZclMfxsX1vv5wfoKegPYhxYnOuiSgit7kCLrVcahgbHAnvb0H+SM0PlZwOxEuaeBJA/B7GdAg==", + + successful: true, + }; + await route.fulfill({ json }); }); }; - await loginToTestAccount({ page, extensionId, context, stubOverrides }); + await loginToTestAccount({ + page, + extensionId, + context, + stubOverrides, + isIntegrationMode, + }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -133,7 +134,7 @@ test("Send XLM payments to recent federated addresses", async ({ context, }) => { test.slow(); - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await page.getByTestId("nav-link-send").click({ force: true }); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); @@ -210,7 +211,7 @@ test("Send XLM payment to C address", async ({ context, }) => { test.slow(); - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await page.getByTestId("nav-link-send").click({ force: true }); @@ -254,7 +255,7 @@ test("Send XLM payment to M address", async ({ context, }) => { test.slow(); - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, isIntegrationMode }); await page.getByTestId("nav-link-send").click({ force: true }); @@ -301,78 +302,82 @@ test("Send token payment to C address", async ({ }) => { test.slow(); const stubOverrides = async () => { - if (!process.env.IS_INTEGRATION_MODE) { - await page.route("**/account-balances/**", async (route) => { - const json = { - balances: { - native: { - token: { - type: "native", - code: "XLM", - }, - total: "10000.0000000", - available: "10000.0000000", - sellingLiabilities: "0", - buyingLiabilities: "0", - minimumBalance: "1", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", - }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, + await page.route("**/account-balances/**", async (route) => { + const json = { + balances: { + native: { + token: { + type: "native", + code: "XLM", + }, + total: "10000.0000000", + available: "10000.0000000", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "1", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, }, - [`E2E:${TEST_TOKEN_ADDRESS}`]: { - token: { - code: "E2E", - issuer: { - key: TEST_TOKEN_ADDRESS, - }, + }, + [`E2E:${TEST_TOKEN_ADDRESS}`]: { + token: { + code: "E2E", + issuer: { + key: TEST_TOKEN_ADDRESS, }, - contractId: TEST_TOKEN_ADDRESS, - total: "500.0000000", - available: "500.0000000", - sellingLiabilities: "0", - buyingLiabilities: "0", - minimumBalance: "0.5", - blockaidData: { - result_type: "Benign", - malicious_score: "0.0", - attack_types: {}, - chain: "stellar", - address: "", - metadata: { - type: "", - }, - fees: {}, - features: [], - trading_limits: {}, - financial_stats: {}, + }, + contractId: TEST_TOKEN_ADDRESS, + total: "500.0000000", + available: "500.0000000", + sellingLiabilities: "0", + buyingLiabilities: "0", + minimumBalance: "0.5", + blockaidData: { + result_type: "Benign", + malicious_score: "0.0", + attack_types: {}, + chain: "stellar", + address: "", + metadata: { + type: "", }, + fees: {}, + features: [], + trading_limits: {}, + financial_stats: {}, }, }, - isFunded: true, - subentryCount: 0, - error: { - horizon: null, - soroban: null, - }, - }; - await route.fulfill({ json }); - }); - } + }, + isFunded: true, + subentryCount: 0, + error: { + horizon: null, + soroban: null, + }, + }; + await route.fulfill({ json }); + }); }; - await loginToTestAccount({ page, extensionId, context, stubOverrides }); + await loginToTestAccount({ + page, + extensionId, + context, + stubOverrides, + isIntegrationMode, + }); - if (process.env.IS_INTEGRATION_MODE) { + if (isIntegrationMode) { // in integration mode, make sure the token is added first await page.getByTestId("account-options-dropdown").click(); await page.getByText("Manage assets").click(); From f4880a9fb21a697d87c8e8c3fd3df79c1ba0fa5d Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 15:44:36 -0500 Subject: [PATCH 25/29] rm debugging stuff --- .github/workflows/runTests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/runTests.yml b/.github/workflows/runTests.yml index 8c3f8b04cc..7d3301b46c 100644 --- a/.github/workflows/runTests.yml +++ b/.github/workflows/runTests.yml @@ -61,9 +61,9 @@ jobs: - run: yarn - run: npx playwright install --with-deps chromium - run: yarn setup - # - run: yarn build:freighter-api + - run: yarn build:freighter-api - run: yarn build:extension - # - run: yarn test:ci + - run: yarn test:ci - run: ${{ github.base_ref == 'master' && 'IS_INTEGRATION_MODE=true' || '' }} yarn test:e2e From e26c9175c8d889f4713ed89f3027ca659c8ae99d Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 16:18:31 -0500 Subject: [PATCH 26/29] add better documentation --- extension/e2e-tests/helpers/login.ts | 3 ++- .../integration-tests/freighterApiIntegration.test.ts | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/extension/e2e-tests/helpers/login.ts b/extension/e2e-tests/helpers/login.ts index caa54001bb..65f55f2259 100644 --- a/extension/e2e-tests/helpers/login.ts +++ b/extension/e2e-tests/helpers/login.ts @@ -91,7 +91,8 @@ export const loginAndFund = async ({ /** * Logs into a deterministic test account, optionally stubbing external APIs. * - * Use `isIntegrationMode` to avoid stubbing in integration runs. + * @param stubOverrides - Optional function to add custom stub routes after `stubAllExternalApis` runs. + * @param isIntegrationMode - Set true to skip all stubbing for integration tests. */ export const loginToTestAccount = async ({ page, diff --git a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts index 12893c663f..c5f5e674b6 100644 --- a/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts +++ b/extension/e2e-tests/integration-tests/freighterApiIntegration.test.ts @@ -2,11 +2,7 @@ import { expect, test, expectPageToHaveScreenshot } from "../test-fixtures"; import { TEST_TOKEN_ADDRESS } from "../helpers/test-token"; import { loginToTestAccount } from "../helpers/login"; import { allowDapp } from "../helpers/allowDapp"; -import { - stubAccountBalances, - stubIsSac, - stubAllExternalApis, -} from "../helpers/stubs"; +import { stubAccountBalances, stubIsSac } from "../helpers/stubs"; const TX_TO_SIGN = "AAAAAgAAAADLvQoIbFw9k0tgjZoOrLTuJJY9kHFYp/YAEAlt/xirbAAAAGQAAAfjAAAOpQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAABngBTmbmUycqG2cAMHcomSR80dRzGtKzxM6gb3yySD5AAAAAAAAAAAAvrwgAAAAAAAAAAA"; From 445f17b2e4a4bd28c77892be7c1d755838d8be5b Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Thu, 29 Jan 2026 19:23:24 -0500 Subject: [PATCH 27/29] copilot pr comments --- extension/e2e-tests/memo.test.ts | 2 +- extension/e2e-tests/sendCollectible.test.ts | 2 +- extension/playwright.config.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/extension/e2e-tests/memo.test.ts b/extension/e2e-tests/memo.test.ts index 1aaaf6a620..1a3643826b 100644 --- a/extension/e2e-tests/memo.test.ts +++ b/extension/e2e-tests/memo.test.ts @@ -47,7 +47,7 @@ test("Send payment shows memo required warning when destination requires memo", // Wait for review sheet to open - this happens after simulation completes await expect(page.getByText("You are sending")).toBeVisible({ - timeout: 200000, + timeout: 30000, }); // Wait for the review transaction content to be ready (not in loading state) diff --git a/extension/e2e-tests/sendCollectible.test.ts b/extension/e2e-tests/sendCollectible.test.ts index 46adc0afe6..8b413f69c4 100644 --- a/extension/e2e-tests/sendCollectible.test.ts +++ b/extension/e2e-tests/sendCollectible.test.ts @@ -340,7 +340,7 @@ test("Send collectible with Soroban mux support to G address allows memo", async true, ); - await loginToTestAccount({ page, extensionId, context }); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click(); await expect(page.getByTestId("send-amount-amount-input")).toBeVisible(); diff --git a/extension/playwright.config.ts b/extension/playwright.config.ts index f97f035806..de8b053462 100644 --- a/extension/playwright.config.ts +++ b/extension/playwright.config.ts @@ -15,7 +15,7 @@ export default defineConfig({ /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: true, + forbidOnly: !!process.env.CI, retries: 5, /* Fail the build if any test fails after retries */ maxFailures: 1, From 69d53497b7d100da8170a620ef66d8c81b755223 Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Fri, 30 Jan 2026 11:11:33 -0500 Subject: [PATCH 28/29] fix flakey sendcollectibles tests --- extension/e2e-tests/sendCollectible.test.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/extension/e2e-tests/sendCollectible.test.ts b/extension/e2e-tests/sendCollectible.test.ts index 8b413f69c4..ebbb74fe79 100644 --- a/extension/e2e-tests/sendCollectible.test.ts +++ b/extension/e2e-tests/sendCollectible.test.ts @@ -17,6 +17,13 @@ test("Send collectible with metadata", async ({ await stubSimulateSendCollectible(page); }; + // Stub contract spec with muxed support = true + await stubContractSpec( + page, + "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", + true, + ); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click(); @@ -58,7 +65,7 @@ test("Send collectible with metadata", async ({ // validate that fee is updated in the review screen await expect(page.getByTestId("send-amount-fee-display")).toHaveText( - "0.00001 XLM", + "0.00002 XLM", ); await expect( @@ -93,6 +100,13 @@ test("Send collectible without metadata", async ({ await stubSimulateSendCollectible(page); }; + // Stub contract spec with muxed support = true + await stubContractSpec( + page, + "CCTYMI5ME6NFJC675P2CHNVG467YQJQ5E4TWP5RAPYYNKWK7DIUUDENN", + true, + ); + await loginToTestAccount({ page, extensionId, context, stubOverrides }); await page.getByTestId("nav-link-send").click({ force: true }); @@ -131,7 +145,7 @@ test("Send collectible without metadata", async ({ // validate that fee is updated in the review screen await expect(page.getByTestId("send-amount-fee-display")).toHaveText( - "0.00001 XLM", + "0.00002 XLM", ); await expect( From bbf8996dfd135e0eba53c6eb67c896088b95517c Mon Sep 17 00:00:00 2001 From: Piyal Basu Date: Wed, 4 Feb 2026 12:23:12 -0500 Subject: [PATCH 29/29] add readme --- extension/e2e-tests/README.md | 330 ++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 extension/e2e-tests/README.md diff --git a/extension/e2e-tests/README.md b/extension/e2e-tests/README.md new file mode 100644 index 0000000000..c88e60f92a --- /dev/null +++ b/extension/e2e-tests/README.md @@ -0,0 +1,330 @@ +# E2E Tests for Freighter Extension + +This directory contains end-to-end tests for the Freighter wallet extension using Playwright. + +## Prerequisites + +Before running the tests, ensure you have: + +1. **Node.js and Yarn**: Install dependencies from the root of the extension directory +2. **Built Extension**: The extension must be built before running tests + +## Setup + +### 1. Install Dependencies + +From the root directory: + +```bash +yarn install +``` + +### 2. Configure Backend + +If you need to test against a specific backend, create an `.env` file at `extension/.env`: + +``` +INDEXER_URL=INSERT_YOUR_INDEXER_URL_V1 +``` + +``` +INDEXER_V2_URL=INSERT_YOUR_INDEXER_URL_V2 +``` + +### 3. Build the Extension + +The tests run against the built extension in the `extension/build` directory: + +```bash +yarn build:extension +``` + +## Running Tests + +### Run All Tests + +From the root directory: + +```bash +yarn test:e2e +``` + +### Run Specific Test Files + +```bash +yarn test:e2e sendPayment.test.ts +``` + +### Run Tests in UI Mode + +Playwright provides a UI mode for debugging: + +```bash +yarn test:e2e --ui +``` + +### Run Tests in Headed Mode + +To see the browser while tests run: + +```bash +yarn test:e2e --headed +``` + +### Run Specific Tests by Name + +```bash +yarn test:e2e -g "Send doesn't throw error" +``` + +## Test Structure + +### Test Files + +- `accountHistory.test.ts` - Tests for account history and transaction viewing +- `addAsset.test.ts` - Tests for adding custom assets +- `addCollectible.test.ts` - Tests for adding NFTs/collectibles +- `allowList.test.ts` - Tests for domain allowlist functionality +- `buyWithOnramp.test.ts` - Tests for on-ramp integration +- `loadAccount.test.ts` - Tests for loading/importing accounts +- `login.test.ts` - Tests for authentication flows +- `memo.test.ts` - Tests for memo functionality in transactions +- `onboarding.test.ts` - Tests for user onboarding flow +- `sendCollectible.test.ts` - Tests for sending NFTs +- `sendPayment.test.ts` - Tests for payment functionality +- `translations-pt.test.ts` - Tests for Portuguese translations + +### Test Fixtures + +The `test-fixtures.ts` file provides custom fixtures for: + +- Browser context with extension loaded +- Extension ID extraction +- Service worker access +- Language configuration + +### Helpers + +The `helpers/` directory contains: + +- `login.ts` - Authentication helper functions +- `stubs.ts` - API mocking utilities +- `test-token.ts` - Test token constants + +## Test Configuration + +The Playwright configuration is in `extension/playwright.config.ts`: + +- **Timeout**: 15 seconds per test +- **Retries**: 5 attempts on failure +- **Workers**: 8 locally, 4 on CI +- **Browser**: Chromium only +- **Viewport**: 1280x720 + +## Debugging Tests + +### View Test Traces + +When tests fail, traces are automatically captured: + +```bash +npx playwright show-trace test-results/[test-name]/trace.zip +``` + +### Debug Mode + +Run with the Playwright Inspector: + +```bash +PWDEBUG=1 npx playwright test +``` + +### Take Screenshots on Failure + +Screenshots are automatically captured in the `test-results/` directory when tests fail. + +## Integration Mode + +For running tests sequentially (useful for tests that modify shared state): + +```bash +IS_INTEGRATION_MODE=true yarn test:e2e +``` + +## CI + +### GitHub Actions + +e2e tests are run in CI by this GitHub action workflow: https://github.com/stellar/freighter/blob/master/.github/workflows/runTests.yml + +This job runs on every commit on a PR. + +This workflow toggles IS_INTEGRATION_MODE `on` if the branch is pointing at `master` (indicating that we're getting ready to deploy to production) + +### View CI Test Trace + +In CI, if the tests fail, the GitHub Action will upload an artifact that will allow you to view a recording of what happened in the browser in CI. This link will be visible in the test run in the `Run actions/upload-artifact@v5` step. Download this artifact and unzip. + +The failed tests can be viewed using the `show-trace` command: + +```bash +npx playwright show-trace test-results/[test-name]/trace.zip +``` + +## Common Issues + +### Extension Not Loading + +- Ensure the extension is built: `yarn build` +- Check that `extension/build` directory exists + +### Test Timeouts + +- Tests are marked with `test.slow()` for operations that may take longer +- Default timeout is 15 seconds, with 5 retries + +### API Stubs Not Working + +- Check that stub functions are properly defined in test setup +- Ensure routes are registered before navigation + +## Writing New Tests + +### Basic Test Structure + +```typescript +import { test, expect, expectPageToHaveScreenshot } from "./test-fixtures"; +import { loginToTestAccount } from "./helpers/login"; + +test("My test description", async ({ page, extensionId, context }) => { + test.slow(); // If test needs more time + + // loginToTestAccount will automatically stub all API's by default + await loginToTestAccount({ page, extensionId, context }); + + // Your test code here + await page.getByTestId("my-element").click(); + await expect(page.getByText("Expected text")).toBeVisible(); +}); +``` + +### Using Stubs + +```typescript +const stubOverrides = async () => { + await stubAccountBalancesWithUSDC(page); +}; + +await loginToTestAccount({ page, extensionId, context, stubOverrides }); +``` + +## Snapshot Testing + +Snapshot tests capture visual or structural baselines of your application and compare future runs against those baselines. This helps catch unintended visual regressions. + +### Visual Snapshots + +Freighter uses the `expectPageToHaveScreenshot` function for visual snapshot testing: + +```typescript +await expectPageToHaveScreenshot({ + page, + screenshot: "my-feature.png", +}); +``` + +**Snapshot files** are stored in directories alongside test files: + +- `sendPayment.test.ts` → `sendPayment.test.ts-snapshots/` +- `addAsset.test.ts` → `addAsset.test.ts-snapshots/` + +### Updating Snapshots + +When you intentionally change the UI, update snapshots: + +```bash +yarn test:e2e --update-snapshots +``` + +Or update snapshots for a specific test: + +```bash +yarn test:e2e sendPayment.test.ts --update-snapshots +``` + +### Reviewing Snapshot Changes + +When a snapshot test fails, you can review the differences: + +1. **In the test results directory**: + + ``` + test-results/[test-name]/ + ├── expected.png (baseline snapshot) + ├── actual.png (current output) + └── diff.png (visual diff highlighting changes) + ``` + +2. **In VS Code**: Use the "Compare" feature on actual/expected/diff images + +3. **In CI**: Download the test artifacts to review snapshot diffs locally + +### Best Practices + +- **Keep snapshots focused**: Use snapshots to verify specific UI components or pages +- **Review carefully**: Always review snapshot diffs before updating to catch unintended changes +- **Commit snapshots**: Include updated snapshots in your git commits +- **Avoid flaky snapshots**: + - Mock dates/times if they appear in screenshots + - Ensure consistent asset loading states + - Use fixed viewports (Playwright provides 1280x720) +- **Document changes**: Add comments when updating snapshots for intentional UI changes + +### Example Snapshot Test + +```typescript +import { test, expect, expectPageToHaveScreenshot } from "./test-fixtures"; + +test("Send payment review screen matches snapshot", async ({ + page, + extensionId, + context, +}) => { + test.slow(); + const stubOverrides = async () => { + await stubAccountBalancesWithUSDC(page); + }; + + await loginToTestAccount({ page, extensionId, context, stubOverrides }); + + // Navigate to send flow + await page.getByTestId("nav-link-send").click(); + await page.getByTestId("send-amount-amount-input").fill("100"); + await page.getByTestId("address-tile").click(); + await page + .getByTestId("send-to-input") + .fill("GBTYAFHGNZSTE4VBWZYAGB3SRGJEPTI5I4Y22KZ4JTVAN56LESB6JZOF"); + await page.getByText("Continue").click(); + + // Capture the payment review screen + await expectPageToHaveScreenshot({ + page, + screenshot: "send-payment-review.png", + }); +}); +``` + +## CI/CD + +Tests run automatically in CI with: + +- 4 parallel workers +- 1-hour global timeout +- Fail-fast on first failure after retries +- `test.only` forbidden in CI + +## Additional Resources + +- [Playwright Documentation](https://playwright.dev/) +- [Freighter Extension README](../README.md) +- [Test Snapshots](./sendPayment.test.ts-snapshots/) - Visual regression test baselines