diff --git a/packages/app/package.json b/packages/app/package.json index 60f4e0d15..5b4f1add7 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -81,6 +81,8 @@ "zustand": "^4.4.1" }, "devDependencies": { + "@marsfoundation/common-nodejs": "workspace:^", + "@marsfoundation/common-testnets": "workspace:^", "@chromatic-com/storybook": "^1.5.0", "@playwright/test": "^1.47.2", "@sentry/react": "^7.114.0", diff --git a/packages/app/src/config/chain/index.ts b/packages/app/src/config/chain/index.ts index 94630321c..1b77fd5ee 100644 --- a/packages/app/src/config/chain/index.ts +++ b/packages/app/src/config/chain/index.ts @@ -18,7 +18,6 @@ import { zeroAddress } from 'viem' import { base, gnosis, mainnet } from 'viem/chains' import { NATIVE_ASSET_MOCK_ADDRESS, infoSkyApiUrl } from '../consts' import { AppConfig } from '../feature-flags' -import { PLAYWRIGHT_USDS_CONTRACTS_NOT_AVAILABLE_KEY } from '../wagmi/config.e2e' import { SUPPORTED_CHAINS, farmAddresses, farmStablecoinsEntryGroup, susdsAddresses } from './constants' import { ChainConfigEntry, ChainMeta, SupportedChainId } from './types' @@ -32,16 +31,13 @@ const commonTokenSymbolToReplacedName = { [TokenSymbol('weETH')]: { name: 'Ether.fi Staked ETH', symbol: TokenSymbol('weETH') }, } -const PLAYWRIGHT_MAINNET_USDS_CONTRACTS_NOT_AVAILABLE = - import.meta.env.VITE_PLAYWRIGHT === '1' && (window as any)[PLAYWRIGHT_USDS_CONTRACTS_NOT_AVAILABLE_KEY] === true - const chainConfig: Record = { [mainnet.id]: { originChainId: mainnet.id, daiSymbol: TokenSymbol('DAI'), sdaiSymbol: TokenSymbol('sDAI'), - usdsSymbol: PLAYWRIGHT_MAINNET_USDS_CONTRACTS_NOT_AVAILABLE ? undefined : TokenSymbol('USDS'), - susdsSymbol: PLAYWRIGHT_MAINNET_USDS_CONTRACTS_NOT_AVAILABLE ? undefined : TokenSymbol('sUSDS'), + usdsSymbol: TokenSymbol('USDS'), + susdsSymbol: TokenSymbol('sUSDS'), psmStables: [TokenSymbol('DAI'), TokenSymbol('USDC'), TokenSymbol('USDS')], meta: { name: 'Ethereum Mainnet', @@ -89,25 +85,21 @@ const chainConfig: Record = { oracleType: 'vault', address: CheckedAddress('0x83f20f44975d03b1b09e64809b757c47f942beea'), }, - ...(PLAYWRIGHT_MAINNET_USDS_CONTRACTS_NOT_AVAILABLE - ? [] - : ([ - { - symbol: TokenSymbol('sUSDS'), - oracleType: 'vault', - address: susdsAddresses[mainnet.id], - }, - { - symbol: TokenSymbol('USDS'), - oracleType: 'fixed-usd', - address: CheckedAddress('0xdC035D45d973E3EC169d2276DDab16f1e407384F'), - }, - { - symbol: TokenSymbol('SKY'), - oracleType: 'zero-price', - address: CheckedAddress('0x56072C95FAA701256059aa122697B133aDEd9279'), - }, - ] as const)), + { + symbol: TokenSymbol('sUSDS'), + oracleType: 'vault', + address: susdsAddresses[mainnet.id], + }, + { + symbol: TokenSymbol('USDS'), + oracleType: 'fixed-usd', + address: CheckedAddress('0xdC035D45d973E3EC169d2276DDab16f1e407384F'), + }, + { + symbol: TokenSymbol('SKY'), + oracleType: 'zero-price', + address: CheckedAddress('0x56072C95FAA701256059aa122697B133aDEd9279'), + }, ], markets: { defaultAssetToBorrow: TokenSymbol('DAI'), @@ -165,12 +157,8 @@ const chainConfig: Record = { }, savings: { savingsDaiInfoQuery: mainnetSavingsDaiInfoQuery, - savingsUsdsInfoQuery: PLAYWRIGHT_MAINNET_USDS_CONTRACTS_NOT_AVAILABLE ? undefined : mainnetSavingsUsdsInfoQuery, - inputTokens: [ - TokenSymbol('DAI'), - TokenSymbol('USDC'), - ...(PLAYWRIGHT_MAINNET_USDS_CONTRACTS_NOT_AVAILABLE ? [] : [TokenSymbol('USDS')]), - ], + savingsUsdsInfoQuery: mainnetSavingsUsdsInfoQuery, + inputTokens: [TokenSymbol('DAI'), TokenSymbol('USDC'), TokenSymbol('USDS')], getEarningsApiUrl: (address) => `${infoSkyApiUrl}/savings-rate/wallets/${address.toLowerCase()}/?days_ago=9999`, savingsRateApiUrl: `${infoSkyApiUrl}/savings-rate/`, }, diff --git a/packages/app/src/config/feature-flags/appConfig.default.ts b/packages/app/src/config/feature-flags/appConfig.default.ts index e4d8e21ba..dde19f807 100644 --- a/packages/app/src/config/feature-flags/appConfig.default.ts +++ b/packages/app/src/config/feature-flags/appConfig.default.ts @@ -49,6 +49,10 @@ export function getDefaultAppConfig(): AppConfig { address: '0xdC035D45d973E3EC169d2276DDab16f1e407384F', decimals: 18, }, + cbBTC: { + address: '0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf', + decimals: 8, + }, }, }, }, diff --git a/packages/app/src/config/wagmi/config.e2e.ts b/packages/app/src/config/wagmi/config.e2e.ts index 1dd78a1ce..50a018624 100644 --- a/packages/app/src/config/wagmi/config.e2e.ts +++ b/packages/app/src/config/wagmi/config.e2e.ts @@ -14,7 +14,6 @@ export const PLAYWRIGHT_CHAIN_ID = '__PLAYWRIGHT_CHAIN_ID' as const export const PLAYWRIGHT_WALLET_ADDRESS_KEY = '__PLAYWRIGHT_WALLET_ADDRESS' as const export const PLAYWRIGHT_WALLET_PRIVATE_KEY_KEY = '__PLAYWRIGHT_WALLET_PRIVATE_KEY' as const export const PLAYWRIGHT_WALLET_FORK_URL_KEY = '__PLAYWRIGHT_WALLET_FORK_URL_KEY' as const -export const PLAYWRIGHT_USDS_CONTRACTS_NOT_AVAILABLE_KEY = '__PLAYWRIGHT_USDS_CONTRACTS_NOT_AVAILABLE' as const export const VIEM_TIMEOUT_ON_FORKS = 60_000 // forks tend to be slow. This improves reliability/performance. Default is 10_000 diff --git a/packages/app/src/features/actions/ActionsContainer.PageObject.ts b/packages/app/src/features/actions/ActionsContainer.PageObject.ts index 204f87a41..43adc01b5 100644 --- a/packages/app/src/features/actions/ActionsContainer.PageObject.ts +++ b/packages/app/src/features/actions/ActionsContainer.PageObject.ts @@ -1,20 +1,17 @@ -import { Locator, Page, expect } from '@playwright/test' +import { Locator, expect } from '@playwright/test' import { formatPercentage } from '@/domain/common/format' import { BasePageObject } from '@/test/e2e/BasePageObject' -import { ForkContext } from '@/test/e2e/forking/setupFork' -import { isPage } from '@/test/e2e/utils' +import { TestContext } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' import { Percentage } from '@marsfoundation/common-universal' import { ActionType } from './logic/types' export class ActionsPageObject extends BasePageObject { - constructor(pageOrLocator: Page | Locator) { - if (isPage(pageOrLocator)) { - super(pageOrLocator) + constructor(testContext: TestContext, locator?: Locator) { + super(testContext, locator) + if (!locator) { this.region = this.locatePanelByHeader('Actions') - } else { - super(pageOrLocator) } } @@ -27,27 +24,23 @@ export class ActionsPageObject extends BasePageObject { } // #region actions - async acceptAllActionsAction(expectedNumberOfActions: number, forkContext?: ForkContext): Promise { + async acceptAllActionsAction(expectedNumberOfActions: number): Promise { for (let index = 0; index < expectedNumberOfActions; index++) { const row = this.region.getByTestId(testIds.actions.row(index)) await row.getByRole('button', { name: actionButtonRegex }).click() + await expect(row.getByRole('button', { name: actionButtonRegex })).not.toBeVisible() // @note: we are setting block timestamp of the next tx (especially after executing all txs) - if (forkContext?.isVnet) { - await expect(row.getByRole('button', { name: actionButtonRegex })).not.toBeVisible() - await forkContext.progressSimulation(this.page, 5) - } + await this.testContext.testnetController.progressSimulation(5) } } - async acceptActionAtIndex(index: number, forkContext?: ForkContext): Promise { + async acceptActionAtIndex(index: number): Promise { const row = this.region.getByTestId(testIds.actions.row(index)) await row.getByRole('button', { name: actionButtonRegex }).click() + await expect(row.getByRole('button', { name: actionButtonRegex })).not.toBeVisible() // @note: we are setting block timestamp of the next tx (especially after executing all txs) - if (forkContext?.isVnet) { - await expect(row.getByRole('button', { name: actionButtonRegex })).not.toBeVisible() - await forkContext.progressSimulation(this.page, 5) - } + await this.testContext.testnetController.progressSimulation(5) } async switchPreferPermitsAction(): Promise { diff --git a/packages/app/src/features/actions/flavours/approve/logic/approveAction.ts b/packages/app/src/features/actions/flavours/approve/logic/approveAction.ts index e5325424d..fc25d2eb4 100644 --- a/packages/app/src/features/actions/flavours/approve/logic/approveAction.ts +++ b/packages/app/src/features/actions/flavours/approve/logic/approveAction.ts @@ -19,7 +19,9 @@ export function createApproveActionConfig(action: ApproveAction, context: Action account, chainId, }), - select: (data) => ({ canBeSkipped: data >= toBigInt(action.token.toBaseUnit(action.value)) }), + select: (data) => ({ + canBeSkipped: data >= toBigInt(action.token.toBaseUnit(action.requiredValue ?? action.value)), + }), }) }, diff --git a/packages/app/src/features/dialogs/borrow/BorrowDialog.test-e2e.ts b/packages/app/src/features/dialogs/borrow/BorrowDialog.test-e2e.ts index a82643237..87098e233 100644 --- a/packages/app/src/features/dialogs/borrow/BorrowDialog.test-e2e.ts +++ b/packages/app/src/features/dialogs/borrow/BorrowDialog.test-e2e.ts @@ -1,22 +1,16 @@ -import { test } from '@playwright/test' -import { mainnet } from 'viem/chains' - import { borrowValidationIssueToMessage } from '@/domain/market-validators/validateBorrow' -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { BorrowPageObject } from '@/pages/Borrow.PageObject' import { MyPortfolioPageObject } from '@/pages/MyPortfolio.PageObject' import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' -import { screenshot } from '@/test/e2e/utils' - +import { test } from '@playwright/test' +import { mainnet } from 'viem/chains' import { CollateralDialogPageObject } from '../collateral/CollateralDialog.PageObject' import { DialogPageObject } from '../common/Dialog.PageObject' -const headerRegExp = /Borrow */ +const header = /Borrow */ test.describe('Borrow dialog', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) const initialBalances = { rETH: 100, wstETH: 100, @@ -28,11 +22,18 @@ test.describe('Borrow dialog', () => { wstETH: 2, } const daiToBorrow = 1500 - const expectedInitialHealthFactor = '5.42' - const expectedHealthFactor = '2.04' + const expectedInitialHealthFactor = '9.68' + const expectedHealthFactor = '2.46' + + let myPortfolioPage: MyPortfolioPageObject + let borrowDialog: DialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -40,89 +41,65 @@ test.describe('Borrow dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositAssetsActions(initialDeposits, daiToBorrow) - await borrowPage.viewInMyPortfolioAction() + const borrowPage = new BorrowPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + borrowDialog = new DialogPageObject({ testContext, header }) - const myPortfolioPage = new MyPortfolioPageObject(page) + await borrowPage.depositAssetsActions({ assetsToDeposit: initialDeposits, daiToBorrow }) + await borrowPage.viewInMyPortfolioAction() // wait for all transactions to be executed await myPortfolioPage.expectHealthFactor(expectedInitialHealthFactor) }) - test('opens dialog with selected asset', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('opens dialog with selected asset', async () => { await myPortfolioPage.clickBorrowButtonAction('rETH') - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.expectSelectedAsset('rETH') await borrowDialog.expectDialogHeader('Borrow rETH') await borrowDialog.expectHealthFactorBeforeVisible() - - await screenshot(borrowDialog.getDialog(), 'borrow-dialog-default-view') }) - test('calculates health factor changes correctly', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('calculates health factor changes correctly', async () => { await myPortfolioPage.clickBorrowButtonAction('rETH') - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.fillAmountAction(1) - await borrowDialog.expectRiskLevelBefore('Healthy') await borrowDialog.expectHealthFactorBefore(expectedInitialHealthFactor) await borrowDialog.expectRiskLevelAfter('Moderate') await borrowDialog.expectHealthFactorAfter(expectedHealthFactor) - - // @note this is needed for deterministic screenshots - const actionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectEnabledActionAtIndex(0) - - await screenshot(borrowDialog.getDialog(), 'borrow-dialog-health-factor') }) - test('after borrow, health factor matches myPortfolio', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('after borrow, health factor matches myPortfolio', async () => { await myPortfolioPage.clickBorrowButtonAction('rETH') - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.fillAmountAction(1) - const actionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) - + await borrowDialog.actionsContainer.acceptAllActionsAction(1) await borrowDialog.viewInMyPortfolioAction() + await myPortfolioPage.expectHealthFactor(expectedHealthFactor) }) - test('has correct action plan for erc-20', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) - + test('has correct action plan for erc-20', async () => { await myPortfolioPage.clickBorrowButtonAction('rETH') - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.fillAmountAction(1) - const actionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectActions([{ type: 'borrow', asset: 'rETH' }]) + await borrowDialog.actionsContainer.expectActions([{ type: 'borrow', asset: 'rETH' }]) }) - test('can borrow erc-20', async ({ page }) => { + test('can borrow erc-20', async () => { const borrow = { asset: 'rETH', amount: 1, } - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickBorrowButtonAction(borrow.asset) - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.fillAmountAction(borrow.amount) - const actionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) - await borrowDialog.expectSuccessPage([borrow], fork) - - await screenshot(borrowDialog.getDialog(), 'borrow-dialog-erc-20-success') - + await borrowDialog.actionsContainer.acceptAllActionsAction(1) + await borrowDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'rETH', amount: '1.00', usdValue: '$4,413.26' }], + }) await borrowDialog.viewInMyPortfolioAction() await myPortfolioPage.expectBorrowTable({ @@ -130,44 +107,32 @@ test.describe('Borrow dialog', () => { }) }) - test('has correct action plan for native asset', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) - + test('has correct action plan for native asset', async () => { await myPortfolioPage.clickBorrowButtonAction('WETH') - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.selectAssetAction('ETH') await borrowDialog.fillAmountAction(1) - await borrowDialog.expectHealthFactorVisible() - - const actionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectActions([ + await borrowDialog.actionsContainer.expectActions([ { type: 'approveDelegation', asset: 'ETH' }, { type: 'borrow', asset: 'ETH' }, ]) - - await screenshot(borrowDialog.getDialog(), 'borrow-dialog-eth-action-plan') }) - test('can borrow native asset', async ({ page }) => { + test('can borrow native asset', async () => { const borrow = { asset: 'ETH', amount: 1, } - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickBorrowButtonAction('WETH') - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.selectAssetAction(borrow.asset) await borrowDialog.fillAmountAction(1) - const actionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await borrowDialog.expectSuccessPage([borrow], fork) - await screenshot(borrowDialog.getDialog(), 'borrow-dialog-eth-success') - + await borrowDialog.actionsContainer.acceptAllActionsAction(2) + await borrowDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'ETH', amount: '1.00', usdValue: '$3,928.31' }], + }) await borrowDialog.viewInMyPortfolioAction() await myPortfolioPage.expectBorrowTable({ @@ -175,24 +140,19 @@ test.describe('Borrow dialog', () => { }) }) - test('can borrow same asset again', async ({ page }) => { + test('can borrow same asset again', async () => { const borrow = { asset: 'DAI', amount: 1500, } - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickBorrowButtonAction(borrow.asset) - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.fillAmountAction(borrow.amount) - const actionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) - await borrowDialog.expectSuccessPage([borrow], fork) - - await screenshot(borrowDialog.getDialog(), 'borrow-dialog-borrow-twice-success') - + await borrowDialog.actionsContainer.acceptAllActionsAction(1) + await borrowDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'DAI', amount: '1,500.00', usdValue: '$1,500.00' }], + }) await borrowDialog.viewInMyPortfolioAction() await myPortfolioPage.expectBorrowTable({ @@ -200,17 +160,12 @@ test.describe('Borrow dialog', () => { }) }) - test("can't borrow more than allowed", async ({ page }) => { + test("can't borrow more than allowed", async () => { const borrowAsset = 'wstETH' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.clickBorrowButtonAction(borrowAsset) - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.fillAmountAction(initialDeposits[borrowAsset] * 10) - await borrowDialog.expectAssetInputError(borrowValidationIssueToMessage['insufficient-collateral']) - await borrowDialog.expectHealthFactorBeforeVisible() - await screenshot(borrowDialog.getDialog(), 'borrow-dialog-exceeds-max-amount') }) }) @@ -220,8 +175,15 @@ test.describe('Borrow dialog', () => { rETH: 2, } + let myPortfolioPage: MyPortfolioPageObject + let borrowDialog: DialogPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -229,45 +191,30 @@ test.describe('Borrow dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - // to simulate a position with only deposits, we go through the easy borrow flow - // but interrupt it before the borrow action, going directly to the myPortfolio - // this way we have deposit transactions executed, but no borrow transaction - // resulting in a position with only deposits - await borrowPage.fillDepositAssetAction(0, 'wstETH', initialDeposits.wstETH) - await borrowPage.addNewDepositAssetAction() - await borrowPage.fillBorrowAssetAction(1) // doesn't matter, we're not borrowing anything - await borrowPage.fillDepositAssetAction(1, 'rETH', initialDeposits.rETH) - await borrowPage.submitAction() - - const actionsContainer = new ActionsPageObject(page) - for (let i = 0; i < 4; i++) { - await actionsContainer.acceptActionAtIndex(i) - } - await actionsContainer.expectEnabledActionAtIndex(4) + const borrowPage = new BorrowPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + borrowDialog = new DialogPageObject({ testContext, header }) + await borrowPage.depositWithoutBorrowActions({ + assetsToDeposit: { ...initialDeposits }, + }) - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.goToMyPortfolioAction() - await myPortfolioPage.expectDepositedAssets(10_220) + await myPortfolioPage.expectDepositedAssets('$18.16K') }) - test('can borrow erc-20', async ({ page }) => { + test('can borrow erc-20', async () => { const borrow = { asset: 'wstETH', amount: 1, } - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.clickBorrowButtonAction(borrow.asset) - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.fillAmountAction(borrow.amount) - const actionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) - await borrowDialog.expectSuccessPage([borrow], fork) - - await screenshot(borrowDialog.getDialog(), 'borrow-dialog-only-deposit-erc-20-success') - + await borrowDialog.actionsContainer.acceptAllActionsAction(1) + await borrowDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'wstETH', amount: '1.00', usdValue: '$4,665.46' }], + }) await borrowDialog.viewInMyPortfolioAction() await myPortfolioPage.expectBorrowTable({ @@ -275,24 +222,19 @@ test.describe('Borrow dialog', () => { }) }) - test('can borrow USDC', async ({ page }) => { + test('can borrow USDC', async () => { const borrow = { asset: 'USDC', amount: 100, } - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickBorrowButtonAction(borrow.asset) - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.fillAmountAction(borrow.amount) - const actionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) - await borrowDialog.expectSuccessPage([borrow], fork) - - await screenshot(borrowDialog.getDialog(), 'borrow-dialog-USDC-success') - + await borrowDialog.actionsContainer.acceptAllActionsAction(1) + await borrowDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'USDC', amount: '100.00', usdValue: '$100.00' }], + }) await borrowDialog.viewInMyPortfolioAction() await myPortfolioPage.expectBorrowTable({ @@ -300,55 +242,42 @@ test.describe('Borrow dialog', () => { }) }) - test('displays health factor', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('displays health factor', async () => { await myPortfolioPage.clickBorrowButtonAction('rETH') - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.fillAmountAction(1) await borrowDialog.expectHealthFactorAfterVisible() - - // @note this is needed for deterministic screenshots - const actionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectEnabledActionAtIndex(0) - - await screenshot(borrowDialog.getDialog(), 'borrow-dialog-only-deposit-health-factor') }) - test('clicking MAX sets input to 99% of possible borrow', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('clicking MAX sets input to 99% of possible borrow', async () => { await myPortfolioPage.clickBorrowButtonAction('DAI') - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.clickMaxAmountAction() - - await borrowDialog.expectInputValue('6929.369808') + await borrowDialog.expectInputValue('14200.947199') await borrowDialog.expectMaxButtonDisabled() await borrowDialog.expectLiquidationRiskWarning( 'Borrowing this amount puts you at risk of quick liquidation. You may lose part of your collateral.', ) - await borrowDialog.clickAcknowledgeRisk() - await borrowDialog.actionsContainer.expectActions([{ type: 'borrow', asset: 'DAI' }]) await borrowDialog.actionsContainer.expectEnabledActionAtIndex(0) }) }) test.describe('Position in isolation mode', () => { - const fork = setupFork({ - blockNumber: 20230000n, - chainId: mainnet.id, - simulationDateOverride: new Date('2024-07-04T15:32:19Z'), - }) const initialDeposits = { weETH: 200, } let myPortfolioPage: MyPortfolioPageObject + let borrowDialog: DialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: 20230000n, + chainId: mainnet.id, + }, initialPage: 'myPortfolio', account: { type: 'connected-random', @@ -356,29 +285,29 @@ test.describe('Borrow dialog', () => { }, }) - myPortfolioPage = new MyPortfolioPageObject(page) + const depositDialog = new DialogPageObject({ testContext, header: /Deposit weETH/ }) + const collateralDialog = new CollateralDialogPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + borrowDialog = new DialogPageObject({ testContext, header }) + await myPortfolioPage.clickDepositButtonAction('weETH') - const depositDialog = new DialogPageObject(page, /Deposit weETH/) + await depositDialog.fillAmountAction(initialDeposits.weETH) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.viewInMyPortfolioAction() await myPortfolioPage.clickCollateralSwitchAction('weETH') - const collateralDialog = new CollateralDialogPageObject(page) - await collateralDialog.setUseAsCollateralAction('weETH', 'enabled') + await collateralDialog.setUseAsCollateralAction({ assetName: 'weETH', setting: 'enabled' }) await collateralDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectDepositedAssets(671_900) + await myPortfolioPage.expectDepositedAssets('$671.9K') }) - test('MAX borrow accounts for isolation debt ceiling', async ({ page }) => { + test('MAX borrow accounts for isolation debt ceiling', async () => { await myPortfolioPage.clickBorrowButtonAction('DAI') - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.clickMaxAmountAction() - await borrowDialog.expectInputValue('110616.31') await borrowDialog.expectMaxButtonDisabled() await borrowDialog.actionsContainer.expectActions([{ type: 'borrow', asset: 'DAI' }]) @@ -387,19 +316,19 @@ test.describe('Borrow dialog', () => { }) test.describe('Position with large deposit', () => { - const fork = setupFork({ - blockNumber: 20235425n, - chainId: mainnet.id, - simulationDateOverride: new Date('2024-07-04T21:26:19Z'), - }) const initialDeposits = { WETH: 100_000, } let myPortfolioPage: MyPortfolioPageObject + let borrowDialog: DialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'myPortfolio', account: { type: 'connected-random', @@ -407,35 +336,34 @@ test.describe('Borrow dialog', () => { }, }) - myPortfolioPage = new MyPortfolioPageObject(page) + const depositDialog = new DialogPageObject({ testContext, header: /Deposit WETH/ }) + myPortfolioPage = new MyPortfolioPageObject(testContext) + borrowDialog = new DialogPageObject({ testContext, header }) + await myPortfolioPage.clickDepositButtonAction('WETH') - const depositDialog = new DialogPageObject(page, /Deposit WETH/) + await depositDialog.fillAmountAction(initialDeposits.WETH) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectDepositedAssets(313_328_590) + + await myPortfolioPage.expectDepositedAssets('$392.8M') }) - test('MAX borrow accounts for borrow cap', async ({ page }) => { + test('MAX borrow accounts for borrow cap', async () => { await myPortfolioPage.clickBorrowButtonAction('wstETH') - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.clickMaxAmountAction() - - await borrowDialog.expectInputValue('99.323398') + await borrowDialog.expectInputValue('5064.577659') await borrowDialog.expectMaxButtonDisabled() await borrowDialog.actionsContainer.expectActions([{ type: 'borrow', asset: 'wstETH' }]) await borrowDialog.actionsContainer.expectEnabledActionAtIndex(0) }) - test('MAX borrow accounts for available liquidity', async ({ page }) => { + test('MAX borrow accounts for available liquidity', async () => { await myPortfolioPage.clickBorrowButtonAction('USDC') - const borrowDialog = new DialogPageObject(page, headerRegExp) await borrowDialog.clickMaxAmountAction() - - await borrowDialog.expectInputValue('409207.097251') + await borrowDialog.expectInputValue('67115.418673') await borrowDialog.expectMaxButtonDisabled() await borrowDialog.actionsContainer.expectActions([{ type: 'borrow', asset: 'USDC' }]) await borrowDialog.actionsContainer.expectEnabledActionAtIndex(0) @@ -447,7 +375,11 @@ test.describe('Borrow dialog', () => { let myPortfolioPage: MyPortfolioPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -455,11 +387,11 @@ test.describe('Borrow dialog', () => { }, }) - borrowDialog = new DialogPageObject(page, headerRegExp) - myPortfolioPage = new MyPortfolioPageObject(page) + const borrowPage = new BorrowPageObject(testContext) + borrowDialog = new DialogPageObject({ testContext, header }) + myPortfolioPage = new MyPortfolioPageObject(testContext) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ rETH: 2, wstETH: 10 }) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: { rETH: 2, wstETH: 10 } }) await myPortfolioPage.goToMyPortfolioAction() }) diff --git a/packages/app/src/features/dialogs/borrow/logic/form.ts b/packages/app/src/features/dialogs/borrow/logic/form.ts index 3d216028c..c4a162679 100644 --- a/packages/app/src/features/dialogs/borrow/logic/form.ts +++ b/packages/app/src/features/dialogs/borrow/logic/form.ts @@ -47,6 +47,7 @@ export function getFormFieldsForBorrowDialog({ const changeAsset = (newSymbol: TokenSymbol): void => { form.setValue('symbol', newSymbol) form.setValue('value', '') + form.setValue('isMaxSelected', false) form.clearErrors() } diff --git a/packages/app/src/features/dialogs/claim-rewards/ClaimRewardsDialog.PageObject.ts b/packages/app/src/features/dialogs/claim-rewards/ClaimRewardsDialog.PageObject.ts index 86f024bd9..66d27e172 100644 --- a/packages/app/src/features/dialogs/claim-rewards/ClaimRewardsDialog.PageObject.ts +++ b/packages/app/src/features/dialogs/claim-rewards/ClaimRewardsDialog.PageObject.ts @@ -1,13 +1,11 @@ -import { Locator, Page, expect } from '@playwright/test' - +import { TestContext } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' - +import { Locator, expect } from '@playwright/test' import { DialogPageObject } from '../common/Dialog.PageObject' export class ClaimRewardsDialogPageObject extends DialogPageObject { - constructor(page: Page) { - super(page, /.*/) - this.region = this.locateDialogByHeader('Claim rewards') + constructor(testContext: TestContext) { + super({ testContext, header: /Claim rewards/ }) } // #region assertions diff --git a/packages/app/src/features/dialogs/claim-rewards/ClaimRewardsDialog.test-e2e.ts b/packages/app/src/features/dialogs/claim-rewards/ClaimRewardsDialog.test-e2e.ts index cf0ceccea..c807d0c0e 100644 --- a/packages/app/src/features/dialogs/claim-rewards/ClaimRewardsDialog.test-e2e.ts +++ b/packages/app/src/features/dialogs/claim-rewards/ClaimRewardsDialog.test-e2e.ts @@ -1,24 +1,22 @@ -import { test } from '@playwright/test' -import { mainnet } from 'viem/chains' - -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { TopbarPageObject } from '@/features/topbar/Topbar.PageObject' import { MyPortfolioPageObject } from '@/pages/MyPortfolio.PageObject' -import { setupFork } from '@/test/e2e/forking/setupFork' -import { setup } from '@/test/e2e/setup' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' +import { TestContext, setup } from '@/test/e2e/setup' +import { test } from '@playwright/test' +import { mainnet } from 'viem/chains' import { ClaimRewardsDialogPageObject } from './ClaimRewardsDialog.PageObject' test.describe('Claim rewards dialog', () => { - const fork = setupFork({ - blockNumber: 20189272n, // block number where the reward program is finished - chainId: mainnet.id, - }) let navbar: TopbarPageObject let claimRewardsDialog: ClaimRewardsDialogPageObject - let actionsContainer: ActionsPageObject + let testContext: TestContext<'connected-address'> test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-address', @@ -26,11 +24,10 @@ test.describe('Claim rewards dialog', () => { }, }) - navbar = new TopbarPageObject(page) + navbar = new TopbarPageObject(testContext) await navbar.openClaimRewardsDialog() - claimRewardsDialog = new ClaimRewardsDialogPageObject(page) - actionsContainer = new ActionsPageObject(claimRewardsDialog.locatePanelByHeader('Actions')) + claimRewardsDialog = new ClaimRewardsDialogPageObject(testContext) }) test('displays correct transaction overview', async () => { @@ -38,13 +35,13 @@ test.describe('Claim rewards dialog', () => { { tokenSymbol: 'wstETH', amount: '6.3697', - amountUSD: '$25,583.20', + amountUSD: '$29,717.60', }, ]) }) test('has correct action plan', async () => { - await actionsContainer.expectActions([ + await claimRewardsDialog.actionsContainer.expectActions([ { type: 'claimMarketRewards', asset: 'wstETH', @@ -52,18 +49,18 @@ test.describe('Claim rewards dialog', () => { ]) }) - test('executes transaction', async ({ page }) => { - await actionsContainer.acceptAllActionsAction(1) + test('executes transaction', async () => { + await claimRewardsDialog.actionsContainer.acceptAllActionsAction(1) await claimRewardsDialog.expectClaimRewardsSuccessPage([ { tokenSymbol: 'wstETH', amount: '6.3697', - amountUSD: '$25,583.20', + amountUSD: '$29,717.60', }, ]) - const myPortfolioPage = new MyPortfolioPageObject(page) + const myPortfolioPage = new MyPortfolioPageObject(testContext) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectBalancesInDepositTable({ diff --git a/packages/app/src/features/dialogs/collateral/CollateralDialog.PageObject.ts b/packages/app/src/features/dialogs/collateral/CollateralDialog.PageObject.ts index 89b0db666..c86b82a11 100644 --- a/packages/app/src/features/dialogs/collateral/CollateralDialog.PageObject.ts +++ b/packages/app/src/features/dialogs/collateral/CollateralDialog.PageObject.ts @@ -1,21 +1,23 @@ -import { Page, expect } from '@playwright/test' - -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' +import { TestContext } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' - +import { expect } from '@playwright/test' import { CollateralSetting } from '../collateral/types' import { DialogPageObject } from '../common/Dialog.PageObject' export class CollateralDialogPageObject extends DialogPageObject { - constructor(page: Page) { - super(page, /.*/) - this.region = this.locateDialogByHeader('Collateral') + constructor(testContext: TestContext) { + super({ testContext, header: /Collateral/ }) } // #region actions - async setUseAsCollateralAction(assetName: string, setting: CollateralSetting): Promise { - const actionsContainer = new ActionsPageObject(this.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) + async setUseAsCollateralAction({ + assetName, + setting, + }: { + assetName: string + setting: CollateralSetting + }): Promise { + await this.actionsContainer.acceptAllActionsAction(1) // assertion used for waiting if (setting === 'enabled') { diff --git a/packages/app/src/features/dialogs/collateral/CollateralDialog.test-e2e.ts b/packages/app/src/features/dialogs/collateral/CollateralDialog.test-e2e.ts index 4e5fbe172..afc20407d 100644 --- a/packages/app/src/features/dialogs/collateral/CollateralDialog.test-e2e.ts +++ b/packages/app/src/features/dialogs/collateral/CollateralDialog.test-e2e.ts @@ -1,24 +1,19 @@ -import { test } from '@playwright/test' -import { mainnet } from 'viem/chains' - import { setUseAsCollateralValidationIssueToMessage } from '@/domain/market-validators/validateSetUseAsCollateral' -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { BorrowPageObject } from '@/pages/Borrow.PageObject' import { MyPortfolioPageObject } from '@/pages/MyPortfolio.PageObject' -import { DEFAULT_BLOCK_NUMBER, GNO_ACTIVE_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' - +import { test } from '@playwright/test' +import { mainnet } from 'viem/chains' import { DialogPageObject } from '../common/Dialog.PageObject' import { CollateralDialogPageObject } from './CollateralDialog.PageObject' test.describe('Collateral dialog', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) const initialBalances = { wstETH: 100, rETH: 100, DAI: 10000, - GNO: 100, + weETH: 100, } test.describe('Deposited multiple assets, no borrow', () => { @@ -29,8 +24,15 @@ test.describe('Collateral dialog', () => { DAI: 1000, // cannot be used as collateral } + let collateralDialog: CollateralDialogPageObject + let myPortfolioPage: MyPortfolioPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -38,17 +40,18 @@ test.describe('Collateral dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions(initialDeposits) - const myPortfolioPage = new MyPortfolioPageObject(page) + const borrowPage = new BorrowPageObject(testContext) + const depositDialog = new DialogPageObject({ testContext, header: /Deposit/ }) + myPortfolioPage = new MyPortfolioPageObject(testContext) + collateralDialog = new CollateralDialogPageObject(testContext) + + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: initialDeposits }) await myPortfolioPage.goToMyPortfolioAction() // Depositing DAI in myPortfolio await myPortfolioPage.clickDepositButtonAction('DAI') - const depositDialog = new DialogPageObject(page, /Deposit/) await depositDialog.fillAmountAction(myPortfolioDesposits.DAI) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.viewInMyPortfolioAction() await myPortfolioPage.expectDepositTable({ @@ -57,32 +60,27 @@ test.describe('Collateral dialog', () => { }) }) - test('disables collateral', async ({ page }) => { + test('disables collateral', async () => { const collateral = 'wstETH' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.expectCollateralSwitch(collateral, true) await myPortfolioPage.clickCollateralSwitchAction(collateral) - const collateralDialog = new CollateralDialogPageObject(page) await collateralDialog.expectDialogHeader('Collateral') await collateralDialog.expectHealthFactorNotVisible() - const actionsContainer = new ActionsPageObject(collateralDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) + await collateralDialog.actionsContainer.acceptAllActionsAction(1) await collateralDialog.expectSetUseAsCollateralSuccessPage(collateral, 'disabled') await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectCollateralSwitch('wstETH', false) }) - test('enables collateral', async ({ page }) => { + test('enables collateral', async () => { const collateral = 'wstETH' // disabling collateral - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.clickCollateralSwitchAction(collateral) - const collateralDialog = new CollateralDialogPageObject(page) - await collateralDialog.setUseAsCollateralAction(collateral, 'disabled') + await collateralDialog.setUseAsCollateralAction({ assetName: collateral, setting: 'disabled' }) await myPortfolioPage.goToMyPortfolioAction() // enabling collateral @@ -90,45 +88,38 @@ test.describe('Collateral dialog', () => { await myPortfolioPage.clickCollateralSwitchAction(collateral) await collateralDialog.expectDialogHeader('Collateral') await collateralDialog.expectHealthFactorNotVisible() - const actionsContainer = new ActionsPageObject(collateralDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) + await collateralDialog.actionsContainer.acceptAllActionsAction(1) await collateralDialog.expectSetUseAsCollateralSuccessPage(collateral, 'enabled') await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectCollateralSwitch(collateral, true) }) - test('cannot enable collateral for asset that cannot be used as collateral', async ({ page }) => { + test('cannot enable collateral for asset that cannot be used as collateral', async () => { const asset = 'DAI' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.expectCollateralSwitch(asset, false) await myPortfolioPage.clickCollateralSwitchAction(asset) - const collateralDialog = new CollateralDialogPageObject(page) await collateralDialog.expectDialogHeader('Collateral') await collateralDialog.expectHealthFactorNotVisible() await collateralDialog.expectAlertMessage(setUseAsCollateralValidationIssueToMessage['zero-ltv-asset']) - const actionsContainer = new ActionsPageObject(collateralDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectDisabledActionAtIndex(0) + await collateralDialog.actionsContainer.expectDisabledActionAtIndex(0) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectCollateralSwitch(asset, false) }) - test('cannot enable collateral for not deposited asset', async ({ page }) => { + test('cannot enable collateral for not deposited asset', async () => { const asset = 'WBTC' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.expectCollateralSwitch(asset, false) await myPortfolioPage.clickCollateralSwitchAction(asset) - const collateralDialog = new CollateralDialogPageObject(page) await collateralDialog.expectDialogHeader('Collateral') await collateralDialog.expectHealthFactorNotVisible() await collateralDialog.expectAlertMessage(setUseAsCollateralValidationIssueToMessage['zero-deposit-asset']) - const actionsContainer = new ActionsPageObject(collateralDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectDisabledActionAtIndex(0) + await collateralDialog.actionsContainer.expectDisabledActionAtIndex(0) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectCollateralSwitch(asset, false) @@ -140,9 +131,15 @@ test.describe('Collateral dialog', () => { wstETH: 1, } const daiToBorrow = 1000 + let collateralDialog: CollateralDialogPageObject + let myPortfolioPage: MyPortfolioPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -150,32 +147,30 @@ test.describe('Collateral dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositAssetsActions(initialDeposits, daiToBorrow) + const borrowPage = new BorrowPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + collateralDialog = new CollateralDialogPageObject(testContext) + + await borrowPage.depositAssetsActions({ assetsToDeposit: initialDeposits, daiToBorrow }) await borrowPage.viewInMyPortfolioAction() - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.goToMyPortfolioAction() - await myPortfolioPage.expectDepositTable({ wstETH: initialDeposits.wstETH, }) }) - test('cannot disable sole collateral', async ({ page }) => { + test('cannot disable sole collateral', async () => { const collateral = 'wstETH' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.expectCollateralSwitch(collateral, true) await myPortfolioPage.clickCollateralSwitchAction(collateral) - const collateralDialog = new CollateralDialogPageObject(page) await collateralDialog.expectDialogHeader('Collateral') - await collateralDialog.expectHealthFactorBefore('2.08') + await collateralDialog.expectHealthFactorBefore('3.73') await collateralDialog.expectHealthFactorAfter('0') await collateralDialog.expectAlertMessage(setUseAsCollateralValidationIssueToMessage['exceeds-ltv']) - const actionsContainer = new ActionsPageObject(collateralDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectDisabledActionAtIndex(0) + await collateralDialog.actionsContainer.expectDisabledActionAtIndex(0) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectCollateralSwitch(collateral, true) @@ -188,9 +183,15 @@ test.describe('Collateral dialog', () => { rETH: 0.01, } const daiToBorrow = 1000 + let collateralDialog: CollateralDialogPageObject + let myPortfolioPage: MyPortfolioPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -198,52 +199,47 @@ test.describe('Collateral dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositAssetsActions(initialDeposits, daiToBorrow) + const borrowPage = new BorrowPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + collateralDialog = new CollateralDialogPageObject(testContext) + + await borrowPage.depositAssetsActions({ assetsToDeposit: initialDeposits, daiToBorrow }) await borrowPage.viewInMyPortfolioAction() - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.goToMyPortfolioAction() - await myPortfolioPage.expectDepositTable({ wstETH: initialDeposits.wstETH, rETH: initialDeposits.rETH, }) }) - test('disables collateral', async ({ page }) => { + test('disables collateral', async () => { const collateral = 'rETH' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.expectCollateralSwitch(collateral, true) await myPortfolioPage.clickCollateralSwitchAction(collateral) - const collateralDialog = new CollateralDialogPageObject(page) await collateralDialog.expectDialogHeader('Collateral') - await collateralDialog.expectHealthFactorBefore('2.1') - await collateralDialog.expectHealthFactorAfter('2.08') - const actionsContainer = new ActionsPageObject(collateralDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) - + await collateralDialog.expectHealthFactorBefore('3.77') + await collateralDialog.expectHealthFactorAfter('3.73') + await collateralDialog.actionsContainer.acceptAllActionsAction(1) await collateralDialog.expectSetUseAsCollateralSuccessPage(collateral, 'disabled') + await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectCollateralSwitch('rETH', false) }) - test('cannot disable collateral when second one would not cover loan', async ({ page }) => { + test('cannot disable collateral when second one would not cover loan', async () => { const collateral = 'wstETH' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.expectCollateralSwitch(collateral, true) await myPortfolioPage.clickCollateralSwitchAction(collateral) - const collateralDialog = new CollateralDialogPageObject(page) await collateralDialog.expectDialogHeader('Collateral') - await collateralDialog.expectHealthFactorBefore('2.1') - await collateralDialog.expectHealthFactorAfter('0.02') + await collateralDialog.expectHealthFactorBefore('3.77') + await collateralDialog.expectHealthFactorAfter('0.04') await collateralDialog.expectAlertMessage(setUseAsCollateralValidationIssueToMessage['exceeds-ltv']) - const actionsContainer = new ActionsPageObject(collateralDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectDisabledActionAtIndex(0) + await collateralDialog.actionsContainer.expectDisabledActionAtIndex(0) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectCollateralSwitch(collateral, true) @@ -251,8 +247,7 @@ test.describe('Collateral dialog', () => { }) test.describe('Isolation mode', () => { - const fork = setupFork({ blockNumber: GNO_ACTIVE_BLOCK_NUMBER, chainId: mainnet.id }) - const isolatedAsset = 'GNO' + const isolatedAsset = 'weETH' const regularAsset = 'rETH' const initialDeposits = { [regularAsset]: 1, @@ -261,8 +256,15 @@ test.describe('Collateral dialog', () => { [isolatedAsset]: 100, } + let collateralDialog: CollateralDialogPageObject + let myPortfolioPage: MyPortfolioPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -271,49 +273,46 @@ test.describe('Collateral dialog', () => { }) // Depositing regular asset at borrow page to show myPortfolio positions - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions(initialDeposits) - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.goToMyPortfolioAction() + const borrowPage = new BorrowPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + collateralDialog = new CollateralDialogPageObject(testContext) + + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: initialDeposits }) + await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectDepositTable({ [regularAsset]: initialDeposits[regularAsset], }) // Depositing isolated asset at myPortfolio await myPortfolioPage.clickDepositButtonAction(isolatedAsset) - const depositDialog = new DialogPageObject(page, /Deposit/) + const depositDialog = new DialogPageObject({ testContext, header: /Deposit/ }) await depositDialog.fillAmountAction(myPortfolioDesposits[isolatedAsset]) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.viewInMyPortfolioAction() - const collateralDialog = new CollateralDialogPageObject(page) // Disabling regular asset as collateral await myPortfolioPage.clickCollateralSwitchAction(regularAsset) - await collateralDialog.setUseAsCollateralAction(regularAsset, 'disabled') + await collateralDialog.setUseAsCollateralAction({ assetName: regularAsset, setting: 'disabled' }) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectCollateralSwitch(isolatedAsset, false) // Entering isolation mode await myPortfolioPage.clickCollateralSwitchAction(isolatedAsset) - await collateralDialog.setUseAsCollateralAction(isolatedAsset, 'enabled') + await collateralDialog.setUseAsCollateralAction({ assetName: isolatedAsset, setting: 'enabled' }) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectCollateralSwitch(isolatedAsset, true) }) - test('cannot enable asset as collateral in isolation mode', async ({ page }) => { + test('cannot enable asset as collateral in isolation mode', async () => { const collateral = 'rETH' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.expectCollateralSwitch(collateral, false) await myPortfolioPage.clickCollateralSwitchAction(collateral) - const collateralDialog = new CollateralDialogPageObject(page) await collateralDialog.expectAlertMessage(setUseAsCollateralValidationIssueToMessage['isolation-mode-active']) - const actionsContainer = new ActionsPageObject(collateralDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectDisabledActionAtIndex(0) + await collateralDialog.actionsContainer.expectDisabledActionAtIndex(0) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectCollateralSwitch(collateral, false) @@ -326,7 +325,11 @@ test.describe('Collateral dialog', () => { let myPortfolioPage: MyPortfolioPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -334,19 +337,23 @@ test.describe('Collateral dialog', () => { }, }) - collateralDialog = new CollateralDialogPageObject(page) - myPortfolioPage = new MyPortfolioPageObject(page) + const borrowPage = new BorrowPageObject(testContext) + const borrowDialog = new DialogPageObject({ testContext, header: /Borrow/ }) + collateralDialog = new CollateralDialogPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ rETH: 2, wstETH: 10 }) - await myPortfolioPage.goToMyPortfolioAction() + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: { rETH: 2, wstETH: 10 } }) + await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.clickBorrowButtonAction('WETH') - const borrowDialog = new DialogPageObject(page, /Borrow/) + await borrowDialog.fillAmountAction(7) await borrowDialog.actionsContainer.acceptAllActionsAction(1) - await borrowDialog.expectSuccessPage([{ asset: 'WETH', amount: 7 }], fork) + await borrowDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'WETH', amount: '7.00', usdValue: '$27,498.19' }], + }) await borrowDialog.viewInMyPortfolioAction() + await myPortfolioPage.expectAssetToBeInBorrowTable('WETH') }) @@ -369,13 +376,18 @@ test.describe('Collateral dialog', () => { test.describe('Not in danger zone', () => { let collateralDialog: CollateralDialogPageObject let myPortfolioPage: MyPortfolioPageObject + let borrowPage: BorrowPageObject const rETHDeposit = { asset: 'rETH', amount: 1 } const wstETHDeposit = { asset: 'wstETH', amount: 1 } const daiBorrow = { asset: 'DAI', amount: 500 } test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -383,15 +395,21 @@ test.describe('Collateral dialog', () => { }, }) - collateralDialog = new CollateralDialogPageObject(page) - myPortfolioPage = new MyPortfolioPageObject(page) + collateralDialog = new CollateralDialogPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + borrowPage = new BorrowPageObject(testContext) }) - test('validation issue; risk warning is not shown', async ({ page }) => { + test('validation issue; risk warning is not shown', async () => { // depositing single asset as collateral, so turing off will trigger validation - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositAssetsActions({ rETH: rETHDeposit.amount }, daiBorrow.amount) - await borrowPage.expectSuccessPage([rETHDeposit], daiBorrow, fork) + await borrowPage.depositAssetsActions({ + assetsToDeposit: { rETH: rETHDeposit.amount }, + daiToBorrow: daiBorrow.amount, + }) + await borrowPage.expectSuccessPage({ + deposited: [{ asset: 'rETH', amount: '1.00', usdValue: '$4,413.26' }], + borrowed: { asset: 'DAI', amount: '500.00', usdValue: '$500.00' }, + }) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectAssetToBeInBorrowTable('DAI') @@ -400,14 +418,20 @@ test.describe('Collateral dialog', () => { await collateralDialog.expectLiquidationRiskWarningNotVisible() }) - test('no validation issue; risk warning is not shown', async ({ page }) => { + test('no validation issue; risk warning is not shown', async () => { // depositing multiple assets as collateral, so turning off single asset will not trigger validation - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositAssetsActions( - { wstETH: wstETHDeposit.amount, rETH: rETHDeposit.amount }, - daiBorrow.amount, - ) - await borrowPage.expectSuccessPage([wstETHDeposit, rETHDeposit], daiBorrow, fork) + await borrowPage.depositAssetsActions({ + assetsToDeposit: { wstETH: wstETHDeposit.amount, rETH: rETHDeposit.amount }, + daiToBorrow: daiBorrow.amount, + }) + await borrowPage.expectSuccessPage({ + deposited: [ + { asset: 'wstETH', amount: '1.00', usdValue: '$4,665.46' }, + { asset: 'rETH', amount: '1.00', usdValue: '$4,413.26' }, + ], + borrowed: { asset: 'DAI', amount: '500.00', usdValue: '$500.00' }, + }) + await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectAssetToBeInBorrowTable('DAI') diff --git a/packages/app/src/features/dialogs/common/Dialog.PageObject.ts b/packages/app/src/features/dialogs/common/Dialog.PageObject.ts index d1a7fd7c4..a7d99ae42 100644 --- a/packages/app/src/features/dialogs/common/Dialog.PageObject.ts +++ b/packages/app/src/features/dialogs/common/Dialog.PageObject.ts @@ -1,22 +1,22 @@ -import { Locator, Page, expect } from '@playwright/test' +import { Locator, expect } from '@playwright/test' import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { BasePageObject } from '@/test/e2e/BasePageObject' import { TestTokenWithValue, expectAssets } from '@/test/e2e/assertions' -import { ForkContext } from '@/test/e2e/forking/setupFork' -import { calculateAssetsWorth, isPage } from '@/test/e2e/utils' +import { TestContext } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' +export interface DialogPageObjectParams { + testContext: TestContext + header: RegExp +} + export class DialogPageObject extends BasePageObject { public readonly actionsContainer: ActionsPageObject - constructor(pageOrLocator: Page | Locator, header: RegExp) { - if (isPage(pageOrLocator)) { - super(pageOrLocator) - this.region = this.locateDialogByHeader(header) - } else { - super(pageOrLocator) - } - this.actionsContainer = new ActionsPageObject(this.locatePanelByHeader('Actions')) + constructor({ testContext, header }: DialogPageObjectParams) { + super(testContext) + this.region = this.locateDialogByHeader(header) + this.actionsContainer = new ActionsPageObject(testContext, this.locatePanelByHeader('Actions')) } getDialog(): Locator { @@ -53,20 +53,14 @@ export class DialogPageObject extends BasePageObject { // #endregion actions // #region assertions - async expectSuccessPage( - tokenWithValue: TestTokenWithValue[], - fork: ForkContext, - assetWorthOverrides?: Record, - ): Promise { + async expectSuccessPage({ + tokenWithValue, + }: { + tokenWithValue: TestTokenWithValue[] + }): Promise { await expect(this.region.getByText('Congrats, all done!')).toBeVisible() - - const transformed = tokenWithValue.reduce((acc, { asset, amount: value }) => ({ ...acc, [asset]: value }), {}) - - const { assetsWorth } = await calculateAssetsWorth(fork.forkUrl, transformed) - const mergedAssetsWorth = { ...assetsWorth, ...assetWorthOverrides } - const summary = await this.region.getByTestId(testIds.dialog.success).textContent() - expectAssets(summary!, tokenWithValue, mergedAssetsWorth) + expectAssets(summary!, tokenWithValue) } async expectRiskLevelBefore(riskLevel: string): Promise { diff --git a/packages/app/src/features/dialogs/common/logic/transfer-from-user/form.ts b/packages/app/src/features/dialogs/common/logic/transfer-from-user/form.ts index dfacace5c..ce67e6a47 100644 --- a/packages/app/src/features/dialogs/common/logic/transfer-from-user/form.ts +++ b/packages/app/src/features/dialogs/common/logic/transfer-from-user/form.ts @@ -74,6 +74,7 @@ export function getFieldsForTransferFromUserForm({ const changeAsset = (newSymbol: TokenSymbol): void => { form.setValue('symbol', newSymbol) form.setValue('value', '') + form.setValue('isMaxSelected', false) form.clearErrors() } diff --git a/packages/app/src/features/dialogs/convert-stables/ConvertStablesDialog.PageObject.ts b/packages/app/src/features/dialogs/convert-stables/ConvertStablesDialog.PageObject.ts index 7441df320..2ef154772 100644 --- a/packages/app/src/features/dialogs/convert-stables/ConvertStablesDialog.PageObject.ts +++ b/packages/app/src/features/dialogs/convert-stables/ConvertStablesDialog.PageObject.ts @@ -1,10 +1,11 @@ import { DialogPageObject, TxOverviewWithRoute } from '@/features/dialogs/common/Dialog.PageObject' +import { TestContext } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' -import { Locator, Page, expect } from '@playwright/test' +import { Locator, expect } from '@playwright/test' export class ConvertStablesDialogPageObject extends DialogPageObject { - constructor(page: Page) { - super(page, /Convert Tokens/) + constructor(testContext: TestContext) { + super({ testContext, header: /Convert Tokens/ }) } // # region locators diff --git a/packages/app/src/features/dialogs/convert-stables/ConvertStablesDialog.test-e2e.ts b/packages/app/src/features/dialogs/convert-stables/ConvertStablesDialog.test-e2e.ts index 811e68121..9a31dd640 100644 --- a/packages/app/src/features/dialogs/convert-stables/ConvertStablesDialog.test-e2e.ts +++ b/packages/app/src/features/dialogs/convert-stables/ConvertStablesDialog.test-e2e.ts @@ -1,18 +1,20 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { ConvertStablesDialogPageObject } from './ConvertStablesDialog.PageObject' test.describe('Convert Stables Dialog', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let convertStablesDialog: ConvertStablesDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,9 +25,9 @@ test.describe('Convert Stables Dialog', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickConvertStablesButtonAction() - convertStablesDialog = new ConvertStablesDialogPageObject(page) + convertStablesDialog = new ConvertStablesDialogPageObject(testContext) }) test('has correct selectors configuration', async ({ page }) => { diff --git a/packages/app/src/features/dialogs/convert-stables/e2e/base/UsdcToUsds.test-e2e.ts b/packages/app/src/features/dialogs/convert-stables/e2e/base/UsdcToUsds.test-e2e.ts index 9539dde75..0ac9048ad 100644 --- a/packages/app/src/features/dialogs/convert-stables/e2e/base/UsdcToUsds.test-e2e.ts +++ b/packages/app/src/features/dialogs/convert-stables/e2e/base/UsdcToUsds.test-e2e.ts @@ -1,17 +1,20 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { BASE_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { base } from 'viem/chains' import { ConvertStablesDialogPageObject } from '../../ConvertStablesDialog.PageObject' test.describe('Convert USDC to USDS', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let convertStablesDialog: ConvertStablesDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + chainId: base.id, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -22,10 +25,10 @@ test.describe('Convert USDC to USDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickConvertStablesButtonAction() - convertStablesDialog = new ConvertStablesDialogPageObject(page) + convertStablesDialog = new ConvertStablesDialogPageObject(testContext) await convertStablesDialog.selectAssetInAction('USDC') await convertStablesDialog.selectAssetOutAction('USDS') await convertStablesDialog.fillAmountInAction(10_000) diff --git a/packages/app/src/features/dialogs/convert-stables/e2e/base/UsdsToUsdc.test-e2e.ts b/packages/app/src/features/dialogs/convert-stables/e2e/base/UsdsToUsdc.test-e2e.ts index 495fd9ba0..bd59d4e1e 100644 --- a/packages/app/src/features/dialogs/convert-stables/e2e/base/UsdsToUsdc.test-e2e.ts +++ b/packages/app/src/features/dialogs/convert-stables/e2e/base/UsdsToUsdc.test-e2e.ts @@ -1,17 +1,20 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { BASE_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { base } from 'viem/chains' import { ConvertStablesDialogPageObject } from '../../ConvertStablesDialog.PageObject' test.describe('Convert USDS to USDC', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let convertStablesDialog: ConvertStablesDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + chainId: base.id, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -22,10 +25,10 @@ test.describe('Convert USDS to USDC', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickConvertStablesButtonAction() - convertStablesDialog = new ConvertStablesDialogPageObject(page) + convertStablesDialog = new ConvertStablesDialogPageObject(testContext) await convertStablesDialog.selectAssetInAction('USDS') await convertStablesDialog.selectAssetOutAction('USDC') await convertStablesDialog.fillAmountInAction(10_000) diff --git a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/DaiToUsdc.test-e2e.ts b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/DaiToUsdc.test-e2e.ts index de83923ee..fd535b167 100644 --- a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/DaiToUsdc.test-e2e.ts +++ b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/DaiToUsdc.test-e2e.ts @@ -1,18 +1,20 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { ConvertStablesDialogPageObject } from '../../ConvertStablesDialog.PageObject' test.describe('Convert DAI to USDC', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let convertStablesDialog: ConvertStablesDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,10 +25,10 @@ test.describe('Convert DAI to USDC', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickConvertStablesButtonAction() - convertStablesDialog = new ConvertStablesDialogPageObject(page) + convertStablesDialog = new ConvertStablesDialogPageObject(testContext) await convertStablesDialog.selectAssetInAction('DAI') await convertStablesDialog.selectAssetOutAction('USDC') await convertStablesDialog.fillAmountInAction(10_000) diff --git a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/DaiToUsds.test-e2e.ts b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/DaiToUsds.test-e2e.ts index b64437b61..df67ccb42 100644 --- a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/DaiToUsds.test-e2e.ts +++ b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/DaiToUsds.test-e2e.ts @@ -1,18 +1,20 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { ConvertStablesDialogPageObject } from '../../ConvertStablesDialog.PageObject' test.describe('Convert DAI to USDS', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let convertStablesDialog: ConvertStablesDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,10 +25,10 @@ test.describe('Convert DAI to USDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickConvertStablesButtonAction() - convertStablesDialog = new ConvertStablesDialogPageObject(page) + convertStablesDialog = new ConvertStablesDialogPageObject(testContext) await convertStablesDialog.selectAssetInAction('DAI') await convertStablesDialog.selectAssetOutAction('USDS') await convertStablesDialog.fillAmountInAction(10_000) diff --git a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdcToDai.test-e2e.ts b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdcToDai.test-e2e.ts index 66fcf6653..15f35e0eb 100644 --- a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdcToDai.test-e2e.ts +++ b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdcToDai.test-e2e.ts @@ -1,18 +1,20 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { ConvertStablesDialogPageObject } from '../../ConvertStablesDialog.PageObject' test.describe('Convert USDC to DAI', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let convertStablesDialog: ConvertStablesDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,10 +25,10 @@ test.describe('Convert USDC to DAI', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickConvertStablesButtonAction() - convertStablesDialog = new ConvertStablesDialogPageObject(page) + convertStablesDialog = new ConvertStablesDialogPageObject(testContext) await convertStablesDialog.selectAssetInAction('USDC') await convertStablesDialog.selectAssetOutAction('DAI') await convertStablesDialog.fillAmountInAction(10_000) diff --git a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdcToUsds.test-e2e.ts b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdcToUsds.test-e2e.ts index 3d43aeeb5..7c8568311 100644 --- a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdcToUsds.test-e2e.ts +++ b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdcToUsds.test-e2e.ts @@ -1,18 +1,20 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { ConvertStablesDialogPageObject } from '../../ConvertStablesDialog.PageObject' test.describe('Convert USDC to USDS', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let convertStablesDialog: ConvertStablesDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,10 +25,10 @@ test.describe('Convert USDC to USDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickConvertStablesButtonAction() - convertStablesDialog = new ConvertStablesDialogPageObject(page) + convertStablesDialog = new ConvertStablesDialogPageObject(testContext) await convertStablesDialog.selectAssetInAction('USDC') await convertStablesDialog.selectAssetOutAction('USDS') await convertStablesDialog.fillAmountInAction(10_000) diff --git a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdsToDai.test-e2e.ts b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdsToDai.test-e2e.ts index 1a269054c..9c04e05f4 100644 --- a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdsToDai.test-e2e.ts +++ b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdsToDai.test-e2e.ts @@ -1,18 +1,20 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { ConvertStablesDialogPageObject } from '../../ConvertStablesDialog.PageObject' test.describe('Convert USDS to DAI', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let convertStablesDialog: ConvertStablesDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,10 +25,10 @@ test.describe('Convert USDS to DAI', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickConvertStablesButtonAction() - convertStablesDialog = new ConvertStablesDialogPageObject(page) + convertStablesDialog = new ConvertStablesDialogPageObject(testContext) await convertStablesDialog.selectAssetInAction('USDS') await convertStablesDialog.selectAssetOutAction('DAI') await convertStablesDialog.fillAmountInAction(10_000) diff --git a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdsToUsdc.test-e2e.ts b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdsToUsdc.test-e2e.ts index 7fce3b536..1e84f5d25 100644 --- a/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdsToUsdc.test-e2e.ts +++ b/packages/app/src/features/dialogs/convert-stables/e2e/mainnet/UsdsToUsdc.test-e2e.ts @@ -1,18 +1,20 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { ConvertStablesDialogPageObject } from '../../ConvertStablesDialog.PageObject' test.describe('Convert USDS to USDC', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let convertStablesDialog: ConvertStablesDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,10 +25,10 @@ test.describe('Convert USDS to USDC', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickConvertStablesButtonAction() - convertStablesDialog = new ConvertStablesDialogPageObject(page) + convertStablesDialog = new ConvertStablesDialogPageObject(testContext) await convertStablesDialog.selectAssetInAction('USDS') await convertStablesDialog.selectAssetOutAction('USDC') await convertStablesDialog.fillAmountInAction(10_000) diff --git a/packages/app/src/features/dialogs/deposit/DepositDialog.test-e2e.ts b/packages/app/src/features/dialogs/deposit/DepositDialog.test-e2e.ts index 15f466339..70c90e19a 100644 --- a/packages/app/src/features/dialogs/deposit/DepositDialog.test-e2e.ts +++ b/packages/app/src/features/dialogs/deposit/DepositDialog.test-e2e.ts @@ -1,21 +1,17 @@ import { test } from '@playwright/test' import { mainnet } from 'viem/chains' -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { BorrowPageObject } from '@/pages/Borrow.PageObject' import { MyPortfolioPageObject } from '@/pages/MyPortfolio.PageObject' import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' -import { screenshot } from '@/test/e2e/utils' -import { tenderlyRpcActions } from '@/domain/tenderly/TenderlyRpcActions' +import { TestTokenWithValue } from '@/test/e2e/assertions' import { DialogPageObject } from '../common/Dialog.PageObject' const headerRegExp = /Deposit */ test.describe('Deposit dialog', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) const initialBalances = { wstETH: 100, rETH: 100, @@ -28,11 +24,18 @@ test.describe('Deposit dialog', () => { rETH: 2, } const daiToBorrow = 1500 - const expectedInitialHealthFactor = '4.03' - const expectedHealthFactor = '5.35' + const expectedInitialHealthFactor = '7.2' + const expectedHealthFactor = '9.55' + + let myPortfolioPage: MyPortfolioPageObject + let depositDialog: DialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -40,136 +43,101 @@ test.describe('Deposit dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositAssetsActions(initialDeposits, daiToBorrow) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositAssetsActions({ assetsToDeposit: initialDeposits, daiToBorrow }) await borrowPage.viewInMyPortfolioAction() - const myPortfolioPage = new MyPortfolioPageObject(page) + myPortfolioPage = new MyPortfolioPageObject(testContext) // @todo This waits for the refetch of the data after successful borrow transaction to happen. // This is no ideal, probably we need to refactor expectDepositTable so it takes advantage from // playwright's timeouts instead of parsing it's current state. Then we would be able to // easily wait for the table to be updated. await myPortfolioPage.expectAssetToBeInDepositTable('DAI') + await myPortfolioPage.expectDepositTable(initialDeposits) + + depositDialog = new DialogPageObject({ + testContext, + header: headerRegExp, + }) }) - test('opens dialog with selected asset', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('opens dialog with selected asset', async () => { await myPortfolioPage.clickDepositButtonAction('rETH') - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.expectSelectedAsset('rETH') await depositDialog.expectDialogHeader('Deposit rETH') await depositDialog.expectHealthFactorBeforeVisible() - - await screenshot(depositDialog.getDialog(), 'deposit-dialog-default-view') }) - test('calculates health factor changes correctly', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('calculates health factor changes correctly', async () => { await myPortfolioPage.clickDepositButtonAction('rETH') - - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.fillAmountAction(1) await depositDialog.expectRiskLevelBefore('Healthy') await depositDialog.expectHealthFactorBefore(expectedInitialHealthFactor) await depositDialog.expectRiskLevelAfter('Healthy') await depositDialog.expectHealthFactorAfter(expectedHealthFactor) - - // @note this is needed for deterministic screenshots - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectEnabledActionAtIndex(0) - - await screenshot(depositDialog.getDialog(), 'deposit-dialog-health-factor') }) - test('after deposit, health factor matches myPortfolio', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('after deposit, health factor matches myPortfolio', async () => { await myPortfolioPage.clickDepositButtonAction('rETH') - - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.fillAmountAction(1) - - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.viewInMyPortfolioAction() await myPortfolioPage.expectHealthFactor(expectedHealthFactor) }) - test('has correct action plan for erc-20 with permit support', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.expectDepositTable(initialDeposits) - + test('has correct action plan for erc-20 with permit support', async () => { await myPortfolioPage.clickDepositButtonAction('wstETH') - - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.fillAmountAction(1) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectActions([ + + await depositDialog.actionsContainer.expectActions([ { type: 'permit', asset: 'wstETH' }, { type: 'deposit', asset: 'wstETH' }, ]) }) - test('can switch to approves in action plan', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.expectDepositTable(initialDeposits) - + test('can switch to approves in action plan', async () => { await myPortfolioPage.clickDepositButtonAction('wstETH') - - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.fillAmountAction(1) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ + await depositDialog.actionsContainer.expectEnabledActionAtIndex(0) + await depositDialog.actionsContainer.expectActions([ { type: 'permit', asset: 'wstETH' }, { type: 'deposit', asset: 'wstETH' }, ]) - await actionsContainer.switchPreferPermitsAction() + await depositDialog.actionsContainer.switchPreferPermitsAction() - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ + await depositDialog.actionsContainer.expectEnabledActionAtIndex(0) + await depositDialog.actionsContainer.expectActions([ { type: 'approve', asset: 'wstETH' }, { type: 'deposit', asset: 'wstETH' }, ]) }) - test('has correct action plan for erc-20 with no permit support', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.expectDepositTable(initialDeposits) - + test('has correct action plan for erc-20 with no permit support', async () => { await myPortfolioPage.clickDepositButtonAction('rETH') - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.fillAmountAction(1) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectActions([ + await depositDialog.actionsContainer.expectActions([ { type: 'approve', asset: 'rETH' }, { type: 'deposit', asset: 'rETH' }, ]) }) - test('can deposit erc-20 using permits', async ({ page }) => { - const deposit = { + test('can deposit erc-20 using permits', async () => { + const deposit: TestTokenWithValue = { asset: 'wstETH', - amount: 1, + amount: '1.00', + usdValue: '$4,665.46', } - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.expectDepositTable(initialDeposits) - await myPortfolioPage.clickDepositButtonAction(deposit.asset) - - const depositDialog = new DialogPageObject(page, headerRegExp) - await depositDialog.fillAmountAction(deposit.amount) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await depositDialog.expectSuccessPage([deposit], fork) - - await screenshot(depositDialog.getDialog(), 'deposit-dialog-wsteth-success') + await depositDialog.fillAmountAction(Number(deposit.amount)) + await depositDialog.actionsContainer.acceptAllActionsAction(2) + await depositDialog.expectSuccessPage({ tokenWithValue: [deposit] }) await depositDialog.viewInMyPortfolioAction() @@ -179,24 +147,17 @@ test.describe('Deposit dialog', () => { }) }) - test('can deposit erc-20 using approves', async ({ page }) => { - const deposit = { + test('can deposit erc-20 using approves', async () => { + const deposit: TestTokenWithValue = { asset: 'rETH', - amount: 1, + amount: '1.00', + usdValue: '$4,413.26', } - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.expectDepositTable(initialDeposits) - await myPortfolioPage.clickDepositButtonAction(deposit.asset) - - const depositDialog = new DialogPageObject(page, headerRegExp) - await depositDialog.fillAmountAction(deposit.amount) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await depositDialog.expectSuccessPage([deposit], fork) - - await screenshot(depositDialog.getDialog(), 'deposit-dialog-reth-success') + await depositDialog.fillAmountAction(Number(deposit.amount)) + await depositDialog.actionsContainer.acceptAllActionsAction(2) + await depositDialog.expectSuccessPage({ tokenWithValue: [deposit] }) await depositDialog.viewInMyPortfolioAction() @@ -206,48 +167,35 @@ test.describe('Deposit dialog', () => { }) }) - test('has correct action plan for native asset', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.expectDepositTable(initialDeposits) - + test('has correct action plan for native asset', async () => { await myPortfolioPage.clickDepositButtonAction('WETH') - - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.selectAssetAction('ETH') await depositDialog.fillAmountAction(1) await depositDialog.expectHealthFactorVisible() - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectActions([{ type: 'deposit', asset: 'ETH' }]) - - await screenshot(depositDialog.getDialog(), 'deposit-dialog-eth-action-plan') + await depositDialog.actionsContainer.expectActions([{ type: 'deposit', asset: 'ETH' }]) }) - test('can deposit native asset', async ({ page }) => { - const deposit = { + test('can deposit native asset', async () => { + const deposit: TestTokenWithValue = { asset: 'WETH', - amount: 1, + amount: '1.00', + usdValue: '$3,928.31', } - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.expectDepositTable(initialDeposits) - await myPortfolioPage.clickDepositButtonAction(deposit.asset) - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.selectAssetAction('ETH') - await depositDialog.fillAmountAction(deposit.amount) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) - await depositDialog.expectSuccessPage( - [ + await depositDialog.fillAmountAction(Number(deposit.amount)) + await depositDialog.actionsContainer.acceptAllActionsAction(1) + await depositDialog.expectSuccessPage({ + tokenWithValue: [ { asset: 'ETH', amount: deposit.amount, + usdValue: deposit.usdValue, }, ], - fork, - ) - await screenshot(depositDialog.getDialog(), 'deposit-dialog-eth-success') + }) await depositDialog.viewInMyPortfolioAction() @@ -258,53 +206,41 @@ test.describe('Deposit dialog', () => { }) }) - test("can't deposit more than wallet balance", async ({ page }) => { + test("can't deposit more than wallet balance", async () => { const depositAsset = 'rETH' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.clickDepositButtonAction(depositAsset) - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.fillAmountAction(initialBalances[depositAsset] - initialDeposits[depositAsset] + 1) await depositDialog.expectAssetInputError('Exceeds your balance') await depositDialog.expectHealthFactorBeforeVisible() - await screenshot(depositDialog.getDialog(), 'deposit-dialog-exceeds-balance') }) - test('requires new approve when the input value is increased', async ({ page }) => { + test('requires new approve when the input value is increased', async () => { const depositAsset = 'rETH' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.clickDepositButtonAction(depositAsset) - - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.fillAmountAction(1) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - - await actionsContainer.acceptActionAtIndex(0) - await actionsContainer.expectEnabledActionAtIndex(1, { type: 'deposit', asset: depositAsset }) + await depositDialog.actionsContainer.acceptActionAtIndex(0) + await depositDialog.actionsContainer.expectEnabledActionAtIndex(1, { type: 'deposit', asset: depositAsset }) await depositDialog.fillAmountAction(2) - await actionsContainer.expectEnabledActionAtIndex(0, { type: 'approve', asset: depositAsset }) + await depositDialog.actionsContainer.expectEnabledActionAtIndex(0, { type: 'approve', asset: depositAsset }) }) - test('requires new permit when the input value is changed', async ({ page }) => { + test('requires new permit when the input value is changed', async () => { const depositAsset = 'wstETH' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.clickDepositButtonAction(depositAsset) - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.fillAmountAction(2) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - - await actionsContainer.acceptActionAtIndex(0) - await actionsContainer.expectEnabledActionAtIndex(1, { type: 'deposit', asset: depositAsset }) + await depositDialog.actionsContainer.acceptActionAtIndex(0) + await depositDialog.actionsContainer.expectEnabledActionAtIndex(1, { type: 'deposit', asset: depositAsset }) await depositDialog.fillAmountAction(1) - await actionsContainer.expectEnabledActionAtIndex(0, { type: 'permit', asset: depositAsset }) + await depositDialog.actionsContainer.expectEnabledActionAtIndex(0, { type: 'permit', asset: depositAsset }) }) }) @@ -314,8 +250,15 @@ test.describe('Deposit dialog', () => { rETH: 2, } + let myPortfolioPage: MyPortfolioPageObject + let depositDialog: DialogPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -323,7 +266,7 @@ test.describe('Deposit dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) + const borrowPage = new BorrowPageObject(testContext) // to simulate a position with only deposits, we go through the easy borrow flow // but interrupt it before the borrow action, going directly to the myPortfolio // this way we have deposit transactions executed, but no borrow transaction @@ -334,43 +277,40 @@ test.describe('Deposit dialog', () => { await borrowPage.fillDepositAssetAction(1, 'rETH', initialDeposits.rETH) await borrowPage.submitAction() - const actionsContainer = new ActionsPageObject(page) for (let i = 0; i < 4; i++) { - await actionsContainer.acceptActionAtIndex(i) + await borrowPage.actionsContainer.acceptActionAtIndex(i) } - await actionsContainer.expectEnabledActionAtIndex(4) + await borrowPage.actionsContainer.expectEnabledActionAtIndex(4) - const myPortfolioPage = new MyPortfolioPageObject(page) + myPortfolioPage = new MyPortfolioPageObject(testContext) await myPortfolioPage.goToMyPortfolioAction() + + depositDialog = new DialogPageObject({ + testContext, + header: headerRegExp, + }) }) - test('does not display health factor', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('does not display health factor', async () => { await myPortfolioPage.clickDepositButtonAction('rETH') - - const depositDialog = new DialogPageObject(page, headerRegExp) await depositDialog.fillAmountAction(1) await depositDialog.expectHealthFactorNotVisible() - - // @note this is needed for deterministic screenshots - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectEnabledActionAtIndex(0) - - await screenshot(depositDialog.getDialog(), 'deposit-dialog-only-deposit-health-factor') }) }) test.describe('No position', () => { - const fork = setupFork({ blockNumber: 19588510n, chainId: mainnet.id }) // block number with WBTC supply close to cap - test('can deposit up to max cap', async ({ page }) => { const initialBalances = { ETH: 1, - WBTC: 1000, + cbBTC: 52, } - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'myPortfolio', account: { type: 'connected-random', @@ -378,31 +318,30 @@ test.describe('Deposit dialog', () => { }, }) - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickDepositButtonAction('WBTC') + const myPortfolioPage = new MyPortfolioPageObject(testContext) + await myPortfolioPage.clickDepositButtonAction('cbBTC') - const depositDialog = new DialogPageObject(page, headerRegExp) + const depositDialog = new DialogPageObject({ + testContext, + header: headerRegExp, + }) await depositDialog.clickMaxAmountAction() - await tenderlyRpcActions.evmIncreaseTime(fork.forkUrl, 5 * 60) + await testContext.testnetController.progressSimulationAndMine(5 * 60) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await depositDialog.expectSuccessPage( - [ + await depositDialog.actionsContainer.acceptAllActionsAction(2) + await depositDialog.expectSuccessPage({ + tokenWithValue: [ { - asset: 'WBTC', - amount: 507.527307, + asset: 'cbBTC', + amount: '50.0464443', + usdValue: '$5,088,872.59', }, ], - fork, - { - WBTC: 34_087_363.63, - }, - ) + }) await depositDialog.viewInMyPortfolioAction() await myPortfolioPage.expectDepositTable({ - WBTC: 507.527307, + cbBTC: 50.0464443, }) }) @@ -412,7 +351,11 @@ test.describe('Deposit dialog', () => { USDT: 10000, } - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'myPortfolio', account: { type: 'connected-random', @@ -420,23 +363,25 @@ test.describe('Deposit dialog', () => { }, }) - const myPortfolioPage = new MyPortfolioPageObject(page) + const myPortfolioPage = new MyPortfolioPageObject(testContext) await myPortfolioPage.clickDepositButtonAction('USDT') - const depositDialog = new DialogPageObject(page, headerRegExp) + const depositDialog = new DialogPageObject({ + testContext, + header: headerRegExp, + }) await depositDialog.fillAmountAction(initialBalances.USDT) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await depositDialog.expectSuccessPage( - [ + await depositDialog.actionsContainer.acceptAllActionsAction(2) + await depositDialog.expectSuccessPage({ + tokenWithValue: [ { asset: 'USDT', - amount: initialBalances.USDT, + amount: '10,000.00', + usdValue: '$10,000.00', }, ], - fork, - ) + }) await depositDialog.viewInMyPortfolioAction() await myPortfolioPage.expectDepositTable({ @@ -445,7 +390,11 @@ test.describe('Deposit dialog', () => { }) test('retains some native asset when depositing max', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'myPortfolio', account: { type: 'connected-random', @@ -453,9 +402,12 @@ test.describe('Deposit dialog', () => { }, }) - const myPortfolioPage = new MyPortfolioPageObject(page) + const myPortfolioPage = new MyPortfolioPageObject(testContext) await myPortfolioPage.clickDepositButtonAction('WETH') - const depositDialog = new DialogPageObject(page, headerRegExp) + const depositDialog = new DialogPageObject({ + testContext, + header: headerRegExp, + }) await depositDialog.selectAssetAction('ETH') await depositDialog.clickMaxAmountAction() diff --git a/packages/app/src/features/dialogs/deposit/logic/form.ts b/packages/app/src/features/dialogs/deposit/logic/form.ts index b638a61b4..782c6d845 100644 --- a/packages/app/src/features/dialogs/deposit/logic/form.ts +++ b/packages/app/src/features/dialogs/deposit/logic/form.ts @@ -49,6 +49,7 @@ export function getFormFieldsForDepositDialog({ const changeAsset = (newSymbol: TokenSymbol): void => { form.setValue('symbol', newSymbol) form.setValue('value', '') + form.setValue('isMaxSelected', false) form.clearErrors() } diff --git a/packages/app/src/features/dialogs/e-mode/EModeDialog.PageObject.ts b/packages/app/src/features/dialogs/e-mode/EModeDialog.PageObject.ts index 02530e113..6172dacc2 100644 --- a/packages/app/src/features/dialogs/e-mode/EModeDialog.PageObject.ts +++ b/packages/app/src/features/dialogs/e-mode/EModeDialog.PageObject.ts @@ -1,12 +1,15 @@ import { EModeCategoryName } from '@/domain/e-mode/types' +import { TestContext } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' -import { Locator, Page, expect } from '@playwright/test' +import { Locator, expect } from '@playwright/test' import { DialogPageObject } from '../common/Dialog.PageObject' export class EModeDialogPageObject extends DialogPageObject { - constructor(page: Page) { - super(page, /.*/) - this.region = this.locateDialogByHeader('Set E-Mode Category') + constructor(testContext: TestContext) { + super({ + testContext, + header: /Set E-Mode Category/, + }) } // #region locators diff --git a/packages/app/src/features/dialogs/e-mode/EModeDialog.test-e2e.ts b/packages/app/src/features/dialogs/e-mode/EModeDialog.test-e2e.ts index 224edd3ff..c4734d2cc 100644 --- a/packages/app/src/features/dialogs/e-mode/EModeDialog.test-e2e.ts +++ b/packages/app/src/features/dialogs/e-mode/EModeDialog.test-e2e.ts @@ -2,7 +2,6 @@ import { setUserEModeValidationIssueToMessage } from '@/domain/market-validators import { BorrowPageObject } from '@/pages/Borrow.PageObject' import { MyPortfolioPageObject } from '@/pages/MyPortfolio.PageObject' import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' @@ -10,15 +9,17 @@ import { DialogPageObject } from '../common/Dialog.PageObject' import { EModeDialogPageObject } from './EModeDialog.PageObject' test.describe('E-Mode dialog', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) - test.describe('ETH correlated assets borrowed', () => { let eModeDialog: EModeDialogPageObject let borrowDialog: DialogPageObject let myPortfolioPage: MyPortfolioPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -26,12 +27,15 @@ test.describe('E-Mode dialog', () => { }, }) - eModeDialog = new EModeDialogPageObject(page) - borrowDialog = new DialogPageObject(page, /Borrow/) - myPortfolioPage = new MyPortfolioPageObject(page) + eModeDialog = new EModeDialogPageObject(testContext) + borrowDialog = new DialogPageObject({ + testContext, + header: /Borrow/, + }) + myPortfolioPage = new MyPortfolioPageObject(testContext) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ wstETH: 20 }) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: { wstETH: 20 } }) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.clickBorrowButtonAction('rETH') @@ -53,8 +57,8 @@ test.describe('E-Mode dialog', () => { availableAssets: { assets: 'All assets', }, - hf: '1.75', - maxLtv: '68.50%', + hf: '1.79', + maxLtv: '79.00%', }) await eModeDialog.clickEModeCategoryTileAction('ETH Correlated') @@ -66,12 +70,12 @@ test.describe('E-Mode dialog', () => { assets: 'WETH, wstETH, rETH', }, hf: { - before: '1.75', - after: '2.05', + before: '1.79', + after: '2.08', }, maxLtv: { - before: '68.50%', - after: '90.00%', + before: '79.00%', + after: '92.00%', }, }) @@ -106,12 +110,12 @@ test.describe('E-Mode dialog', () => { assets: 'All assets', }, hf: { - before: '2.05', - after: '1.75', + before: '2.08', + after: '1.79', }, maxLtv: { - before: '90.00%', - after: '68.50%', + before: '92.00%', + after: '79.00%', }, }) await eModeDialog.actionsContainer.acceptAllActionsAction(1) @@ -144,7 +148,11 @@ test.describe('E-Mode dialog', () => { let myPortfolioPage: MyPortfolioPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -152,12 +160,15 @@ test.describe('E-Mode dialog', () => { }, }) - eModeDialog = new EModeDialogPageObject(page) - borrowDialog = new DialogPageObject(page, /Borrow/) - myPortfolioPage = new MyPortfolioPageObject(page) + eModeDialog = new EModeDialogPageObject(testContext) + borrowDialog = new DialogPageObject({ + testContext, + header: /Borrow/, + }) + myPortfolioPage = new MyPortfolioPageObject(testContext) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ wstETH: 1 }) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: { wstETH: 1 } }) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.clickBorrowButtonAction('USDC') @@ -175,8 +186,8 @@ test.describe('E-Mode dialog', () => { availableAssets: { assets: 'All assets', }, - hf: '2.08', - maxLtv: '68.50%', + hf: '3.73', + maxLtv: '79.00%', }) await eModeDialog.clickEModeCategoryTileAction('Stablecoins') @@ -188,12 +199,12 @@ test.describe('E-Mode dialog', () => { assets: 'sDAI, USDC, USDT', }, hf: { - before: '2.08', - after: '2.08', + before: '3.73', + after: '3.73', }, maxLtv: { - before: '68.50%', - after: '68.50%', + before: '79.00%', + after: '79.00%', }, }) @@ -228,12 +239,12 @@ test.describe('E-Mode dialog', () => { assets: 'All assets', }, hf: { - before: '2.08', - after: '2.08', + before: '3.73', + after: '3.73', }, maxLtv: { - before: '68.50%', - after: '68.50%', + before: '79.00%', + after: '79.00%', }, }) await eModeDialog.actionsContainer.acceptAllActionsAction(1) @@ -249,7 +260,11 @@ test.describe('E-Mode dialog', () => { let myPortfolioPage: MyPortfolioPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -257,12 +272,15 @@ test.describe('E-Mode dialog', () => { }, }) - eModeDialog = new EModeDialogPageObject(page) - borrowDialog = new DialogPageObject(page, /Borrow/) - myPortfolioPage = new MyPortfolioPageObject(page) + eModeDialog = new EModeDialogPageObject(testContext) + borrowDialog = new DialogPageObject({ + testContext, + header: /Borrow/, + }) + myPortfolioPage = new MyPortfolioPageObject(testContext) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ wstETH: 10 }) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: { wstETH: 10 } }) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.clickBorrowButtonAction('rETH') @@ -270,7 +288,7 @@ test.describe('E-Mode dialog', () => { await borrowDialog.actionsContainer.acceptAllActionsAction(1) await borrowDialog.viewInMyPortfolioAction() - await myPortfolioPage.clickBorrowButtonAction('WBTC') + await myPortfolioPage.clickBorrowButtonAction('cbBTC') await borrowDialog.fillAmountAction(0.1) await borrowDialog.actionsContainer.acceptAllActionsAction(1) await borrowDialog.viewInMyPortfolioAction() @@ -293,12 +311,12 @@ test.describe('E-Mode dialog', () => { assets: 'sDAI, USDC, USDT', }, hf: { - before: '3.12', - after: '3.12', + before: '2.56', + after: '2.56', }, maxLtv: { - before: '68.50%', - after: '68.50%', + before: '79.00%', + after: '79.00%', }, }) await eModeDialog.actionsContainer.expectDisabledActions([{ type: 'setUserEMode', eModeCategoryId: 2 }]) @@ -317,12 +335,12 @@ test.describe('E-Mode dialog', () => { assets: 'WETH, wstETH, rETH', }, hf: { - before: '3.12', - after: '3.65', + before: '2.56', + after: '2.98', }, maxLtv: { - before: '68.50%', - after: '90.00%', + before: '79.00%', + after: '92.00%', }, }) await eModeDialog.expectAlertMessage( @@ -337,7 +355,11 @@ test.describe('E-Mode dialog', () => { let myPortfolioPage: MyPortfolioPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -345,11 +367,11 @@ test.describe('E-Mode dialog', () => { }, }) - eModeDialog = new EModeDialogPageObject(page) - myPortfolioPage = new MyPortfolioPageObject(page) + eModeDialog = new EModeDialogPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ wstETH: 20 }) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: { wstETH: 20 } }) await myPortfolioPage.goToMyPortfolioAction() }) @@ -367,8 +389,8 @@ test.describe('E-Mode dialog', () => { assets: 'WETH, wstETH, rETH', }, maxLtv: { - before: '68.50%', - after: '90.00%', + before: '79.00%', + after: '92.00%', }, }) @@ -392,8 +414,8 @@ test.describe('E-Mode dialog', () => { assets: 'sDAI, USDC, USDT', }, maxLtv: { - before: '68.50%', - after: '68.50%', + before: '79.00%', + after: '79.00%', }, }) @@ -419,8 +441,8 @@ test.describe('E-Mode dialog', () => { assets: 'All assets', }, maxLtv: { - before: '68.50%', - after: '68.50%', + before: '79.00%', + after: '79.00%', }, }) await eModeDialog.actionsContainer.acceptAllActionsAction(1) @@ -436,7 +458,11 @@ test.describe('E-Mode dialog', () => { let myPortfolioPage: MyPortfolioPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -444,19 +470,24 @@ test.describe('E-Mode dialog', () => { }, }) - eModeDialog = new EModeDialogPageObject(page) - myPortfolioPage = new MyPortfolioPageObject(page) + eModeDialog = new EModeDialogPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ rETH: 2, wstETH: 10 }) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: { rETH: 2, wstETH: 10 } }) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.clickBorrowButtonAction('WETH') - const borrowDialog = new DialogPageObject(page, /Borrow/) + const borrowDialog = new DialogPageObject({ + testContext, + header: /Borrow/, + }) await borrowDialog.fillAmountAction(8) await borrowDialog.clickAcknowledgeRisk() await borrowDialog.actionsContainer.acceptAllActionsAction(1) - await borrowDialog.expectSuccessPage([{ asset: 'WETH', amount: 8 }], fork) + await borrowDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'WETH', amount: '8.00', usdValue: '$31,426.51' }], + }) await borrowDialog.viewInMyPortfolioAction() await myPortfolioPage.expectAssetToBeInBorrowTable('WETH') @@ -498,7 +529,11 @@ test.describe('E-Mode dialog', () => { let myPortfolioPage: MyPortfolioPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -506,18 +541,23 @@ test.describe('E-Mode dialog', () => { }, }) - eModeDialog = new EModeDialogPageObject(page) - myPortfolioPage = new MyPortfolioPageObject(page) + eModeDialog = new EModeDialogPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ rETH: 2, wstETH: 10 }) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: { rETH: 2, wstETH: 10 } }) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.clickBorrowButtonAction('WETH') - const borrowDialog = new DialogPageObject(page, /Borrow/) + const borrowDialog = new DialogPageObject({ + testContext, + header: /Borrow/, + }) await borrowDialog.fillAmountAction(2) await borrowDialog.actionsContainer.acceptAllActionsAction(1) - await borrowDialog.expectSuccessPage([{ asset: 'WETH', amount: 2 }], fork) + await borrowDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'WETH', amount: '2.00', usdValue: '$7,856.63' }], + }) await borrowDialog.viewInMyPortfolioAction() await myPortfolioPage.expectAssetToBeInBorrowTable('WETH') }) diff --git a/packages/app/src/features/dialogs/repay/RepayDialog.test-e2e.ts b/packages/app/src/features/dialogs/repay/RepayDialog.test-e2e.ts index 9593c7ec7..a77a3c983 100644 --- a/packages/app/src/features/dialogs/repay/RepayDialog.test-e2e.ts +++ b/packages/app/src/features/dialogs/repay/RepayDialog.test-e2e.ts @@ -1,33 +1,23 @@ -import { Page, test } from '@playwright/test' -import { mainnet } from 'viem/chains' - import { repayValidationIssueToMessage } from '@/domain/market-validators/validateRepay' -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { BorrowPageObject } from '@/pages/Borrow.PageObject' import { MyPortfolioPageObject } from '@/pages/MyPortfolio.PageObject' -import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' -import { setup } from '@/test/e2e/setup' -import { screenshot } from '@/test/e2e/utils' - -import { tenderlyRpcActions } from '@/domain/tenderly/TenderlyRpcActions' -import { injectFixedDate } from '@/test/e2e/injectSetup' -import { BaseUnitNumber, NormalizedUnitNumber } from '@marsfoundation/common-universal' -import { http, Address, createPublicClient } from 'viem' +import { DEFAULT_BLOCK_NUMBER, TOKENS_ON_FORK } from '@/test/e2e/constants' +import { TestContext, setup } from '@/test/e2e/setup' +import { BaseUnitNumber, NormalizedUnitNumber, toBigInt } from '@marsfoundation/common-universal' +import { test } from '@playwright/test' +import { mainnet } from 'viem/chains' import { DialogPageObject } from '../common/Dialog.PageObject' const headerRegExp = /Repa*/ test.describe('Repay dialog', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) const initialBalances = { wstETH: 100, rETH: 100, WETH: 100, - DAI: 10000, + ETH: 100, + DAI: 100000, } - const expectedInitialHealthFactor = '5.65' - const expectedHealthFactor = '5.82' test.describe('Position with borrowed DAI', () => { const initialDeposits = { @@ -35,8 +25,16 @@ test.describe('Repay dialog', () => { } as const const daiToBorrow = 3500 + let testContext: TestContext<'connected-random'> + let repayDialog: DialogPageObject + let myPortfolioPage: MyPortfolioPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -44,114 +42,72 @@ test.describe('Repay dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositAssetsActions(initialDeposits, daiToBorrow) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositAssetsActions({ assetsToDeposit: initialDeposits, daiToBorrow }) await borrowPage.viewInMyPortfolioAction() - - const myPortfolioPage = new MyPortfolioPageObject(page) - // @todo This waits for the refetch of the data after successful borrow transaction to happen. - // This is no ideal, probably we need to refactor expectDepositTable so it takes advantage from - // playwright's timeouts instead of parsing it's current state. Then we would be able to - // easily wait for the table to be updated. + repayDialog = new DialogPageObject({ testContext, header: headerRegExp }) + myPortfolioPage = new MyPortfolioPageObject(testContext) await myPortfolioPage.expectAssetToBeInDepositTable('DAI') }) - test('opens dialog with selected asset', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('opens dialog with selected asset', async () => { await myPortfolioPage.clickRepayButtonAction('DAI') - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.expectSelectedAsset('DAI') await repayDialog.expectDialogHeader('Repay DAI') await repayDialog.expectHealthFactorBeforeVisible() - - await screenshot(repayDialog.getDialog(), 'repay-dialog-default-view') }) - test('calculates health factor changes correctly when repaying part', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('calculates health factor changes correctly when repaying part', async () => { await myPortfolioPage.clickRepayButtonAction('DAI') - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.fillAmountAction(100) - await repayDialog.expectRiskLevelBefore('Healthy') - await repayDialog.expectHealthFactorBefore(expectedInitialHealthFactor) + await repayDialog.expectHealthFactorBefore('10.09') await repayDialog.expectRiskLevelAfter('Healthy') - await repayDialog.expectHealthFactorAfter(expectedHealthFactor) - - // @note this is needed for deterministic screenshots - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectEnabledActionAtIndex(0) - - await screenshot(repayDialog.getDialog(), 'repay-dialog-health-factor-partial-repay') + await repayDialog.expectHealthFactorAfter('10.38') }) - test('calculates health factor changes correctly when repaying all', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('calculates health factor changes correctly when repaying all', async () => { await myPortfolioPage.clickRepayButtonAction('DAI') - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.clickMaxAmountAction() - await repayDialog.expectRiskLevelBefore('Healthy') - await repayDialog.expectHealthFactorBefore(expectedInitialHealthFactor) + await repayDialog.expectHealthFactorBefore('10.09') await repayDialog.expectRiskLevelAfter('No debt') await repayDialog.expectHealthFactorAfter(String.fromCharCode(0x221e)) - - // @note this is needed for deterministic screenshots - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectEnabledActionAtIndex(0) - - await screenshot(repayDialog.getDialog(), 'repay-dialog-health-factor-full-repay') }) - test('after repay, health factor matches myPortfolio', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('after repay, health factor matches myPortfolio', async () => { await myPortfolioPage.clickRepayButtonAction('DAI') - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.fillAmountAction(100) - - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - + await repayDialog.actionsContainer.acceptAllActionsAction(2) await repayDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectHealthFactor(expectedHealthFactor) + await myPortfolioPage.expectHealthFactor('10.38') }) - test('has correct action plan for DAI', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) - + test('has correct action plan for DAI', async () => { await myPortfolioPage.clickRepayButtonAction('DAI') - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.fillAmountAction(100) - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectActions([ + await repayDialog.actionsContainer.expectActions([ { type: 'approve', asset: 'DAI' }, { type: 'repay', asset: 'DAI' }, ]) }) - test('can repay DAI', async ({ page }) => { + test('can repay DAI', async () => { const repay = { asset: 'DAI', amount: 100, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickRepayButtonAction(repay.asset) - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.fillAmountAction(repay.amount) - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await repayDialog.expectSuccessPage([repay], fork) - - await screenshot(repayDialog.getDialog(), 'repay-dialog-dai-success') - + await repayDialog.actionsContainer.acceptAllActionsAction(2) + await repayDialog.expectSuccessPage({ tokenWithValue: [{ asset: 'DAI', amount: '100.00', usdValue: '$100.00' }] }) await repayDialog.viewInMyPortfolioAction() await myPortfolioPage.expectBorrowTable({ @@ -159,24 +115,19 @@ test.describe('Repay dialog', () => { }) }) - test('can fully repay DAI', async ({ page }) => { + test('can fully repay DAI', async () => { const repay = { asset: 'DAI', amount: 3500, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickRepayButtonAction(repay.asset) - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.clickMaxAmountAction() - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await repayDialog.expectSuccessPage([repay], fork) - - await screenshot(repayDialog.getDialog(), 'repay-dialog-dai-success') - + await repayDialog.actionsContainer.acceptAllActionsAction(2) + await repayDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'DAI', amount: '3,500.00', usdValue: '$3,500.00' }], + }) await repayDialog.viewInMyPortfolioAction() await myPortfolioPage.expectBorrowTable({ @@ -184,83 +135,62 @@ test.describe('Repay dialog', () => { }) }) - // @todo: doesn't work properly because of fixed date or something - test.skip('exact approvals are not required when repaying all', async ({ page }) => { + test('exact approvals are not required when repaying all', async ({ page }) => { const repay = { asset: 'DAI', amount: 3500, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickRepayButtonAction(repay.asset) - - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.clickMaxAmountAction() - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - // (1) first approval with extra buffer - await actionsContainer.acceptActionAtIndex(0) - await actionsContainer.expectEnabledActionAtIndex(1) + await repayDialog.actionsContainer.acceptActionAtIndex(0) + await repayDialog.actionsContainer.expectEnabledActionAtIndex(1) await page.reload() await myPortfolioPage.clickRepayButtonAction(repay.asset) await repayDialog.clickMaxAmountAction() + await repayDialog.actionsContainer.acceptActionAtIndex(1) - // exact amount of debt slightly increased but approval (1) has a buffer so it should be enough - // this should be rewrite to assert whole action plan and then accept - // await actionsContainer.acceptActionAtIndex(1, { type: 'repay', asset: repay.asset }) - // await actionsContainer.acceptNextActionAction() - - await repayDialog.expectSuccessPage([repay], fork) + await repayDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'DAI', amount: '3,500.00', usdValue: '$3,500.00' }], + }) }) }) test.describe('Position when borrowed asset was not in user wallet before', () => { - const DAI_ADDRESS = '0x6B175474E89094C44Da98b954EedeAC495271d0F' - const DAI_DECIMALS = 18 - const initialDeposits = { wstETH: 10, } as const const daiToBorrow = 10_000 - const daiDebtIncreaseIn1Epoch = 1.0000029476774694 // hardcoded for DAI borrow rate 5.53% - const daiDebtIncreaseIn2Epochs = 1.0000058953636277 // hardcoded for DAI borrow rate 5.53% + const daiDebtIncreaseIn1Epoch = 1.0000067529 // hardcoded for DAI borrow rate 12.55% + const daiDebtIncreaseIn2Epochs = 1.000013502 // hardcoded for DAI borrow rate 12.55% - let account: Address let myPortfolioPage: MyPortfolioPageObject let repayDialog: DialogPageObject - - async function overrideDaiBalance({ balance, page }: { balance: BaseUnitNumber; page: Page }): Promise { - await tenderlyRpcActions.setTokenBalance(fork.forkUrl, DAI_ADDRESS, account, balance) - await page.reload() - } + let testContext: TestContext<'connected-random'> test.beforeEach(async ({ page }) => { - ;({ account } = await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', assetBalances: { wstETH: 10 }, }, - })) + }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositAssetsActions(initialDeposits, daiToBorrow) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositAssetsActions({ assetsToDeposit: initialDeposits, daiToBorrow }) await borrowPage.viewInMyPortfolioAction() - myPortfolioPage = new MyPortfolioPageObject(page) - repayDialog = new DialogPageObject(page, headerRegExp) + myPortfolioPage = new MyPortfolioPageObject(testContext) + repayDialog = new DialogPageObject({ testContext, header: headerRegExp }) - await myPortfolioPage.expectHealthFactor('2.08') - - // forcefully set browser time to the timestamp of borrow transaction - const publicClient = createPublicClient({ - transport: http(fork.forkUrl), - }) - const block = await publicClient.getBlock() - await injectFixedDate(page, new Date(Number(block.timestamp) * 1000)) - await page.reload() + await myPortfolioPage.expectHealthFactor('3.73') }) test('can repay if balance is less than debt', async ({ page }) => { @@ -271,17 +201,18 @@ test.describe('Repay dialog', () => { } as const await overrideDaiBalance({ - balance: BaseUnitNumber(NormalizedUnitNumber(newBalance).shiftedBy(DAI_DECIMALS)), - page, + balance: NormalizedUnitNumber(newBalance), + testContext, }) + await page.reload() await myPortfolioPage.clickRepayButtonAction(repay.asset) await repayDialog.clickMaxAmountAction() - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await repayDialog.expectSuccessPage([repay], fork) - + await repayDialog.actionsContainer.acceptAllActionsAction(2) + await repayDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'DAI', amount: '9,000.00', usdValue: '$9,000.00' }], + }) await repayDialog.viewInMyPortfolioAction() await myPortfolioPage.expectNonZeroAmountInBorrowTable(repay.asset) @@ -296,29 +227,28 @@ test.describe('Repay dialog', () => { asset: 'DAI', amount: daiToBorrow, } as const - const daiDebtIn1Epoch = NormalizedUnitNumber(daiToBorrow).times(daiDebtIncreaseIn1Epoch) // newBalance = (daiToBorrow, daiDebtIn1Epoch) / 2 - a number somewhere between daiToBorrow and daiDebtIn1Epoch - const newBalance = BaseUnitNumber(daiDebtIn1Epoch.plus(daiToBorrow).div(2).shiftedBy(DAI_DECIMALS)) + const newBalance = NormalizedUnitNumber(daiDebtIn1Epoch.plus(daiToBorrow).div(2)) await overrideDaiBalance({ balance: newBalance, - page, + testContext, }) + await page.reload() await myPortfolioPage.clickRepayButtonAction(repay.asset) await repayDialog.clickMaxAmountAction() - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await repayDialog.expectSuccessPage( - [ + await repayDialog.actionsContainer.acceptAllActionsAction(2) + await repayDialog.expectSuccessPage({ + tokenWithValue: [ { - asset: repay.asset, - amount: daiToBorrow, + asset: 'DAI', + amount: '10,000.00', + usdValue: '$10,000.00', }, ], - fork, - ) + }) await repayDialog.viewInMyPortfolioAction() @@ -334,27 +264,26 @@ test.describe('Repay dialog', () => { const daiDebtIn1Epoch = NormalizedUnitNumber(daiToBorrow).times(daiDebtIncreaseIn1Epoch) const daiDebtIn2Epochs = NormalizedUnitNumber(daiToBorrow).times(daiDebtIncreaseIn2Epochs) // newBalance = (daiDebtIn1Epoch + daiDebtIn2Epochs) / 2 - a number somewhere between daiDebtIn1Epoch and daiDebtIn2Epochs - const newBalance = BaseUnitNumber(daiDebtIn2Epochs.plus(daiDebtIn1Epoch).div(2).shiftedBy(DAI_DECIMALS)) + const newBalance = NormalizedUnitNumber(daiDebtIn2Epochs.plus(daiDebtIn1Epoch).div(2)) await overrideDaiBalance({ balance: newBalance, - page, + testContext, }) + await page.reload() await myPortfolioPage.clickRepayButtonAction(repay.asset) - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.clickMaxAmountAction() - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await repayDialog.expectSuccessPage( - [ + await repayDialog.actionsContainer.acceptAllActionsAction(2) + await repayDialog.expectSuccessPage({ + tokenWithValue: [ { - asset: repay.asset, - amount: daiToBorrow, + asset: 'DAI', + amount: '10,000.00', + usdValue: '$10,000.00', }, ], - fork, - ) + }) await repayDialog.viewInMyPortfolioAction() @@ -379,8 +308,16 @@ test.describe('Repay dialog', () => { amount: 10, } + let testContext: TestContext<'connected-random'> + let repayDialog: DialogPageObject + let myPortfolioPage: MyPortfolioPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -388,143 +325,129 @@ test.describe('Repay dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions(initialDeposits) // deposit whole wallet balance - const myPortfolioPage = new MyPortfolioPageObject(page) + const borrowPage = new BorrowPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + repayDialog = new DialogPageObject({ testContext, header: headerRegExp }) + + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: initialDeposits }) // deposit whole wallet balance await myPortfolioPage.goToMyPortfolioAction() // borrow wstETH and WETH - const borrowDialog = new DialogPageObject(page, /Borrow */) - const borrowActionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) + const borrowDialog = new DialogPageObject({ testContext, header: /Borrow */ }) // borrow wstETH await myPortfolioPage.clickBorrowButtonAction(wstETHBorrow.asset) await borrowDialog.fillAmountAction(wstETHBorrow.amount) - await borrowActionsContainer.acceptAllActionsAction(1) + await borrowDialog.actionsContainer.acceptAllActionsAction(1) await borrowDialog.viewInMyPortfolioAction() // borrow WETH await myPortfolioPage.clickBorrowButtonAction(WETHBorrow.asset) await borrowDialog.fillAmountAction(WETHBorrow.amount) - await borrowActionsContainer.acceptAllActionsAction(1) + await borrowDialog.actionsContainer.acceptAllActionsAction(1) await borrowDialog.viewInMyPortfolioAction() }) - test('can change asset to aToken', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('can change asset to aToken', async () => { await myPortfolioPage.clickRepayButtonAction('wstETH') - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.selectAssetAction('awstETH') await repayDialog.expectSelectedAsset('awstETH') await repayDialog.expectDialogHeader('Repay wstETH') await repayDialog.expectHealthFactorBeforeVisible() }) - test('has correct action plan for repaying erc-20 using aToken', async ({ page }) => { + test('has correct action plan for repaying erc-20 using aToken', async () => { const repay = { asset: 'awstETH', amount: 5, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.clickRepayButtonAction('wstETH') - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.selectAssetAction(repay.asset) await repayDialog.fillAmountAction(repay.amount) - - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectActions([{ type: 'repay', asset: repay.asset }]) - - await screenshot(repayDialog.getDialog(), 'repay-dialog-erc20-atoken-action-plan') + await repayDialog.actionsContainer.expectActions([{ type: 'repay', asset: repay.asset }]) }) - test('can repay erc-20 using aToken', async ({ page }) => { + test('can repay erc-20 using aToken', async () => { const repay = { asset: 'awstETH', amount: 5, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.clickRepayButtonAction('wstETH') - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.selectAssetAction(repay.asset) await repayDialog.fillAmountAction(repay.amount) + await repayDialog.actionsContainer.acceptAllActionsAction(1) + await repayDialog.viewInMyPortfolioAction() - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) + await myPortfolioPage.expectBorrowTable({ + wstETH: wstETHBorrow.amount - repay.amount, + }) + }) - await screenshot(repayDialog.getDialog(), 'repay-dialog-erc20-atoken-success') + test('can repay debt using native asset', async () => { + const repay = { + asset: 'ETH', + amount: 1, + } as const + + await myPortfolioPage.clickRepayButtonAction('WETH') + await repayDialog.selectAssetAction(repay.asset) + await repayDialog.fillAmountAction(repay.amount) + await repayDialog.actionsContainer.acceptAllActionsAction(1) await repayDialog.viewInMyPortfolioAction() await myPortfolioPage.expectBorrowTable({ - wstETH: wstETHBorrow.amount - repay.amount, + WETH: WETHBorrow.amount - repay.amount, }) }) - test('has correct action plan for erc-20 repay with permits', async ({ page }) => { + test('has correct action plan for erc-20 repay with permits', async () => { const repay = { asset: 'wstETH', amount: 5, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickRepayButtonAction(repay.asset) - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.fillAmountAction(repay.amount) - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectActions([ + await repayDialog.actionsContainer.expectActions([ { type: 'permit', asset: repay.asset }, { type: 'repay', asset: repay.asset }, ]) - - await screenshot(repayDialog.getDialog(), 'repay-dialog-erc20-permit-action-plan') }) - test('has correct action plan for erc-20 repay with approves', async ({ page }) => { + test('has correct action plan for erc-20 repay with approves', async () => { const repay = { asset: 'wstETH', amount: 5, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickRepayButtonAction(repay.asset) - const repayDialog = new DialogPageObject(page, headerRegExp) - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.switchPreferPermitsAction() - + await repayDialog.actionsContainer.switchPreferPermitsAction() await repayDialog.fillAmountAction(repay.amount) - await actionsContainer.expectActions([ + await repayDialog.actionsContainer.expectActions([ { type: 'approve', asset: repay.asset }, { type: 'repay', asset: repay.asset }, ]) - - await screenshot(repayDialog.getDialog(), 'repay-dialog-erc20-approve-action-plan') }) - test('can repay erc-20 using permits', async ({ page }) => { + test('can repay erc-20 using permits', async () => { const repay = { asset: 'wstETH', amount: 5, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickRepayButtonAction(repay.asset) - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.fillAmountAction(repay.amount) - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await repayDialog.expectSuccessPage([repay], fork) - - await screenshot(repayDialog.getDialog(), 'repay-dialog-erc20-success') - + await repayDialog.actionsContainer.acceptAllActionsAction(2) + await repayDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'wstETH', amount: '5.00', usdValue: '$23,327.32' }], + }) await repayDialog.viewInMyPortfolioAction() await myPortfolioPage.expectBorrowTable({ @@ -532,23 +455,20 @@ test.describe('Repay dialog', () => { }) }) - test('can repay erc-20 using approves', async ({ page }) => { + test('can repay erc-20 using approves', async () => { const repay = { asset: 'wstETH', amount: 5, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickRepayButtonAction(repay.asset) - const repayDialog = new DialogPageObject(page, headerRegExp) - const actionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) - await actionsContainer.switchPreferPermitsAction() + await repayDialog.actionsContainer.switchPreferPermitsAction() await repayDialog.fillAmountAction(repay.amount) - await actionsContainer.acceptAllActionsAction(2) - await repayDialog.expectSuccessPage([repay], fork) - + await repayDialog.actionsContainer.acceptAllActionsAction(2) + await repayDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'wstETH', amount: '5.00', usdValue: '$23,327.32' }], + }) await repayDialog.viewInMyPortfolioAction() await myPortfolioPage.expectBorrowTable({ @@ -577,8 +497,16 @@ test.describe('Repay dialog', () => { amount: 10, } + let testContext: TestContext<'connected-random'> + let repayDialog: DialogPageObject + let myPortfolioPage: MyPortfolioPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -586,107 +514,100 @@ test.describe('Repay dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions(initialDeposits) // deposit whole wallet balance - const myPortfolioPage = new MyPortfolioPageObject(page) + const borrowPage = new BorrowPageObject(testContext) + repayDialog = new DialogPageObject({ testContext, header: headerRegExp }) + myPortfolioPage = new MyPortfolioPageObject(testContext) + + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: initialDeposits }) // deposit whole wallet balance await myPortfolioPage.goToMyPortfolioAction() // borrow wstETH and WETH - const borrowDialog = new DialogPageObject(page, /Borrow */) - const borrowActionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) + const borrowDialog = new DialogPageObject({ testContext, header: /Borrow */ }) // borrow wstETH await myPortfolioPage.clickBorrowButtonAction(wstETHBorrow.asset) await borrowDialog.fillAmountAction(wstETHBorrow.amount) - await borrowActionsContainer.acceptAllActionsAction(1) + await borrowDialog.actionsContainer.acceptAllActionsAction(1) await borrowDialog.viewInMyPortfolioAction() // borrow WETH await myPortfolioPage.clickBorrowButtonAction(WETHBorrow.asset) await borrowDialog.fillAmountAction(WETHBorrow.amount) await borrowDialog.clickAcknowledgeRisk() - await borrowActionsContainer.acceptAllActionsAction(1) + await borrowDialog.actionsContainer.acceptAllActionsAction(1) await borrowDialog.viewInMyPortfolioAction() // deposit wstETH to have balance not enough to later repay debt using wstETH - const depositDialog = new DialogPageObject(page, /Deposit */) - const depositActionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) + const depositDialog = new DialogPageObject({ testContext, header: /Deposit */ }) await myPortfolioPage.clickDepositButtonAction(wstETHDeposit.asset) await depositDialog.fillAmountAction(wstETHDeposit.amount) - await depositActionsContainer.acceptAllActionsAction(2) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.viewInMyPortfolioAction() }) - test('cannot repay repay more than owe', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('cannot repay repay more than owe', async () => { await myPortfolioPage.clickRepayButtonAction(WETHBorrow.asset) - const repayDialog = new DialogPageObject(page, headerRegExp) - await repayDialog.expectHealthFactorBefore('2.03') + await repayDialog.expectHealthFactorBefore('2.05') await repayDialog.fillAmountAction(WETHBorrow.amount + 1) await repayDialog.expectAssetInputError(repayValidationIssueToMessage['exceeds-debt']) - - await screenshot(repayDialog.getDialog(), 'repay-dialog-more-than-owe') }) - test('cannot repay more than wallet balance', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('cannot repay more than wallet balance', async () => { await myPortfolioPage.clickRepayButtonAction(wstETHBorrow.asset) - const repayDialog = new DialogPageObject(page, headerRegExp) - await repayDialog.expectHealthFactorBefore('2.03') + await repayDialog.expectHealthFactorBefore('2.05') await repayDialog.fillAmountAction(1) await repayDialog.expectAssetInputError(repayValidationIssueToMessage['exceeds-balance']) - - await screenshot(repayDialog.getDialog(), 'repay-dialog-more-than-balance') }) }) - // @note Add tests when problem with native asset deposit is solved - test.describe('Position with native token debt', () => {}) - test.describe('Position with only deposit', () => { const initialDeposits = { wstETH: 10, } as const + let testContext: TestContext<'connected-random'> + let repayDialog: DialogPageObject + let myPortfolioPage: MyPortfolioPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', - assetBalances: { ...initialBalances }, + assetBalances: { ...initialBalances, ETH: 0 }, }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions(initialDeposits) - const myPortfolioPage = new MyPortfolioPageObject(page) + const borrowPage = new BorrowPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + repayDialog = new DialogPageObject({ testContext, header: headerRegExp }) + + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: initialDeposits }) await myPortfolioPage.goToMyPortfolioAction() }) - test('nothing to repay', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('nothing to repay', async () => { await myPortfolioPage.expectBorrowedAssetsToBeEmpty() - await screenshot(page, 'repay-dialog-nothing-to-repay') }) - test('when repaying native asset retain some in wallet', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('when repaying native asset retain some in wallet', async () => { await myPortfolioPage.clickBorrowButtonAction('WETH') - const borrowDialog = new DialogPageObject(page, /Borrow */) + const borrowDialog = new DialogPageObject({ testContext, header: /Borrow */ }) await borrowDialog.selectAssetAction('ETH') await borrowDialog.fillAmountAction(5) - const borrowActionsContainer = new ActionsPageObject(borrowDialog.locatePanelByHeader('Actions')) - await borrowActionsContainer.acceptAllActionsAction(2) + await borrowDialog.actionsContainer.acceptAllActionsAction(2) await borrowDialog.viewInMyPortfolioAction() await myPortfolioPage.expectBorrowTable({ WETH: 5 }) await myPortfolioPage.clickRepayButtonAction('WETH') - const repayDialog = new DialogPageObject(page, headerRegExp) await repayDialog.selectAssetAction('ETH') - const repayActionsContainer = new ActionsPageObject(repayDialog.locatePanelByHeader('Actions')) // wait for select to switch to ETH - await repayActionsContainer.expectActions([ + await repayDialog.actionsContainer.expectActions([ { type: 'repay', asset: 'ETH', @@ -698,3 +619,12 @@ test.describe('Repay dialog', () => { }) }) }) + +async function overrideDaiBalance({ + balance, + testContext, +}: { balance: NormalizedUnitNumber; testContext: TestContext<'connected-random'> }): Promise { + const dai = TOKENS_ON_FORK[mainnet.id].DAI + const daiBalance = toBigInt(BaseUnitNumber(balance.shiftedBy(dai.decimals))) + return testContext.testnetController.client.setErc20Balance(dai.address, testContext.account, daiBalance) +} diff --git a/packages/app/src/features/dialogs/savings/common/e2e/SavingsDialog.PageObject.ts b/packages/app/src/features/dialogs/savings/common/e2e/SavingsDialog.PageObject.ts index 83363a605..7d3133fcb 100644 --- a/packages/app/src/features/dialogs/savings/common/e2e/SavingsDialog.PageObject.ts +++ b/packages/app/src/features/dialogs/savings/common/e2e/SavingsDialog.PageObject.ts @@ -1,17 +1,26 @@ +import { TestContext } from '@/test/e2e/setup' import { getBalance, getTokenBalance } from '@/test/e2e/utils' import { testIds } from '@/ui/utils/testIds' -import { Locator, Page, expect } from '@playwright/test' +import { getUrlFromClient } from '@marsfoundation/common-testnets' +import { Locator, expect } from '@playwright/test' import { Address } from 'viem' import { DialogPageObject, TxOverviewWithRoute } from '../../../common/Dialog.PageObject' +export interface SavingsDialogPageObjectParams { + testContext: TestContext + type: 'deposit' | 'withdraw' | 'send' +} + export class SavingsDialogPageObject extends DialogPageObject { private readonly type: 'deposit' | 'withdraw' | 'send' - constructor({ page, type }: { page: Page; type: 'deposit' | 'withdraw' | 'send' }) { - super( - page, - new RegExp(`${type === 'deposit' ? 'Deposit to' : type === 'send' ? 'Send from' : 'Withdraw from'} Savings`), - ) + constructor({ testContext, type }: SavingsDialogPageObjectParams) { + super({ + testContext, + header: new RegExp( + `${type === 'deposit' ? 'Deposit to' : type === 'send' ? 'Send from' : 'Withdraw from'} Savings`, + ), + }) this.type = type } @@ -104,30 +113,33 @@ export class SavingsDialogPageObject extends DialogPageObject { } async expectReceiverBalance({ - forkUrl, receiver, expectedBalance, }: { - forkUrl: string receiver: Address expectedBalance: number }): Promise { - const currentBalance = await getBalance({ forkUrl, address: receiver }) + const currentBalance = await getBalance({ + forkUrl: getUrlFromClient(this.testContext.testnetController.client), + address: receiver, + }) expect(currentBalance.isEqualTo(expectedBalance)).toBe(true) } async expectReceiverTokenBalance({ - forkUrl, receiver, token, expectedBalance, }: { - forkUrl: string receiver: Address token: { address: Address; decimals: number } expectedBalance: number }): Promise { - const currentTokenBalance = await getTokenBalance({ forkUrl, address: receiver, token }) + const currentTokenBalance = await getTokenBalance({ + forkUrl: getUrlFromClient(this.testContext.testnetController.client), + address: receiver, + token, + }) expect(currentTokenBalance.isEqualTo(expectedBalance)).toBe(true) } diff --git a/packages/app/src/features/dialogs/savings/deposit/SavingsDepositDialog.test-e2e.ts b/packages/app/src/features/dialogs/savings/deposit/e2e/General.test-e2e.ts similarity index 59% rename from packages/app/src/features/dialogs/savings/deposit/SavingsDepositDialog.test-e2e.ts rename to packages/app/src/features/dialogs/savings/deposit/e2e/General.test-e2e.ts index 2b57db00a..16be8cfae 100644 --- a/packages/app/src/features/dialogs/savings/deposit/SavingsDepositDialog.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/deposit/e2e/General.test-e2e.ts @@ -1,25 +1,21 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { GNOSIS_DEFAULT_BLOCK_NUMBER, LITE_PSM_ACTIONS_OPERABLE } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { BASE_DEFAULT_BLOCK_NUMBER, DEFAULT_BLOCK_NUMBER, GNOSIS_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { base, gnosis, mainnet } from 'viem/chains' -import { SavingsDialogPageObject } from '../common/e2e/SavingsDialog.PageObject' +import { SavingsDialogPageObject } from '../../common/e2e/SavingsDialog.PageObject' test.describe('Savings deposit dialog', () => { test.describe('Mainnet', () => { - const fork = setupFork({ - blockNumber: LITE_PSM_ACTIONS_OPERABLE, - chainId: mainnet.id, - useTenderlyVnet: true, - }) - let depositDialog: SavingsDialogPageObject let savingsPage: SavingsPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -31,52 +27,63 @@ test.describe('Savings deposit dialog', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickStartSavingButtonAction() - depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) }) test('can switch between tokens', async () => { - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await depositDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ + await depositDialog.actionsContainer.expectEnabledActionAtIndex(0) + await depositDialog.actionsContainer.expectActions([ { type: 'approve', asset: 'DAI' }, - { type: 'depositToSavings', asset: 'DAI', savingsAsset: 'sDAI' }, + { type: 'depositToSavings', asset: 'DAI', savingsAsset: 'sUSDS' }, ]) await depositDialog.selectAssetAction('USDC') await depositDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ + await depositDialog.actionsContainer.expectEnabledActionAtIndex(0) + await depositDialog.actionsContainer.expectActions([ { type: 'approve', asset: 'USDC' }, - { type: 'depositToSavings', asset: 'USDC', savingsAsset: 'sDAI' }, + { type: 'depositToSavings', asset: 'USDC', savingsAsset: 'sUSDS' }, ]) await depositDialog.selectAssetAction('DAI') await depositDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ + await depositDialog.actionsContainer.expectEnabledActionAtIndex(0) + await depositDialog.actionsContainer.expectActions([ { type: 'approve', asset: 'DAI' }, - { type: 'depositToSavings', asset: 'DAI', savingsAsset: 'sDAI' }, + { type: 'depositToSavings', asset: 'DAI', savingsAsset: 'sUSDS' }, ]) }) test('can select only supported assets', async () => { await depositDialog.openAssetSelectorAction() - await depositDialog.expectAssetSelectorOptions(['DAI', 'USDC']) + await depositDialog.expectAssetSelectorOptions(['DAI', 'USDC', 'USDS']) + }) + + test('can click max after switching tokens', async () => { + await depositDialog.expectInputValue('') + await depositDialog.clickMaxAmountAction() + await depositDialog.expectInputValue('10000') + await depositDialog.selectAssetAction('USDC') + await depositDialog.expectInputValue('') + await depositDialog.clickMaxAmountAction() + await depositDialog.expectInputValue('10000') }) }) test.describe('Gnosis', () => { - const fork = setupFork({ blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let depositDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: gnosis.id, + blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -86,10 +93,10 @@ test.describe('Savings deposit dialog', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickStartSavingButtonAction() - depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) }) test('can select only supported assets', async () => { @@ -99,13 +106,15 @@ test.describe('Savings deposit dialog', () => { }) test.describe('Base', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) - let depositDialog: SavingsDialogPageObject let savingsPage: SavingsPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: base.id, + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -116,34 +125,32 @@ test.describe('Savings deposit dialog', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickStartSavingButtonAction() - depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) }) test('can switch between tokens', async () => { - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await depositDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ + await depositDialog.actionsContainer.expectEnabledActionAtIndex(0) + await depositDialog.actionsContainer.expectActions([ { type: 'approve', asset: 'USDS' }, { type: 'depositToSavings', asset: 'USDS', savingsAsset: 'sUSDS' }, ]) await depositDialog.selectAssetAction('USDC') await depositDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ + await depositDialog.actionsContainer.expectEnabledActionAtIndex(0) + await depositDialog.actionsContainer.expectActions([ { type: 'approve', asset: 'USDC' }, { type: 'depositToSavings', asset: 'USDC', savingsAsset: 'sUSDS' }, ]) await depositDialog.selectAssetAction('USDS') await depositDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ + await depositDialog.actionsContainer.expectEnabledActionAtIndex(0) + await depositDialog.actionsContainer.expectActions([ { type: 'approve', asset: 'USDS' }, { type: 'depositToSavings', asset: 'USDS', savingsAsset: 'sUSDS' }, ]) diff --git a/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/Validation.test-e2e.ts b/packages/app/src/features/dialogs/savings/deposit/e2e/Validation.test-e2e.ts similarity index 59% rename from packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/Validation.test-e2e.ts rename to packages/app/src/features/dialogs/savings/deposit/e2e/Validation.test-e2e.ts index 9b68080f1..5e6a00166 100644 --- a/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/Validation.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/deposit/e2e/Validation.test-e2e.ts @@ -1,34 +1,36 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' -import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' -import { depositValidationIssueToMessage } from '../../logic/validation' +import { SavingsDialogPageObject } from '../../common/e2e/SavingsDialog.PageObject' +import { depositValidationIssueToMessage } from '../logic/validation' test.describe('Validation', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) let savingsPage: SavingsPageObject let depositDialog: SavingsDialogPageObject test.describe('Input value exceeds balance', () => { test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', assetBalances: { ETH: 1, - DAI: 100, + USDS: 100, }, }, }) - savingsPage = new SavingsPageObject(page) - await savingsPage.clickDepositButtonAction('DAI') + savingsPage = new SavingsPageObject(testContext) + await savingsPage.clickDepositButtonAction('USDS') - depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) }) @@ -38,48 +40,52 @@ test.describe('Validation', () => { test('actions are disabled', async () => { await depositDialog.actionsContainer.expectDisabledActions([ - { type: 'approve', asset: 'DAI' }, - { type: 'depositToSavings', asset: 'DAI', savingsAsset: 'sDAI' }, + { type: 'approve', asset: 'USDS' }, + { type: 'depositToSavings', asset: 'USDS', savingsAsset: 'sUSDS' }, ]) }) test('displays sensible tx overview', async () => { await depositDialog.expectNativeRouteTransactionOverview({ apy: { - value: '5.00%', - description: 'Earn ~500.00 DAI/year', + value: '12.50%', + description: 'Earn ~1,250.00 USDS/year', }, routeItems: [ { - tokenAmount: '10,000.00 DAI', + tokenAmount: '10,000.00 USDS', tokenUsdValue: '$10,000.00', }, { - tokenAmount: '9,332.66 sDAI', + tokenAmount: '9,830.34 sUSDS', tokenUsdValue: '$10,000.00', }, ], - outcome: '9,332.66 sDAI', + outcome: '9,830.34 sUSDS', outcomeUsd: '$10,000.00', }) }) }) test('displays validation error for dirty input with 0 value', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', assetBalances: { ETH: 1, - DAI: 100, + USDS: 100, }, }, }) - savingsPage = new SavingsPageObject(page) - await savingsPage.clickDepositButtonAction('DAI') - depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + savingsPage = new SavingsPageObject(testContext) + await savingsPage.clickDepositButtonAction('USDS') + depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10) await depositDialog.fillAmountAction(0) diff --git a/packages/app/src/features/dialogs/savings/deposit/e2e/base/DepositUSDC.test-e2e.ts b/packages/app/src/features/dialogs/savings/deposit/e2e/base/DepositUSDC.test-e2e.ts index a9e4461eb..ba97bedf2 100644 --- a/packages/app/src/features/dialogs/savings/deposit/e2e/base/DepositUSDC.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/deposit/e2e/base/DepositUSDC.test-e2e.ts @@ -1,19 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { BASE_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { base } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Deposit USDC', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) - let savingsPage: SavingsPageObject let depositDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: base.id, + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -24,10 +25,10 @@ test.describe('Deposit USDC', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('USDC') - depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) }) @@ -41,8 +42,8 @@ test.describe('Deposit USDC', () => { test('displays transaction overview', async () => { await depositDialog.expectNativeRouteTransactionOverview({ apy: { - value: '6.50%', - description: 'Earn ~650.00 USDS/year', + value: '8.50%', + description: 'Earn ~850.00 USDS/year', }, routeItems: [ { @@ -54,23 +55,25 @@ test.describe('Deposit USDC', () => { tokenUsdValue: '$10,000.00', }, { - tokenAmount: '9,911.77 sUSDS', + tokenAmount: '9,872.98 sUSDS', tokenUsdValue: '$10,000.00', }, ], - outcome: '9,911.77 sUSDS', + outcome: '9,872.98 sUSDS', outcomeUsd: '$10,000.00', }) }) test('executes deposit', async () => { - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.expectSuccessPage() await depositDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,911.77 sUSDS', estimatedUsdsValue: '10,000' }) + await savingsPage.expectSavingsUsdsBalance({ + susdsBalance: '9,872.98 sUSDS', + estimatedUsdsValue: '9,999.999999', // USDC has 6 decimals, so the value is rounded down. This is consistent with the data in the smart contract + }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '-') }) }) diff --git a/packages/app/src/features/dialogs/savings/deposit/e2e/base/DepositUSDS.test-e2e.ts b/packages/app/src/features/dialogs/savings/deposit/e2e/base/DepositUSDS.test-e2e.ts index 2e4952d86..6c5b9f1b7 100644 --- a/packages/app/src/features/dialogs/savings/deposit/e2e/base/DepositUSDS.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/deposit/e2e/base/DepositUSDS.test-e2e.ts @@ -1,18 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { BASE_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { base } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Deposit USDS', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let depositDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: base.id, + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,10 +25,10 @@ test.describe('Deposit USDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('USDS') - depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) }) @@ -40,8 +42,8 @@ test.describe('Deposit USDS', () => { test('displays transaction overview', async () => { await depositDialog.expectNativeRouteTransactionOverview({ apy: { - value: '6.50%', - description: 'Earn ~650.00 USDS/year', + value: '8.50%', + description: 'Earn ~850.00 USDS/year', }, routeItems: [ { @@ -49,11 +51,11 @@ test.describe('Deposit USDS', () => { tokenUsdValue: '$10,000.00', }, { - tokenAmount: '9,911.77 sUSDS', + tokenAmount: '9,872.98 sUSDS', tokenUsdValue: '$10,000.00', }, ], - outcome: '9,911.77 sUSDS', + outcome: '9,872.98 sUSDS', outcomeUsd: '$10,000.00', }) @@ -61,13 +63,12 @@ test.describe('Deposit USDS', () => { }) test('executes deposit', async () => { - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.expectSuccessPage() await depositDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,911.77 sUSDS', estimatedUsdsValue: '10,000' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,872.98 sUSDS', estimatedUsdsValue: '10,000' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '-') }) }) diff --git a/packages/app/src/features/dialogs/savings/deposit/e2e/gnosis/DepositXDAI.test-e2e.ts b/packages/app/src/features/dialogs/savings/deposit/e2e/gnosis/DepositXDAI.test-e2e.ts index 375097842..9ae4949e7 100644 --- a/packages/app/src/features/dialogs/savings/deposit/e2e/gnosis/DepositXDAI.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/deposit/e2e/gnosis/DepositXDAI.test-e2e.ts @@ -1,23 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' import { GNOSIS_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { gnosis } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Deposit XDAI on Gnosis', () => { - const fork = setupFork({ - blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, - chainId: gnosis.id, - useTenderlyVnet: true, - }) let savingsPage: SavingsPageObject let depositDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: gnosis.id, + blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -27,10 +24,10 @@ test.describe('Deposit XDAI on Gnosis', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('XDAI') - depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) }) @@ -62,8 +59,7 @@ test.describe('Deposit XDAI on Gnosis', () => { }) test('executes deposit', async () => { - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1, fork) + await depositDialog.actionsContainer.acceptAllActionsAction(1) await depositDialog.expectSuccessPage() await depositDialog.clickBackToSavingsButton() diff --git a/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositDAI.test-e2e.ts b/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositDAI.test-e2e.ts index ddc8a5aef..2f33df811 100644 --- a/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositDAI.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositDAI.test-e2e.ts @@ -1,19 +1,21 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' -import { setup } from '@/test/e2e/setup' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' +import { TestContext, setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Deposit DAI', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let depositDialog: SavingsDialogPageObject + let testContext: TestContext<'connected-random'> test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -24,10 +26,10 @@ test.describe('Deposit DAI', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('DAI') - depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) }) @@ -42,8 +44,8 @@ test.describe('Deposit DAI', () => { test('displays transaction overview', async () => { await depositDialog.expectNativeRouteTransactionOverview({ apy: { - value: '6.25%', - description: 'Earn ~625.00 USDS/year', + value: '12.50%', + description: 'Earn ~1,250.00 USDS/year', }, routeItems: [ { @@ -55,23 +57,25 @@ test.describe('Deposit DAI', () => { tokenUsdValue: '$10,000.00', }, { - tokenAmount: '9,999.77 sUSDS', + tokenAmount: '9,830.34 sUSDS', tokenUsdValue: '$10,000.00', }, ], - outcome: '9,999.77 sUSDS', + outcome: '9,830.34 sUSDS', outcomeUsd: '$10,000.00', }) }) test('executes deposit', async () => { - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.expectSuccessPage() await depositDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,999.77 sUSDS', estimatedUsdsValue: '10,000' }) + await savingsPage.expectSavingsUsdsBalance({ + susdsBalance: '9,830.34 sUSDS', + estimatedUsdsValue: '10,000.000000', + }) await savingsPage.expectStablecoinsInWalletAssetBalance('DAI', '-') }) }) @@ -91,8 +95,8 @@ test.describe('Deposit DAI', () => { test('displays transaction overview', async () => { await depositDialog.expectNativeRouteTransactionOverview({ apy: { - value: '6.00%', - description: 'Earn ~600.00 DAI/year', + value: '11.50%', + description: 'Earn ~1,150.00 DAI/year', }, routeItems: [ { @@ -100,23 +104,22 @@ test.describe('Deposit DAI', () => { tokenUsdValue: '$10,000.00', }, { - tokenAmount: '9,020.46 sDAI', + tokenAmount: '8,884.16 sDAI', tokenUsdValue: '$10,000.00', }, ], - outcome: '9,020.46 sDAI', + outcome: '8,884.16 sDAI', outcomeUsd: '$10,000.00', }) }) test('executes deposit', async () => { - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.expectSuccessPage() await depositDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '9,020.46 sDAI', estimatedDaiValue: '10,000' }) + await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '8,884.16 sDAI', estimatedDaiValue: '10,000.000000' }) await savingsPage.expectStablecoinsInWalletAssetBalance('DAI', '-') }) }) @@ -133,7 +136,7 @@ test.describe('Deposit DAI', () => { await depositDialog.expectSuccessPage() await depositDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '9,020.46 sDAI', estimatedDaiValue: '10,000' }) + await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '8,884.16 sDAI', estimatedDaiValue: '10,000.000000' }) await savingsPage.expectStablecoinsInWalletAssetBalance('DAI', '-') }) @@ -151,7 +154,7 @@ test.describe('Deposit DAI', () => { await depositDialog.expectSuccessPage() await depositDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,999.77 sUSDS', estimatedUsdsValue: '10,000' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,830.34 sUSDS', estimatedUsdsValue: '10,000.000000' }) await savingsPage.expectStablecoinsInWalletAssetBalance('DAI', '-') }) }) diff --git a/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositUSDC.test-e2e.ts b/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositUSDC.test-e2e.ts index 9ac008573..e31a3ca3a 100644 --- a/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositUSDC.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositUSDC.test-e2e.ts @@ -1,19 +1,21 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' -import { setup } from '@/test/e2e/setup' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' +import { TestContext, setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Deposit USDC', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let depositDialog: SavingsDialogPageObject + let testContext: TestContext<'connected-random'> test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -24,10 +26,10 @@ test.describe('Deposit USDC', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('USDC') - depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) }) @@ -42,8 +44,8 @@ test.describe('Deposit USDC', () => { test('displays transaction overview', async () => { await depositDialog.expectNativeRouteTransactionOverview({ apy: { - value: '6.25%', - description: 'Earn ~625.00 USDS/year', + value: '12.50%', + description: 'Earn ~1,250.00 USDS/year', }, routeItems: [ { @@ -55,23 +57,25 @@ test.describe('Deposit USDC', () => { tokenUsdValue: '$10,000.00', }, { - tokenAmount: '9,999.77 sUSDS', + tokenAmount: '9,830.34 sUSDS', tokenUsdValue: '$10,000.00', }, ], - outcome: '9,999.77 sUSDS', + outcome: '9,830.34 sUSDS', outcomeUsd: '$10,000.00', }) }) test('executes deposit', async () => { - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.expectSuccessPage() await depositDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,999.77 sUSDS', estimatedUsdsValue: '10,000' }) + await savingsPage.expectSavingsUsdsBalance({ + susdsBalance: '9,830.34 sUSDS', + estimatedUsdsValue: '10,000.000000', + }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '-') }) }) @@ -91,8 +95,8 @@ test.describe('Deposit USDC', () => { test('displays transaction overview', async () => { await depositDialog.expectNativeRouteTransactionOverview({ apy: { - value: '6.00%', - description: 'Earn ~600.00 DAI/year', + value: '11.50%', + description: 'Earn ~1,150.00 DAI/year', }, routeItems: [ { @@ -104,23 +108,22 @@ test.describe('Deposit USDC', () => { tokenUsdValue: '$10,000.00', }, { - tokenAmount: '9,020.46 sDAI', + tokenAmount: '8,884.16 sDAI', tokenUsdValue: '$10,000.00', }, ], - outcome: '9,020.46 sDAI', + outcome: '8,884.16 sDAI', outcomeUsd: '$10,000.00', }) }) test('executes deposit', async () => { - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.expectSuccessPage() await depositDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '9,020.46 sDAI', estimatedDaiValue: '10,000' }) + await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '8,884.16 sDAI', estimatedDaiValue: '10,000.000000' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '-') }) }) diff --git a/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositUSDS.test-e2e.ts b/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositUSDS.test-e2e.ts index 5b78e2812..5d468a171 100644 --- a/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositUSDS.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/DepositUSDS.test-e2e.ts @@ -1,19 +1,21 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' -import { setup } from '@/test/e2e/setup' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' +import { TestContext, setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Deposit USDS', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let depositDialog: SavingsDialogPageObject + let testContext: TestContext<'connected-random'> test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -24,10 +26,10 @@ test.describe('Deposit USDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('USDS') - depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) }) @@ -41,8 +43,8 @@ test.describe('Deposit USDS', () => { test('displays transaction overview', async () => { await depositDialog.expectNativeRouteTransactionOverview({ apy: { - value: '6.25%', - description: 'Earn ~625.00 USDS/year', + value: '12.50%', + description: 'Earn ~1,250.00 USDS/year', }, routeItems: [ { @@ -50,11 +52,11 @@ test.describe('Deposit USDS', () => { tokenUsdValue: '$10,000.00', }, { - tokenAmount: '9,999.77 sUSDS', + tokenAmount: '9,830.34 sUSDS', tokenUsdValue: '$10,000.00', }, ], - outcome: '9,999.77 sUSDS', + outcome: '9,830.34 sUSDS', outcomeUsd: '$10,000.00', }) @@ -62,13 +64,12 @@ test.describe('Deposit USDS', () => { }) test('executes deposit', async () => { - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.expectSuccessPage() await depositDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,999.77 sUSDS', estimatedUsdsValue: '10,000' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,830.34 sUSDS', estimatedUsdsValue: '10,000.000000' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '-') }) }) diff --git a/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/General.test-e2e.ts b/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/General.test-e2e.ts deleted file mode 100644 index 2e2211bfd..000000000 --- a/packages/app/src/features/dialogs/savings/deposit/e2e/mainnet/General.test-e2e.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' -import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { LITE_PSM_ACTIONS_OPERABLE } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' -import { setup } from '@/test/e2e/setup' -import { test } from '@playwright/test' -import { mainnet } from 'viem/chains' -import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' - -test.describe('General dialog behavior', () => { - const fork = setupFork({ - blockNumber: LITE_PSM_ACTIONS_OPERABLE, - chainId: mainnet.id, - useTenderlyVnet: true, - }) - - test('can switch between tokens', async ({ page }) => { - await setup(page, fork, { - initialPage: 'savings', - account: { - type: 'connected-random', - assetBalances: { - ETH: 1, - DAI: 100, - USDC: 100, - }, - }, - }) - - const savingsPage = new SavingsPageObject(page) - - await savingsPage.clickDepositButtonAction('DAI') - - const depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) - const actionsContainer = new ActionsPageObject(depositDialog.locatePanelByHeader('Actions')) - - await depositDialog.fillAmountAction(100) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ - { type: 'approve', asset: 'DAI' }, - { type: 'depositToSavings', asset: 'DAI', savingsAsset: 'sDAI' }, - ]) - - await depositDialog.selectAssetAction('USDC') - await depositDialog.fillAmountAction(100) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ - { type: 'approve', asset: 'USDC' }, - { type: 'depositToSavings', asset: 'USDC', savingsAsset: 'sDAI' }, - ]) - - await depositDialog.selectAssetAction('DAI') - await depositDialog.fillAmountAction(100) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ - { type: 'approve', asset: 'DAI' }, - { type: 'depositToSavings', asset: 'DAI', savingsAsset: 'sDAI' }, - ]) - }) -}) diff --git a/packages/app/src/features/dialogs/savings/migrate/downgrade/DowngradeDialog.PageObject.ts b/packages/app/src/features/dialogs/savings/migrate/downgrade/DowngradeDialog.PageObject.ts index 2cca555d3..dd3cfd9e9 100644 --- a/packages/app/src/features/dialogs/savings/migrate/downgrade/DowngradeDialog.PageObject.ts +++ b/packages/app/src/features/dialogs/savings/migrate/downgrade/DowngradeDialog.PageObject.ts @@ -1,10 +1,14 @@ import { DialogPageObject, TxOverviewWithRoute } from '@/features/dialogs/common/Dialog.PageObject' +import { TestContext } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' -import { Page, expect } from '@playwright/test' +import { expect } from '@playwright/test' export class DowngradeDialogPageObject extends DialogPageObject { - constructor(page: Page) { - super(page, /Downgrade/) + constructor(testContext: TestContext) { + super({ + testContext, + header: /Downgrade/, + }) } // #region actions diff --git a/packages/app/src/features/dialogs/savings/migrate/downgrade/e2e/UsdsToDai.test-e2e.ts b/packages/app/src/features/dialogs/savings/migrate/downgrade/e2e/UsdsToDai.test-e2e.ts index 7184de669..ebe145dd2 100644 --- a/packages/app/src/features/dialogs/savings/migrate/downgrade/e2e/UsdsToDai.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/migrate/downgrade/e2e/UsdsToDai.test-e2e.ts @@ -1,16 +1,17 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { DowngradeDialogPageObject } from '../DowngradeDialog.PageObject' test.describe('Downgrade USDS to DAI', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) - test('downgrade to DAI is disabled when USDS balance is 0', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -18,13 +19,17 @@ test.describe('Downgrade USDS to DAI', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.expectDowngradeToDaiToBeDisabled() }) test('uses downgrade action', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -32,11 +37,11 @@ test.describe('Downgrade USDS to DAI', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDowngradeUsdsToDaiOption() - const downgradeDialog = new DowngradeDialogPageObject(page) + const downgradeDialog = new DowngradeDialogPageObject(testContext) await downgradeDialog.fillAmountAction(100) await downgradeDialog.actionsContainer.expectEnabledActionAtIndex(0) @@ -47,7 +52,11 @@ test.describe('Downgrade USDS to DAI', () => { }) test('displays transaction overview', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -55,11 +64,11 @@ test.describe('Downgrade USDS to DAI', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDowngradeUsdsToDaiOption() - const downgradeDialog = new DowngradeDialogPageObject(page) + const downgradeDialog = new DowngradeDialogPageObject(testContext) await downgradeDialog.fillAmountAction(100) await downgradeDialog.expectTransactionOverview({ @@ -79,7 +88,11 @@ test.describe('Downgrade USDS to DAI', () => { }) test('executes transaction', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -87,15 +100,15 @@ test.describe('Downgrade USDS to DAI', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.expectStablecoinsInWalletAssetBalance('DAI', '-') await savingsPage.clickDowngradeUsdsToDaiOption() - const downgradeDialog = new DowngradeDialogPageObject(page) + const downgradeDialog = new DowngradeDialogPageObject(testContext) await downgradeDialog.fillAmountAction(10_000) - await downgradeDialog.actionsContainer.acceptAllActionsAction(2, fork) + await downgradeDialog.actionsContainer.acceptAllActionsAction(2) await downgradeDialog.expectDowngradeSuccessPage({ token: 'USDS', amount: '10,000.00', usdValue: '$10,000.00' }) await downgradeDialog.clickBackToSavingsButton() diff --git a/packages/app/src/features/dialogs/savings/migrate/upgrade/UpgradeDialog.PageObject.ts b/packages/app/src/features/dialogs/savings/migrate/upgrade/UpgradeDialog.PageObject.ts index 3fcb75986..317e49b9f 100644 --- a/packages/app/src/features/dialogs/savings/migrate/upgrade/UpgradeDialog.PageObject.ts +++ b/packages/app/src/features/dialogs/savings/migrate/upgrade/UpgradeDialog.PageObject.ts @@ -1,10 +1,14 @@ import { DialogPageObject, TxOverviewWithRoute } from '@/features/dialogs/common/Dialog.PageObject' +import { TestContext } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' -import { Page, expect } from '@playwright/test' +import { expect } from '@playwright/test' export class UpgradeDialogPageObject extends DialogPageObject { - constructor(page: Page) { - super(page, /Upgrade/) + constructor(testContext: TestContext) { + super({ + testContext, + header: /Upgrade/, + }) } // #region actions diff --git a/packages/app/src/features/dialogs/savings/migrate/upgrade/e2e/DaiToUsds.test-e2e.ts b/packages/app/src/features/dialogs/savings/migrate/upgrade/e2e/DaiToUsds.test-e2e.ts index ef8085cac..dbc46b945 100644 --- a/packages/app/src/features/dialogs/savings/migrate/upgrade/e2e/DaiToUsds.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/migrate/upgrade/e2e/DaiToUsds.test-e2e.ts @@ -1,16 +1,17 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { UpgradeDialogPageObject } from '../UpgradeDialog.PageObject' test.describe('Upgrade DAI to USDS', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) - test('does not show upgrade button when DAI balance is 0', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -18,7 +19,7 @@ test.describe('Upgrade DAI to USDS', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) // wait to load await savingsPage.expectOpportunityStablecoinsAmount('~$10,000.00') @@ -27,7 +28,11 @@ test.describe('Upgrade DAI to USDS', () => { }) test('uses upgrade action', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -35,11 +40,11 @@ test.describe('Upgrade DAI to USDS', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.clickUpgradeDaiToUsdsButtonAction() - const upgradeDialog = new UpgradeDialogPageObject(page) + const upgradeDialog = new UpgradeDialogPageObject(testContext) await upgradeDialog.actionsContainer.expectEnabledActionAtIndex(0) await upgradeDialog.actionsContainer.expectActions([ @@ -49,7 +54,11 @@ test.describe('Upgrade DAI to USDS', () => { }) test('displays transaction overview', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -57,9 +66,9 @@ test.describe('Upgrade DAI to USDS', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.clickUpgradeDaiToUsdsButtonAction() - const upgradeDialog = new UpgradeDialogPageObject(page) + const upgradeDialog = new UpgradeDialogPageObject(testContext) await upgradeDialog.expectTransactionOverview({ routeItems: [ @@ -78,7 +87,11 @@ test.describe('Upgrade DAI to USDS', () => { }) test('executes transaction', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -86,23 +99,23 @@ test.describe('Upgrade DAI to USDS', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '-') await savingsPage.clickUpgradeDaiToUsdsButtonAction() - const upgradeDialog = new UpgradeDialogPageObject(page) + const upgradeDialog = new UpgradeDialogPageObject(testContext) - await upgradeDialog.actionsContainer.acceptAllActionsAction(2, fork) - await upgradeDialog.expectSuccessPage( - [ + await upgradeDialog.actionsContainer.acceptAllActionsAction(2) + await upgradeDialog.expectSuccessPage({ + tokenWithValue: [ { asset: 'DAI', - amount: 10_000, + amount: '10,000.00', + usdValue: '$10,000.00', }, ], - fork, - ) + }) await upgradeDialog.clickBackToSavingsButton() await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '10,000') diff --git a/packages/app/src/features/dialogs/savings/migrate/upgrade/e2e/sDaiToSUsds.test-e2e.ts b/packages/app/src/features/dialogs/savings/migrate/upgrade/e2e/sDaiToSUsds.test-e2e.ts index 34bffeb4b..811c3518a 100644 --- a/packages/app/src/features/dialogs/savings/migrate/upgrade/e2e/sDaiToSUsds.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/migrate/upgrade/e2e/sDaiToSUsds.test-e2e.ts @@ -1,16 +1,17 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { UpgradeDialogPageObject } from '../UpgradeDialog.PageObject' test.describe('Upgrade sDAI to sUSDS', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) - test('does not show upgrade banner when sDai balance is 0', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -18,16 +19,20 @@ test.describe('Upgrade sDAI to sUSDS', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) // wait to load - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '10,000.00 sUSDS', estimatedUsdsValue: '10,000.23' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '10,000.00 sUSDS', estimatedUsdsValue: '10,172.58' }) await savingsPage.expectUpgradeDaiToUsdsButtonToBeHidden() }) test('uses upgrade action', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -35,11 +40,11 @@ test.describe('Upgrade sDAI to sUSDS', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.clickUpgradeSDaiButtonAction() - const upgradeDialog = new UpgradeDialogPageObject(page) + const upgradeDialog = new UpgradeDialogPageObject(testContext) await upgradeDialog.actionsContainer.expectEnabledActionAtIndex(0) await upgradeDialog.actionsContainer.expectActions([ @@ -49,7 +54,11 @@ test.describe('Upgrade sDAI to sUSDS', () => { }) test('displays transaction overview', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -57,34 +66,38 @@ test.describe('Upgrade sDAI to sUSDS', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.clickUpgradeSDaiButtonAction() - const upgradeDialog = new UpgradeDialogPageObject(page) + const upgradeDialog = new UpgradeDialogPageObject(testContext) await upgradeDialog.expectTransactionOverview({ apyChange: { - current: '6.00%', - updated: '6.25%', + current: '11.50%', + updated: '12.50%', }, routeItems: [ { tokenAmount: '10,000.00 sDAI', - tokenUsdValue: '$11,085.91', + tokenUsdValue: '$11,255.99', }, { - tokenAmount: '11,085.65 sUSDS', - tokenUsdValue: '$11,085.91', + tokenAmount: '11,065.02 sUSDS', + tokenUsdValue: '$11,255.99', }, ], - outcome: '11,085.65 sUSDS', - outcomeUsd: '$11,085.91', + outcome: '11,065.02 sUSDS', + outcomeUsd: '$11,255.99', }) }) test('executes transaction', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -92,14 +105,14 @@ test.describe('Upgrade sDAI to sUSDS', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.clickUpgradeSDaiButtonAction() - const upgradeDialog = new UpgradeDialogPageObject(page) - await upgradeDialog.actionsContainer.acceptAllActionsAction(2, fork) - await upgradeDialog.expectUpgradeSuccessPage({ token: 'sDAI', amount: '10,000.00', usdValue: '$11,085.91' }) + const upgradeDialog = new UpgradeDialogPageObject(testContext) + await upgradeDialog.actionsContainer.acceptAllActionsAction(2) + await upgradeDialog.expectUpgradeSuccessPage({ token: 'sDAI', amount: '10,000.00', usdValue: '$11,255.99' }) await upgradeDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '21,085.65 sUSDS', estimatedUsdsValue: '21,086.13' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '21,065.02 sUSDS', estimatedUsdsValue: '21,428.579836' }) }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/SavingsWithdrawDialog.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/SavingsWithdrawDialog.test-e2e.ts deleted file mode 100644 index e36053f0b..000000000 --- a/packages/app/src/features/dialogs/savings/withdraw/SavingsWithdrawDialog.test-e2e.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' -import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { DEFAULT_BLOCK_NUMBER, GNOSIS_DEFAULT_BLOCK_NUMBER, LITE_PSM_ACTIONS_OPERABLE } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' -import { setup } from '@/test/e2e/setup' -import { test } from '@playwright/test' -import { base, gnosis, mainnet } from 'viem/chains' -import { SavingsDialogPageObject } from '../common/e2e/SavingsDialog.PageObject' - -test.describe('Savings withdraw dialog', () => { - test.describe('Mainnet', () => { - const fork = setupFork({ - blockNumber: LITE_PSM_ACTIONS_OPERABLE, - chainId: mainnet.id, - useTenderlyVnet: true, - }) - - test('can switch between tokens', async ({ page }) => { - await setup(page, fork, { - initialPage: 'savings', - account: { - type: 'connected-random', - assetBalances: { - ETH: 1, - sDAI: 1000, - }, - }, - }) - - const savingsPage = new SavingsPageObject(page) - - await savingsPage.clickWithdrawSDaiButtonAction() - - const withdrawalDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) - const actionsContainer = new ActionsPageObject(withdrawalDialog.locatePanelByHeader('Actions')) - - await withdrawalDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ - { type: 'withdrawFromSavings', asset: 'DAI', savingsAsset: 'sDAI', mode: 'withdraw' }, - ]) - - await withdrawalDialog.selectAssetAction('USDC') - await withdrawalDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ - { type: 'approve', asset: 'sDAI' }, - { type: 'withdrawFromSavings', asset: 'USDC', savingsAsset: 'sDAI', mode: 'withdraw' }, - ]) - - await withdrawalDialog.selectAssetAction('DAI') - await withdrawalDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ - { type: 'withdrawFromSavings', asset: 'DAI', savingsAsset: 'sDAI', mode: 'withdraw' }, - ]) - }) - }) - - test.describe('Base', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) - - test('can switch between tokens', async ({ page }) => { - await setup(page, fork, { - initialPage: 'savings', - account: { - type: 'connected-random', - assetBalances: { - ETH: 1, - sUSDS: 1000, - }, - }, - }) - - const savingsPage = new SavingsPageObject(page) - - await savingsPage.clickWithdrawSUsdsButtonAction() - - const withdrawalDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) - const actionsContainer = new ActionsPageObject(withdrawalDialog.locatePanelByHeader('Actions')) - - await withdrawalDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ - { type: 'approve', asset: 'sUSDS' }, - { type: 'withdrawFromSavings', asset: 'USDS', savingsAsset: 'sUSDS', mode: 'withdraw' }, - ]) - - await withdrawalDialog.selectAssetAction('USDC') - await withdrawalDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ - { type: 'approve', asset: 'sUSDS' }, - { type: 'withdrawFromSavings', asset: 'USDC', savingsAsset: 'sUSDS', mode: 'withdraw' }, - ]) - - await withdrawalDialog.selectAssetAction('USDS') - await withdrawalDialog.fillAmountAction(1000) - await actionsContainer.expectEnabledActionAtIndex(0) - await actionsContainer.expectActions([ - { type: 'approve', asset: 'sUSDS' }, - { type: 'withdrawFromSavings', asset: 'USDS', savingsAsset: 'sUSDS', mode: 'withdraw' }, - ]) - }) - }) -}) - -test.describe('Savings withdraw dialog send mode', () => { - test.describe('Mainnet', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) - let savingsPage: SavingsPageObject - let sendDialog: SavingsDialogPageObject - - test.beforeEach(async ({ page }) => { - await setup(page, fork, { - initialPage: 'savings', - account: { - type: 'connected-random', - assetBalances: { - ETH: 1, - sDAI: 10_000, - }, - }, - }) - - savingsPage = new SavingsPageObject(page) - await savingsPage.clickSendSDaiButtonAction() - - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) - }) - - test('can select only supported assets', async () => { - await sendDialog.openAssetSelectorAction() - await sendDialog.expectAssetSelectorOptions(['DAI', 'USDC']) - }) - }) - - test.describe('Gnosis', () => { - const fork = setupFork({ blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id, useTenderlyVnet: true }) - let savingsPage: SavingsPageObject - let sendDialog: SavingsDialogPageObject - - test.beforeEach(async ({ page }) => { - await setup(page, fork, { - initialPage: 'savings', - account: { - type: 'connected-random', - assetBalances: { - XDAI: 100, - sDAI: 10_000, - }, - }, - }) - - savingsPage = new SavingsPageObject(page) - await savingsPage.clickSendSDaiButtonAction() - - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) - }) - - test('can select only supported assets', async () => { - await sendDialog.openAssetSelectorAction() - await sendDialog.expectAssetSelectorOptions(['XDAI']) - }) - }) - - test.describe('Base', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) - let savingsPage: SavingsPageObject - let sendDialog: SavingsDialogPageObject - - test.beforeEach(async ({ page }) => { - await setup(page, fork, { - initialPage: 'savings', - account: { - type: 'connected-random', - assetBalances: { - USDS: 100, - sUSDS: 10_000, - }, - }, - }) - - savingsPage = new SavingsPageObject(page) - await savingsPage.clickSendSUsdsButtonAction() - - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) - }) - - test('can select only supported assets', async () => { - await sendDialog.openAssetSelectorAction() - await sendDialog.expectAssetSelectorOptions(['USDC', 'USDS']) - }) - }) -}) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/General.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/General.test-e2e.ts new file mode 100644 index 000000000..fb0c0587d --- /dev/null +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/General.test-e2e.ts @@ -0,0 +1,81 @@ +import { SavingsPageObject } from '@/pages/Savings.PageObject' +import { BASE_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' +import { setup } from '@/test/e2e/setup' +import { test } from '@playwright/test' +import { base } from 'viem/chains' +import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' + +test.describe('Without send mode', () => { + test('can switch between tokens', async ({ page }) => { + const testContext = await setup(page, { + blockchain: { + chainId: base.id, + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + }, + initialPage: 'savings', + account: { + type: 'connected-random', + assetBalances: { + ETH: 1, + sUSDS: 1000, + }, + }, + }) + + const savingsPage = new SavingsPageObject(testContext) + + await savingsPage.clickWithdrawSUsdsButtonAction() + + const withdrawalDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) + + await withdrawalDialog.fillAmountAction(1000) + await withdrawalDialog.actionsContainer.expectEnabledActionAtIndex(0) + await withdrawalDialog.actionsContainer.expectActions([ + { type: 'approve', asset: 'sUSDS' }, + { type: 'withdrawFromSavings', asset: 'USDS', savingsAsset: 'sUSDS', mode: 'withdraw' }, + ]) + + await withdrawalDialog.selectAssetAction('USDC') + await withdrawalDialog.fillAmountAction(1000) + await withdrawalDialog.actionsContainer.expectEnabledActionAtIndex(0) + await withdrawalDialog.actionsContainer.expectActions([ + { type: 'approve', asset: 'sUSDS' }, + { type: 'withdrawFromSavings', asset: 'USDC', savingsAsset: 'sUSDS', mode: 'withdraw' }, + ]) + + await withdrawalDialog.selectAssetAction('USDS') + await withdrawalDialog.fillAmountAction(1000) + await withdrawalDialog.actionsContainer.expectEnabledActionAtIndex(0) + await withdrawalDialog.actionsContainer.expectActions([ + { type: 'approve', asset: 'sUSDS' }, + { type: 'withdrawFromSavings', asset: 'USDS', savingsAsset: 'sUSDS', mode: 'withdraw' }, + ]) + }) +}) + +test.describe('With send mode', () => { + test('can select only supported assets', async ({ page }) => { + const testContext = await setup(page, { + blockchain: { + chainId: base.id, + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + }, + initialPage: 'savings', + account: { + type: 'connected-random', + assetBalances: { + USDS: 100, + sUSDS: 10_000, + }, + }, + }) + + const savingsPage = new SavingsPageObject(testContext) + await savingsPage.clickSendSUsdsButtonAction() + + const sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) + + await sendDialog.openAssetSelectorAction() + await sendDialog.expectAssetSelectorOptions(['USDC', 'USDS']) + }) +}) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/SendUSDC.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/SendUSDC.test-e2e.ts index d7ba5e841..04d7220f9 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/SendUSDC.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/SendUSDC.test-e2e.ts @@ -1,6 +1,5 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { TOKENS_ON_FORK } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { BASE_DEFAULT_BLOCK_NUMBER, TOKENS_ON_FORK } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { randomAddress } from '@/test/utils/addressUtils' import { test } from '@playwright/test' @@ -8,8 +7,6 @@ import { base } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Send USDC', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) - let savingsPage: SavingsPageObject let sendDialog: SavingsDialogPageObject @@ -18,7 +15,11 @@ test.describe('Send USDC', () => { const usdc = TOKENS_ON_FORK[base.id].USDC test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: base.id, + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -29,10 +30,10 @@ test.describe('Send USDC', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickSendSUsdsButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.selectAssetAction('USDC') await sendDialog.fillAmountAction(amount) @@ -50,7 +51,7 @@ test.describe('Send USDC', () => { await sendDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '6,938.24 sUSDS', + tokenAmount: '6,911.09 sUSDS', tokenUsdValue: '$7,000.00', }, { @@ -69,24 +70,22 @@ test.describe('Send USDC', () => { test('executes send', async () => { await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usdc, expectedBalance: 0, }) - await sendDialog.actionsContainer.acceptAllActionsAction(2, fork) + await sendDialog.actionsContainer.acceptAllActionsAction(2) await sendDialog.expectSuccessPage() await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usdc, expectedBalance: amount, }) await sendDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '3,061.76 sUSDS', estimatedUsdsValue: '3,089' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '3,088.91 sUSDS', estimatedUsdsValue: '3,128.6548910' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '-') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/SendUSDS.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/SendUSDS.test-e2e.ts index 6377de25c..95ab0d43c 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/SendUSDS.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/SendUSDS.test-e2e.ts @@ -1,6 +1,5 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { TOKENS_ON_FORK } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { BASE_DEFAULT_BLOCK_NUMBER, TOKENS_ON_FORK } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { randomAddress } from '@/test/utils/addressUtils' import { test } from '@playwright/test' @@ -8,7 +7,6 @@ import { base } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Send USDS', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let sendDialog: SavingsDialogPageObject const receiver = randomAddress('bob') @@ -16,7 +14,11 @@ test.describe('Send USDS', () => { const usds = TOKENS_ON_FORK[base.id].USDS test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: base.id, + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -27,10 +29,10 @@ test.describe('Send USDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickSendSUsdsButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.fillAmountAction(amount) await sendDialog.fillReceiverAction(receiver) }) @@ -46,7 +48,7 @@ test.describe('Send USDS', () => { await sendDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '6,938.24 sUSDS', + tokenAmount: '6,911.09 sUSDS', tokenUsdValue: '$7,000.00', }, { @@ -61,24 +63,22 @@ test.describe('Send USDS', () => { test('executes send', async () => { await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usds, expectedBalance: 0, }) - await sendDialog.actionsContainer.acceptAllActionsAction(2, fork) + await sendDialog.actionsContainer.acceptAllActionsAction(2) await sendDialog.expectSuccessPage() await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usds, expectedBalance: amount, }) await sendDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '3,061.76 sUSDS', estimatedUsdsValue: '3,089' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '3,088.91 sUSDS', estimatedUsdsValue: '3,128.6548917' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '-') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawMaxUSDC.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawMaxUSDC.test-e2e.ts index d3ac6fc02..fc32b9368 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawMaxUSDC.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawMaxUSDC.test-e2e.ts @@ -1,18 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { BASE_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { base } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Withdraw Max USDC', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: base.id, + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,10 +25,10 @@ test.describe('Withdraw Max USDC', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSUsdsButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.selectAssetAction('USDC') await withdrawDialog.clickMaxAmountAction() }) @@ -43,28 +45,27 @@ test.describe('Withdraw Max USDC', () => { routeItems: [ { tokenAmount: '10,000.00 sUSDS', - tokenUsdValue: '$10,089.01', + tokenUsdValue: '$10,128.65', }, { - tokenAmount: '10,089.01 USDS', - tokenUsdValue: '$10,089.01', + tokenAmount: '10,128.65 USDS', + tokenUsdValue: '$10,128.65', }, ], - outcome: '10,089.01 USDC', - outcomeUsd: '$10,089.01', + outcome: '10,128.65 USDC', + outcomeUsd: '$10,128.65', }) await withdrawDialog.expectUpgradeSwitchToBeHidden() }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() - await savingsPage.expectOpportunityStablecoinsAmount('~$10,089.01') - await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '10,089.01') + await savingsPage.expectOpportunityStablecoinsAmount('~$10,128.65') + await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '10,128.65') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawMaxUSDS.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawMaxUSDS.test-e2e.ts index 44d196dfb..09d6075db 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawMaxUSDS.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawMaxUSDS.test-e2e.ts @@ -1,18 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { BASE_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { base } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Withdraw Max USDS', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: base.id, + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,10 +25,10 @@ test.describe('Withdraw Max USDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSUsdsButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.clickMaxAmountAction() }) @@ -42,28 +44,27 @@ test.describe('Withdraw Max USDS', () => { routeItems: [ { tokenAmount: '10,000.00 sUSDS', - tokenUsdValue: '$10,089.01', + tokenUsdValue: '$10,128.65', }, { - tokenAmount: '10,089.01 USDS', - tokenUsdValue: '$10,089.01', + tokenAmount: '10,128.65 USDS', + tokenUsdValue: '$10,128.65', }, ], - outcome: '10,089.01 USDS', - outcomeUsd: '$10,089.01', + outcome: '10,128.65 USDS', + outcomeUsd: '$10,128.65', }) await withdrawDialog.expectUpgradeSwitchToBeHidden() }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() - await savingsPage.expectOpportunityStablecoinsAmount('~$10,089.01') - await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '10,089.01') + await savingsPage.expectOpportunityStablecoinsAmount('~$10,128.65') + await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '10,128.65') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawUSDC.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawUSDC.test-e2e.ts index 78e012810..43c2ae911 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawUSDC.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawUSDC.test-e2e.ts @@ -1,18 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { BASE_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { base } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Withdraw USDC', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: base.id, + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,10 +25,10 @@ test.describe('Withdraw USDC', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSUsdsButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.selectAssetAction('USDC') await withdrawDialog.fillAmountAction(1000) }) @@ -42,7 +44,7 @@ test.describe('Withdraw USDC', () => { await withdrawDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '991.18 sUSDS', + tokenAmount: '987.30 sUSDS', tokenUsdValue: '$1,000.00', }, { @@ -62,13 +64,12 @@ test.describe('Withdraw USDC', () => { }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,008.82 sUSDS', estimatedUsdsValue: '9,089' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,012.70 sUSDS', estimatedUsdsValue: '9,128.654891' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '1,000') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawUSDS.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawUSDS.test-e2e.ts index ce54ce555..7e8c47ab1 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawUSDS.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/base/WithdrawUSDS.test-e2e.ts @@ -1,18 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { BASE_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { base } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Withdraw USDS', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: base.id, + blockNumber: BASE_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -23,10 +25,10 @@ test.describe('Withdraw USDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSUsdsButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.fillAmountAction(1000) }) @@ -41,7 +43,7 @@ test.describe('Withdraw USDS', () => { await withdrawDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '991.18 sUSDS', + tokenAmount: '987.30 sUSDS', tokenUsdValue: '$1,000.00', }, { @@ -57,13 +59,12 @@ test.describe('Withdraw USDS', () => { }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,008.82 sUSDS', estimatedUsdsValue: '9,089' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '9,012.70 sUSDS', estimatedUsdsValue: '9,128.654892' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '1,000') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/General.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/General.test-e2e.ts new file mode 100644 index 000000000..97c9249e0 --- /dev/null +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/General.test-e2e.ts @@ -0,0 +1,33 @@ +import { SavingsPageObject } from '@/pages/Savings.PageObject' +import { GNOSIS_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' +import { setup } from '@/test/e2e/setup' +import { test } from '@playwright/test' +import { gnosis } from 'viem/chains' +import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' + +test.describe('With send mode', () => { + test('can select only supported assets', async ({ page }) => { + const testContext = await setup(page, { + blockchain: { + chainId: gnosis.id, + blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, + }, + initialPage: 'savings', + account: { + type: 'connected-random', + assetBalances: { + XDAI: 100, + sDAI: 10_000, + }, + }, + }) + + const savingsPage = new SavingsPageObject(testContext) + await savingsPage.clickSendSDaiButtonAction() + + const sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) + + await sendDialog.openAssetSelectorAction() + await sendDialog.expectAssetSelectorOptions(['XDAI']) + }) +}) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/SendXDAI.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/SendXDAI.test-e2e.ts index 21aad26e3..4a353bb42 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/SendXDAI.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/SendXDAI.test-e2e.ts @@ -1,6 +1,5 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' import { GNOSIS_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' import { randomAddress } from '@/test/utils/addressUtils' import { test } from '@playwright/test' @@ -8,14 +7,17 @@ import { gnosis } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Send XDAI on Gnosis', () => { - const fork = setupFork({ blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let sendDialog: SavingsDialogPageObject const receiver = randomAddress('bob') const amount = 7000 test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: gnosis.id, + blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -26,10 +28,10 @@ test.describe('Send XDAI on Gnosis', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickSendSDaiButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.fillAmountAction(amount) await sendDialog.fillReceiverAction(receiver) }) @@ -60,16 +62,14 @@ test.describe('Send XDAI on Gnosis', () => { test('executes send', async () => { await sendDialog.expectReceiverBalance({ - forkUrl: fork.forkUrl, receiver, expectedBalance: 0, }) - await sendDialog.actionsContainer.acceptAllActionsAction(2, fork) + await sendDialog.actionsContainer.acceptAllActionsAction(2) await sendDialog.expectSuccessPage() await sendDialog.expectReceiverBalance({ - forkUrl: fork.forkUrl, receiver, expectedBalance: amount, }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/WithdrawMaxXDAI.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/WithdrawMaxXDAI.test-e2e.ts index f7fee1acc..4a1988ffe 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/WithdrawMaxXDAI.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/WithdrawMaxXDAI.test-e2e.ts @@ -1,23 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' import { GNOSIS_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { gnosis } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Withdraw max XDAI on Gnosis', () => { - const fork = setupFork({ - blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, - chainId: gnosis.id, - useTenderlyVnet: true, - }) let savingsPage: SavingsPageObject let withdrawalDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: gnosis.id, + blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -28,10 +25,10 @@ test.describe('Withdraw max XDAI on Gnosis', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSDaiButtonAction() - withdrawalDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawalDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawalDialog.clickMaxAmountAction() }) @@ -60,8 +57,7 @@ test.describe('Withdraw max XDAI on Gnosis', () => { }) test('executes max withdrawal', async () => { - const actionsContainer = new ActionsPageObject(withdrawalDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawalDialog.actionsContainer.acceptAllActionsAction(2) await withdrawalDialog.expectSuccessPage() await withdrawalDialog.clickBackToSavingsButton() diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/WithdrawXDAI.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/WithdrawXDAI.test-e2e.ts index 8a678c26f..a2ec24281 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/WithdrawXDAI.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/gnosis/WithdrawXDAI.test-e2e.ts @@ -1,23 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' import { GNOSIS_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { gnosis } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Withdraw XDAI on Gnosis', () => { - const fork = setupFork({ - blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, - chainId: gnosis.id, - useTenderlyVnet: true, - }) let savingsPage: SavingsPageObject let withdrawalDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: gnosis.id, + blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -28,10 +25,10 @@ test.describe('Withdraw XDAI on Gnosis', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSDaiButtonAction() - withdrawalDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawalDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawalDialog.fillAmountAction(7000) }) @@ -60,8 +57,7 @@ test.describe('Withdraw XDAI on Gnosis', () => { }) test('executes withdrawal', async () => { - const actionsContainer = new ActionsPageObject(withdrawalDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawalDialog.actionsContainer.acceptAllActionsAction(2) await withdrawalDialog.expectSuccessPage() await withdrawalDialog.clickBackToSavingsButton() diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/General.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/General.test-e2e.ts new file mode 100644 index 000000000..f4c51ef52 --- /dev/null +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/General.test-e2e.ts @@ -0,0 +1,93 @@ +import { SavingsPageObject } from '@/pages/Savings.PageObject' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' +import { setup } from '@/test/e2e/setup' +import { test } from '@playwright/test' +import { mainnet } from 'viem/chains' +import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' + +test.describe('Without send mode', () => { + let withdrawalDialog: SavingsDialogPageObject + let savingsPage: SavingsPageObject + + test.beforeEach(async ({ page }) => { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, + initialPage: 'savings', + account: { + type: 'connected-random', + assetBalances: { + ETH: 1, + sDAI: 1000, + }, + }, + }) + + savingsPage = new SavingsPageObject(testContext) + await savingsPage.clickWithdrawSDaiButtonAction() + + withdrawalDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) + }) + + test('can switch between tokens', async () => { + await withdrawalDialog.fillAmountAction(1000) + await withdrawalDialog.actionsContainer.expectEnabledActionAtIndex(0) + await withdrawalDialog.actionsContainer.expectActions([ + { type: 'withdrawFromSavings', asset: 'DAI', savingsAsset: 'sDAI', mode: 'withdraw' }, + ]) + + await withdrawalDialog.selectAssetAction('USDC') + await withdrawalDialog.fillAmountAction(1000) + await withdrawalDialog.actionsContainer.expectEnabledActionAtIndex(0) + await withdrawalDialog.actionsContainer.expectActions([ + { type: 'approve', asset: 'sDAI' }, + { type: 'withdrawFromSavings', asset: 'USDC', savingsAsset: 'sDAI', mode: 'withdraw' }, + ]) + + await withdrawalDialog.selectAssetAction('DAI') + await withdrawalDialog.fillAmountAction(1000) + await withdrawalDialog.actionsContainer.expectEnabledActionAtIndex(0) + await withdrawalDialog.actionsContainer.expectActions([ + { type: 'withdrawFromSavings', asset: 'DAI', savingsAsset: 'sDAI', mode: 'withdraw' }, + ]) + }) + + test('can click max after switching tokens', async () => { + await withdrawalDialog.expectInputValue('') + await withdrawalDialog.clickMaxAmountAction() + await withdrawalDialog.expectInputValue('1125.599162') + await withdrawalDialog.selectAssetAction('USDC') + await withdrawalDialog.expectInputValue('') + await withdrawalDialog.clickMaxAmountAction() + await withdrawalDialog.expectInputValue('1125.599162') + }) +}) + +test.describe('With send mode', () => { + test('can select only supported assets', async ({ page }) => { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, + initialPage: 'savings', + account: { + type: 'connected-random', + assetBalances: { + ETH: 1, + sDAI: 10_000, + }, + }, + }) + + const savingsPage = new SavingsPageObject(testContext) + await savingsPage.clickSendSDaiButtonAction() + + const sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) + + await sendDialog.openAssetSelectorAction() + await sendDialog.expectAssetSelectorOptions(['DAI', 'USDC', 'USDS']) + }) +}) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendDAI.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendDAI.test-e2e.ts index 620a2781c..f4e211b1f 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendDAI.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendDAI.test-e2e.ts @@ -1,6 +1,5 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' import { DEFAULT_BLOCK_NUMBER, TOKENS_ON_FORK } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' import { randomAddress } from '@/test/utils/addressUtils' import { test } from '@playwright/test' @@ -8,7 +7,6 @@ import { mainnet } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Send DAI on Mainnet', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let sendDialog: SavingsDialogPageObject const receiver = randomAddress('bob') @@ -16,7 +14,11 @@ test.describe('Send DAI on Mainnet', () => { const dai = TOKENS_ON_FORK[mainnet.id].DAI test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -27,10 +29,10 @@ test.describe('Send DAI on Mainnet', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickSendSDaiButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.fillAmountAction(amount) await sendDialog.fillReceiverAction(receiver) }) @@ -45,7 +47,7 @@ test.describe('Send DAI on Mainnet', () => { await sendDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '6,647.10 sDAI', + tokenAmount: '6,218.91 sDAI', tokenUsdValue: '$7,000.00', }, { @@ -60,24 +62,23 @@ test.describe('Send DAI on Mainnet', () => { test('executes send', async () => { await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: dai, expectedBalance: 0, }) - await sendDialog.actionsContainer.acceptAllActionsAction(1, fork) + await sendDialog.actionsContainer.acceptAllActionsAction(1) await sendDialog.expectSuccessPage() await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: dai, expectedBalance: amount, }) await sendDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '3,352.90 sDAI', estimatedDaiValue: '3,530.91' }) + + await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '3,781.09 sDAI', estimatedDaiValue: '4,255.9918184' }) await savingsPage.expectStablecoinsInWalletAssetBalance('DAI', '-') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendDAIValidation.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendDAIValidation.test-e2e.ts index 05f580dec..847220463 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendDAIValidation.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendDAIValidation.test-e2e.ts @@ -1,7 +1,6 @@ import { receiverValidationIssueToMessage } from '@/domain/savings/validateReceiver' import { SavingsPageObject } from '@/pages/Savings.PageObject' import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { Address, zeroAddress } from 'viem' @@ -10,14 +9,17 @@ import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageO import { withdrawValidationIssueToMessage } from '../../logic/validation' test.describe('Asset input validation', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let sendDialog: SavingsDialogPageObject const receiver = '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045' test.describe('Input value exceeds sDAI value', () => { test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -28,10 +30,10 @@ test.describe('Asset input validation', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickSendSDaiButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.fillAmountAction(200) await sendDialog.fillReceiverAction(receiver) }) @@ -50,7 +52,7 @@ test.describe('Asset input validation', () => { await sendDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '189.92 sDAI', + tokenAmount: '177.68 sDAI', tokenUsdValue: '$200.00', }, { @@ -65,7 +67,11 @@ test.describe('Asset input validation', () => { }) test('displays validation error for dirty input with 0 value', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -76,9 +82,9 @@ test.describe('Asset input validation', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickSendSDaiButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.fillAmountAction(10) await sendDialog.fillAmountAction(0) @@ -88,14 +94,17 @@ test.describe('Asset input validation', () => { }) test.describe('Receiver input validation', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let sendDialog: SavingsDialogPageObject let selfAddress: Address test.describe('Incorrect receiver address', () => { test.beforeEach(async ({ page }) => { - const { account } = await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -106,12 +115,12 @@ test.describe('Receiver input validation', () => { }, }) - selfAddress = account + selfAddress = testContext.account - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickSendSDaiButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.fillAmountAction(50) // valid input amount }) @@ -153,7 +162,7 @@ test.describe('Receiver input validation', () => { await sendDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '47.48 sDAI', + tokenAmount: '44.42 sDAI', tokenUsdValue: '$50.00', }, { @@ -168,7 +177,11 @@ test.describe('Receiver input validation', () => { }) test('displays warning when receiver is smart contract address', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -179,9 +192,9 @@ test.describe('Receiver input validation', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickSendSDaiButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.fillAmountAction(50) // valid input amount await sendDialog.fillReceiverAction('0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7') // pot address @@ -190,12 +203,15 @@ test.describe('Receiver input validation', () => { }) test.describe('Form validation', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let sendDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -206,10 +222,10 @@ test.describe('Form validation', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickSendSDaiButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) }) test('actions are disabled when amount is invalid, but receiver is valid', async () => { diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendUSDC.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendUSDC.test-e2e.ts index 4f4df0f0c..c356bba8f 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendUSDC.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendUSDC.test-e2e.ts @@ -1,6 +1,5 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { TOKENS_ON_FORK, USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER, TOKENS_ON_FORK } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { randomAddress } from '@/test/utils/addressUtils' import { test } from '@playwright/test' @@ -8,7 +7,6 @@ import { mainnet } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Send USDC (withdrawing from sUSDS)', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let sendDialog: SavingsDialogPageObject const receiver = randomAddress('bob') @@ -16,7 +14,11 @@ test.describe('Send USDC (withdrawing from sUSDS)', () => { const usdc = TOKENS_ON_FORK[mainnet.id].USDC test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -27,16 +29,16 @@ test.describe('Send USDC (withdrawing from sUSDS)', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('USDS') - const depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + const depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) - await depositDialog.actionsContainer.acceptAllActionsAction(2, fork) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.clickBackToSavingsButton() await savingsPage.clickSendSUsdsButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.selectAssetAction('USDC') await sendDialog.fillAmountAction(amount) await sendDialog.fillReceiverAction(receiver) @@ -53,7 +55,7 @@ test.describe('Send USDC (withdrawing from sUSDS)', () => { await sendDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '6,999.84 sUSDS', + tokenAmount: '6,881.24 sUSDS', tokenUsdValue: '$7,000.00', }, { @@ -72,30 +74,27 @@ test.describe('Send USDC (withdrawing from sUSDS)', () => { test('executes send', async () => { await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usdc, expectedBalance: 0, }) - await sendDialog.actionsContainer.acceptAllActionsAction(2, fork) + await sendDialog.actionsContainer.acceptAllActionsAction(2) await sendDialog.expectSuccessPage() await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usdc, expectedBalance: amount, }) await sendDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '2,999.93 sUSDS', estimatedUsdsValue: '3,000' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '2,949.10 sUSDS', estimatedUsdsValue: '3,000.0003735' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '-') }) }) test.describe('Send USDC (withdrawing from sDAI)', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let sendDialog: SavingsDialogPageObject const receiver = randomAddress('bob') @@ -103,7 +102,11 @@ test.describe('Send USDC (withdrawing from sDAI)', () => { const usdc = TOKENS_ON_FORK[mainnet.id].USDC test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -114,10 +117,10 @@ test.describe('Send USDC (withdrawing from sDAI)', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickSendSDaiButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.selectAssetAction('USDC') await sendDialog.fillAmountAction(amount) await sendDialog.fillReceiverAction(receiver) @@ -134,7 +137,7 @@ test.describe('Send USDC (withdrawing from sDAI)', () => { await sendDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '6,314.32 sDAI', + tokenAmount: '6,218.91 sDAI', tokenUsdValue: '$7,000.00', }, { @@ -153,24 +156,22 @@ test.describe('Send USDC (withdrawing from sDAI)', () => { test('executes send', async () => { await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usdc, expectedBalance: 0, }) - await sendDialog.actionsContainer.acceptAllActionsAction(2, fork) + await sendDialog.actionsContainer.acceptAllActionsAction(2) await sendDialog.expectSuccessPage() await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usdc, expectedBalance: amount, }) await sendDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '3,685.68 sDAI', estimatedDaiValue: '4,085.90' }) + await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '3,781.09 sDAI', estimatedDaiValue: '4,255.9920127' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '-') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendUSDS.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendUSDS.test-e2e.ts index 9f9223c2e..7b29d1cd4 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendUSDS.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/SendUSDS.test-e2e.ts @@ -1,6 +1,5 @@ import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { TOKENS_ON_FORK, USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER, TOKENS_ON_FORK } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { randomAddress } from '@/test/utils/addressUtils' import { test } from '@playwright/test' @@ -8,7 +7,6 @@ import { mainnet } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Send USDS (withdrawing from sUSDS)', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let sendDialog: SavingsDialogPageObject const receiver = randomAddress('bob') @@ -16,7 +14,11 @@ test.describe('Send USDS (withdrawing from sUSDS)', () => { const usds = TOKENS_ON_FORK[mainnet.id].USDS test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -27,16 +29,16 @@ test.describe('Send USDS (withdrawing from sUSDS)', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('USDS') - const depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + const depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) - await depositDialog.actionsContainer.acceptAllActionsAction(2, fork) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.clickBackToSavingsButton() await savingsPage.clickSendSUsdsButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.fillAmountAction(amount) await sendDialog.fillReceiverAction(receiver) }) @@ -51,7 +53,7 @@ test.describe('Send USDS (withdrawing from sUSDS)', () => { await sendDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '6,999.84 sUSDS', + tokenAmount: '6,881.24 sUSDS', tokenUsdValue: '$7,000.00', }, { @@ -66,30 +68,27 @@ test.describe('Send USDS (withdrawing from sUSDS)', () => { test('executes send', async () => { await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usds, expectedBalance: 0, }) - await sendDialog.actionsContainer.acceptAllActionsAction(1, fork) + await sendDialog.actionsContainer.acceptAllActionsAction(1) await sendDialog.expectSuccessPage() await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usds, expectedBalance: amount, }) await sendDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '2,999.93 sUSDS', estimatedUsdsValue: '3,000' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '2,949.10 sUSDS', estimatedUsdsValue: '3,000.0001867' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '-') }) }) test.describe('Send USDS (withdrawing from sDAI)', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let sendDialog: SavingsDialogPageObject const receiver = randomAddress('bob') @@ -97,7 +96,11 @@ test.describe('Send USDS (withdrawing from sDAI)', () => { const usds = TOKENS_ON_FORK[mainnet.id].USDS test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -108,10 +111,10 @@ test.describe('Send USDS (withdrawing from sDAI)', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickSendSDaiButtonAction() - sendDialog = new SavingsDialogPageObject({ page, type: 'send' }) + sendDialog = new SavingsDialogPageObject({ testContext, type: 'send' }) await sendDialog.selectAssetAction('USDS') await sendDialog.fillAmountAction(amount) await sendDialog.fillReceiverAction(receiver) @@ -128,7 +131,7 @@ test.describe('Send USDS (withdrawing from sDAI)', () => { await sendDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '6,314.32 sDAI', + tokenAmount: '6,218.91 sDAI', tokenUsdValue: '$7,000.00', }, { @@ -147,24 +150,22 @@ test.describe('Send USDS (withdrawing from sDAI)', () => { test('executes send', async () => { await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usds, expectedBalance: 0, }) - await sendDialog.actionsContainer.acceptAllActionsAction(2, fork) + await sendDialog.actionsContainer.acceptAllActionsAction(2) await sendDialog.expectSuccessPage() await sendDialog.expectReceiverTokenBalance({ - forkUrl: fork.forkUrl, receiver, token: usds, expectedBalance: amount, }) await sendDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '3,685.68 sDAI', estimatedDaiValue: '4,085.90' }) + await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '3,781.09 sDAI', estimatedDaiValue: '4,255.9920127' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '-') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawDAI.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawDAI.test-e2e.ts index 0f682b6a6..c48cc1e5b 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawDAI.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawDAI.test-e2e.ts @@ -1,7 +1,5 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' @@ -9,12 +7,15 @@ import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageO import { withdrawValidationIssueToMessage } from '../../logic/validation' test.describe('Withdraw DAI on Mainnet', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) let savingsPage: SavingsPageObject let withdrawalDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -25,10 +26,10 @@ test.describe('Withdraw DAI on Mainnet', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSDaiButtonAction() - withdrawalDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawalDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawalDialog.fillAmountAction(7000) }) @@ -42,7 +43,7 @@ test.describe('Withdraw DAI on Mainnet', () => { await withdrawalDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '6,532.86 sDAI', + tokenAmount: '6,218.91 sDAI', tokenUsdValue: '$7,000.00', }, { @@ -56,25 +57,27 @@ test.describe('Withdraw DAI on Mainnet', () => { }) test('executes withdrawal', async () => { - const actionsContainer = new ActionsPageObject(withdrawalDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) + await withdrawalDialog.actionsContainer.acceptAllActionsAction(1) await withdrawalDialog.expectSuccessPage() await withdrawalDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '3,467.14 sDAI', estimatedDaiValue: '3,715.05' }) + await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '3,781.09 sDAI', estimatedDaiValue: '4,255.9918184' }) await savingsPage.expectStablecoinsInWalletAssetBalance('DAI', '7,000.00') }) }) test.describe('Validation', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) let savingsPage: SavingsPageObject let withdrawalDialog: SavingsDialogPageObject test.describe('Input value exceeds sDAI value', () => { test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -85,10 +88,10 @@ test.describe('Validation', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSDaiButtonAction() - withdrawalDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawalDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawalDialog.fillAmountAction(200) }) @@ -106,7 +109,7 @@ test.describe('Validation', () => { await withdrawalDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '186.65 sDAI', + tokenAmount: '177.68 sDAI', tokenUsdValue: '$200.00', }, { @@ -121,7 +124,11 @@ test.describe('Validation', () => { }) test('displays validation error for dirty input with 0 value', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -132,9 +139,9 @@ test.describe('Validation', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSDaiButtonAction() - withdrawalDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawalDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawalDialog.fillAmountAction(10) await withdrawalDialog.fillAmountAction(0) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxDAI.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxDAI.test-e2e.ts index 478c3be80..8e888384e 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxDAI.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxDAI.test-e2e.ts @@ -1,19 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Withdraw max DAI on Mainnet', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) let savingsPage: SavingsPageObject let withdrawalDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -24,10 +25,10 @@ test.describe('Withdraw max DAI on Mainnet', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSDaiButtonAction() - withdrawalDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawalDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawalDialog.clickMaxAmountAction() }) @@ -42,26 +43,25 @@ test.describe('Withdraw max DAI on Mainnet', () => { routeItems: [ { tokenAmount: '10,000.00 sDAI', - tokenUsdValue: '$10,715.05', + tokenUsdValue: '$11,255.99', }, { - tokenAmount: '10,715.05 DAI', - tokenUsdValue: '$10,715.05', + tokenAmount: '11,255.99 DAI', + tokenUsdValue: '$11,255.99', }, ], - outcome: '10,715.05 DAI', - outcomeUsd: '$10,715.05', + outcome: '11,255.99 DAI', + outcomeUsd: '$11,255.99', }) }) test('executes max withdrawal', async () => { - const actionsContainer = new ActionsPageObject(withdrawalDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) + await withdrawalDialog.actionsContainer.acceptAllActionsAction(1) await withdrawalDialog.expectSuccessPage() await withdrawalDialog.clickBackToSavingsButton() - await savingsPage.expectOpportunityStablecoinsAmount('~$10,715.05') - await savingsPage.expectStablecoinsInWalletAssetBalance('DAI', '10,715.05') + await savingsPage.expectOpportunityStablecoinsAmount('~$11,255.99') + await savingsPage.expectStablecoinsInWalletAssetBalance('DAI', '11,255.99') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxUSDC.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxUSDC.test-e2e.ts index c6fcd4f84..29239802b 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxUSDC.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxUSDC.test-e2e.ts @@ -1,19 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Withdraw USDC from sUSDS', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -24,16 +25,16 @@ test.describe('Withdraw USDC from sUSDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('USDS') - const depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + const depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) - await depositDialog.actionsContainer.acceptAllActionsAction(2, fork) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.clickBackToSavingsButton() await savingsPage.clickWithdrawSUsdsButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.selectAssetAction('USDC') await withdrawDialog.clickMaxAmountAction() }) @@ -49,7 +50,7 @@ test.describe('Withdraw USDC from sUSDS', () => { await withdrawDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '9,999.77 sUSDS', + tokenAmount: '9,830.34 sUSDS', tokenUsdValue: '$10,000.00', }, { @@ -69,8 +70,7 @@ test.describe('Withdraw USDC from sUSDS', () => { }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() @@ -81,12 +81,15 @@ test.describe('Withdraw USDC from sUSDS', () => { }) test.describe('Withdraw USDC from sDAI', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -97,10 +100,10 @@ test.describe('Withdraw USDC from sDAI', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSDaiButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.selectAssetAction('USDC') await withdrawDialog.clickMaxAmountAction() }) @@ -117,32 +120,31 @@ test.describe('Withdraw USDC from sDAI', () => { routeItems: [ { tokenAmount: '10,000.00 sDAI', - tokenUsdValue: '$11,085.91', + tokenUsdValue: '$11,255.99', }, { - tokenAmount: '11,085.91 DAI', - tokenUsdValue: '$11,085.91', + tokenAmount: '11,255.99 DAI', + tokenUsdValue: '$11,255.99', }, { - tokenAmount: '11,085.91 USDC', - tokenUsdValue: '$11,085.91', + tokenAmount: '11,255.99 USDC', + tokenUsdValue: '$11,255.99', }, ], - outcome: '11,085.91 USDC', - outcomeUsd: '$11,085.91', + outcome: '11,255.99 USDC', + outcomeUsd: '$11,255.99', }) await withdrawDialog.expectUpgradeSwitchToBeHidden() }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() - await savingsPage.expectOpportunityStablecoinsAmount('~$11,085.91') - await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '11,085.91') + await savingsPage.expectOpportunityStablecoinsAmount('~$11,255.99') + await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '11,255.99') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxUSDS.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxUSDS.test-e2e.ts index 129100da9..82ea1b76a 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxUSDS.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawMaxUSDS.test-e2e.ts @@ -1,19 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Withdraw USDS from sUSDS', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -24,16 +25,16 @@ test.describe('Withdraw USDS from sUSDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('USDS') - const depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + const depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) - await depositDialog.actionsContainer.acceptAllActionsAction(2, fork) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.clickBackToSavingsButton() await savingsPage.clickWithdrawSUsdsButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.clickMaxAmountAction() }) @@ -47,7 +48,7 @@ test.describe('Withdraw USDS from sUSDS', () => { await withdrawDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '9,999.77 sUSDS', + tokenAmount: '9,830.34 sUSDS', tokenUsdValue: '$10,000.00', }, { @@ -63,8 +64,7 @@ test.describe('Withdraw USDS from sUSDS', () => { }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(1) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() @@ -75,12 +75,15 @@ test.describe('Withdraw USDS from sUSDS', () => { }) test.describe('Withdraw USDS from sDAI', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -91,10 +94,10 @@ test.describe('Withdraw USDS from sDAI', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSDaiButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.selectAssetAction('USDS') await withdrawDialog.clickMaxAmountAction() }) @@ -111,32 +114,31 @@ test.describe('Withdraw USDS from sDAI', () => { routeItems: [ { tokenAmount: '10,000.00 sDAI', - tokenUsdValue: '$11,085.91', + tokenUsdValue: '$11,255.99', }, { - tokenAmount: '11,085.91 DAI', - tokenUsdValue: '$11,085.91', + tokenAmount: '11,255.99 DAI', + tokenUsdValue: '$11,255.99', }, { - tokenAmount: '11,085.91 USDS', - tokenUsdValue: '$11,085.91', + tokenAmount: '11,255.99 USDS', + tokenUsdValue: '$11,255.99', }, ], - outcome: '11,085.91 USDS', - outcomeUsd: '$11,085.91', + outcome: '11,255.99 USDS', + outcomeUsd: '$11,255.99', }) await withdrawDialog.expectUpgradeSwitchToBeHidden() }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() - await savingsPage.expectOpportunityStablecoinsAmount('~$11,085.91') - await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '11,085.91') + await savingsPage.expectOpportunityStablecoinsAmount('~$11,255.99') + await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '11,255.99') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawUSDC.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawUSDC.test-e2e.ts index 6874b89b8..bf58c3d99 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawUSDC.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawUSDC.test-e2e.ts @@ -1,19 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Withdraw USDC from sUSDS', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -24,16 +25,16 @@ test.describe('Withdraw USDC from sUSDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('USDC') - const depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + const depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) - await depositDialog.actionsContainer.acceptAllActionsAction(2, fork) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.clickBackToSavingsButton() await savingsPage.clickWithdrawSUsdsButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.selectAssetAction('USDC') await withdrawDialog.fillAmountAction(1000) }) @@ -49,7 +50,7 @@ test.describe('Withdraw USDC from sUSDS', () => { await withdrawDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '999.98 sUSDS', + tokenAmount: '983.03 sUSDS', tokenUsdValue: '$1,000.00', }, { @@ -69,24 +70,26 @@ test.describe('Withdraw USDC from sUSDS', () => { }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '8,999.79 sUSDS', estimatedUsdsValue: '9,000' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '8,847.31 sUSDS', estimatedUsdsValue: '9,000.000373' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '1,000') }) }) test.describe('Withdraw USDC from sDAI', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -97,10 +100,10 @@ test.describe('Withdraw USDC from sDAI', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSDaiButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.selectAssetAction('USDC') await withdrawDialog.fillAmountAction(1000) }) @@ -116,7 +119,7 @@ test.describe('Withdraw USDC from sDAI', () => { await withdrawDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '902.05 sDAI', + tokenAmount: '888.42 sDAI', tokenUsdValue: '$1,000.00', }, { @@ -136,13 +139,12 @@ test.describe('Withdraw USDC from sDAI', () => { }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '9,097.95 sDAI', estimatedDaiValue: '10,085.90' }) + await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '9,111.58 sDAI', estimatedDaiValue: '10,255.992013' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDC', '1,000') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawUSDS.test-e2e.ts b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawUSDS.test-e2e.ts index 2d2143a3e..0382178d0 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawUSDS.test-e2e.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/e2e/mainnet/WithdrawUSDS.test-e2e.ts @@ -1,19 +1,20 @@ -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { SavingsDialogPageObject } from '../../../common/e2e/SavingsDialog.PageObject' test.describe('Withdraw USDS from sUSDS', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -24,16 +25,16 @@ test.describe('Withdraw USDS from sUSDS', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('USDS') - const depositDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + const depositDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositDialog.fillAmountAction(10_000) - await depositDialog.actionsContainer.acceptAllActionsAction(2, fork) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.clickBackToSavingsButton() await savingsPage.clickWithdrawSUsdsButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.fillAmountAction(1000) }) @@ -47,7 +48,7 @@ test.describe('Withdraw USDS from sUSDS', () => { await withdrawDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '999.98 sUSDS', + tokenAmount: '983.03 sUSDS', tokenUsdValue: '$1,000.00', }, { @@ -63,24 +64,26 @@ test.describe('Withdraw USDS from sUSDS', () => { }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(1) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '8,999.79 sUSDS', estimatedUsdsValue: '9,000' }) + await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '8,847.31 sUSDS', estimatedUsdsValue: '9,000.000187' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '1,000') }) }) test.describe('Withdraw USDS from sDAI', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let savingsPage: SavingsPageObject let withdrawDialog: SavingsDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -91,10 +94,10 @@ test.describe('Withdraw USDS from sDAI', () => { }, }) - savingsPage = new SavingsPageObject(page) + savingsPage = new SavingsPageObject(testContext) await savingsPage.clickWithdrawSDaiButtonAction() - withdrawDialog = new SavingsDialogPageObject({ page, type: 'withdraw' }) + withdrawDialog = new SavingsDialogPageObject({ testContext, type: 'withdraw' }) await withdrawDialog.selectAssetAction('USDS') await withdrawDialog.fillAmountAction(1000) }) @@ -110,7 +113,7 @@ test.describe('Withdraw USDS from sDAI', () => { await withdrawDialog.expectNativeRouteTransactionOverview({ routeItems: [ { - tokenAmount: '902.05 sDAI', + tokenAmount: '888.42 sDAI', tokenUsdValue: '$1,000.00', }, { @@ -130,13 +133,12 @@ test.describe('Withdraw USDS from sDAI', () => { }) test('executes withdraw', async () => { - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2, fork) + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) await withdrawDialog.expectSuccessPage() await withdrawDialog.clickBackToSavingsButton() - await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '9,097.95 sDAI', estimatedDaiValue: '10,085.90' }) + await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '9,111.58 sDAI', estimatedDaiValue: '10,255.992013' }) await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '1,000') }) }) diff --git a/packages/app/src/features/dialogs/savings/withdraw/logic/getFormFieldsForWithdrawDialog.ts b/packages/app/src/features/dialogs/savings/withdraw/logic/getFormFieldsForWithdrawDialog.ts index 75b77465e..f8fc1ed25 100644 --- a/packages/app/src/features/dialogs/savings/withdraw/logic/getFormFieldsForWithdrawDialog.ts +++ b/packages/app/src/features/dialogs/savings/withdraw/logic/getFormFieldsForWithdrawDialog.ts @@ -21,7 +21,6 @@ export function getFormFieldsForWithdrawDialog({ form.setValue('symbol', newSymbol) form.setValue('value', '') form.setValue('isMaxSelected', false) - form.clearErrors() } diff --git a/packages/app/src/features/dialogs/withdraw/WithdrawDialog.test-e2e.ts b/packages/app/src/features/dialogs/withdraw/WithdrawDialog.test-e2e.ts index 4b167bfc2..769290b01 100644 --- a/packages/app/src/features/dialogs/withdraw/WithdrawDialog.test-e2e.ts +++ b/packages/app/src/features/dialogs/withdraw/WithdrawDialog.test-e2e.ts @@ -1,30 +1,24 @@ -import { test } from '@playwright/test' -import { mainnet } from 'viem/chains' - import { withdrawalValidationIssueToMessage } from '@/domain/market-validators/validateWithdraw' -import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { BorrowPageObject } from '@/pages/Borrow.PageObject' import { MyPortfolioPageObject } from '@/pages/MyPortfolio.PageObject' import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' -import { setup } from '@/test/e2e/setup' -import { screenshot } from '@/test/e2e/utils' - +import { TestContext, setup } from '@/test/e2e/setup' +import { test } from '@playwright/test' +import { mainnet } from 'viem/chains' import { CollateralDialogPageObject } from '../collateral/CollateralDialog.PageObject' import { DialogPageObject } from '../common/Dialog.PageObject' import { EModeDialogPageObject } from '../e-mode/EModeDialog.PageObject' import { withdrawValidationIssueToMessage } from '../savings/withdraw/logic/validation' -const headerRegExp = /Withdr*/ - test.describe('Withdraw dialog', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) const initialBalances = { wstETH: 100, rETH: 100, ETH: 100, } + const header = /Withdr*/ + test.describe('Position with deposit and borrow', () => { const initialDeposits = { wstETH: 2, @@ -32,8 +26,15 @@ test.describe('Withdraw dialog', () => { } as const const daiToBorrow = 3500 + let withdrawDialog: DialogPageObject + let myPortfolioPage: MyPortfolioPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -41,11 +42,13 @@ test.describe('Withdraw dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositAssetsActions(initialDeposits, daiToBorrow) + const borrowPage = new BorrowPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + withdrawDialog = new DialogPageObject({ testContext, header }) + + await borrowPage.depositAssetsActions({ assetsToDeposit: initialDeposits, daiToBorrow }) await borrowPage.viewInMyPortfolioAction() - const myPortfolioPage = new MyPortfolioPageObject(page) // @todo This waits for the refetch of the data after successful borrow transaction to happen. // This is no ideal, probably we need to refactor expectDepositTable so it takes advantage from // playwright's timeouts instead of parsing it's current state. Then we would be able to @@ -53,66 +56,44 @@ test.describe('Withdraw dialog', () => { await myPortfolioPage.expectAssetToBeInDepositTable('DAI') }) - test('opens dialog with selected asset', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('opens dialog with selected asset', async () => { await myPortfolioPage.clickWithdrawButtonAction('rETH') - const withdrawDialog = new DialogPageObject(page, headerRegExp) await withdrawDialog.expectSelectedAsset('rETH') await withdrawDialog.expectDialogHeader('Withdraw rETH') await withdrawDialog.expectHealthFactorBeforeVisible() - - await screenshot(withdrawDialog.getDialog(), 'withdraw-dialog-default-view') }) - test('calculates health factor changes correctly', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('calculates health factor changes correctly', async () => { await myPortfolioPage.clickWithdrawButtonAction('rETH') - const withdrawDialog = new DialogPageObject(page, headerRegExp) await withdrawDialog.fillAmountAction(1) - - await withdrawDialog.expectRiskLevelBefore('Moderate') - await withdrawDialog.expectHealthFactorBefore('2.32') - await withdrawDialog.expectRiskLevelAfter('Risky') - await withdrawDialog.expectHealthFactorAfter('1.76') - - // @note this is needed for deterministic screenshots - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectEnabledActionAtIndex(0) - - await screenshot(withdrawDialog.getDialog(), 'withdraw-dialog-health-factor') + await withdrawDialog.expectRiskLevelBefore('Healthy') + await withdrawDialog.expectHealthFactorBefore('4.15') + await withdrawDialog.expectRiskLevelAfter('Healthy') + await withdrawDialog.expectHealthFactorAfter('3.14') }) - test('has correct action plan for erc-20', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) - + test('has correct action plan for erc-20', async () => { await myPortfolioPage.clickWithdrawButtonAction('rETH') - const withdrawDialog = new DialogPageObject(page, headerRegExp) await withdrawDialog.fillAmountAction(1) - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectActions([{ type: 'withdraw', asset: 'rETH' }]) + await withdrawDialog.actionsContainer.expectActions([{ type: 'withdraw', asset: 'rETH' }]) }) - test('can withdraw erc-20', async ({ page }) => { + test('can withdraw erc-20', async () => { const withdraw = { asset: 'rETH', amount: 1, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickWithdrawButtonAction(withdraw.asset) - const withdrawDialog = new DialogPageObject(page, headerRegExp) await withdrawDialog.fillAmountAction(withdraw.amount) - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) - await withdrawDialog.expectSuccessPage([withdraw], fork) - - await screenshot(withdrawDialog.getDialog(), 'withdraw-dialog-erc-20-success') - + await withdrawDialog.actionsContainer.acceptAllActionsAction(1) + await withdrawDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'rETH', amount: '1.00', usdValue: '$4,413.26' }], + }) await withdrawDialog.viewInMyPortfolioAction() await myPortfolioPage.expectDepositTable({ @@ -129,8 +110,15 @@ test.describe('Withdraw dialog', () => { } as const const daiToBorrow = 4500 + let withdrawDialog: DialogPageObject + let myPortfolioPage: MyPortfolioPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -138,44 +126,34 @@ test.describe('Withdraw dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositAssetsActions(initialDeposits, daiToBorrow) + const borrowPage = new BorrowPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + withdrawDialog = new DialogPageObject({ testContext, header }) + + await borrowPage.depositAssetsActions({ assetsToDeposit: initialDeposits, daiToBorrow }) await borrowPage.viewInMyPortfolioAction() - const myPortfolioPage = new MyPortfolioPageObject(page) - // @todo This waits for the refetch of the data after successful borrow transaction to happen. - // This is no ideal, probably we need to refactor expectDepositTable so it takes advantage from - // playwright's timeouts instead of parsing it's current state. Then we would be able to - // easily wait for the table to be updated. await myPortfolioPage.expectAssetToBeInDepositTable('DAI') }) - test('cannot withdraw amount that will result in health factor under 1', async ({ page }) => { + test('cannot withdraw amount that will result in health factor under 1', async () => { const withdrawAsset = 'wstETH' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.expectDepositTable(initialDeposits) await myPortfolioPage.clickWithdrawButtonAction(withdrawAsset) - const withdrawDialog = new DialogPageObject(page, headerRegExp) - await withdrawDialog.expectHealthFactorBefore('2.75') + await withdrawDialog.expectHealthFactorBefore('4.93') await withdrawDialog.fillAmountAction(initialDeposits[withdrawAsset] - 0.1) // we subtract small amount to ensure that we have enough balance in test, which may not be the case due to timestamp issues await withdrawDialog.expectAssetInputError('Remaining collateral cannot support the loan') - - await screenshot(withdrawDialog.getDialog(), 'withdraw-dialog-cannot-support-loan') }) - test('cannot withdraw more than deposited', async ({ page }) => { + test('cannot withdraw more than deposited', async () => { const withdrawAsset = 'rETH' - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.expectDepositTable(initialDeposits) await myPortfolioPage.clickWithdrawButtonAction(withdrawAsset) - const withdrawDialog = new DialogPageObject(page, headerRegExp) - await withdrawDialog.expectHealthFactorBefore('2.75') + await withdrawDialog.expectHealthFactorBefore('4.93') await withdrawDialog.fillAmountAction(initialDeposits[withdrawAsset] + 1) await withdrawDialog.expectAssetInputError(withdrawalValidationIssueToMessage['exceeds-balance']) - - await screenshot(withdrawDialog.getDialog(), 'withdraw-dialog-more-than-deposited') }) }) @@ -189,8 +167,15 @@ test.describe('Withdraw dialog', () => { amount: 1000, } + let withdrawDialog: DialogPageObject + let myPortfolioPage: MyPortfolioPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -198,68 +183,56 @@ test.describe('Withdraw dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) - const actionsContainer = new ActionsPageObject(page) + const borrowPage = new BorrowPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + withdrawDialog = new DialogPageObject({ testContext, header }) + await borrowPage.fillDepositAssetAction(0, ETHdeposit.asset, ETHdeposit.amount) await borrowPage.fillBorrowAssetAction(borrow.amount) - await borrowPage.submitAction() + await borrowPage.actionsContainer.acceptAllActionsAction(2) + await borrowPage.expectSuccessPage({ + deposited: [{ asset: 'ETH', amount: '10.00', usdValue: '$39,283.13' }], + borrowed: { asset: 'DAI', amount: '1,000.00', usdValue: '$1,000.00' }, + }) - await actionsContainer.acceptAllActionsAction(2) - - await borrowPage.expectSuccessPage([ETHdeposit], borrow, fork) - - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.goToMyPortfolioAction() }) // @note When ETH is deposited, deposit table shows WETH instead of ETH - test('has correct action plan for native asset', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) - + test('has correct action plan for native asset', async () => { await myPortfolioPage.clickWithdrawButtonAction('WETH') - const withdrawDialog = new DialogPageObject(page, headerRegExp) await withdrawDialog.selectAssetAction('ETH') await withdrawDialog.fillAmountAction(1) await withdrawDialog.expectHealthFactorVisible() - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectActions([ + await withdrawDialog.actionsContainer.expectActions([ { type: 'approve', asset: 'aWETH' }, { type: 'withdraw', asset: 'ETH' }, ]) - - await screenshot(withdrawDialog.getDialog(), 'withdraw-dialog-eth-action-plan') }) // @note When ETH is deposited, deposit table shows WETH instead of ETH - test('can withdraw native asset', async ({ page }) => { + test('can withdraw native asset', async () => { const withdrawAmount = 1 - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.clickWithdrawButtonAction('WETH') - const withdrawDialog = new DialogPageObject(page, headerRegExp) await withdrawDialog.selectAssetAction('ETH') await withdrawDialog.fillAmountAction(withdrawAmount) - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await withdrawDialog.expectSuccessPage( - [ + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) + await withdrawDialog.expectSuccessPage({ + tokenWithValue: [ { asset: 'ETH', - amount: withdrawAmount, + amount: '1.00', + usdValue: '$3,928.31', }, ], - fork, - ) - await screenshot(withdrawDialog.getDialog(), 'withdraw-dialog-eth-success') - + }) await withdrawDialog.viewInMyPortfolioAction() await myPortfolioPage.expectDepositTable({ - // @todo Figure out how WETH and ETH conversion should work WETH: ETHdeposit.amount - withdrawAmount, }) }) @@ -271,8 +244,15 @@ test.describe('Withdraw dialog', () => { ETH: 2, } as const + let withdrawDialog: DialogPageObject + let myPortfolioPage: MyPortfolioPageObject + test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -280,7 +260,9 @@ test.describe('Withdraw dialog', () => { }, }) - const borrowPage = new BorrowPageObject(page) + const borrowPage = new BorrowPageObject(testContext) + myPortfolioPage = new MyPortfolioPageObject(testContext) + withdrawDialog = new DialogPageObject({ testContext, header }) // to simulate a position with only deposits, we go through the easy borrow flow // but interrupt it before the borrow action, going directly to the myPortfolio // this way we have deposit transactions executed, but no borrow transaction @@ -291,31 +273,25 @@ test.describe('Withdraw dialog', () => { await borrowPage.fillDepositAssetAction(1, 'ETH', initialDeposits.ETH) await borrowPage.submitAction() - const actionsContainer = new ActionsPageObject(page) - await actionsContainer.acceptAllActionsAction(3) - await actionsContainer.expectEnabledActionAtIndex(3) + await borrowPage.actionsContainer.acceptAllActionsAction(3) + await borrowPage.actionsContainer.expectEnabledActionAtIndex(3) - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.goToMyPortfolioAction() }) - test('can withdraw erc-20', async ({ page }) => { + test('can withdraw erc-20', async () => { const withdraw = { asset: 'wstETH', amount: 1, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.clickWithdrawButtonAction(withdraw.asset) - const withdrawDialog = new DialogPageObject(page, headerRegExp) await withdrawDialog.fillAmountAction(withdraw.amount) - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) - await withdrawDialog.expectSuccessPage([withdraw], fork) - - await screenshot(withdrawDialog.getDialog(), 'withdraw-dialog-only-deposit-erc-20-success') - + await withdrawDialog.actionsContainer.acceptAllActionsAction(1) + await withdrawDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'wstETH', amount: '1.00', usdValue: '$4,665.46' }], + }) await withdrawDialog.viewInMyPortfolioAction() await myPortfolioPage.expectDepositTable({ @@ -324,23 +300,19 @@ test.describe('Withdraw dialog', () => { }) }) - test('can fully withdraw erc-20', async ({ page }) => { + test('can fully withdraw erc-20', async () => { const withdraw = { asset: 'wstETH', amount: 10, } as const - const myPortfolioPage = new MyPortfolioPageObject(page) await myPortfolioPage.clickWithdrawButtonAction(withdraw.asset) - const withdrawDialog = new DialogPageObject(page, headerRegExp) await withdrawDialog.clickMaxAmountAction() - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) - await withdrawDialog.expectSuccessPage([withdraw], fork) - - await screenshot(withdrawDialog.getDialog(), 'withdraw-dialog-only-deposit-erc-20-success') - + await withdrawDialog.actionsContainer.acceptAllActionsAction(1) + await withdrawDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'wstETH', amount: '10.00', usdValue: '$46,654.64' }], + }) await withdrawDialog.viewInMyPortfolioAction() await myPortfolioPage.expectDepositTable({ @@ -349,40 +321,22 @@ test.describe('Withdraw dialog', () => { }) }) - test('does not display health factor', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('does not display health factor', async () => { await myPortfolioPage.clickWithdrawButtonAction('wstETH') - const withdrawDialog = new DialogPageObject(page, headerRegExp) await withdrawDialog.fillAmountAction(1) - await withdrawDialog.expectHealthFactorNotVisible() - - // @note this is needed for deterministic screenshots - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.expectEnabledActionAtIndex(0) - - await screenshot(withdrawDialog.getDialog(), 'withdraw-dialog-only-deposit-health-factor') }) - test('can fully withdraw native asset', async ({ page }) => { - const myPortfolioPage = new MyPortfolioPageObject(page) + test('can fully withdraw native asset', async () => { await myPortfolioPage.clickWithdrawButtonAction('WETH') - const withdrawDialog = new DialogPageObject(page, headerRegExp) await withdrawDialog.selectAssetAction('ETH') await withdrawDialog.clickMaxAmountAction() - const actionsContainer = new ActionsPageObject(withdrawDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(2) - await withdrawDialog.expectSuccessPage( - [ - { - asset: 'ETH', - amount: initialDeposits.ETH, - }, - ], - fork, - ) + await withdrawDialog.actionsContainer.acceptAllActionsAction(2) + await withdrawDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'ETH', amount: '2.00', usdValue: '$7,856.63' }], + }) await withdrawDialog.viewInMyPortfolioAction() @@ -394,11 +348,16 @@ test.describe('Withdraw dialog', () => { }) test.describe('Liquidation risk warning', () => { + let testContext: TestContext<'connected-random'> let withdrawDialog: DialogPageObject let myPortfolioPage: MyPortfolioPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -406,18 +365,20 @@ test.describe('Withdraw dialog', () => { }, }) - withdrawDialog = new DialogPageObject(page, headerRegExp) - myPortfolioPage = new MyPortfolioPageObject(page) + withdrawDialog = new DialogPageObject({ testContext, header }) + myPortfolioPage = new MyPortfolioPageObject(testContext) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ rETH: 2, wstETH: 10 }) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: { rETH: 2, wstETH: 10 } }) await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.clickBorrowButtonAction('WETH') - const borrowDialog = new DialogPageObject(page, /Borrow/) + const borrowDialog = new DialogPageObject({ testContext, header: /Borrow/ }) await borrowDialog.fillAmountAction(7) await borrowDialog.actionsContainer.acceptAllActionsAction(1) - await borrowDialog.expectSuccessPage([{ asset: 'WETH', amount: 7 }], fork) + await borrowDialog.expectSuccessPage({ + tokenWithValue: [{ asset: 'WETH', amount: '7.00', usdValue: '$27,498.19' }], + }) await borrowDialog.viewInMyPortfolioAction() await myPortfolioPage.expectAssetToBeInBorrowTable('WETH') }) @@ -456,17 +417,19 @@ test.describe('Withdraw dialog', () => { await withdrawDialog.expectLiquidationRiskWarningNotVisible() }) - test('hf in danger zone; asset not collateral; risk warning is not shown', async ({ page }) => { + test('hf in danger zone; asset not collateral; risk warning is not shown', async () => { // disabling collateral and entering danger zone await myPortfolioPage.clickCollateralSwitchAction('rETH') - const collateralDialog = new CollateralDialogPageObject(page) + + const collateralDialog = new CollateralDialogPageObject(testContext) await collateralDialog.clickAcknowledgeRisk() await collateralDialog.actionsContainer.acceptAllActionsAction(1) await collateralDialog.expectSetUseAsCollateralSuccessPage('rETH', 'disabled') + await myPortfolioPage.goToMyPortfolioAction() await myPortfolioPage.expectCollateralSwitch('rETH', false) - await myPortfolioPage.clickWithdrawButtonAction('rETH') + await withdrawDialog.clickMaxAmountAction() await withdrawDialog.actionsContainer.expectEnabledActionAtIndex(0) await withdrawDialog.expectLiquidationRiskWarningNotVisible() @@ -478,26 +441,33 @@ test.describe('Withdraw dialog', () => { let borrowDialog: DialogPageObject let depositDialog: DialogPageObject let myPortfolioPage: MyPortfolioPageObject + let collateralDialog: CollateralDialogPageObject + let testContext: TestContext<'connected-random'> test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'myPortfolio', account: { type: 'connected-random', - assetBalances: { ETH: 10, wstETH: 5, rETH: 1, WBTC: 1 }, + assetBalances: { ETH: 10, wstETH: 5, rETH: 1, cbBTC: 1 }, }, }) - withdrawDialog = new DialogPageObject(page, headerRegExp) - myPortfolioPage = new MyPortfolioPageObject(page) - borrowDialog = new DialogPageObject(page, /Borrow/) + withdrawDialog = new DialogPageObject({ testContext, header }) + myPortfolioPage = new MyPortfolioPageObject(testContext) + borrowDialog = new DialogPageObject({ testContext, header: /Borrow/ }) + depositDialog = new DialogPageObject({ testContext, header: /Deposit/ }) + collateralDialog = new CollateralDialogPageObject(testContext) await myPortfolioPage.clickDepositButtonAction('wstETH') - depositDialog = new DialogPageObject(page, /Deposit/) await depositDialog.fillAmountAction(5) - await depositDialog.actionsContainer.acceptAllActionsAction(2, fork) + await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectDepositedAssets(13_104.84) + await myPortfolioPage.expectDepositedAssets('$23.33K') }) test('withdraws amount up to HF 1.01', async () => { @@ -505,99 +475,96 @@ test.describe('Withdraw dialog', () => { await borrowDialog.fillAmountAction(5000) await borrowDialog.actionsContainer.acceptAllActionsAction(1) await borrowDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectHealthFactor('2.08') + await myPortfolioPage.expectHealthFactor('3.73') await myPortfolioPage.clickWithdrawButtonAction('wstETH') await withdrawDialog.clickMaxAmountAction() await withdrawDialog.clickAcknowledgeRisk() - await withdrawDialog.expectInputValue('2.576392') - await withdrawDialog.expectHealthFactorBefore('2.08') + await withdrawDialog.expectInputValue('3.646973') + await withdrawDialog.expectHealthFactorBefore('3.73') await withdrawDialog.expectHealthFactorAfter('1.01') await withdrawDialog.actionsContainer.expectActions([{ type: 'withdraw', asset: 'wstETH' }]) await withdrawDialog.actionsContainer.expectEnabledActionAtIndex(0) }) test('works for collaterals with different liquidation thresholds', async () => { - await myPortfolioPage.clickDepositButtonAction('WBTC') + await myPortfolioPage.clickDepositButtonAction('cbBTC') await depositDialog.fillAmountAction(1) await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectDepositedAssets(54_910) + await myPortfolioPage.expectDepositedAssets('$125K') await myPortfolioPage.clickBorrowButtonAction('DAI') await borrowDialog.fillAmountAction(35000) - await borrowDialog.clickAcknowledgeRisk() await borrowDialog.actionsContainer.acceptAllActionsAction(1) await borrowDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectHealthFactor('1.19') + await myPortfolioPage.expectHealthFactor('2.71') - await myPortfolioPage.clickWithdrawButtonAction('WBTC') + await myPortfolioPage.clickWithdrawButtonAction('cbBTC') await withdrawDialog.clickMaxAmountAction() await withdrawDialog.clickAcknowledgeRisk() - await withdrawDialog.expectInputValue('0.204922') - await withdrawDialog.expectHealthFactorBefore('1.19') + await withdrawDialog.expectInputValue('0.781174') + await withdrawDialog.expectHealthFactorBefore('2.71') await withdrawDialog.expectHealthFactorAfter('1.01') - await withdrawDialog.actionsContainer.expectActions([{ type: 'withdraw', asset: 'WBTC' }]) + await withdrawDialog.actionsContainer.expectActions([{ type: 'withdraw', asset: 'cbBTC' }]) await withdrawDialog.actionsContainer.expectEnabledActionAtIndex(0) }) - test('works in e-mode', async ({ page }) => { + test('works in e-mode', async () => { await myPortfolioPage.clickBorrowButtonAction('WETH') await borrowDialog.fillAmountAction(2) await borrowDialog.actionsContainer.acceptAllActionsAction(1) await borrowDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectHealthFactor('2.3') + await myPortfolioPage.expectHealthFactor('2.38') await myPortfolioPage.clickEModeButtonAction() - const eModeDialog = new EModeDialogPageObject(page) + const eModeDialog = new EModeDialogPageObject(testContext) await eModeDialog.clickEModeCategoryTileAction('ETH Correlated') await eModeDialog.actionsContainer.acceptAllActionsAction(1) await eModeDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectHealthFactor('2.69') + await myPortfolioPage.expectHealthFactor('2.76') await myPortfolioPage.clickWithdrawButtonAction('wstETH') await withdrawDialog.clickMaxAmountAction() await withdrawDialog.clickAcknowledgeRisk() - await withdrawDialog.expectInputValue('3.119467') - await withdrawDialog.expectHealthFactorBefore('2.69') + await withdrawDialog.expectInputValue('3.171143') + await withdrawDialog.expectHealthFactorBefore('2.76') await withdrawDialog.expectHealthFactorAfter('1.01') await withdrawDialog.actionsContainer.expectActions([{ type: 'withdraw', asset: 'wstETH' }]) await withdrawDialog.actionsContainer.expectEnabledActionAtIndex(0) }) - test('works for asset with usage as collateral disabled', async ({ page }) => { + test('works for asset with usage as collateral disabled', async () => { await myPortfolioPage.clickBorrowButtonAction('DAI') await borrowDialog.clickMaxAmountAction() await borrowDialog.clickAcknowledgeRisk() await borrowDialog.actionsContainer.acceptAllActionsAction(1) await borrowDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectHealthFactor('1.17') + await myPortfolioPage.expectHealthFactor('1.02') await myPortfolioPage.clickDepositButtonAction('rETH') - const depositDialog = new DialogPageObject(page, /Deposit/) await depositDialog.fillAmountAction(1) await depositDialog.actionsContainer.acceptAllActionsAction(2) await depositDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectHealthFactor('1.39') + await myPortfolioPage.expectHealthFactor('1.22') await myPortfolioPage.clickCollateralSwitchAction('rETH') - const collateralDialog = new CollateralDialogPageObject(page) await collateralDialog.clickAcknowledgeRisk() - await collateralDialog.setUseAsCollateralAction('rETH', 'disabled') + await collateralDialog.setUseAsCollateralAction({ assetName: 'rETH', setting: 'disabled' }) await myPortfolioPage.goToMyPortfolioAction() - await myPortfolioPage.expectHealthFactor('1.17') + await myPortfolioPage.expectHealthFactor('1.02') await myPortfolioPage.clickWithdrawButtonAction('rETH') await withdrawDialog.clickMaxAmountAction() await withdrawDialog.expectInputValue('1') await withdrawDialog.expectMaxButtonDisabled() - await withdrawDialog.expectHealthFactorBefore('1.17') - await withdrawDialog.expectHealthFactorAfter('1.17') + await withdrawDialog.expectHealthFactorBefore('1.02') + await withdrawDialog.expectHealthFactorAfter('1.02') await withdrawDialog.actionsContainer.expectActions([{ type: 'withdraw', asset: 'rETH' }]) await withdrawDialog.actionsContainer.expectEnabledActionAtIndex(0) }) @@ -606,9 +573,9 @@ test.describe('Withdraw dialog', () => { await myPortfolioPage.clickDepositButtonAction('WETH') await depositDialog.selectAssetAction('ETH') await depositDialog.fillAmountAction(5) - await depositDialog.actionsContainer.acceptAllActionsAction(1, fork) + await depositDialog.actionsContainer.acceptAllActionsAction(1) await depositDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectDepositedAssets(24_450) + await myPortfolioPage.expectDepositedAssets('$42.97K') await myPortfolioPage.clickWithdrawButtonAction('WETH') await withdrawDialog.selectAssetAction('ETH') @@ -619,7 +586,7 @@ test.describe('Withdraw dialog', () => { { type: 'withdraw', asset: 'ETH' }, ]) - await withdrawDialog.actionsContainer.acceptActionAtIndex(0, fork) + await withdrawDialog.actionsContainer.acceptActionAtIndex(0) await withdrawDialog.actionsContainer.expectEnabledActionAtIndex(1) await withdrawDialog.closeDialog() @@ -628,16 +595,16 @@ test.describe('Withdraw dialog', () => { await depositDialog.fillAmountAction(4) await depositDialog.actionsContainer.acceptAllActionsAction(1) await depositDialog.viewInMyPortfolioAction() - await myPortfolioPage.expectDepositedAssets(33_530) + await myPortfolioPage.expectDepositedAssets('$58.68K') // following checks leverage the fact that approval is cached, therefore we input different values to estimate the approval value await myPortfolioPage.clickWithdrawButtonAction('WETH') await withdrawDialog.selectAssetAction('ETH') - await withdrawDialog.fillAmountAction(5.000001) + await withdrawDialog.fillAmountAction(5.000004) await withdrawDialog.actionsContainer.expectEnabledActionAtIndex(1) - await withdrawDialog.fillAmountAction(5.000003) + await withdrawDialog.fillAmountAction(5.000005) await withdrawDialog.actionsContainer.expectEnabledActionAtIndex(1) - await withdrawDialog.fillAmountAction(5.000004) + await withdrawDialog.fillAmountAction(5.00006) await withdrawDialog.actionsContainer.expectEnabledActionAtIndex(0) }) }) diff --git a/packages/app/src/features/dialogs/withdraw/logic/form.ts b/packages/app/src/features/dialogs/withdraw/logic/form.ts index d05f1c6ab..0c2a20ee4 100644 --- a/packages/app/src/features/dialogs/withdraw/logic/form.ts +++ b/packages/app/src/features/dialogs/withdraw/logic/form.ts @@ -68,6 +68,7 @@ export function getFormFieldsForWithdrawDialog( const changeAsset = (newSymbol: TokenSymbol): void => { form.setValue('symbol', newSymbol) form.setValue('value', '') + form.setValue('isMaxSelected', false) form.clearErrors() } diff --git a/packages/app/src/features/farm-details/FarmDetails.PageObject.ts b/packages/app/src/features/farm-details/FarmDetails.PageObject.ts index 54f461cb3..57f5925c9 100644 --- a/packages/app/src/features/farm-details/FarmDetails.PageObject.ts +++ b/packages/app/src/features/farm-details/FarmDetails.PageObject.ts @@ -1,8 +1,9 @@ import { BasePageObject } from '@/test/e2e/BasePageObject' import { AssetsInTests, TOKENS_ON_FORK } from '@/test/e2e/constants' -import { ForkContext } from '@/test/e2e/forking/setupFork' import { getTokenBalance } from '@/test/e2e/utils' import { testIds } from '@/ui/utils/testIds' +import { getUrlFromClient } from '@marsfoundation/common-testnets' +import { NormalizedUnitNumber } from '@marsfoundation/common-universal' import { Locator, expect } from '@playwright/test' import { Address } from 'viem' @@ -54,26 +55,22 @@ export class FarmDetailsPageObject extends BasePageObject { } async expectTokenBalance({ - fork, symbol, - minBalance, - maxBalance, + balance, address, }: { - fork: ForkContext symbol: AssetsInTests - minBalance: number - maxBalance: number + balance: NormalizedUnitNumber address: Address }): Promise { - const token: { address: Address; decimals: number } = (TOKENS_ON_FORK as any)[fork.chainId][symbol] - const balance = await getTokenBalance({ + const chainId = await this.testContext.testnetController.client.getChainId() + const token: { address: Address; decimals: number } = (TOKENS_ON_FORK as any)[chainId][symbol] + const actualBalance = await getTokenBalance({ address, - forkUrl: fork.forkUrl, + forkUrl: getUrlFromClient(this.testContext.testnetController.client), token, }) - expect(balance.toNumber()).toBeGreaterThanOrEqual(minBalance) - expect(balance.toNumber()).toBeLessThanOrEqual(maxBalance) + expect(balance.eq(actualBalance)).toBe(true) } async expectPointsSyncWarning(): Promise { diff --git a/packages/app/src/features/farm-details/dialogs/claim/ClaimDialog.PageObject.ts b/packages/app/src/features/farm-details/dialogs/claim/ClaimDialog.PageObject.ts index 1bfcedfb6..bd9125e09 100644 --- a/packages/app/src/features/farm-details/dialogs/claim/ClaimDialog.PageObject.ts +++ b/packages/app/src/features/farm-details/dialogs/claim/ClaimDialog.PageObject.ts @@ -1,10 +1,14 @@ import { DialogPageObject } from '@/features/dialogs/common/Dialog.PageObject' +import { TestContext } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' -import { Page, expect } from '@playwright/test' +import { expect } from '@playwright/test' export class ClaimDialogPageObject extends DialogPageObject { - constructor(page: Page) { - super(page, /Claim/) + constructor(testContext: TestContext) { + super({ + testContext, + header: /Claim/, + }) } // #region actions diff --git a/packages/app/src/features/farm-details/dialogs/claim/e2e/mainnet/ClaimSKY.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/claim/e2e/mainnet/ClaimSKY.test-e2e.ts index 0e7b7c4c7..3a28e05ed 100644 --- a/packages/app/src/features/farm-details/dialogs/claim/e2e/mainnet/ClaimSKY.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/claim/e2e/mainnet/ClaimSKY.test-e2e.ts @@ -1,22 +1,25 @@ import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' import { StakeDialogPageObject } from '@/features/farm-details/dialogs/stake/StakeDialog.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' +import { NormalizedUnitNumber } from '@marsfoundation/common-universal' import { test } from '@playwright/test' import { Address } from 'viem' import { mainnet } from 'viem/chains' import { ClaimDialogPageObject } from '../../ClaimDialog.PageObject' test.describe('Claim SKY rewards', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let claimDialog: ClaimDialogPageObject let account: Address test.beforeEach(async ({ page }) => { - ;({ account } = await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -29,20 +32,22 @@ test.describe('Claim SKY rewards', () => { USDS: 10_000, }, }, - })) + }) + account = testContext.account + await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - const stakeDialog = new StakeDialogPageObject(page) + const stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.fillAmountAction(10_000) await stakeDialog.actionsContainer.acceptAllActionsAction(2) await stakeDialog.clickBackToFarmAction() - await fork.progressSimulation(page, 24 * 60 * 60) // 24 hours + await testContext.testnetController.progressSimulationAndMine(24 * 60 * 60) // 24 hours await page.reload() await farmDetailsPage.clickInfoPanelClaimButtonAction() - claimDialog = new ClaimDialogPageObject(page) + claimDialog = new ClaimDialogPageObject(testContext) }) test('has correct action plan', async () => { @@ -53,9 +58,8 @@ test.describe('Claim SKY rewards', () => { test('displays transaction overview', async () => { await claimDialog.expectTransactionOverview({ reward: { - // amount is imprecise because of timing issues in e2e tests - amount: '3,539', - amountUSD: '$213', + amount: '49.44', + amountUSD: '2.98', }, }) }) @@ -68,15 +72,13 @@ test.describe('Claim SKY rewards', () => { await farmDetailsPage.expectTokenToDepositBalance('USDS', '-') await farmDetailsPage.expectReward({ - reward: '0', + reward: '0.00000', rewardUsd: '$0.00', }) await farmDetailsPage.expectTokenBalance({ address: account, - fork, symbol: 'SKY', - minBalance: 3_525, - maxBalance: 3_545, + balance: NormalizedUnitNumber('49.4365427929088'), }) await farmDetailsPage.expectStaked({ amount: '10,000.00', asset: 'USDS' }) }) diff --git a/packages/app/src/features/farm-details/dialogs/stake/StakeDialog.PageObject.ts b/packages/app/src/features/farm-details/dialogs/stake/StakeDialog.PageObject.ts index 546a238af..5b9ed7fe5 100644 --- a/packages/app/src/features/farm-details/dialogs/stake/StakeDialog.PageObject.ts +++ b/packages/app/src/features/farm-details/dialogs/stake/StakeDialog.PageObject.ts @@ -1,10 +1,14 @@ import { DialogPageObject } from '@/features/dialogs/common/Dialog.PageObject' +import { TestContext } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' -import { Page, expect } from '@playwright/test' +import { expect } from '@playwright/test' export class StakeDialogPageObject extends DialogPageObject { - constructor(page: Page) { - super(page, /Deposit/) + constructor(testContext: TestContext) { + super({ + testContext, + header: /Deposit/, + }) } // #region actions diff --git a/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeDAI.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeDAI.test-e2e.ts index 055339d1d..aa075dfb6 100644 --- a/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeDAI.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeDAI.test-e2e.ts @@ -1,6 +1,5 @@ import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' @@ -8,12 +7,15 @@ import { mainnet } from 'viem/chains' import { StakeDialogPageObject } from '../../StakeDialog.PageObject' test.describe('Stake DAI to SKY farm', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let stakeDialog: StakeDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -29,9 +31,9 @@ test.describe('Stake DAI to SKY farm', () => { }) await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.selectAssetAction('DAI') await stakeDialog.fillAmountAction(10_000) }) @@ -48,8 +50,8 @@ test.describe('Stake DAI to SKY farm', () => { test('displays transaction overview', async () => { await stakeDialog.expectTransactionOverview({ estimatedRewards: { - apy: '778.72%', - description: 'Earn ~1,291,972.67 SKY/year', + apy: '10.88%', + description: 'Earn ~18,044.13 SKY/year', }, route: { swaps: [ @@ -79,8 +81,8 @@ test.describe('Stake DAI to SKY farm', () => { await farmDetailsPage.expectTokenToDepositBalance('USDS', '-') await farmDetailsPage.expectReward({ - reward: '0.1', - rewardUsd: '<$0.01', + reward: '0.00000', + rewardUsd: '$0.00', }) await farmDetailsPage.expectStaked({ amount: '10,000.00', asset: 'USDS' }) }) diff --git a/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeSDAI.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeSDAI.test-e2e.ts index 22ef1e9f5..191c67710 100644 --- a/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeSDAI.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeSDAI.test-e2e.ts @@ -1,6 +1,5 @@ import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' @@ -8,12 +7,15 @@ import { mainnet } from 'viem/chains' import { StakeDialogPageObject } from '../../StakeDialog.PageObject' test.describe('Stake sDAI to SKY farm', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let stakeDialog: StakeDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -29,9 +31,9 @@ test.describe('Stake sDAI to SKY farm', () => { }) await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.selectAssetAction('sDAI') await stakeDialog.fillAmountAction(1_000) }) @@ -49,18 +51,18 @@ test.describe('Stake sDAI to SKY farm', () => { test('displays transaction overview', async () => { await stakeDialog.expectTransactionOverview({ estimatedRewards: { - apy: '780.23%', - description: 'Earn ~143,505.01 SKY/year', + apy: '10.88%', + description: 'Earn ~2,031.10 SKY/year', }, route: { swaps: [ { tokenAmount: '1,000.00 sDAI', - tokenUsdValue: '$1,108.59', + tokenUsdValue: '$1,125.60', }, { - tokenAmount: '1,108.59 USDS', - tokenUsdValue: '$1,108.59', + tokenAmount: '1,125.60 USDS', + tokenUsdValue: '$1,125.60', }, ], final: { @@ -68,7 +70,7 @@ test.describe('Stake sDAI to SKY farm', () => { lowerText: 'Deposited', }, }, - outcome: '1,108.59 USDS', + outcome: '1,125.60 USDS', }) }) @@ -81,9 +83,9 @@ test.describe('Stake sDAI to SKY farm', () => { await farmDetailsPage.expectTokenToDepositBalance('sDAI', '-') await farmDetailsPage.expectTokenToDepositBalance('USDS', '-') // no dust left await farmDetailsPage.expectReward({ - reward: '0.01', - rewardUsd: '<$0.01', + reward: '0.00000', + rewardUsd: '$0.00', }) - await farmDetailsPage.expectStaked({ amount: '1,108.59', asset: 'USDS' }) + await farmDetailsPage.expectStaked({ amount: '1,125.60', asset: 'USDS' }) }) }) diff --git a/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeSUSDS.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeSUSDS.test-e2e.ts index 08310fa66..a2cc3e1f8 100644 --- a/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeSUSDS.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeSUSDS.test-e2e.ts @@ -1,21 +1,23 @@ import { SavingsDialogPageObject } from '@/features/dialogs/savings/common/e2e/SavingsDialog.PageObject' import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' import { SavingsPageObject } from '@/pages/Savings.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { buildUrl, setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { StakeDialogPageObject } from '../../StakeDialog.PageObject' -test.describe('Stake sDAI to SKY farm', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) +test.describe('Stake sUSDS to SKY farm', () => { let farmDetailsPage: FarmDetailsPageObject let stakeDialog: StakeDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'savings', account: { type: 'connected-random', @@ -28,9 +30,9 @@ test.describe('Stake sDAI to SKY farm', () => { await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) // deposit some tokens to sUSDS first so we're able to withdraw them next - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.clickDepositButtonAction('USDS') - const depositToSavingsDialog = new SavingsDialogPageObject({ page, type: 'deposit' }) + const depositToSavingsDialog = new SavingsDialogPageObject({ testContext, type: 'deposit' }) await depositToSavingsDialog.clickMaxAmountAction() await depositToSavingsDialog.actionsContainer.acceptAllActionsAction(2) await depositToSavingsDialog.clickBackToSavingsButton() @@ -41,9 +43,9 @@ test.describe('Stake sDAI to SKY farm', () => { }), ) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.selectAssetAction('sUSDS') await stakeDialog.fillAmountAction(1_000) }) @@ -60,18 +62,18 @@ test.describe('Stake sDAI to SKY farm', () => { test('displays transaction overview', async () => { await stakeDialog.expectTransactionOverview({ estimatedRewards: { - apy: '780.23%', - description: 'Earn ~129,451.12 SKY/year', + apy: '10.88%', + description: 'Earn ~1,835.60 SKY/year', }, route: { swaps: [ { tokenAmount: '1,000.00 sUSDS', - tokenUsdValue: '$1,000.02', + tokenUsdValue: '$1,017.26', }, { - tokenAmount: '1,000.02 USDS', - tokenUsdValue: '$1,000.02', + tokenAmount: '1,017.26 USDS', + tokenUsdValue: '$1,017.26', }, ], final: { @@ -79,7 +81,7 @@ test.describe('Stake sDAI to SKY farm', () => { lowerText: 'Deposited', }, }, - outcome: '1,000.02 USDS', + outcome: '1,017.26 USDS', }) }) @@ -91,9 +93,9 @@ test.describe('Stake sDAI to SKY farm', () => { await farmDetailsPage.expectTokenToDepositBalance('USDS', '-') // no dust left await farmDetailsPage.expectReward({ - reward: '0.01', - rewardUsd: '<$0.01', + reward: '0.00000', + rewardUsd: '$0.00', }) - await farmDetailsPage.expectStaked({ amount: '1,000.02', asset: 'USDS' }) + await farmDetailsPage.expectStaked({ amount: '1,017.26', asset: 'USDS' }) }) }) diff --git a/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeUSDC.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeUSDC.test-e2e.ts index 18d542fb0..08c340136 100644 --- a/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeUSDC.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeUSDC.test-e2e.ts @@ -1,6 +1,5 @@ import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' @@ -8,12 +7,15 @@ import { mainnet } from 'viem/chains' import { StakeDialogPageObject } from '../../StakeDialog.PageObject' test.describe('Stake USDC to SKY farm', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let stakeDialog: StakeDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -29,9 +31,9 @@ test.describe('Stake USDC to SKY farm', () => { }) await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.selectAssetAction('USDC') await stakeDialog.fillAmountAction(10_000) }) @@ -48,8 +50,8 @@ test.describe('Stake USDC to SKY farm', () => { test('displays transaction overview', async () => { await stakeDialog.expectTransactionOverview({ estimatedRewards: { - apy: '778.72%', - description: 'Earn ~1,291,972.67 SKY/year', + apy: '10.88%', + description: 'Earn ~18,044.13 SKY/year', }, route: { swaps: [ @@ -79,8 +81,8 @@ test.describe('Stake USDC to SKY farm', () => { await farmDetailsPage.expectTokenToDepositBalance('USDS', '-') await farmDetailsPage.expectReward({ - reward: '0.1', - rewardUsd: '<$0.01', + reward: '0.00000', + rewardUsd: '$0.00', }) await farmDetailsPage.expectStaked({ amount: '10,000.00', asset: 'USDS' }) }) diff --git a/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeUSDS.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeUSDS.test-e2e.ts index e256efaa0..6447b1fe2 100644 --- a/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeUSDS.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/stake/e2e/mainnet/StakeUSDS.test-e2e.ts @@ -1,6 +1,5 @@ import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' @@ -9,12 +8,15 @@ import { mainnet } from 'viem/chains' import { StakeDialogPageObject } from '../../StakeDialog.PageObject' test.describe('Stake USDS to SKY farm', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let stakeDialog: StakeDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -30,9 +32,9 @@ test.describe('Stake USDS to SKY farm', () => { }) await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.fillAmountAction(10_000) }) @@ -46,8 +48,8 @@ test.describe('Stake USDS to SKY farm', () => { test('displays transaction overview', async () => { await stakeDialog.expectTransactionOverview({ estimatedRewards: { - apy: '778.72%', - description: 'Earn ~1,291,972.67 SKY/year', + apy: '10.88%', + description: 'Earn ~18,044.13 SKY/year', }, route: { swaps: [ @@ -73,8 +75,8 @@ test.describe('Stake USDS to SKY farm', () => { await farmDetailsPage.expectTokenToDepositBalance('USDS', '-') await farmDetailsPage.expectReward({ - reward: '0.1', - rewardUsd: '<$0.01', + reward: '0.00000', + rewardUsd: '$0.00', }) await farmDetailsPage.expectStaked({ amount: '10,000.00', asset: 'USDS' }) }) @@ -85,12 +87,15 @@ test.describe('Stake USDS to CLE farm', () => { const testUserAddress = privateKeyToAddress('0xa9f2d3eda4403df2fe54b97291d65d69824e0e2b3134c33b7145cf9b912966d5') const harSuffix = testUserAddress.slice(0, 10) - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let stakeDialog: StakeDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -107,9 +112,9 @@ test.describe('Stake USDS to CLE farm', () => { }) await overrideInfoSkyRouteWithHAR({ page, key: `2-cle-farm-0-balance-${harSuffix}` }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.fillAmountAction(10_000) }) @@ -154,7 +159,7 @@ test.describe('Stake USDS to CLE farm', () => { await overrideInfoSkyRouteWithHAR({ page, key: `3-cle-farm-10000-balance-${harSuffix}` }) await farmDetailsPage.expectReward({ - reward: '257.6', + reward: '257.460', }) await farmDetailsPage.expectPointsSyncWarningToBeHidden() await farmDetailsPage.expectInfoPanelClaimButtonToBeHidden() diff --git a/packages/app/src/features/farm-details/dialogs/unstake/UnstakeDialog.PageObject.ts b/packages/app/src/features/farm-details/dialogs/unstake/UnstakeDialog.PageObject.ts index d338b5a4c..11c43973c 100644 --- a/packages/app/src/features/farm-details/dialogs/unstake/UnstakeDialog.PageObject.ts +++ b/packages/app/src/features/farm-details/dialogs/unstake/UnstakeDialog.PageObject.ts @@ -1,10 +1,11 @@ import { DialogPageObject } from '@/features/dialogs/common/Dialog.PageObject' +import { TestContext } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' -import { Page, expect } from '@playwright/test' +import { expect } from '@playwright/test' export class UnstakeDialogPageObject extends DialogPageObject { - constructor(page: Page) { - super(page, /Withdraw/) + constructor(testContext: TestContext) { + super({ testContext, header: /Withdraw/ }) } // #region actions @@ -33,7 +34,7 @@ export class UnstakeDialogPageObject extends DialogPageObject { await expect(this.page.getByTestId(testIds.farmDetails.unstakeDialog.exitFarmSwitchPanel.switch)).not.toBeChecked() } - async expectExitFarmSwitchReward({ min, max, token, usdValue }: Reward): Promise { + async expectExitFarmSwitchReward({ amount, token, usdValue }: Reward): Promise { const regexp = /~([\d,\.]+) (\w+) \(~\$([\d,\.]+)\)/ const rewardRowText = await this.page .getByTestId(testIds.farmDetails.unstakeDialog.exitFarmSwitchPanel.reward) @@ -44,8 +45,7 @@ export class UnstakeDialogPageObject extends DialogPageObject { const [rewardAmount, rewardToken, rewardUsdValue] = match!.slice(1) const rewardNumber = Number(rewardAmount?.replace(/,/g, '')) - expect(rewardNumber).toBeGreaterThanOrEqual(min) - expect(rewardNumber).toBeLessThanOrEqual(max) + expect(rewardNumber).toBe(amount) expect(rewardToken).toBe(token) expect(rewardUsdValue).toContain(usdValue) } @@ -92,9 +92,8 @@ export class UnstakeDialogPageObject extends DialogPageObject { .getByTestId(testIds.farmDetails.unstakeDialog.transactionOverview.rewardOutcome) .textContent() const rewardNumber = Number(rewardAmount?.replace(/[^0-9.]/g, '')) + expect(rewardNumber).toBe(reward.amount) - expect(rewardNumber).toBeGreaterThanOrEqual(reward.min) - expect(rewardNumber).toBeLessThanOrEqual(reward.max) await expect( this.page.getByTestId(testIds.farmDetails.unstakeDialog.transactionOverview.rewardOutcome), ).toContainText(reward.token) @@ -111,8 +110,7 @@ export class UnstakeDialogPageObject extends DialogPageObject { } export interface Reward { - min: number - max: number + amount: number token: string usdValue: string } diff --git a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeDAI.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeDAI.test-e2e.ts index a1ec4e704..204c86c2e 100644 --- a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeDAI.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeDAI.test-e2e.ts @@ -1,6 +1,5 @@ import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' @@ -9,13 +8,16 @@ import { StakeDialogPageObject } from '../../../stake/StakeDialog.PageObject' import { UnstakeDialogPageObject } from '../../UnstakeDialog.PageObject' test.describe('Unstake DAI from SKY farm', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let unstakeDialog: UnstakeDialogPageObject let stakeDialog: StakeDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -32,9 +34,9 @@ test.describe('Unstake DAI from SKY farm', () => { }) await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.selectAssetAction('USDS') await stakeDialog.fillAmountAction(10_000) @@ -42,11 +44,11 @@ test.describe('Unstake DAI from SKY farm', () => { await stakeDialog.clickBackToFarmAction() - await fork.progressSimulation(page, 24 * 60 * 60) // 24 hours + await testContext.testnetController.progressSimulationAndMine(24 * 60 * 60) // 24 hours await page.reload() await farmDetailsPage.clickInfoPanelUnstakeButtonAction() - unstakeDialog = new UnstakeDialogPageObject(page) + unstakeDialog = new UnstakeDialogPageObject(testContext) await unstakeDialog.selectAssetAction('DAI') await unstakeDialog.fillAmountAction(5_000) @@ -91,8 +93,8 @@ test.describe('Unstake DAI from SKY farm', () => { await farmDetailsPage.expectTokenToDepositBalance('DAI', '15,000.00') await farmDetailsPage.expectTokenToDepositBalance('USDS', '-') await farmDetailsPage.expectReward({ - reward: '3,539', - rewardUsd: '$213', + reward: '49.43940', + rewardUsd: '2.98', }) await farmDetailsPage.expectStaked({ amount: '5,000.00', asset: 'USDS' }) }) diff --git a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeUSDC.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeUSDC.test-e2e.ts index 55d33303d..1fe1a4aed 100644 --- a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeUSDC.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeUSDC.test-e2e.ts @@ -1,6 +1,5 @@ import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' @@ -9,13 +8,16 @@ import { StakeDialogPageObject } from '../../../stake/StakeDialog.PageObject' import { UnstakeDialogPageObject } from '../../UnstakeDialog.PageObject' test.describe('Unstake USDC from SKY farm', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let unstakeDialog: UnstakeDialogPageObject let stakeDialog: StakeDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -32,9 +34,9 @@ test.describe('Unstake USDC from SKY farm', () => { }) await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.selectAssetAction('USDS') await stakeDialog.fillAmountAction(10_000) @@ -42,11 +44,11 @@ test.describe('Unstake USDC from SKY farm', () => { await stakeDialog.clickBackToFarmAction() - await fork.progressSimulation(page, 24 * 60 * 60) // 24 hours + await testContext.testnetController.progressSimulationAndMine(24 * 60 * 60) // 24 hours await page.reload() await farmDetailsPage.clickInfoPanelUnstakeButtonAction() - unstakeDialog = new UnstakeDialogPageObject(page) + unstakeDialog = new UnstakeDialogPageObject(testContext) await unstakeDialog.selectAssetAction('USDC') await unstakeDialog.fillAmountAction(5_000) @@ -91,8 +93,8 @@ test.describe('Unstake USDC from SKY farm', () => { await farmDetailsPage.expectTokenToDepositBalance('USDC', '15,000.00') await farmDetailsPage.expectTokenToDepositBalance('USDS', '-') await farmDetailsPage.expectReward({ - reward: '3,539', - rewardUsd: '$213', + reward: '49.43940', + rewardUsd: '2.98', }) await farmDetailsPage.expectStaked({ amount: '5,000.00', asset: 'USDS' }) }) diff --git a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeUSDS.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeUSDS.test-e2e.ts index 4335e96d0..077f7df99 100644 --- a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeUSDS.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/UnstakeUSDS.test-e2e.ts @@ -1,6 +1,5 @@ import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' @@ -10,13 +9,16 @@ import { StakeDialogPageObject } from '../../../stake/StakeDialog.PageObject' import { UnstakeDialogPageObject } from '../../UnstakeDialog.PageObject' test.describe('Unstake USDS from SKY farm', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let unstakeDialog: UnstakeDialogPageObject let stakeDialog: StakeDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -33,9 +35,9 @@ test.describe('Unstake USDS from SKY farm', () => { }) await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.selectAssetAction('DAI') await stakeDialog.fillAmountAction(10_000) @@ -43,11 +45,11 @@ test.describe('Unstake USDS from SKY farm', () => { await stakeDialog.clickBackToFarmAction() - await fork.progressSimulation(page, 24 * 60 * 60) // 24 hours + await testContext.testnetController.progressSimulationAndMine(24 * 60 * 60) // 24 hours await page.reload() await farmDetailsPage.clickInfoPanelUnstakeButtonAction() - unstakeDialog = new UnstakeDialogPageObject(page) + unstakeDialog = new UnstakeDialogPageObject(testContext) await unstakeDialog.selectAssetAction('USDS') await unstakeDialog.fillAmountAction(5_000) @@ -90,8 +92,8 @@ test.describe('Unstake USDS from SKY farm', () => { await farmDetailsPage.expectTokenToDepositBalance('USDS', '15,000.00') await farmDetailsPage.expectTokenToDepositBalance('DAI', '-') await farmDetailsPage.expectReward({ - reward: '3,539', - rewardUsd: '$213', + reward: '49.43654', + rewardUsd: '2.98', }) await farmDetailsPage.expectStaked({ amount: '5,000.00', asset: 'USDS' }) }) @@ -102,12 +104,15 @@ test.describe('Unstake USDS from CLE farm', () => { const testUserAddress = privateKeyToAddress('0xa9f2d3eda4403df2fe54b97291d65d69824e0e2b3134c33b7145cf9b912966d5') const harSuffix = testUserAddress.slice(0, 10) - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let unstakeDialog: UnstakeDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -124,16 +129,16 @@ test.describe('Unstake USDS from CLE farm', () => { }) await overrideInfoSkyRouteWithHAR({ page, key: `2-cle-farm-0-balance-${harSuffix}` }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - const stakeDialog = new StakeDialogPageObject(page) + const stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.fillAmountAction(10_000) await stakeDialog.actionsContainer.acceptAllActionsAction(2) await stakeDialog.clickBackToFarmAction() await overrideInfoSkyRouteWithHAR({ page, key: `3-cle-farm-10000-balance-${harSuffix}` }) await farmDetailsPage.clickInfoPanelUnstakeButtonAction() - unstakeDialog = new UnstakeDialogPageObject(page) + unstakeDialog = new UnstakeDialogPageObject(testContext) await unstakeDialog.selectAssetAction('USDS') await unstakeDialog.fillAmountAction(5_000) @@ -171,7 +176,7 @@ test.describe('Unstake USDS from CLE farm', () => { await farmDetailsPage.expectTokenToDepositBalance('USDS', '5,000.00') await farmDetailsPage.expectReward({ - reward: '257.6', + reward: '257.460', }) await farmDetailsPage.expectStaked({ amount: '5,000.00', asset: 'USDS' }) await farmDetailsPage.expectPointsSyncWarning() @@ -179,7 +184,7 @@ test.describe('Unstake USDS from CLE farm', () => { await overrideInfoSkyRouteWithHAR({ page, key: `4-cle-farm-5000-balance-${harSuffix}` }) await farmDetailsPage.expectReward({ - reward: '257.6', + reward: '257.460', }) await farmDetailsPage.expectPointsSyncWarningToBeHidden() await farmDetailsPage.expectInfoPanelClaimButtonToBeHidden() diff --git a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxDai.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxDai.test-e2e.ts index 26d11da6b..d47cc7769 100644 --- a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxDai.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxDai.test-e2e.ts @@ -1,8 +1,8 @@ import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' +import { NormalizedUnitNumber } from '@marsfoundation/common-universal' import { test } from '@playwright/test' import { Address } from 'viem' import { mainnet } from 'viem/chains' @@ -10,14 +10,14 @@ import { StakeDialogPageObject } from '../../../stake/StakeDialog.PageObject' import { UnstakeDialogPageObject } from '../../UnstakeDialog.PageObject' test.describe('Withdraw max DAI from SKY farm', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let unstakeDialog: UnstakeDialogPageObject let stakeDialog: StakeDialogPageObject let account: Address test.beforeEach(async ({ page }) => { - ;({ account } = await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -32,13 +32,14 @@ test.describe('Withdraw max DAI from SKY farm', () => { USDC: 10_000, }, }, - })) + }) await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) + account = testContext.account await stakeDialog.selectAssetAction('USDS') await stakeDialog.fillAmountAction(10_000) @@ -46,11 +47,11 @@ test.describe('Withdraw max DAI from SKY farm', () => { await stakeDialog.clickBackToFarmAction() - await fork.progressSimulation(page, 24 * 60 * 60) // 24 hours + await testContext.testnetController.progressSimulationAndMine(24 * 60 * 60) // 24 hours await page.reload() await farmDetailsPage.clickInfoPanelUnstakeButtonAction() - unstakeDialog = new UnstakeDialogPageObject(page) + unstakeDialog = new UnstakeDialogPageObject(testContext) await unstakeDialog.selectAssetAction('DAI') await unstakeDialog.clickMaxAmountAction() @@ -120,9 +121,8 @@ test.describe('Withdraw max DAI from SKY farm', () => { usdValue: '10,000.00', }, reward: { - min: 3538, - max: 3541, - usdValue: '213', + amount: 49.44, + usdValue: '2.98', token: 'SKY', }, }) @@ -136,8 +136,8 @@ test.describe('Withdraw max DAI from SKY farm', () => { await farmDetailsPage.expectTokenToDepositBalance('DAI', '20,000.00') await farmDetailsPage.expectReward({ - reward: '3,539', - rewardUsd: '$213', + reward: '49.436543', + rewardUsd: '2.98', }) }) @@ -153,10 +153,8 @@ test.describe('Withdraw max DAI from SKY farm', () => { await farmDetailsPage.expectTokenBalance({ address: account, - fork, symbol: 'SKY', - minBalance: 3_525, - maxBalance: 3_545, + balance: NormalizedUnitNumber('49.4365427929088'), }) }) }) diff --git a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxUSDC.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxUSDC.test-e2e.ts index ae7fd30fe..4fcc6fb87 100644 --- a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxUSDC.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxUSDC.test-e2e.ts @@ -1,8 +1,8 @@ import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' +import { NormalizedUnitNumber } from '@marsfoundation/common-universal' import { test } from '@playwright/test' import { Address } from 'viem' import { mainnet } from 'viem/chains' @@ -10,14 +10,14 @@ import { StakeDialogPageObject } from '../../../stake/StakeDialog.PageObject' import { UnstakeDialogPageObject } from '../../UnstakeDialog.PageObject' test.describe('Withdraw max USDC from SKY farm', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let unstakeDialog: UnstakeDialogPageObject let stakeDialog: StakeDialogPageObject let account: Address test.beforeEach(async ({ page }) => { - ;({ account } = await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -32,13 +32,14 @@ test.describe('Withdraw max USDC from SKY farm', () => { USDC: 10_000, }, }, - })) + }) await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) + account = testContext.account await stakeDialog.selectAssetAction('USDS') await stakeDialog.fillAmountAction(10_000) @@ -46,11 +47,11 @@ test.describe('Withdraw max USDC from SKY farm', () => { await stakeDialog.clickBackToFarmAction() - await fork.progressSimulation(page, 24 * 60 * 60) // 24 hours + await testContext.testnetController.progressSimulationAndMine(24 * 60 * 60) // 24 hours await page.reload() await farmDetailsPage.clickInfoPanelUnstakeButtonAction() - unstakeDialog = new UnstakeDialogPageObject(page) + unstakeDialog = new UnstakeDialogPageObject(testContext) await unstakeDialog.selectAssetAction('USDC') await unstakeDialog.clickMaxAmountAction() @@ -120,9 +121,8 @@ test.describe('Withdraw max USDC from SKY farm', () => { usdValue: '10,000.00', }, reward: { - min: 3538, - max: 3541, - usdValue: '213', + amount: 49.44, + usdValue: '2.98', token: 'SKY', }, }) @@ -136,8 +136,8 @@ test.describe('Withdraw max USDC from SKY farm', () => { await farmDetailsPage.expectTokenToDepositBalance('USDC', '20,000.00') await farmDetailsPage.expectReward({ - reward: '3,539', - rewardUsd: '$213', + reward: '49.436543', + rewardUsd: '2.98', }) }) @@ -152,11 +152,9 @@ test.describe('Withdraw max USDC from SKY farm', () => { await farmDetailsPage.expectInfoPanelToBeVisible() await farmDetailsPage.expectTokenBalance({ - address: account, - fork, symbol: 'SKY', - minBalance: 3_525, - maxBalance: 3_545, + balance: NormalizedUnitNumber('49.4365427929088'), + address: account, }) }) }) diff --git a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxUSDS.test-e2e.ts b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxUSDS.test-e2e.ts index a7a50a0f9..88e08f073 100644 --- a/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxUSDS.test-e2e.ts +++ b/packages/app/src/features/farm-details/dialogs/unstake/e2e/mainnet/WithdrawMaxUSDS.test-e2e.ts @@ -1,8 +1,8 @@ import { FarmDetailsPageObject } from '@/features/farm-details/FarmDetails.PageObject' -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' +import { NormalizedUnitNumber } from '@marsfoundation/common-universal' import { test } from '@playwright/test' import { Address } from 'viem' import { privateKeyToAddress } from 'viem/accounts' @@ -11,14 +11,17 @@ import { StakeDialogPageObject } from '../../../stake/StakeDialog.PageObject' import { UnstakeDialogPageObject } from '../../UnstakeDialog.PageObject' test.describe('Withdraw max USDS from SKY farm', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let unstakeDialog: UnstakeDialogPageObject let stakeDialog: StakeDialogPageObject let account: Address test.beforeEach(async ({ page }) => { - ;({ account } = await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -33,13 +36,14 @@ test.describe('Withdraw max USDS from SKY farm', () => { USDC: 10_000, }, }, - })) + }) await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - stakeDialog = new StakeDialogPageObject(page) + stakeDialog = new StakeDialogPageObject(testContext) + account = testContext.account await stakeDialog.selectAssetAction('USDS') await stakeDialog.fillAmountAction(10_000) @@ -47,11 +51,11 @@ test.describe('Withdraw max USDS from SKY farm', () => { await stakeDialog.clickBackToFarmAction() - await fork.progressSimulation(page, 24 * 60 * 60) // 24 hours + await testContext.testnetController.progressSimulationAndMine(24 * 60 * 60) // 24 hours await page.reload() await farmDetailsPage.clickInfoPanelUnstakeButtonAction() - unstakeDialog = new UnstakeDialogPageObject(page) + unstakeDialog = new UnstakeDialogPageObject(testContext) await unstakeDialog.selectAssetAction('USDS') await unstakeDialog.clickMaxAmountAction() @@ -61,10 +65,9 @@ test.describe('Withdraw max USDS from SKY farm', () => { await unstakeDialog.expectExitFarmSwitchToBeVisible() await unstakeDialog.expectExitFarmSwitchNotChecked() await unstakeDialog.expectExitFarmSwitchReward({ - min: 3538, - max: 3541, + amount: 49.44, token: 'SKY', - usdValue: '213', + usdValue: '2.98', }) }) @@ -120,9 +123,8 @@ test.describe('Withdraw max USDS from SKY farm', () => { usdValue: '10,000.00', }, reward: { - min: 3538, - max: 3541, - usdValue: '213', + amount: 49.44, + usdValue: '2.98', token: 'SKY', }, }) @@ -136,8 +138,8 @@ test.describe('Withdraw max USDS from SKY farm', () => { await farmDetailsPage.expectTokenToDepositBalance('USDS', '10,000.00') await farmDetailsPage.expectReward({ - reward: '3,539', - rewardUsd: '$213', + reward: '49.436543', + rewardUsd: '2.98', }) }) @@ -153,10 +155,8 @@ test.describe('Withdraw max USDS from SKY farm', () => { await farmDetailsPage.expectTokenBalance({ address: account, - fork, symbol: 'SKY', - minBalance: 3_525, - maxBalance: 3_545, + balance: NormalizedUnitNumber('49.4365427929088'), }) }) }) @@ -166,12 +166,15 @@ test.describe('Withdraw max USDS from CLE farm', () => { const testUserAddress = privateKeyToAddress('0xa9f2d3eda4403df2fe54b97291d65d69824e0e2b3134c33b7145cf9b912966d5') const harSuffix = testUserAddress.slice(0, 10) - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmDetailsPage: FarmDetailsPageObject let unstakeDialog: UnstakeDialogPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'farmDetails', initialPageParams: { chainId: mainnet.id.toString(), @@ -188,16 +191,16 @@ test.describe('Withdraw max USDS from CLE farm', () => { }) await overrideInfoSkyRouteWithHAR({ page, key: `2-cle-farm-0-balance-${harSuffix}` }) - farmDetailsPage = new FarmDetailsPageObject(page) + farmDetailsPage = new FarmDetailsPageObject(testContext) await farmDetailsPage.clickInfoPanelStakeButtonAction() - const stakeDialog = new StakeDialogPageObject(page) + const stakeDialog = new StakeDialogPageObject(testContext) await stakeDialog.fillAmountAction(10_000) await stakeDialog.actionsContainer.acceptAllActionsAction(2) await stakeDialog.clickBackToFarmAction() await overrideInfoSkyRouteWithHAR({ page, key: `3-cle-farm-10000-balance-${harSuffix}` }) await farmDetailsPage.clickInfoPanelUnstakeButtonAction() - unstakeDialog = new UnstakeDialogPageObject(page) + unstakeDialog = new UnstakeDialogPageObject(testContext) await unstakeDialog.selectAssetAction('USDS') await unstakeDialog.clickMaxAmountAction() diff --git a/packages/app/src/features/farm-details/dialogs/unstake/logic/getFormFieldsForUnstakeDialog.ts b/packages/app/src/features/farm-details/dialogs/unstake/logic/getFormFieldsForUnstakeDialog.ts index 3039a29d8..3367cf692 100644 --- a/packages/app/src/features/farm-details/dialogs/unstake/logic/getFormFieldsForUnstakeDialog.ts +++ b/packages/app/src/features/farm-details/dialogs/unstake/logic/getFormFieldsForUnstakeDialog.ts @@ -22,7 +22,6 @@ export function getFormFieldsForUnstakeDialog({ form.setValue('symbol', newSymbol) form.setValue('value', '') form.setValue('isMaxSelected', false) - form.clearErrors() } diff --git a/packages/app/src/features/farm-details/logic/calculateReward.ts b/packages/app/src/features/farm-details/logic/calculateReward.ts index 5f6053e0b..209ff3fff 100644 --- a/packages/app/src/features/farm-details/logic/calculateReward.ts +++ b/packages/app/src/features/farm-details/logic/calculateReward.ts @@ -28,6 +28,7 @@ export function calculateReward({ const earnedTimestampInMs = earnedTimestamp * 1000 const timeDiff = ((timestampInMs > periodFinishInMs ? periodFinishInMs : timestampInMs) - earnedTimestampInMs) / 1000 + const accruedEarned = staked.multipliedBy(rewardRate).multipliedBy(BigNumber.max(timeDiff, 0)).dividedBy(totalSupply) const earnedInTotal = NormalizedUnitNumber(earned.plus(accruedEarned)) diff --git a/packages/app/src/features/savings/components/growing-balance/GrowingBalance.tsx b/packages/app/src/features/savings/components/growing-balance/GrowingBalance.tsx index 067fab3c4..a89faf843 100644 --- a/packages/app/src/features/savings/components/growing-balance/GrowingBalance.tsx +++ b/packages/app/src/features/savings/components/growing-balance/GrowingBalance.tsx @@ -5,6 +5,7 @@ import { cn } from '@/ui/utils/style' import { testIds } from '@/ui/utils/testIds' import { getFractionalPart, getWholePart } from '@/utils/bigNumber' import { useTimestamp } from '@/utils/useTimestamp' +import { NormalizedUnitNumber } from '@marsfoundation/common-universal' import { SavingsOverview } from '../../logic/makeSavingsOverview' export interface GrowingBalanceProps { @@ -23,7 +24,8 @@ export function GrowingBalance({ savingsType, }: GrowingBalanceProps) { const { timestampInMs } = useTimestamp({ refreshIntervalInMs: balanceRefreshIntervalInMs }) - const { depositedAssets, depositedAssetsPrecision } = calculateSavingsBalance(timestampInMs) + const { depositedAssets: _depositedAssets, depositedAssetsPrecision } = calculateSavingsBalance(timestampInMs) + const depositedAssets = NormalizedUnitNumber(_depositedAssets.toFixed(depositedAssetsPrecision)) return (
diff --git a/packages/app/src/features/topbar/Topbar.test-e2e.ts b/packages/app/src/features/topbar/Topbar.test-e2e.ts index 8ec70d6b3..467401555 100644 --- a/packages/app/src/features/topbar/Topbar.test-e2e.ts +++ b/packages/app/src/features/topbar/Topbar.test-e2e.ts @@ -1,73 +1,72 @@ -import { test } from '@playwright/test' -import { mainnet } from 'viem/chains' - +import { MyPortfolioPageObject } from '@/pages/MyPortfolio.PageObject' import { overrideAirdropInfoRoute } from '@/test/e2e/airdropInfo' import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' - -import { MyPortfolioPageObject } from '@/pages/MyPortfolio.PageObject' +import { test } from '@playwright/test' +import { mainnet } from 'viem/chains' import { TopbarPageObject } from './Topbar.PageObject' test.describe('Topbar', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) - test.describe('Airdrop counter', () => { test('Disconnected', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'easyBorrow', account: { type: 'not-connected', }, }) - const topbar = new TopbarPageObject(page) + const topbar = new TopbarPageObject(testContext) await topbar.expectAirdropCompactValue('0') await topbar.openAirdropDropdown() await topbar.expectAirdropPreciseValue('0.00 SPK') }) test('Connected', async ({ page }) => { - const { account } = await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'easyBorrow', account: { type: 'connected-random', }, }) - await overrideAirdropInfoRoute(page, { account }) + await overrideAirdropInfoRoute(page, { account: testContext.account }) - const topbar = new TopbarPageObject(page) - await topbar.expectAirdropCompactValue('7.841M') + const topbar = new TopbarPageObject(testContext) + await topbar.expectAirdropCompactValue('8.227M') await topbar.openAirdropDropdown() - await topbar.expectAirdropPreciseValue('7,840,591') + await topbar.expectAirdropPreciseValue('8,227,011.131') }) test('Api error', async ({ page }) => { - const { account } = await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'easyBorrow', account: { type: 'connected-random', }, }) - await overrideAirdropInfoRoute(page, { account, shouldFail: true }) + await overrideAirdropInfoRoute(page, { account: testContext.account, shouldFail: true }) - const topbar = new TopbarPageObject(page) + const topbar = new TopbarPageObject(testContext) await topbar.expectAirdropBadgeNotVisible() }) test('Wallet with no airdrop', async ({ page }) => { - const { account } = await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'easyBorrow', account: { type: 'connected-random', }, }) - await overrideAirdropInfoRoute(page, { account, noAirdrop: true }) + await overrideAirdropInfoRoute(page, { account: testContext.account, noAirdrop: true }) - const topbar = new TopbarPageObject(page) + const topbar = new TopbarPageObject(testContext) await topbar.expectAirdropCompactValue('0') await topbar.openAirdropDropdown() await topbar.expectAirdropPreciseValue('0.00 SPK') @@ -75,13 +74,12 @@ test.describe('Topbar', () => { }) test.describe('Rewards badge', () => { - const fork = setupFork({ - blockNumber: 20189272n, // block number where the reward program is finished - chainId: mainnet.id, - }) - test('Displays total rewards in badge', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-address', @@ -89,12 +87,16 @@ test.describe('Topbar', () => { }, }) - const topbar = new TopbarPageObject(page) - await topbar.expectClaimableRewardsValue('$25.58K') + const topbar = new TopbarPageObject(testContext) + await topbar.expectClaimableRewardsValue('$29.72K') }) test('Displays details in dropdown', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-address', @@ -102,28 +104,32 @@ test.describe('Topbar', () => { }, }) - const topbar = new TopbarPageObject(page) + const topbar = new TopbarPageObject(testContext) await topbar.openRewardsDropdown() await topbar.expectRewards([ { tokenSymbol: 'wstETH', amount: '6.3697', - amountUSD: '$25,583.20', + amountUSD: '$29,717.60', }, ]) }) test('Does not display badge when no rewards', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'myPortfolio', account: { type: 'connected-random', }, }) - const topbar = new TopbarPageObject(page) - const myPortfolioPage = new MyPortfolioPageObject(page) + const topbar = new TopbarPageObject(testContext) + const myPortfolioPage = new MyPortfolioPageObject(testContext) await myPortfolioPage.expectPositionToBeEmpty() // waiting for reserves to load await topbar.expectRewardsBadgeNotVisible() // asserting that after reserves are loaded, rewards badge is not visible @@ -132,7 +138,8 @@ test.describe('Topbar', () => { test.describe('Malformed localStorage', () => { test('Sandbox info in wagmi.store but not in zustand-app-store', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'easyBorrow', account: { type: 'not-connected', @@ -157,7 +164,7 @@ test.describe('Topbar', () => { await page.reload() - const topbar = new TopbarPageObject(page) + const topbar = new TopbarPageObject(testContext) await topbar.expectSavingsLinkVisible() }) }) diff --git a/packages/app/src/pages/Borrow.PageObject.ts b/packages/app/src/pages/Borrow.PageObject.ts index d9047ebd2..08ec360dc 100644 --- a/packages/app/src/pages/Borrow.PageObject.ts +++ b/packages/app/src/pages/Borrow.PageObject.ts @@ -1,14 +1,18 @@ -import { expect } from '@playwright/test' - import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { BasePageObject } from '@/test/e2e/BasePageObject' import { TestTokenWithValue, expectAssets } from '@/test/e2e/assertions' -import { ForkContext } from '@/test/e2e/forking/setupFork' -import { buildUrl } from '@/test/e2e/setup' -import { calculateAssetsWorth } from '@/test/e2e/utils' +import { TestContext, buildUrl } from '@/test/e2e/setup' import { testIds } from '@/ui/utils/testIds' +import { expect } from '@playwright/test' export class BorrowPageObject extends BasePageObject { + public readonly actionsContainer: ActionsPageObject + + constructor(testContext: TestContext) { + super(testContext) + this.actionsContainer = new ActionsPageObject(testContext, this.locatePanelByHeader('Actions')) + } + // #region actions async fillDepositAssetAction(index: number, asset: string, amount: number): Promise { const inputGroup = this.page @@ -51,19 +55,27 @@ export class BorrowPageObject extends BasePageObject { await this.page.getByRole('link', { name: 'View in Savings' }).click() } - async depositAssetsActions(assetsToDeposit: Record, daiToBorrow: number): Promise { - const actionsContainer = new ActionsPageObject(this.locatePanelByHeader('Actions')) - await this.depositWithoutBorrowActions(assetsToDeposit, daiToBorrow, actionsContainer) - await actionsContainer.acceptActionAtIndex(Object.entries(assetsToDeposit).length * 2) // accept final borrow action - } - - async depositWithoutBorrowActions( - assetsToDeposit: Record, - daiToBorrow?: number, - _actionsContainer?: ActionsPageObject, - ): Promise { - const actionsContainer = _actionsContainer ?? new ActionsPageObject(this.locatePanelByHeader('Actions')) - + async depositAssetsActions({ + assetsToDeposit, + daiToBorrow, + }: { + assetsToDeposit: Record + daiToBorrow: number + }): Promise { + await this.depositWithoutBorrowActions({ + assetsToDeposit, + daiToBorrow, + }) + await this.actionsContainer.acceptActionAtIndex(Object.entries(assetsToDeposit).length * 2) // accept final borrow action + } + + async depositWithoutBorrowActions({ + assetsToDeposit, + daiToBorrow, + }: { + assetsToDeposit: Record + daiToBorrow?: number + }): Promise { let index = 0 for (const [asset, amount] of Object.entries(assetsToDeposit)) { if (index !== 0) { @@ -74,8 +86,8 @@ export class BorrowPageObject extends BasePageObject { } await this.fillBorrowAssetAction(daiToBorrow ?? 1) // defaulted value won't matter, if only depositing await this.submitAction() - await actionsContainer.acceptAllActionsAction(2 * index) // omitting the borrow action - await actionsContainer.expectEnabledActionAtIndex(2 * index) + await this.actionsContainer.acceptAllActionsAction(2 * index) // omitting the borrow action + await this.actionsContainer.expectEnabledActionAtIndex(2 * index) } async goToEasyBorrowAction(): Promise { @@ -115,35 +127,22 @@ export class BorrowPageObject extends BasePageObject { await expect(this.page.getByTestId(testIds.easyBorrow.form.usdsBorrowAlert)).toBeVisible() } - async expectSuccessPage( - deposited: TestTokenWithValue[], - borrowed: TestTokenWithValue, - fork: ForkContext, - assetsWorthOverride?: Record, - ): Promise { + async expectSuccessPage({ + deposited, + borrowed, + }: { + deposited: TestTokenWithValue[] + borrowed: TestTokenWithValue + }): Promise { await expect(this.page.getByText('Congrats, all done!')).toBeVisible() - const transformed = [...deposited, borrowed].reduce( - (acc, { asset, amount: value }) => ({ ...acc, [asset]: value }), - {}, - ) - - const assetsWorth = await (async () => { - if (assetsWorthOverride) { - return assetsWorthOverride - } - - const { assetsWorth } = await calculateAssetsWorth(fork.forkUrl, transformed) - return assetsWorth - })() - if (deposited.length > 0) { const depositSummary = await this.page.getByTestId(testIds.easyBorrow.success.deposited).textContent() - expectAssets(depositSummary!, deposited, assetsWorth) + expectAssets(depositSummary!, deposited) } const borrowSummary = await this.page.getByTestId(testIds.easyBorrow.success.borrowed).textContent() - expectAssets(borrowSummary!, [borrowed], assetsWorth) + expectAssets(borrowSummary!, [borrowed]) } // #endregion } diff --git a/packages/app/src/pages/Borrow.test-e2e.ts b/packages/app/src/pages/Borrow.test-e2e.ts index 5d8945c40..feb9e82fa 100644 --- a/packages/app/src/pages/Borrow.test-e2e.ts +++ b/packages/app/src/pages/Borrow.test-e2e.ts @@ -1,22 +1,20 @@ import { borrowValidationIssueToMessage } from '@/domain/market-validators/validateBorrow' import { ActionsPageObject } from '@/features/actions/ActionsContainer.PageObject' import { CollateralDialogPageObject } from '@/features/dialogs/collateral/CollateralDialog.PageObject' -import { DEFAULT_BLOCK_NUMBER, USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' -import { buildUrl, setup } from '@/test/e2e/setup' -import { screenshot } from '@/test/e2e/utils' -import { Page, test } from '@playwright/test' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' +import { TestContext, buildUrl, setup } from '@/test/e2e/setup' +import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { BorrowPageObject } from './Borrow.PageObject' import { MyPortfolioPageObject } from './MyPortfolio.PageObject' import { SavingsPageObject } from './Savings.PageObject' test.describe('Borrow page', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) - test.describe('deposit ETH, borrow DAI', () => { let borrowPage: BorrowPageObject let actionsContainer: ActionsPageObject + let testContext: TestContext + const deposit = { asset: 'ETH', amount: 1, @@ -25,11 +23,15 @@ test.describe('Borrow page', () => { asset: 'DAI', amount: 1000, } - const expectedLtv = '44.07%' - const expectedHealthFactor = '1.87' + const expectedLtv = '25.46%' + const expectedHealthFactor = '3.26' test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -39,8 +41,8 @@ test.describe('Borrow page', () => { }, }) - borrowPage = new BorrowPageObject(page) - actionsContainer = new ActionsPageObject(page) + borrowPage = new BorrowPageObject(testContext) + actionsContainer = new ActionsPageObject(testContext) }) test('calculates LTV correctly', async () => { @@ -53,7 +55,7 @@ test.describe('Borrow page', () => { await borrowPage.expectHealthFactor(expectedHealthFactor) }) - test('builds action plan', async ({ page }) => { + test('builds action plan', async () => { await borrowPage.fillDepositAssetAction(0, deposit.asset, deposit.amount) await borrowPage.fillBorrowAssetAction(borrow.amount) @@ -63,10 +65,9 @@ test.describe('Borrow page', () => { { type: 'deposit', asset: 'ETH', amount: '1.00' }, { type: 'borrow', asset: 'DAI', amount: '1,000.00' }, ]) - await screenshot(page, 'deposit-eth-actions-plan') }) - test('successfully builds position', async ({ page }) => { + test('successfully builds position', async () => { await borrowPage.fillDepositAssetAction(0, deposit.asset, deposit.amount) await borrowPage.fillBorrowAssetAction(borrow.amount) @@ -74,24 +75,28 @@ test.describe('Borrow page', () => { await actionsContainer.acceptAllActionsAction(2) - await borrowPage.expectSuccessPage([deposit], borrow, fork) - await screenshot(page, 'deposit-eth-success') + await borrowPage.expectSuccessPage({ + deposited: [{ asset: 'ETH', amount: '1.00', usdValue: '$3,928.31' }], + borrowed: { asset: 'DAI', amount: '1,000.00', usdValue: '$1,000.00' }, + }) }) - test('HF matches after position is created', async ({ page }) => { + test('HF matches after position is created', async () => { await borrowPage.fillDepositAssetAction(0, deposit.asset, deposit.amount) await borrowPage.fillBorrowAssetAction(borrow.amount) await borrowPage.submitAction() await actionsContainer.acceptAllActionsAction(2) - await expectHFOnMyPortfolio(page, borrowPage, expectedHealthFactor) + await expectHFOnMyPortfolio(testContext, borrowPage, expectedHealthFactor) }) }) test.describe('deposit wstETH and rETH, borrow DAI', () => { let borrowPage: BorrowPageObject let actionsContainer: ActionsPageObject + let testContext: TestContext<'connected-random'> + const wstETHdeposit = { asset: 'wstETH', amount: 1, @@ -104,11 +109,15 @@ test.describe('Borrow page', () => { asset: 'DAI', amount: 1000, } - const expectedLTV = '19.57%' - const expectedHealthFactor = '4.06' + const expectedLTV = '11.01%' + const expectedHealthFactor = '7.26' test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -119,8 +128,8 @@ test.describe('Borrow page', () => { }, }) - borrowPage = new BorrowPageObject(page) - actionsContainer = new ActionsPageObject(page) + borrowPage = new BorrowPageObject(testContext) + actionsContainer = new ActionsPageObject(testContext) }) test('calculates LTV correctly', async () => { @@ -135,7 +144,7 @@ test.describe('Borrow page', () => { await borrowPage.expectHealthFactor(expectedHealthFactor) }) - test('uses permits in action plan for assets with permit support', async ({ page }) => { + test('uses permits in action plan for assets with permit support', async () => { await borrowPage.fillDepositAssetAction(0, wstETHdeposit.asset, wstETHdeposit.amount) await borrowPage.fillBorrowAssetAction(borrow.amount) @@ -146,10 +155,9 @@ test.describe('Borrow page', () => { { type: 'deposit', asset: 'wstETH', amount: '1.00' }, { type: 'borrow', asset: 'DAI', amount: '1,000.00' }, ]) - await screenshot(page, 'deposit-wsteth-permit-actions-plan') }) - test('uses approve in action plan for assets with no permit support', async ({ page }) => { + test('uses approve in action plan for assets with no permit support', async () => { await borrowPage.fillDepositAssetAction(0, rETHdeposit.asset, rETHdeposit.amount) await borrowPage.fillBorrowAssetAction(borrow.amount) @@ -160,10 +168,9 @@ test.describe('Borrow page', () => { { type: 'deposit', asset: 'rETH', amount: '1.00' }, { type: 'borrow', asset: 'DAI', amount: '1,000.00' }, ]) - await screenshot(page, 'deposit-reth-approve-actions-plan') }) - test('can switch to approves in action plan', async ({ page }) => { + test('can switch to approves in action plan', async () => { await borrowPage.fillDepositAssetAction(0, wstETHdeposit.asset, wstETHdeposit.amount) await borrowPage.fillBorrowAssetAction(borrow.amount) @@ -175,10 +182,9 @@ test.describe('Borrow page', () => { { type: 'deposit', asset: 'wstETH', amount: '1.00' }, { type: 'borrow', asset: 'DAI', amount: '1,000.00' }, ]) - await screenshot(page, 'deposit-wsteth-approve-actions-plan') }) - test('builds action plan for 2 assets', async ({ page }) => { + test('builds action plan for 2 assets', async () => { await borrowPage.addNewDepositAssetAction() await borrowPage.fillDepositAssetAction(0, wstETHdeposit.asset, wstETHdeposit.amount) await borrowPage.fillDepositAssetAction(1, rETHdeposit.asset, rETHdeposit.amount) @@ -193,10 +199,9 @@ test.describe('Borrow page', () => { { type: 'deposit', asset: 'rETH', amount: '1.00' }, { type: 'borrow', asset: 'DAI', amount: '1,000.00' }, ]) - await screenshot(page, 'deposit-wsteth-reth-actions-plan') }) - test('successfully builds position', async ({ page }) => { + test('successfully builds position', async () => { await borrowPage.addNewDepositAssetAction() await borrowPage.fillDepositAssetAction(0, wstETHdeposit.asset, wstETHdeposit.amount) await borrowPage.fillDepositAssetAction(1, rETHdeposit.asset, rETHdeposit.amount) @@ -206,11 +211,16 @@ test.describe('Borrow page', () => { await actionsContainer.acceptAllActionsAction(5) - await borrowPage.expectSuccessPage([wstETHdeposit, rETHdeposit], borrow, fork) - await screenshot(page, 'deposit-wsteth-reth-success') + await borrowPage.expectSuccessPage({ + deposited: [ + { asset: 'wstETH', amount: '1.00', usdValue: '$4,665.46' }, + { asset: 'rETH', amount: '1.00', usdValue: '$4,413.26' }, + ], + borrowed: { asset: 'DAI', amount: '1,000.00', usdValue: '$1,000.00' }, + }) }) - test('successfully builds position using only approves', async ({ page }) => { + test('successfully builds position using only approves', async () => { await borrowPage.addNewDepositAssetAction() await borrowPage.fillDepositAssetAction(0, wstETHdeposit.asset, wstETHdeposit.amount) await borrowPage.fillDepositAssetAction(1, rETHdeposit.asset, rETHdeposit.amount) @@ -221,11 +231,16 @@ test.describe('Borrow page', () => { await actionsContainer.switchPreferPermitsAction() await actionsContainer.acceptAllActionsAction(5) - await borrowPage.expectSuccessPage([wstETHdeposit, rETHdeposit], borrow, fork) - await screenshot(page, 'deposit-wsteth-reth-success') + await borrowPage.expectSuccessPage({ + deposited: [ + { asset: 'wstETH', amount: '1.00', usdValue: '$4,665.46' }, + { asset: 'rETH', amount: '1.00', usdValue: '$4,413.26' }, + ], + borrowed: { asset: 'DAI', amount: '1,000.00', usdValue: '$1,000.00' }, + }) }) - test('HF matches after position is created', async ({ page }) => { + test('HF matches after position is created', async () => { await borrowPage.addNewDepositAssetAction() await borrowPage.fillDepositAssetAction(0, wstETHdeposit.asset, wstETHdeposit.amount) await borrowPage.fillDepositAssetAction(1, rETHdeposit.asset, rETHdeposit.amount) @@ -234,23 +249,28 @@ test.describe('Borrow page', () => { await borrowPage.submitAction() await actionsContainer.acceptAllActionsAction(5) - await expectHFOnMyPortfolio(page, borrowPage, expectedHealthFactor) + await expectHFOnMyPortfolio(testContext, borrowPage, expectedHealthFactor) }) }) test.describe('no new deposit, existing position, borrow DAI', () => { let borrowPage: BorrowPageObject let actionsContainer: ActionsPageObject + let testContext: TestContext<'connected-random'> const borrow = { asset: 'DAI', amount: 1000, } - const expectedLTV = '8.04%' - const expectedHealthFactor = '9.89' + const expectedLTV = '9.06%' + const expectedHealthFactor = '8.83' test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -261,9 +281,9 @@ test.describe('Borrow page', () => { }, }) - borrowPage = new BorrowPageObject(page) - actionsContainer = new ActionsPageObject(page) - await borrowPage.depositAssetsActions({ rETH: 5 }, 1000) + borrowPage = new BorrowPageObject(testContext) + actionsContainer = new ActionsPageObject(testContext) + await borrowPage.depositAssetsActions({ assetsToDeposit: { rETH: 5 }, daiToBorrow: 1000 }) await page.reload() }) @@ -276,34 +296,82 @@ test.describe('Borrow page', () => { await borrowPage.expectHealthFactor(expectedHealthFactor) }) - test('builds action plan', async ({ page }) => { + test('builds action plan', async () => { await borrowPage.fillBorrowAssetAction(borrow.amount) await borrowPage.submitAction() await actionsContainer.expectExtendedActions([{ type: 'borrow', asset: 'DAI', amount: '1,000.00' }]) - await screenshot(page, 'borrow-with-no-deposit-actions-plan') }) - test('successfully borrows', async ({ page }) => { + test('successfully borrows', async () => { await borrowPage.fillBorrowAssetAction(borrow.amount) await borrowPage.submitAction() await actionsContainer.acceptAllActionsAction(1) - await borrowPage.expectSuccessPage([], borrow, fork) - await screenshot(page, 'borrow-with-no-deposit-success') + await borrowPage.expectSuccessPage({ + deposited: [], + borrowed: { asset: 'DAI', amount: '1,000.00', usdValue: '$1,000.00' }, + }) }) - test('HF matches after position is created', async ({ page }) => { + test('HF matches after position is created', async () => { await borrowPage.fillBorrowAssetAction(borrow.amount) await borrowPage.submitAction() await actionsContainer.acceptAllActionsAction(1) - await expectHFOnMyPortfolio(page, borrowPage, expectedHealthFactor) + await expectHFOnMyPortfolio(testContext, borrowPage, expectedHealthFactor) + }) + }) + + test('borrows usds', async ({ page }) => { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, + initialPage: 'easyBorrow', + account: { + type: 'connected-random', + assetBalances: { + wstETH: 10, + }, + }, + }) + + const borrowPage = new BorrowPageObject(testContext) + const actionsContainer = new ActionsPageObject(testContext) + + await borrowPage.fillDepositAssetAction(0, 'wstETH', 10) + await borrowPage.selectBorrowAction('USDS') + await borrowPage.fillBorrowAssetAction(10_000) + await borrowPage.submitAction() + + await borrowPage.expectUsdsBorrowAlert() + await actionsContainer.acceptAllActionsAction(5) + await borrowPage.expectSuccessPage({ + deposited: [ + { + asset: 'wstETH', + amount: '10.00', + usdValue: '$46,654.64', + }, + ], + borrowed: { + asset: 'USDS', + amount: '10,000.00', + usdValue: '$10,000.00', + }, }) + + await expectHFOnMyPortfolio(testContext, borrowPage, '3.73') + + await page.goto(buildUrl('savings')) + const savingsPage = new SavingsPageObject(testContext) + await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '10,000') }) test.describe('no wallet connected', () => { @@ -318,27 +386,29 @@ test.describe('Borrow page', () => { } test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'not-connected', }, }) - borrowPage = new BorrowPageObject(page) + borrowPage = new BorrowPageObject(testContext) }) - test('shows borrow rate correctly', async ({ page }) => { + test('shows borrow rate correctly', async () => { await borrowPage.fillDepositAssetAction(0, deposit.asset, deposit.amount) await borrowPage.fillBorrowAssetAction(borrow.amount) - await borrowPage.expectLtv('40.19%') - await screenshot(page, 'borrow-form-not-connected-correct-ltv') + await borrowPage.expectLtv('22.66%') }) - test('form is interactive', async ({ page }) => { + test('form is interactive', async () => { await borrowPage.fillDepositAssetAction(0, deposit.asset, deposit.amount) await borrowPage.fillBorrowAssetAction(borrow.amount) - await screenshot(page, 'borrow-form-not-connected-interactive') }) }) @@ -346,32 +416,35 @@ test.describe('Borrow page', () => { let borrowPage: BorrowPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', assetBalances: { ETH: 10, rETH: 10, - WBTC: 10_000, + cbBTC: 100, }, }, }) - borrowPage = new BorrowPageObject(page) + borrowPage = new BorrowPageObject(testContext) }) - test('is invalid when depositing more than available', async ({ page }) => { + test('is invalid when depositing more than available', async () => { const deposit = { asset: 'ETH', amount: 100, } await borrowPage.fillDepositAssetAction(0, deposit.asset, deposit.amount) await borrowPage.expectAssetInputInvalid('Exceeds your balance') - await screenshot(page, 'borrow-form-deposit-more-than-available') }) - test('is invalid when borrowing more than collateral', async ({ page }) => { + test('is invalid when borrowing more than collateral', async () => { const deposit = { asset: 'ETH', amount: 1, @@ -383,42 +456,44 @@ test.describe('Borrow page', () => { await borrowPage.fillDepositAssetAction(0, deposit.asset, deposit.amount) await borrowPage.fillBorrowAssetAction(borrow.amount) await borrowPage.expectAssetInputInvalid(borrowValidationIssueToMessage['insufficient-collateral']) - await screenshot(page, 'borrow-form-borrow-more-than-available') }) - test('is invalid when borrowing more than available', async ({ page }) => { + test('is invalid when borrowing more than available', async () => { const deposit = { asset: 'ETH', amount: 1, } const borrow = { asset: 'DAI', - amount: 100_000_000, + amount: 1_000_000_000, } await borrowPage.fillDepositAssetAction(0, deposit.asset, deposit.amount) await borrowPage.fillBorrowAssetAction(borrow.amount) await borrowPage.expectAssetInputInvalid(borrowValidationIssueToMessage['exceeds-liquidity']) - await screenshot(page, 'borrow-form-borrow-more-than-available') }) test('is valid when not depositing anything but having existing position', async ({ page }) => { - await borrowPage.depositAssetsActions({ rETH: 5 }, 1000) + await borrowPage.depositAssetsActions({ assetsToDeposit: { rETH: 5 }, daiToBorrow: 1000 }) await page.reload() await borrowPage.fillBorrowAssetAction(1000) await borrowPage.expectBorrowButtonActive() - await screenshot(page, 'borrow-form-has-position') }) test('is invalid when breaching supply cap', async () => { - await borrowPage.fillDepositAssetAction(0, 'WBTC', 10_000) + await borrowPage.fillDepositAssetAction(0, 'cbBTC', 100) await borrowPage.expectAssetInputInvalid('Deposit cap reached') }) }) test.describe('depositable assets', () => { + let testContext: TestContext<'connected-random'> test.beforeEach(async ({ page }) => { - await setup(page, fork, { + testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -427,23 +502,22 @@ test.describe('Borrow page', () => { }) }) - test('deposit asset, turn off usage as collateral, try to deposit again', async ({ page }) => { + test('deposit asset, turn off usage as collateral, try to deposit again', async () => { const collateral = 'wstETH' // Only depositing asset - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ [collateral]: 5 }) - const myPortfolioPage = new MyPortfolioPageObject(page) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: { [collateral]: 5 } }) + const myPortfolioPage = new MyPortfolioPageObject(testContext) await myPortfolioPage.goToMyPortfolioAction() // Turning off usage as collateral at myPortfolio await myPortfolioPage.expectCollateralSwitch(collateral, true) await myPortfolioPage.clickCollateralSwitchAction(collateral) - const collateralDialog = new CollateralDialogPageObject(page) + const collateralDialog = new CollateralDialogPageObject(testContext) await collateralDialog.expectDialogHeader('Collateral') await collateralDialog.expectHealthFactorNotVisible() - const actionsContainer = new ActionsPageObject(collateralDialog.locatePanelByHeader('Actions')) - await actionsContainer.acceptAllActionsAction(1) + await collateralDialog.actionsContainer.acceptAllActionsAction(1) await collateralDialog.expectSetUseAsCollateralSuccessPage(collateral, 'disabled') // Expecting asset not listed in deposit selector after turning off usage as collateral @@ -457,7 +531,11 @@ test.describe('Borrow page', () => { test.describe('In danger zone', () => { test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -465,9 +543,9 @@ test.describe('Borrow page', () => { }, }) - borrowPage = new BorrowPageObject(page) + borrowPage = new BorrowPageObject(testContext) await borrowPage.fillDepositAssetAction(0, 'rETH', 1) - await borrowPage.fillBorrowAssetAction(1500) + await borrowPage.fillBorrowAssetAction(3400) await borrowPage.submitAction() }) @@ -478,15 +556,18 @@ test.describe('Borrow page', () => { }) test('actions stay disabled until risk warning is acknowledged', async () => { - const actionsContainer = new ActionsPageObject(borrowPage.locatePanelByHeader('Actions')) - await actionsContainer.expectDisabledActionAtIndex(0) + await borrowPage.actionsContainer.expectDisabledActionAtIndex(0) await borrowPage.clickAcknowledgeRisk() - await actionsContainer.expectEnabledActionAtIndex(0) + await borrowPage.actionsContainer.expectEnabledActionAtIndex(0) }) }) test('hf above danger zone threshold; risk warning is not shown', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -494,7 +575,7 @@ test.describe('Borrow page', () => { }, }) - const borrowPage = new BorrowPageObject(page) + const borrowPage = new BorrowPageObject(testContext) await borrowPage.fillDepositAssetAction(0, 'rETH', 1) await borrowPage.fillBorrowAssetAction(1000) await borrowPage.submitAction() @@ -504,67 +585,13 @@ test.describe('Borrow page', () => { }) }) -test.describe('Borrow page (usds deployed)', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) - let borrowPage: BorrowPageObject - let actionsContainer: ActionsPageObject - - test.beforeEach(async ({ page }) => { - await setup(page, fork, { - initialPage: 'easyBorrow', - account: { - type: 'connected-random', - assetBalances: { - wstETH: 10, - }, - }, - }) - - borrowPage = new BorrowPageObject(page) - actionsContainer = new ActionsPageObject(page) - }) - - test('borrows usds', async ({ page }) => { - await borrowPage.fillDepositAssetAction(0, 'wstETH', 10) - await borrowPage.selectBorrowAction('USDS') - await borrowPage.fillBorrowAssetAction(10_000) - await borrowPage.submitAction() - - await borrowPage.expectUsdsBorrowAlert() - await actionsContainer.acceptAllActionsAction(5) - await borrowPage.expectSuccessPage( - [ - { - asset: 'wstETH', - amount: 10, - }, - ], - { - asset: 'USDS', - amount: 10_000, - }, - fork, - { - wstETH: 27_843.94, - USDS: 10_000, - }, - ) - - await expectHFOnMyPortfolio(page, borrowPage, '2.23') - - await page.goto(buildUrl('savings')) - const savingsPage = new SavingsPageObject(page) - await savingsPage.expectStablecoinsInWalletAssetBalance('USDS', '10,000') - }) -}) - async function expectHFOnMyPortfolio( - page: Page, + testContext: TestContext, borrowPage: BorrowPageObject, expectedHealthFactor: string, ): Promise { await borrowPage.viewInMyPortfolioAction() - const myPortfolioPage = new MyPortfolioPageObject(page) + const myPortfolioPage = new MyPortfolioPageObject(testContext) await myPortfolioPage.expectHealthFactor(expectedHealthFactor) } diff --git a/packages/app/src/pages/Farms.test-e2e.ts b/packages/app/src/pages/Farms.test-e2e.ts index 4dfe19bbc..249b04ed7 100644 --- a/packages/app/src/pages/Farms.test-e2e.ts +++ b/packages/app/src/pages/Farms.test-e2e.ts @@ -1,5 +1,4 @@ -import { USDS_ACTIVATED_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { overrideInfoSkyRouteWithHAR } from '@/test/e2e/info-sky' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' @@ -7,11 +6,14 @@ import { mainnet } from 'viem/chains' import { FarmsPageObject } from './Farms.PageObject' test.describe('Farms', () => { - const fork = setupFork({ blockNumber: USDS_ACTIVATED_BLOCK_NUMBER, chainId: mainnet.id, useTenderlyVnet: true }) let farmsPage: FarmsPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'farms', account: { type: 'not-connected', @@ -19,7 +21,7 @@ test.describe('Farms', () => { }) await overrideInfoSkyRouteWithHAR({ page, key: '1-sky-farm-with-8_51-apy' }) - farmsPage = new FarmsPageObject(page) + farmsPage = new FarmsPageObject(testContext) }) test('farms list', async () => { diff --git a/packages/app/src/pages/MarketDetails.test-e2e.ts b/packages/app/src/pages/MarketDetails.test-e2e.ts index b356b6037..91aeeffca 100644 --- a/packages/app/src/pages/MarketDetails.test-e2e.ts +++ b/packages/app/src/pages/MarketDetails.test-e2e.ts @@ -1,11 +1,8 @@ -import { test } from '@playwright/test' -import { gnosis, mainnet } from 'viem/chains' - import { DialogPageObject } from '@/features/dialogs/common/Dialog.PageObject' -import { CAP_AUTOMATOR_BLOCK_NUMBER, GNOSIS_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER, GNOSIS_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { buildUrl, setup } from '@/test/e2e/setup' -import { screenshot } from '@/test/e2e/utils' +import { test } from '@playwright/test' +import { gnosis, mainnet } from 'viem/chains' import { BorrowPageObject } from './Borrow.PageObject' import { MarketDetailsPageObject } from './MarketDetails.PageObject' @@ -17,70 +14,70 @@ test.describe('Market details Mainnet', () => { const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' const WBTC = '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599' - const fork = setupFork({ - blockNumber: CAP_AUTOMATOR_BLOCK_NUMBER, - chainId: mainnet.id, - simulationDateOverride: new Date('2024-09-04T14:21:19Z'), - }) - test.describe('Market overview', () => { test('DAI', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: DAI, chainId: fork.chainId.toString() }, + initialPageParams: { asset: DAI, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) - await marketDetailsPage.expectMarketOverviewValue('Borrowed', '$910.8M') - await marketDetailsPage.expectMarketOverviewValue('Instantly available', '$44.01M') - await marketDetailsPage.expectMarketOverviewValue('Sky capacity', '$1.586B') - - await screenshot(page, 'market-details-dai') + const marketDetailsPage = new MarketDetailsPageObject(testContext) + await marketDetailsPage.expectMarketOverviewValue('Borrowed', '$1.626B') + await marketDetailsPage.expectMarketOverviewValue('Instantly available', '$112.8M') + await marketDetailsPage.expectMarketOverviewValue('Sky capacity', '$793.4M') }) test('WETH', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: WETH, chainId: fork.chainId.toString() }, + initialPageParams: { asset: WETH, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) - await marketDetailsPage.expectMarketOverviewValue('Borrowed', '$571.1M') - await marketDetailsPage.expectMarketOverviewValue('Instantly available', '$125.4M') - - await screenshot(page, 'market-details-weth') + const marketDetailsPage = new MarketDetailsPageObject(testContext) + await marketDetailsPage.expectMarketOverviewValue('Borrowed', '$1.365B') + await marketDetailsPage.expectMarketOverviewValue('Instantly available', '$171M') }) test.describe('token that cannot be borrowed', () => { test('overview is visible when borrowed balance greater than non-zero', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'marketDetails', - initialPageParams: { asset: WBTC, chainId: fork.chainId.toString() }, + initialPageParams: { asset: WBTC, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectToBeLoaded() }) test('overview is hidden when borrowed balance equal zero', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'marketDetails', - initialPageParams: { asset: WEETH, chainId: fork.chainId.toString() }, + initialPageParams: { asset: WEETH, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectMarketOverviewToBeHidden() }) }) @@ -92,15 +89,16 @@ test.describe('Market details Mainnet', () => { } test('guest state', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: DAI, chainId: fork.chainId.toString() }, + initialPageParams: { asset: DAI, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectToBeLoaded() @@ -111,15 +109,16 @@ test.describe('Market details Mainnet', () => { }) test("can't deposit if not enough balance", async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: WETH, chainId: fork.chainId.toString() }, + initialPageParams: { asset: WETH, chainId: mainnet.id.toString() }, account: { type: 'connected-random', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectToBeLoaded() @@ -127,15 +126,16 @@ test.describe('Market details Mainnet', () => { }) test("can't lend if not enough balance", async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: DAI, chainId: fork.chainId.toString() }, + initialPageParams: { asset: DAI, chainId: mainnet.id.toString() }, account: { type: 'connected-random', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectToBeLoaded() @@ -143,15 +143,16 @@ test.describe('Market details Mainnet', () => { }) test("can't borrow if not enough balance", async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: DAI, chainId: fork.chainId.toString() }, + initialPageParams: { asset: DAI, chainId: mainnet.id.toString() }, account: { type: 'connected-random', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectToBeLoaded() @@ -160,7 +161,8 @@ test.describe('Market details Mainnet', () => { }) test('opens dialogs for DAI', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -172,31 +174,32 @@ test.describe('Market details Mainnet', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ ...initialDeposits }) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: initialDeposits }) - await page.goto(buildUrl('marketDetails', { asset: DAI, chainId: fork.chainId.toString() })) + await page.goto(buildUrl('marketDetails', { asset: DAI, chainId: mainnet.id.toString() })) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.openDialogAction('Lend') - const lendDialog = new DialogPageObject(page, /Deposit/i) + const lendDialog = new DialogPageObject({ testContext, header: /Deposit/i }) await lendDialog.expectDialogHeader('Deposit DAI') await lendDialog.closeDialog() await marketDetailsPage.openDialogAction('Deposit') - const depositDialog = new DialogPageObject(page, /Deposit/i) + const depositDialog = new DialogPageObject({ testContext, header: /Deposit/i }) await depositDialog.expectDialogHeader('Deposit sDAI') await depositDialog.closeDialog() await marketDetailsPage.openDialogAction('Borrow') - const borrowDialog = new DialogPageObject(page, /Borrow/i) + const borrowDialog = new DialogPageObject({ testContext, header: /Borrow/i }) await borrowDialog.expectDialogHeader('Borrow DAI') await borrowDialog.closeDialog() }) test('opens dialogs for WETH', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -207,27 +210,28 @@ test.describe('Market details Mainnet', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ ...initialDeposits }) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: initialDeposits }) - await page.goto(buildUrl('marketDetails', { asset: WETH, chainId: fork.chainId.toString() })) + await page.goto(buildUrl('marketDetails', { asset: WETH, chainId: mainnet.id.toString() })) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.openDialogAction('Deposit') - const lendDialog = new DialogPageObject(page, /Deposit/i) + const lendDialog = new DialogPageObject({ testContext, header: /Deposit/i }) await lendDialog.expectDialogHeader('Deposit WETH') await lendDialog.closeDialog() await marketDetailsPage.openDialogAction('Borrow') - const borrowDialog = new DialogPageObject(page, /Borrow/i) + const borrowDialog = new DialogPageObject({ testContext, header: /Borrow/i }) await borrowDialog.expectDialogHeader('Borrow WETH') await borrowDialog.closeDialog() }) // @todo: this scenario is inaccurate, because user has only ETH - in future dialog should open on ETH tab test('opens dialogs for WETH when having only ETH', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -238,32 +242,33 @@ test.describe('Market details Mainnet', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositWithoutBorrowActions({ ...initialDeposits }) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositWithoutBorrowActions({ assetsToDeposit: initialDeposits }) - await page.goto(buildUrl('marketDetails', { asset: WETH, chainId: fork.chainId.toString() })) + await page.goto(buildUrl('marketDetails', { asset: WETH, chainId: mainnet.id.toString() })) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectWalletBalance('5.00 WETH') await marketDetailsPage.openDialogAction('Deposit') - const lendDialog = new DialogPageObject(page, /Deposit/i) + const lendDialog = new DialogPageObject({ testContext, header: /Deposit/i }) await lendDialog.expectDialogHeader('Deposit WETH') await lendDialog.closeDialog() await marketDetailsPage.openDialogAction('Borrow') - const borrowDialog = new DialogPageObject(page, /Borrow/i) + const borrowDialog = new DialogPageObject({ testContext, header: /Borrow/i }) await borrowDialog.expectDialogHeader('Borrow WETH') await borrowDialog.closeDialog() }) test('wallet displays sum of WETH and ETH', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', initialPageParams: { asset: WETH, - chainId: fork.chainId.toString(), + chainId: mainnet.id.toString(), }, account: { type: 'connected-random', @@ -275,28 +280,26 @@ test.describe('Market details Mainnet', () => { }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectWalletBalance('15.00 WETH') }) }) test.describe('Isolated assets', () => { - const BLOCK_NUMBER_WITH_WEETH = 20118125n - const fork = setupFork({ blockNumber: BLOCK_NUMBER_WITH_WEETH, chainId: mainnet.id }) - test('Correctly displays debt ceiling', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: WEETH, chainId: fork.chainId.toString() }, + initialPageParams: { asset: WEETH, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) - await marketDetailsPage.expectDebt('$3.17M') - await marketDetailsPage.expectDebtCeiling('$50M') + const marketDetailsPage = new MarketDetailsPageObject(testContext) + await marketDetailsPage.expectDebt('$89M') + await marketDetailsPage.expectDebtCeiling('$200M') }) }) @@ -304,7 +307,8 @@ test.describe('Market details Mainnet', () => { const NOT_A_RESERVE = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266' test('displays 404 page for unknown chain', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', initialPageParams: { asset: DAI, chainId: '12345' }, account: { @@ -312,55 +316,58 @@ test.describe('Market details Mainnet', () => { }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expect404() }) test('displays 404 page for unknown asset', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: NOT_A_RESERVE, chainId: fork.chainId.toString() }, + initialPageParams: { asset: NOT_A_RESERVE, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expect404() }) }) test.describe('Cap automator', () => { test('WETH', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: WETH, chainId: fork.chainId.toString() }, + initialPageParams: { asset: WETH, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) - await marketDetailsPage.expectSupplyCap('403.2K WETH') + await marketDetailsPage.expectSupplyCap('569.9K WETH') await marketDetailsPage.expectSupplyMaxCap('2M WETH') await marketDetailsPage.expectSupplyCapCooldown('0h 00m 00s') - await marketDetailsPage.expectBorrowCap('256K WETH') + await marketDetailsPage.expectBorrowCap('368.2K WETH') await marketDetailsPage.expectBorrowMaxCap('1M WETH') await marketDetailsPage.expectBorrowCapCooldown('0h 00m 00s') }) test('USDC', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: USDC, chainId: fork.chainId.toString() }, + initialPageParams: { asset: USDC, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectSupplyPanelNotVisible() @@ -370,18 +377,19 @@ test.describe('Market details Mainnet', () => { }) test('WBTC', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: WBTC, chainId: fork.chainId.toString() }, + initialPageParams: { asset: WBTC, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) - await marketDetailsPage.expectSupplyCap('4,780 WBTC') - await marketDetailsPage.expectSupplyMaxCap('10K WBTC') + await marketDetailsPage.expectSupplyCap('1,941 WBTC') + await marketDetailsPage.expectSupplyMaxCap('5,000 WBTC') await marketDetailsPage.expectSupplyCapCooldown('0h 00m 00s') await marketDetailsPage.expectBorrowPanelNotVisible() @@ -392,15 +400,16 @@ test.describe('Market details Mainnet', () => { test.describe('Oracles', () => { test('Fixed price', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: DAI, chainId: fork.chainId.toString() }, + initialPageParams: { asset: DAI, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectOraclePanelToHaveTitle('Fixed Price') @@ -411,52 +420,54 @@ test.describe('Market details Mainnet', () => { }) }) test('Market price - not redundant', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: WBTC, chainId: fork.chainId.toString() }, + initialPageParams: { asset: WBTC, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectOraclePanelToHaveTitle('Market Price') await marketDetailsPage.expectOracleToBeNotRedundant() await marketDetailsPage.expectOracleInfo({ - price: '$58,229.82', + price: '$101,496.42', asset: 'WBTC', oracleContract: '0x230E0321Cf38F09e247e50Afc7801EA2351fe56F', }) }) test('Yielding fixed price - redundant', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'marketDetails', - initialPageParams: { asset: WEETH, chainId: fork.chainId.toString() }, + initialPageParams: { asset: WEETH, chainId: mainnet.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectOraclePanelToHaveTitle('Yielding Fixed Price') await marketDetailsPage.expectOracleToBeRedundant() await marketDetailsPage.expectOracleInfo({ - price: '$2,576.50', + price: '$4,145.06', asset: 'weETH', - oracleContract: '0x1A6BDB22b9d7a454D20EAf12DB55D6B5F058183D', + oracleContract: '0x28897036f8459bFBa886083dD6b4Ce4d2f14a57F', }) await marketDetailsPage.expectYieldingFixedOracleBaseAssetInfo({ asset: 'WETH', - price: '$2,460.69', - oracleContract: '0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419', + price: '$3,928.31', + oracleContract: '0xb20A1374EfCaFa32F701Ab14316fA2E5b3400eD5', }) await marketDetailsPage.expectYieldingFixedOracleRatioInfo({ - ratio: '1.0471', + ratio: '1.0552', ratioContract: '0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee', }) }) @@ -469,23 +480,18 @@ test.describe('Market details Gnosis', () => { const WETH = '0x6A023CCd1ff6F2045C3309768eAd9E68F978f6e1' const sDAI = '0xaf204776c7245bF4147c2612BF6e5972Ee483701' - const fork = setupFork({ - blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, - chainId: gnosis.id, - useTenderlyVnet: true, - }) - test.describe('Cap automator', () => { test('WETH', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id }, initialPage: 'marketDetails', - initialPageParams: { asset: WETH, chainId: fork.chainId.toString() }, + initialPageParams: { asset: WETH, chainId: gnosis.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectSupplyCap('5,000 WETH') await marketDetailsPage.expectSupplyMaxCapNotVisible() @@ -495,15 +501,16 @@ test.describe('Market details Gnosis', () => { }) test('XDAI', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id }, initialPage: 'marketDetails', - initialPageParams: { asset: XDAI, chainId: fork.chainId.toString() }, + initialPageParams: { asset: XDAI, chainId: gnosis.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectSupplyCap('20M WXDAI') await marketDetailsPage.expectSupplyMaxCapNotVisible() @@ -517,15 +524,16 @@ test.describe('Market details Gnosis', () => { test.describe('Oracles', () => { test('Fixed price', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id }, initialPage: 'marketDetails', - initialPageParams: { asset: XDAI, chainId: fork.chainId.toString() }, + initialPageParams: { asset: XDAI, chainId: gnosis.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectOraclePanelToHaveTitle('Fixed Price') @@ -537,15 +545,16 @@ test.describe('Market details Gnosis', () => { }) test('Underlying asset price', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id }, initialPage: 'marketDetails', - initialPageParams: { asset: EURe, chainId: fork.chainId.toString() }, + initialPageParams: { asset: EURe, chainId: gnosis.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectOraclePanelToHaveTitle('Underlying Asset Price') @@ -557,15 +566,16 @@ test.describe('Market details Gnosis', () => { }) test('Yielding fixed price - not redundant', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id }, initialPage: 'marketDetails', - initialPageParams: { asset: sDAI, chainId: fork.chainId.toString() }, + initialPageParams: { asset: sDAI, chainId: gnosis.id.toString() }, account: { type: 'not-connected', }, }) - const marketDetailsPage = new MarketDetailsPageObject(page) + const marketDetailsPage = new MarketDetailsPageObject(testContext) await marketDetailsPage.expectOraclePanelToHaveTitle('Yielding Fixed Price') await marketDetailsPage.expectOracleToBeNotRedundant() diff --git a/packages/app/src/pages/Markets.test-e2e.ts b/packages/app/src/pages/Markets.test-e2e.ts index 6cd2c120a..fb69d5f40 100644 --- a/packages/app/src/pages/Markets.test-e2e.ts +++ b/packages/app/src/pages/Markets.test-e2e.ts @@ -1,31 +1,33 @@ -import { WEETH_ACTIVE_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' +import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { mainnet } from 'viem/chains' import { MarketsPageObject } from './Markets.PageObject' test.describe('Markets', () => { - const fork = setupFork({ blockNumber: WEETH_ACTIVE_BLOCK_NUMBER, chainId: mainnet.id }) let marketsPage: MarketsPageObject test.beforeEach(async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + chainId: mainnet.id, + blockNumber: DEFAULT_BLOCK_NUMBER, + }, initialPage: 'markets', account: { type: 'not-connected', }, }) - marketsPage = new MarketsPageObject(page) + marketsPage = new MarketsPageObject(testContext) }) test('summary', async () => { await marketsPage.expectSummary([ - { description: 'Total market size', value: '$4.441B' }, - { description: 'Total value locked', value: '$2.869B' }, - { description: 'Total available', value: '$2.904B' }, - { description: 'Total borrows', value: '$1.537B' }, + { description: 'Total market size', value: '$8.145B' }, + { description: 'Total value locked', value: '$5.068B' }, + { description: 'Total available', value: '$5.149B' }, + { description: 'Total borrows', value: '$2.997B' }, ]) }) @@ -37,15 +39,15 @@ test.describe('Markets', () => { symbol: 'wstETH', }, totalSupplied: { - tokenAmount: '519K', - usdValue: '$2.06B', + tokenAmount: '861.3K', + usdValue: '$4.018B', }, depositAPY: { value: '<0.01%', }, totalBorrowed: { - tokenAmount: '51.56', - usdValue: '$204.7K', + tokenAmount: '98.42', + usdValue: '$459.2K', }, borrowAPY: { value: '0.25%', @@ -62,19 +64,19 @@ test.describe('Markets', () => { symbol: 'DAI', }, totalSupplied: { - tokenAmount: '962.8M', - usdValue: '$962.8M', + tokenAmount: '1.739B', + usdValue: '$1.739B', }, depositAPY: { // @note: This value is different in production since VITE_FEATURE_DISABLE_DAI_LEND is disabled in playwright tests - value: '8.52%', + value: '11.69%', }, totalBorrowed: { - tokenAmount: '913.6M', - usdValue: '$913.6M', + tokenAmount: '1.626B', + usdValue: '$1.626B', }, borrowAPY: { - value: '9.00%', + value: '12.55%', hasAirDrop: true, }, status: { @@ -90,19 +92,19 @@ test.describe('Markets', () => { symbol: 'ETH', }, totalSupplied: { - tokenAmount: '252.1K', - usdValue: '$854.8M', + tokenAmount: '391.1K', + usdValue: '$1.536B', }, depositAPY: { - value: '1.31%', + value: '2.03%', hasAirDrop: true, }, totalBorrowed: { - tokenAmount: '177K', - usdValue: '$600M', + tokenAmount: '347.6K', + usdValue: '$1.365B', }, borrowAPY: { - value: '1.97%', + value: '2.41%', }, status: { supply: 'Can be supplied', @@ -112,22 +114,22 @@ test.describe('Markets', () => { }, { asset: { - name: 'Wrapped BTC', - symbol: 'WBTC', + name: 'Coinbase Wrapped BTC', + symbol: 'cbBTC', }, totalSupplied: { - tokenAmount: '5,790', - usdValue: '$358M', + tokenAmount: '2,950', + usdValue: '$300M', }, depositAPY: { value: '<0.01%', }, totalBorrowed: { - tokenAmount: '332.8', - usdValue: '$20.58M', + tokenAmount: '5.65', + usdValue: '$574.6K', }, borrowAPY: { - value: '0.19%', + value: '0.01%', }, status: { supply: 'Can be supplied', @@ -137,57 +139,80 @@ test.describe('Markets', () => { }, { asset: { - name: 'Rocket Pool Staked ETH', - symbol: 'rETH', + name: 'Ether.fi Staked ETH', + symbol: 'weETH', }, totalSupplied: { - tokenAmount: '38.95K', - usdValue: '$146.5M', + tokenAmount: '51.75', + usdValue: '$214.5M', + }, + depositAPY: { + value: '0.00%', + }, + totalBorrowed: undefined, + borrowAPY: undefined, + status: { + supply: 'Can be supplied', + collateral: 'Can be used as collateral only in isolation mode', + borrow: 'Cannot be borrowed', + }, + }, + { + asset: { + name: 'Wrapped BTC', + symbol: 'WBTC', + }, + totalSupplied: { + tokenAmount: '1,742', + usdValue: '$176.8', }, depositAPY: { value: '<0.01%', }, totalBorrowed: { - tokenAmount: '6.271', - usdValue: '$23.59K', - }, - borrowAPY: { - value: '0.25%', + tokenAmount: '18.12', + usdValue: '$1.839M', }, + borrowAPY: undefined, status: { supply: 'Can be supplied', - collateral: 'Can be used as collateral', - borrow: 'Can be borrowed', + collateral: 'Cannot be used as collateral', + borrow: 'Cannot be borrowed', }, }, { asset: { - name: 'Ether.fi Staked ETH', - symbol: 'weETH', + name: 'Rocket Pool Staked ETH', + symbol: 'rETH', }, totalSupplied: { - tokenAmount: '11.66K', - usdValue: '$41.17M', + tokenAmount: '34.47K', + usdValue: '$152.1M', }, depositAPY: { - value: '0.00%', + value: '<0.01%', + }, + totalBorrowed: { + tokenAmount: '7.991', + usdValue: '$35.26K', + }, + borrowAPY: { + value: '0.25%', }, - totalBorrowed: undefined, - borrowAPY: undefined, status: { supply: 'Can be supplied', - collateral: 'Can be used as collateral only in isolation mode', - borrow: 'Cannot be borrowed', + collateral: 'Can be used as collateral', + borrow: 'Can be borrowed', }, }, { asset: { - name: 'Savings Dai', - symbol: 'sDAI', + name: 'Savings USDS', + symbol: 'sUSDS', }, totalSupplied: { - tokenAmount: '13.49M', - usdValue: '$14.73M', + tokenAmount: '4.154M', + usdValue: '$4.226M', }, depositAPY: { value: '0.00%', @@ -206,18 +231,18 @@ test.describe('Markets', () => { symbol: 'USDC', }, totalSupplied: { - tokenAmount: '2.559M', - usdValue: '$2.559M', + tokenAmount: '1.916M', + usdValue: '$1.916M', }, depositAPY: { - value: '5.90%', + value: '16.20%', }, totalBorrowed: { - tokenAmount: '2.077M', - usdValue: '$2.077M', + tokenAmount: '1.849M', + usdValue: '$1.849M', }, borrowAPY: { - value: '7.72%', + value: '17.79%', }, status: { supply: 'Can be supplied', @@ -225,24 +250,44 @@ test.describe('Markets', () => { borrow: 'Can be borrowed', }, }, + { + asset: { + name: 'Savings Dai', + symbol: 'sDAI', + }, + totalSupplied: { + tokenAmount: '1.25M', + usdValue: '$1.407M', + }, + depositAPY: { + value: '0.00%', + }, + totalBorrowed: undefined, + borrowAPY: undefined, + status: { + supply: 'Can be supplied', + collateral: 'Can be used as collateral', + borrow: 'Cannot be borrowed', + }, + }, { asset: { name: 'Tether USD', symbol: 'USDT', }, totalSupplied: { - tokenAmount: '316.6K', - usdValue: '$316.6K', + tokenAmount: '579.3K', + usdValue: '$579.3K', }, depositAPY: { - value: '4.03%', + value: '6.58%', }, totalBorrowed: { - tokenAmount: '213.2K', - usdValue: '$213.2K', + tokenAmount: '424.3K', + usdValue: '$424.3K', }, borrowAPY: { - value: '6.36%', + value: '9.60%', }, status: { supply: 'Can be supplied', @@ -263,8 +308,8 @@ test.describe('Markets', () => { isFrozen: true, }, totalSupplied: { - tokenAmount: '55.1', - usdValue: '$15.91K', + tokenAmount: '5', + usdValue: '$1,459', }, depositAPY: undefined, totalBorrowed: undefined, diff --git a/packages/app/src/pages/MyPortfolio.PageObject.ts b/packages/app/src/pages/MyPortfolio.PageObject.ts index cfcf5465b..ed4d03133 100644 --- a/packages/app/src/pages/MyPortfolio.PageObject.ts +++ b/packages/app/src/pages/MyPortfolio.PageObject.ts @@ -1,9 +1,8 @@ -import { USD_MOCK_TOKEN } from '@/domain/types/Token' import { BasePageObject } from '@/test/e2e/BasePageObject' import { buildUrl } from '@/test/e2e/setup' import { parseTable } from '@/test/e2e/utils' import { testIds } from '@/ui/utils/testIds' -import { assert, NormalizedUnitNumber } from '@marsfoundation/common-universal' +import { assert } from '@marsfoundation/common-universal' import { expect } from '@playwright/test' import { z } from 'zod' @@ -98,21 +97,22 @@ export class MyPortfolioPageObject extends BasePageObject { await expect(locator).toHaveText(hf) } - async expectDepositedAssets(total: number): Promise { + async expectDepositedAssets(total: string): Promise { const locator = this.page.getByTestId(testIds.myPortfolio.deposited) - await expect(locator).toHaveText(USD_MOCK_TOKEN.formatUSD(NormalizedUnitNumber(total), { compact: true })) + await expect(locator).toHaveText(total) } - async expectBorrowedAssets(total: number): Promise { + async expectBorrowedAssets(total: string): Promise { const locator = this.page.getByTestId(testIds.myPortfolio.borrowed) - await expect(locator).toHaveText(USD_MOCK_TOKEN.formatUSD(NormalizedUnitNumber(total), { compact: true })) + await expect(locator).toHaveText(total) } async expectGuestScreen(): Promise { await expect( - this.page.getByRole('heading', { name: 'This page is available ony for connected users', exact: true }), + this.page.getByRole('heading', { name: 'Connect your wallet to use Spark', exact: true }), ).toBeVisible() await expect(this.page.getByRole('button', { name: 'Connect wallet', exact: true })).toBeVisible() + await expect(this.page.getByRole('button', { name: 'Try in Sandbox Mode', exact: true })).toBeVisible() } async expectDepositTable(assets: Record): Promise { diff --git a/packages/app/src/pages/MyPortfolio.test-e2e.ts b/packages/app/src/pages/MyPortfolio.test-e2e.ts index c2423985f..a2cdc5253 100644 --- a/packages/app/src/pages/MyPortfolio.test-e2e.ts +++ b/packages/app/src/pages/MyPortfolio.test-e2e.ts @@ -1,43 +1,41 @@ -import { test } from '@playwright/test' -import { mainnet } from 'viem/chains' - import { DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { setup } from '@/test/e2e/setup' -import { calculateAssetsWorth, screenshot } from '@/test/e2e/utils' - +import { test } from '@playwright/test' +import { mainnet } from 'viem/chains' import { BorrowPageObject } from './Borrow.PageObject' import { MyPortfolioPageObject } from './MyPortfolio.PageObject' test.describe('MyPortfolio', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) - - test.skip('guest state', async ({ page }) => { - await setup(page, fork, { + test('guest state', async ({ page }) => { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, account: { type: 'not-connected', }, initialPage: 'myPortfolio', }) - const myPortfolioPage = new MyPortfolioPageObject(page) + const myPortfolioPage = new MyPortfolioPageObject(testContext) await myPortfolioPage.expectGuestScreen() - - await screenshot(page, 'myPortfolio-guest') }) test('empty account', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'myPortfolio', account: { type: 'connected-random', }, }) - const myPortfolioPage = new MyPortfolioPageObject(page) + const myPortfolioPage = new MyPortfolioPageObject(testContext) await myPortfolioPage.expectPositionToBeEmpty() - - await screenshot(page, 'myPortfolio-empty-account') }) test('no position', async ({ page }) => { @@ -48,14 +46,18 @@ test.describe('MyPortfolio', () => { USDC: 400, WETH: 1, } - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'myPortfolio', account: { type: 'connected-random', assetBalances, }, }) - const myPortfolioPage = new MyPortfolioPageObject(page) + const myPortfolioPage = new MyPortfolioPageObject(testContext) await myPortfolioPage.expectPositionToBeEmpty() await myPortfolioPage.expectBalancesInDepositTable({ @@ -64,8 +66,6 @@ test.describe('MyPortfolio', () => { sDAI: 300, USDC: 400, }) - - await screenshot(page, 'myPortfolio-no-position') }) test('with open position', async ({ page }) => { @@ -74,7 +74,11 @@ test.describe('MyPortfolio', () => { rETH: 2, } const daiToBorrow = 1500 - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: DEFAULT_BLOCK_NUMBER, + chainId: mainnet.id, + }, initialPage: 'easyBorrow', account: { type: 'connected-random', @@ -82,20 +86,18 @@ test.describe('MyPortfolio', () => { }, }) - const borrowPage = new BorrowPageObject(page) - await borrowPage.depositAssetsActions(assetsToDeposit, daiToBorrow) + const borrowPage = new BorrowPageObject(testContext) + await borrowPage.depositAssetsActions({ assetsToDeposit, daiToBorrow }) await borrowPage.viewInMyPortfolioAction() - const myPortfolioPage = new MyPortfolioPageObject(page) - await myPortfolioPage.expectHealthFactor('5.42') - await myPortfolioPage.expectDepositedAssets((await calculateAssetsWorth(fork.forkUrl, assetsToDeposit)).total) - await myPortfolioPage.expectBorrowedAssets((await calculateAssetsWorth(fork.forkUrl, { DAI: daiToBorrow })).total) + const myPortfolioPage = new MyPortfolioPageObject(testContext) + await myPortfolioPage.expectHealthFactor('9.68') + await myPortfolioPage.expectDepositedAssets('$18.16K') + await myPortfolioPage.expectBorrowedAssets('$1,500') await myPortfolioPage.expectDepositTable(assetsToDeposit) await myPortfolioPage.expectBalancesInDepositTable({ DAI: daiToBorrow, }) - - await screenshot(page, 'myPortfolio-open-position') }) }) diff --git a/packages/app/src/pages/Savings.PageObject.ts b/packages/app/src/pages/Savings.PageObject.ts index aad8491bf..5f461cfb7 100644 --- a/packages/app/src/pages/Savings.PageObject.ts +++ b/packages/app/src/pages/Savings.PageObject.ts @@ -158,7 +158,16 @@ export class SavingsPageObject extends BasePageObject { async expectStablecoinsInWalletAssetBalance(assetName: string, value: string): Promise { const panel = this.locateStablecoinsInWalletPanel() - const row = panel.getByRole('row').filter({ has: this.page.getByRole('cell', { name: assetName, exact: true }) }) + const row = (() => { + if (assetName === 'DAI' && value !== '-') { + return panel + .getByRole('row') + .filter({ has: this.page.getByTestId(testIds.savings.stablecoinsInWallet.upgradeDaiToUsdsCell) }) + } + + return panel.getByRole('row').filter({ has: this.page.getByRole('cell', { name: assetName, exact: true }) }) + })() + await expect(row.getByRole('cell', { name: value })).toBeVisible() } diff --git a/packages/app/src/pages/Savings.test-e2e.ts b/packages/app/src/pages/Savings.test-e2e.ts index 3bf32dcee..7c74f5780 100644 --- a/packages/app/src/pages/Savings.test-e2e.ts +++ b/packages/app/src/pages/Savings.test-e2e.ts @@ -1,31 +1,29 @@ +import { BASE_DEFAULT_BLOCK_NUMBER, DEFAULT_BLOCK_NUMBER, GNOSIS_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' +import { setup } from '@/test/e2e/setup' import { test } from '@playwright/test' import { base, gnosis, mainnet } from 'viem/chains' -import { DEFAULT_BLOCK_NUMBER, GNOSIS_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' -import { setup } from '@/test/e2e/setup' - import { SavingsPageObject } from './Savings.PageObject' test.describe('Savings Mainnet', () => { - const fork = setupFork({ blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }) - test('guest state', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'savings', account: { type: 'not-connected', }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) - await savingsPage.expectAPY('5%') + await savingsPage.expectAPY('12.5%') await savingsPage.expectConnectWalletCTA() }) test('calculates current value', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'savings', account: { type: 'connected-random', @@ -35,16 +33,17 @@ test.describe('Savings Mainnet', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '100.00', - estimatedDaiValue: '107.1505', + estimatedDaiValue: '112.55991', }) }) test('calculates current projections', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'savings', account: { type: 'connected-random', @@ -54,14 +53,15 @@ test.describe('Savings Mainnet', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) - await savingsPage.expectSavingDaiCurrentProjection('$0.43', '30-day') - await savingsPage.expectSavingDaiCurrentProjection('$5.36', '1-year') + await savingsPage.expectSavingDaiCurrentProjection('$1.01', '30-day') + await savingsPage.expectSavingDaiCurrentProjection('$12.94', '1-year') }) test('displays the total value of stablecoins in the wallet', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: DEFAULT_BLOCK_NUMBER, chainId: mainnet.id }, initialPage: 'savings', account: { type: 'connected-random', @@ -72,31 +72,31 @@ test.describe('Savings Mainnet', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.expectOpportunityStablecoinsAmount('~$200.00') }) }) test.describe('Savings Gnosis', () => { - const fork = setupFork({ blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id, useTenderlyVnet: true }) - test('guest state', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id }, initialPage: 'savings', account: { type: 'not-connected', }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.expectAPY('10.6%') await savingsPage.expectConnectWalletCTA() }) test('calculates current value', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id }, initialPage: 'savings', account: { type: 'connected-random', @@ -106,7 +106,7 @@ test.describe('Savings Gnosis', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.expectSavingsDaiBalance({ sdaiBalance: '100.00', @@ -115,7 +115,8 @@ test.describe('Savings Gnosis', () => { }) test('calculates current projections', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id }, initialPage: 'savings', account: { type: 'connected-random', @@ -125,14 +126,15 @@ test.describe('Savings Gnosis', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.expectSavingDaiCurrentProjection('$0.95', '30-day') await savingsPage.expectSavingDaiCurrentProjection('$11.53', '1-year') }) test('displays the total value of stablecoins in the wallet', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id }, initialPage: 'savings', account: { type: 'connected-random', @@ -142,31 +144,31 @@ test.describe('Savings Gnosis', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.expectOpportunityStablecoinsAmount('~$100.00') }) }) test.describe('Savings Base', () => { - const fork = setupFork({ chainId: base.id, blockNumber: 22143788n, useTenderlyVnet: true }) - test('guest state', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: BASE_DEFAULT_BLOCK_NUMBER, chainId: base.id }, initialPage: 'savings', account: { type: 'not-connected', }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) - await savingsPage.expectAPY('6.5%') + await savingsPage.expectAPY('8.5%') await savingsPage.expectConnectWalletCTA() }) test('calculates current value', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: BASE_DEFAULT_BLOCK_NUMBER, chainId: base.id }, initialPage: 'savings', account: { type: 'connected-random', @@ -176,16 +178,17 @@ test.describe('Savings Base', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.expectSavingsUsdsBalance({ susdsBalance: '100.00', - estimatedUsdsValue: '100.8901', + estimatedUsdsValue: '101.28654604', }) }) test('calculates current projections', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: BASE_DEFAULT_BLOCK_NUMBER, chainId: base.id }, initialPage: 'savings', account: { type: 'connected-random', @@ -195,14 +198,15 @@ test.describe('Savings Base', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) - await savingsPage.expectSavingUsdsCurrentProjection('$0.52', '30-day') - await savingsPage.expectSavingUsdsCurrentProjection('$6.56', '1-year') + await savingsPage.expectSavingUsdsCurrentProjection('$0.68', '30-day') + await savingsPage.expectSavingUsdsCurrentProjection('$8.61', '1-year') }) test('displays the total value of stablecoins in the wallet', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { blockNumber: BASE_DEFAULT_BLOCK_NUMBER, chainId: base.id }, initialPage: 'savings', account: { type: 'connected-random', @@ -213,7 +217,7 @@ test.describe('Savings Base', () => { }, }) - const savingsPage = new SavingsPageObject(page) + const savingsPage = new SavingsPageObject(testContext) await savingsPage.expectOpportunityStablecoinsAmount('~$200.00') }) diff --git a/packages/app/src/test/e2e/BasePageObject.ts b/packages/app/src/test/e2e/BasePageObject.ts index 7052138d0..4794743a6 100644 --- a/packages/app/src/test/e2e/BasePageObject.ts +++ b/packages/app/src/test/e2e/BasePageObject.ts @@ -1,21 +1,22 @@ import { testIds } from '@/ui/utils/testIds' import { Locator, Page, expect } from '@playwright/test' -import { isPage } from './utils' +import { TestContext } from './setup' /** * BasePageObject is a class that contains common selectors and actions that are shared across the whole app. */ export class BasePageObject { + protected readonly testContext: TestContext protected readonly page: Page protected region: Locator - constructor(pageOrLocator: Page | Locator) { - if (isPage(pageOrLocator)) { - this.page = pageOrLocator - this.region = pageOrLocator.locator('body') + constructor(testContext: TestContext, locator?: Locator) { + this.testContext = testContext + this.page = testContext.page + if (locator) { + this.region = locator } else { - this.page = pageOrLocator.page() - this.region = pageOrLocator + this.region = this.page.locator('body') } } diff --git a/packages/app/src/test/e2e/assertions.ts b/packages/app/src/test/e2e/assertions.ts index ef4d41ab2..a79908839 100644 --- a/packages/app/src/test/e2e/assertions.ts +++ b/packages/app/src/test/e2e/assertions.ts @@ -1,25 +1,16 @@ import { Page, expect } from '@playwright/test' - -import { USD_MOCK_TOKEN } from '@/domain/types/Token' -import { NormalizedUnitNumber } from '@marsfoundation/common-universal' import { Abi, ContractFunctionName, ContractFunctionParameters, encodeFunctionData } from 'viem' import { __TX_LIST_KEY } from './constants' export interface TestTokenWithValue { asset: string - amount: number + amount: string + usdValue: string } -export function expectAssets(summary: string, assets: TestTokenWithValue[], assetsWorth: Record): void { +export function expectAssets(summary: string, assets: TestTokenWithValue[]): void { for (const asset of assets) { - const worth = assetsWorth[asset.asset]! - const amountFormatted = new Intl.NumberFormat('en-US', { - minimumFractionDigits: 2, - maximumFractionDigits: 18, // 18 is the maximum number of decimals for a token - }).format(asset.amount) - const usdValueFormatted = USD_MOCK_TOKEN.formatUSD(NormalizedUnitNumber(worth)) - - expect(summary).toMatch(`${asset.asset}${amountFormatted} ${usdValueFormatted}`) + expect(summary).toMatch(`${asset.asset}${asset.amount} ${asset.usdValue}`) } } diff --git a/packages/app/src/test/e2e/constants.ts b/packages/app/src/test/e2e/constants.ts index fd75ecc15..39a5168c7 100644 --- a/packages/app/src/test/e2e/constants.ts +++ b/packages/app/src/test/e2e/constants.ts @@ -56,6 +56,10 @@ const TOKENS_ON_MAINNET = { address: '0x56072c95faa701256059aa122697b133aded9279', decimals: 18, }, + cbBTC: { + address: '0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf', + decimals: 8, + }, } as const export const TOKENS_ON_FORK = { @@ -118,22 +122,16 @@ type NonNativeTokens = | keyof (typeof TOKENS_ON_FORK)[8453] export type AssetsInTests = 'ETH' | 'XDAI' | NonNativeTokens -// @note At this block number: -// DAI oracle returns exactly 1 -// GNO is offboarded -export const DEFAULT_BLOCK_NUMBER = 19092430n -export const GNOSIS_DEFAULT_BLOCK_NUMBER = 34543308n -export const USDS_ACTIVATED_BLOCK_NUMBER = 20771186n - -export const LITE_PSM_ACTIONS_OPERABLE = 20618776n -export const LITE_PSM_ACTIONS_OPERABLE_DATE = new Date('2024-08-27T08:40:00Z') +export const __TX_LIST_KEY = '__PLAYWRIGHT_TX_LIST' as any -export const WBTC_SUPPLY_CAP_REACHED_BLOCK_NUMBER = 19034436n +// @note: Block from 14 December 2024: +// Stable oracles returning exactly 1 +// GNO is offboarded +// USDS, PSM light are deployed +export const DEFAULT_BLOCK_NUMBER = 21400000n +// Edge cases export const GNO_ACTIVE_BLOCK_NUMBER = 18365842n -export const WEETH_ACTIVE_BLOCK_NUMBER = 20173717n - -export const __TX_LIST_KEY = '__PLAYWRIGHT_TX_LIST' as any - -export const CAP_AUTOMATOR_BLOCK_NUMBER = 20670518n +export const BASE_DEFAULT_BLOCK_NUMBER = 23000000n +export const GNOSIS_DEFAULT_BLOCK_NUMBER = 34543308n diff --git a/packages/app/src/test/e2e/forking/ITestForkService.ts b/packages/app/src/test/e2e/forking/ITestForkService.ts deleted file mode 100644 index db9810bf6..000000000 --- a/packages/app/src/test/e2e/forking/ITestForkService.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface ITestForkService { - createFork: (args: CreateForkArgs) => Promise - deleteFork: (forkUrl: string) => Promise -} - -export interface CreateForkArgs { - originChainId: number - forkChainId: number - blockNumber: bigint -} diff --git a/packages/app/src/test/e2e/forking/TestTenderlyForkService.ts b/packages/app/src/test/e2e/forking/TestTenderlyForkService.ts deleted file mode 100644 index 4b5c7ac4d..000000000 --- a/packages/app/src/test/e2e/forking/TestTenderlyForkService.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { createTenderlyFork } from '@/domain/sandbox/createTenderlyFork' -import { solidFetch } from '@/utils/solidFetch' -import { CreateForkArgs, ITestForkService } from './ITestForkService' - -export class TestTenderlyForkService implements ITestForkService { - private readonly baseUrl = 'https://api.tenderly.co/api/v1' - - constructor(private readonly opts: { apiKey: string; tenderlyAccount: string; tenderlyProject: string }) {} - - private getProjectUrl(): string { - return `${this.baseUrl}/account/${this.opts.tenderlyAccount}/project/${this.opts.tenderlyProject}` - } - - async createFork({ originChainId, forkChainId, blockNumber }: CreateForkArgs): Promise { - const { rpcUrl } = await createTenderlyFork({ - apiUrl: `${this.getProjectUrl()}/fork`, - originChainId, - forkChainId, - namePrefix: 'test-e2e', - blockNumber, - headers: { - 'X-Access-Key': this.opts.apiKey, - }, - }) - - return rpcUrl - } - - async deleteFork(forkUrl: string): Promise { - const forkId = forkUrl.split('/').pop() - await solidFetch(`${this.getProjectUrl()}/fork/${forkId}`, { - method: 'delete', - headers: { - 'X-Access-Key': this.opts.apiKey, - }, - }) - } -} diff --git a/packages/app/src/test/e2e/forking/TestTenderlyVnetService.ts b/packages/app/src/test/e2e/forking/TestTenderlyVnetService.ts deleted file mode 100644 index a0cf5573f..000000000 --- a/packages/app/src/test/e2e/forking/TestTenderlyVnetService.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { randomHexId } from '@/utils/random' -import { TenderlyVnetClient } from '../../../domain/tenderly/TenderlyVnetClient' -import { CreateForkArgs, ITestForkService } from './ITestForkService' - -export class TestTenderlyVnetService implements ITestForkService { - private readonly client: TenderlyVnetClient - - constructor(opts: { apiKey: string; account: string; project: string }) { - this.client = new TenderlyVnetClient(opts) - } - - async createFork({ originChainId, forkChainId, blockNumber }: CreateForkArgs): Promise { - const { rpcUrl } = await this.client.create({ - forkChainId, - originChainId, - blockNumber, - name: `test-e2e-${randomHexId()}`, - }) - - return rpcUrl - } - - async deleteFork(_forkUrl: string): Promise { - // doesn't support deleting vnets yet - } -} diff --git a/packages/app/src/test/e2e/forking/setupFork.ts b/packages/app/src/test/e2e/forking/setupFork.ts deleted file mode 100644 index a404ece2d..000000000 --- a/packages/app/src/test/e2e/forking/setupFork.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { basePsm3Address } from '@/config/contracts-generated' -import { tenderlyRpcActions } from '@/domain/tenderly/TenderlyRpcActions' -import { Page, test } from '@playwright/test' -import { http, createPublicClient } from 'viem' -import { base, gnosis, mainnet } from 'viem/chains' -import { injectUpdatedDate } from '../injectSetup' -import { processEnv } from '../processEnv' -import { injectFunds } from '../setup' -import { ITestForkService } from './ITestForkService' -import { TestTenderlyForkService } from './TestTenderlyForkService' -import { TestTenderlyVnetService } from './TestTenderlyVnetService' - -export interface ForkContext { - forkUrl: string - forkService: ITestForkService - initialSnapshotId: string - initialSimulationDate: Date - isVnet: boolean - chainId: number - simulationDate: Date - - progressSimulation(page: Page, seconds: number): Promise -} - -// @note: https://github.com/marsfoundation/app#deterministic-time-in-e2e-tests -// used only with tenderly forks (not vnets) -export const _simulationDate = new Date('2024-06-04T10:21:19Z') - -type AvailableChainId = typeof mainnet.id | typeof gnosis.id | typeof base.id -/** - * Fork is shared across the whole test file and is fixed to a single block number. - * It's created once and deleted after all tests are finished but after each test it's reverted to the initial state. - */ -export type SetupForkOptions = - | { - blockNumber: bigint - chainId: AvailableChainId - useTenderlyVnet?: false // using tenderly forks is the default - simulationDateOverride?: Date - } - | { - blockNumber: bigint - chainId: AvailableChainId - useTenderlyVnet: true // vnets are more powerful forks alternative provided by Tenderly - } - -export function setupFork(options: SetupForkOptions): ForkContext { - const apiKey = processEnv('TENDERLY_API_KEY') - const tenderlyAccount = processEnv('TENDERLY_ACCOUNT') - const tenderlyProject = processEnv('TENDERLY_PROJECT') - - const isVnet = !!options.useTenderlyVnet - const chainId = options.chainId - const simulationDateOverride = !isVnet ? options.simulationDateOverride : undefined - - const forkService: ITestForkService = isVnet - ? new TestTenderlyVnetService({ apiKey, account: tenderlyAccount, project: tenderlyProject }) - : new TestTenderlyForkService({ apiKey, tenderlyAccount, tenderlyProject }) - - const simulationDate = simulationDateOverride ?? (!isVnet ? _simulationDate : undefined) // undefined means get it based on block number - - const forkContext: ForkContext = { - forkService, - // we lie to typescript here, because it will be set in beforeAll - forkUrl: undefined as any, - isVnet, - initialSnapshotId: undefined as any, - initialSimulationDate: undefined as any, - simulationDate: simulationDate as any, - chainId, - - async progressSimulation(page: Page, seconds: number): Promise { - this.simulationDate = new Date(this.simulationDate.getTime() + seconds * 1000) - const newTimestamp = Math.floor(this.simulationDate.getTime() / 1000) - - await injectUpdatedDate(page, this.simulationDate) - await tenderlyRpcActions.evmSetNextBlockTimestamp(forkContext.forkUrl, Number(newTimestamp)) - }, - } - // @todo refactor after dropping tenderly fork support - - test.beforeAll(async () => { - forkContext.forkUrl = await forkService.createFork({ - blockNumber: options.blockNumber, - originChainId: chainId, - forkChainId: chainId, - }) - - if (simulationDate) { - const deltaTimeForward = Math.floor((simulationDate.getTime() - Date.now()) / 1000) - await tenderlyRpcActions.evmIncreaseTime(forkContext.forkUrl, deltaTimeForward) - forkContext.simulationDate = simulationDate - forkContext.initialSimulationDate = simulationDate - await tenderlyRpcActions.evmSetNextBlockTimestamp( - forkContext.forkUrl, - Math.floor(simulationDate.getTime() / 1000), - ) - } else { - const client = createPublicClient({ - chain: mainnet, // @todo select chain based on chainId - transport: http(forkContext.forkUrl), - }) - - const latestBlock = await client.getBlock() - // We select the block before the latest one to avoid including the vnet creation block, - // which has the current timestamp instead of the timestamp from the latest block on the chain. - // After this we create a new block with the timestamp of next to the latest block, and the - // forked chain is operable in a normal way. - const block = await client.getBlock({ blockNumber: latestBlock.number - 1n }) - forkContext.simulationDate = new Date(Number(block.timestamp) * 1000) - forkContext.initialSimulationDate = forkContext.simulationDate - await tenderlyRpcActions.evmSetNextBlockTimestamp(forkContext.forkUrl, Number(block.timestamp)) - } - - if (options.chainId === base.id) { - // inject liquidity for psm on base - await injectFunds(forkContext, basePsm3Address[base.id], { - USDS: 10_000_000, - sUSDS: 10_000_000, - USDC: 10_000_000, - }) - } - - forkContext.initialSnapshotId = await tenderlyRpcActions.snapshot(forkContext.forkUrl) - }) - - test.beforeEach(async () => { - await tenderlyRpcActions.revertToSnapshot(forkContext.forkUrl, forkContext.initialSnapshotId) - if (forkContext.isVnet) { - forkContext.simulationDate = forkContext.initialSimulationDate - } - }) - - test.afterAll(async () => { - if (processEnv.optionalBoolean('TENDERLY_PERSIST_FORK')) { - return - } - - if (forkContext.forkUrl) { - await forkService.deleteFork(forkContext.forkUrl) - } - }) - - return forkContext -} diff --git a/packages/app/src/test/e2e/getTestnetContext.ts b/packages/app/src/test/e2e/getTestnetContext.ts new file mode 100644 index 000000000..1120bbc00 --- /dev/null +++ b/packages/app/src/test/e2e/getTestnetContext.ts @@ -0,0 +1,61 @@ +import { randomHexId } from '@/utils/random' +import { getEnv } from '@marsfoundation/common-nodejs/env' +import { TenderlyTestnetFactory, TestnetClient } from '@marsfoundation/common-testnets' + +interface TestnetContext { + client: TestnetClient + initialSnapshotId: string + cleanup: () => Promise +} + +const testnetCache = new Map() +for (const eventType of ['exit', 'SIGINT', 'SIGUSR1', 'SIGUSR2', 'uncaughtException', 'SIGTERM']) { + process.on(eventType, async () => { + const keys = Array.from(testnetCache.keys()) + return Promise.all( + keys.map(async (key) => { + const context = testnetCache.get(key)! + testnetCache.delete(key) + return context.cleanup() + }), + ) + }) +} + +export async function getTestnetContext({ + chainId, + blockNumber, +}: { chainId: number; blockNumber: bigint }): Promise { + const key = `${chainId}-${blockNumber.toString()}` + if (testnetCache.has(key)) { + return testnetCache.get(key)! + } + + const env = getEnv() + const factory = new TenderlyTestnetFactory({ + account: env.string('TENDERLY_ACCOUNT'), + project: env.string('TENDERLY_PROJECT'), + apiKey: env.string('TENDERLY_API_KEY'), + }) + + const testnetId = randomHexId() + const { client, cleanup } = await factory.create({ + id: `test-e2e-${testnetId}`, + displayName: `Spark E2E Testnet ${testnetId}`, + forkChainId: chainId, + originChainId: chainId, + blockNumber, + }) + + const initialSnapshotId = await client.snapshot() + + const context: TestnetContext = { + client, + initialSnapshotId, + cleanup, + } + + testnetCache.set(key, context) + + return context +} diff --git a/packages/app/src/test/e2e/injectSetup.ts b/packages/app/src/test/e2e/injectSetup.ts index a53849fc2..a96e1feff 100644 --- a/packages/app/src/test/e2e/injectSetup.ts +++ b/packages/app/src/test/e2e/injectSetup.ts @@ -2,15 +2,10 @@ import { Page } from '@playwright/test' import { PLAYWRIGHT_CHAIN_ID, - PLAYWRIGHT_USDS_CONTRACTS_NOT_AVAILABLE_KEY, PLAYWRIGHT_WALLET_ADDRESS_KEY, PLAYWRIGHT_WALLET_FORK_URL_KEY, PLAYWRIGHT_WALLET_PRIVATE_KEY_KEY, } from '@/config/wagmi/config.e2e' - -import { http, createPublicClient, zeroAddress } from 'viem' -import { base, mainnet } from 'viem/chains' -import { ForkContext } from './forking/setupFork' import { InjectableWallet } from './setup' export async function injectWalletConfiguration(page: Page, wallet: InjectableWallet): Promise { @@ -47,74 +42,3 @@ export async function injectNetworkConfiguration(page: Page, rpcUrl: string, cha }, ) } - -export async function injectFixedDate(page: Page, date: Date): Promise { - // setup fake Date for deterministic tests - // https://github.com/microsoft/playwright/issues/6347#issuecomment-1085850728 - const fakeNow = date.valueOf() - await page.addInitScript(overrideDateClass, fakeNow) -} - -// the only difference between this and injectFixedDate is the use of page.evaluate instead of page.addInitScript -export async function injectUpdatedDate(page: Page, date: Date): Promise { - // setup fake Date for deterministic tests - // https://github.com/microsoft/playwright/issues/6347#issuecomment-1085850728 - const fakeNow = date.valueOf() - await page.evaluate(overrideDateClass, fakeNow) -} - -function overrideDateClass(fakeNow: number): void { - // biome-ignore lint/suspicious/noGlobalAssign: - // @ts-ignore - Date = class extends Date { - // @ts-ignore - constructor(...args) { - if (args.length === 0) { - super(fakeNow) - } else { - // @ts-ignore - super(...args) - } - } - } - // Override Date.now() to start from fakeNow - const __DateNowOffset = fakeNow - Date.now() - const __DateNow = Date.now - Date.now = () => __DateNow() + __DateNowOffset - - // @todo: When we are able to set timestamps for transactions, make tests that use vnets use line below instead of the overriding Date.now with offset - // Date.now = () => fakeNow -} - -export async function injectFlags(page: Page, forkContext: ForkContext): Promise { - const susdsDeployed = await isSudsDeployed(forkContext) - - await page.addInitScript( - ({ PLAYWRIGHT_USDS_CONTRACTS_NOT_AVAILABLE_KEY, susdsDeployed }) => { - if (!susdsDeployed) { - ;(window as any)[PLAYWRIGHT_USDS_CONTRACTS_NOT_AVAILABLE_KEY] = true - } - }, - { PLAYWRIGHT_USDS_CONTRACTS_NOT_AVAILABLE_KEY, susdsDeployed }, - ) -} - -async function isSudsDeployed(forkContext: ForkContext): Promise { - const susdsAddress = (() => { - if (forkContext.chainId === mainnet.id) { - return '0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD' - } - - if (forkContext.chainId === base.id) { - return '0x5875eEE11Cf8398102FdAd704C9E96607675467a' - } - - return zeroAddress - })() - const publicClient = createPublicClient({ - transport: http(forkContext.forkUrl), - }) - const susdsBytecode = await publicClient.getBytecode({ address: susdsAddress }) - - return susdsBytecode !== undefined && susdsBytecode.length > 2 -} diff --git a/packages/app/src/test/e2e/setup.ts b/packages/app/src/test/e2e/setup.ts index eb1249286..fe7aad01b 100644 --- a/packages/app/src/test/e2e/setup.ts +++ b/packages/app/src/test/e2e/setup.ts @@ -1,14 +1,12 @@ +import { Path, paths } from '@/config/paths' +import { TestnetClient, getUrlFromClient } from '@marsfoundation/common-testnets' +import { assertNever } from '@marsfoundation/common-universal' import { Page } from '@playwright/test' import { generatePath } from 'react-router-dom' import { Address, Hash, parseEther, parseUnits } from 'viem' - -import { Path, paths } from '@/config/paths' -import { BaseUnitNumber } from '@marsfoundation/common-universal' - -import { tenderlyRpcActions } from '@/domain/tenderly/TenderlyRpcActions' import { AssetsInTests, TOKENS_ON_FORK } from './constants' -import { ForkContext } from './forking/setupFork' -import { injectFixedDate, injectFlags, injectNetworkConfiguration, injectWalletConfiguration } from './injectSetup' +import { getTestnetContext } from './getTestnetContext' +import { injectNetworkConfiguration, injectWalletConfiguration } from './injectSetup' import { generateAccount } from './utils' export type InjectableWallet = { address: Address } | { privateKey: string } @@ -43,76 +41,76 @@ export type AccountOptions = T extends 'not-connected' } : never +export interface BlockchainOptions { + chainId: number + blockNumber: bigint +} export interface SetupOptions { + blockchain: BlockchainOptions initialPage: K initialPageParams?: PathParams account: AccountOptions skipInjectingNetwork?: boolean } -export type SetupReturn = T extends 'not-connected' - ? { - getLogs: () => string[] - } - : { - account: Address - getLogs: () => string[] - } +export type ProgressSimulation = (seconds: number) => Promise +export interface TestnetController { + client: TestnetClient + progressSimulation: ProgressSimulation + progressSimulationAndMine: ProgressSimulation +} + +export type TestContext = (T extends 'not-connected' + ? {} + : { account: Address }) & { + testnetController: TestnetController + page: Page +} // should be called at the beginning of any test export async function setup( page: Page, - forkContext: ForkContext, options: SetupOptions, -): Promise> { - if (options.skipInjectingNetwork === true) { - // if explicitly disabled, do not inject network config abort all network requests to RPC providers - await page.route(/alchemy/, (route) => route.abort()) - await page.route(/rpc.ankr/, (route) => route.abort()) - } else { - await injectNetworkConfiguration(page, forkContext.forkUrl, forkContext.chainId) - } - await injectFixedDate(page, forkContext.simulationDate) - await injectFlags(page, forkContext) - let address: Address | undefined +): Promise> { + const { client: testnetClient, initialSnapshotId } = await getTestnetContext(options.blockchain) + await testnetClient.revert(initialSnapshotId) - if (options.account.type !== 'not-connected') { - if (options.account.type === 'connected-random') { - const account = generateAccount({ privateKey: undefined }) - address = account.address - await injectWalletConfiguration(page, account) - await injectFunds(forkContext, account.address, options.account.assetBalances) - } - if (options.account.type === 'connected-pkey') { - const account = generateAccount({ privateKey: options.account.privateKey }) - address = account.address - await injectWalletConfiguration(page, account) - await injectFunds(forkContext, account.address, options.account.assetBalances) - } - if (options.account.type === 'connected-address') { - address = options.account.address - await injectWalletConfiguration(page, { address }) - } + await injectPageSetup({ page, testnetClient, options }) + const address = await setupAccount({ page, testnetClient, options: options.account }) + await page.goto(buildUrl(options.initialPage, options.initialPageParams)) + + async function progressSimulation(seconds: number): Promise { + const { timestamp: currentTimestamp } = await testnetClient.getBlock() + + const progressedTimestamp = currentTimestamp + BigInt(seconds) + await testnetClient.setNextBlockTimestamp(progressedTimestamp) + await page.clock.setFixedTime(Number(currentTimestamp) * 1000) } - const errorLogs = [] as string[] + async function progressSimulationAndMine(seconds: number): Promise { + await progressSimulation(seconds) + await testnetClient.mineBlocks(1n) + await progressSimulation(1) + } - page.on('console', (message) => { - if (message.type() === 'error') { - errorLogs.push(message.text()) - } - }) + // @note: Set next block to be mined timestamp to be 5 seconds more. + await progressSimulation(5) - await page.goto(buildUrl(options.initialPage, options.initialPageParams)) + const testnetController: TestnetController = { + client: testnetClient, + progressSimulation, + progressSimulationAndMine, + } return { + page, account: address, - getLogs: () => errorLogs, + testnetController, } as any } export async function injectFunds( - forkContext: ForkContext, + testnetClient: TestnetClient, address: Address, assetBalances?: AssetBalances, ): Promise { @@ -120,45 +118,77 @@ export async function injectFunds( return } - if (forkContext.isVnet) { - const promises = Object.entries(assetBalances).map(async ([tokenName, balance]) => { - if (tokenName === 'ETH' || tokenName === 'XDAI') { - await tenderlyRpcActions.setBalance( - forkContext.forkUrl, - address, - BaseUnitNumber(parseEther(balance.toString())), - ) - } else { - await tenderlyRpcActions.setTokenBalance( - forkContext.forkUrl, - (TOKENS_ON_FORK as any)[forkContext.chainId][tokenName].address, - address, - BaseUnitNumber( - parseUnits(balance.toString(), (TOKENS_ON_FORK as any)[forkContext.chainId][tokenName].decimals), - ), - ) - } - }) - await Promise.all(promises) - } else { - // todo remove once we only support vnets - for (const [tokenName, balance] of Object.entries(assetBalances)) { - if (tokenName === 'ETH' || tokenName === 'XDAI') { - await tenderlyRpcActions.setBalance( - forkContext.forkUrl, - address, - BaseUnitNumber(parseEther(balance.toString())), - ) - } else { - await tenderlyRpcActions.setTokenBalance( - forkContext.forkUrl, - (TOKENS_ON_FORK as any)[forkContext.chainId][tokenName].address, - address, - BaseUnitNumber( - parseUnits(balance.toString(), (TOKENS_ON_FORK as any)[forkContext.chainId][tokenName].decimals), - ), - ) - } + const chainId = await testnetClient.getChainId() + for (const [tokenName, balance] of Object.entries(assetBalances)) { + const { timestamp } = await testnetClient.getBlock() + await testnetClient.setNextBlockTimestamp(timestamp + 1n) + if (tokenName === 'ETH' || tokenName === 'XDAI') { + await testnetClient.setBalance(address, parseEther(balance.toString())) + } else { + await testnetClient.setErc20Balance( + (TOKENS_ON_FORK as any)[chainId][tokenName].address, + address, + parseUnits(balance.toString(), (TOKENS_ON_FORK as any)[chainId][tokenName].decimals), + ) } } } + +async function setupAccount({ + page, + testnetClient, + options, +}: { + page: Page + testnetClient: TestnetClient + options: AccountOptions +}): Promise
{ + switch (options.type) { + case 'connected-random': { + const account = generateAccount({ privateKey: undefined }) + await injectWalletConfiguration(page, account) + await injectFunds(testnetClient, account.address, options.assetBalances) + return account.address + } + + case 'connected-pkey': { + const account = generateAccount({ privateKey: options.privateKey }) + await injectWalletConfiguration(page, account) + await injectFunds(testnetClient, account.address, options.assetBalances) + return account.address + } + + case 'connected-address': { + await injectWalletConfiguration(page, { address: options.address }) + return options.address + } + + case 'not-connected': + return undefined + + default: + assertNever(options) + } +} + +async function injectPageSetup({ + page, + testnetClient, + options, +}: { + page: Page + testnetClient: TestnetClient + options: SetupOptions +}): Promise { + if (options.skipInjectingNetwork === true) { + // if explicitly disabled, do not inject network config abort all network requests to RPC providers + await page.route(/alchemy/, (route) => route.abort()) + await page.route(/rpc.ankr/, (route) => route.abort()) + await page.route(/blockanalitica.com/, (route) => route.abort()) + } else { + await injectNetworkConfiguration(page, getUrlFromClient(testnetClient), options.blockchain.chainId) + } + + const { timestamp } = await testnetClient.getBlock() + await page.clock.setFixedTime(Number(timestamp) * 1000) +} diff --git a/packages/app/src/test/e2e/utils.ts b/packages/app/src/test/e2e/utils.ts index 98c53e708..ff60025f2 100644 --- a/packages/app/src/test/e2e/utils.ts +++ b/packages/app/src/test/e2e/utils.ts @@ -1,8 +1,3 @@ -import { - lendingPoolAddressProviderAddress, - uiPoolDataProviderAbi, - uiPoolDataProviderAddress, -} from '@/config/contracts-generated' import { USD_MOCK_TOKEN } from '@/domain/types/Token' import { bigNumberify } from '@/utils/bigNumber' import { BaseUnitNumber, NormalizedUnitNumber } from '@marsfoundation/common-universal' @@ -10,54 +5,6 @@ import { Locator, Page } from '@playwright/test' import { http, Address, createPublicClient, erc20Abi, weiUnits } from 'viem' import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts' -/** - * Helper function to take deterministic screenshots. - */ -export async function screenshot(pageOrLocator: Page | Locator, name: string): Promise { - const page = isPage(pageOrLocator) ? pageOrLocator : pageOrLocator.page() - const locator = isPage(pageOrLocator) ? page.locator('html') : pageOrLocator - - // note: hide entirely elements that can change in size - const selectorsToHide = [ - `[data-testid="wallet-button"]`, // hide address because it can change - '.toast-notifications', // hide notifications because sometimes they are fast to disappear and can't be captured deterministically - `[data-testid="react-confetti"]`, - ] - // note: mask elements that can change but not in size - const selectorsToMask: string[] = [] - - // hide elements - await page.evaluate((selectors) => { - for (const selector of selectors) { - const element: any = document.querySelector(selector) - if (!element) { - continue // skip if element not found - } - - element.__oldDisplay = element.style.display - element.style.display = 'none' - } - }, selectorsToHide) - - await locator.screenshot({ - path: `__screenshots-e2e__/${name}-${page.viewportSize()?.width}.png`, - animations: 'disabled', - mask: selectorsToMask.map((selector) => page.locator(selector)), - }) - - // unhide elements - await page.evaluate((selectors) => { - for (const selector of selectors) { - const element: any = document.querySelector(selector) - if (!element) { - return - } - - element.style.display = element.__oldDisplay - } - }, selectorsToHide) -} - export async function waitForButtonEnabled(page: Page, name: string): Promise { await page.waitForFunction((name) => { const buttons = document.querySelectorAll('button') @@ -113,46 +60,6 @@ export async function parseTable(tableLocator: Locator, parseRow: (row: strin return table } -export async function calculateAssetsWorth( - forkUrl: string, - balances: Record, -): Promise<{ total: number; assetsWorth: Record }> { - const publicClient = createPublicClient({ - transport: http(forkUrl), - }) - const chainId = await publicClient.getChainId() - - const uiPoolDataProvider = uiPoolDataProviderAddress[chainId as keyof typeof uiPoolDataProviderAddress] - const lendingPoolAddressProvider = - lendingPoolAddressProviderAddress[chainId as keyof typeof lendingPoolAddressProviderAddress] - if (!uiPoolDataProvider || !lendingPoolAddressProvider) { - throw new Error(`Couldn't find addresses for chain ${chainId}`) - } - - const [reserves, baseCurrencyInfo] = await publicClient.readContract({ - address: uiPoolDataProvider, - functionName: 'getReservesData', - args: [lendingPoolAddressProvider], - abi: uiPoolDataProviderAbi, - }) - - let total = 0 - const assetsWorth: Record = {} - for (const [asset, amount] of Object.entries(balances)) { - const price = reserves.find( - (reserve) => reserve.symbol === asset || (asset === 'ETH' && reserve.symbol === 'WETH'), - )?.priceInMarketReferenceCurrency - if (!price) { - throw new Error(`Couldn't find price for ${asset}`) - } - - total += Number(price) * amount - assetsWorth[asset] = (Number(price) * amount) / Number(baseCurrencyInfo.marketReferenceCurrencyPriceInUsd) - } - - return { total: total / Number(baseCurrencyInfo.marketReferenceCurrencyPriceInUsd), assetsWorth } -} - export function isPage(pageOrLocator: Page | Locator): pageOrLocator is Page { return 'addInitScript' in pageOrLocator } diff --git a/packages/app/src/ui/assets/index.ts b/packages/app/src/ui/assets/index.ts index 4efe2854e..914cbd15b 100644 --- a/packages/app/src/ui/assets/index.ts +++ b/packages/app/src/ui/assets/index.ts @@ -267,4 +267,5 @@ const tokenColors: Record = { [TokenSymbol('WXDAI')]: '253 177 31', [TokenSymbol('XDAI')]: '255 192 70', [TokenSymbol('CLE')]: '47 208 91', + [TokenSymbol('cbBTC')]: '0 82 255', } diff --git a/packages/app/src/ui/layouts/app-layout/components/PageNotSupportedWarning.test-e2e.ts b/packages/app/src/ui/layouts/app-layout/components/PageNotSupportedWarning.test-e2e.ts index 471b0fb96..7d0b8367d 100644 --- a/packages/app/src/ui/layouts/app-layout/components/PageNotSupportedWarning.test-e2e.ts +++ b/packages/app/src/ui/layouts/app-layout/components/PageNotSupportedWarning.test-e2e.ts @@ -2,35 +2,40 @@ import { test } from '@playwright/test' import { gnosis } from 'viem/chains' import { GNOSIS_DEFAULT_BLOCK_NUMBER } from '@/test/e2e/constants' -import { setupFork } from '@/test/e2e/forking/setupFork' import { buildUrl, setup } from '@/test/e2e/setup' import { PageNotSupportedWarningPageObject } from './PageNotSupportedWarning.PageObject' test.describe('PageNotSupportedWarning', () => { - const fork = setupFork({ blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, chainId: gnosis.id, useTenderlyVnet: true }) - test('Displays not supported warning on unsupported page', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, + chainId: gnosis.id, + }, initialPage: 'farms', account: { type: 'connected-random', }, }) - const warning = new PageNotSupportedWarningPageObject(page) + const warning = new PageNotSupportedWarningPageObject(testContext) await warning.expectSwitchNetworkVisible() }) test('Displays not supported warning on entering the unsupported page', async ({ page }) => { - await setup(page, fork, { + const testContext = await setup(page, { + blockchain: { + blockNumber: GNOSIS_DEFAULT_BLOCK_NUMBER, + chainId: gnosis.id, + }, initialPage: 'savings', account: { type: 'connected-random', }, }) - const warning = new PageNotSupportedWarningPageObject(page) + const warning = new PageNotSupportedWarningPageObject(testContext) await warning.expectSwitchNetworkNotVisible() diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc5e79f56..35d830003 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -216,6 +216,12 @@ importers: '@chromatic-com/storybook': specifier: ^1.5.0 version: 1.5.0(react@18.2.0) + '@marsfoundation/common-nodejs': + specifier: workspace:^ + version: link:../common-nodejs + '@marsfoundation/common-testnets': + specifier: workspace:^ + version: link:../common-testnets '@playwright/test': specifier: ^1.47.2 version: 1.47.2