From ddcb59274d836516e53fabf32fe81a28475dbd56 Mon Sep 17 00:00:00 2001 From: seaona Date: Mon, 1 Sep 2025 11:34:19 +0200 Subject: [PATCH 1/2] wss mock setup --- test/e2e/helpers.js | 15 +-- test/e2e/mock-e2e.js | 4 +- test/e2e/tests/solana/common-solana.ts | 6 +- .../solana/mocks/websocketDefaultMocks.ts | 56 +++++++++++ .../solana/web-socket-connection.spec.ts | 16 ++- test/e2e/websocket-solana-mocks.ts | 99 ++++++------------- 6 files changed, 114 insertions(+), 82 deletions(-) create mode 100644 test/e2e/tests/solana/mocks/websocketDefaultMocks.ts diff --git a/test/e2e/helpers.js b/test/e2e/helpers.js index 46236551eafa..a27a931814fa 100644 --- a/test/e2e/helpers.js +++ b/test/e2e/helpers.js @@ -26,7 +26,7 @@ const { getServerMochaToBackground, } = require('./background-socket/server-mocha-to-background'); const LocalWebSocketServer = require('./websocket-server').default; -const { setSolanaWebsocketMocks } = require('./websocket-solana-mocks'); +const { setupSolanaWebsocketMocks } = require('./websocket-solana-mocks'); const tinyDelayMs = 200; const regularDelayMs = tinyDelayMs * 2; @@ -128,7 +128,10 @@ async function withFixtures(options, testSuite) { ethConversionInUsd, monConversionInUsd, manifestFlags, - withSolanaWebSocket = false, + withSolanaWebSocket = { + server: false, + mocks: [], + }, } = options; // Normalize localNodeOptions @@ -261,12 +264,10 @@ async function withFixtures(options, testSuite) { } } - if (withSolanaWebSocket) { + if (withSolanaWebSocket.server) { localWebSocketServer = LocalWebSocketServer.getServerInstance(); localWebSocketServer.start(); - // All specs use the same ws mocks. - // If we need custom ws mocks we can expand logic for supporting custom ws mocks like with http - await setSolanaWebsocketMocks(); + await setupSolanaWebsocketMocks(withSolanaWebSocket.mocks); } const { mockedEndpoint, getPrivacyReport } = await setupMocking( @@ -454,7 +455,7 @@ async function withFixtures(options, testSuite) { })(), ); - if (withSolanaWebSocket) { + if (withSolanaWebSocket.server) { shutdownTasks.push(localWebSocketServer.stopAndCleanup()); } diff --git a/test/e2e/mock-e2e.js b/test/e2e/mock-e2e.js index d7d95b7b4d3d..3df51e967c09 100644 --- a/test/e2e/mock-e2e.js +++ b/test/e2e/mock-e2e.js @@ -143,7 +143,7 @@ const privateHostMatchers = [ * @param {object} options - Network mock options. * @param {string} options.chainId - The chain ID used by the default configured network. * @param {string} options.ethConversionInUsd - The USD conversion rate for ETH. - * @param {boolean} withSolanaWebSocket - If we want to re-route all the ws requests to our Solana Local WS server + * @param {object} withSolanaWebSocket - Solana WebSocket configuration with server flag and mocks function * @returns {Promise} */ async function setupMocking( @@ -946,7 +946,7 @@ async function setupMocking( * Solana Websocket * Setup HTTP intercept for WebSocket handshake requests */ - if (withSolanaWebSocket) { + if (withSolanaWebSocket.server) { await server .forAnyWebSocket() .matching((req) => diff --git a/test/e2e/tests/solana/common-solana.ts b/test/e2e/tests/solana/common-solana.ts index 8eef6c4ebb34..10c857a3de12 100644 --- a/test/e2e/tests/solana/common-solana.ts +++ b/test/e2e/tests/solana/common-solana.ts @@ -11,6 +11,7 @@ import { ACCOUNT_TYPE } from '../../constants'; import { loginWithBalanceValidation } from '../../page-objects/flows/login.flow'; import { mockProtocolSnap } from '../../mock-response-data/snaps/snap-binary-mocks'; import AssetListPage from '../../page-objects/pages/home/asset-list'; +import { DEFAULT_SOLANA_WS_MOCKS } from './mocks/websocketDefaultMocks'; const SOLANA_URL_REGEX_MAINNET = /^https:\/\/solana-(mainnet|devnet)\.infura\.io\/v3*/u; @@ -1611,7 +1612,10 @@ export async function withSolanaAccountSnap( fixtures: fixtures.build(), title, dapp: true, - withSolanaWebSocket: true, + withSolanaWebSocket: { + server: true, + mocks: DEFAULT_SOLANA_WS_MOCKS, + }, manifestFlags: { // This flag is used to enable/disable the remote mode for the carousel // component, which will impact to the slides count. diff --git a/test/e2e/tests/solana/mocks/websocketDefaultMocks.ts b/test/e2e/tests/solana/mocks/websocketDefaultMocks.ts new file mode 100644 index 000000000000..8612c6aa40a8 --- /dev/null +++ b/test/e2e/tests/solana/mocks/websocketDefaultMocks.ts @@ -0,0 +1,56 @@ +/** + * Configuration for a WebSocket message mock + */ +export interface WebSocketMessageMock { + /** String(s) that the message should include to trigger this mock */ + messageIncludes: string | string[]; + /** The JSON response to send back */ + response: object; + /** Delay before sending the response (in milliseconds) */ + delay?: number; + /** Custom log message for this mock */ + logMessage?: string; +} + +export const DEFAULT_SOLANA_WS_MOCKS: WebSocketMessageMock[] = [ + { + messageIncludes: 'signatureSubscribe', + response: { + jsonrpc: '2.0', + result: 8648699534240963, + id: '1', + }, + delay: 500, + logMessage: 'Signature subscribe message received from client', + }, + { + messageIncludes: 'accountSubscribe', + response: { + jsonrpc: '2.0', + result: 'b07ebf7caf2238a9b604d4dfcaf1934280fcd347d6eded62bc0def6cbb767d11', + id: '1', + }, + delay: 500, + logMessage: 'Account subscribe message received from client', + }, + { + messageIncludes: ['programSubscribe', 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'], + response: { + jsonrpc: '2.0', + result: '568eafd45635c108d0d426361143de125a841628a58679f5a024cbab9a20b41c', + id: '1', + }, + delay: 500, + logMessage: 'Program subscribe message received from client', + }, + { + messageIncludes: ['programSubscribe', 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'], + response: { + jsonrpc: '2.0', + result: 'f33dd9975158af47bf16c7f6062a73191d4595c59cfec605d5a51e25c65ffb51', + id: '1', + }, + delay: 500, + logMessage: 'Program subscribe message received from client', + }, +]; diff --git a/test/e2e/tests/solana/web-socket-connection.spec.ts b/test/e2e/tests/solana/web-socket-connection.spec.ts index 516411d052b1..7729229eda89 100644 --- a/test/e2e/tests/solana/web-socket-connection.spec.ts +++ b/test/e2e/tests/solana/web-socket-connection.spec.ts @@ -8,6 +8,7 @@ import HeaderNavbar from '../../page-objects/pages/header-navbar'; import AccountListPage from '../../page-objects/pages/account-list-page'; import FixtureBuilder from '../../fixture-builder'; import LocalWebSocketServer from '../../websocket-server'; +import { DEFAULT_SOLANA_WS_MOCKS } from './mocks/websocketDefaultMocks'; describe('Solana Web Socket', function (this: Suite) { it('a websocket connection is open when MetaMask full view is open', async function () { @@ -15,7 +16,10 @@ describe('Solana Web Socket', function (this: Suite) { { fixtures: new FixtureBuilder().build(), title: this.test?.fullTitle(), - withSolanaWebSocket: true, + withSolanaWebSocket: { + server: true, + mocks: DEFAULT_SOLANA_WS_MOCKS, + }, manifestFlags: { remoteFeatureFlags: { addSolanaAccount: true, @@ -50,7 +54,10 @@ describe('Solana Web Socket', function (this: Suite) { { fixtures: new FixtureBuilder().build(), title: this.test?.fullTitle(), - withSolanaWebSocket: true, + withSolanaWebSocket: { + server: true, + mocks: DEFAULT_SOLANA_WS_MOCKS, + }, manifestFlags: { remoteFeatureFlags: { addSolanaAccount: true, @@ -95,7 +102,10 @@ describe('Solana Web Socket', function (this: Suite) { { fixtures: new FixtureBuilder().build(), title: this.test?.fullTitle(), - withSolanaWebSocket: true, + withSolanaWebSocket: { + server: true, + mocks: DEFAULT_SOLANA_WS_MOCKS, + }, manifestFlags: { remoteFeatureFlags: { addSolanaAccount: true, diff --git a/test/e2e/websocket-solana-mocks.ts b/test/e2e/websocket-solana-mocks.ts index f7d8b168e527..c75ae2d4b0a0 100644 --- a/test/e2e/websocket-solana-mocks.ts +++ b/test/e2e/websocket-solana-mocks.ts @@ -1,12 +1,15 @@ // eslint-disable-next-line @typescript-eslint/no-shadow import { WebSocket } from 'ws'; import LocalWebSocketServer from './websocket-server'; +import { WebSocketMessageMock } from './tests/solana/mocks/websocketDefaultMocks'; /** - * WebSocket Solana mocks - * This function should be called after the WebSocket server is started + * Sets up Solana WebSocket mocks with configurable message handlers + * @param mocks Array of message mock configurations */ -export async function setSolanaWebsocketMocks(): Promise { +export async function setupSolanaWebsocketMocks( + mocks: WebSocketMessageMock[] = [], +): Promise { const localWebSocketServer = LocalWebSocketServer.getServerInstance(); const wsServer = localWebSocketServer.getServer(); @@ -18,72 +21,30 @@ export async function setSolanaWebsocketMocks(): Promise { socket.on('message', (data) => { const message = data.toString(); console.log('Message received from client:', message); - if (message.includes('signatureSubscribe')) { - console.log('Signature subscribe message received from client'); - setTimeout(() => { - socket.send( - JSON.stringify({ - jsonrpc: '2.0', - result: 8648699534240963, - id: '1', - }), - ); - console.log('Simulated message sent to the client'); - }, 500); // Delay the message by 500ms - } - if (message.includes('accountSubscribe')) { - console.log('Account subscribe message received from client'); - setTimeout(() => { - socket.send( - JSON.stringify({ - jsonrpc: '2.0', - result: - 'b07ebf7caf2238a9b604d4dfcaf1934280fcd347d6eded62bc0def6cbb767d11', - id: '1', - }), - ); - console.log( - 'Simulated message for accountSubscribe sent to the client', - ); - }, 500); // Delay the message by 500ms - } - if ( - message.includes('programSubscribe') && - message.includes('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA') - ) { - console.log('Program subscribe message received from client'); - setTimeout(() => { - socket.send( - JSON.stringify({ - jsonrpc: '2.0', - result: - '568eafd45635c108d0d426361143de125a841628a58679f5a024cbab9a20b41c', - id: '1', - }), - ); - console.log( - 'Simulated message for programSubscribe Token2022 sent to the client', - ); - }, 500); // Delay the message by 500ms - } - if ( - message.includes('programSubscribe') && - message.includes('TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb') - ) { - console.log('Program subscribe message received from client'); - setTimeout(() => { - socket.send( - JSON.stringify({ - jsonrpc: '2.0', - result: - 'f33dd9975158af47bf16c7f6062a73191d4595c59cfec605d5a51e25c65ffb51', - id: '1', - }), - ); - console.log( - 'Simulated message for programSubscribe sent to the client', - ); - }, 500); // Delay the message by 500ms + + // Check each mock configuration + for (const mock of mocks) { + const includes = Array.isArray(mock.messageIncludes) + ? mock.messageIncludes + : [mock.messageIncludes]; + + // Check if all required strings are included in the message + const matches = includes.every((includeStr) => message.includes(includeStr)); + + if (matches) { + if (mock.logMessage) { + console.log(mock.logMessage); + } + + const delay = mock.delay || 500; + setTimeout(() => { + socket.send(JSON.stringify(mock.response)); + console.log(`Simulated message sent to the client for: ${includes.join(' + ')}`); + }, delay); + + // Break after first match to avoid multiple responses + break; + } } }); }); From d8cca1adc6e1bcdcdfdb50e29da0d41afb9163fc Mon Sep 17 00:00:00 2001 From: seaona Date: Mon, 1 Sep 2025 11:48:06 +0200 Subject: [PATCH 2/2] fix lint --- .../solana/mocks/websocketDefaultMocks.ts | 23 +++++++++++++------ test/e2e/websocket-solana-mocks.ts | 11 ++++++--- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/test/e2e/tests/solana/mocks/websocketDefaultMocks.ts b/test/e2e/tests/solana/mocks/websocketDefaultMocks.ts index 8612c6aa40a8..372e25b755c2 100644 --- a/test/e2e/tests/solana/mocks/websocketDefaultMocks.ts +++ b/test/e2e/tests/solana/mocks/websocketDefaultMocks.ts @@ -1,7 +1,7 @@ /** * Configuration for a WebSocket message mock */ -export interface WebSocketMessageMock { +export type WebSocketMessageMock = { /** String(s) that the message should include to trigger this mock */ messageIncludes: string | string[]; /** The JSON response to send back */ @@ -10,7 +10,7 @@ export interface WebSocketMessageMock { delay?: number; /** Custom log message for this mock */ logMessage?: string; -} +}; export const DEFAULT_SOLANA_WS_MOCKS: WebSocketMessageMock[] = [ { @@ -27,27 +27,36 @@ export const DEFAULT_SOLANA_WS_MOCKS: WebSocketMessageMock[] = [ messageIncludes: 'accountSubscribe', response: { jsonrpc: '2.0', - result: 'b07ebf7caf2238a9b604d4dfcaf1934280fcd347d6eded62bc0def6cbb767d11', + result: + 'b07ebf7caf2238a9b604d4dfcaf1934280fcd347d6eded62bc0def6cbb767d11', id: '1', }, delay: 500, logMessage: 'Account subscribe message received from client', }, { - messageIncludes: ['programSubscribe', 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'], + messageIncludes: [ + 'programSubscribe', + 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + ], response: { jsonrpc: '2.0', - result: '568eafd45635c108d0d426361143de125a841628a58679f5a024cbab9a20b41c', + result: + '568eafd45635c108d0d426361143de125a841628a58679f5a024cbab9a20b41c', id: '1', }, delay: 500, logMessage: 'Program subscribe message received from client', }, { - messageIncludes: ['programSubscribe', 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'], + messageIncludes: [ + 'programSubscribe', + 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb', + ], response: { jsonrpc: '2.0', - result: 'f33dd9975158af47bf16c7f6062a73191d4595c59cfec605d5a51e25c65ffb51', + result: + 'f33dd9975158af47bf16c7f6062a73191d4595c59cfec605d5a51e25c65ffb51', id: '1', }, delay: 500, diff --git a/test/e2e/websocket-solana-mocks.ts b/test/e2e/websocket-solana-mocks.ts index c75ae2d4b0a0..9775f0371dde 100644 --- a/test/e2e/websocket-solana-mocks.ts +++ b/test/e2e/websocket-solana-mocks.ts @@ -5,7 +5,8 @@ import { WebSocketMessageMock } from './tests/solana/mocks/websocketDefaultMocks /** * Sets up Solana WebSocket mocks with configurable message handlers - * @param mocks Array of message mock configurations + * + * @param mocks - Array of message mock configurations */ export async function setupSolanaWebsocketMocks( mocks: WebSocketMessageMock[] = [], @@ -29,7 +30,9 @@ export async function setupSolanaWebsocketMocks( : [mock.messageIncludes]; // Check if all required strings are included in the message - const matches = includes.every((includeStr) => message.includes(includeStr)); + const matches = includes.every((includeStr) => + message.includes(includeStr), + ); if (matches) { if (mock.logMessage) { @@ -39,7 +42,9 @@ export async function setupSolanaWebsocketMocks( const delay = mock.delay || 500; setTimeout(() => { socket.send(JSON.stringify(mock.response)); - console.log(`Simulated message sent to the client for: ${includes.join(' + ')}`); + console.log( + `Simulated message sent to the client for: ${includes.join(' + ')}`, + ); }, delay); // Break after first match to avoid multiple responses