diff --git a/.changeset/fresh-poets-count.md b/.changeset/fresh-poets-count.md new file mode 100644 index 000000000..2abfe6b2b --- /dev/null +++ b/.changeset/fresh-poets-count.md @@ -0,0 +1,6 @@ +--- +"@fuel-wallet/types": patch +"fuels-wallet": patch +--- + +feat: improve nft support + dont allow sending funds to assetId address diff --git a/packages/app/package.json b/packages/app/package.json index 318602ca1..1635ec088 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -26,6 +26,7 @@ "@fuel-ui/test-utils": "0.17.0", "@fuel-wallet/connections": "workspace:*", "@fuels/local-storage": "0.20.0", + "@fuels/playwright-utils": "workspace:*", "@fuels/react-xstore": "0.20.0", "@hookform/resolvers": "3.9.0", "@react-aria/utils": "3.21.0", diff --git a/packages/app/playwright.config.ts b/packages/app/playwright.config.ts index 42d69f9ac..1d5a6a594 100644 --- a/packages/app/playwright.config.ts +++ b/packages/app/playwright.config.ts @@ -8,7 +8,7 @@ const IS_CI = process.env.CI; export const playwrightConfig: PlaywrightTestConfig = { workers: 1, - retries: 1, + retries: IS_CI ? 1 : 0, testMatch: join(__dirname, './playwright/**/*.test.ts'), testDir: join(__dirname, './playwright/'), outputDir: join(__dirname, './playwright-results/'), @@ -30,6 +30,7 @@ export const playwrightConfig: PlaywrightTestConfig = { trace: 'on-first-retry', actionTimeout: 5000, screenshot: 'only-on-failure', + headless: false, }, // ignore lock test because it takes too long and it will be tested in a separate config testIgnore: [join(__dirname, './playwright/crx/lock.test.ts')], diff --git a/packages/app/playwright/e2e/SendTransaction.test.ts b/packages/app/playwright/e2e/SendTransaction.test.ts index db3c00e08..7dc3ea27a 100644 --- a/packages/app/playwright/e2e/SendTransaction.test.ts +++ b/packages/app/playwright/e2e/SendTransaction.test.ts @@ -1,14 +1,8 @@ import type { Account } from '@fuel-wallet/types'; +import { expectButtonToBeEnabled } from '@fuels/playwright-utils'; import type { Browser, Page } from '@playwright/test'; import test, { chromium, expect } from '@playwright/test'; -import { - type Bech32Address, - Provider, - Wallet, - bn, - fromBech32, - toB256, -} from 'fuels'; +import { Provider, Wallet, bn } from 'fuels'; import { getButtonByText, @@ -62,7 +56,13 @@ test.describe('SendTransaction', () => { await getInputByName(page, 'amount').fill('0.001'); // Submit transaction - await getButtonByText(page, 'Review').click(); + + const btnLocator = getButtonByText(page, 'Review'); + + await expectButtonToBeEnabled(btnLocator); + await page.waitForTimeout(5000); + await expectButtonToBeEnabled(btnLocator); + await btnLocator.click(); await getButtonByText(page, 'Approve').click(); await hasText(page, '0.001 ETH'); @@ -92,7 +92,13 @@ test.describe('SendTransaction', () => { await getInputByName(page, 'amount').fill('0.001'); // Submit transaction - await getButtonByText(page, 'Review').click(); + // make sure the button is enabled + const btnLocator = getButtonByText(page, 'Review'); + + await expectButtonToBeEnabled(btnLocator); + await page.waitForTimeout(5000); + await expectButtonToBeEnabled(btnLocator); + await btnLocator.click(); // Approve transaction await hasText(page, '0.001 ETH'); @@ -131,7 +137,13 @@ test.describe('SendTransaction', () => { await hasText(page, 'Balance: 1,000,000.000'); // Submit transaction - await getButtonByText(page, 'Review').click(); + + const btnLocator = getButtonByText(page, 'Review'); + + await expectButtonToBeEnabled(btnLocator); + await page.waitForTimeout(5000); + await expectButtonToBeEnabled(btnLocator); + await btnLocator.click(); // Approve transaction await hasText(page, `0.01 ${ALT_ASSET.symbol}`); @@ -163,7 +175,12 @@ test.describe('SendTransaction', () => { await page.waitForSelector('button:has-text("Review")'); await page.waitForTimeout(1000); - await getButtonByText(page, 'Review').click(); + const btnLocator = getButtonByText(page, 'Review'); + + await expectButtonToBeEnabled(btnLocator); + await page.waitForTimeout(5000); + await expectButtonToBeEnabled(btnLocator); + await btnLocator.click(); await hasText(page, '0.001 ETH'); @@ -200,7 +217,12 @@ test.describe('SendTransaction', () => { await page.waitForSelector('button:has-text("Review")'); await page.waitForTimeout(1000); - await getButtonByText(page, 'Review').click(); + const btnLocator = getButtonByText(page, 'Review'); + + await expectButtonToBeEnabled(btnLocator); + await page.waitForTimeout(5000); + await expectButtonToBeEnabled(btnLocator); + await btnLocator.click(); await hasText(page, '0.001 ETH'); @@ -241,7 +263,12 @@ test.describe('SendTransaction', () => { await page.waitForSelector('button:has-text("Review")'); await page.waitForTimeout(1000); - await getButtonByText(page, 'Review').click(); + const btnLocatorBeforeApprv = getButtonByText(page, 'Review'); + + await expectButtonToBeEnabled(btnLocatorBeforeApprv); + await page.waitForTimeout(5000); + await expectButtonToBeEnabled(btnLocatorBeforeApprv); + await btnLocatorBeforeApprv.click(); // Waiting button change to Approve in order to get updated fee amount await page.waitForSelector('button:has-text("Approve")'); @@ -258,7 +285,12 @@ test.describe('SendTransaction', () => { await page.waitForSelector('button:has-text("Review")'); await page.waitForTimeout(1000); - await getButtonByText(page, 'Review').click(); + const btnLocator = getButtonByText(page, 'Review'); + + await expectButtonToBeEnabled(btnLocator); + await page.waitForTimeout(5000); + await expectButtonToBeEnabled(btnLocator); + await btnLocator.click(); // Waiting button change to Approve in order to get updated fee amount await page.waitForSelector('button:has-text("Approve")'); @@ -308,7 +340,13 @@ test.describe('SendTransaction', () => { const maxAmountAfterFee = await getInputByName(page, 'amount').inputValue(); // Submit transaction - await getButtonByText(page, 'Review').click(); + + const btnLocator = getButtonByText(page, 'Review'); + + await expectButtonToBeEnabled(btnLocator); + await page.waitForTimeout(5000); + await expectButtonToBeEnabled(btnLocator); + await btnLocator.click(); // Approve transaction await hasText(page, `${maxAmountAfterFee} ETH`); diff --git a/packages/app/src/systems/Account/components/BalanceAssets/BalanceAssets.tsx b/packages/app/src/systems/Account/components/BalanceAssets/BalanceAssets.tsx index 7956c3c25..8250942b1 100644 --- a/packages/app/src/systems/Account/components/BalanceAssets/BalanceAssets.tsx +++ b/packages/app/src/systems/Account/components/BalanceAssets/BalanceAssets.tsx @@ -1,6 +1,7 @@ import { Button, CardList } from '@fuel-ui/react'; import type { CoinAsset } from '@fuel-wallet/types'; import { useMemo, useState } from 'react'; +import { isUnknownAsset } from '~/systems/Asset'; import { AssetItem, AssetList } from '~/systems/Asset/components'; import type { AssetListEmptyProps } from '~/systems/Asset/components/AssetList/AssetListEmpty'; @@ -21,7 +22,10 @@ export const BalanceAssets = ({ }: BalanceAssetListProp) => { const [showUnknown, setShowUnknown] = useState(false); const unknownLength = useMemo( - () => balances?.filter((balance) => !balance.asset?.name).length, + () => + balances?.filter( + (balance) => balance.asset && isUnknownAsset(balance.asset) + ).length, [balances] ); @@ -29,7 +33,8 @@ export const BalanceAssets = ({ const isEmpty = !balances || !balances.length; if (isEmpty) return ; const balancesToShow = balances.filter( - (balance) => showUnknown || balance.asset?.name + (balance) => + showUnknown || (balance.asset && !isUnknownAsset(balance.asset)) ); function toggle() { @@ -37,15 +42,22 @@ export const BalanceAssets = ({ } return ( - {balancesToShow.map((balance) => ( - - ))} + {balancesToShow.map((balance) => { + if (!balance.asset) return null; + + const shouldShowAddAssetBtn = isUnknownAsset(balance.asset); + + return ( + + ); + })} {!!(!isLoading && unknownLength) && (