diff --git a/.github/workflows/frontend-e2e-tests.yml b/.github/workflows/frontend-e2e-tests.yml index 3747ceb209..06b4413a4a 100644 --- a/.github/workflows/frontend-e2e-tests.yml +++ b/.github/workflows/frontend-e2e-tests.yml @@ -26,8 +26,8 @@ jobs: environment_url: ${{ steps.vercel.outputs.environment_url }} run: echo "$environment_url" - preview-swap-tests: - timeout-minutes: 10 + preview-swap-osmo-tests: + timeout-minutes: 15 runs-on: macos-latest needs: wait-for-deployment steps: @@ -65,13 +65,61 @@ jobs: WALLET_ID: ${{ secrets.TEST_WALLET_ID }} run: | cd packages/e2e - npx playwright test -g "Test Swap feature" + npx playwright test swap.osmo.wallet - name: upload Swap test results if: failure() id: swap-test-results uses: actions/upload-artifact@v4 with: - name: preview-swap-test-results + name: osmo-swap-test-results + path: packages/e2e/playwright-report + + preview-swap-usdc-tests: + timeout-minutes: 15 + runs-on: macos-latest + needs: [wait-for-deployment, preview-swap-osmo-tests] + steps: + - name: Check out repository + uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e + - name: print environment_url and BRANCH_NAME + env: + BASE_URL: "https://${{ needs.wait-for-deployment.outputs.environment_url }}" + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + run: | + echo "$BASE_URL" + echo "$BRANCH_NAME" + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20.x + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: "**/node_modules" + key: ${{ runner.OS }}-20.x-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.OS }}-20.x- + - name: Install Playwright + run: | + echo "$GITHUB_OUTPUT" + yarn --cwd packages/e2e install --frozen-lockfile && npx playwright install --with-deps chromium + - name: Run Swap Pair tests + env: + BASE_URL: "https://${{ needs.wait-for-deployment.outputs.environment_url }}" + PRIVATE_KEY: ${{ secrets.TEST_PRIVATE_KEY }} + WALLET_ID: ${{ secrets.TEST_WALLET_ID }} + run: | + cd packages/e2e + npx playwright test swap.usdc.wallet + - name: upload Swap test results + if: failure() + id: swap-test-results + uses: actions/upload-artifact@v4 + with: + name: usdc-swap-test-results path: packages/e2e/playwright-report preview-portfolio-trx-tests: @@ -153,9 +201,10 @@ jobs: path: packages/e2e/playwright-report preview-trade-tests: - timeout-minutes: 10 + timeout-minutes: 15 runs-on: macos-latest - needs: [wait-for-deployment, preview-swap-tests] + needs: + [wait-for-deployment, preview-swap-osmo-tests, preview-swap-usdc-tests] steps: - name: Check out repository uses: actions/checkout@v4 diff --git a/.github/workflows/monitoring-quote-geo-e2e-tests.yml b/.github/workflows/monitoring-quote-geo-e2e-tests.yml index 66efec6c00..5936b565f3 100644 --- a/.github/workflows/monitoring-quote-geo-e2e-tests.yml +++ b/.github/workflows/monitoring-quote-geo-e2e-tests.yml @@ -28,6 +28,9 @@ jobs: run: curl -L "https://ipinfo.io" -s - name: Check out repository uses: actions/checkout@v4 + with: + sparse-checkout: | + packages/e2e - name: Setup Node.js uses: actions/setup-node@v4 with: diff --git a/.github/workflows/prod-frontend-e2e-tests.yml b/.github/workflows/prod-frontend-e2e-tests.yml index 2b81ca22f9..240f5ab722 100644 --- a/.github/workflows/prod-frontend-e2e-tests.yml +++ b/.github/workflows/prod-frontend-e2e-tests.yml @@ -30,7 +30,7 @@ jobs: prod-e2e-tests: runs-on: macos-latest - timeout-minutes: 15 + timeout-minutes: 20 needs: wait-for-deployment environment: name: prod_swap_test @@ -38,6 +38,8 @@ jobs: - name: Check out repository uses: actions/checkout@v4 with: + sparse-checkout: | + packages/e2e ref: master - name: Setup Node.js uses: actions/setup-node@v4 @@ -60,7 +62,7 @@ jobs: WALLET_ID: ${{ secrets.TEST_WALLET_ID }} run: | cd packages/e2e - npx playwright test transactions portfolio swap.wallet + npx playwright test transactions portfolio swap.osmo.wallet - name: upload test results if: always() id: e2e-test-results diff --git a/packages/e2e/README.md b/packages/e2e/README.md index 77c5e1b589..82362c370a 100644 --- a/packages/e2e/README.md +++ b/packages/e2e/README.md @@ -16,7 +16,7 @@ All you need to add is a private keys for wallets that are being used: To install Playwright, please execute `npx playwright install --with-deps chromium` from the /web folder. To run a Select pair tests, please execute `npx playwright test -g "Test Select Swap Pair feature"` from the /web folder. -To run a Swap E2E tests, please execute `npx playwright test -g "Test Swap feature"` from the /web folder. +To run a Swap E2E tests, please execute `npx playwright test swap.osmo.wallet` from the /web folder. To run a Monitoring E2E tests, please execute `npx playwright test monitoring --timeout 180000` from the /web folder. Tests can be executed locally in a browser by changing `headless: true` to `headless: false`. diff --git a/packages/e2e/pages/trade-page.ts b/packages/e2e/pages/trade-page.ts index 32c14d9298..41f0605bc0 100644 --- a/packages/e2e/pages/trade-page.ts +++ b/packages/e2e/pages/trade-page.ts @@ -3,350 +3,414 @@ import { type Locator, type Page, expect, -} from '@playwright/test' +} from "@playwright/test"; -import { BasePage } from './base-page' +import { BasePage } from "./base-page"; export class TradePage extends BasePage { - readonly page: Page - readonly swapBtn: Locator - readonly swapMaxBtn: Locator - readonly flipAssetsBtn: Locator - readonly exchangeRate: Locator - readonly trxSuccessful: Locator - readonly trxBroadcasting: Locator - readonly trxLink: Locator - readonly inputAmount: Locator - readonly confirmSwapBtn: Locator - readonly buyTabBtn: Locator - readonly buyBtn: Locator - readonly sellTabBtn: Locator - readonly sellBtn: Locator - readonly limitTabBtn: Locator - readonly orderHistoryLink: Locator - readonly limitPrice: Locator + readonly page: Page; + readonly swapBtn: Locator; + readonly swapMaxBtn: Locator; + readonly flipAssetsBtn: Locator; + readonly exchangeRate: Locator; + readonly trxSuccessful: Locator; + readonly trxBroadcasting: Locator; + readonly trxLink: Locator; + readonly inputAmount: Locator; + readonly confirmSwapBtn: Locator; + readonly buyTabBtn: Locator; + readonly buyBtn: Locator; + readonly sellTabBtn: Locator; + readonly sellBtn: Locator; + readonly limitTabBtn: Locator; + readonly orderHistoryLink: Locator; + readonly limitPrice: Locator; constructor(page: Page) { - super(page) - this.page = page - this.swapBtn = page.locator('//button[@data-testid="trade-button-swap"]') - this.buyTabBtn = page.locator('//div[@class]/button[.="Buy"]/p[@class]/..') - this.buyBtn = page.locator('//div[@class]/button[@class]/h6[.="Buy"]/..') - this.sellBtn = page.locator('//div[@class]/button[@class]/h6[.="Sell"]/..') + super(page); + this.page = page; + this.swapBtn = page.locator('//button[@data-testid="trade-button-swap"]'); + this.buyTabBtn = page.locator('//div[@class]/button[.="Buy"]/p[@class]/..'); + this.buyBtn = page.locator('//div[@class]/button[@class]/h6[.="Buy"]/..'); + this.sellBtn = page.locator('//div[@class]/button[@class]/h6[.="Sell"]/..'); this.sellTabBtn = page.locator( - '//div[@class]/button[.="Sell"]/p[@class]/..', - ) - this.confirmSwapBtn = page.locator('//div[@class]/button[.="Confirm"]') - this.swapMaxBtn = page.locator('//span[.="Max"]') + '//div[@class]/button[.="Sell"]/p[@class]/..' + ); + this.confirmSwapBtn = page.locator('//div[@class]/button[.="Confirm"]'); + this.swapMaxBtn = page.locator('//span[.="Max"]'); this.flipAssetsBtn = page.locator( - '//div/button[contains(@class, "ease-bounce")]', - ) - this.exchangeRate = page.locator('//span[@data-testid="token-price"]') - this.trxSuccessful = page.getByText('Transaction Successful') - this.trxLink = page.getByText('View explorer') - this.trxBroadcasting = page.locator('//h6[.="Transaction Broadcasting"]') + '//div/button[contains(@class, "ease-bounce")]' + ); + this.exchangeRate = page.locator('//span[@data-testid="token-price"]'); + this.trxSuccessful = page.getByText("Transaction Successful"); + this.trxLink = page.getByText("View explorer"); + this.trxBroadcasting = page.locator('//h6[.="Transaction Broadcasting"]'); this.inputAmount = page.locator( - "//input[contains(@data-testid, 'trade-input')]", - ) - this.limitTabBtn = page.locator('//div[@class="w-full"]/button[.="Limit"]') - this.orderHistoryLink = page.getByText('Order history') - this.limitPrice = page.locator("//div/input[@type='text']") + "//input[contains(@data-testid, 'trade-input')]" + ); + this.limitTabBtn = page.locator('//div[@class="w-full"]/button[.="Limit"]'); + this.orderHistoryLink = page.getByText("Order history"); + this.limitPrice = page.locator("//div/input[@type='text']"); } async goto() { - const assetPromise = this.page.waitForRequest('**/assets.json') - await this.page.goto('/') - const request = await assetPromise - expect(request).toBeTruthy() + const assetPromise = this.page.waitForRequest("**/assets.json"); + await this.page.goto("/"); + const request = await assetPromise; + expect(request).toBeTruthy(); // we expect that after 2 seconds tokens are loaded and any failure after this point should be considered a bug. - await this.page.waitForTimeout(2000) - const currentUrl = this.page.url() - console.log(`FE opened at: ${currentUrl}`) + await this.page.waitForTimeout(2000); + const currentUrl = this.page.url(); + console.log(`FE opened at: ${currentUrl}`); } async gotoOrdersHistory(timeout = 1) { - await this.page.waitForTimeout(1000) - await this.orderHistoryLink.click() - await this.page.waitForTimeout(1000) - await new Promise((f) => setTimeout(f, timeout * 1000)) - const currentUrl = this.page.url() - console.log(`FE opened at: ${currentUrl}`) + await this.page.waitForTimeout(1000); + await this.orderHistoryLink.click(); + await this.page.waitForTimeout(1000); + await new Promise((f) => setTimeout(f, timeout * 1000)); + const currentUrl = this.page.url(); + console.log(`FE opened at: ${currentUrl}`); } async openBuyTab() { - await this.buyTabBtn.click() + await this.buyTabBtn.click(); } async openSellTab() { - await this.sellTabBtn.click() + await this.sellTabBtn.click(); } async openLimit() { - await this.limitTabBtn.click() - await this.page.waitForTimeout(1000) + await this.limitTabBtn.click(); + await this.page.waitForTimeout(1000); } async getLimitPrice() { - const lp = await this.limitPrice.inputValue() - console.log(`Current limit price is: ${lp}`) - return lp + const lp = await this.limitPrice.inputValue(); + console.log(`Current limit price is: ${lp}`); + return lp; } async setLimitPriceChange(change: string) { - const locator = `//button/span[contains(@class, "body2") and .="${change}"]` - await this.page.locator(locator).click() - await this.page.waitForTimeout(1000) + const locator = `//button/span[contains(@class, "body2") and .="${change}"]`; + await this.page.locator(locator).click(); + await this.page.waitForTimeout(1000); } async setLimitPrice(price: string) { - console.log(`Set Order Limit Price to: ${price}`) - await this.limitPrice.fill(price, { timeout: 2000 }) + console.log(`Set Order Limit Price to: ${price}`); + await this.limitPrice.fill(price, { timeout: 2000 }); } async flipTokenPair() { - await this.flipAssetsBtn.click() - await this.page.waitForTimeout(2000) - console.log('Fliped token pair.') + await this.flipAssetsBtn.click(); + await this.page.waitForTimeout(2000); + console.log("Fliped token pair."); } async clickMaxAmountButton() { - await this.swapMaxBtn.click({ timeout: 2000 }) - await this.page.waitForTimeout(1000) - console.log('Clicked Max token amount button.') + await this.swapMaxBtn.click({ timeout: 2000 }); + await this.page.waitForTimeout(1000); + console.log("Clicked Max token amount button."); } async enterAmount(amount: string) { // Just enter an amount for the swap and wait for a quote - await this.inputAmount.fill(amount, { timeout: 2000 }) - await this.page.waitForTimeout(1000) - await expect(this.inputAmount).toHaveValue(amount, { timeout: 1000 }) - const exchangeRate = await this.getExchangeRate() - console.log(`Swap ${amount} with rate: ${exchangeRate}`) + await this.inputAmount.fill(amount, { timeout: 2000 }); + await this.page.waitForTimeout(1000); + await expect(this.inputAmount).toHaveValue(amount, { timeout: 1000 }); + const exchangeRate = await this.getExchangeRate(); + console.log(`Swap ${amount} with rate: ${exchangeRate}`); + } + + private async approveInKeplrAndGetMsg(context: BrowserContext) { + console.log("Wait for 5 seconds for any popup"); + await this.page.waitForTimeout(5_000); + const pages = context.pages(); + console.log(`Number of Open Pages: ${pages.length}`); + if (pages.length === 2) { + const approvePage = pages[1]; + const approvePageTitle = approvePage.url(); + console.log(`Approve page is opened at: ${approvePageTitle}`); + const msgContent = await approvePage + .getByText("type: osmosis/poolmanager/") + .textContent(); + console.log(`Wallet is approving this msg: \n${msgContent}`); + await approvePage + .getByRole("button", { name: "Approve" }) + .click({ timeout: 4000 }); + return msgContent; + } + console.log("Second page was not opened in 5 seconds."); + } + + async justApproveIfNeeded(context: BrowserContext) { + console.log("Wait for 7 seconds for any popup"); + await this.page.waitForTimeout(7_000); + const pages = context.pages(); + console.log(`Number of Open Pages: ${pages.length}`); + if (pages.length === 2) { + const approvePage = pages[1]; + const approvePageTitle = approvePage.url(); + console.log(`Approve page is opened at: ${approvePageTitle}`); + await approvePage + .getByRole("button", { name: "Approve" }) + .click({ timeout: 4000 }); + } + console.log("Second page was not opened in 7 seconds."); } async swapAndGetWalletMsg(context: BrowserContext) { // Make sure to have sufficient balance and swap button is enabled expect( await this.isInsufficientBalanceForSwap(), - 'Insufficient balance for the swap!', - ).toBeFalsy() - await expect(this.swapBtn).toBeEnabled({ timeout: 7000 }) - // Handle Pop-up page -> - await this.swapBtn.click() - const pageApprove = context.waitForEvent('page') - await this.confirmSwapBtn.click() - const approvePage = await pageApprove - await approvePage.waitForLoadState() - const approvePageTitle = approvePage.url() - console.log(`Approve page is opened at: ${approvePageTitle}`) - const approveBtn = approvePage.getByRole('button', { - name: 'Approve', - }) - await expect(approveBtn).toBeEnabled() - const msgContentAmount = await approvePage - .getByText('type: osmosis/poolmanager/') - .textContent() - console.log(`Wallet is approving this msg: \n${msgContentAmount}`) - // Approve trx - await approveBtn.click() - // wait for trx confirmation - await this.page.waitForTimeout(4000) - //await approvePage.close(); - // Handle Pop-up page <- - return { msgContentAmount } + "Insufficient balance for the swap!" + ).toBeFalsy(); + console.log("Swap and Sign now.."); + await expect(this.swapBtn, "Swap button is disabled!").toBeEnabled({ + timeout: 7000, + }); + await this.swapBtn.click({ timeout: 4000 }); + // Handle 1-click by default + const oneClick = '//div[@role="dialog"]//button[@data-state="checked"]'; + if (await this.page.locator(oneClick).isVisible({ timeout: 2000 })) { + await this.page.locator(oneClick).click({ timeout: 3000 }); + } + await this.confirmSwapBtn.click({ timeout: 5000 }); + return await this.approveInKeplrAndGetMsg(context); } async selectAsset(token: string) { - const tokenLocator = '//div//button[@type]//img[@alt]' - const fromToken = this.page.locator(tokenLocator).nth(0) - await fromToken.click() + const tokenLocator = "//div//button[@type]//img[@alt]"; + const fromToken = this.page.locator(tokenLocator).nth(0); + await fromToken.click(); // we expect that after 1 second token filter is displayed. - await this.page.waitForTimeout(1000) - await this.page.getByPlaceholder('Search').fill(token) + await this.page.waitForTimeout(1000); + await this.page.getByPlaceholder("Search").fill(token); const fromLocator = this.page.locator( - `//div/button[@data-testid='token-select-asset']//span[.='${token}']`, - ) - await fromLocator.click() + `//div/button[@data-testid='token-select-asset']//span[.='${token}']` + ); + await fromLocator.click(); } async selectPair(from: string, to: string) { // Filter does not show already selected tokens - console.log(`Select pair ${from} to ${to}`) + console.log(`Select pair ${from} to ${to}`); const fromToken = this.page.locator( - "//div//button[@data-testid='token-in']//img[@alt]", - ) + "//div//button[@data-testid='token-in']//img[@alt]" + ); const toToken = this.page.locator( - "//div//button[@data-testid='token-out']//img[@alt]", - ) + "//div//button[@data-testid='token-out']//img[@alt]" + ); // Select From Token - await fromToken.click({ timeout: 4000 }) + await fromToken.click({ timeout: 4000 }); // we expect that after 1 second token filter is displayed. - await this.page.waitForTimeout(1000) - await this.page.getByPlaceholder('Search').fill(from) + await this.page.waitForTimeout(1000); + await this.page.getByPlaceholder("Search").fill(from); const fromLocator = this.page .locator( - `//div/button[@data-testid='token-select-asset']//span[.='${from}']`, + `//div/button[@data-testid='token-select-asset']//span[.='${from}']` ) - .first() - await fromLocator.click({ timeout: 4000 }) + .first(); + await fromLocator.click({ timeout: 4000 }); // Select To Token - await toToken.click({ timeout: 4000 }) + await toToken.click({ timeout: 4000 }); // we expect that after 1 second token filter is displayed. - await this.page.waitForTimeout(1000) - await this.page.getByPlaceholder('Search').fill(to) + await this.page.waitForTimeout(1000); + await this.page.getByPlaceholder("Search").fill(to); const toLocator = this.page .locator( - `//div/button[@data-testid='token-select-asset']//span[.='${to}']`, + `//div/button[@data-testid='token-select-asset']//span[.='${to}']` ) - .first() - await toLocator.click() + .first(); + await toLocator.click(); // we expect that after 2 seconds exchange rate is populated. - await this.page.waitForTimeout(2000) - expect(await this.getExchangeRate()).toContain(from) - expect(await this.getExchangeRate()).toContain(to) + await this.page.waitForTimeout(2000); + expect(await this.getExchangeRate()).toContain(from); + expect(await this.getExchangeRate()).toContain(to); } async getExchangeRate() { - return await this.exchangeRate.innerText() + return await this.exchangeRate.innerText(); } async isTransactionSuccesful(delay = 7) { - console.log(`Wait for a transaction success for ${delay} seconds.`) + console.log(`Wait for a transaction success for ${delay} seconds.`); await expect(this.trxSuccessful).toBeVisible({ timeout: delay * 1000, visible: true, - }) + }); } async getTransactionUrl() { - const trxUrl = await this.trxLink.getAttribute('href') - console.log(`Trx url: ${trxUrl}`) - await this.page.reload() - return trxUrl + const trxUrl = await this.trxLink.getAttribute("href"); + console.log(`Trx url: ${trxUrl}`); + await this.page.reload(); + return trxUrl; } async isTransactionBroadcasted(delay = 5) { - console.log(`Wait for a transaction broadcasting for ${delay} seconds.`) - return await this.trxBroadcasting.isVisible({ timeout: delay * 1000 }) + console.log(`Wait for a transaction broadcasting for ${delay} seconds.`); + return await this.trxBroadcasting.isVisible({ timeout: delay * 1000 }); } async isInsufficientBalance() { const issufBalanceBtn = this.page.locator( - '//span[.="Insufficient balance"]', - ) - return await issufBalanceBtn.isVisible({ timeout: 2000 }) + '//span[.="Insufficient balance"]' + ); + return await issufBalanceBtn.isVisible({ timeout: 2000 }); } async isInsufficientBalanceForSwap() { const issufBalanceBtn = this.page.locator( - '//button[.="Insufficient balance"]', - ) - return await issufBalanceBtn.isVisible({ timeout: 2000 }) + '//button[.="Insufficient balance"]' + ); + return await issufBalanceBtn.isVisible({ timeout: 2000 }); } async isSufficientBalanceForTrade() { // Make sure to have sufficient balance for a trade expect( await this.isInsufficientBalance(), - 'Insufficient balance for the swap!', - ).toBeFalsy() + "Insufficient balance for the swap!" + ).toBeFalsy(); } async isError() { - const errorBtn = this.page.locator('//button[.="Error"]') - return await errorBtn.isVisible({ timeout: 2000 }) + const errorBtn = this.page.locator('//button[.="Error"]'); + return await errorBtn.isVisible({ timeout: 2000 }); } async showSwapInfo() { - const swapInfo = this.page.locator("//button//span[.='Show details']") - await swapInfo.click({ timeout: 2000 }) + const swapInfo = this.page.locator("//button//span[.='Show details']"); + await expect(swapInfo, "Show Swap Info button not visible!").toBeVisible({ + timeout: 4000, + }); + await swapInfo.click({ timeout: 2000 }); } async getPriceInpact() { const priceInpactSpan = this.page.locator( - '//span[.="Price Impact"]/..//span[@class="text-bullish-400"]', - ) - return await priceInpactSpan.textContent() + '//span[.="Price Impact"]/..//span[@class="text-bullish-400"]' + ); + return await priceInpactSpan.textContent(); } async takeScreenshot(name: string) { await this.page.screenshot({ path: `screenshot-trade-${name}.png`, fullPage: true, - }) + }); } async getSelectedSwapPair() { - const tokenLocator = '//div//button[@type]//img[@alt]/../h5' - const fromToken = this.page.locator(tokenLocator).nth(0) - const toToken = this.page.locator(tokenLocator).nth(1) - await expect(fromToken).toBeVisible({ timeout: 2000 }) - const fromTokenText = await fromToken.innerText() - const toTokenText = await toToken.innerText() - console.log(`Current pair: ${fromTokenText}/${toTokenText}`) - return `${fromTokenText}/${toTokenText}` + const tokenLocator = "//div//button[@type]//img[@alt]/../h5"; + const fromToken = this.page.locator(tokenLocator).nth(0); + const toToken = this.page.locator(tokenLocator).nth(1); + await expect(fromToken).toBeVisible({ timeout: 2000 }); + const fromTokenText = await fromToken.innerText(); + const toTokenText = await toToken.innerText(); + console.log(`Current pair: ${fromTokenText}/${toTokenText}`); + return `${fromTokenText}/${toTokenText}`; } async buyAndGetWalletMsg(context: BrowserContext, limit = false) { - await expect(this.buyBtn, 'Buy button is disabled!').toBeEnabled({ + await expect(this.buyBtn, "Buy button is disabled!").toBeEnabled({ timeout: 9000, - }) + }); // Handle Pop-up page -> - await this.buyBtn.click() - const pageApprove = context.waitForEvent('page') - await this.confirmSwapBtn.click() - await this.page.waitForTimeout(200) - const approvePage = await pageApprove - await approvePage.waitForLoadState() - const approveBtn = approvePage.getByRole('button', { - name: 'Approve', - }) - await expect(approveBtn).toBeEnabled() - let msgTextLocator = 'type: osmosis/poolmanager/' + await this.buyBtn.click(); + const pageApprove = context.waitForEvent("page"); + await this.confirmSwapBtn.click(); + await this.page.waitForTimeout(200); + const approvePage = await pageApprove; + await approvePage.waitForLoadState(); + const approveBtn = approvePage.getByRole("button", { + name: "Approve", + }); + await expect(approveBtn).toBeEnabled(); + let msgTextLocator = "type: osmosis/poolmanager/"; if (limit) { - msgTextLocator = 'Execute contract' + msgTextLocator = "Execute contract"; } const msgContentAmount = await approvePage .getByText(msgTextLocator) - .textContent() - console.log(`Wallet is approving this msg: \n${msgContentAmount}`) + .textContent(); + console.log(`Wallet is approving this msg: \n${msgContentAmount}`); // Approve trx - await approveBtn.click() + await approveBtn.click(); // wait for trx confirmation - await this.page.waitForTimeout(2000) + await this.page.waitForTimeout(2000); // Handle Pop-up page <- - return { msgContentAmount } + return { msgContentAmount }; } async sellAndGetWalletMsg(context: BrowserContext, limit = false) { // Make sure Sell button is enabled - await expect(this.sellBtn, 'Sell button is disabled!').toBeEnabled({ + await expect(this.sellBtn, "Sell button is disabled!").toBeEnabled({ timeout: 9000, - }) + }); // Handle Pop-up page -> - await this.sellBtn.click() - const pageApprove = context.waitForEvent('page') - await this.confirmSwapBtn.click() - await this.page.waitForTimeout(200) - const approvePage = await pageApprove - await approvePage.waitForLoadState() - const approveBtn = approvePage.getByRole('button', { - name: 'Approve', - }) - await expect(approveBtn).toBeEnabled() - let msgTextLocator = 'type: osmosis/poolmanager/' + await this.sellBtn.click(); + const pageApprove = context.waitForEvent("page"); + await this.confirmSwapBtn.click(); + await this.page.waitForTimeout(200); + const approvePage = await pageApprove; + await approvePage.waitForLoadState(); + const approveBtn = approvePage.getByRole("button", { + name: "Approve", + }); + await expect(approveBtn).toBeEnabled(); + let msgTextLocator = "type: osmosis/poolmanager/"; if (limit) { - msgTextLocator = 'Execute contract' + msgTextLocator = "Execute contract"; } const msgContentAmount = await approvePage .getByText(msgTextLocator) - .textContent() - console.log(`Wallet is approving this msg: \n${msgContentAmount}`) + .textContent(); + console.log(`Wallet is approving this msg: \n${msgContentAmount}`); // Approve trx - await approveBtn.click() + await approveBtn.click(); // wait for trx confirmation - await this.page.waitForTimeout(2000) + await this.page.waitForTimeout(2000); // Handle Pop-up page <- - return { msgContentAmount } + return { msgContentAmount }; + } + + async sellAndApprove(context: BrowserContext) { + // Make sure Sell button is enabled + await expect(this.sellBtn, "Sell button is disabled!").toBeEnabled({ + timeout: 9000, + }); + await this.sellBtn.click(); + await this.confirmSwapBtn.click(); + await this.justApproveIfNeeded(context); + await this.page.waitForTimeout(1000); + } + + async buyAndApprove(context: BrowserContext, limit = false) { + await expect(this.buyBtn, "Buy button is disabled!").toBeEnabled({ + timeout: 9000, + }); + await this.buyBtn.click(); + await this.confirmSwapBtn.click(); + await this.justApproveIfNeeded(context); + await this.page.waitForTimeout(1000); + } + + async swapAndApprove(context: BrowserContext) { + // Make sure to have sufficient balance and swap button is enabled + expect( + await this.isInsufficientBalanceForSwap(), + "Insufficient balance for the swap!" + ).toBeFalsy(); + console.log("Swap and Sign now.."); + await expect(this.swapBtn, "Swap button is disabled!").toBeEnabled({ + timeout: 7000, + }); + await this.swapBtn.click({ timeout: 4000 }); + await this.confirmSwapBtn.click({ timeout: 5000 }); + await this.justApproveIfNeeded(context); } } diff --git a/packages/e2e/tests/monitoring.limit.wallet.spec.ts b/packages/e2e/tests/monitoring.limit.wallet.spec.ts index 09597c65f6..9de6eaf2ab 100644 --- a/packages/e2e/tests/monitoring.limit.wallet.spec.ts +++ b/packages/e2e/tests/monitoring.limit.wallet.spec.ts @@ -1,97 +1,83 @@ -import { type BrowserContext, chromium, expect, test } from '@playwright/test' -import { TestConfig } from '../test-config' -import { UnzipExtension } from '../unzip-extension' +import { type BrowserContext, chromium, expect, test } from "@playwright/test"; +import { TestConfig } from "../test-config"; +import { UnzipExtension } from "../unzip-extension"; -import { WalletPage } from '../pages/keplr-page' -import { TradePage } from '../pages/trade-page' +import { WalletPage } from "../pages/keplr-page"; +import { TradePage } from "../pages/trade-page"; -test.describe('Test Filled Limit Order feature', () => { - let context: BrowserContext - const privateKey = process.env.PRIVATE_KEY ?? 'private_key' - let tradePage: TradePage +test.describe("Test Filled Limit Order feature", () => { + let context: BrowserContext; + const privateKey = process.env.PRIVATE_KEY ?? "private_key"; + let tradePage: TradePage; test.beforeAll(async () => { - const pathToExtension = new UnzipExtension().getPathToExtension() - console.log('\nSetup Wallet Extension before tests.') + const pathToExtension = new UnzipExtension().getPathToExtension(); + console.log("\nSetup Wallet Extension before tests."); // Launch Chrome with a Keplr wallet extension context = await chromium.launchPersistentContext( - '', - new TestConfig().getBrowserExtensionConfig(false, pathToExtension), - ) + "", + new TestConfig().getBrowserExtensionConfig(false, pathToExtension) + ); // Get all new pages (including Extension) in the context and wait - const emptyPage = context.pages()[0] - await emptyPage.waitForTimeout(2000) - const page = context.pages()[1] - const walletPage = new WalletPage(page) + const emptyPage = context.pages()[0]; + await emptyPage.waitForTimeout(2000); + const page = context.pages()[1]; + const walletPage = new WalletPage(page); // Import existing Wallet (could be aggregated in one function). - await walletPage.importWalletWithPrivateKey(privateKey) - await walletPage.setWalletNameAndPassword('Monitoring E2E Tests') - await walletPage.selectChainsAndSave() - await walletPage.finish() + await walletPage.importWalletWithPrivateKey(privateKey); + await walletPage.setWalletNameAndPassword("Monitoring E2E Tests"); + await walletPage.selectChainsAndSave(); + await walletPage.finish(); // Switch to Application - tradePage = new TradePage(context.pages()[0]) - await tradePage.goto() - await tradePage.connectWallet() - expect(await tradePage.isError(), 'Swap is not available!').toBeFalsy() - }) + tradePage = new TradePage(context.pages()[0]); + await tradePage.goto(); + await tradePage.connectWallet(); + expect(await tradePage.isError(), "Swap is not available!").toBeFalsy(); + }); test.afterAll(async () => { - await context.close() - }) + await context.close(); + }); // biome-ignore lint/correctness/noEmptyPattern: test.afterEach(async ({}, testInfo) => { - console.log(`Test [${testInfo.title}] status: ${testInfo.status}`) - if (testInfo.status === 'failed') { - const name = testInfo.title - process.env.GITHUB_STEP_SUMMARY = `Test ${name} failed.` + console.log(`Test [${testInfo.title}] status: ${testInfo.status}`); + if (testInfo.status === "failed") { + const name = testInfo.title; + process.env.GITHUB_STEP_SUMMARY = `Test ${name} failed.`; } - }) + }); - test('User should be able to limit sell OSMO', async () => { - await tradePage.goto() - await tradePage.openSellTab() - await tradePage.openLimit() - await tradePage.selectAsset('OSMO') - await tradePage.enterAmount('1.08') - await tradePage.setLimitPriceChange('Market') - const { msgContentAmount } = await tradePage.sellAndGetWalletMsg( - context, - true, - ) - expect(msgContentAmount, 'No msg from the wallet!').toBeTruthy() - // now this is converted from USDC - expect(msgContentAmount).toContain('place_limit') - expect(msgContentAmount).toContain('"order_direction": "ask"') - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) + test("User should be able to limit sell OSMO", async () => { + await tradePage.goto(); + await tradePage.openSellTab(); + await tradePage.openLimit(); + await tradePage.selectAsset("OSMO"); + await tradePage.enterAmount("1.08"); + await tradePage.setLimitPriceChange("Market"); + await tradePage.sellAndApprove(context); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); - test('User should be able to limit buy OSMO', async () => { - const PRICE_INCREASE_FACTOR = 1.07 // 7% increase for limit price - const ORDER_HISTORY_TIMEOUT = 30 // Seconds to wait for order history - await tradePage.goto() - await tradePage.openBuyTab() - await tradePage.openLimit() - await tradePage.selectAsset('OSMO') - await tradePage.enterAmount('1.04') - await tradePage.setLimitPriceChange('Market') - const limitPrice = Number(await tradePage.getLimitPrice()) - const highLimitPrice = (limitPrice * PRICE_INCREASE_FACTOR).toFixed(4) - await tradePage.setLimitPrice(String(highLimitPrice)) - const { msgContentAmount } = await tradePage.buyAndGetWalletMsg( - context, - true, - ) - expect(msgContentAmount, 'No msg from the wallet!').toBeTruthy() - expect(msgContentAmount).toContain('"quantity": "1040000"') - expect(msgContentAmount).toContain('place_limit') - expect(msgContentAmount).toContain('"order_direction": "bid"') - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - await tradePage.gotoOrdersHistory(ORDER_HISTORY_TIMEOUT) + test("User should be able to limit buy OSMO", async () => { + const PRICE_INCREASE_FACTOR = 1.07; // 7% increase for limit price + const ORDER_HISTORY_TIMEOUT = 30; // Seconds to wait for order history + await tradePage.goto(); + await tradePage.openBuyTab(); + await tradePage.openLimit(); + await tradePage.selectAsset("OSMO"); + await tradePage.enterAmount("1.04"); + await tradePage.setLimitPriceChange("Market"); + const limitPrice = Number(await tradePage.getLimitPrice()); + const highLimitPrice = (limitPrice * PRICE_INCREASE_FACTOR).toFixed(4); + await tradePage.setLimitPrice(String(highLimitPrice)); + await tradePage.buyAndApprove(context); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + //await tradePage.gotoOrdersHistory(ORDER_HISTORY_TIMEOUT); //const p = context.pages()[0] //const trxPage = new TransactionsPage(p) //await trxPage.isFilledByLimitPrice(highLimitPrice) - }) -}) + }); +}); diff --git a/packages/e2e/tests/monitoring.market.wallet.spec.ts b/packages/e2e/tests/monitoring.market.wallet.spec.ts index 130a9f6543..d584ba4755 100644 --- a/packages/e2e/tests/monitoring.market.wallet.spec.ts +++ b/packages/e2e/tests/monitoring.market.wallet.spec.ts @@ -60,9 +60,7 @@ test.describe("Test Market Buy/Sell Order feature", () => { await tradePage.enterAmount("1.55"); await tradePage.isSufficientBalanceForTrade(); await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.buyAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain("type: osmosis/poolmanager/"); + await tradePage.buyAndApprove(context); await tradePage.isTransactionSuccesful(TRX_SUCCESS_TIMEOUT); await tradePage.getTransactionUrl(); }); @@ -76,9 +74,7 @@ test.describe("Test Market Buy/Sell Order feature", () => { await tradePage.enterAmount("1.54"); await tradePage.isSufficientBalanceForTrade(); await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.sellAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain("type: osmosis/poolmanager/"); + await tradePage.sellAndApprove(context); await tradePage.isTransactionSuccesful(TRX_SUCCESS_TIMEOUT); await tradePage.getTransactionUrl(); }); @@ -90,9 +86,7 @@ test.describe("Test Market Buy/Sell Order feature", () => { await tradePage.enterAmount("1.54"); await tradePage.isSufficientBalanceForTrade(); await tradePage.showSwapInfo(); - const { msgContentAmount } = await tradePage.sellAndGetWalletMsg(context); - expect(msgContentAmount).toBeTruthy(); - expect(msgContentAmount).toContain("type: osmosis/poolmanager/"); + await tradePage.sellAndApprove(context); await tradePage.isTransactionSuccesful(TRX_SUCCESS_TIMEOUT); await tradePage.getTransactionUrl(); }); diff --git a/packages/e2e/tests/monitoring.swap.wallet.spec.ts b/packages/e2e/tests/monitoring.swap.wallet.spec.ts index 5127f85525..2c47d52a3b 100644 --- a/packages/e2e/tests/monitoring.swap.wallet.spec.ts +++ b/packages/e2e/tests/monitoring.swap.wallet.spec.ts @@ -1,101 +1,61 @@ -import { type BrowserContext, chromium, expect, test } from '@playwright/test' +import { type BrowserContext, chromium, expect, test } from "@playwright/test"; -import { WalletPage } from '../pages/keplr-page' -import { TradePage } from '../pages/trade-page' -import { TestConfig } from '../test-config' -import { UnzipExtension } from '../unzip-extension' +import { WalletPage } from "../pages/keplr-page"; +import { TradePage } from "../pages/trade-page"; +import { TestConfig } from "../test-config"; +import { UnzipExtension } from "../unzip-extension"; -test.describe('Test Swap Stables feature', () => { - let context: BrowserContext - const privateKey = process.env.PRIVATE_KEY ?? 'private_key' - let tradePage: TradePage - const USDC = - 'ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4' - const USDCa = - 'ibc/D189335C6E4A68B513C10AB227BF1C1D38C746766278BA3EEB4FB14124F1D858' - const allUSDT = - 'factory/osmo1em6xs47hd82806f5cxgyufguxrrc7l0aqx7nzzptjuqgswczk8csavdxek/alloyed/allUSDT' - const swapAmount = '0.55' +test.describe("Test Swap Stables feature", () => { + let context: BrowserContext; + const privateKey = process.env.PRIVATE_KEY ?? "private_key"; + let tradePage: TradePage; + const swapAmount = "0.55"; test.beforeAll(async () => { - const pathToExtension = new UnzipExtension().getPathToExtension() - console.log('\nSetup Wallet Extension before tests.') + const pathToExtension = new UnzipExtension().getPathToExtension(); + console.log("\nSetup Wallet Extension before tests."); // Launch Chrome with a Keplr wallet extension context = await chromium.launchPersistentContext( - '', - new TestConfig().getBrowserExtensionConfig(false, pathToExtension), - ) + "", + new TestConfig().getBrowserExtensionConfig(false, pathToExtension) + ); // Get all new pages (including Extension) in the context and wait - const emptyPage = context.pages()[0] - await emptyPage.waitForTimeout(2000) - let page = context.pages()[1] - const walletPage = new WalletPage(page) + const emptyPage = context.pages()[0]; + await emptyPage.waitForTimeout(2000); + let page = context.pages()[1]; + const walletPage = new WalletPage(page); // Import existing Wallet (could be aggregated in one function). - await walletPage.importWalletWithPrivateKey(privateKey) - await walletPage.setWalletNameAndPassword('Test Stables') - await walletPage.selectChainsAndSave() - await walletPage.finish() - page = context.pages()[0] - tradePage = new TradePage(page) - - await tradePage.goto() - await tradePage.connectWallet() - expect(await tradePage.isError(), 'Swap is not available!').toBeFalsy() - }) + await walletPage.importWalletWithPrivateKey(privateKey); + await walletPage.setWalletNameAndPassword("Test Stables"); + await walletPage.selectChainsAndSave(); + await walletPage.finish(); + page = context.pages()[0]; + tradePage = new TradePage(page); + + await tradePage.goto(); + await tradePage.connectWallet(); + expect(await tradePage.isError(), "Swap is not available!").toBeFalsy(); + }); test.afterAll(async () => { - await context.close() - }) - - test('User should be able to swap USDC to USDC.eth.axl', async () => { - await tradePage.goto() - await tradePage.selectPair('USDC', 'USDC.eth.axl') - await tradePage.enterAmount(swapAmount) - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${USDC}`) - expect(msgContentAmount).toContain(`token_out_denom: ${USDCa}`) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap USDC.eth.axl to USDC', async () => { - await tradePage.goto() - await tradePage.selectPair('USDC.eth.axl', 'USDC') - await tradePage.enterAmount(swapAmount) - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${USDCa}`) - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap USDT to USDC', async () => { - await tradePage.goto() - await tradePage.selectPair('USDT', 'USDC') - await tradePage.enterAmount(swapAmount) - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(USDC) - expect(msgContentAmount).toContain(allUSDT) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap USDC to USDT', async () => { - await tradePage.goto() - await tradePage.selectPair('USDC', 'USDT') - await tradePage.enterAmount(swapAmount) - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${USDC}`) - expect(msgContentAmount).toContain(allUSDT) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) -}) + await context.close(); + }); + + // biome-ignore lint/complexity/noForEach: + [ + { from: "USDC", to: "USDC.eth.axl" }, + { from: "USDC.eth.axl", to: "USDC" }, + { from: "USDC", to: "USDT" }, + { from: "USDT", to: "USDC" }, + ].forEach(({ from, to }) => { + test(`User should be able to swap ${from} to ${to}`, async () => { + await tradePage.goto(); + await tradePage.selectPair(from, to); + await tradePage.enterAmount(swapAmount); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + }); +}); diff --git a/packages/e2e/tests/select.spec.ts b/packages/e2e/tests/select.spec.ts index e1c55aa042..f78f4bc23f 100644 --- a/packages/e2e/tests/select.spec.ts +++ b/packages/e2e/tests/select.spec.ts @@ -4,105 +4,104 @@ import { type Page, chromium, test, -} from '@playwright/test' +} from "@playwright/test"; -import { TradePage } from '../pages/trade-page' -import { TestConfig } from '../test-config' +import { TradePage } from "../pages/trade-page"; +import { TestConfig } from "../test-config"; // Pairs are selected from top 10 -test.describe('Test Select Swap Pair feature', () => { - let context: BrowserContext - let swapPage: TradePage - let page: Page +test.describe("Test Select Swap Pair feature", () => { + let context: BrowserContext; + let swapPage: TradePage; + let page: Page; test.beforeAll(async () => { context = await chromium.launchPersistentContext( - '', - new TestConfig().getBrowserConfig(true), - ) - page = context.pages()[0] - swapPage = new TradePage(page) - await swapPage.goto() - }) + "", + new TestConfig().getBrowserConfig(true) + ); + page = context.pages()[0]; + swapPage = new TradePage(page); + await swapPage.goto(); + }); test.afterAll(async () => { - await context.close() - }) - - // Price Impact-54.768% -> no liquidity - test('User should be able to select nBTC/USDC', async () => { - await swapPage.goto() - await swapPage.selectPair('nBTC', 'USDC') - await swapPage.enterAmount('0.01') - await swapPage.showSwapInfo() - }) - - test('User should be able to select WBTC/USDC', async () => { - await swapPage.goto() - await swapPage.selectPair('WBTC', 'USDC') - await swapPage.enterAmount('0.1') - await swapPage.showSwapInfo() - }) - - test('User should be able to select OSMO/USDC', async () => { - await swapPage.goto() - await swapPage.selectPair('OSMO', 'USDC') - await swapPage.enterAmount('1') - await swapPage.showSwapInfo() - }) - - test('User should be able to select INJ/USDC', async () => { - await swapPage.goto() - await swapPage.selectPair('INJ', 'USDC') - await swapPage.enterAmount('10') - await swapPage.showSwapInfo() - }) - - test('User should be able to select TIA/USDC', async () => { - await swapPage.goto() - await swapPage.selectPair('TIA', 'USDC') - await swapPage.enterAmount('100') - await swapPage.showSwapInfo() - }) - - test('User should be able to select ATOM/USDC', async () => { - await swapPage.selectPair('ATOM', 'USDC') - await swapPage.enterAmount('100') - }) - - test('User should be able to select USDT/USDC', async () => { - await swapPage.selectPair('USDT', 'USDC') - await swapPage.enterAmount('10000') - }) - - test('User should be able to select TIA/OSMO', async () => { - await swapPage.selectPair('TIA', 'OSMO') - await swapPage.enterAmount('100') - }) - - test('User should be able to select AKT/OSMO', async () => { - await swapPage.selectPair('AKT', 'OSMO') - await swapPage.enterAmount('100') - }) - - test('User should be able to select PICA/OSMO', async () => { - await swapPage.selectPair('PICA', 'OSMO') - await swapPage.enterAmount('100') - }) - - test('User should be able to select USDT/OSMO', async () => { - await swapPage.selectPair('USDT', 'OSMO') - await swapPage.enterAmount('100') - }) - - test('User should be able to select TIA/BOOT', async () => { + await context.close(); + }); + + test("User should be able to select BTC/USDC", async () => { + await swapPage.goto(); + await swapPage.selectPair("nBTC", "USDC"); + await swapPage.enterAmount("0.01"); + await swapPage.showSwapInfo(); + }); + + test("User should be able to select WBTC/USDC", async () => { + await swapPage.goto(); + await swapPage.selectPair("WBTC", "USDC"); + await swapPage.enterAmount("0.1"); + await swapPage.showSwapInfo(); + }); + + test("User should be able to select OSMO/USDC", async () => { + await swapPage.goto(); + await swapPage.selectPair("OSMO", "USDC"); + await swapPage.enterAmount("1"); + await swapPage.showSwapInfo(); + }); + + test("User should be able to select INJ/USDC", async () => { + await swapPage.goto(); + await swapPage.selectPair("INJ", "USDC"); + await swapPage.enterAmount("10"); + await swapPage.showSwapInfo(); + }); + + test("User should be able to select TIA/USDC", async () => { + await swapPage.goto(); + await swapPage.selectPair("TIA", "USDC"); + await swapPage.enterAmount("100"); + await swapPage.showSwapInfo(); + }); + + test("User should be able to select ATOM/USDC", async () => { + await swapPage.selectPair("ATOM", "USDC"); + await swapPage.enterAmount("100"); + }); + + test("User should be able to select USDT/USDC", async () => { + await swapPage.selectPair("USDT", "USDC"); + await swapPage.enterAmount("10000"); + }); + + test("User should be able to select TIA/OSMO", async () => { + await swapPage.selectPair("TIA", "OSMO"); + await swapPage.enterAmount("100"); + }); + + test("User should be able to select AKT/OSMO", async () => { + await swapPage.selectPair("AKT", "OSMO"); + await swapPage.enterAmount("100"); + }); + + test("User should be able to select PICA/OSMO", async () => { + await swapPage.selectPair("PICA", "OSMO"); + await swapPage.enterAmount("100"); + }); + + test("User should be able to select USDT/OSMO", async () => { + await swapPage.selectPair("USDT", "OSMO"); + await swapPage.enterAmount("100"); + }); + + test("User should be able to select TIA/BOOT", async () => { // Just to verify some odd pair - await swapPage.selectPair('TIA', 'BOOT') - await swapPage.enterAmount('100') - }) - - test('User should be able to select stATOM/USDC', async () => { - await swapPage.selectPair('stATOM', 'USDC') - await swapPage.enterAmount('100') - }) -}) + await swapPage.selectPair("TIA", "BOOT"); + await swapPage.enterAmount("100"); + }); + + test("User should be able to select stATOM/USDC", async () => { + await swapPage.selectPair("stATOM", "USDC"); + await swapPage.enterAmount("100"); + }); +}); diff --git a/packages/e2e/tests/swap.osmo.wallet.spec.ts b/packages/e2e/tests/swap.osmo.wallet.spec.ts new file mode 100644 index 0000000000..06302eaca7 --- /dev/null +++ b/packages/e2e/tests/swap.osmo.wallet.spec.ts @@ -0,0 +1,83 @@ +import { type BrowserContext, chromium, expect, test } from "@playwright/test"; + +import { TestConfig } from "../test-config"; +import { UnzipExtension } from "../unzip-extension"; + +import { WalletPage } from "../pages/keplr-page"; +import { TradePage } from "../pages/trade-page"; + +test.describe("Test Swap to/from OSMO feature", () => { + let context: BrowserContext; + const walletId = + process.env.WALLET_ID ?? "osmo1qyc8u7cn0zjxcu9dvrjz5zwfnn0ck92v62ak9l"; + const privateKey = process.env.PRIVATE_KEY ?? "private_key"; + let tradePage: TradePage; + const ATOM = + "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2"; + + test.beforeAll(async () => { + const pathToExtension = new UnzipExtension().getPathToExtension(); + console.log("\nSetup Wallet Extension before tests."); + // Launch Chrome with a Keplr wallet extension + context = await chromium.launchPersistentContext( + "", + new TestConfig().getBrowserExtensionConfig(false, pathToExtension) + ); + // Get all new pages (including Extension) in the context and wait + const emptyPage = context.pages()[0]; + await emptyPage.waitForTimeout(2000); + const page = context.pages()[1]; + const walletPage = new WalletPage(page); + // Import existing Wallet (could be aggregated in one function). + await walletPage.importWalletWithPrivateKey(privateKey); + await walletPage.setWalletNameAndPassword("Test Swaps"); + await walletPage.selectChainsAndSave(); + await walletPage.finish(); + // Switch to Application + tradePage = new TradePage(context.pages()[0]); + await tradePage.goto(); + await tradePage.connectWallet(); + expect(await tradePage.isError(), "Swap is not available!").toBeFalsy(); + }); + + test.afterAll(async () => { + await context.close(); + }); + + test.skip("User should be able to swap OSMO to WBTC", async () => { + await tradePage.goto(); + await tradePage.selectPair("OSMO", "WBTC"); + await tradePage.enterAmount("0.9"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain("denom: uosmo"); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + + test("User should be able to swap OSMO to ATOM", async () => { + await tradePage.goto(); + await tradePage.selectPair("OSMO", "ATOM"); + await tradePage.enterAmount("0.2"); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`token_out_denom: ${ATOM}`); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain("denom: uosmo"); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + + test("User should be able to swap ATOM to OSMO", async () => { + await tradePage.goto(); + await tradePage.selectPair("ATOM", "OSMO"); + await tradePage.enterAmount("0.01"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`denom: ${ATOM}`); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain("token_out_denom: uosmo"); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); +}); diff --git a/packages/e2e/tests/swap.usdc.wallet.spec.ts b/packages/e2e/tests/swap.usdc.wallet.spec.ts new file mode 100644 index 0000000000..b7e157a7e7 --- /dev/null +++ b/packages/e2e/tests/swap.usdc.wallet.spec.ts @@ -0,0 +1,184 @@ +import { type BrowserContext, chromium, expect, test } from "@playwright/test"; + +import { TestConfig } from "../test-config"; +import { UnzipExtension } from "../unzip-extension"; + +import { WalletPage } from "../pages/keplr-page"; +import { TradePage } from "../pages/trade-page"; + +test.describe("Test Swap to/from USDC feature", () => { + let context: BrowserContext; + const walletId = + process.env.WALLET_ID ?? "osmo1qyc8u7cn0zjxcu9dvrjz5zwfnn0ck92v62ak9l"; + const privateKey = process.env.PRIVATE_KEY ?? "private_key"; + let tradePage: TradePage; + const USDC = + "ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4"; + const ATOM = + "ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2"; + const TIA = + "ibc/D79E7D83AB399BFFF93433E54FAA480C191248FC556924A2A8351AE2638B3877"; + const INJ = + "ibc/64BA6E31FE887D66C6F8F31C7B1A80C7CA179239677B4088BB55F5EA07DBE273"; + const AKT = + "ibc/1480B8FD20AD5FCAE81EA87584D269547DD4D436843C1D20F15E00EB64743EF4"; + + test.beforeAll(async () => { + const pathToExtension = new UnzipExtension().getPathToExtension(); + console.log("\nSetup Wallet Extension before tests."); + // Launch Chrome with a Keplr wallet extension + context = await chromium.launchPersistentContext( + "", + new TestConfig().getBrowserExtensionConfig(false, pathToExtension) + ); + // Get all new pages (including Extension) in the context and wait + const emptyPage = context.pages()[0]; + await emptyPage.waitForTimeout(2000); + const page = context.pages()[1]; + const walletPage = new WalletPage(page); + // Import existing Wallet (could be aggregated in one function). + await walletPage.importWalletWithPrivateKey(privateKey); + await walletPage.setWalletNameAndPassword("Test Swaps"); + await walletPage.selectChainsAndSave(); + await walletPage.finish(); + // Switch to Application + tradePage = new TradePage(context.pages()[0]); + await tradePage.goto(); + await tradePage.connectWallet(); + expect(await tradePage.isError(), "Swap is not available!").toBeFalsy(); + }); + + test.afterAll(async () => { + await context.close(); + }); + + test("User should be able to swap OSMO to USDC", async () => { + await tradePage.goto(); + await tradePage.selectPair("OSMO", "USDC"); + await tradePage.enterAmount("0.2"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`token_out_denom: ${USDC}`); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain("denom: uosmo"); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + + test("User should be able to swap USDC to OSMO", async () => { + await tradePage.goto(); + await tradePage.selectPair("USDC", "OSMO"); + await tradePage.enterAmount("0.1"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain("token_out_denom: uosmo"); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain(`denom: ${USDC}`); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + + test("User should be able to swap ATOM to USDC", async () => { + await tradePage.goto(); + await tradePage.selectPair("ATOM", "USDC"); + await tradePage.enterAmount("0.015"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`denom: ${ATOM}`); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain(`token_out_denom: ${USDC}`); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + + test("User should be able to swap USDC to ATOM", async () => { + await tradePage.goto(); + await tradePage.selectPair("USDC", "ATOM"); + await tradePage.enterAmount("0.1"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`denom: ${USDC}`); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain(`token_out_denom: ${ATOM}`); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + + test("User should be able to swap USDC to TIA", async () => { + await tradePage.goto(); + await tradePage.selectPair("USDC", "TIA"); + await tradePage.enterAmount("0.1"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`denom: ${USDC}`); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain(`token_out_denom: ${TIA}`); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + + test("User should be able to swap TIA to USDC", async () => { + await tradePage.goto(); + await tradePage.selectPair("TIA", "USDC"); + await tradePage.enterAmount("0.02"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`denom: ${TIA}`); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain(`token_out_denom: ${USDC}`); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + + test("User should be able to swap USDC to INJ", async () => { + await tradePage.goto(); + await tradePage.selectPair("USDC", "INJ"); + await tradePage.enterAmount("0.2"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`denom: ${USDC}`); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain(`token_out_denom: ${INJ}`); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + + test("User should be able to swap INJ to USDC", async () => { + await tradePage.goto(); + await tradePage.selectPair("INJ", "USDC"); + await tradePage.enterAmount("0.01"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`denom: ${INJ}`); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain(`token_out_denom: ${USDC}`); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + + test("User should be able to swap USDC to AKT", async () => { + await tradePage.goto(); + await tradePage.selectPair("USDC", "AKT"); + await tradePage.enterAmount("0.1"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`denom: ${USDC}`); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain(`token_out_denom: ${AKT}`); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); + + test("User should be able to swap AKT to USDC", async () => { + await tradePage.goto(); + await tradePage.selectPair("AKT", "USDC"); + await tradePage.enterAmount("0.025"); + await tradePage.showSwapInfo(); + await tradePage.swapAndApprove(context); + //expect(msgContent).toContain(`denom: ${AKT}`); + //expect(msgContent).toContain(`sender: ${walletId}`); + //expect(msgContent).toContain(`token_out_denom: ${USDC}`); + await tradePage.isTransactionSuccesful(); + await tradePage.getTransactionUrl(); + }); +}); diff --git a/packages/e2e/tests/swap.wallet.spec.ts b/packages/e2e/tests/swap.wallet.spec.ts deleted file mode 100644 index 394b6fbe4c..0000000000 --- a/packages/e2e/tests/swap.wallet.spec.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { type BrowserContext, chromium, expect, test } from '@playwright/test' - -import { TestConfig } from '../test-config' -import { UnzipExtension } from '../unzip-extension' - -import { WalletPage } from '../pages/keplr-page' -import { TradePage } from '../pages/trade-page' - -test.describe('Test Swap feature', () => { - let context: BrowserContext - const walletId = - process.env.WALLET_ID ?? 'osmo1qyc8u7cn0zjxcu9dvrjz5zwfnn0ck92v62ak9l' - const privateKey = process.env.PRIVATE_KEY ?? 'private_key' - let tradePage: TradePage - const USDC = - 'ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4' - const ATOM = - 'ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2' - const TIA = - 'ibc/D79E7D83AB399BFFF93433E54FAA480C191248FC556924A2A8351AE2638B3877' - const INJ = - 'ibc/64BA6E31FE887D66C6F8F31C7B1A80C7CA179239677B4088BB55F5EA07DBE273' - const AKT = - 'ibc/1480B8FD20AD5FCAE81EA87584D269547DD4D436843C1D20F15E00EB64743EF4' - - test.beforeAll(async () => { - const pathToExtension = new UnzipExtension().getPathToExtension() - console.log('\nSetup Wallet Extension before tests.') - // Launch Chrome with a Keplr wallet extension - context = await chromium.launchPersistentContext( - '', - new TestConfig().getBrowserExtensionConfig(false, pathToExtension), - ) - // Get all new pages (including Extension) in the context and wait - const emptyPage = context.pages()[0] - await emptyPage.waitForTimeout(2000) - const page = context.pages()[1] - const walletPage = new WalletPage(page) - // Import existing Wallet (could be aggregated in one function). - await walletPage.importWalletWithPrivateKey(privateKey) - await walletPage.setWalletNameAndPassword('Test Swaps') - await walletPage.selectChainsAndSave() - await walletPage.finish() - // Switch to Application - tradePage = new TradePage(context.pages()[0]) - await tradePage.goto() - await tradePage.connectWallet() - expect(await tradePage.isError(), 'Swap is not available!').toBeFalsy() - }) - - test.afterAll(async () => { - await context.close() - }) - - test('User should be able to swap OSMO to ATOM', async () => { - await tradePage.goto() - await tradePage.selectPair('OSMO', 'ATOM') - await tradePage.enterAmount('0.2') - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`token_out_denom: ${ATOM}`) - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain('denom: uosmo') - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap ATOM to OSMO', async () => { - await tradePage.goto() - await tradePage.selectPair('ATOM', 'OSMO') - await tradePage.enterAmount('0.01') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${ATOM}`) - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain('token_out_denom: uosmo') - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap OSMO to USDC', async () => { - await tradePage.goto() - await tradePage.selectPair('OSMO', 'USDC') - await tradePage.enterAmount('0.2') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain('denom: uosmo') - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap OSMO to WBTC', async () => { - await tradePage.goto() - await tradePage.selectPair('OSMO', 'WBTC') - await tradePage.enterAmount('0.9') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain('denom: uosmo') - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap USDC to OSMO', async () => { - await tradePage.goto() - await tradePage.selectPair('USDC', 'OSMO') - await tradePage.enterAmount('0.1') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain('token_out_denom: uosmo') - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain(`denom: ${USDC}`) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap ATOM to USDC', async () => { - await tradePage.goto() - await tradePage.selectPair('ATOM', 'USDC') - await tradePage.enterAmount('0.015') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${ATOM}`) - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap USDC to ATOM', async () => { - await tradePage.goto() - await tradePage.selectPair('USDC', 'ATOM') - await tradePage.enterAmount('0.1') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${USDC}`) - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain(`token_out_denom: ${ATOM}`) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap USDC to TIA', async () => { - await tradePage.goto() - await tradePage.selectPair('USDC', 'TIA') - await tradePage.enterAmount('0.1') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${USDC}`) - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain(`token_out_denom: ${TIA}`) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap TIA to USDC', async () => { - await tradePage.goto() - await tradePage.selectPair('TIA', 'USDC') - await tradePage.enterAmount('0.02') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${TIA}`) - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap USDC to INJ', async () => { - await tradePage.goto() - await tradePage.selectPair('USDC', 'INJ') - await tradePage.enterAmount('0.2') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${USDC}`) - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain(`token_out_denom: ${INJ}`) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap INJ to USDC', async () => { - await tradePage.goto() - await tradePage.selectPair('INJ', 'USDC') - await tradePage.enterAmount('0.01') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${INJ}`) - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap USDC to AKT', async () => { - await tradePage.goto() - await tradePage.selectPair('USDC', 'AKT') - await tradePage.enterAmount('0.1') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${USDC}`) - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain(`token_out_denom: ${AKT}`) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) - - test('User should be able to swap AKT to USDC', async () => { - await tradePage.goto() - await tradePage.selectPair('AKT', 'USDC') - await tradePage.enterAmount('0.025') - await tradePage.showSwapInfo() - const { msgContentAmount } = await tradePage.swapAndGetWalletMsg(context) - expect(msgContentAmount).toBeTruthy() - expect(msgContentAmount).toContain(`denom: ${AKT}`) - expect(msgContentAmount).toContain(`sender: ${walletId}`) - expect(msgContentAmount).toContain(`token_out_denom: ${USDC}`) - await tradePage.isTransactionSuccesful() - await tradePage.getTransactionUrl() - }) -}) diff --git a/packages/server/src/queries/complex/pools/env.ts b/packages/server/src/queries/complex/pools/env.ts index 47cfc68b4c..2702095934 100644 --- a/packages/server/src/queries/complex/pools/env.ts +++ b/packages/server/src/queries/complex/pools/env.ts @@ -1,7 +1,9 @@ import { IS_TESTNET } from "../../../env"; /** Cosmwasm Code Ids confirmed to be transmuter pools in current env. */ -const TransmuterPoolCodeIds = IS_TESTNET ? ["3084"] : ["148"]; +const TransmuterPoolCodeIds = IS_TESTNET + ? ["3084"] + : ["148", "814", "867", "996"]; const AstroportPclPoolCodeIds = IS_TESTNET ? ["8611"] : ["842"]; const WhitewhalePoolCodeIds = IS_TESTNET ? ["?"] : ["503", "641"]; diff --git a/packages/server/src/queries/complex/transactions/transactions.ts b/packages/server/src/queries/complex/transactions/transactions.ts index 66c0062956..da6a16853b 100644 --- a/packages/server/src/queries/complex/transactions/transactions.ts +++ b/packages/server/src/queries/complex/transactions/transactions.ts @@ -141,6 +141,12 @@ export async function getTransactions({ address, page, pageSize, + messageTypes: [ + "/osmosis.poolmanager.v1beta1.MsgSwapExactAmountIn", + "/osmosis.poolmanager.v1beta1.MsgSplitRouteSwapExactAmountIn", + "/osmosis.poolmanager.v1beta1.MsgSwapExactAmountOut", + "/osmosis.poolmanager.v1beta1.MsgSplitRouteSwapExactAmountOut", + ], }); // if the length of the data is equal to the page size, there is a next page diff --git a/packages/server/src/queries/data-services/transactions.ts b/packages/server/src/queries/data-services/transactions.ts index b104858b2d..2732917046 100644 --- a/packages/server/src/queries/data-services/transactions.ts +++ b/packages/server/src/queries/data-services/transactions.ts @@ -83,15 +83,20 @@ export async function queryTransactions({ address, page, pageSize, + messageTypes, }: { address: string; page: string; pageSize: string; + messageTypes: string[]; }): Promise { const url = new URL(`/v2/txs/${address}`, HISTORICAL_DATA_URL); url.searchParams.append("page", page); url.searchParams.append("pageSize", pageSize); + if (messageTypes.length > 0) { + url.searchParams.append("messageTypes", messageTypes.join(",")); + } const headers = { Authorization: `Bearer ${process.env.NUMIA_API_KEY}`, diff --git a/packages/web/README.md b/packages/web/README.md index 4e9d18d9c1..c6f67ae29a 100644 --- a/packages/web/README.md +++ b/packages/web/README.md @@ -102,28 +102,3 @@ JavaScript; ``` It returns `unknown` types, so you may need to type cast to resolve TS errors. - -## E2E Tests - -### Run E2E Tests - -To install Playwright, please execute `npx playwright install` from the /web folder. - -To run Select pair tests, please execute `npx playwright test -g "Test Select Swap Pair feature"` from the /web folder. -To run Swap E2E tests, please execute `npx playwright test -g "Test Swap feature"` from the /web folder. - -Tests can be executed locally in a browser by changing `headless: true` to `headless: false`. - -## GitHub E2E Tests workflow - -[Tests Workflow](https://github.com/osmosis-labs/osmosis-frontend/blob/stage/.github/workflows/frontend-e2e-tests.yml) is initiated on `push: branches-ignore: - master` event and awaits a deployment to a Vercel environment. The `await_deployment` script is querying for a building deployment and fails if deployment failed or not started in 30 seconds. - -It contains following jobs: - -- initial `wait-for-deployment` script -- Preview tests `preview-swap-tests` -- Preview tests `preview-portfolio-trx-tests` -- Preview tests `preview-pools-and-select-pair-tests` -- Preview tests `preview-trade-tests` -- Preview tests `preview-claim-tests` -- Test report is uploaded as Artifact on fail. diff --git a/packages/web/components/bridge/amount-screen.tsx b/packages/web/components/bridge/amount-screen.tsx index 03b07f4581..3bb2dc80a5 100644 --- a/packages/web/components/bridge/amount-screen.tsx +++ b/packages/web/components/bridge/amount-screen.tsx @@ -1177,7 +1177,7 @@ export const AmountScreen = observer(
{toChain?.chainType === "bitcoin" && direction === "withdraw" - ? t("transfer.continue") + ? t("transfer.confirmAmount") : pendingChainApproval ? t("transfer.pendingApproval") : t("transfer.connectTo", { diff --git a/packages/web/components/bridge/bridge-wallet-select-modal.tsx b/packages/web/components/bridge/bridge-wallet-select-modal.tsx index 1067b7de50..438da83218 100644 --- a/packages/web/components/bridge/bridge-wallet-select-modal.tsx +++ b/packages/web/components/bridge/bridge-wallet-select-modal.tsx @@ -66,7 +66,7 @@ export const BridgeWalletSelectModal: FunctionComponent< props.direction === "withdraw" && props.toChain.chainType === "bitcoin" ) { - modalTitle = t("transfer.inputBitcoinAddress"); + modalTitle = t("transfer.enterBitcoinAddress"); } else { modalTitle = t("transfer.selectWithdrawWallet", { network: props.toChain.prettyName, @@ -578,7 +578,7 @@ const SendToAnotherAddressForm: FunctionComponent< diff --git a/packages/web/components/bridge/deposit-address-screen.tsx b/packages/web/components/bridge/deposit-address-screen.tsx index b6f106298b..188dfa40c1 100644 --- a/packages/web/components/bridge/deposit-address-screen.tsx +++ b/packages/web/components/bridge/deposit-address-screen.tsx @@ -155,7 +155,7 @@ export const DepositAddressScreen = observer( )} > {showQrCode ? ( -
+
{isLoading || !data?.depositData?.depositAddress ? ( @@ -188,6 +188,13 @@ export const DepositAddressScreen = observer( : t("transfer.copyToClipboard")}
+ } + onClick={() => setShowQrCode(false)} + />
) : (
@@ -443,8 +450,12 @@ const TransferDetails: FunctionComponent<{ {totalFees .inequalitySymbol(showTotalFeeIneqSymbol) .toString()} - {" + "} - {depositData.providerFee.toString()}{" "} + {!depositData.providerFee.toDec().isZero() && ( + <> + {" + "} + {depositData.providerFee.toString()} + + )}{" "} {t("transfer.fees")} )} @@ -521,7 +532,13 @@ const ProviderFeesRow: FunctionComponent<{ label={t("transfer.providerFees")} isLoading={isRefetchingQuote} > -

{depositData.providerFee.toString()}

+ {depositData.providerFee.toDec().isZero() ? ( +

{t("transfer.free")}

+ ) : ( +

+ {depositData.providerFee.toString()} +

+ )} ); }; diff --git a/packages/web/components/chart/historical-chart.tsx b/packages/web/components/chart/historical-chart.tsx index 97848fed37..2941a221e0 100644 --- a/packages/web/components/chart/historical-chart.tsx +++ b/packages/web/components/chart/historical-chart.tsx @@ -121,7 +121,7 @@ export const HistoricalChart = memo((props: HistoricalChartProps) => { data, }, ]} - onCrosshairMove={(params) => { + onDataPointHover={(params) => { if (params.seriesData.size > 0) { const [data] = [...params.seriesData.values()] as AreaData[]; diff --git a/packages/web/components/chart/historical-volume-chart.tsx b/packages/web/components/chart/historical-volume-chart.tsx index 657b86bb6a..99c774997b 100644 --- a/packages/web/components/chart/historical-volume-chart.tsx +++ b/packages/web/components/chart/historical-volume-chart.tsx @@ -95,7 +95,7 @@ export const HistoricalVolumeChart = memo( data, }, ]} - onCrosshairMove={(params) => { + onDataPointHover={(params) => { if (params.seriesData.size > 0) { const [data] = [...params.seriesData.values()] as AreaData[]; diff --git a/packages/web/components/chart/light-weight-charts/chart.tsx b/packages/web/components/chart/light-weight-charts/chart.tsx index 98db6cf8ee..ba09a0a5d1 100644 --- a/packages/web/components/chart/light-weight-charts/chart.tsx +++ b/packages/web/components/chart/light-weight-charts/chart.tsx @@ -11,6 +11,7 @@ import { import React, { memo, PropsWithChildren, + useCallback, useEffect, useRef, useState, @@ -196,6 +197,7 @@ interface ChartProps { params: ChartControllerParams ) => ChartController; onCrosshairMove?: (params: MouseEventParams) => void; + onDataPointHover?: (params: MouseEventParams) => void; } export const Chart = memo( @@ -207,10 +209,25 @@ export const Chart = memo( children, series, onCrosshairMove, + onDataPointHover, Controller, } = props; const [container, setContainer] = useState(null); const chart = useRef>(); + const lastHoverDataPointLogicalIndex = + useRef["logical"]>(undefined); + + const onCrosshairMoveInternal = useCallback( + (params: MouseEventParams) => { + onCrosshairMove?.(params); + + if (lastHoverDataPointLogicalIndex.current !== params.logical) { + onDataPointHover?.(params); + } + lastHoverDataPointLogicalIndex.current = params.logical; + }, + [onCrosshairMove, onDataPointHover] + ); useSyncExternalStore( resizeSubscribe, @@ -228,7 +245,7 @@ export const Chart = memo( }, series, container, - onCrosshairMove, + onCrosshairMove: onCrosshairMoveInternal, }); } diff --git a/packages/web/components/input/textarea-box.tsx b/packages/web/components/input/textarea-box.tsx index d5dd1cd558..91fe98db51 100644 --- a/packages/web/components/input/textarea-box.tsx +++ b/packages/web/components/input/textarea-box.tsx @@ -74,7 +74,7 @@ export const TextareaBox: FunctionComponent = ({ key={textareaKey} ref={textareaRef} className={classNames( - "md:leading-0 w-full resize-none appearance-none bg-transparent pt-px align-middle leading-10 outline-none placeholder:text-osmoverse-500 md:p-0", + "w-full resize-none appearance-none bg-transparent py-2 align-middle outline-none placeholder:text-osmoverse-500 md:p-0", { "text-white-disabled": disabled, "text-white-high": currentValue != "" && !disabled, @@ -103,7 +103,7 @@ export const TextareaBox: FunctionComponent = ({ /> {trailingSymbol && ( - + {trailingSymbol} )} diff --git a/packages/web/components/nomic/nomic-pending-transfers.tsx b/packages/web/components/nomic/nomic-pending-transfers.tsx index 1e183143da..12d794413d 100644 --- a/packages/web/components/nomic/nomic-pending-transfers.tsx +++ b/packages/web/components/nomic/nomic-pending-transfers.tsx @@ -44,7 +44,7 @@ const useNomicTransactionsStore = create( transactions: new Map(), upsertTransaction: (transactions) => { set((state) => { - const nextTransactions = state.transactions; + const nextTransactions = new Map(state.transactions); transactions.forEach((transaction) => { nextTransactions.set(transaction.transactionId, transaction); }); @@ -336,7 +336,8 @@ const TransactionDetailsModal = ({

-

bc0123ab...456def

+ {/* TODO: Get origin bitcoin address from pending deposit */} + {/*

bc0123ab...456def

*/}
diff --git a/packages/web/config/feature-flag.ts b/packages/web/config/feature-flag.ts index 5513197fea..8b01b25237 100644 --- a/packages/web/config/feature-flag.ts +++ b/packages/web/config/feature-flag.ts @@ -3,7 +3,10 @@ import { IS_TESTNET } from "./env"; /** Blacklists pools out at the query level. Marks them as non existant. */ export const BlacklistedPoolIds: string[] = ["895"]; -/** Cosmwasm Code Ids confirmed to be transmuter pools in current env. */ +/** + * Cosmwasm Code Ids confirmed to be transmuter pools in current env. + * @deprecated use packages/server/src/queries/complex/pools/env.ts + */ export const TransmuterPoolCodeIds = IS_TESTNET ? ["3084"] : ["148"]; export const RecommendedSwapDenoms = [ diff --git a/packages/web/localizations/de.json b/packages/web/localizations/de.json index 7de8bc7782..f3c5c963f4 100644 --- a/packages/web/localizations/de.json +++ b/packages/web/localizations/de.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "Diese Adresse läuft bald ab. Bitte fordern Sie eine neue Adresse an, um Geldverluste zu vermeiden.", "createNewDepositAddress": "Neue Einzahlungsadresse erstellen", "transactionDetails": "Details der Transaktion", - "continue": "Weitermachen", - "inputBitcoinAddress": "Bitcoin-Adresse eingeben" + "confirmAmount": "Betrag bestätigen", + "enterBitcoinAddress": "Bitcoin-Adresse eingeben" }, "unknownError": "Unbekannter Fehler", "viewExplorer": "Explorer anzeigen", diff --git a/packages/web/localizations/en.json b/packages/web/localizations/en.json index e82f34fa9e..9ea8c6a95a 100644 --- a/packages/web/localizations/en.json +++ b/packages/web/localizations/en.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "This address is about to expire. Please request a new address to avoid losing funds.", "createNewDepositAddress": "Create new deposit address", "transactionDetails": "Transaction details", - "continue": "Continue", - "inputBitcoinAddress": "Input Bitcoin address" + "confirmAmount": "Confirm Amount", + "enterBitcoinAddress": "Enter Bitcoin address" }, "unknownError": "Unknown error", "viewExplorer": "View explorer", diff --git a/packages/web/localizations/es.json b/packages/web/localizations/es.json index 463237c081..1b454ee07c 100644 --- a/packages/web/localizations/es.json +++ b/packages/web/localizations/es.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "Esta dirección está a punto de caducar. Solicite una nueva dirección para evitar perder fondos.", "createNewDepositAddress": "Crear nueva dirección de depósito", "transactionDetails": "Detalles de la transacción", - "continue": "Continuar", - "inputBitcoinAddress": "Introducir dirección de Bitcoin" + "confirmAmount": "Confirmar importe", + "enterBitcoinAddress": "Introducir dirección de Bitcoin" }, "unknownError": "Error desconocido", "viewExplorer": "Ver Explorador", diff --git a/packages/web/localizations/fa.json b/packages/web/localizations/fa.json index c8863ce971..8dd5f6c0c9 100644 --- a/packages/web/localizations/fa.json +++ b/packages/web/localizations/fa.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "این آدرس رو به اتمام است. لطفاً برای جلوگیری از از دست دادن وجوه، یک آدرس جدید درخواست کنید.", "createNewDepositAddress": "آدرس سپرده جدید ایجاد کنید", "transactionDetails": "جزئیات معامله", - "continue": "ادامه دهید", - "inputBitcoinAddress": "آدرس بیت کوین را وارد کنید" + "confirmAmount": "مبلغ را تأیید کنید", + "enterBitcoinAddress": "آدرس بیت کوین را وارد کنید" }, "unknownError": "خطای نا شناس", "viewExplorer": "مشاهده جزئیات تراکنش", diff --git a/packages/web/localizations/fr.json b/packages/web/localizations/fr.json index b83af190f2..1d2d606971 100644 --- a/packages/web/localizations/fr.json +++ b/packages/web/localizations/fr.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "Cette adresse est sur le point d'expirer. Veuillez demander une nouvelle adresse pour éviter de perdre des fonds.", "createNewDepositAddress": "Créer une nouvelle adresse de dépôt", "transactionDetails": "Détails de la transaction", - "continue": "Continuer", - "inputBitcoinAddress": "Entrez l'adresse Bitcoin" + "confirmAmount": "Confirmer le montant", + "enterBitcoinAddress": "Entrez l'adresse Bitcoin" }, "unknownError": "Erreur inconnue", "viewExplorer": "Voir dans l'exploreur", diff --git a/packages/web/localizations/gu.json b/packages/web/localizations/gu.json index 2dcb5d1346..866ea5a52f 100644 --- a/packages/web/localizations/gu.json +++ b/packages/web/localizations/gu.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "આ સરનામું સમાપ્ત થવામાં છે. ભંડોળ ગુમાવવાનું ટાળવા માટે કૃપા કરીને નવા સરનામાની વિનંતી કરો.", "createNewDepositAddress": "નવું ડિપોઝિટ સરનામું બનાવો", "transactionDetails": "વ્યવહારની વિગતો", - "continue": "ચાલુ રાખો", - "inputBitcoinAddress": "ઇનપુટ Bitcoin સરનામું" + "confirmAmount": "રકમની પુષ્ટિ કરો", + "enterBitcoinAddress": "Bitcoin સરનામું દાખલ કરો" }, "unknownError": "અજાણી ભૂલ", "viewExplorer": "સંશોધક જુઓ", diff --git a/packages/web/localizations/hi.json b/packages/web/localizations/hi.json index 79d85cf6bd..e546f079a4 100644 --- a/packages/web/localizations/hi.json +++ b/packages/web/localizations/hi.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "यह पता समाप्त होने वाला है। कृपया धनराशि खोने से बचने के लिए नया पता मांगें।", "createNewDepositAddress": "नया जमा पता बनाएं", "transactionDetails": "लेन-देन विवरण", - "continue": "जारी रखना", - "inputBitcoinAddress": "बिटकॉइन पता इनपुट करें" + "confirmAmount": "राशि की पुष्टि करें", + "enterBitcoinAddress": "बिटकॉइन पता दर्ज करें" }, "unknownError": "अज्ञात त्रुटि", "viewExplorer": "एक्सप्लोरर देखें", diff --git a/packages/web/localizations/ja.json b/packages/web/localizations/ja.json index 3962007d2f..0f6e650829 100644 --- a/packages/web/localizations/ja.json +++ b/packages/web/localizations/ja.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "このアドレスは有効期限が近づいています。資金の損失を避けるために、新しいアドレスをリクエストしてください。", "createNewDepositAddress": "新しい入金アドレスを作成する", "transactionDetails": "取引の詳細", - "continue": "続く", - "inputBitcoinAddress": "Bitcoinアドレスを入力" + "confirmAmount": "金額を確認", + "enterBitcoinAddress": "ビットコインアドレスを入力" }, "unknownError": "不明なエラー", "viewExplorer": "エクスプローラーを表示する", diff --git a/packages/web/localizations/ko.json b/packages/web/localizations/ko.json index f2a53be22d..f3562e4099 100644 --- a/packages/web/localizations/ko.json +++ b/packages/web/localizations/ko.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "이 주소는 곧 만료됩니다. 자금 손실을 피하려면 새 주소를 요청하세요.", "createNewDepositAddress": "새로운 입금 주소 생성", "transactionDetails": "거래내역", - "continue": "계속하다", - "inputBitcoinAddress": "비트코인 주소를 입력하세요" + "confirmAmount": "금액 확인", + "enterBitcoinAddress": "비트코인 주소를 입력하세요" }, "unknownError": "알 수 없는 에러", "viewExplorer": "블록 익스플로러 보기", diff --git a/packages/web/localizations/pl.json b/packages/web/localizations/pl.json index ecdd1bfd5a..72005cab7f 100644 --- a/packages/web/localizations/pl.json +++ b/packages/web/localizations/pl.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "Ten adres wkrótce wygaśnie. Poproś o nowy adres, aby uniknąć utraty środków.", "createNewDepositAddress": "Utwórz nowy adres depozytowy", "transactionDetails": "Szczegóły transakcji", - "continue": "Kontynuować", - "inputBitcoinAddress": "Wprowadź adres Bitcoin" + "confirmAmount": "Potwierdź kwotę", + "enterBitcoinAddress": "Wprowadź adres Bitcoin" }, "unknownError": "Nieznany błąd", "viewExplorer": "zobacz eksplorer", diff --git a/packages/web/localizations/pt-br.json b/packages/web/localizations/pt-br.json index d3c8f34b94..aef1df2819 100644 --- a/packages/web/localizations/pt-br.json +++ b/packages/web/localizations/pt-br.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "Este endereço está prestes a expirar. Solicite um novo endereço para evitar perda de fundos.", "createNewDepositAddress": "Criar novo endereço de depósito", "transactionDetails": "Detalhes da transação", - "continue": "Continuar", - "inputBitcoinAddress": "Insira o endereço do Bitcoin" + "confirmAmount": "Confirmar valor", + "enterBitcoinAddress": "Insira o endereço do Bitcoin" }, "unknownError": "Erro desconhecido", "viewExplorer": "Visualizar explorer", diff --git a/packages/web/localizations/ro.json b/packages/web/localizations/ro.json index f30052567d..16ebbe6520 100644 --- a/packages/web/localizations/ro.json +++ b/packages/web/localizations/ro.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "Această adresă este pe cale să expire. Vă rugăm să solicitați o nouă adresă pentru a evita pierderea fondurilor.", "createNewDepositAddress": "Creați o nouă adresă de depozit", "transactionDetails": "Detalii tranzacție", - "continue": "Continua", - "inputBitcoinAddress": "Introdu adresa Bitcoin" + "confirmAmount": "Confirmați suma", + "enterBitcoinAddress": "Introdu adresa Bitcoin" }, "unknownError": "Eroare necunoscuta", "viewExplorer": "vezi explorer", diff --git a/packages/web/localizations/ru.json b/packages/web/localizations/ru.json index 46cfddb2e3..a52c5bbdf6 100644 --- a/packages/web/localizations/ru.json +++ b/packages/web/localizations/ru.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "Срок действия этого адреса истекает. Пожалуйста, запросите новый адрес, чтобы избежать потери средств.", "createNewDepositAddress": "Создать новый адрес депозита", "transactionDetails": "Подробности транзакции", - "continue": "Продолжать", - "inputBitcoinAddress": "Введите адрес Bitcoin" + "confirmAmount": "Подтвердите сумму", + "enterBitcoinAddress": "Введите адрес Bitcoin" }, "unknownError": "Неизвестная ошибка", "viewExplorer": "Посмотреть проводник", diff --git a/packages/web/localizations/tr.json b/packages/web/localizations/tr.json index 3d68a242a5..c8cfa844c5 100644 --- a/packages/web/localizations/tr.json +++ b/packages/web/localizations/tr.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "Bu adresin süresi dolmak üzere. Lütfen para kaybetmemek için yeni bir adres talep edin.", "createNewDepositAddress": "Yeni para yatırma adresi oluştur", "transactionDetails": "İşlem detayları", - "continue": "Devam etmek", - "inputBitcoinAddress": "Bitcoin adresini girin" + "confirmAmount": "Tutarı Onayla", + "enterBitcoinAddress": "Bitcoin adresini girin" }, "unknownError": "Bilinmeyen hata", "viewExplorer": "gezginde görüntüle", diff --git a/packages/web/localizations/zh-cn.json b/packages/web/localizations/zh-cn.json index d900572c35..ec063e8299 100644 --- a/packages/web/localizations/zh-cn.json +++ b/packages/web/localizations/zh-cn.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "此地址即将过期。请申请新地址以避免资金损失。", "createNewDepositAddress": "创建新的存款地址", "transactionDetails": "交易详情", - "continue": "继续", - "inputBitcoinAddress": "输入比特币地址" + "confirmAmount": "确认金额", + "enterBitcoinAddress": "输入比特币地址" }, "unknownError": "未知错误", "viewExplorer": "浏览器查看", diff --git a/packages/web/localizations/zh-hk.json b/packages/web/localizations/zh-hk.json index e646b585df..ddd9e95be9 100644 --- a/packages/web/localizations/zh-hk.json +++ b/packages/web/localizations/zh-hk.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "該地址即將過期。請申請新地址以避免資金損失。", "createNewDepositAddress": "建立新的儲值地址", "transactionDetails": "交易詳情", - "continue": "繼續", - "inputBitcoinAddress": "輸入比特幣地址" + "confirmAmount": "確認金額", + "enterBitcoinAddress": "輸入比特幣地址" }, "unknownError": "未知錯誤", "viewExplorer": "使用區塊瀏覽器查看", diff --git a/packages/web/localizations/zh-tw.json b/packages/web/localizations/zh-tw.json index 48e02280ef..98b25a3068 100644 --- a/packages/web/localizations/zh-tw.json +++ b/packages/web/localizations/zh-tw.json @@ -928,8 +928,8 @@ "addressAboutToExpire": "該地址即將過期。請申請新地址以避免資金損失。", "createNewDepositAddress": "建立新的儲值地址", "transactionDetails": "交易詳情", - "continue": "繼續", - "inputBitcoinAddress": "輸入比特幣地址" + "confirmAmount": "確認金額", + "enterBitcoinAddress": "輸入比特幣地址" }, "unknownError": "未知錯誤", "viewExplorer": "使用區塊瀏覽器查看", diff --git a/packages/web/server/api/local-router.ts b/packages/web/server/api/local-router.ts index fa9f5b9bc0..115a642084 100644 --- a/packages/web/server/api/local-router.ts +++ b/packages/web/server/api/local-router.ts @@ -6,9 +6,9 @@ import { oneClickTradingRouter, orderbookRouter, paramsRouter, + poolsRouter, portfolioRouter, swapRouter, - poolsRouter, } from "@osmosis-labs/trpc"; import { localBridgeTransferRouter } from "~/server/api/routers/local-bridge-transfer";