From 6e59bddd0b825ca4edfe341f82047385b59a0338 Mon Sep 17 00:00:00 2001 From: Luis Aguilar Date: Tue, 18 Jul 2023 16:45:31 -0600 Subject: [PATCH] feat: add base swap page and routing --- .env.example | 2 ++ .tool-versions | 2 ++ src/app/features/swap/index.ts | 1 + src/app/features/swap/use-swap-feature.ts | 5 ++++ .../pages/home/components/home-actions.tsx | 6 ++++ src/app/pages/home/components/swap-button.tsx | 26 +++++++++++++++++ src/app/pages/swap/index.ts | 2 ++ src/app/pages/swap/swap-container.tsx | 29 +++++++++++++++++++ src/app/pages/swap/swap-routes.tsx | 20 +++++++++++++ src/app/pages/swap/swap.tsx | 19 ++++++++++++ src/app/routes/app-routes.tsx | 13 +++++++++ src/shared/route-urls.ts | 3 ++ tests/fixtures/fixtures.ts | 7 +++++ tests/page-object-models/home.page.ts | 7 +++++ tests/page-object-models/swap.page.ts | 18 ++++++++++++ tests/selectors/home.selectors.ts | 1 + tests/selectors/swap.selectors.ts | 3 ++ tests/specs/swap/swap.spec.ts | 17 +++++++++++ 18 files changed, 181 insertions(+) create mode 100644 .tool-versions create mode 100644 src/app/features/swap/index.ts create mode 100644 src/app/features/swap/use-swap-feature.ts create mode 100644 src/app/pages/home/components/swap-button.tsx create mode 100644 src/app/pages/swap/index.ts create mode 100644 src/app/pages/swap/swap-container.tsx create mode 100644 src/app/pages/swap/swap-routes.tsx create mode 100644 src/app/pages/swap/swap.tsx create mode 100644 tests/page-object-models/swap.page.ts create mode 100644 tests/selectors/swap.selectors.ts create mode 100644 tests/specs/swap/swap.spec.ts diff --git a/.env.example b/.env.example index 7d028477..f76e0244 100644 --- a/.env.example +++ b/.env.example @@ -4,3 +4,5 @@ SEGMENT_WRITE_KEY=segmentwritekey SENTRY_DSN=sentrydsn TRANSAK_API_KEY=transakapikey WALLET_ENVIRONMENT=development + +SWAP_ENABLED=true diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 00000000..a6271e18 --- /dev/null +++ b/.tool-versions @@ -0,0 +1,2 @@ +nodejs 16.13.0 +yarn 1.22.19 diff --git a/src/app/features/swap/index.ts b/src/app/features/swap/index.ts new file mode 100644 index 00000000..a3f0e882 --- /dev/null +++ b/src/app/features/swap/index.ts @@ -0,0 +1 @@ +export * from './use-swap-feature'; diff --git a/src/app/features/swap/use-swap-feature.ts b/src/app/features/swap/use-swap-feature.ts new file mode 100644 index 00000000..a5d8ac12 --- /dev/null +++ b/src/app/features/swap/use-swap-feature.ts @@ -0,0 +1,5 @@ +export function useSwapFeature() { + return { + swapIsEnabled: !!process.env.SWAP_ENABLED + }; +} diff --git a/src/app/pages/home/components/home-actions.tsx b/src/app/pages/home/components/home-actions.tsx index e120ef13..020b1ff4 100644 --- a/src/app/pages/home/components/home-actions.tsx +++ b/src/app/pages/home/components/home-actions.tsx @@ -2,17 +2,23 @@ import { Suspense } from 'react'; import { Stack, StackProps } from '@stacks/ui'; +import { useSwapFeature } from '@app/features/swap'; + import { BuyButton } from './buy-button'; import { ReceiveButton } from './receive-button'; import { SendButton } from './send-button'; +import { SwapButton } from './swap-button'; export function HomeActions(props: StackProps) { + const { swapIsEnabled } = useSwapFeature(); + return ( }> + {swapIsEnabled && } ); diff --git a/src/app/pages/home/components/swap-button.tsx b/src/app/pages/home/components/swap-button.tsx new file mode 100644 index 00000000..4df2d705 --- /dev/null +++ b/src/app/pages/home/components/swap-button.tsx @@ -0,0 +1,26 @@ +import { useNavigate } from 'react-router-dom'; + +import { ButtonProps } from '@stacks/ui'; +import { HomePageSelectors } from '@tests/selectors/home.selectors'; + +import { RouteUrls } from '@shared/route-urls'; + +import { PrimaryButton } from '@app/components/primary-button'; + +import { HomeActionButton } from './tx-button'; +import { FiRefreshCw } from 'react-icons/fi'; + +export function SwapButton(props: ButtonProps) { + const navigate = useNavigate(); + + return ( + navigate(RouteUrls.Swap)} + {...props} + /> + ); +} diff --git a/src/app/pages/swap/index.ts b/src/app/pages/swap/index.ts new file mode 100644 index 00000000..d4efaa7e --- /dev/null +++ b/src/app/pages/swap/index.ts @@ -0,0 +1,2 @@ +export * from './swap'; +export * from './swap-routes'; diff --git a/src/app/pages/swap/swap-container.tsx b/src/app/pages/swap/swap-container.tsx new file mode 100644 index 00000000..59afa6fd --- /dev/null +++ b/src/app/pages/swap/swap-container.tsx @@ -0,0 +1,29 @@ +import { Outlet } from 'react-router-dom'; + +import { Flex } from '@stacks/ui'; + +import { whenPageMode } from '@app/common/utils'; +import { ModalHeader } from '@app/components/modal-header'; +import { useRouteHeader } from '@app/common/hooks/use-route-header'; + +import { CENTERED_FULL_PAGE_MAX_WIDTH } from '@app/components/global-styles/full-page-styles'; + +export function SwapContainer() { + useRouteHeader(, true); + + return whenPageMode({ + full: ( + + + + ), + popup: , + }); +} diff --git a/src/app/pages/swap/swap-routes.tsx b/src/app/pages/swap/swap-routes.tsx new file mode 100644 index 00000000..e75ae760 --- /dev/null +++ b/src/app/pages/swap/swap-routes.tsx @@ -0,0 +1,20 @@ +import { Route } from "react-router-dom"; + +import { RouteUrls } from "@shared/route-urls"; +import { AccountGate } from "@app/routes/account-gate"; + +import { Swap } from "./swap"; +import { SwapContainer } from "./swap-container"; + +export const swapRoutes = ( + }> + + + + } + /> + +); diff --git a/src/app/pages/swap/swap.tsx b/src/app/pages/swap/swap.tsx new file mode 100644 index 00000000..886aaad5 --- /dev/null +++ b/src/app/pages/swap/swap.tsx @@ -0,0 +1,19 @@ +import { Text } from "@app/components/typography"; +import { Flex } from "@stacks/ui"; +import { SwapCryptoAssetSelectors } from "@tests/selectors/swap.selectors"; + +export function Swap() { + return ( + + Coming soon! + + ); +} diff --git a/src/app/routes/app-routes.tsx b/src/app/routes/app-routes.tsx index b0258374..3df56125 100644 --- a/src/app/routes/app-routes.tsx +++ b/src/app/routes/app-routes.tsx @@ -55,6 +55,7 @@ import { SendInscriptionSummary } from '@app/pages/send/ordinal-inscription/sent import { sendCryptoAssetFormRoutes } from '@app/pages/send/send-crypto-asset-form/send-crypto-asset-form.routes'; import { SignOutConfirmDrawer } from '@app/pages/sign-out-confirm/sign-out-confirm'; import { StacksMessageSigningRequest } from '@app/pages/stacks-message-signing-request/stacks-message-signing-request'; +import { swapRoutes } from '@app/pages/swap'; import { TransactionRequest } from '@app/pages/transaction-request/transaction-request'; import { UnauthorizedRequest } from '@app/pages/unauthorized-request/unauthorized-request'; import { Unlock } from '@app/pages/unlock'; @@ -353,6 +354,18 @@ function useAppRoutes() { } /> + { + const { RpcSignBip322MessageRoute } = await import( + '@app/pages/rpc-sign-bip322-message/rpc-sign-bip322-message' + ); + return { Component: RpcSignBip322MessageRoute }; + }} + /> + + {swapRoutes} + {/* Catch-all route redirects to onboarding */} } /> diff --git a/src/shared/route-urls.ts b/src/shared/route-urls.ts index 25615a1a..08c073f7 100644 --- a/src/shared/route-urls.ts +++ b/src/shared/route-urls.ts @@ -106,4 +106,7 @@ export enum RouteUrls { // Shared legacy and rpc request routes RequestError = '/request-error', UnauthorizedRequest = '/unauthorized-request', + + // Swap routes + Swap = '/swap', } diff --git a/tests/fixtures/fixtures.ts b/tests/fixtures/fixtures.ts index 9c59c6ec..9aef22ad 100644 --- a/tests/fixtures/fixtures.ts +++ b/tests/fixtures/fixtures.ts @@ -1,8 +1,11 @@ import { BrowserContext, test as base, chromium } from '@playwright/test'; + import { GlobalPage } from '@tests/page-object-models/global.page'; import { HomePage } from '@tests/page-object-models/home.page'; import { OnboardingPage } from '@tests/page-object-models/onboarding.page'; import { SendPage } from '@tests/page-object-models/send.page'; +import { SwapPage } from '@tests/page-object-models/swap.page'; + import path from 'path'; interface TestFixtures { @@ -12,6 +15,7 @@ interface TestFixtures { homePage: HomePage; onboardingPage: OnboardingPage; sendPage: SendPage; + swapPage: SwapPage } /** @@ -55,4 +59,7 @@ export const test = base.extend({ sendPage: async ({ page }, use) => { await use(new SendPage(page)); }, + swapPage: async ({ page }, use) => { + await use(new SwapPage(page)); + } }); diff --git a/tests/page-object-models/home.page.ts b/tests/page-object-models/home.page.ts index df7e8db8..595a9d9a 100644 --- a/tests/page-object-models/home.page.ts +++ b/tests/page-object-models/home.page.ts @@ -12,6 +12,8 @@ export class HomePage { readonly drawerActionButton: Locator; readonly receiveButton: Locator; readonly sendButton: Locator; + readonly swapButton: Locator; + readonly testNetworkSelector: string = createTestSelector( WalletDefaultNetworkConfigurationIds.testnet ); @@ -21,12 +23,17 @@ export class HomePage { this.drawerActionButton = page.getByTestId(HomePageSelectors.DrawerHeaderActionBtn); this.receiveButton = page.getByTestId(HomePageSelectors.ReceiveCryptoAssetBtn); this.sendButton = page.getByTestId(HomePageSelectors.SendCryptoAssetBtn); + this.swapButton = page.getByTestId(HomePageSelectors.SwapBtn); } async goToReceiveModal() { await this.page.getByTestId(HomePageSelectors.ReceiveCryptoAssetBtn).click(); } + async goToSwapPage() { + await this.page.getByTestId(HomePageSelectors.SwapBtn).click(); + } + // Open issue with Playwright's ability to copyToClipboard from legacy tests: // https://github.com/microsoft/playwright/issues/8114#issuecomment-1103317576 // Also, an open issue to consistently determine `isMac` in the workaround: diff --git a/tests/page-object-models/swap.page.ts b/tests/page-object-models/swap.page.ts new file mode 100644 index 00000000..7011b743 --- /dev/null +++ b/tests/page-object-models/swap.page.ts @@ -0,0 +1,18 @@ +import { Locator, Page } from '@playwright/test'; +import { SwapCryptoAssetSelectors } from '@tests/selectors/swap.selectors'; + +import { createTestSelector } from '@tests/utils'; + +export class SwapPage { + readonly page: Page; + + constructor(page: Page) { + this.page = page; + } + + async waitForSendPageReady() { + await this.page.waitForSelector(createTestSelector(SwapCryptoAssetSelectors.SwapPageReady), { + state: 'attached', + }); + } +} diff --git a/tests/selectors/home.selectors.ts b/tests/selectors/home.selectors.ts index 1685184e..1990f1d1 100644 --- a/tests/selectors/home.selectors.ts +++ b/tests/selectors/home.selectors.ts @@ -8,4 +8,5 @@ export enum HomePageSelectors { SendCryptoAssetBtn = 'send-crypto-asset-btn', ActivityTabBtn = 'tab-activity', BalancesTabBtn = 'tab-balances', + SwapBtn = 'swap-btn', } diff --git a/tests/selectors/swap.selectors.ts b/tests/selectors/swap.selectors.ts new file mode 100644 index 00000000..537cd29e --- /dev/null +++ b/tests/selectors/swap.selectors.ts @@ -0,0 +1,3 @@ +export enum SwapCryptoAssetSelectors { + SwapPageReady = 'swap-page-ready', +} diff --git a/tests/specs/swap/swap.spec.ts b/tests/specs/swap/swap.spec.ts new file mode 100644 index 00000000..590f45ab --- /dev/null +++ b/tests/specs/swap/swap.spec.ts @@ -0,0 +1,17 @@ +import { test } from '../../fixtures/fixtures'; + +test.describe('swap', () => { + test.beforeEach(async ({ extensionId, globalPage, homePage, onboardingPage, swapPage }) => { + await globalPage.setupAndUseApiCalls(extensionId); + await onboardingPage.signInWithTestAccount(extensionId); + await homePage.enableTestMode(); + await homePage.swapButton.click(); + await swapPage.waitForSendPageReady(); + }); + + test.describe('swap', () => { + test('that it shows swap page', async ({ sendPage }) => { + await test.expect(sendPage.page.getByText('Coming soon!')).toBeVisible(); + }); + }) +})