Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/canary-session-proposal-timing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@reown/appkit-testing': patch
---

Add `WalletPage.waitForSessionProposal()` — a deterministic signal (approve-button visibility) for canary session-proposal timing that replaces brittle WalletConnect console-log parsing in the laboratory canary fixture.
57 changes: 19 additions & 38 deletions apps/laboratory/tests/shared/fixtures/w3m-wallet-fixture.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint no-console: 0 */
import { WalletPage, WalletValidator } from '@reown/appkit-testing'
import { DEFAULT_SESSION_PARAMS } from '@reown/appkit-testing'

Expand All @@ -14,34 +13,10 @@
// MW -> test Modal + Wallet
export const testConnectedMW = base.extend<ModalWalletFixture>({
walletPage: async ({ context, modalPage, timingRecords }, use) => {
// Setup
let pairingCreatedTime: Date | null = null
let verificationStartedTime: Date | null = null

timeStart('new WalletPage')
const walletPage = new WalletPage(await context.newPage())
timeEnd('new WalletPage')

walletPage.page.on('console', msg => {
if (msg.text().includes('set') && msg.text().includes('core/pairing/pairing')) {
pairingCreatedTime = new Date()
}
if (msg.text().includes('resolving attestation')) {
verificationStartedTime = new Date()
}
if (msg.text().includes('session_proposal') && msg.text().includes('verifyContext')) {
// For some reason this log is emitted twice; so only recording the time once
if (verificationStartedTime) {
const verificationEndedTime = new Date()
timingRecords.push({
item: 'sessionProposalVerification',
timeMs: verificationEndedTime.getTime() - verificationStartedTime.getTime()
})
verificationStartedTime = null
}
}
})

timeStart('walletPage.load')
await walletPage.load()
timeEnd('walletPage.load')
Expand All @@ -53,29 +28,35 @@

timeStart('walletPage.connectWithUri')
await walletPage.connectWithUri(uri)
// Capture immediately on resolution — nothing awaited in between — to avoid skewing the interval.
const connectionInitiated = new Date()
timeEnd('walletPage.connectWithUri')
Comment on lines 29 to 33

const connectionInitiated = new Date()
// The session proposal is received once the wallet renders the request UI (approve button).

Check failure on line 35 in apps/laboratory/tests/shared/fixtures/w3m-wallet-fixture.ts

View workflow job for this annotation

GitHub Actions / code_style (lint)

Expected a block comment instead of consecutive line comments
// Deterministic, owned-testid signal instead of parsing SDK console logs. Also guards delivery
// failures: a proposal that never arrives times out here and fails the run (pages via the

Check failure on line 37 in apps/laboratory/tests/shared/fixtures/w3m-wallet-fixture.ts

View workflow job for this annotation

GitHub Actions / code_style (lint)

Comments should not begin with a lowercase character
// success/failure canary). Interval includes the wallet's render time.

Check failure on line 38 in apps/laboratory/tests/shared/fixtures/w3m-wallet-fixture.ts

View workflow job for this annotation

GitHub Actions / code_style (lint)

Comments should not begin with a lowercase character
timeStart('walletPage.waitForSessionProposal')
await walletPage.waitForSessionProposal()
const proposalReceived = new Date()
timeEnd('walletPage.waitForSessionProposal')

timingRecords.push({
item: 'sessionProposalReceived',
timeMs: proposalReceived.getTime() - connectionInitiated.getTime()
})

// Handle session proposal
// Approve the session proposal (request UI already visible from the wait above)
timeStart('walletPage.handleSessionProposal')
await walletPage.handleSessionProposal(DEFAULT_SESSION_PARAMS)
const proposalApproved = new Date()
timeEnd('walletPage.handleSessionProposal')

const proposalReceived = new Date()

timingRecords.push({
item: 'receiveSessionProposal',
timeMs: proposalReceived.getTime() - connectionInitiated.getTime()
item: 'sessionProposalApproved',
timeMs: proposalApproved.getTime() - proposalReceived.getTime()
})

if (pairingCreatedTime) {
timingRecords.push({
item: 'pairingReceiveSessionProposal',
timeMs: proposalReceived.getTime() - (pairingCreatedTime as Date).getTime()
})
}

const walletValidator = new WalletValidator(walletPage.page)

timeStart('walletValidator.expectConnected')
Expand Down
22 changes: 21 additions & 1 deletion packages/testing/src/pages/WalletPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,29 @@ export class WalletPage {
await this.performRequestAction(variant)
}

sessionRequestButton(variant: string) {
return this.page.getByTestId(`session-${variant}-button`)
}
Comment on lines +86 to +88

/**
* Resolves once the wallet has received a session proposal and rendered the request UI
* (the approve button becomes visible). Deterministic signal for canary timing — replaces
* brittle console-log parsing. Shares the same owned testid as `performRequestAction`, so a
* selector change breaks the approve flow too and fails the run (paging via the
* success/failure canary) rather than silently dropping the timing metric. Note: the interval
* includes the wallet's render time; the pure relay/SDK delivery leg needs a wallet-side signal.
*/
async waitForSessionProposal(timeout = 30000) {
await this.page.waitForLoadState()
await expect(
this.sessionRequestButton('approve'),
'Session proposal should be received (approve button visible)'
).toBeVisible({ timeout })
}

async performRequestAction(variant: string) {
await this.page.waitForLoadState()
const btn = this.page.getByTestId(`session-${variant}-button`)
const btn = this.sessionRequestButton(variant)
await expect(btn, `Session ${variant} element should be visible`).toBeVisible({
timeout: 30000
})
Expand Down
Loading