/* eslint-disable no-restricted-syntax -- waitForTimeout: no event source exists for Vue component animation settling and wagmi wallet connector state transitions. See AGENTS.md #Engineering Principles. */ /** * Shared wallet helpers for holdout scenarios. * * Functions here operate in the Playwright Node.js context (not the browser). * UI interactions use Playwright locators; on-chain reads use direct RPC calls * so that tests do not depend on the app's wallet state for balance queries. */ import type { Page } from '@playwright/test'; import { expect } from '@playwright/test'; import { rpcCall } from './rpc'; // ── Balance readers ────────────────────────────────────────────────────────── /** Return the native ETH balance (in wei) of `address`. */ export async function getEthBalance(rpcUrl: string, address: string): Promise { const result = (await rpcCall(rpcUrl, 'eth_getBalance', [address, 'latest'])) as string; return BigInt(result); } /** Return the ERC-20 KRK balance (in wei) of `address` on the given token contract. */ export async function getKrkBalance(rpcUrl: string, krkAddress: string, address: string): Promise { const selector = '0x70a08231'; // balanceOf(address) const data = selector + address.slice(2).padStart(64, '0'); const result = (await rpcCall(rpcUrl, 'eth_call', [{ to: krkAddress, data }, 'latest'])) as string; return BigInt(result); } // ── UI helpers ─────────────────────────────────────────────────────────────── /** * Connect the test wallet via the desktop UI flow. * * Expects the page to already be on the web app with the navbar visible. * The injected wallet provider must already be set up by createWalletContext. * Verifies connection by waiting for the connected button to appear in the navbar. */ export async function connectWallet(page: Page): Promise { // Trigger resize so Vue's useMobile composable re-evaluates with screen.width=1280. await page.evaluate(() => window.dispatchEvent(new Event('resize'))); await page.waitForTimeout(2_000); const screenWidth = await page.evaluate(() => window.screen.width); console.log(`[wallet] screen.width = ${screenWidth}`); // Check if wallet is already connected (e.g. wagmi auto-reconnected from storage) const connectedButton = page.locator('.connect-button--connected').first(); if (await connectedButton.isVisible({ timeout: 1_000 }).catch(() => false)) { console.log('[wallet] Wallet already connected (auto-reconnect)'); return; } let panelOpened = false; const connectButton = page.locator('.connect-button--disconnected').first(); if (await connectButton.isVisible({ timeout: 10_000 })) { console.log('[wallet] Found desktop Connect button, clicking...'); await connectButton.click(); panelOpened = true; } else { // Fallback: mobile login icon. Dead code when screen.width=1280 but kept for safety. const mobileLoginIcon = page.locator('.navbar-end svg').first(); if (await mobileLoginIcon.isVisible({ timeout: 2_000 })) { console.log('[wallet] Found mobile login icon, clicking...'); await mobileLoginIcon.click(); panelOpened = true; } } if (panelOpened) { await page.waitForTimeout(1_000); const injectedConnector = page.locator('.connectors-element').first(); if (await injectedConnector.isVisible({ timeout: 5_000 })) { console.log('[wallet] Clicking wallet connector...'); await injectedConnector.click(); await page.waitForTimeout(2_000); } else { console.log('[wallet] WARNING: No wallet connector found in panel'); } } // The navbar shows .connect-button--connected once wagmi reports status=connected. await expect(page.locator('.connect-button--connected').first()).toBeVisible({ timeout: 15_000 }); console.log('[wallet] Wallet connected'); } /** * Disconnect the wallet by opening the connected panel and clicking the logout icon. * * Verifies disconnection by waiting for the Connect button to reappear. */ export async function disconnectWallet(page: Page): Promise { const connectedButton = page.locator('.connect-button--connected').first(); await expect(connectedButton).toBeVisible({ timeout: 5_000 }); await connectedButton.click(); // Panel opens showing .connected-header-logout (img alt="Logout"). const logoutIcon = page.locator('.connected-header-logout').first(); await expect(logoutIcon).toBeVisible({ timeout: 5_000 }); await logoutIcon.click(); await expect(page.locator('.connect-button--disconnected').first()).toBeVisible({ timeout: 10_000 }); console.log('[wallet] Wallet disconnected'); }