diff --git a/scripts/harb-evaluator/scenarios/sovereign-exit/always-leave.spec.ts b/scripts/harb-evaluator/scenarios/sovereign-exit/always-leave.spec.ts index b4c677a..389f533 100644 --- a/scripts/harb-evaluator/scenarios/sovereign-exit/always-leave.spec.ts +++ b/scripts/harb-evaluator/scenarios/sovereign-exit/always-leave.spec.ts @@ -6,8 +6,9 @@ * * Reuses tests/setup/ infrastructure — no new wallet or navigation helpers. * - * Account 5 from the Anvil test mnemonic is used so it never collides with - * the deploy scripts (which use accounts 0–1). + * Account 0 from the Anvil test mnemonic is used (same as e2e tests). + * Deploy scripts also use Account 0, but each test run gets a fresh Anvil stack, + * so no collision occurs. */ import { expect, test } from '@playwright/test'; import { Interface, Wallet } from 'ethers'; @@ -15,8 +16,8 @@ import { createWalletContext } from '../../../../tests/setup/wallet-provider'; import { getStackConfig } from '../../../../tests/setup/stack'; import { navigateSPA } from '../../../../tests/setup/navigate'; -// Anvil account 5 — never used by deploy or txnBot -const PK = '0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba'; +// Anvil account 0 — same as e2e tests (deploy uses it but state is reset per stack) +const PK = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80'; const ACCOUNT = new Wallet(PK); const ACCOUNT_ADDRESS = ACCOUNT.address; @@ -91,56 +92,80 @@ test('I can always leave', async ({ browser }) => { await page.evaluate(() => window.dispatchEvent(new Event('resize'))); await page.waitForTimeout(2_000); - // ── 2. Connect wallet via the UI ──────────────────────────────────── + // ── 2. Connect wallet via the UI (matches e2e/01 pattern) ──────────── console.log('[TEST] Connecting wallet...'); + let panelOpened = false; + const connectButton = page.locator('.connect-button--disconnected').first(); if (await connectButton.isVisible({ timeout: 5_000 })) { + console.log('[TEST] Found desktop Connect button, clicking...'); await connectButton.click(); - await page.waitForTimeout(1_000); - const connector = page.locator('.connectors-element').first(); - if (await connector.isVisible({ timeout: 5_000 })) { - await connector.click(); - await page.waitForTimeout(2_000); - } else { - console.log('[TEST] WARNING: wallet connector panel not found after clicking Connect'); - } + panelOpened = true; } else { - console.log('[TEST] Connect button not found — wallet may already be connected or UI class changed'); + const screenWidth = await page.evaluate(() => window.screen.width); + console.log(`[TEST] DEBUG: screen.width = ${screenWidth}`); + // Fallback to mobile login icon (dead code — wallet-provider always sets screen.width=1280, copied from e2e/01 for consistency) + const mobileLoginIcon = page.locator('.navbar-end svg').first(); + if (await mobileLoginIcon.isVisible({ timeout: 2_000 })) { + console.log('[TEST] Found mobile login icon, clicking...'); + await mobileLoginIcon.click(); + panelOpened = true; + } else { + console.log('[TEST] No Connect button or mobile icon — wallet may already be connected'); + } } - // Confirm wallet address is displayed in the navbar (app shows first ~6 chars) - const addrPrefix = ACCOUNT_ADDRESS.slice(0, 8); // e.g. "0x996550" + if (panelOpened) { + await page.waitForTimeout(1_000); + console.log('[TEST] Looking for wallet connector in panel...'); + const injectedConnector = page.locator('.connectors-element').first(); + if (await injectedConnector.isVisible({ timeout: 5_000 })) { + console.log('[TEST] Clicking wallet connector...'); + await injectedConnector.click(); + await page.waitForTimeout(2_000); + } else { + console.log('[TEST] WARNING: No wallet connector found in panel'); + } + } + + // Confirm wallet address is displayed in the navbar + const addrPrefix = ACCOUNT_ADDRESS.slice(0, 8); await expect(page.getByText(new RegExp(addrPrefix, 'i')).first()).toBeVisible({ timeout: 15_000 }); console.log('[TEST] Wallet connected'); - // ── 3. Navigate to get-krk and buy KRK via the swap widget ────────── - console.log('[TEST] Navigating to get-krk...'); - await navigateSPA(page, '/app/get-krk'); + // ── 3. Navigate to cheats page (has swap widget, same as e2e tests) ── + console.log('[TEST] Navigating to cheats...'); + await navigateSPA(page, '/app/cheats'); + await expect(page.getByRole('heading', { name: 'Cheat Console' })).toBeVisible({ timeout: 10_000 }); - // The LocalSwapWidget is rendered when VITE_ENABLE_LOCAL_SWAP=true - const swapInput = page.locator('#local-swap-amount'); + // The cheats page has an inline FInput with label 'ETH to spend' + const swapInput = page.getByLabel('ETH to spend'); await expect(swapInput).toBeVisible({ timeout: 15_000 }); console.log('[TEST] Swap widget visible'); const krkBefore = await getKrkBalance(config.rpcUrl, config.contracts.Kraiken, ACCOUNT_ADDRESS); console.log(`[TEST] KRK balance before buy: ${krkBefore}`); + // Use fill() which triggers input events for Vue v-model binding await swapInput.fill('0.1'); + await page.waitForTimeout(500); - const buyButton = page.locator('.local-swap-widget .swap-button'); + const buyButton = page.getByRole('button', { name: 'Buy' }).last(); await expect(buyButton).toBeVisible(); + // Debug: screenshot before clicking + await page.screenshot({ path: 'test-results/holdout-before-buy.png' }); console.log('[TEST] Clicking Buy KRK...'); await buyButton.click(); + await page.waitForTimeout(3_000); + await page.screenshot({ path: 'test-results/holdout-after-buy.png' }); - // Wait for the swap to complete (button cycles through "Submitting…" → "Buy KRK") + // Wait for the swap to complete (button cycles through "Submitting…" → "Buy") try { - await buyButton.filter({ hasText: /Submitting/i }).waitFor({ state: 'visible', timeout: 5_000 }); + await page.getByRole('button', { name: /Submitting/i }).waitFor({ state: 'visible', timeout: 5_000 }); console.log('[TEST] Swap in progress...'); - await buyButton.filter({ hasText: /Buy KRK/i }).waitFor({ state: 'visible', timeout: 60_000 }); + await page.getByRole('button', { name: 'Buy' }).last().waitFor({ state: 'visible', timeout: 60_000 }); console.log('[TEST] Swap completed'); } catch (err) { - // On a fast Anvil node the button may cycle too quickly to observe. - // Log the caught value so the root cause is visible if a real error occurred. console.log(`[TEST] Button state not observed (may be instant): ${err}`); } await page.waitForTimeout(2_000);