diff --git a/apps/transfers/README.md b/apps/transfers/README.md index 9f1a081..e9d2d7e 100644 --- a/apps/transfers/README.md +++ b/apps/transfers/README.md @@ -18,7 +18,6 @@ Install rust by executing a script from the internet (😅): curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` - Check the version with `cargo version`. Finally add the wasm target: @@ -242,37 +241,7 @@ data come through. ### Run the Frontend -Now on your own machine, checkout the -https://github.com/informalsystems/cycles-hackathon-app. - -Copy the `.env.example` file to `.env.local`: - -```bash -cp .env.example .env.local -``` - -and set the relevant fields. You should have the contract address and TEE pubkey -from the output of the `deploy.sh` and `handshake.sh` scripts, respectfully. The -chain id is probably `testing` and the IP address for the URLs is probably -`143.244.186.205`. Modify accordingly. For example: - -```bash -#.env.local -NEXT_PUBLIC_TRANSFERS_CONTRACT_ADDRESS=wasm1ch9ed27cdu3a4fkx37gnagm7jcthj0rggnmmjwwwe4xhwmk0d65q8fn9pz -NEXT_PUBLIC_ENCLAVE_PUBLIC_KEY=030c25e39743fd4c7553d87873919281d567b5c328fb903cbfbe9541518736a2d2 -NEXT_PUBLIC_CHAIN_ID=testing -NEXT_PUBLIC_CHAIN_RPC_URL=http://143.244.186.205:26657 -NEXT_PUBLIC_CHAIN_REST_URL=http://143.244.186.205:1317 -``` - -Install and run the app: - -```bash -npm install -f -npm run dev -``` - -You can now open the app in http://localhost:3000/. +Now on your own machine, follow [these steps](./frontend/README.md#development). Make sure you have Keplr installed in your browser and you should now be able to use the app! diff --git a/apps/transfers/frontend/.env.example b/apps/transfers/frontend/.env.example index 1271ab5..88c51a3 100644 --- a/apps/transfers/frontend/.env.example +++ b/apps/transfers/frontend/.env.example @@ -1,9 +1,13 @@ +# App required variables NEXT_PUBLIC_TARGET_CHAIN=localWasm NEXT_PUBLIC_ENCLAVE_PUBLIC_KEY=02360955ff74750f6ea0b539f41cce89451f591e4c835d0a5406e6effa96dd169d NEXT_PUBLIC_TRANSFERS_CONTRACT_ADDRESS=wasm1jfgr0vgunezkhfmdy7krrupu6yjhx224nxtjptll2ylkkqhyzeshrspu9 -# E2E Testing +# E2E testing required variables TEST_BASE_URL=http://127.0.0.1:3000 TEST_KEPLR_EXTENSION_VERSION=0.12.124 TEST_WALLET_MNEMONIC=debris topic trash february punch advance tackle alert reduce box chase lend buffalo effort napkin drip mountain result rely swear tornado master devote what +TEST_SECONDARY_WALLET_MNEMONIC=employ jungle nuclear clutch general vicious thrive width time asthma shadow orchard wage affair matrix slush room weapon prize that record path grit tourist +TEST_SECONDARY_WALLET_ADDRESS=wasm1lejkm8nevz4hgmafyfm03upkkj76cvzj4geapv TEST_WALLET_PASSWORD=;pzPCXB^@92byC +PLAYWRIGHT_HTML_OPEN=never diff --git a/apps/transfers/frontend/README.md b/apps/transfers/frontend/README.md index b3c26f7..8263631 100644 --- a/apps/transfers/frontend/README.md +++ b/apps/transfers/frontend/README.md @@ -1,13 +1,13 @@ # Transfer App -This is an example frontend that illustrates how to interact with a Transfer Quartz App. +This is an example frontend that illustrates how to interact with a Quartz app. -This example offers: +This example offers the ability to: - Deposit amounts into a balance - Withdraw the whole deposit -- Transfer amounts between wallet addresses in a private-preserving way -- Query your encrypted balance to capture changes +- Transfer amounts between wallets in a private-preserving way +- Query your encrypted balance - Switch between Keplr wallets ## Requirements @@ -26,7 +26,7 @@ Install dependencies: npm ci ``` -The App requires some environment variables to fully work. Be sure to set up those accordingly to your local environment. +The app requires some environment variables to fully work. Be sure to set up those accordingly to your local environment. You should start from the template: @@ -34,10 +34,52 @@ You should start from the template: cp .env.example .env.local ``` +Required environment variables: + +``` +# Choose target chain configuration +NEXT_PUBLIC_TARGET_CHAIN= +# Enclave public key to encrypt transfers +NEXT_PUBLIC_ENCLAVE_PUBLIC_KEY= +# Target transfers contract +NEXT_PUBLIC_TRANSFERS_CONTRACT_ADDRESS= +``` + Run the app: ```bash npm run dev ``` -And now everything is up & running 🎉 +App will be running on http://localhost:3000/ and now everything is up & running 🎉 + +## E2E Testing + +For tests to work, you need to set up the following required environment variables: + +``` +# Frontend base url +TEST_BASE_URL= +# Keplr browser extension version +TEST_KEPLR_EXTENSION_VERSION= +# Main wallet mnemonic (Use only funded wallets) +TEST_WALLET_MNEMONIC= +# Secondary wallet mnemonic (Use only funded wallets) +TEST_SECONDARY_WALLET_MNEMONIC= +# Secondary wallet address +TEST_SECONDARY_WALLET_ADDRESS= +# Keplr wallet password. It can be whatever +TEST_WALLET_PASSWORD= +``` + +Run all E2E tests: + +```bash +npm run test +``` + +If want to run the tests with the Playwright dedicated interface, run: + +```bash +npm run test:ui +``` diff --git a/apps/transfers/frontend/env.d.ts b/apps/transfers/frontend/env.d.ts index ed52b7c..7b2dee7 100644 --- a/apps/transfers/frontend/env.d.ts +++ b/apps/transfers/frontend/env.d.ts @@ -3,5 +3,11 @@ namespace NodeJS { NEXT_PUBLIC_ENCLAVE_PUBLIC_KEY: string NEXT_PUBLIC_TARGET_CHAIN: string NEXT_PUBLIC_TRANSFERS_CONTRACT_ADDRESS: string + TEST_BASE_URL: string + TEST_KEPLR_EXTENSION_VERSION: string + TEST_WALLET_MNEMONIC: string + TEST_SECONDARY_WALLET_MNEMONIC: string + TEST_SECONDARY_WALLET_ADDRESS: string + TEST_WALLET_PASSWORD: string } } diff --git a/apps/transfers/frontend/package.json b/apps/transfers/frontend/package.json index e45865f..e586794 100644 --- a/apps/transfers/frontend/package.json +++ b/apps/transfers/frontend/package.json @@ -9,7 +9,8 @@ "lint": "eslint .", "lint:fix": "eslint . --fix", "test": "playwright test", - "test:ui": "playwright test --ui" + "test:ui": "playwright test --ui", + "prepare": "npx playwright install chromium" }, "dependencies": { "eciesjs": "^0.4.7", diff --git a/apps/transfers/frontend/playwright.config.ts b/apps/transfers/frontend/playwright.config.ts index d6c8e49..bb04d35 100644 --- a/apps/transfers/frontend/playwright.config.ts +++ b/apps/transfers/frontend/playwright.config.ts @@ -25,6 +25,8 @@ export default defineConfig({ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: 'html', + timeout: 0, + globalTimeout: process.env.CI ? 5 * 60 * 1000 : undefined, /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ diff --git a/apps/transfers/frontend/src/app/(anon)/page.tsx b/apps/transfers/frontend/src/app/(anon)/page.tsx index 55d2907..f571c19 100644 --- a/apps/transfers/frontend/src/app/(anon)/page.tsx +++ b/apps/transfers/frontend/src/app/(anon)/page.tsx @@ -22,6 +22,7 @@ export default function Landing() {

Connect your Keplr wallet to log in

diff --git a/apps/transfers/frontend/src/app/(anon)/set-seed/page.tsx b/apps/transfers/frontend/src/app/(anon)/set-seed/page.tsx index 1cf711b..17d3dd1 100644 --- a/apps/transfers/frontend/src/app/(anon)/set-seed/page.tsx +++ b/apps/transfers/frontend/src/app/(anon)/set-seed/page.tsx @@ -30,12 +30,14 @@ export default function SetSeed() {
Continue with the autogenerated seed phrase setIsModalOpen(true)} > diff --git a/apps/transfers/frontend/src/app/(protected)/dashboard/page.tsx b/apps/transfers/frontend/src/app/(protected)/dashboard/page.tsx index 18ba312..8bcb961 100644 --- a/apps/transfers/frontend/src/app/(protected)/dashboard/page.tsx +++ b/apps/transfers/frontend/src/app/(protected)/dashboard/page.tsx @@ -96,7 +96,7 @@ export default function Dashboard() { ).then((data) => { setLoading(false) setBalance(retrieveBalance(data)) - showSuccess('Balance updated correctly') + showSuccess('Balance updated successfully') }) } }, @@ -167,6 +167,7 @@ export default function Dashboard() { setIsDepositModalOpen(true)} > @@ -174,6 +175,7 @@ export default function Dashboard() { Deposit setIsTransferModalOpen(true)} @@ -182,6 +184,7 @@ export default function Dashboard() { Transfer setIsWithdrawModalOpen(true)} @@ -192,6 +195,7 @@ export default function Dashboard() {
{ const res = confirm( diff --git a/apps/transfers/frontend/src/components/DepositModalWindow.tsx b/apps/transfers/frontend/src/components/DepositModalWindow.tsx index 3293471..859af47 100644 --- a/apps/transfers/frontend/src/components/DepositModalWindow.tsx +++ b/apps/transfers/frontend/src/components/DepositModalWindow.tsx @@ -101,6 +101,7 @@ export function DepositModalWindow(props: ModalWindowProps) { Deposit diff --git a/apps/transfers/frontend/src/components/EnterSeedModal.tsx b/apps/transfers/frontend/src/components/EnterSeedModal.tsx index 354ca40..bfca199 100644 --- a/apps/transfers/frontend/src/components/EnterSeedModal.tsx +++ b/apps/transfers/frontend/src/components/EnterSeedModal.tsx @@ -66,6 +66,7 @@ export function EnterSeedModal({ Continue diff --git a/apps/transfers/frontend/src/components/ModalWindow/ModalWindow.tsx b/apps/transfers/frontend/src/components/ModalWindow/ModalWindow.tsx index 05d209a..ac5fe07 100644 --- a/apps/transfers/frontend/src/components/ModalWindow/ModalWindow.tsx +++ b/apps/transfers/frontend/src/components/ModalWindow/ModalWindow.tsx @@ -100,7 +100,7 @@ export function ModalWindow({ onTransitionEnd={handleTransitionEnd} {...otherProps} > - {children} + {isOpen && children}
, document.body, diff --git a/apps/transfers/frontend/src/components/TransferModalWindow.tsx b/apps/transfers/frontend/src/components/TransferModalWindow.tsx index 18f0a01..900d1a1 100644 --- a/apps/transfers/frontend/src/components/TransferModalWindow.tsx +++ b/apps/transfers/frontend/src/components/TransferModalWindow.tsx @@ -154,6 +154,7 @@ export function TransferModalWindow(props: ModalWindowProps) { Transfer
diff --git a/apps/transfers/frontend/src/components/WithdrawModalWindow.tsx b/apps/transfers/frontend/src/components/WithdrawModalWindow.tsx index 1aa120c..a13af25 100644 --- a/apps/transfers/frontend/src/components/WithdrawModalWindow.tsx +++ b/apps/transfers/frontend/src/components/WithdrawModalWindow.tsx @@ -59,6 +59,7 @@ export function WithdrawModalWindow(props: ModalWindowProps) { Withdraw diff --git a/apps/transfers/frontend/src/config/routes.ts b/apps/transfers/frontend/src/config/routes.ts new file mode 100644 index 0000000..8bc07c2 --- /dev/null +++ b/apps/transfers/frontend/src/config/routes.ts @@ -0,0 +1,7 @@ +type Url = 'landing' | 'seed' | 'dashboard' + +export const routes: Record = { + landing: '/', + seed: '/set-seed', + dashboard: '/dashboard', +} diff --git a/apps/transfers/frontend/tests/e2e/auth.spec.ts b/apps/transfers/frontend/tests/e2e/auth.spec.ts new file mode 100644 index 0000000..6c56582 --- /dev/null +++ b/apps/transfers/frontend/tests/e2e/auth.spec.ts @@ -0,0 +1,39 @@ +import { routes } from '@/config/routes' +import test from './fixtures' +import { connectWallet } from './helpers/connectWalet' +import { setSeedPhrase } from './helpers/setSeedPhrase' + +const { dashboard, landing, seed } = routes + +test.describe('Auth', () => { + test('can go nowhere but landing page without a wallet', async ({ page }) => { + await page.goto(seed) + await page.goto(dashboard) + await test + .expect(page.getByRole('button', { name: /connect/i })) + .toBeVisible() + }) + + test('can go nowhere but seed page without a seed phrase', async ({ + context, + page, + }) => { + await connectWallet({ context, page }) + + await page.goto(landing) + await page.goto(dashboard) + await test.expect(page.getByText(/recovery seed phrase/i)).toBeVisible() + }) + + test('cannot go to anon pages once fully logged in', async ({ + context, + page, + }) => { + await connectWallet({ context, page }) + await setSeedPhrase({ page }) + + await page.goto(landing) + await page.goto(seed) + await test.expect(page.getByText(/balance:/i)).toBeVisible() + }) +}) diff --git a/apps/transfers/frontend/tests/e2e/fixtures.ts b/apps/transfers/frontend/tests/e2e/fixtures.ts index 96ffa05..1508032 100644 --- a/apps/transfers/frontend/tests/e2e/fixtures.ts +++ b/apps/transfers/frontend/tests/e2e/fixtures.ts @@ -1,88 +1,49 @@ -import { - test as baseTest, - chromium, - expect, - BrowserContext, -} from '@playwright/test' +import { test as baseTest, chromium } from '@playwright/test' import path from 'path' +import { importWallet } from './helpers/importWallet' + +let extensionUrl: string +const pathToExtension = path.join( + __dirname, + 'extensions', + `keplr-extension-manifest-v3-v${process.env.TEST_KEPLR_EXTENSION_VERSION}`, +) + // Tests fixtures -const test = baseTest.extend<{}, { _globalContext: BrowserContext }>({ - // Shared context for tests so Keplr initialization runs only once for all tests - _globalContext: [ - async ({}, use) => { - const mnemonicWords = process.env.TEST_KEPLR_MNEMONIC!.split(' ') - const pathToExtension = path.join( - __dirname, - 'extensions', - `keplr-extension-manifest-v3-v${process.env.TEST_KEPLR_EXTENSION_VERSION}`, - ) - // We launch browser with the extension - const context = await chromium.launchPersistentContext('', { - headless: false, - args: [ - `--disable-extensions-except=${pathToExtension}`, - `--load-extension=${pathToExtension}`, - ], - }) - const page = await context.waitForEvent('page') - const extensionId = /\/\/(.*?)\//.exec(page.url())![1] +const test = baseTest.extend<{ + extensionUrl: string +}>({ + // Overwritten Playwright context to setup Keplr wallet before all tests + context: async ({}, use) => { + // Launch browser with Keplr installed + const context = await chromium.launchPersistentContext('', { + headless: false, + args: [ + `--disable-extensions-except=${pathToExtension}`, + `--load-extension=${pathToExtension}`, + ], + }) - // Keplr import wallet flow - await page.waitForURL(new RegExp(`${extensionId}/register.html`)) - await expect(page.getByText('Import an existing wallet')).toBeVisible() - await page - .getByRole('button', { name: 'Import an existing wallet' }) - .click() - await expect( - page.getByText('Use recovery phrase or private key'), - ).toBeVisible() - await page - .getByRole('button', { name: 'Use recovery phrase or private key' }) - .click() + const page = await context.waitForEvent('page') - await page.getByText('24 Words').click() - const seedInputs = await page.locator('input') - for (let i = 0; i < mnemonicWords.length; i++) { - await seedInputs.nth(i).fill(mnemonicWords[i]) - } - await page.getByRole('button', { name: 'Import', exact: true }).click() + // Retrieve target URL to interact with Keplr extension + const extensionId = /\/\/(.*?)\//.exec(page.url())![1] + extensionUrl = `chrome-extension://${extensionId}` - await page - .getByPlaceholder('e.g. Trading, NFT Vault, Investment') - .fill('Playwright Wallet') - const inputs = await page.getByPlaceholder( - 'At least 8 characters in length', - ) - for (let i = 0; i < (await inputs.count()); i++) { - await inputs.nth(i).fill(process.env.TEST_KEPLR_PASSWORD!) - } - await page.getByRole('button', { name: 'Next' }).click() + // Import a wallet to be used in tests + await importWallet({ + extensionUrl, + mnemonic: process.env.TEST_WALLET_MNEMONIC, + name: 'main', + page, + }) - await expect(page.getByText('Select Chains')).toBeVisible() - await page.getByRole('button', { name: 'Save' }).click() - - // Accept app suggested testnet info - await page.goto('/') - const addChainPage = await context.waitForEvent('page') - await addChainPage.getByRole('button', { name: 'Approve' }).click() - - // Wait for App to load - await test.expect(page.getByText('Balance:')).toBeVisible() - - await use(context) - await context.close() - }, - { scope: 'worker' }, - ], - context: async ({ _globalContext }, use) => { - await use(_globalContext) + await use(context) + await context.close() }, - page: async ({ context }, use) => { - const page = await context.newPage() - - await use(page) - await page.close() + extensionUrl: async ({}, use) => { + await use(extensionUrl) }, }) diff --git a/apps/transfers/frontend/tests/e2e/helpers/connectWalet.ts b/apps/transfers/frontend/tests/e2e/helpers/connectWalet.ts new file mode 100644 index 0000000..532b713 --- /dev/null +++ b/apps/transfers/frontend/tests/e2e/helpers/connectWalet.ts @@ -0,0 +1,21 @@ +import { BrowserContext, Page } from '@playwright/test' + +import { routes } from '@/config/routes' + +export const connectWallet = async ({ + context, + page, +}: { + context: BrowserContext + page: Page +}) => { + // Connect to Keplr wallet + await page.goto(routes.landing) + await page.getByRole('button', { name: /connect/i }).click() + + // Accept app suggested testnet info + const addChainPage = await context.waitForEvent('page') + + await addChainPage.getByRole('button', { name: /approve/i }).click() + await addChainPage.waitForEvent('close') +} diff --git a/apps/transfers/frontend/tests/e2e/helpers/getBalance.ts b/apps/transfers/frontend/tests/e2e/helpers/getBalance.ts new file mode 100644 index 0000000..693be89 --- /dev/null +++ b/apps/transfers/frontend/tests/e2e/helpers/getBalance.ts @@ -0,0 +1,20 @@ +import { BrowserContext, Page } from '@playwright/test' +import { signTx } from './signTx' + +export const getBalance = async ({ + context, + page, +}: { + context: BrowserContext + page: Page +}) => { + // Check new balance + await page.getByRole('button', { name: /get/i }).click() + + await signTx({ context, page }) + + // Wait for the success alert to appear so we know balance updated + await page.getByText(/\$/i).waitFor({ state: 'visible' }) + + return page.getByText(/\$/i).textContent() +} diff --git a/apps/transfers/frontend/tests/e2e/helpers/importWallet.ts b/apps/transfers/frontend/tests/e2e/helpers/importWallet.ts new file mode 100644 index 0000000..c7e2546 --- /dev/null +++ b/apps/transfers/frontend/tests/e2e/helpers/importWallet.ts @@ -0,0 +1,41 @@ +import { Page } from '@playwright/test' + +export const importWallet = async ({ + extensionUrl, + mnemonic, + name, + page, +}: { + extensionUrl: string + mnemonic: string + name: string + page: Page +}) => { + await page.goto(`${extensionUrl}/register.html`) + + const mnemonicWords = mnemonic.split(' ') + + await page.getByRole('button', { name: /import/i }).click() + await page.getByRole('button', { name: /use/i }).click() + await page.getByRole('button', { name: /24/ }).click() + + const seedInputs = await page.locator('input') + + for (let i = 0; i < mnemonicWords.length; i++) { + await seedInputs.nth(i).fill(mnemonicWords[i]) + } + + await page.getByRole('button', { name: 'Import', exact: true }).click() + await page.getByPlaceholder('e.g. Trading, NFT Vault,').fill(name) + + const inputs = await page.getByPlaceholder('At least 8 characters in length') + + for (let i = 0; i < (await inputs.count()); i++) { + await inputs.nth(i).fill(process.env.TEST_WALLET_PASSWORD) + } + + await page.getByRole('button', { name: /next/i }).click() + await page.getByRole('button', { name: /save/i }).click() + + await page.close() +} diff --git a/apps/transfers/frontend/tests/e2e/helpers/setSeedPhrase.ts b/apps/transfers/frontend/tests/e2e/helpers/setSeedPhrase.ts new file mode 100644 index 0000000..5610999 --- /dev/null +++ b/apps/transfers/frontend/tests/e2e/helpers/setSeedPhrase.ts @@ -0,0 +1,17 @@ +import { Page } from '@playwright/test' + +export const setSeedPhrase = async ({ + page, + seedPhrase, +}: { + page: Page + seedPhrase?: string +}) => { + if (!seedPhrase) { + await page.getByRole('button', { name: /continue with/i }).click() + } else { + await page.getByRole('button', { name: /enter my own/i }).click() + await page.locator('input').fill(seedPhrase) + await page.getByRole('button', { name: 'Continue', exact: true }).click() + } +} diff --git a/apps/transfers/frontend/tests/e2e/helpers/signTx.ts b/apps/transfers/frontend/tests/e2e/helpers/signTx.ts new file mode 100644 index 0000000..c720551 --- /dev/null +++ b/apps/transfers/frontend/tests/e2e/helpers/signTx.ts @@ -0,0 +1,16 @@ +import { BrowserContext, Page } from '@playwright/test' + +export const signTx = async ({ + context, + page, +}: { + context: BrowserContext + page: Page +}) => { + // Sign tx + const signPage = await context.waitForEvent('page') + + await signPage.getByRole('button', { name: /approve/i }).click() + await signPage.waitForEvent('close') + await page.getByText(/successfully/i).waitFor({ state: 'visible' }) +} diff --git a/apps/transfers/frontend/tests/e2e/helpers/swapWallet.ts b/apps/transfers/frontend/tests/e2e/helpers/swapWallet.ts new file mode 100644 index 0000000..57420af --- /dev/null +++ b/apps/transfers/frontend/tests/e2e/helpers/swapWallet.ts @@ -0,0 +1,19 @@ +import { BrowserContext } from '@playwright/test' + +export const swapWallet = async ({ + context, + extensionUrl, + name, +}: { + context: BrowserContext + extensionUrl: string + name: string +}) => { + const page = await context.newPage() + + await page.goto(`${extensionUrl}/popup.html`) + await page.locator('div[cursor="pointer"] > svg').nth(1).click() + await page.getByText(name).click() + + await page.close() +} diff --git a/apps/transfers/frontend/tests/e2e/seed-phrase.spec.ts b/apps/transfers/frontend/tests/e2e/seed-phrase.spec.ts new file mode 100644 index 0000000..deeb801 --- /dev/null +++ b/apps/transfers/frontend/tests/e2e/seed-phrase.spec.ts @@ -0,0 +1,31 @@ +import test from './fixtures' +import { connectWallet } from './helpers/connectWalet' +import { setSeedPhrase } from './helpers/setSeedPhrase' + +test.beforeEach(async ({ context, page }) => { + await connectWallet({ context, page }) +}) + +test.describe('Seed Phrase', () => { + test('can use autogenerated seed phrase', async ({ page }) => { + await setSeedPhrase({ page }) + await test + .expect( + await page.evaluate(() => + window.localStorage.getItem('ephemeral-mnemonic'), + ), + ) + .toBeDefined() + }) + + test('can enter and use a custom seed phrase', async ({ page }) => { + await setSeedPhrase({ page, seedPhrase: process.env.TEST_WALLET_MNEMONIC }) + await test + .expect( + await page.evaluate(() => + window.localStorage.getItem('ephemeral-mnemonic'), + ), + ) + .toEqual(process.env.TEST_WALLET_MNEMONIC) + }) +}) diff --git a/apps/transfers/frontend/tests/e2e/transfers.spec.ts b/apps/transfers/frontend/tests/e2e/transfers.spec.ts index c2ab8f1..d603c12 100644 --- a/apps/transfers/frontend/tests/e2e/transfers.spec.ts +++ b/apps/transfers/frontend/tests/e2e/transfers.spec.ts @@ -1,15 +1,131 @@ import test from './fixtures' +import { importWallet } from './helpers/importWallet' +import { getBalance } from './helpers/getBalance' +import { swapWallet } from './helpers/swapWallet' +import { signTx } from './helpers/signTx' +import { connectWallet } from './helpers/connectWalet' +import { setSeedPhrase } from './helpers/setSeedPhrase' -test.beforeEach(async ({ page }) => { - await page.goto('/') +test.describe.configure({ mode: 'serial' }) +test.beforeEach(async ({ context, page }) => { + await connectWallet({ context, page }) + await setSeedPhrase({ page, seedPhrase: process.env.TEST_WALLET_MNEMONIC }) }) +let mainBalance: number + test.describe('Transfers', () => { - test('app should render correctly', async ({ page }) => { - await test.expect(page.getByText('Balance:')).toBeVisible() + test('can deposit a sum successfully', async ({ context, page }) => { + // Initialize the balance + mainBalance = Number( + (await getBalance({ context, page }))!.replace('$', ''), + ) + + await page.getByRole('button', { name: /deposit/i }).click() + await page.keyboard.type('20') + await page + .getByRole('button', { name: /deposit/i }) + .nth(1) + .click() + + await signTx({ context, page }) + + await page + .getByRole('button', { name: /cancel/i, includeHidden: false }) + .click() + + // Check new balance + await page.waitForTimeout(4000) + + mainBalance += 20 + + await test + .expect(await getBalance({ context, page })) + .toEqual(`$${mainBalance}`) }) - test('balance should be 0 at first', async ({ page }) => { - await test.expect(page.getByText('$0')).toBeVisible() + test('can transfer to another wallet successfully', async ({ + context, + extensionUrl, + page, + }) => { + // Import a secondary wallet to transfer to + await importWallet({ + extensionUrl, + mnemonic: process.env.TEST_SECONDARY_WALLET_MNEMONIC, + page: await context.newPage(), + name: 'secondary', + }) + + // Initialize the secondary account balance after importing + const secondaryBalance = Number( + (await getBalance({ context, page }))!.replace('$', ''), + ) + + // Swap back to main wallet + await swapWallet({ context, extensionUrl, name: 'main' }) + + // Transfer to the secondary wallet + await page.getByRole('button', { name: /transfer/i }).click() + await page.keyboard.type(process.env.TEST_SECONDARY_WALLET_ADDRESS) + await page.getByPlaceholder('0.00').fill('10') + await page + .getByRole('button', { name: /transfer/i }) + .nth(1) + .click() + + await signTx({ context, page }) + + await page + .getByRole('button', { name: /cancel/i, includeHidden: false }) + .click() + + // Check new balance + await page.waitForTimeout(4000) + mainBalance -= 10 + await test + .expect(await getBalance({ context, page })) + .toEqual(`$${mainBalance}`) + + // Swap to secondary to check if the transfer was received + await swapWallet({ context, extensionUrl, name: 'secondary' }) + + await test + .expect(await getBalance({ context, page })) + .toEqual(`$${secondaryBalance + 10}`) + + // Set balance to 0 again for cleaning purposes + await page.getByRole('button', { name: /withdraw/i }).click() + await page + .getByRole('button', { name: /withdraw/i }) + .nth(1) + .click() + + await signTx({ context, page }) + + await page + .getByRole('button', { name: /cancel/i, includeHidden: false }) + .click() + + // Back to main wallet + await swapWallet({ context, extensionUrl, name: 'main' }) + }) + + test('can withdraw deposited sum successfully', async ({ context, page }) => { + await page.getByRole('button', { name: /withdraw/i }).click() + await page + .getByRole('button', { name: /withdraw/i }) + .nth(1) + .click() + + await signTx({ context, page }) + + await page + .getByRole('button', { name: /cancel/i, includeHidden: false }) + .click() + + // Check new balance + await page.waitForTimeout(4000) + await test.expect(await getBalance({ context, page })).toEqual('$0') }) }) diff --git a/apps/transfers/frontend/tests/global.setup.ts b/apps/transfers/frontend/tests/global.setup.ts index 97b1798..0937c33 100644 --- a/apps/transfers/frontend/tests/global.setup.ts +++ b/apps/transfers/frontend/tests/global.setup.ts @@ -13,9 +13,9 @@ async function globalSetup() { const resp = await fetch(downloadUrl) if (resp.ok && resp.body) { - Readable.fromWeb(resp.body as any).pipe( - unzipper.Extract({ path: folderPath }), - ) + await Readable.fromWeb(resp.body as any) + .pipe(unzipper.Extract({ path: folderPath })) + .promise() } } }