feat: add base swap page and routing

This commit is contained in:
Luis Aguilar
2023-07-18 16:45:31 -06:00
committed by Fara Woolf
parent 4cc6252dee
commit 6e59bddd0b
18 changed files with 181 additions and 0 deletions

View File

@@ -4,3 +4,5 @@ SEGMENT_WRITE_KEY=segmentwritekey
SENTRY_DSN=sentrydsn
TRANSAK_API_KEY=transakapikey
WALLET_ENVIRONMENT=development
SWAP_ENABLED=true

2
.tool-versions Normal file
View File

@@ -0,0 +1,2 @@
nodejs 16.13.0
yarn 1.22.19

View File

@@ -0,0 +1 @@
export * from './use-swap-feature';

View File

@@ -0,0 +1,5 @@
export function useSwapFeature() {
return {
swapIsEnabled: !!process.env.SWAP_ENABLED
};
}

View File

@@ -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 (
<Suspense fallback={<></>}>
<Stack isInline mt={['base', 'base', 'unset']} spacing="base-tight" {...props}>
<SendButton />
<ReceiveButton />
<BuyButton />
{swapIsEnabled && <SwapButton />}
</Stack>
</Suspense>
);

View File

@@ -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 (
<HomeActionButton
label="Swap"
icon={FiRefreshCw}
buttonComponent={PrimaryButton}
data-testid={HomePageSelectors.SwapBtn}
onClick={() => navigate(RouteUrls.Swap)}
{...props}
/>
);
}

View File

@@ -0,0 +1,2 @@
export * from './swap';
export * from './swap-routes';

View File

@@ -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(<ModalHeader hideActions defaultGoBack title="Swap" />, true);
return whenPageMode({
full: (
<Flex
maxHeight="90vh"
border={['unset', '1px solid']}
borderRadius={['unset', '16px']}
borderColor={['unset', '#DCDDE2']}
maxWidth={['100%', CENTERED_FULL_PAGE_MAX_WIDTH]}
minWidth={['100%', CENTERED_FULL_PAGE_MAX_WIDTH]}
>
<Outlet />
</Flex>
),
popup: <Outlet />,
});
}

View File

@@ -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 = (
<Route element={<SwapContainer />}>
<Route
path={RouteUrls.Swap}
element={
<AccountGate>
<Swap />
</AccountGate>
}
/>
</Route>
);

View File

@@ -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 (
<Flex
data-testid={SwapCryptoAssetSelectors.SwapPageReady}
alignItems={['left', 'center']}
maxHeight={['unset', '85vh']}
flexDirection="column"
justifyContent="start"
overflowY="auto"
flexGrow={1}
>
<Text marginTop="15px" marginBottom="15px">Coming soon!</Text>
</Flex>
);
}

View File

@@ -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() {
}
/>
<Route
path={RouteUrls.RpcSignBip322Message}
lazy={async () => {
const { RpcSignBip322MessageRoute } = await import(
'@app/pages/rpc-sign-bip322-message/rpc-sign-bip322-message'
);
return { Component: RpcSignBip322MessageRoute };
}}
/>
{swapRoutes}
{/* Catch-all route redirects to onboarding */}
<Route path="*" element={<Navigate replace to={RouteUrls.Onboarding} />} />
</Route>

View File

@@ -106,4 +106,7 @@ export enum RouteUrls {
// Shared legacy and rpc request routes
RequestError = '/request-error',
UnauthorizedRequest = '/unauthorized-request',
// Swap routes
Swap = '/swap',
}

View File

@@ -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<TestFixtures>({
sendPage: async ({ page }, use) => {
await use(new SendPage(page));
},
swapPage: async ({ page }, use) => {
await use(new SwapPage(page));
}
});

View File

@@ -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:

View File

@@ -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',
});
}
}

View File

@@ -8,4 +8,5 @@ export enum HomePageSelectors {
SendCryptoAssetBtn = 'send-crypto-asset-btn',
ActivityTabBtn = 'tab-activity',
BalancesTabBtn = 'tab-balances',
SwapBtn = 'swap-btn',
}

View File

@@ -0,0 +1,3 @@
export enum SwapCryptoAssetSelectors {
SwapPageReady = 'swap-page-ready',
}

View File

@@ -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();
});
})
})