diff --git a/package.json b/package.json index ba838ec1..56cf5cdf 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,12 @@ "ethers": "^6.7.1" }, "scripts": { + "earn-protocol": "REPORT_FOLDER=earn-protocol npx playwright test --project=earn-protocol", "api-tests": "REPORT_FOLDER=api-tests npx playwright test --project=api-tests", "verify-staging": "REPORT_FOLDER=verify-staging npx playwright test --project=verify-staging", "no-wallet": "REPORT_FOLDER=no-wallet npx playwright test --project=no-wallet", "no-wallet:portfolio": "REPORT_FOLDER=no-wallet-portfolio npx playwright test --project=no-wallet-portfolio", + "with-real-wallet": "REPORT_FOLDER=with-real-wallet npx playwright test --project=with-real-wallet --workers=1", "with-wallet:rays": "REPORT_FOLDER=with-wallet-rays npx playwright test --project=with-wallet-rays --workers=1", "with-wallet:token-swap-rate": "REPORT_FOLDER=with-wallet-token-swap-rate npx playwright test --project=with-wallet-token-swap-rate --workers=1", "with-wallet:rays-and-token-swap-rate": "REPORT_FOLDER=with-wallet-rays-and-token-swap-rate npx playwright test --project=with-wallet-rays-and-token-swap-rate --workers=1", diff --git a/playwright.config.ts b/playwright.config.ts index a42adee0..145a2f32 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -1,6 +1,6 @@ require('dotenv').config(); import { devices, type PlaywrightTestConfig, type ReporterDescription } from '@playwright/test'; -import { baseUrl } from 'utils/config'; +import { baseUrl, earnProtocolBaseUrl } from 'utils/config'; // Config to hold extra property interface TestConfig extends PlaywrightTestConfig { @@ -36,6 +36,15 @@ const defaultConfig: PlaywrightTestConfig = { /* Configure projects for major browsers */ projects: [ + { + name: 'earn-protocol', + testMatch: ['earnProtocol/**'], + use: { + baseURL: earnProtocolBaseUrl, + ...devices['Desktop Chrome'], + }, + }, + { name: 'api-tests', testMatch: ['api/**'], @@ -68,6 +77,12 @@ const defaultConfig: PlaywrightTestConfig = { }, }, + { + name: 'with-real-wallet', + testMatch: ['withRealWallet/**'], + use: { ...devices['Desktop Chrome'] }, + }, + { name: 'with-wallet-rays', testMatch: ['withWallet/rays/**'], @@ -102,6 +117,12 @@ const defaultConfig: PlaywrightTestConfig = { use: { ...devices['Desktop Chrome'] }, }, + { + name: 'with-wallet-aave-ethereum-new', + testMatch: ['withWallet/aaveV3_new/ethereum/**'], + use: { ...devices['Desktop Chrome'] }, + }, + { name: 'with-wallet-aave-arbitrum', testMatch: ['withWallet/aaveV3/arbitrum/**'], diff --git a/srcEarnProtocol/app.ts b/srcEarnProtocol/app.ts new file mode 100644 index 00000000..6c075d16 --- /dev/null +++ b/srcEarnProtocol/app.ts @@ -0,0 +1,51 @@ +import { Page } from '@playwright/test'; +// import { Modals } from './modals'; +import { + // Borrow, + // Earn, + Header, + // Homepage, + // Multiply, + // Portfolio, + // Position, + // Rays, +} from './pages'; + +export class App { + readonly page: Page; + + // readonly borrow: Borrow; + + // readonly earn: Earn; + + readonly header: Header; + + // readonly homepage: Homepage; + + // readonly modals: Modals; + + // readonly multiply: Multiply; + + // readonly portfolio: Portfolio; + + // readonly position: Position; + + // readonly rays: Rays; + + constructor(page: Page) { + this.page = page; + // this.borrow = new Borrow(page); + // this.earn = new Earn(page); + this.header = new Header(page); + // this.homepage = new Homepage(page); + // this.modals = new Modals(page); + // this.multiply = new Multiply(page); + // this.portfolio = new Portfolio(page); + // this.position = new Position(page); + // this.rays = new Rays(page); + } + + async pause() { + await this.page.pause(); + } +} diff --git a/srcEarnProtocol/fixtures/noWallet.ts b/srcEarnProtocol/fixtures/noWallet.ts new file mode 100644 index 00000000..56b86838 --- /dev/null +++ b/srcEarnProtocol/fixtures/noWallet.ts @@ -0,0 +1,42 @@ +import { test as base } from '@playwright/test'; +import { App } from '../app'; +import { updateFlagsAndRejectCookies } from 'utils/localStorage'; + +type MyFixtures = { + app: App; +}; + +export const test = base.extend({ + app: async ({ page }, use) => { + const app = new App(page); + + await app.page.goto(''); + // await app.homepage.shouldBeVisible(); + + // const featuresFlags = process.env.FLAGS_FEATURES ? process.env.FLAGS_FEATURES.split(' ') : null; + // const automationMinNetValueFlags = process.env.FLAGS_AUTOMATION_MIN_NET_VALUE + // ? process.env.FLAGS_AUTOMATION_MIN_NET_VALUE.split(' ') + // : null; + + // await updateFlagsAndRejectCookies({ + // app, + // featuresFlags, + // automationMinNetValueFlags, + // }); + + await use(app); + + await app.page.close(); + }, +}); + +export function step(target: Function, context: ClassMethodDecoratorContext) { + return function replacementMethod(...args: any) { + const name = this.constructor.name + '.' + (context.name as string); + return test.step(name, async () => { + return await target.call(this, ...args); + }); + }; +} + +export const expect = test.expect; diff --git a/srcEarnProtocol/fixtures/wallet.ts b/srcEarnProtocol/fixtures/wallet.ts new file mode 100644 index 00000000..b6aa3b19 --- /dev/null +++ b/srcEarnProtocol/fixtures/wallet.ts @@ -0,0 +1,68 @@ +import { test as base, chromium } from '@playwright/test'; +import { initialSetup } from '@synthetixio/synpress/commands/metamask'; +import { setExpectInstance } from '@synthetixio/synpress/commands/playwright'; +import { prepareMetamask } from '@synthetixio/synpress/helpers'; +import { App } from '../app'; + +type MyFixtures = { + app: App; +}; + +type BrowserContext = { + context: BrowserContext; +}; + +export const test = base.extend({ + context: async ({}, use) => { + // required for synpress as it shares same expect instance as playwright + await setExpectInstance(expect); + + // download metamask + const metamaskPath = await prepareMetamask(process.env.METAMASK_VERSION || '10.25.0'); + + // prepare browser args + const browserArgs = [ + `--disable-extensions-except=${metamaskPath}`, + `--load-extension=${metamaskPath}`, + '--remote-debugging-port=9222', + ]; + + if (process.env.CI) { + browserArgs.push('--disable-gpu'); + } + + if (process.env.HEADLESS_MODE) { + browserArgs.push('--headless=new'); + } + + // launch browser + const context = await chromium.launchPersistentContext('', { + headless: false, + args: browserArgs, + }); + + // wait for metamask + await context.pages()[0].waitForTimeout(3000); + + // setup metamask + await initialSetup(chromium, { + secretWordsOrPrivateKey: 'test test test test test test test test test test test junk', + network: 'mainnet', + password: 'Tester@1234', + enableAdvancedSettings: true, + enableExperimentalSettings: false, + }); + + await use(context); + }, + + app: async ({ page }, use) => { + const app = new App(page); + + await use(app); + + await app.page.close(); + }, +}); + +export const expect = test.expect; diff --git a/srcEarnProtocol/pages/header/index.ts b/srcEarnProtocol/pages/header/index.ts new file mode 100644 index 00000000..c5005e7c --- /dev/null +++ b/srcEarnProtocol/pages/header/index.ts @@ -0,0 +1,26 @@ +import { expect, step } from '#earnProtocolFixtures'; +import { Locator, Page } from '@playwright/test'; + +export class Header { + readonly page: Page; + + readonly headerLocator: Locator; + + constructor(page: Page) { + this.page = page; + this.headerLocator = page.locator('header'); + } + + @step + async shouldHaveSummerfiLogo() { + await expect( + this.headerLocator.locator('img[alt="Summer.fi"]').nth(0), + 'Summer.fi logo should be visible' + ).toBeVisible(); + } + + @step + async earn() { + await this.headerLocator.getByRole('link', { name: 'Earn' }).click(); + } +} diff --git a/srcEarnProtocol/pages/index.ts b/srcEarnProtocol/pages/index.ts new file mode 100644 index 00000000..a2d2b9a0 --- /dev/null +++ b/srcEarnProtocol/pages/index.ts @@ -0,0 +1,3 @@ +import { Header } from './header'; + +export { Header }; diff --git a/tests/earnProtocol/firstTest.spec.ts b/tests/earnProtocol/firstTest.spec.ts new file mode 100644 index 00000000..47d59ade --- /dev/null +++ b/tests/earnProtocol/firstTest.spec.ts @@ -0,0 +1,13 @@ +import { test } from '#earnProtocolFixtures'; + +test('Header - Open Earn page', async ({ app }) => { + await app.header.shouldHaveSummerfiLogo(); + + await app.header.earn(); + + // TO BE COMPOLETED + + // + // await app.pause(); + // +}); diff --git a/tests/withRealWallet/aaveV3MultiplyOptimism.spec.ts b/tests/withRealWallet/aaveV3MultiplyOptimism.spec.ts new file mode 100644 index 00000000..00810b2b --- /dev/null +++ b/tests/withRealWallet/aaveV3MultiplyOptimism.spec.ts @@ -0,0 +1,61 @@ +import { BrowserContext, expect, test } from '@playwright/test'; +import { resetState } from '@synthetixio/synpress/commands/synpress'; +import { metamaskSetUp, setup } from 'utils/setup'; +import { extremelyLongTestTimeout } from 'utils/config'; +import * as tx from 'utils/tx'; +import { App } from 'src/app'; + +let context: BrowserContext; +let app: App; + +const walletPK: string = process.env.VERY_OLD_TEST_WALLET_PK; + +test.describe.configure({ mode: 'serial' }); + +test.describe('Aave v3 Multiply - Optimism - Wallet connected', async () => { + test.afterAll(async () => { + await app.page.close(); + + await context.close(); + + await resetState(); + }); + + test('It should open an Aave v3 Multiply Optimism position - ETH/USDC @regression', async () => { + test.info().annotations.push({ + type: 'Test case', + description: '12067', + }); + + test.setTimeout(extremelyLongTestTimeout); + + await test.step('Test setup', async () => { + ({ context } = await metamaskSetUp({ network: 'optimism' })); + let page = await context.newPage(); + app = new App(page); + + await setup({ + app, + network: 'optimism', + withoutFork: true, + withExistingWallet: { + privateKey: walletPK, + }, + }); + }); + + await app.page.goto('/optimism/aave/v3/multiply/eth-usdc#setup'); + + await app.position.setup.deposit({ token: 'ETH', amount: '0.001' }); + + await app.position.setup.confirm(); + // Thre are two 'confirm' steps + await app.position.setup.confirm(); + + await test.step('Reject Permission To Spend', async () => { + await expect(async () => { + await tx.rejectPermissionToSpend(); + }).toPass(); + }); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index b2e36746..563a6302 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,10 +2,12 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "#walletFixtures": ["./src/fixtures/wallet.ts"], + "#earnProtocolFixtures": ["./srcEarnProtocol/fixtures/noWallet.ts"], "#noWalletFixtures": ["./src/fixtures/noWallet.ts"], - "#walletUtils": ["./utils/wallet.ts"], "#termsAndConditions": ["./utils/termsAndConditions.ts"], + "#walletFixtures": ["./src/fixtures/wallet.ts"], + "#walletUtils": ["./utils/wallet.ts"], + } } } \ No newline at end of file diff --git a/utils/config.ts b/utils/config.ts index 391bde81..a8ab85ca 100644 --- a/utils/config.ts +++ b/utils/config.ts @@ -2,6 +2,9 @@ require('dotenv').config(); export const baseUrl = process.env.BASE_URL ?? 'https://staging.summer.fi'; +export const earnProtocolBaseUrl = + process.env.BASE_URL_EARN_PROTOCOL ?? 'https://earn-protocol-staging.oasisapp.dev/'; + export const expectDefaultTimeout: number = 5_000; export const hooksTimeout: number = diff --git a/utils/setup.ts b/utils/setup.ts index 8a6c9d52..01e81e86 100644 --- a/utils/setup.ts +++ b/utils/setup.ts @@ -80,10 +80,6 @@ export const setup = async ({ withExistingWallet?: { privateKey: string }; }) => { let forkId: string; - const walletAddress = await metamask.walletAddress(); - // Logging walletAddress for debugging purposes - // - Info displayed in 'Attachments > stdout' section of playwright reports - console.log(' Wallet Address: ', walletAddress); await app.page.goto(''); await app.homepage.shouldBeVisible(); @@ -114,6 +110,11 @@ export const setup = async ({ await metamask.importAccount(withExistingWallet?.privateKey); } + const walletAddress = await metamask.getWalletAddress(); + // Logging walletAddress for debugging purposes + // - Info displayed in 'Attachments > stdout' section of playwright reports + console.log(' Wallet Address: ', walletAddress); + await wallet.connect(app); await termsAndconditions.accept(app);