From c0695e101fe25d361f299aa7e73cd2566aa23f69 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 6 Mar 2026 09:27:17 +0000 Subject: [PATCH] fix: Swap completion detection relies on a fragile timing assumption (#415) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- tests/e2e/01-acquire-and-stake.spec.ts | 19 ++++++++++++------- tests/e2e/02-max-stake-all-tax-rates.spec.ts | 17 +++++++++++------ 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/tests/e2e/01-acquire-and-stake.spec.ts b/tests/e2e/01-acquire-and-stake.spec.ts index f3ab929..cf43386 100644 --- a/tests/e2e/01-acquire-and-stake.spec.ts +++ b/tests/e2e/01-acquire-and-stake.spec.ts @@ -184,16 +184,21 @@ test.describe('Acquire & Stake', () => { console.log('[TEST] Clicking Buy KRK button...'); 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...'); try { - await page.getByRole('button', { name: /Submitting/i }).waitFor({ state: 'visible', timeout: 5_000 }); - console.log('[TEST] Swap initiated, waiting for completion...'); - await expect(page.getByTestId('swap-buy-button')).toHaveText('Buy KRK', { timeout: 60_000 }); - console.log('[TEST] Swap completed!'); - } catch (e) { - console.log('[TEST] No "Submitting" state detected, swap may have completed instantly'); + await expect(buyButton).toBeDisabled({ timeout: 5_000 }); + console.log('[TEST] Swap initiated...'); + } catch { + console.log('[TEST] Swap completed before disabled state was observable (fast RPC).'); } + 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. await page.waitForTimeout(2_000); diff --git a/tests/e2e/02-max-stake-all-tax-rates.spec.ts b/tests/e2e/02-max-stake-all-tax-rates.spec.ts index 26afc48..378a783 100644 --- a/tests/e2e/02-max-stake-all-tax-rates.spec.ts +++ b/tests/e2e/02-max-stake-all-tax-rates.spec.ts @@ -194,15 +194,20 @@ test.describe('Max Stake All Tax Rates', () => { await expect(buyButton).toBeVisible(); 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...'); try { - await page.getByRole('button', { name: /Submitting/i }).waitFor({ state: 'visible', timeout: 5_000 }); - await expect(page.getByTestId('swap-buy-button')).toHaveText('Buy KRK', { timeout: 60_000 }); - console.log('[TEST] Swap completed!'); - } catch (e) { - console.log('[TEST] Swap may have completed instantly'); + await expect(buyButton).toBeDisabled({ timeout: 5_000 }); + } catch { + console.log('[TEST] Swap completed before disabled state was observable (fast RPC).'); } + 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. await page.waitForTimeout(2_000);