diff --git a/tests/mocks/mock-bitcoin-tx.ts b/tests/mocks/mock-bitcoin-tx.ts new file mode 100644 index 0000000000..0830b64275 --- /dev/null +++ b/tests/mocks/mock-bitcoin-tx.ts @@ -0,0 +1,13 @@ +import type { Page } from '@playwright/test'; + +import { BITCOIN_API_BASE_URL_TESTNET3 } from '@leather.io/models'; + +import { mockMainnetNsTransactionsTestAccount } from './mock-utxos'; + +export async function mockTestAccountBtcBroadcastTransaction(page: Page) { + await page.route(`${BITCOIN_API_BASE_URL_TESTNET3}/tx`, route => + route.fulfill({ + body: mockMainnetNsTransactionsTestAccount[0].txid, + }) + ); +} diff --git a/tests/mocks/mock-utxos.ts b/tests/mocks/mock-utxos.ts index ef44bdb90c..4783e53009 100644 --- a/tests/mocks/mock-utxos.ts +++ b/tests/mocks/mock-utxos.ts @@ -42,7 +42,8 @@ export const mockUtxosListWithRunes = [ value: 546, }, ]; -const mockMainnetNsTransactionsTestAccount = [ + +export const mockMainnetNsTransactionsTestAccount = [ { txid: '58d44000884f0ba4cdcbeb1ac082e6c802d300c16b0d3251738e8cf6a57397ce', version: 2, diff --git a/tests/specs/rpc-send-transfer/rpc-send-transfer.spec.ts b/tests/specs/rpc-send-transfer/rpc-send-transfer.spec.ts new file mode 100644 index 0000000000..0e3c6e1af3 --- /dev/null +++ b/tests/specs/rpc-send-transfer/rpc-send-transfer.spec.ts @@ -0,0 +1,87 @@ +import { BrowserContext, Page } from '@playwright/test'; +import { TEST_TESTNET_ACCOUNT_2_BTC_ADDRESS } from '@tests/mocks/constants'; +import { mockTestAccountBtcBroadcastTransaction } from '@tests/mocks/mock-bitcoin-tx'; + +import { RpcSendTransferParams } from '@leather.io/rpc'; + +import { test } from '../../fixtures/fixtures'; + +const baseParams = { + recipients: [ + { + address: TEST_TESTNET_ACCOUNT_2_BTC_ADDRESS, + amount: '800', + }, + { + address: TEST_TESTNET_ACCOUNT_2_BTC_ADDRESS, + amount: '900', + }, + ], + network: 'testnet', +}; + +test.describe('Send transfer (RPC)', () => { + test.beforeEach(async ({ extensionId, globalPage, onboardingPage, page }) => { + await globalPage.setupAndUseApiCalls(extensionId); + await onboardingPage.signInWithTestAccount(extensionId); + await page.goto('localhost:3000', { waitUntil: 'networkidle' }); + }); + + function clickActionButton(context: BrowserContext) { + return async (buttonToPress: 'Cancel' | 'Approve') => { + const popup = await context.waitForEvent('page'); + await popup.waitForTimeout(1000); + const btn = popup.locator(`text="${buttonToPress}"`); + await btn.click(); + }; + } + + async function mockPopupRequests(context: BrowserContext) { + const popup = await context.waitForEvent('page'); + await mockTestAccountBtcBroadcastTransaction(popup); + } + + function openSendTransfer(page: Page) { + return async (params: RpcSendTransferParams) => + page.evaluate( + async params => + (window as any).LeatherProvider?.request('sendTransfer', { + ...params, + }).catch((e: unknown) => e), + { ...params } + ); + } + + test('that the request can be broadcasted', async ({ page, context }) => { + void mockPopupRequests(context); + + const [result] = await Promise.all([ + openSendTransfer(page)(baseParams), + clickActionButton(context)('Approve'), + ]); + + delete result.id; + + test.expect(result).toEqual({ + jsonrpc: '2.0', + result: { txid: '58d44000884f0ba4cdcbeb1ac082e6c802d300c16b0d3251738e8cf6a57397ce' }, + }); + }); + + test('that the request can be cancelled', async ({ page, context }) => { + const [result] = await Promise.all([ + openSendTransfer(page)(baseParams), + clickActionButton(context)('Cancel'), + ]); + + delete result.id; + + test.expect(result).toEqual({ + jsonrpc: '2.0', + error: { + code: 4001, + message: 'User rejected signing the transaction', + }, + }); + }); +});