Skip to content

test: test Deployment and Tx Fee authorizations#2109

Merged
stalniy merged 2 commits intoakash-network:mainfrom
jzsfkzm:test/2006-authorizations
Nov 6, 2025
Merged

test: test Deployment and Tx Fee authorizations#2109
stalniy merged 2 commits intoakash-network:mainfrom
jzsfkzm:test/2006-authorizations

Conversation

@jzsfkzm
Copy link
Contributor

@jzsfkzm jzsfkzm commented Oct 25, 2025

refs #2006

Summary by CodeRabbit

  • Accessibility

    • Added ARIA labels to authorization action buttons and authorization lists/tables for improved screen reader support.
  • Bug Fixes

    • Fixed form label rendering and increased wallet-connect timeouts for more reliable UI flows.
  • Tests

    • Added end-to-end authorization workflow tests, new test page objects and helpers, clipboard support, transaction-approval helpers, and updated test fixtures with scoped timeouts.
  • UX

    • Introduced consistent shortened-address formatting for compact displays.

@jzsfkzm jzsfkzm requested a review from a team as a code owner October 25, 2025 12:11
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 25, 2025

Walkthrough

Adds ARIA labels and small JSX formatting changes, introduces Playwright page objects and new end-to-end authorization tests, updates test fixtures and wallet-extension popup handling (race between popup and extension page), refactors testing helpers, extracts an address-shortening helper, and increases some test timeouts.

Changes

Cohort / File(s) Summary
Authorization components
apps/deploy-web/src/components/authorizations/AllowanceIssuedRow.tsx, apps/deploy-web/src/components/authorizations/DeploymentGrantTable.tsx, apps/deploy-web/src/components/authorizations/FeeGrantTable.tsx
Added ARIA attributes to action buttons and tables (e.g., aria-label="Edit Authorization", aria-label="Revoke Authorization", table labels like Deployment Authorization List, Tx Fee Authorization List).
UI formatting
apps/deploy-web/src/components/authorizations/Authorizations.tsx
Reflowed Button JSX to multiline; no behavioral changes.
Playwright tests (new)
apps/deploy-web/tests/ui/authorize-spending.spec.ts
New E2E test covering authorize/edit/revoke flows for Deployment and Tx Fee scenarios using a reusable runner.
Test renames
apps/deploy-web/tests/ui/change-wallets.spec.ts, apps/deploy-web/tests/ui/disconnect-wallet.spec.ts
Local variable rename from frontPageextension (no behavior change).
Fixtures & context
apps/deploy-web/tests/ui/fixture/context-with-extension.ts
Added clipboard permissions to chromium launch; converted page fixture to tuple form with { scope: "test", timeout: 5 * 60 * 1000 }.
Testing helpers
apps/deploy-web/tests/ui/fixture/testing-helpers.ts
Simplified fillWalletName and added clickCopyAddressButton(page: Page) to click copy and return clipboard text.
Page objects
apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx
New AuthorizationsPage class and label union types; methods: goto, clickGrantButton, authorizeSpending, editSpending, revokeSpending.
Extension helper
apps/deploy-web/tests/ui/pages/LeapExt.tsx
Constructor uses BrowserContext; added acceptTransaction(context: BrowserContext) and import adjustments for approveWalletOperation.
Wallet setup
apps/deploy-web/tests/ui/fixture/wallet-setup.ts
awaitWalletAndApprove now accepts extensionId and races between context.waitForEvent("page") and getExtensionPage(extensionId) to obtain the popup page.
Timeouts
apps/deploy-web/tests/ui/uiState/isWalletConnected.ts
Increased wait timeouts from 10s to 30s for wallet-connected checks.
UI helpers & components
packages/ui/components/custom/address.tsx, packages/ui/components/input.tsx
Added exported shortenAddress(address) helper and refactored Address component to use it; updated Input to pass label as FormLabel child when formField.id exists.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test Runner
    participant Fixture as Fixture
    participant LeapExt as LeapExt helper
    participant AuthPage as AuthorizationsPage
    participant App as Deploy Web App
    participant Extension as Wallet Extension

    Test->>Fixture: launch browser (clipboard perms), prepare context
    Fixture->>LeapExt: construct LeapExt(context, page)
    Test->>AuthPage: goto()
    AuthPage->>App: click Grant (by label), fill grantee & limit, submit
    App->>LeapExt: triggers wallet popup
    alt popup via context event
      LeapExt->>Extension: acceptTransaction(context) -> approve
    else extension page resolved by id
      Fixture->>Extension: getExtensionPage(extensionId) -> approve
    end
    Extension->>App: wallet approval confirmed
    App->>AuthPage: update authorization list (uses shortenAddress)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

  • Pay attention to:
    • apps/deploy-web/tests/ui/fixture/wallet-setup.ts — Promise.race between popup sources and added extensionId parameter.
    • apps/deploy-web/tests/ui/fixture/context-with-extension.ts — fixture tuple shape, scope and timeout semantics.
    • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx — locator robustness and label unions.
    • apps/deploy-web/tests/ui/pages/LeapExt.tsx — new acceptTransaction and context typing.

Possibly related PRs

Suggested reviewers

  • baktun14
  • ygrishajev

Poem

🐇 I hopped through tests with clipboard in paw,

Buttons blessed with ARIA — polite and law.
Page objects tidy, popups raced and cleared,
Shortened addresses, approvals appeared. ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main focus: adding tests for Deployment and Tx Fee authorizations. It aligns with the new test file (authorize-spending.spec.ts) and complementary changes to support authorization testing.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f0c3880 and a65f1cc.

📒 Files selected for processing (15)
  • apps/deploy-web/src/components/authorizations/AllowanceIssuedRow.tsx (1 hunks)
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx (1 hunks)
  • apps/deploy-web/src/components/authorizations/DeploymentGrantTable.tsx (2 hunks)
  • apps/deploy-web/src/components/authorizations/FeeGrantTable.tsx (1 hunks)
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts (1 hunks)
  • apps/deploy-web/tests/ui/change-wallets.spec.ts (1 hunks)
  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts (1 hunks)
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts (2 hunks)
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts (2 hunks)
  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts (1 hunks)
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx (1 hunks)
  • apps/deploy-web/tests/ui/pages/LeapExt.tsx (2 hunks)
  • apps/deploy-web/tests/ui/uiState/isWalletConnected.ts (1 hunks)
  • packages/ui/components/custom/address.tsx (2 hunks)
  • packages/ui/components/input.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/ui/components/custom/address.tsx
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx
  • apps/deploy-web/tests/ui/pages/LeapExt.tsx
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx
  • apps/deploy-web/src/components/authorizations/FeeGrantTable.tsx
  • apps/deploy-web/src/components/authorizations/AllowanceIssuedRow.tsx
  • apps/deploy-web/src/components/authorizations/DeploymentGrantTable.tsx
  • apps/deploy-web/tests/ui/change-wallets.spec.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts
  • apps/deploy-web/tests/ui/uiState/isWalletConnected.ts
  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts
  • packages/ui/components/input.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts
  • apps/deploy-web/tests/ui/uiState/isWalletConnected.ts
  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts
  • packages/ui/components/input.tsx
🧠 Learnings (5)
📓 Common learnings
Learnt from: baktun14
Repo: akash-network/console PR: 1725
File: apps/api/src/utils/constants.ts:5-5
Timestamp: 2025-07-24T17:00:52.361Z
Learning: In the Akash Network Console project, when cross-cutting concerns or broader refactoring issues are identified during PR review, the preferred approach is to create a separate GitHub issue to track the work rather than expanding the scope of the current PR. This maintains focus and allows for proper planning of architectural improvements.
📚 Learning: 2025-10-15T16:39:55.348Z
Learnt from: jzsfkzm
Repo: akash-network/console PR: 2039
File: apps/deploy-web/tests/ui/change-wallets.spec.ts:4-10
Timestamp: 2025-10-15T16:39:55.348Z
Learning: In the Akash Console E2E tests using the context-with-extension fixture, the first wallet is automatically created during fixture setup via `importWalletToLeap` in `apps/deploy-web/tests/ui/fixture/wallet-setup.ts`, so tests that call `frontPage.createWallet()` are creating a second wallet to test wallet switching functionality.

Applied to files:

  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts
  • apps/deploy-web/tests/ui/uiState/isWalletConnected.ts
  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts
📚 Learning: 2025-07-21T08:24:27.953Z
Learnt from: CR
Repo: akash-network/console PR: 0
File: .cursor/rules/query-by-in-tests.mdc:0-0
Timestamp: 2025-07-21T08:24:27.953Z
Learning: Applies to apps/{deploy-web,provider-console}/**/*.spec.tsx : Use `queryBy` methods instead of `getBy` methods in test expectations in `.spec.tsx` files

Applied to files:

  • apps/deploy-web/tests/ui/authorize-spending.spec.ts
📚 Learning: 2025-10-31T11:26:42.138Z
Learnt from: stalniy
Repo: akash-network/console PR: 2138
File: apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts:379-382
Timestamp: 2025-10-31T11:26:42.138Z
Learning: In TypeScript/JavaScript, the pattern of checking a cached value and then performing an async operation to fetch it without proper synchronization is race condition unsafe:
```typescript
private async getAddress() {
  if (!this.address) {
    this.address = await this.wallet.getFirstAddress();
  }
  return this.address;
}
```
Multiple concurrent calls can all pass the `if (!this.address)` check before any of them sets the value, leading to duplicate async operations. This should be flagged as a race condition. Proper synchronization (mutex, atomic promise caching, or guaranteed single-threaded execution) is required.

Applied to files:

  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts
📚 Learning: 2025-06-05T21:07:51.985Z
Learnt from: baktun14
Repo: akash-network/console PR: 1432
File: apps/deploy-web/src/components/deployments/DeploymentAlerts/DeploymentCloseAlert.tsx:38-38
Timestamp: 2025-06-05T21:07:51.985Z
Learning: The ContactPointSelect component in apps/deploy-web/src/components/alerts/ContactPointSelectForm/ContactPointSelect.tsx uses the useFormContext hook internally to connect to React Hook Form, so it doesn't need to be wrapped in a FormField component.

Applied to files:

  • packages/ui/components/input.tsx
🧬 Code graph analysis (3)
apps/deploy-web/tests/ui/disconnect-wallet.spec.ts (1)
apps/deploy-web/tests/ui/pages/LeapExt.tsx (1)
  • LeapExt (9-45)
apps/deploy-web/tests/ui/authorize-spending.spec.ts (6)
apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx (3)
  • AuthorizeButtonLabel (6-6)
  • AuthorizationListLabel (7-7)
  • AuthorizationsPage (9-42)
apps/deploy-web/tests/ui/fixture/context-with-extension.ts (2)
  • test (12-79)
  • expect (81-81)
packages/ui/components/custom/address.tsx (1)
  • shortenAddress (11-13)
apps/deploy-web/tests/ui/pages/LeapExt.tsx (1)
  • LeapExt (9-45)
apps/deploy-web/tests/ui/fixture/testing-helpers.ts (1)
  • clickCopyAddressButton (31-39)
apps/deploy-web/tests/ui/fixture/wallet-setup.ts (1)
  • getExtensionPage (15-27)
apps/deploy-web/tests/ui/fixture/context-with-extension.ts (3)
apps/deploy-web/tests/ui/fixture/wallet-setup.ts (4)
  • getExtensionPage (15-27)
  • setupWallet (29-34)
  • connectWalletViaLeap (46-57)
  • awaitWalletAndApprove (59-66)
apps/deploy-web/tests/ui/fixture/base-test.ts (1)
  • injectUIConfig (16-25)
apps/deploy-web/tests/ui/actions/selectChainNetwork.ts (1)
  • selectChainNetwork (6-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: Validate local packages
🔇 Additional comments (7)
packages/ui/components/input.tsx (1)

59-59: LGTM! Accessibility improvement for Input component.

The addition of {label} as children and the htmlFor attribute correctly links the FormLabel to the input element, improving accessibility.

apps/deploy-web/tests/ui/uiState/isWalletConnected.ts (1)

7-7: LGTM: Timeout increase aligns with extension-aware flow.

The timeout increase from 10s to 30s is justified given the PR's broader changes to wallet/extension interaction timing, including the race between wallet popup and extension page in the updated wallet-setup flow.

Also applies to: 12-12

apps/deploy-web/tests/ui/disconnect-wallet.spec.ts (1)

6-7: LGTM: Clarifying variable rename.

Renaming frontPage to extension better reflects that the variable holds a LeapExt instance representing the extension interaction layer.

apps/deploy-web/tests/ui/authorize-spending.spec.ts (3)

17-52: LGTM: Well-structured parameterized test suite.

The runAuthorizationTest function provides comprehensive coverage of authorization flows (authorize, edit, revoke) with proper assertions and async handling. The parameterized approach eliminates duplication between Deployment and Tx Fee scenarios.


20-20: Verify whether 5-minute test timeouts are necessary.

Each test sets a 5-minute timeout, which is quite long. While this aligns with the fixture timeout in context-with-extension.ts, consider whether these tests typically complete much faster in practice.

If most test runs complete in under 2 minutes, consider reducing the timeout to 2-3 minutes to catch performance regressions earlier while still providing adequate margin.

Also applies to: 30-30, 41-41


64-80: LGTM: Setup function properly initializes test state.

The setup helper correctly orchestrates wallet creation, navigation, and initial authorization. Since the fixture has scope: "test", each test receives a fresh context, so explicit cleanup is not required.

apps/deploy-web/tests/ui/fixture/context-with-extension.ts (1)

31-31: LGTM: Clipboard permissions support new test helpers.

The addition of clipboard read/write permissions enables the clickCopyAddressButton helper used in the new authorization tests.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (6)
apps/deploy-web/src/components/authorizations/GrantModal.tsx (1)

192-192: ARIA labels on inputs with existing label props.

The aria-label attributes on these FormInput components duplicate the visible label prop values. If FormInput properly associates the label with the input (via htmlFor), the aria-label is redundant since the label text already provides the accessible name. However, this is not harmful and may provide defensive accessibility if the label association isn't perfect.

Also applies to: 204-204

apps/deploy-web/src/components/authorizations/AllowanceModal.tsx (1)

147-147: ARIA labels on inputs with existing label props.

Similar to GrantModal.tsx, these aria-label attributes duplicate the visible label prop values. While potentially redundant if FormInput properly associates labels with inputs, this provides defensive accessibility and maintains consistency with the other authorization modals.

Also applies to: 159-159

apps/deploy-web/src/components/authorizations/Authorizations.tsx (2)

226-229: ARIA label duplicates visible button text.

This button already has visible text content ("Authorize Spend"), which automatically provides the accessible name. The aria-label duplicates this visible text, making it redundant but not harmful. Consider removing the aria-label since the visible text is sufficient for accessibility.


338-349: ARIA label duplicates visible button text.

Similar to the "Authorize Spend" button, this button has visible text content ("Authorize Fee Spend") that already provides an accessible name. The aria-label is redundant but not harmful.

apps/deploy-web/tests/ui/authorize-spending.spec.ts (2)

17-53: Consider restructuring to follow test guidelines.

The current parametric test approach with runAuthorizationTest is functional but doesn't align with the coding guidelines which specify:

  • "Use setup function instead of beforeEach in test files"
  • "setup function must be at the bottom of the root describe block in test files"

The current structure calls setup() directly in each test rather than using a beforeEach-style pattern, and the setup function is at module level rather than within a describe block.

Consider this structure for better guideline compliance:

test.describe("Deployment Authorizations", () => {
  test("can authorize spending", async ({ page, context, extensionId }) => {
    test.setTimeout(5 * 60 * 1000);
    const { authorizationsPage, address } = setup({ page, context, extensionId });
    
    const buttonLabel: AuthorizeButtonLabel = "Authorize Spend";
    const listLabel: AuthorizationListLabel = "Deployment Authorization List";
    
    await authorizationsPage.authorizeSpending(address, buttonLabel);
    
    const shortenedAddress = shortenAddress(address);
    const grantList = authorizationsPage.page.getByLabel(listLabel);
    await expect(grantList.locator("tr", { hasText: shortenedAddress })).toBeVisible();
  });

  // ... other tests

  function setup({ page, context, extensionId }: SetupProps) {
    // setup logic
  }
});

Alternatively, if you want to maintain the parametric approach, document why this pattern was chosen over the standard guidelines.


19-27: Test timeout set per test instead of using fixture configuration.

The 5-minute timeout is set individually in each test case, but the fixture already configures this timeout (line 77 in context-with-extension.ts). This creates redundancy.

Consider removing the per-test timeout since the fixture already handles it:

   test("can authorize spending", async ({ page, context, extensionId }) => {
-    test.setTimeout(5 * 60 * 1000);
-
     const { authorizationsPage, address } = await setup({ page, context, extensionId, buttonLabel });
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55da6d7 and 9af7103.

📒 Files selected for processing (15)
  • apps/deploy-web/src/components/authorizations/AllowanceIssuedRow.tsx (1 hunks)
  • apps/deploy-web/src/components/authorizations/AllowanceModal.tsx (2 hunks)
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx (2 hunks)
  • apps/deploy-web/src/components/authorizations/DeploymentGrantTable.tsx (2 hunks)
  • apps/deploy-web/src/components/authorizations/FeeGrantTable.tsx (1 hunks)
  • apps/deploy-web/src/components/authorizations/GrantModal.tsx (2 hunks)
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts (1 hunks)
  • apps/deploy-web/tests/ui/change-wallets.spec.ts (1 hunks)
  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts (1 hunks)
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts (2 hunks)
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts (2 hunks)
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx (1 hunks)
  • apps/deploy-web/tests/ui/pages/LeapExt.tsx (1 hunks)
  • apps/deploy-web/tests/ui/uiState/isWalletConnected.ts (1 hunks)
  • packages/ui/components/custom/address.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/src/components/authorizations/Authorizations.tsx
  • apps/deploy-web/tests/ui/pages/LeapExt.tsx
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts
  • apps/deploy-web/src/components/authorizations/GrantModal.tsx
  • packages/ui/components/custom/address.tsx
  • apps/deploy-web/tests/ui/change-wallets.spec.ts
  • apps/deploy-web/src/components/authorizations/AllowanceIssuedRow.tsx
  • apps/deploy-web/src/components/authorizations/FeeGrantTable.tsx
  • apps/deploy-web/tests/ui/uiState/isWalletConnected.ts
  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts
  • apps/deploy-web/src/components/authorizations/AllowanceModal.tsx
  • apps/deploy-web/src/components/authorizations/DeploymentGrantTable.tsx
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/src/components/authorizations/Authorizations.tsx
  • apps/deploy-web/tests/ui/pages/LeapExt.tsx
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts
  • apps/deploy-web/src/components/authorizations/GrantModal.tsx
  • packages/ui/components/custom/address.tsx
  • apps/deploy-web/tests/ui/change-wallets.spec.ts
  • apps/deploy-web/src/components/authorizations/AllowanceIssuedRow.tsx
  • apps/deploy-web/src/components/authorizations/FeeGrantTable.tsx
  • apps/deploy-web/tests/ui/uiState/isWalletConnected.ts
  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts
  • apps/deploy-web/src/components/authorizations/AllowanceModal.tsx
  • apps/deploy-web/src/components/authorizations/DeploymentGrantTable.tsx
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/deploy-web/tests/ui/change-wallets.spec.ts
  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts
🧠 Learnings (1)
📚 Learning: 2025-10-15T16:39:55.348Z
Learnt from: jzsfkzm
PR: akash-network/console#2039
File: apps/deploy-web/tests/ui/change-wallets.spec.ts:4-10
Timestamp: 2025-10-15T16:39:55.348Z
Learning: In the Akash Console E2E tests using the context-with-extension fixture, the first wallet is automatically created during fixture setup via `importWalletToLeap` in `apps/deploy-web/tests/ui/fixture/wallet-setup.ts`, so tests that call `frontPage.createWallet()` are creating a second wallet to test wallet switching functionality.

Applied to files:

  • apps/deploy-web/tests/ui/change-wallets.spec.ts
  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts
🧬 Code graph analysis (6)
apps/deploy-web/tests/ui/change-wallets.spec.ts (1)
apps/deploy-web/tests/ui/pages/LeapExt.tsx (1)
  • LeapExt (9-46)
apps/deploy-web/tests/ui/disconnect-wallet.spec.ts (1)
apps/deploy-web/tests/ui/pages/LeapExt.tsx (1)
  • LeapExt (9-46)
apps/deploy-web/src/components/authorizations/AllowanceModal.tsx (1)
packages/ui/components/input.tsx (1)
  • FormInput (123-123)
apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx (2)
apps/deploy-web/tests/ui/fixture/test-env.config.ts (1)
  • testEnvConfig (12-16)
packages/ui/components/custom/address.tsx (1)
  • shortenAddress (11-13)
apps/deploy-web/tests/ui/authorize-spending.spec.ts (6)
apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx (3)
  • AuthorizeButtonLabel (6-6)
  • AuthorizationListLabel (7-7)
  • AuthorizationsPage (9-55)
apps/deploy-web/tests/ui/fixture/context-with-extension.ts (2)
  • test (12-79)
  • expect (81-81)
packages/ui/components/custom/address.tsx (1)
  • shortenAddress (11-13)
apps/deploy-web/tests/ui/pages/LeapExt.tsx (1)
  • LeapExt (9-46)
apps/deploy-web/tests/ui/fixture/testing-helpers.ts (1)
  • clickCopyAddressButton (36-45)
apps/deploy-web/tests/ui/fixture/wallet-setup.ts (1)
  • getExtensionPage (15-27)
apps/deploy-web/tests/ui/fixture/context-with-extension.ts (3)
apps/deploy-web/tests/ui/fixture/wallet-setup.ts (4)
  • getExtensionPage (15-27)
  • setupWallet (29-34)
  • connectWalletViaLeap (46-57)
  • awaitWalletAndApprove (59-63)
apps/deploy-web/tests/ui/fixture/base-test.ts (1)
  • injectUIConfig (16-25)
apps/deploy-web/tests/ui/actions/selectChainNetwork.ts (1)
  • selectChainNetwork (6-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: Validate local packages
🔇 Additional comments (15)
apps/deploy-web/tests/ui/uiState/isWalletConnected.ts (1)

7-7: Document why 30s timeout is needed for authorization workflow.

The timeout increase from 10s to 30s is intentional for your authorization workflow testing with wallet extensions. However, this is significantly longer than other wallet operations in the codebase (which use 20s max) and lacks explanation. Add a code comment clarifying why the extended timeout is necessary, or verify that this timeout is appropriate for your CI environment. Consider whether the 30s timeout addresses a real performance need or masks underlying test flakiness.

apps/deploy-web/src/components/authorizations/FeeGrantTable.tsx (1)

66-66: LGTM!

Adding an aria-label to the Table component improves accessibility for screen reader users by providing context about the table's purpose.

apps/deploy-web/tests/ui/disconnect-wallet.spec.ts (1)

6-7: LGTM!

The variable rename from frontPage to extension better reflects that this is a LeapExt instance representing wallet extension interactions, improving code clarity.

apps/deploy-web/tests/ui/change-wallets.spec.ts (1)

9-11: LGTM!

Consistent with the refactoring in disconnect-wallet.spec.ts, the rename from frontPage to extension improves code clarity and naming consistency across the test suite.

apps/deploy-web/src/components/authorizations/AllowanceIssuedRow.tsx (1)

56-59: LGTM!

Adding aria-labels to these icon-only buttons is essential for accessibility. Screen reader users will now understand the purpose of these action buttons.

apps/deploy-web/src/components/authorizations/DeploymentGrantTable.tsx (2)

133-136: LGTM!

Adding aria-labels to these icon-only Edit and Revoke buttons provides essential accessible names for screen reader users.


167-167: LGTM!

The aria-label on the Table component improves accessibility by providing screen reader users with context about the table's purpose.

packages/ui/components/custom/address.tsx (1)

28-28: LGTM! Good refactor to use the centralized helper.

The change correctly delegates address formatting to the new shortenAddress helper, maintaining consistent behavior while improving code reusability.

apps/deploy-web/tests/ui/fixture/context-with-extension.ts (2)

30-31: LGTM! Clipboard permissions support the new test helpers.

The addition of clipboard read/write permissions enables the clickCopyAddressButton helper to read clipboard contents during tests.


46-78: LGTM! Appropriate fixture scope and timeout configuration.

The tuple format correctly specifies scope: "test" (isolated per test) and a 5-minute timeout, which is reasonable given the fixture performs wallet setup, network selection, and wallet connection. The fallback logic for non-functional networks is a good defensive measure.

apps/deploy-web/tests/ui/fixture/testing-helpers.ts (2)

18-18: LGTM! Simplified by removing unnecessary intermediate await.

The direct return of the fill operation is correct and more concise.


36-45: LGTM! Clipboard reading logic is correct.

The helper properly handles the null case from getCopyAddressButton and uses the Playwright evaluate API to read clipboard contents.

apps/deploy-web/tests/ui/authorize-spending.spec.ts (1)

62-77: Verify the setup creates a second wallet as intended.

The setup function calls extension.createWallet(extensionId) on line 65. Based on learnings, the first wallet is automatically created during fixture setup, so this creates a second wallet for authorization testing.

Confirm this is intentional behavior - creating a second wallet to test authorizations between different wallet addresses. If so, consider adding a comment explaining this:

const setup = async ({ page, context, extensionId, buttonLabel }: SetupProps) => {
  const extension = new LeapExt(context, page);
  const address = await clickCopyAddressButton(await getExtensionPage(context, extensionId));
  
  // Create a second wallet to test cross-wallet authorizations
  await extension.createWallet(extensionId);
  
  // ... rest of setup
};

Based on learnings

apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx (2)

6-7: LGTM! Clear type definitions for authorization UI elements.

The string literal union types provide type safety and document the exact labels used in the UI.


32-40: Good use of shortenAddress for consistent address matching.

The page object correctly uses shortenAddress() to format addresses for UI element selection, ensuring consistency with how addresses are displayed in the authorization lists.

Comment on lines 23 to 30
async authorizeSpending(address: string, buttonLabel: AuthorizeButtonLabel) {
await this.page.getByLabel(buttonLabel).click();
await this.page.getByLabel("Spending Limit").fill("5");
await this.page.getByLabel("Grantee Address").fill(address);

this.context.on("page", this.acceptTransaction.bind(this));
await this.clickGrantButton();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Event listener won't be unregistered due to mismatched function references.

The same issue identified in LeapExt.tsx applies here. Each call to bind(this) creates a new function reference, so the listener registered on line 28 won't be properly removed by the off() call in acceptTransaction() (line 53).

Apply this diff to fix the binding issue:

 export class AuthorizationsPage {
+  private boundAcceptTransaction?: () => Promise<void>;
+
   constructor(
     readonly context: Context,
     readonly page: Page
   ) {}

   // ... other methods

   async authorizeSpending(address: string, buttonLabel: AuthorizeButtonLabel) {
     await this.page.getByLabel(buttonLabel).click();
     await this.page.getByLabel("Spending Limit").fill("5");
     await this.page.getByLabel("Grantee Address").fill(address);

-    this.context.on("page", this.acceptTransaction.bind(this));
+    this.boundAcceptTransaction = this.acceptTransaction.bind(this);
+    this.context.on("page", this.boundAcceptTransaction);
     await this.clickGrantButton();
   }

   async editSpending(address: string, listLabel: AuthorizationListLabel) {
     const shortenedAddress = shortenAddress(address);
     await this.page.getByLabel(listLabel).locator("tr", { hasText: shortenedAddress }).getByLabel("Edit Authorization").click();

     await this.page.getByLabel("Spending Limit").fill("10");

-    this.context.on("page", this.acceptTransaction.bind(this));
+    this.boundAcceptTransaction = this.acceptTransaction.bind(this);
+    this.context.on("page", this.boundAcceptTransaction);
     await this.clickGrantButton();
   }

   async revokeSpending(address: string, listLabel: AuthorizationListLabel) {
     const shortenedAddress = shortenAddress(address);
     await this.page.getByLabel(listLabel).locator("tr", { hasText: shortenedAddress }).getByLabel("Revoke Authorization").click();

-    this.context.on("page", this.acceptTransaction.bind(this));
+    this.boundAcceptTransaction = this.acceptTransaction.bind(this);
+    this.context.on("page", this.boundAcceptTransaction);
     await this.page.getByTestId("confirm-button").click();
   }

   async acceptTransaction() {
     await this.page.waitForLoadState("domcontentloaded");
     await this.page.getByTestId("btn-connect-wallet").click();
-    this.context.off("page", this.acceptTransaction.bind(this));
+    if (this.boundAcceptTransaction) {
+      this.context.off("page", this.boundAcceptTransaction);
+      this.boundAcceptTransaction = undefined;
+    }
   }
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx around lines 23 to 30,
the event listener is registered with this.acceptTransaction.bind(this) which
creates a new function reference and prevents removal later; create a persistent
bound handler (e.g., store const boundAcceptTransaction =
this.acceptTransaction.bind(this) in a local variable or class property) and use
that same boundAcceptTransaction when calling this.context.on(...) and ensure
acceptTransaction() uses this.context.off(boundAcceptTransaction) to unregister
the exact same reference.

Comment on lines 41 to 45
async acceptTransaction() {
await this.page.waitForLoadState("domcontentloaded");
await this.page.getByTestId("btn-connect-wallet").click();
this.context.off("page", this.acceptTransaction.bind(this));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Event listener won't be unregistered due to mismatched function references.

Each call to bind(this) creates a new function reference. When you register the listener with this.context.on("page", this.acceptTransaction.bind(this)) and then try to unregister with this.context.off("page", this.acceptTransaction.bind(this)), you're using different function references, so the listener remains attached.

Apply this diff to fix the binding issue:

+  private boundAcceptTransaction?: () => Promise<void>;
+
   async acceptTransaction() {
     await this.page.waitForLoadState("domcontentloaded");
     await this.page.getByTestId("btn-connect-wallet").click();
-    this.context.off("page", this.acceptTransaction.bind(this));
+    if (this.boundAcceptTransaction) {
+      this.context.off("page", this.boundAcceptTransaction);
+      this.boundAcceptTransaction = undefined;
+    }
   }

Then when registering the listener (where this method is called from), use:

this.boundAcceptTransaction = this.acceptTransaction.bind(this);
this.context.on("page", this.boundAcceptTransaction);

Note: I see this same pattern is used in AuthorizationsPage.tsx. The same fix is needed there as well.

🤖 Prompt for AI Agents
In apps/deploy-web/tests/ui/pages/LeapExt.tsx around lines 41 to 45, the
off("page", this.acceptTransaction.bind(this)) call uses a different function
reference than the one passed to on(), so the listener is never removed; fix by
creating and using a stored bound function: add an instance property (e.g.,
this.boundAcceptTransaction = this.acceptTransaction.bind(this)) where the
listener is registered and use this.context.on("page",
this.boundAcceptTransaction) and here replace the off call with
this.context.off("page", this.boundAcceptTransaction); apply the same pattern to
AuthorizationsPage.tsx where the same bind/unbind mistake exists.

Comment on lines 11 to 13
export const shortenAddress = (address: string) => {
return [address?.slice(0, 8), "...", address?.slice(address?.length - 5)].join("");
};
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Guard against null/undefined address values.

The optional chaining on address?.slice() will return undefined if address is null/undefined, but the join("") will still execute, producing output like "undefined...undefined". Consider adding an early return or guard condition.

Apply this diff to handle null/undefined addresses:

 export const shortenAddress = (address: string) => {
+  if (!address) return "";
   return [address?.slice(0, 8), "...", address?.slice(address?.length - 5)].join("");
 };

Alternatively, remove the optional chaining if the function expects a valid string:

-export const shortenAddress = (address: string) => {
-  return [address?.slice(0, 8), "...", address?.slice(address?.length - 5)].join("");
+export const shortenAddress = (address: string): string => {
+  return `${address.slice(0, 8)}...${address.slice(-5)}`;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const shortenAddress = (address: string) => {
return [address?.slice(0, 8), "...", address?.slice(address?.length - 5)].join("");
};
export const shortenAddress = (address: string): string => {
return `${address.slice(0, 8)}...${address.slice(-5)}`;
};
🤖 Prompt for AI Agents
In packages/ui/components/custom/address.tsx around lines 11 to 13, the
shortenAddress function uses optional chaining on address.slice which yields
"undefined...undefined" when address is null/undefined; add an early guard that
returns an empty string (or the original value) when address is falsy, or
explicitly throw/validate if a string is required, then remove the optional
chaining and safely call slice on the confirmed string so join("") cannot
produce "undefined" parts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jzsfkzm , makes sense to apply this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines 11 to 13
export const shortenAddress = (address: string) => {
return [address?.slice(0, 8), "...", address?.slice(address?.length - 5)].join("");
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jzsfkzm , makes sense to apply this

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/ui/components/custom/address.tsx (1)

11-13: Add guard for null/undefined address values (unresolved from past review).

The function signature expects a valid string, but there's no runtime validation. A previous review suggested adding a guard condition, and a maintainer agreed it should be applied. The change from optional chaining indicates an intent to require valid strings, but without a guard, null/undefined values will cause runtime errors.

Apply this diff to add proper validation:

-export const shortenAddress = (address: string) => {
-  return `${address.slice(0, 8)}...${address.slice(-5)}`;
+export const shortenAddress = (address: string): string => {
+  if (!address) return "";
+  return `${address.slice(0, 8)}...${address.slice(-5)}`;
 };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9af7103 and 5691c7d.

📒 Files selected for processing (9)
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx (1 hunks)
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts (1 hunks)
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts (2 hunks)
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts (2 hunks)
  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts (1 hunks)
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx (1 hunks)
  • apps/deploy-web/tests/ui/pages/LeapExt.tsx (2 hunks)
  • packages/ui/components/custom/address.tsx (2 hunks)
  • packages/ui/components/input.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts
  • apps/deploy-web/tests/ui/pages/LeapExt.tsx
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts
  • packages/ui/components/input.tsx
  • packages/ui/components/custom/address.tsx
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts
  • apps/deploy-web/tests/ui/pages/LeapExt.tsx
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts
  • packages/ui/components/input.tsx
  • packages/ui/components/custom/address.tsx
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx
🧠 Learnings (1)
📚 Learning: 2025-10-15T16:39:55.348Z
Learnt from: jzsfkzm
PR: akash-network/console#2039
File: apps/deploy-web/tests/ui/change-wallets.spec.ts:4-10
Timestamp: 2025-10-15T16:39:55.348Z
Learning: In the Akash Console E2E tests using the context-with-extension fixture, the first wallet is automatically created during fixture setup via `importWalletToLeap` in `apps/deploy-web/tests/ui/fixture/wallet-setup.ts`, so tests that call `frontPage.createWallet()` are creating a second wallet to test wallet switching functionality.

Applied to files:

  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts
  • apps/deploy-web/tests/ui/pages/LeapExt.tsx
🧬 Code graph analysis (4)
apps/deploy-web/tests/ui/pages/LeapExt.tsx (1)
apps/deploy-web/tests/ui/fixture/wallet-setup.ts (1)
  • approveWalletOperation (68-95)
apps/deploy-web/tests/ui/fixture/context-with-extension.ts (3)
apps/deploy-web/tests/ui/fixture/wallet-setup.ts (4)
  • getExtensionPage (15-27)
  • setupWallet (29-34)
  • connectWalletViaLeap (46-57)
  • awaitWalletAndApprove (59-66)
apps/deploy-web/tests/ui/fixture/base-test.ts (1)
  • injectUIConfig (16-25)
apps/deploy-web/tests/ui/actions/selectChainNetwork.ts (1)
  • selectChainNetwork (6-20)
packages/ui/components/input.tsx (2)
packages/ui/components/form.tsx (1)
  • FormLabel (133-133)
packages/ui/components/label.tsx (1)
  • Label (17-17)
apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx (2)
apps/deploy-web/tests/ui/fixture/test-env.config.ts (1)
  • testEnvConfig (12-16)
packages/ui/components/custom/address.tsx (1)
  • shortenAddress (11-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: Validate local packages
🔇 Additional comments (8)
apps/deploy-web/tests/ui/pages/LeapExt.tsx (2)

2-2: LGTM! Type imports aligned with usage.

The updates correctly import BrowserContext and approveWalletOperation, and the constructor parameter type is now explicit and consistent with Playwright's types.

Also applies to: 7-7, 11-11


41-44: LGTM! Clean implementation avoids event listener complexity.

This straightforward implementation waits for the popup page and approves the wallet operation without the event listener registration/cleanup pattern that was problematic in earlier iterations. The simpler approach is more maintainable.

apps/deploy-web/tests/ui/fixture/context-with-extension.ts (1)

30-31: LGTM! Clipboard permissions support copy operations in tests.

The clipboard permissions are appropriate for E2E tests that need to verify address copying functionality.

apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx (4)

1-13: LGTM! Clean page object setup with type-safe label constraints.

The type aliases for AuthorizeButtonLabel and AuthorizationListLabel provide compile-time safety for UI interaction selectors, following best practices for the page object pattern.


23-28: LGTM! Authorization flow correctly delegates wallet approval to caller.

The method performs the UI interactions for setting up authorization without attempting to handle the wallet approval popup. Past reviews flagged event listener issues, but the current implementation correctly separates concerns by letting the test orchestrate the approval step externally (as seen in LeapExt.acceptTransaction).


30-35: LGTM! Edit flow correctly uses shortened address for matching.

The method properly shortens the address to match the displayed format in the table, ensuring reliable element location.


37-41: LGTM! Revoke flow follows consistent pattern.

The revocation flow correctly implements a two-step confirmation pattern and matches rows using the shortened address format.

apps/deploy-web/tests/ui/fixture/wallet-setup.ts (1)

59-66: All callers have been updated with the extensionId parameter.

The verification confirms that the only caller at apps/deploy-web/tests/ui/fixture/context-with-extension.ts:71 is already passing all three required parameters: context, page, and extensionId. The implementation correctly uses this parameter in the getExtensionPage() call. No issues found.

Comment on lines +46 to +78
page: [
async ({ context, extensionId }, use) => {
try {
await context.waitForEvent("page", { timeout: 5000 });
} catch {
// ignore timeout error
}

const extPage = await getExtensionPage(context, extensionId);
const extPage = await getExtensionPage(context, extensionId);

await setupWallet(context, extPage);
await extPage.close();
const page = await context.newPage();
await injectUIConfig(page);
await setupWallet(context, extPage);
await extPage.close();
const page = await context.newPage();
await injectUIConfig(page);

if (testEnvConfig.NETWORK_ID !== "mainnet") {
try {
await page.goto(testEnvConfig.BASE_URL);
await connectWalletViaLeap(context, page);
await selectChainNetwork(page, testEnvConfig.NETWORK_ID);
await connectWalletViaLeap(context, page);
} catch {
// Fallback in case the default network is non-functional.
// E.g., during network upgrade when sandbox is already on a different version from mainnet
await page.goto(`${testEnvConfig.BASE_URL}?network=${testEnvConfig.NETWORK_ID}`);
await awaitWalletAndApprove(context, page);
if (testEnvConfig.NETWORK_ID !== "mainnet") {
try {
await page.goto(testEnvConfig.BASE_URL);
await connectWalletViaLeap(context, page);
await selectChainNetwork(page, testEnvConfig.NETWORK_ID);
await connectWalletViaLeap(context, page);
} catch {
// Fallback in case the default network is non-functional.
// E.g., during network upgrade when sandbox is already on a different version from mainnet
await page.goto(`${testEnvConfig.BASE_URL}?network=${testEnvConfig.NETWORK_ID}`);
await awaitWalletAndApprove(context, page, extensionId);
}
}
}

await use(page);
}
await use(page);
},
{ scope: "test", timeout: 5 * 60 * 1000 }
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the 5-minute timeout is necessary.

The page fixture now has explicit scope and timeout configuration. The test scope is appropriate for isolation, but the 5-minute timeout seems quite long for fixture setup.

Is the 5-minute timeout necessary for your test environment? Consider whether a shorter timeout (e.g., 2-3 minutes) would be sufficient, as excessively long timeouts can mask real issues with slow setup operations.


🌐 Web query:

What is a typical timeout for Playwright page fixtures in E2E tests?

💡 Result:

  • Default: Playwright’s per-test timeout is 30,000 ms (30s), and fixtures share that timeout by default. [1]
  • Common practice: keep quick page fixtures within the default 30s; for slower (worker-scoped or heavy) page fixtures people commonly set a separate fixture timeout of 60,000 ms (60s) or similar. Example: { timeout: 60000 } on the fixture. [1][2]

References:
[1] Playwright Test — Timeouts (defaults and fixture behavior).
[2] Playwright docs/examples showing fixture timeout usage (example uses 60000 ms).


Reduce fixture timeout from 5 minutes to align with best practices.

The 5-minute timeout (300,000 ms) is significantly excessive. Playwright's default per-test timeout is 30 seconds, and even for slower or heavy fixtures, common practice is to use a separate fixture timeout of around 60 seconds.

Set the timeout to 60,000 ms (1 minute) or 90,000 ms if the wallet setup consistently requires that duration. Overly long timeouts mask real issues with slow operations.

🤖 Prompt for AI Agents
In apps/deploy-web/tests/ui/fixture/context-with-extension.ts around lines 46 to
78, the fixture timeout is set to 5 * 60 * 1000 (300000 ms) which is excessive;
change the timeout value in the fixture options to 60000 (60,000 ms) to align
with best practices (or 90000 if you have measured that the wallet setup
consistently needs more time), keeping the same scope and behavior otherwise.

return (
<div className={cn("space-y-1", className)}>
{label && (formField.id ? <FormLabel>{label}</FormLabel> : <Label htmlFor={`${finalId}-input`}>{label}</Label>)}
{label && (formField.id ? <FormLabel htmlFor={`${finalId}-input`}>{label}</FormLabel> : <Label htmlFor={`${finalId}-input`}>{label}</Label>)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Good accessibility improvement; verify consistency with Textarea.

The addition of {label} as children to FormLabel and the htmlFor attribute improves accessibility by ensuring the label renders correctly and explicitly links to the input.

However, the Textarea component at line 107 uses FormLabel without the htmlFor attribute. For consistency, verify whether Textarea's FormLabel should also include htmlFor={${formField.id ? formField.id : id}-input} to match this pattern.


🏁 Script executed:

#!/bin/bash
# Verify if FormLabel in other similar components should also have htmlFor attribute
rg -n -C3 -P '<FormLabel[^>]*>.*?</FormLabel>' --type=tsx --type=ts

Length of output: 27





---

🏁 Script executed:

```shell
#!/bin/bash
# Alternative approach: find and examine the input.tsx file directly
echo "=== Examining input.tsx file ==="
fd -e tsx -e ts input.tsx

Length of output: 177


🏁 Script executed:

#!/bin/bash
# Search for FormLabel patterns using file glob instead of type
rg -n -C3 '<FormLabel' packages/ui/ 

Length of output: 1199


🏁 Script executed:

#!/bin/bash
# Look for all tsx files in the ui components directory
fd -e tsx packages/ui/components/

Length of output: 397



---

🏁 Script executed:

```shell
#!/bin/bash
# Examine the full input.tsx file to understand context around both components
cat packages/ui/components/input.tsx

Length of output: 4778


Add htmlFor attribute to Textarea's FormLabel for consistency with Input component.

The accessibility improvement at line 59 (adding htmlFor to Input's FormLabel) is good. However, Textarea at line 107 uses FormLabel without the htmlFor attribute. Both components follow identical patterns when formField.id exists, so Textarea's FormLabel should also include htmlFor={${formField.id ? formField.id : id}-input} to maintain consistent accessibility.

Update line 107:

{label && (formField.id ? <FormLabel htmlFor={`${formField.id ? formField.id : id}-input`}>{label}</FormLabel> : <Label htmlFor={`${id}-input`}>{label}</Label>)}
🤖 Prompt for AI Agents
In packages/ui/components/input.tsx around lines 59 and 107, the Textarea
component's FormLabel is missing the htmlFor attribute (unlike the Input
component), so add htmlFor using the same id expression as Input: set
FormLabel's htmlFor to `${formField.id ? formField.id : id}-input` and keep the
existing Label fallback using `${id}-input`; this ensures consistent accessible
labeling for both Input and Textarea.

@stalniy stalniy force-pushed the test/2006-authorizations branch from 5691c7d to f0c3880 Compare November 5, 2025 13:20
@codecov
Copy link

codecov bot commented Nov 5, 2025

Codecov Report

❌ Patch coverage is 0% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.47%. Comparing base (7c1cc9e) to head (a65f1cc).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...c/components/authorizations/AllowanceIssuedRow.tsx 0.00% 2 Missing ⚠️
...components/authorizations/DeploymentGrantTable.tsx 0.00% 2 Missing ⚠️

❌ Your patch status has failed because the patch coverage (0.00%) is below the target coverage (50.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2109      +/-   ##
==========================================
- Coverage   46.82%   46.47%   -0.35%     
==========================================
  Files        1015     1005      -10     
  Lines       28800    28451     -349     
  Branches     7482     7453      -29     
==========================================
- Hits        13485    13223     -262     
+ Misses      14124    14046      -78     
+ Partials     1191     1182       -9     
Flag Coverage Δ *Carryforward flag
api 82.11% <ø> (ø) Carriedforward from 7c1cc9e
deploy-web 25.21% <0.00%> (+<0.01%) ⬆️
log-collector ?
notifications 88.11% <ø> (ø) Carriedforward from 7c1cc9e
provider-console 81.48% <ø> (ø)
provider-proxy 85.28% <ø> (ø) Carriedforward from 7c1cc9e

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
...b/src/components/authorizations/Authorizations.tsx 0.00% <ø> (ø)
...eb/src/components/authorizations/FeeGrantTable.tsx 0.00% <ø> (ø)
...c/components/authorizations/AllowanceIssuedRow.tsx 0.00% <0.00%> (ø)
...components/authorizations/DeploymentGrantTable.tsx 0.00% <0.00%> (ø)

... and 11 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5691c7d and f0c3880.

📒 Files selected for processing (13)
  • apps/deploy-web/src/components/authorizations/AllowanceIssuedRow.tsx (1 hunks)
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx (1 hunks)
  • apps/deploy-web/src/components/authorizations/DeploymentGrantTable.tsx (2 hunks)
  • apps/deploy-web/src/components/authorizations/FeeGrantTable.tsx (1 hunks)
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts (1 hunks)
  • apps/deploy-web/tests/ui/change-wallets.spec.ts (1 hunks)
  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts (1 hunks)
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts (2 hunks)
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts (2 hunks)
  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts (1 hunks)
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx (1 hunks)
  • apps/deploy-web/tests/ui/pages/LeapExt.tsx (2 hunks)
  • apps/deploy-web/tests/ui/uiState/isWalletConnected.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/deploy-web/src/components/authorizations/Authorizations.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/deploy-web/src/components/authorizations/DeploymentGrantTable.tsx
  • apps/deploy-web/tests/ui/authorize-spending.spec.ts
  • apps/deploy-web/tests/ui/uiState/isWalletConnected.ts
  • apps/deploy-web/tests/ui/change-wallets.spec.ts
  • apps/deploy-web/src/components/authorizations/AllowanceIssuedRow.tsx
  • apps/deploy-web/src/components/authorizations/FeeGrantTable.tsx
  • apps/deploy-web/tests/ui/disconnect-wallet.spec.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/tests/ui/pages/LeapExt.tsx
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts
  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/tests/ui/pages/LeapExt.tsx
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts
  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: baktun14
Repo: akash-network/console PR: 1725
File: apps/api/src/utils/constants.ts:5-5
Timestamp: 2025-07-24T17:00:52.361Z
Learning: In the Akash Network Console project, when cross-cutting concerns or broader refactoring issues are identified during PR review, the preferred approach is to create a separate GitHub issue to track the work rather than expanding the scope of the current PR. This maintains focus and allows for proper planning of architectural improvements.
Learnt from: jzsfkzm
Repo: akash-network/console PR: 2039
File: apps/deploy-web/tests/ui/change-wallets.spec.ts:4-10
Timestamp: 2025-10-15T16:39:55.348Z
Learning: In the Akash Console E2E tests using the context-with-extension fixture, the first wallet is automatically created during fixture setup via `importWalletToLeap` in `apps/deploy-web/tests/ui/fixture/wallet-setup.ts`, so tests that call `frontPage.createWallet()` are creating a second wallet to test wallet switching functionality.
📚 Learning: 2025-10-15T16:39:55.348Z
Learnt from: jzsfkzm
Repo: akash-network/console PR: 2039
File: apps/deploy-web/tests/ui/change-wallets.spec.ts:4-10
Timestamp: 2025-10-15T16:39:55.348Z
Learning: In the Akash Console E2E tests using the context-with-extension fixture, the first wallet is automatically created during fixture setup via `importWalletToLeap` in `apps/deploy-web/tests/ui/fixture/wallet-setup.ts`, so tests that call `frontPage.createWallet()` are creating a second wallet to test wallet switching functionality.

Applied to files:

  • apps/deploy-web/tests/ui/pages/LeapExt.tsx
  • apps/deploy-web/tests/ui/fixture/context-with-extension.ts
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts
  • apps/deploy-web/tests/ui/fixture/wallet-setup.ts
📚 Learning: 2025-10-31T11:26:42.138Z
Learnt from: stalniy
Repo: akash-network/console PR: 2138
File: apps/api/src/billing/lib/batch-signing-client/batch-signing-client.service.ts:379-382
Timestamp: 2025-10-31T11:26:42.138Z
Learning: In TypeScript/JavaScript, the pattern of checking a cached value and then performing an async operation to fetch it without proper synchronization is race condition unsafe:
```typescript
private async getAddress() {
  if (!this.address) {
    this.address = await this.wallet.getFirstAddress();
  }
  return this.address;
}
```
Multiple concurrent calls can all pass the `if (!this.address)` check before any of them sets the value, leading to duplicate async operations. This should be flagged as a race condition. Proper synchronization (mutex, atomic promise caching, or guaranteed single-threaded execution) is required.

Applied to files:

  • apps/deploy-web/tests/ui/pages/LeapExt.tsx
  • apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx
  • apps/deploy-web/tests/ui/fixture/testing-helpers.ts
🧬 Code graph analysis (3)
apps/deploy-web/tests/ui/pages/LeapExt.tsx (1)
apps/deploy-web/tests/ui/fixture/wallet-setup.ts (1)
  • approveWalletOperation (68-95)
apps/deploy-web/tests/ui/fixture/context-with-extension.ts (4)
apps/deploy-web/tests/ui/fixture/wallet-setup.ts (4)
  • getExtensionPage (15-27)
  • setupWallet (29-34)
  • connectWalletViaLeap (46-57)
  • awaitWalletAndApprove (59-66)
apps/deploy-web/tests/ui/fixture/base-test.ts (1)
  • injectUIConfig (16-25)
apps/deploy-web/tests/ui/fixture/test-env.config.ts (1)
  • testEnvConfig (12-16)
apps/deploy-web/tests/ui/actions/selectChainNetwork.ts (1)
  • selectChainNetwork (6-20)
apps/deploy-web/tests/ui/pages/AuthorizationsPage.tsx (2)
apps/deploy-web/tests/ui/fixture/test-env.config.ts (1)
  • testEnvConfig (12-16)
packages/ui/components/custom/address.tsx (1)
  • shortenAddress (11-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: Validate local packages
🔇 Additional comments (2)
apps/deploy-web/tests/ui/fixture/testing-helpers.ts (1)

17-19: Streamlined fill helper looks good.

Removing the extra wait/variable keeps the helper lean without changing behavior.

apps/deploy-web/tests/ui/pages/LeapExt.tsx (1)

41-44: Nice reuse of the shared approval flow.

Hooking into approveWalletOperation keeps LeapExt aligned with the fixture helpers.

Comment on lines +31 to +39
export const clickCopyAddressButton = async (page: Page) => {
await page.getByRole("button", { name: /akash\.\.\.[a-z0-9]{5}/ }).click();

const clipboardContents = await page.evaluate(async () => {
return await navigator.clipboard.readText();
});

return clipboardContents;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Regex misses real button labels.

shortenAddress now renders labels like akash1ab...vwxyz, so this pattern never matches (it insists on akash...). The click will hang as soon as the prefix includes digits, breaking every test case with a real address.

Loosen the regex so it tolerates the characters between akash and the ellipsis.

-export const clickCopyAddressButton = async (page: Page) => {
-  await page.getByRole("button", { name: /akash\.\.\.[a-z0-9]{5}/ }).click();
-
-  const clipboardContents = await page.evaluate(async () => {
-    return await navigator.clipboard.readText();
-  });
-
-  return clipboardContents;
-};
+export const clickCopyAddressButton = async (page: Page) => {
+  const copyButton = page.getByRole("button", { name: /akash.*\.\.\.[a-z0-9]{5}/i });
+  await copyButton.click();
+
+  const clipboardContents = await page.evaluate(async () => {
+    return await navigator.clipboard.readText();
+  });
+
+  return clipboardContents;
+};
🤖 Prompt for AI Agents
In apps/deploy-web/tests/ui/fixture/testing-helpers.ts around lines 31 to 39,
the button role selector uses a regex that expects "akash\.\.\.[a-z0-9]{5}" and
fails when there are characters (including digits) between "akash" and the
ellipsis; update the regex to allow any lowercase alphanumeric characters
between "akash" and the "..." (for example change it to something like
/akash[a-z0-9]*\.\.\.[a-z0-9]{5}/) so the selector matches labels like
"akash1ab...vwxyz" and ensure the literal dots are escaped in the pattern.

Comment on lines +59 to 66
export async function awaitWalletAndApprove(context: BrowserContext, page: Page, extensionId: string) {
const popupPage = await Promise.race([
context.waitForEvent("page", { timeout: 5_000 }),
getExtensionPage(context, extensionId),
]);
await approveWalletOperation(popupPage);
await isWalletConnected(page);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Prevent timeout rejection from breaking the fallback.

If no popup arrives within 5 s, context.waitForEvent rejects first, so the whole Promise.race throws and skips the extension-page fallback. The loser promise also rejects unhandled, so the test flakes even when getExtensionPage would succeed milliseconds later.

Cache the extension-page promise and catch the timeout so you always settle with a Page.

 export async function awaitWalletAndApprove(context: BrowserContext, page: Page, extensionId: string) {
-  const popupPage = await Promise.race([
-    context.waitForEvent("page", { timeout: 5_000 }),
-    getExtensionPage(context, extensionId),
-  ]);
+  const extensionPagePromise = getExtensionPage(context, extensionId);
+  const popupPage =
+    (await Promise.race([
+      context.waitForEvent("page", { timeout: 5_000 }),
+      extensionPagePromise
+    ]).catch(async () => await extensionPagePromise)) ?? (await extensionPagePromise);
   await approveWalletOperation(popupPage);
   await isWalletConnected(page);
 }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/deploy-web/tests/ui/fixture/wallet-setup.ts around lines 59 to 66, the
Promise.race currently rejects when context.waitForEvent times out and prevents
the getExtensionPage fallback from ever resolving; to fix it, cache the
getExtensionPage(context, extensionId) promise in a variable, replace the raw
waitForEvent timeout with a non-throwing wrapper (e.g., a promise that resolves
to null on timeout or catches the rejection), then race the two so that a
rejected waitForEvent won’t abort the race or create an unhandled rejection;
finally, after the race ensure you always have a Page by using the cached
extension promise if the timeout path returned null and then proceed to
approveWalletOperation and isWalletConnected.

@stalniy stalniy force-pushed the test/2006-authorizations branch from f0c3880 to a65f1cc Compare November 6, 2025 06:27
@stalniy stalniy merged commit c94cea9 into akash-network:main Nov 6, 2025
62 of 63 checks passed
@stalniy
Copy link
Contributor

stalniy commented Nov 6, 2025

@jzsfkzm just for the future, the title of commit is wrong. This is not "test" only, because you modified deploy-web sources, this requires a new build. Otherwise test wont pass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments