fix: Swap completion detection relies on a fragile timing assumption (#415)

Replace the try/catch on observing the transient 'Submitting…' button text with a
two-phase disabled→enabled check. The button gains the `disabled` attribute the
moment `swapping=true` and loses it when the swap finishes. By placing
`toBeEnabled({ timeout: 60_000 })` unconditionally after the try block, both
paths (fast RPC where disabled state cycles in <100 ms and slow RPC where it is
clearly observable) now wait for the actual ready state rather than falling
through to only a 2-second static guard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
openhands 2026-03-06 09:27:17 +00:00
parent 5bea99ddf4
commit c0695e101f
2 changed files with 23 additions and 13 deletions

View file

@ -184,16 +184,21 @@ test.describe('Acquire & Stake', () => {
console.log('[TEST] Clicking Buy KRK button...'); console.log('[TEST] Clicking Buy KRK button...');
await buyButton.click(); await buyButton.click();
// Wait for button to show "Submitting..." then return to "Buy KRK" // Wait for swap to complete. The button becomes disabled (swapping=true) while the
// transaction is in flight and re-enables (swapping=false) when it finishes.
// Try to observe the disabled state first; if the RPC responds so fast that the
// disabled state cycles before we can observe it, the try throws and we fall through.
// Either way, the unconditional toBeEnabled() call below waits for the final ready
// state, covering both fast-RPC (already enabled) and slow-RPC (waiting to enable) paths.
console.log('[TEST] Waiting for swap to process...'); console.log('[TEST] Waiting for swap to process...');
try { try {
await page.getByRole('button', { name: /Submitting/i }).waitFor({ state: 'visible', timeout: 5_000 }); await expect(buyButton).toBeDisabled({ timeout: 5_000 });
console.log('[TEST] Swap initiated, waiting for completion...'); console.log('[TEST] Swap initiated...');
await expect(page.getByTestId('swap-buy-button')).toHaveText('Buy KRK', { timeout: 60_000 }); } catch {
console.log('[TEST] Swap completed!'); console.log('[TEST] Swap completed before disabled state was observable (fast RPC).');
} catch (e) {
console.log('[TEST] No "Submitting" state detected, swap may have completed instantly');
} }
await expect(buyButton).toBeEnabled({ timeout: 60_000 });
console.log('[TEST] Swap completed!');
// eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for Ponder indexing lag and UI re-renders after on-chain transactions in E2E tests. See AGENTS.md #Engineering Principles. // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for Ponder indexing lag and UI re-renders after on-chain transactions in E2E tests. See AGENTS.md #Engineering Principles.
await page.waitForTimeout(2_000); await page.waitForTimeout(2_000);

View file

@ -194,15 +194,20 @@ test.describe('Max Stake All Tax Rates', () => {
await expect(buyButton).toBeVisible(); await expect(buyButton).toBeVisible();
await buyButton.click(); await buyButton.click();
// Wait for swap to complete // Wait for swap to complete. The button becomes disabled (swapping=true) while the
// transaction is in flight and re-enables (swapping=false) when it finishes.
// Try to observe the disabled state first; if the RPC responds so fast that the
// disabled state cycles before we can observe it, the try throws and we fall through.
// Either way, the unconditional toBeEnabled() call below waits for the final ready
// state, covering both fast-RPC (already enabled) and slow-RPC (waiting to enable) paths.
console.log('[TEST] Waiting for swap to process...'); console.log('[TEST] Waiting for swap to process...');
try { try {
await page.getByRole('button', { name: /Submitting/i }).waitFor({ state: 'visible', timeout: 5_000 }); await expect(buyButton).toBeDisabled({ timeout: 5_000 });
await expect(page.getByTestId('swap-buy-button')).toHaveText('Buy KRK', { timeout: 60_000 }); } catch {
console.log('[TEST] Swap completed!'); console.log('[TEST] Swap completed before disabled state was observable (fast RPC).');
} catch (e) {
console.log('[TEST] Swap may have completed instantly');
} }
await expect(buyButton).toBeEnabled({ timeout: 60_000 });
console.log('[TEST] Swap completed!');
// eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for Ponder indexing lag and UI re-renders after on-chain transactions in E2E tests. See AGENTS.md #Engineering Principles. // eslint-disable-next-line no-restricted-syntax -- waitForTimeout: no event source exists for Ponder indexing lag and UI re-renders after on-chain transactions in E2E tests. See AGENTS.md #Engineering Principles.
await page.waitForTimeout(2_000); await page.waitForTimeout(2_000);