diff --git a/src/background/messaging/rpc-methods/open.ts b/src/background/messaging/rpc-methods/open.ts index fcd7cd3f864..5da5214dfe4 100644 --- a/src/background/messaging/rpc-methods/open.ts +++ b/src/background/messaging/rpc-methods/open.ts @@ -2,7 +2,7 @@ import { RpcErrorCode } from '@btckit/types'; import { RouteUrls } from '@shared/route-urls'; import { OpenRequest } from '@shared/rpc/methods/open'; -import { makeRpcErrorResponse } from '@shared/rpc/rpc-methods'; +import { makeRpcErrorResponse, makeRpcSuccessResponse } from '@shared/rpc/rpc-methods'; import { listenForPopupClose, @@ -13,18 +13,37 @@ import { trackRpcRequestSuccess } from '../rpc-message-handler'; export async function rpcOpen(message: OpenRequest, port: chrome.runtime.Port) { const { urlParams, tabId } = makeSearchParamsWithDefaults(port, [['requestId', message.id]]); - const { id } = await triggerRequestWindowOpen(RouteUrls.Home, urlParams); - void trackRpcRequestSuccess({ endpoint: message.method }); - listenForPopupClose({ - tabId, - id, - response: makeRpcErrorResponse('open', { + try { + const { id } = await triggerRequestWindowOpen(RouteUrls.Home, urlParams); + void trackRpcRequestSuccess({ endpoint: message.method }); + + chrome.tabs.sendMessage( + tabId, + makeRpcSuccessResponse('open', { + id: message.id, + result: { message: 'Success' }, + }) + ); + + listenForPopupClose({ + tabId, + id, + response: makeRpcErrorResponse('open', { + id: message.id, + error: { + code: RpcErrorCode.USER_REJECTION, + message: 'User rejected request to open wallet', + }, + }), + }); + } catch (error) { + makeRpcErrorResponse('open', { id: message.id, error: { - code: RpcErrorCode.USER_REJECTION, - message: 'User rejected request to open wallet', + code: RpcErrorCode.SERVER_ERROR, + message: 'Request to open wallet failed', }, - }), - }); + }); + } } diff --git a/src/shared/rpc/methods/open-wallet.ts b/src/shared/rpc/methods/open-wallet.ts new file mode 100644 index 00000000000..fca8912665a --- /dev/null +++ b/src/shared/rpc/methods/open-wallet.ts @@ -0,0 +1,14 @@ +import { DefineRpcMethod, RpcRequest, RpcResponse } from '@btckit/types'; +import * as yup from 'yup'; + +const rpcOpenWalletParamsSchema = yup.object().shape({ + url: yup.string(), +}); + +type OpenWalletRequestParams = yup.InferType; + +export type OpenWalletRequest = RpcRequest<'openWallet', OpenWalletRequestParams>; + +type OpenWalletResponse = RpcResponse; + +export type OpenWallet = DefineRpcMethod; diff --git a/src/shared/rpc/methods/open.ts b/src/shared/rpc/methods/open.ts index 2ee6a16d6f4..866d0668a1d 100644 --- a/src/shared/rpc/methods/open.ts +++ b/src/shared/rpc/methods/open.ts @@ -9,6 +9,6 @@ type OpenRequestParams = yup.InferType; export type OpenRequest = RpcRequest<'open', OpenRequestParams>; -type OpenResponse = RpcResponse; +type OpenResponse = RpcResponse<{ message: string }>; export type Open = DefineRpcMethod; diff --git a/tests/specs/rpc-open/open.spec.ts b/tests/specs/rpc-open/open.spec.ts new file mode 100644 index 00000000000..4f60517bfe2 --- /dev/null +++ b/tests/specs/rpc-open/open.spec.ts @@ -0,0 +1,72 @@ +import type { BrowserContext, Page } from '@playwright/test'; +import { TEST_PASSWORD } from '@tests/mocks/constants'; +import { HomePageSelectors } from '@tests/selectors/home.selectors'; + +import { test } from '../../fixtures/fixtures'; + +const successResponse = { + jsonrpc: '2.0', + result: { + message: 'Success', + }, +}; + +async function interceptRequestPopup(context: BrowserContext) { + return context.waitForEvent('page'); +} + +async function assertWalletHomeOpens(popup: Page) { + await popup.getByTestId(HomePageSelectors.HomePageContainer).waitFor(); + // await page.getByTestId(HomePageSelectors.HomePageContainer).waitFor(); + const button = popup.getByTestId(HomePageSelectors.FundAccountBtn); + await test.expect(button).toBeVisible(); + // await button.click(); +} +async function initiateOpen(page: Page) { + return page.evaluate(async () => (window as any).LeatherProvider?.request('open')); +} + +test.describe('Rpc: Open', () => { + test.beforeEach(async ({ extensionId, globalPage, onboardingPage }) => { + await globalPage.setupAndUseApiCalls(extensionId); + + await onboardingPage.signInWithTestAccount(extensionId); + }); + + test('the wallet opens successfully', async ({ page, context }) => { + await page.goto('localhost:3000'); + const openPromise = await initiateOpen(page); + + const popup = await interceptRequestPopup(context); + await assertWalletHomeOpens(popup); + + const result = await openPromise; + if (!result) throw new Error('Expected result'); + const { id, ...payloadWithoutId } = result; + + await test.expect(payloadWithoutId).toEqual(successResponse); + }); + + test('the promise rejects when user closes the popup window', async ({ page, context }) => { + await page.goto('localhost:3000'); + const openPromise = initiateOpen(page); + const popup = await interceptRequestPopup(context); + await popup.close(); + await test.expect(openPromise).rejects.toThrow(); + }); + + test('it forces user to unlock wallet when wallet is locked', async ({ + homePage, + page, + context, + }) => { + await homePage.lock(); + await page.goto('localhost:3000'); + const openPromise = initiateOpen(page); + const popup = await interceptRequestPopup(context); + await popup.getByRole('textbox').fill(TEST_PASSWORD); + await popup.getByRole('button', { name: 'Continue' }).click(); + await assertWalletHomeOpens(popup); + await test.expect(openPromise).resolves.toMatchObject(successResponse); + }); +});