@deeeed/metamask-harness 0.47.4 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +3 -2
- package/adapters/extension/lib/macos-focus.cjs +2 -2
- package/adapters/extension/live.sh +6 -8
- package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +1 -0
- package/adapters/shared/ensure-runner-deps.sh +6 -0
- package/dist/adapters/extension/runtime-decision.js +18 -1
- package/dist/adapters/extension/runtime.js +5 -5
- package/dist/adapters/extension/surface.js +1 -0
- package/dist/app-lifecycle.js +3 -1
- package/dist/command-contract.js +2 -0
- package/dist/commands/call.js +1 -8
- package/dist/commands/device-target.js +12 -3
- package/dist/commands/doctor.js +7 -5
- package/dist/commands/fixtures.js +1 -1
- package/dist/commands/help.js +17 -5
- package/dist/commands/launch/index.js +10 -0
- package/dist/commands/manifest.js +3 -1
- package/dist/commands/mobile-device-view.js +13 -3
- package/dist/commands/parse-args.js +2 -0
- package/dist/commands/run-engine.js +29 -4
- package/dist/commands/run.js +1 -1
- package/dist/commands/runtime-launch.js +10 -1
- package/dist/commands/status.js +8 -4
- package/dist/devices.js +31 -9
- package/dist/execution-provenance.js +8 -7
- package/dist/funding-execution-context.js +62 -17
- package/dist/heal-bounds.js +3 -3
- package/dist/live-adapter-contract.js +4 -0
- package/dist/manifest.js +2 -13
- package/dist/metamask-action-validation.js +3 -2
- package/dist/mm-harness-cli.js +4 -2
- package/dist/runner.js +14 -3
- package/docs/RECIPES.md +135 -24
- package/docs/RELEASE-QA-CAPABILITY-MAP.md +3 -2
- package/library/actions/core/perps/_controller.mjs +24 -24
- package/library/actions/core/perps/assert_orders.mjs +3 -5
- package/library/actions/core/perps/assert_positions.mjs +3 -5
- package/library/actions/core/perps/close_orders.mjs +39 -19
- package/library/actions/core/perps/close_positions.mjs +53 -12
- package/library/actions/core/perps/edit_order.mjs +2 -0
- package/library/actions/core/perps/ensure_orders.mjs +3 -4
- package/library/actions/core/perps/ensure_positions.mjs +4 -5
- package/library/actions/core/perps/place_order.mjs +7 -14
- package/library/actions/core/perps/read_account.mjs +2 -0
- package/library/actions/core/perps/read_orders.mjs +2 -0
- package/library/actions/core/perps/read_positions.mjs +3 -1
- package/library/actions/core/perps/read_snapshot.mjs +3 -0
- package/library/actions/core/perps/start_state.mjs +3 -14
- package/library/actions/core/perps/teardown_state.mjs +3 -14
- package/library/actions/core/perps/update_position_tpsl.mjs +13 -19
- package/library/actions/core/wallet/list_accounts.mjs +3 -0
- package/library/actions/extension/analytics/consent.mjs +2 -0
- package/library/actions/extension/analytics/set_consent.mjs +2 -0
- package/library/actions/extension/assets/home-token-identity.mjs +31 -0
- package/library/actions/extension/assets/import_custom_token.mjs +63 -79
- package/library/actions/extension/assets/open_details.mjs +19 -7
- package/library/actions/extension/assets/prepare_send.mjs +1 -0
- package/library/actions/extension/assets/read_details.mjs +62 -29
- package/library/actions/extension/assets/read_visible_state.mjs +5 -1
- package/library/actions/extension/assets/review_send.mjs +1 -0
- package/library/actions/extension/assets/select_network_scope.mjs +17 -9
- package/library/actions/extension/assets/send.mjs +2 -0
- package/library/actions/extension/assets/set_custom_gas.mjs +1 -0
- package/library/actions/extension/assets/set_token_visibility.mjs +86 -17
- package/library/actions/extension/assets/verify_sorting.mjs +63 -14
- package/library/actions/extension/deeplink/open.mjs +1 -0
- package/library/actions/extension/networks/add_chainlist.mjs +2 -0
- package/library/actions/extension/networks/add_custom.mjs +21 -17
- package/library/actions/extension/networks/custom_network.mjs +10 -3
- package/library/actions/extension/networks/read_visible_state.mjs +2 -0
- package/library/actions/extension/networks/remove_custom.mjs +1 -0
- package/library/actions/extension/performance/_navigation-memory.mjs +37 -6
- package/library/actions/extension/performance/compare_idle_navigation_memory.mjs +5 -2
- package/library/actions/extension/performance/measure_detached_dom.mjs +5 -2
- package/library/actions/extension/performance/measure_navigation_memory.mjs +5 -2
- package/library/actions/extension/perps/assert_orders.mjs +1 -0
- package/library/actions/extension/perps/assert_positions.mjs +1 -0
- package/library/actions/extension/perps/assert_visible_consistency.mjs +11 -4
- package/library/actions/extension/perps/close_orders.mjs +4 -1
- package/library/actions/extension/perps/close_positions.mjs +1 -0
- package/library/actions/extension/perps/close_visible_position.mjs +160 -11
- package/library/actions/extension/perps/compare_provider_market.mjs +2 -0
- package/library/actions/extension/perps/edit_margin.mjs +3 -1
- package/library/actions/extension/perps/ensure_orders.mjs +1 -0
- package/library/actions/extension/perps/ensure_positions.mjs +1 -0
- package/library/actions/extension/perps/mutation-receipt.mjs +54 -3
- package/library/actions/extension/perps/open_balance_action.mjs +17 -7
- package/library/actions/extension/perps/open_position_action.mjs +1 -0
- package/library/actions/extension/perps/perps.mjs +550 -69
- package/library/actions/extension/perps/place_order.mjs +1 -0
- package/library/actions/extension/perps/read_eligibility.mjs +1 -0
- package/library/actions/extension/perps/read_funds_confirmation.mjs +10 -0
- package/library/actions/extension/perps/read_orders.mjs +1 -0
- package/library/actions/extension/perps/read_positions.mjs +1 -0
- package/library/actions/extension/perps/read_snapshot.mjs +4 -1
- package/library/actions/extension/perps/read_visible_state.mjs +12 -6
- package/library/actions/extension/perps/search_markets.mjs +8 -2
- package/library/actions/extension/perps/select_activity_filter.mjs +2 -1
- package/library/actions/extension/perps/select_market_filter.mjs +75 -45
- package/library/actions/extension/perps/set_market_favorite.mjs +7 -3
- package/library/actions/extension/perps/state.mjs +2 -0
- package/library/actions/extension/perps/update_position_tpsl.mjs +3 -1
- package/library/actions/extension/perps/visible-mutation-identity.mjs +6 -2
- package/library/actions/extension/platform/cdp.mjs +50 -142
- package/library/actions/extension/settings/set_basic_functionality.mjs +1 -0
- package/library/actions/extension/swap_bridge/quote-state.mjs +56 -0
- package/library/actions/extension/swap_bridge/read_visible_state.mjs +5 -1
- package/library/actions/extension/swap_bridge/select_assets.mjs +12 -1
- package/library/actions/extension/swap_bridge/set_amount.mjs +11 -8
- package/library/actions/extension/swap_bridge/set_max_amount.mjs +18 -18
- package/library/actions/extension/swap_bridge/set_slippage.mjs +1 -9
- package/library/actions/extension/ui/locators.mjs +1 -0
- package/library/actions/extension/ui/navigate.mjs +60 -14
- package/library/actions/extension/wallet/ensure_unlocked.mjs +2 -0
- package/library/actions/extension/wallet/import.mjs +2 -0
- package/library/actions/extension/wallet/list_accounts.mjs +1 -0
- package/library/actions/extension/wallet/lock.mjs +4 -1
- package/library/actions/extension/wallet/read_state.mjs +1 -0
- package/library/actions/extension/wallet/reset.mjs +2 -0
- package/library/actions/extension/wallet/secret-input.mjs +2 -0
- package/library/actions/extension/wallet/select_account.mjs +2 -0
- package/library/actions/extension/wallet/setup.mjs +1 -0
- package/library/actions/extension/wallet/state.mjs +2 -0
- package/library/actions/extension/wallet/visible-session.mjs +2 -0
- package/library/actions/mobile/analytics/consent-settings.mjs +1 -0
- package/library/actions/mobile/analytics/set_consent.mjs +1 -0
- package/library/actions/mobile/app/network-control.mjs +2 -0
- package/library/actions/mobile/app/network.mjs +1 -0
- package/library/actions/mobile/app/network_assert.mjs +1 -0
- package/library/actions/mobile/app/network_capture.mjs +1 -0
- package/library/actions/mobile/assets/import_custom_token.mjs +3 -0
- package/library/actions/mobile/assets/open_details.mjs +1 -0
- package/library/actions/mobile/assets/read_details.mjs +1 -0
- package/library/actions/mobile/assets/read_visible_state.mjs +4 -1
- package/library/actions/mobile/assets/set_token_visibility.mjs +15 -9
- package/library/actions/mobile/assets/verify_sorting.mjs +90 -7
- package/library/actions/mobile/deeplink/open.mjs +1 -0
- package/library/actions/mobile/networks/add_custom.mjs +1 -0
- package/library/actions/mobile/networks/network-management.mjs +23 -15
- package/library/actions/mobile/networks/read_visible_state.mjs +1 -0
- package/library/actions/mobile/networks/remove_custom.mjs +7 -2
- package/library/actions/mobile/perps/assert_orders.mjs +1 -0
- package/library/actions/mobile/perps/assert_positions.mjs +1 -0
- package/library/actions/mobile/perps/capture_performance.mjs +1 -0
- package/library/actions/mobile/perps/close_orders.mjs +1 -0
- package/library/actions/mobile/perps/close_positions.mjs +1 -0
- package/library/actions/mobile/perps/ensure_orders.mjs +1 -0
- package/library/actions/mobile/perps/ensure_positions.mjs +1 -0
- package/library/actions/mobile/perps/measure_homepage_visible.mjs +1 -0
- package/library/actions/mobile/perps/performance-capture.mjs +2 -0
- package/library/actions/mobile/perps/perps.mjs +8 -1
- package/library/actions/mobile/perps/place_order.mjs +1 -0
- package/library/actions/mobile/perps/prepare_local_snapshot_endpoint.mjs +2 -0
- package/library/actions/mobile/perps/read-visible-state-loop.mjs +3 -0
- package/library/actions/mobile/perps/read_orders.mjs +1 -0
- package/library/actions/mobile/perps/read_positions.mjs +1 -0
- package/library/actions/mobile/perps/read_visible_state.mjs +1 -0
- package/library/actions/mobile/perps/search_markets.mjs +1 -0
- package/library/actions/mobile/perps/set_market_favorite.mjs +17 -19
- package/library/actions/mobile/platform/bridge.mjs +16 -4
- package/library/actions/mobile/platform/native-session-name.mjs +1 -0
- package/library/actions/mobile/platform/native-session.mjs +28 -17
- package/library/actions/mobile/platform/observe-ui.mjs +4 -2
- package/library/actions/mobile/platform/tool-paths.mjs +1 -0
- package/library/actions/mobile/swap_bridge/native-session.mjs +1 -0
- package/library/actions/mobile/swap_bridge/read_visible_state.mjs +1 -0
- package/library/actions/mobile/swap_bridge/select_assets.mjs +2 -0
- package/library/actions/mobile/swap_bridge/set_amount.mjs +1 -0
- package/library/actions/mobile/swap_bridge/set_max_amount.mjs +1 -0
- package/library/actions/mobile/swap_bridge/set_slippage.mjs +1 -0
- package/library/actions/mobile/swap_bridge/submit_transaction.mjs +2 -0
- package/library/actions/mobile/ui/locators.mjs +1 -0
- package/library/actions/mobile/ui/native-navigation.mjs +2 -0
- package/library/actions/mobile/ui/navigate.mjs +3 -1
- package/library/actions/mobile/wallet/ensure_unlocked.mjs +2 -0
- package/library/actions/mobile/wallet/home.mjs +1 -0
- package/library/actions/mobile/wallet/import.mjs +2 -0
- package/library/actions/mobile/wallet/list_accounts.mjs +1 -0
- package/library/actions/mobile/wallet/lock.mjs +1 -0
- package/library/actions/mobile/wallet/native-ui.mjs +2 -0
- package/library/actions/mobile/wallet/read_state.mjs +2 -0
- package/library/actions/mobile/wallet/reset-helper.mjs +1 -0
- package/library/actions/mobile/wallet/reset.mjs +1 -0
- package/library/actions/mobile/wallet/select_account.mjs +2 -0
- package/library/actions/mobile/wallet/setup.mjs +2 -0
- package/library/actions/shared/analytics/assert_events.mjs +3 -0
- package/library/actions/shared/analytics/consent.mjs +3 -0
- package/library/actions/shared/analytics/read_events.mjs +2 -0
- package/library/actions/shared/analytics/start_capture.mjs +3 -0
- package/library/actions/shared/app/network-artifact.mjs +2 -0
- package/library/actions/shared/app/network-assert.mjs +2 -0
- package/library/actions/shared/assets/visible-state.mjs +2 -0
- package/library/actions/shared/deeplink/url.mjs +3 -0
- package/library/actions/shared/networks/visible-state.mjs +2 -0
- package/library/actions/shared/perps/visible-state.mjs +16 -3
- package/library/actions/shared/swap-bridge/transaction.mjs +3 -0
- package/library/actions/shared/swap-bridge/visible-state.mjs +2 -0
- package/library/actions/shared/ui/locators.mjs +2 -0
- package/library/actions/shared/wallet/import-source.mjs +3 -0
- package/library/manifests/core.action-manifest.json +34 -2
- package/library/manifests/extension.action-manifest.json +50 -17
- package/library/manifests/mobile.action-manifest.json +11 -10
- package/library/recipes/core/perps/smoke.recipe.json +23 -0
- package/library/recipes/core/perps/snapshot.recipe.json +26 -1
- package/library/recipes/extension/assets/release-custom-network-token-persistence.recipe.json +25 -8
- package/library/recipes/extension/performance/navigation-memory-suite.recipe.json +219 -0
- package/library/recipes/extension/performance/navigation-memory.recipe.json +61 -156
- package/library/recipes/extension/wallet/smoke.recipe.json +17 -8
- package/library/recipes/mobile/app/lifecycle-smoke.recipe.json +89 -0
- package/library/recipes/mobile/networks/release-custom-network-persistence.recipe.json +31 -6
- package/library/recipes/mobile/networks/release-multichain-visibility.recipe.json +5 -4
- package/library/recipes/mobile/wallet/smoke.recipe.json +17 -8
- package/library/recipes/{assets → shared/assets}/release-token-address-import.recipe.json +7 -0
- package/library/recipes/{assets → shared/assets}/release-token-details.recipe.json +2 -2
- package/library/recipes/shared/assets/release-token-hide-readd.recipe.json +91 -0
- package/library/recipes/{assets → shared/assets}/release-token-persistence.recipe.json +3 -0
- package/library/recipes/{assets → shared/assets}/release-token-search-import.recipe.json +4 -1
- package/library/recipes/{assets → shared/assets}/release-token-sorting.recipe.json +13 -2
- package/library/recipes/{swap-bridge → shared/swap-bridge}/release-quote.recipe.json +29 -3
- package/package.json +3 -3
- package/site/assets/help-recipes.json +220 -27
- package/library/recipes/assets/release-token-hide-readd.recipe.json +0 -57
- package/library/recipes/core/perps/clean-market-testnet.recipe.json +0 -44
- package/library/recipes/core/perps/order-lifecycle.recipe.json +0 -82
- package/library/recipes/core/perps/read-markets.recipe.json +0 -36
- package/library/recipes/core/perps/trading-lifecycle.recipe.json +0 -80
- package/library/recipes/extension/perps/release-activity-filters.recipe.json +0 -51
- package/library/recipes/extension/perps/release-funds-flows.recipe.json +0 -76
- package/library/recipes/extension/perps/release-live-limit-order.recipe.json +0 -109
- package/library/recipes/extension/perps/release-market-filters.recipe.json +0 -97
- package/library/recipes/extension/perps/release-order-entry.recipe.json +0 -158
- package/library/recipes/extension/perps/release-order-validation.recipe.json +0 -259
- package/library/recipes/extension/perps/release-visible-consistency.recipe.json +0 -47
- package/library/recipes/extension/perps/source-dev-snapshot-consistency.recipe.json +0 -76
- package/library/recipes/mobile/app/lifecycle.android-smoke.recipe.json +0 -69
- package/library/recipes/mobile/perps/chase-assert-running.recipe.json +0 -110
- package/library/recipes/mobile/perps/chase-place.recipe.json +0 -145
- package/library/recipes/mobile/perps/chase-terminate.recipe.json +0 -98
- package/library/recipes/mobile/perps/performance.recipe.json +0 -722
- package/library/recipes/mobile/perps/pro-order-setup.recipe.json +0 -111
- package/library/recipes/mobile/perps/pro-order-start-state.recipe.json +0 -53
- package/library/recipes/mobile/perps/scale-assert-orders.recipe.json +0 -126
- package/library/recipes/mobile/perps/scale-place.recipe.json +0 -186
- package/library/recipes/mobile/perps/twap-assert-active.recipe.json +0 -97
- package/library/recipes/mobile/perps/twap-place.recipe.json +0 -146
- package/library/recipes/mobile/runner/action-validation.recipe.json +0 -336
- package/library/recipes/perps/clean-market-testnet.recipe.json +0 -49
- package/library/recipes/perps/lifecycle.recipe.json +0 -144
- package/library/recipes/perps/release-live-market-order.recipe.json +0 -139
- package/library/recipes/perps/release-watchlist.recipe.json +0 -111
- package/library/recipes/swap-bridge/release-max-quote.recipe.json +0 -72
- /package/library/recipes/{assets → shared/assets}/release-token-list.recipe.json +0 -0
- /package/library/recipes/{perps → shared/perps}/release-market-details.recipe.json +0 -0
- /package/library/recipes/{perps → shared/perps}/release-market-search.recipe.json +0 -0
- /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-custom-slippage.recipe.json +0 -0
- /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-live-max-swap.recipe.json +0 -0
- /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-live-swap.recipe.json +0 -0
- /package/library/recipes/{swap-bridge → shared/swap-bridge}/release-surface.recipe.json +0 -0
- /package/library/recipes/{wallet → shared/wallet}/import.recipe.json +0 -0
- /package/library/recipes/{wallet → shared/wallet}/reset-import.recipe.json +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Read the displayed Perps deposit or withdrawal confirmation and check requested UI expectations.
|
|
2
|
+
// Report preview fields, submit availability, and layout without submitting funds.
|
|
1
3
|
import { runAdapter, withExtensionPage } from '../platform/cdp.mjs';
|
|
2
4
|
|
|
3
5
|
function expectedList(value, name) {
|
|
@@ -117,6 +119,14 @@ export async function readFundsConfirmation(page, node, mode, timeoutMs = 30_000
|
|
|
117
119
|
if (observed?.title !== expectedTitle || observed?.amount === null) {
|
|
118
120
|
throw new Error(`Perps ${mode} confirmation did not finish loading.`);
|
|
119
121
|
}
|
|
122
|
+
if (node.require_preview_fields === true) {
|
|
123
|
+
const missing = ['transactionFee', 'estimatedTime', 'receive'].filter((field) => !observed[field]);
|
|
124
|
+
if (!observed.payToken && !observed.receiveToken) missing.push('payToken/receiveToken');
|
|
125
|
+
if (observed.loadingVisible) missing.push('loading not settled');
|
|
126
|
+
if (missing.length > 0) {
|
|
127
|
+
throw new Error(`Perps ${mode} preview is incomplete: ${missing.join(', ')}.\nNext: mm-harness logs --full`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
120
130
|
if (node.require_no_horizontal_overflow === true && (
|
|
121
131
|
observed.layout.horizontalOverflow || observed.layout.clippedTestIds.length > 0
|
|
122
132
|
)) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Read bounded, normalized Perps snapshots through background APIs, optionally sampling market changes.
|
|
2
|
+
// History checks can require a matching visible activity card identity.
|
|
1
3
|
import { pathToFileURL } from 'node:url';
|
|
2
4
|
|
|
3
5
|
import { normalizeMarketSymbol, runAdapter, withExtensionPage } from '../platform/cdp.mjs';
|
|
@@ -499,7 +501,8 @@ async function visibleActivityCards(page) {
|
|
|
499
501
|
return {
|
|
500
502
|
testId: String(element.getAttribute('data-testid') || '').slice(0, 500),
|
|
501
503
|
label: String(element.innerText || '').replace(/\\s+/gu, ' ').trim().slice(0, 500),
|
|
502
|
-
visible: style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0
|
|
504
|
+
visible: style.display !== 'none' && style.visibility !== 'hidden' && rect.width > 0 && rect.height > 0 &&
|
|
505
|
+
rect.bottom > 0 && rect.right > 0 && rect.top < innerHeight && rect.left < innerWidth,
|
|
503
506
|
};
|
|
504
507
|
})`);
|
|
505
508
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
// Capture Perps DOM controls, order-entry values, and layout within configured item and visibility bounds.
|
|
2
|
+
// Normalize the observation and check requested visible-state expectations.
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
|
|
1
5
|
import { runAdapter, withExtensionPage } from '../platform/cdp.mjs';
|
|
2
6
|
import {
|
|
3
7
|
normalizeVisiblePerpsState,
|
|
@@ -38,7 +42,7 @@ export async function readVisiblePerpsState(page, node = {}) {
|
|
|
38
42
|
const raw = await page.evaluate(`(() => {
|
|
39
43
|
const includeOffscreen = ${JSON.stringify(options.includeOffscreen)};
|
|
40
44
|
const maximum = ${JSON.stringify(options.maxItems)};
|
|
41
|
-
const relevant = /^(?:perps-|explore-markets-|market-list-view|market-row-|filter-select-button|sort-dropdown-button|search-input|position-card-|order-card-|transaction-card-|bottom-nav-|back-button|direction-|order-type-|amount-|balance-percent-|leverage-|auto-close|submit-order-button|limit-price-|tp-|sl-|custom-amount-|pay-with-|confirm-footer-button|wallet-initiated-header-back-button|transaction-fee-|bridge-(?:fee|time)-|receive-(?:row|value))/u;
|
|
45
|
+
const relevant = /^(?:perps-|parent-selector-perps-(?:market-list|order-entry)|explore-markets-|market-list-view|market-row-|filter-select-button|sort-dropdown-button|search-input|position-card-|order-card-|transaction-card-|bottom-nav-|back-button|direction-|order-type-|amount-|balance-percent-|leverage-|auto-close|submit-order-button|limit-price-|tp-|sl-|custom-amount-|pay-with-|confirm-footer-button|wallet-initiated-header-back-button|transaction-fee-|bridge-(?:fee|time)-|receive-(?:row|value))/u;
|
|
42
46
|
const items = [];
|
|
43
47
|
const offscreenItems = [];
|
|
44
48
|
const clippedTestIds = [];
|
|
@@ -115,7 +119,7 @@ export async function readVisiblePerpsState(page, node = {}) {
|
|
|
115
119
|
items,
|
|
116
120
|
offscreenItems,
|
|
117
121
|
truncated: matched > items.length + offscreenItems.length,
|
|
118
|
-
orderEntry: document.querySelector('[data-testid="perps-order-entry-page"]') ? {
|
|
122
|
+
orderEntry: document.querySelector('[data-testid="parent-selector-perps-order-entry"], [data-testid="perps-order-entry-page"]') ? {
|
|
119
123
|
symbol: field('perps-order-entry-asset-symbol')?.label || null,
|
|
120
124
|
direction,
|
|
121
125
|
orderType: field('order-type-limit')?.pressed === 'true' ? 'limit' : 'market',
|
|
@@ -150,7 +154,9 @@ export async function readVisiblePerpsState(page, node = {}) {
|
|
|
150
154
|
};
|
|
151
155
|
}
|
|
152
156
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
158
|
+
runAdapter(async (input) => withExtensionPage(input, async (page) => ({
|
|
159
|
+
action: input.action,
|
|
160
|
+
...await readVisiblePerpsState(page, input.node),
|
|
161
|
+
})));
|
|
162
|
+
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
// Enter a Perps market search query and wait for at least one displayed result row.
|
|
1
2
|
import { dataTestId, runAdapter, withExtensionPage } from '../platform/cdp.mjs';
|
|
2
3
|
|
|
3
4
|
runAdapter(async (input) => withExtensionPage(input, async (page) => {
|
|
4
5
|
const query = String(input.node?.query ?? '').trim();
|
|
5
6
|
const timeoutMs = Number(input.node?.timeout_ms ?? 30_000);
|
|
6
7
|
if (!query) throw new Error('metamask.perps.search_markets requires a non-empty query.');
|
|
7
|
-
|
|
8
|
+
const searchInput = dataTestId('search-input');
|
|
9
|
+
if (!await page.evaluate(`Boolean(document.querySelector(${JSON.stringify(searchInput)}))`)) {
|
|
10
|
+
await page.click(dataTestId('market-list-search-toggle'));
|
|
11
|
+
await page.waitForSelector(searchInput, { timeoutMs });
|
|
12
|
+
}
|
|
13
|
+
await page.setInput(searchInput, query);
|
|
8
14
|
const deadline = Date.now() + timeoutMs;
|
|
9
15
|
let marketIds = [];
|
|
10
16
|
while (Date.now() <= deadline) {
|
|
@@ -18,7 +24,7 @@ runAdapter(async (input) => withExtensionPage(input, async (page) => {
|
|
|
18
24
|
.filter(Boolean)
|
|
19
25
|
.slice(0, 100))()`);
|
|
20
26
|
if (marketIds.length > 0) break;
|
|
21
|
-
await
|
|
27
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
22
28
|
}
|
|
23
29
|
if (marketIds.length === 0) {
|
|
24
30
|
throw new Error(`Perps market search returned no visible rows for ${JSON.stringify(query)}.`);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Select a Perps activity filter and wait for its route, label, and loaded cards or empty state.
|
|
1
2
|
import { pathToFileURL } from 'node:url';
|
|
2
3
|
|
|
3
4
|
import { dataTestId, runAdapter, withExtensionPage } from '../platform/cdp.mjs';
|
|
@@ -62,7 +63,7 @@ export async function selectActivityFilter(page, input, options = {}) {
|
|
|
62
63
|
entries: cards.map((card) => card.label),
|
|
63
64
|
loadedBoundary: visible(document.querySelector('[data-testid="perps-activity-page-skeleton"]'))
|
|
64
65
|
? null
|
|
65
|
-
: visible(document.querySelector('[data-testid="perps-activity-page"]'))
|
|
66
|
+
: visible(document.querySelector('[data-testid="perps-activity-page"],[data-testid="parent-selector-perps-activity"]'))
|
|
66
67
|
? cards.length > 0 ? 'visible-cards' : 'loaded-empty'
|
|
67
68
|
: null,
|
|
68
69
|
empty: String(document.body?.innerText || '').replace(/\\s+/gu, ' ').trim().slice(0, 2_000),
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
+
// Select a Perps market category through the dropdown or category rail and inspect the resulting list.
|
|
1
2
|
import { pathToFileURL } from 'node:url';
|
|
2
3
|
|
|
3
4
|
import { dataTestId, runAdapter, withExtensionPage } from '../platform/cdp.mjs';
|
|
4
|
-
import {
|
|
5
|
-
normalizeVisiblePerpsState,
|
|
6
|
-
resolveVisibleStateOptions,
|
|
7
|
-
} from '../../shared/perps/visible-state.mjs';
|
|
5
|
+
import { readVisiblePerpsState } from './read_visible_state.mjs';
|
|
8
6
|
|
|
9
7
|
const FILTERS = new Map([
|
|
10
8
|
['all', 'all'],
|
|
@@ -34,21 +32,7 @@ async function visibleLabel(page, selector) {
|
|
|
34
32
|
})()`);
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
const filter = String(input.node?.filter ?? '').trim().toLowerCase();
|
|
39
|
-
const option = FILTERS.get(filter);
|
|
40
|
-
if (!option) {
|
|
41
|
-
throw new Error(`metamask.perps.select_market_filter received unsupported filter ${JSON.stringify(filter)}.`);
|
|
42
|
-
}
|
|
43
|
-
const options = resolveVisibleStateOptions({
|
|
44
|
-
surface: 'market-list',
|
|
45
|
-
include_offscreen: true,
|
|
46
|
-
max_items: input.node?.max_items ?? 100,
|
|
47
|
-
minimum_market_count: input.node?.minimum_market_count ?? 1,
|
|
48
|
-
maximum_market_count: input.node?.maximum_market_count ?? 200,
|
|
49
|
-
});
|
|
50
|
-
const timeoutMs = pollOptions.timeoutMs ?? input.node?.timeout_ms ?? 10_000;
|
|
51
|
-
const pollIntervalMs = pollOptions.pollIntervalMs ?? 100;
|
|
35
|
+
async function selectDropdownFilter(page, filter, option, timeoutMs, pollIntervalMs) {
|
|
52
36
|
await page.click(dataTestId('filter-select-button'));
|
|
53
37
|
const optionSelector = dataTestId(`filter-select-option-${option}`);
|
|
54
38
|
try {
|
|
@@ -76,37 +60,83 @@ export async function selectMarketFilter(page, input, pollOptions = {}) {
|
|
|
76
60
|
}
|
|
77
61
|
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
78
62
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
63
|
+
return { selectedLabel: selectedState.label, controlKind: 'dropdown', alreadySelected: false };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function categoryRailState(page) {
|
|
67
|
+
return page.evaluate(`(() => ({
|
|
68
|
+
active: [...document.querySelectorAll('[data-testid^="market-list-categories-pill-"][aria-pressed="true"]')].map((element) => ({
|
|
69
|
+
id: element.getAttribute('data-testid'),
|
|
70
|
+
option: element.getAttribute('data-testid').slice('market-list-categories-pill-'.length),
|
|
71
|
+
label: String(element.innerText || '').trim(),
|
|
72
|
+
})),
|
|
73
|
+
watchlist: document.querySelector('[data-testid="market-list-watchlist-toggle"]')?.getAttribute('aria-pressed') === 'true',
|
|
74
|
+
}))()`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function selectCategoryRail(page, option, timeoutMs, pollIntervalMs) {
|
|
78
|
+
const deadline = Date.now() + timeoutMs;
|
|
79
|
+
const matches = (state) => !state.watchlist && (option === 'all'
|
|
80
|
+
? state.active.length === 0
|
|
81
|
+
: state.active.length === 1 && state.active[0].option === option);
|
|
82
|
+
const initial = await categoryRailState(page);
|
|
83
|
+
const alreadySelected = matches(initial);
|
|
84
|
+
if (!alreadySelected) {
|
|
85
|
+
if (option === 'all') {
|
|
86
|
+
if (initial.watchlist) await page.click(dataTestId('market-list-watchlist-toggle'));
|
|
87
|
+
for (const selected of initial.active) await page.click(dataTestId(selected.id));
|
|
88
|
+
} else {
|
|
89
|
+
let selector = dataTestId(`market-list-categories-pill-${option}`);
|
|
90
|
+
if (!(await visibleLabel(page, selector)).visible) {
|
|
91
|
+
const more = dataTestId('market-list-categories-more-button');
|
|
92
|
+
selector = dataTestId(`market-list-categories-more-option-${option}`);
|
|
93
|
+
if (!(await visibleLabel(page, selector)).visible) {
|
|
94
|
+
if (!(await visibleLabel(page, more)).visible) {
|
|
95
|
+
throw new Error(`Perps market filter ${JSON.stringify(option)} is not available in this release.`);
|
|
96
|
+
}
|
|
97
|
+
await page.click(more);
|
|
98
|
+
}
|
|
99
|
+
await page.waitForSelector(selector, { timeoutMs: Math.max(1, deadline - Date.now()) });
|
|
100
|
+
}
|
|
101
|
+
await page.click(selector);
|
|
101
102
|
}
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
}
|
|
104
|
+
let selected = await categoryRailState(page);
|
|
105
|
+
while (!matches(selected)) {
|
|
106
|
+
if (Date.now() >= deadline) {
|
|
107
|
+
throw new Error(`Perps category ${JSON.stringify(option)} did not become selected: ${JSON.stringify(selected)}.`);
|
|
108
|
+
}
|
|
109
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
110
|
+
selected = await categoryRailState(page);
|
|
111
|
+
}
|
|
112
|
+
return { selectedLabel: selected.active[0]?.label ?? null, controlKind: 'category-rail', alreadySelected };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export async function selectMarketFilter(page, input, pollOptions = {}) {
|
|
116
|
+
const filter = String(input.node?.filter ?? '').trim().toLowerCase();
|
|
117
|
+
const option = FILTERS.get(filter);
|
|
118
|
+
if (!option) {
|
|
119
|
+
throw new Error(`metamask.perps.select_market_filter received unsupported filter ${JSON.stringify(filter)}.`);
|
|
120
|
+
}
|
|
121
|
+
const timeoutMs = pollOptions.timeoutMs ?? input.node?.timeout_ms ?? 10_000;
|
|
122
|
+
const pollIntervalMs = pollOptions.pollIntervalMs ?? 100;
|
|
123
|
+
const rail = await visibleLabel(page, dataTestId('market-list-categories'));
|
|
124
|
+
const selection = rail.visible
|
|
125
|
+
? await selectCategoryRail(page, option, timeoutMs, pollIntervalMs)
|
|
126
|
+
: await selectDropdownFilter(page, filter, option, timeoutMs, pollIntervalMs);
|
|
127
|
+
const state = await readVisiblePerpsState(page, {
|
|
128
|
+
surface: 'market-list',
|
|
129
|
+
include_offscreen: true,
|
|
130
|
+
max_items: input.node?.max_items ?? 100,
|
|
131
|
+
minimum_market_count: input.node?.minimum_market_count ?? 1,
|
|
132
|
+
maximum_market_count: input.node?.maximum_market_count ?? 200,
|
|
133
|
+
});
|
|
104
134
|
return {
|
|
105
135
|
action: input.action,
|
|
106
136
|
filter,
|
|
107
137
|
option,
|
|
108
|
-
|
|
109
|
-
...
|
|
138
|
+
...selection,
|
|
139
|
+
...state,
|
|
110
140
|
proofPath: 'trusted-pointer-visible-ui',
|
|
111
141
|
};
|
|
112
142
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Set the current market's favorite state through its visible control, or require it to be unchanged.
|
|
1
2
|
import { dataTestId, runAdapter, withExtensionPage } from '../platform/cdp.mjs';
|
|
2
3
|
|
|
3
4
|
runAdapter(async (input) => withExtensionPage(input, async (page) => {
|
|
@@ -20,9 +21,15 @@ runAdapter(async (input) => withExtensionPage(input, async (page) => {
|
|
|
20
21
|
const button = document.querySelector(${JSON.stringify(selector)});
|
|
21
22
|
if (!button) throw new Error('Perps favorite control is not visible.');
|
|
22
23
|
const label = String(button.getAttribute('aria-label') || button.innerText || '').trim();
|
|
24
|
+
if (!/^(?:add to|remove from) favorites$/iu.test(label)) {
|
|
25
|
+
throw new Error('Perps favorite control has an unsupported label: ' + JSON.stringify(label));
|
|
26
|
+
}
|
|
23
27
|
return { label, favorite: /^remove from favorites$/iu.test(label) };
|
|
24
28
|
})()`);
|
|
25
29
|
const before = await readState();
|
|
30
|
+
if (requireUnchanged && before.favorite !== desired) {
|
|
31
|
+
throw new Error(`Perps favorite state for ${market} did not persist across navigation; no change was made.`);
|
|
32
|
+
}
|
|
26
33
|
if (before.favorite !== desired) {
|
|
27
34
|
await page.click(selector);
|
|
28
35
|
}
|
|
@@ -37,9 +44,6 @@ runAdapter(async (input) => withExtensionPage(input, async (page) => {
|
|
|
37
44
|
throw new Error(`Perps favorite state did not become ${desired}.`);
|
|
38
45
|
}
|
|
39
46
|
const changed = before.favorite !== after.favorite;
|
|
40
|
-
if (requireUnchanged && changed) {
|
|
41
|
-
throw new Error(`Perps favorite state for ${market} did not persist across navigation.`);
|
|
42
|
-
}
|
|
43
47
|
return {
|
|
44
48
|
action: input.action,
|
|
45
49
|
market,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Build a page expression that reads Perps provider, network, initialization, and eligibility from state hooks.
|
|
1
2
|
export function readPerpsRuntimeStateExpression() {
|
|
2
3
|
return `(async () => {
|
|
3
4
|
const hooks = globalThis.stateHooks || {};
|
|
@@ -11,6 +12,7 @@ export function readPerpsRuntimeStateExpression() {
|
|
|
11
12
|
return {
|
|
12
13
|
available: typeof request === 'function',
|
|
13
14
|
activeProvider: metamask.activeProvider || nestedPerps.activeProvider || 'hyperliquid',
|
|
15
|
+
providerKnown: typeof (metamask.activeProvider ?? nestedPerps.activeProvider) === 'string',
|
|
14
16
|
networkKnown: typeof metamask.isTestnet === 'boolean' || typeof nestedPerps.isTestnet === 'boolean',
|
|
15
17
|
isTestnet: Boolean(metamask.isTestnet ?? nestedPerps.isTestnet),
|
|
16
18
|
initializationState: metamask.initializationState || nestedPerps.initializationState || null,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Submit live take-profit and stop-loss changes through visible controls with mutation receipts.
|
|
2
|
+
// Check the funded position identity and observe the exact requested prices.
|
|
1
3
|
import { dataTestId, runAdapter, withExtensionPage } from '../platform/cdp.mjs';
|
|
2
4
|
import {
|
|
3
5
|
assertTrustedExternalMutationTarget,
|
|
@@ -229,7 +231,6 @@ export async function updatePositionTpsl(input) {
|
|
|
229
231
|
let dispatchTarget;
|
|
230
232
|
try {
|
|
231
233
|
await requireCurrentVisibleFundingBalance(input, page, timeoutMs, fundingBalance.observedBaseUnits);
|
|
232
|
-
await requirePerpsTradingContext(input, page);
|
|
233
234
|
assertTrustedExternalMutationTarget(input, page, identity);
|
|
234
235
|
const current = await readPosition(page, market);
|
|
235
236
|
if (current.size !== before.size || current.direction !== before.direction
|
|
@@ -246,6 +247,7 @@ export async function updatePositionTpsl(input) {
|
|
|
246
247
|
const rect = element.getBoundingClientRect();
|
|
247
248
|
return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };
|
|
248
249
|
})()`);
|
|
250
|
+
await requirePerpsTradingContext(input, page);
|
|
249
251
|
assertTrustedExternalMutationTarget(input, page, identity);
|
|
250
252
|
} catch (error) {
|
|
251
253
|
throw externalMutationNotDispatched(error instanceof Error ? error.message : String(error));
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Parse and match visible Perps position and order identities using USD base-unit tolerances.
|
|
2
|
+
// Also wait for a stable, loaded Perps home view, optionally requiring zero positions and orders.
|
|
1
3
|
const INTEGER = /^(0|[1-9][0-9]{0,29})$/u;
|
|
2
4
|
|
|
3
5
|
export function parseUsdBaseUnits(value) {
|
|
@@ -129,10 +131,12 @@ export async function waitForStableGlobalPerpsHome(page, options = {}) {
|
|
|
129
131
|
return rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden';
|
|
130
132
|
};
|
|
131
133
|
const visibleCount = (selector) => [...document.querySelectorAll(selector)].filter(visible).length;
|
|
132
|
-
const balance = document.querySelector('[data-testid="perps-balance-
|
|
134
|
+
const balance = document.querySelector('[data-testid="perps-balance-actions-available-value"]')
|
|
135
|
+
?? document.querySelector('[data-testid="perps-balance-dropdown-balance"]');
|
|
133
136
|
return {
|
|
134
137
|
route: String(location.hash),
|
|
135
|
-
viewVisible: visible(document.querySelector('[data-testid="perps-
|
|
138
|
+
viewVisible: visible(document.querySelector('[data-testid="perps-home-page"]')
|
|
139
|
+
?? document.querySelector('[data-testid="perps-view"]')),
|
|
136
140
|
loading: visibleCount('[data-testid$="-skeleton"], [data-testid*="loading"]') > 0,
|
|
137
141
|
marketCount: visibleCount('[data-testid="perps-explore-markets-row"]'),
|
|
138
142
|
positionCount: visibleCount('[data-testid^="position-card-"]:not([data-testid^="position-card-roe-"])'),
|