diff --git a/packages/app/.env.playwright b/packages/app/.env.playwright
index 847fc84de..08ff13cce 100644
--- a/packages/app/.env.playwright
+++ b/packages/app/.env.playwright
@@ -4,6 +4,6 @@ VITE_PLAYWRIGHT=true
VITE_FEATURE_CONFIGURABLE_SLIPPAGE=1
# development
-VITE_DEV_NATIVE_ROUTES=0
+VITE_DEV_NATIVE_ROUTES=1
VITE_BLOCK_ANALITICA_API_URL=https://spark-api.blockanalitica.com/api
diff --git a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/MakerTransactionOverview.tsx b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/MakerTransactionOverview.tsx
index 890bd6b41..2d987cfeb 100644
--- a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/MakerTransactionOverview.tsx
+++ b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/MakerTransactionOverview.tsx
@@ -23,33 +23,28 @@ export function MakerTransactionOverview({ txOverview, selectedToken }: MakerTra
assert(route.length > 0, 'Route must have at least one item')
const outcome = route.at(-1)!
- let dataTestIdIndex = 0
-
return (
Transaction overview
-
+
-
+
{route.map((item, index) => (
-
+
))}
-
+
-
-
+
+
)
diff --git a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/APYDetails.tsx b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/APYDetails.tsx
index dea2e2283..5500a5d29 100644
--- a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/APYDetails.tsx
+++ b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/APYDetails.tsx
@@ -1,6 +1,7 @@
import { formatPercentage } from '@/domain/common/format'
import { NormalizedUnitNumber, Percentage } from '@/domain/types/NumericValues'
import { USD_MOCK_TOKEN } from '@/domain/types/Token'
+import { testIds } from '@/ui/utils/testIds'
export interface APYDetailsProps {
APY: Percentage
@@ -10,8 +11,13 @@ export interface APYDetailsProps {
export function APYDetails({ APY, daiEarnRate }: APYDetailsProps) {
return (
-
{formatPercentage(APY)}
-
Earn ~{USD_MOCK_TOKEN.formatUSD(daiEarnRate)} DAI per year
+
{formatPercentage(APY)}
+
+ Earn ~{USD_MOCK_TOKEN.format(daiEarnRate, { style: 'auto' })} DAI per year
+
)
}
diff --git a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/MakerBadge.tsx b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/MakerBadge.tsx
index 9aaec1387..da92c7896 100644
--- a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/MakerBadge.tsx
+++ b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/MakerBadge.tsx
@@ -4,11 +4,15 @@ import { Info } from '@/ui/molecules/info/Info'
export interface MakerBadgeProps {
token: Token
+ 'data-testid'?: string
}
-export function MakerBadge({ token }: MakerBadgeProps) {
+export function MakerBadge({ token, 'data-testid': dataTestId }: MakerBadgeProps) {
return (
-
+
Powered by Maker.
diff --git a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/RouteItem.tsx b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/RouteItem.tsx
index 9ae77c7ce..0feb40e35 100644
--- a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/RouteItem.tsx
+++ b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/RouteItem.tsx
@@ -1,19 +1,24 @@
import { USD_MOCK_TOKEN } from '@/domain/types/Token'
import { assets } from '@/ui/assets'
import { cn } from '@/ui/utils/style'
+import { testIds } from '@/ui/utils/testIds'
import { RouteItem as RouteItemType } from '../../../types'
export interface RouteItemProps {
item: RouteItemType
+ index: number
isLast: boolean
}
-export function RouteItem({ item, isLast }: RouteItemProps) {
+export function RouteItem({ item, index, isLast }: RouteItemProps) {
return (
-
+
{item.token.format(item.value, { style: 'auto' })} {item.token.symbol}
-
+
{USD_MOCK_TOKEN.formatUSD(item.usdValue)}
{!isLast && (
diff --git a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/TransactionOutcome.tsx b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/TransactionOutcome.tsx
index 218527786..a27d62836 100644
--- a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/TransactionOutcome.tsx
+++ b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/TransactionOutcome.tsx
@@ -3,11 +3,12 @@ import { RouteItem } from '../../../types'
export interface TransactionOutcomeProps {
outcome: RouteItem
+ 'data-testid'?: string
}
-export function TransactionOutcome({ outcome }: TransactionOutcomeProps) {
+export function TransactionOutcome({ outcome, 'data-testid': dataTestId }: TransactionOutcomeProps) {
return (
-
+
{outcome.token.format(outcome.value, { style: 'auto' })} {outcome.token.symbol}
diff --git a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/TransactionOverviewDetailsItem.tsx b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/TransactionOverviewDetailsItem.tsx
index 0a068f19c..fe661789b 100644
--- a/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/TransactionOverviewDetailsItem.tsx
+++ b/packages/app/src/features/dialogs/savings/common/components/maker-transaction-overview/components/TransactionOverviewDetailsItem.tsx
@@ -3,16 +3,11 @@ import { ReactNode } from 'react'
export interface TransactionOverviewDetailsItemProps {
label: string
children: ReactNode
- 'data-testid'?: string
}
-export function TransactionOverviewDetailsItem({
- label,
- children,
- 'data-testid': dataTestId,
-}: TransactionOverviewDetailsItemProps) {
+export function TransactionOverviewDetailsItem({ label, children }: TransactionOverviewDetailsItemProps) {
return (
-
+
diff --git a/packages/app/src/features/dialogs/savings/deposit/SavingsDepositDialog.PageObject.ts b/packages/app/src/features/dialogs/savings/deposit/SavingsDepositDialog.PageObject.ts
index ac26eab38..8e75bb092 100644
--- a/packages/app/src/features/dialogs/savings/deposit/SavingsDepositDialog.PageObject.ts
+++ b/packages/app/src/features/dialogs/savings/deposit/SavingsDepositDialog.PageObject.ts
@@ -45,6 +45,44 @@ export class SavingsDepositDialogPageObject extends DialogPageObject {
}
}
+ async expectNativeRouteTransactionOverview(transactionOverview: NativeRouteTransactionOverview): Promise
{
+ const panel = this.locatePanelByHeader('Transaction overview')
+ await expect(panel).toBeVisible()
+ const txOverviewTestIds = testIds.dialog.savings.nativeRouteTransactionOverview
+
+ const apyValue = panel.getByTestId(txOverviewTestIds.apy.value)
+ const apyDescription = panel.getByTestId(txOverviewTestIds.apy.description)
+ await expect(apyValue).toContainText(transactionOverview.apy.value)
+ await expect(apyDescription).toContainText(transactionOverview.apy.description)
+
+ for (const [index, { tokenAmount: tokenWithAmount, tokenUsdValue }] of transactionOverview.routeItems.entries()) {
+ const routeItem = panel.getByTestId(txOverviewTestIds.routeItem.tokenWithAmount(index))
+ const routeItemUSD = panel.getByTestId(txOverviewTestIds.routeItem.tokenUsdValue(index))
+ await expect(routeItem).toContainText(tokenWithAmount)
+ await expect(routeItemUSD).toContainText(tokenUsdValue)
+ }
+
+ const makerBadge = panel.getByTestId(txOverviewTestIds.makerBadge)
+ await expect(makerBadge).toBeVisible()
+
+ const outcome = panel.getByTestId(txOverviewTestIds.outcome)
+ await expect(outcome).toContainText(transactionOverview.outcome)
+ }
+
+ async expectToUseNativeSDaiAction(nativeSDaiDepositParams: {
+ title: string
+ type: 'deposit' | 'withdraw'
+ }): Promise {
+ const testId =
+ nativeSDaiDepositParams.type === 'deposit'
+ ? testIds.actions.flavours.nativeSDaiDepositActionRow.wrapper
+ : testIds.actions.flavours.nativeSDaiWithdrawActionRow.wrapper
+ const depositRow = this.locatePanelByHeader('Actions').getByTestId(testId)
+
+ await expect(depositRow).toBeVisible()
+ await expect(depositRow).toContainText(nativeSDaiDepositParams.title)
+ }
+
async expectToUseLifiSwap(lifiSwapParams: LifiSwapParams): Promise {
const exchangeRow = this.locatePanelByHeader('Actions').getByTestId(
testIds.actions.flavours.exchangeActionRow.wrapper,
@@ -82,3 +120,15 @@ interface LifiSwapParams {
}
type TransactionOverview = [string, string][]
+
+interface NativeRouteTransactionOverview {
+ apy: {
+ value: string
+ description: string
+ }
+ routeItems: {
+ tokenAmount: string
+ tokenUsdValue: string
+ }[]
+ outcome: string
+}
diff --git a/packages/app/src/features/dialogs/savings/deposit/e2e/DepositDAI.test-e2e.ts b/packages/app/src/features/dialogs/savings/deposit/e2e/DepositDAI.test-e2e.ts
new file mode 100644
index 000000000..2d0f0440f
--- /dev/null
+++ b/packages/app/src/features/dialogs/savings/deposit/e2e/DepositDAI.test-e2e.ts
@@ -0,0 +1,71 @@
+import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject'
+import { SavingsPageObject } from '@/pages/Savings.PageObject'
+import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants'
+import { setup } from '@/test/e2e/setup'
+import { setupFork } from '@/test/e2e/setupFork'
+import { test } from '@playwright/test'
+import { mainnet } from 'viem/chains'
+import { SavingsDepositDialogPageObject } from '../SavingsDepositDialog.PageObject'
+
+test.describe('Deposit DAI on Mainnet', () => {
+ const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id })
+ let savingsPage: SavingsPageObject
+ let depositDialog: SavingsDepositDialogPageObject
+
+ test.beforeEach(async ({ page }) => {
+ await setup(page, fork, {
+ initialPage: 'savings',
+ account: {
+ type: 'connected',
+ assetBalances: {
+ ETH: 1,
+ DAI: 10_000,
+ },
+ },
+ })
+
+ savingsPage = new SavingsPageObject(page)
+ await savingsPage.clickDepositButtonAction('DAI')
+
+ depositDialog = new SavingsDepositDialogPageObject(page)
+ await depositDialog.fillAmountAction(10_000)
+ })
+
+ test('uses native sDai deposit', async ({ page, browser }) => {
+ await depositDialog.expectToUseNativeSDaiAction({
+ title: 'Wrap DAI into sDAI',
+ type: 'deposit',
+ })
+ })
+
+ test('displays transaction overview', async () => {
+ await depositDialog.expectNativeRouteTransactionOverview({
+ apy: {
+ value: '5.00%',
+ description: 'Earn ~$500.00 DAI per year',
+ },
+ routeItems: [
+ {
+ tokenAmount: '10,000.00 DAI',
+ tokenUsdValue: '$10,000.00',
+ },
+ {
+ tokenAmount: '9,332.66 sDAI',
+ tokenUsdValue: '$10,000.00',
+ },
+ ],
+ outcome: '9,332.66 sDAI worth $10,000.00',
+ })
+ })
+
+ test('executes deposit', async () => {
+ const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions'))
+ await actionsContainer.acceptAllActionsAction(2)
+
+ await depositDialog.expectSuccessPage()
+ await depositDialog.clickBackToSavingsButton()
+
+ await savingsPage.expectSavingsBalance({ sDaiBalance: '9,332.66 sDAI', estimatedDaiValue: '10,000' })
+ await savingsPage.expectCashInWalletAssetBalance('DAI', '-')
+ })
+})
diff --git a/packages/app/src/ui/utils/testIds.ts b/packages/app/src/ui/utils/testIds.ts
index bb35465c8..d133e8a97 100644
--- a/packages/app/src/ui/utils/testIds.ts
+++ b/packages/app/src/ui/utils/testIds.ts
@@ -53,6 +53,20 @@ export const testIds = makeTestIds({
},
success: true,
acknowledgeRiskSwitch: true,
+ savings: {
+ nativeRouteTransactionOverview: {
+ apy: {
+ value: true,
+ description: true,
+ },
+ routeItem: {
+ tokenWithAmount: (index: number) => index,
+ tokenUsdValue: (index: number) => index,
+ },
+ outcome: true,
+ makerBadge: true,
+ },
+ },
depositSavings: {
transactionDetailsRow: (index: number) => index,
},
@@ -76,6 +90,9 @@ export const testIds = makeTestIds({
nativeSDaiDepositActionRow: {
wrapper: true,
},
+ nativeSDaiWithdrawActionRow: {
+ wrapper: true,
+ },
},
},
navbar: {