diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 00000000..104b2ef7 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,42 @@ +name: Playwright Tests +env: + CI: true + WALLET_ENVIRONMENT: testing +on: + push: + branches: [dev, main] + pull_request: + branches: [dev, main] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Install dependencies + run: yarn + - name: Install Playwright Browsers + run: yarn playwright install --with-deps + - name: Build extension in test mode + run: yarn build:test + - name: Run Playwright tests + # Playwright can only test extensions in headed mode, see + # https://playwright.dev/docs/chrome-extensions. To run a browser in + # headed mode, a display server is necessary. However, this job runs on + # an Ubuntu worker without a display server. + # + # The `xvfb-run` utility, + # https://manpages.ubuntu.com/manpages/xenial/man1/xvfb-run.1.html, + # provides a virtual X display server to the process it runs, allowing + # processes that require a display server to run in environments where + # one is not available. + run: xvfb-run yarn playwright test + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore index e9d305d2..a282b0f4 100755 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ coverage .jest-cache release_body.md trace* +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/jest.config.js b/jest.config.js index dddd21e2..4f82ac61 100755 --- a/jest.config.js +++ b/jest.config.js @@ -18,7 +18,7 @@ Object.keys(compilerOptions.paths).forEach(key => { }); module.exports = { - setupFilesAfterEnv: ['./tests/jest-unit.setup.js'], + setupFilesAfterEnv: ['./tests-legacy/jest-unit.setup.js'], collectCoverage: true, coverageReporters: ['html', 'json-summary'], collectCoverageFrom: ['src/**/*.{ts,tsx}'], @@ -27,7 +27,7 @@ module.exports = { 'ts-jest': { // https://huafu.github.io/ts-jest/user/config/diagnostics diagnostics: false, - tsconfig: '/tests/tsconfig.json', + tsconfig: '/tests-legacy/tsconfig.json', }, VERSION: version, }, @@ -37,7 +37,7 @@ module.exports = { ...pathNames, ...pathsToModuleNameMapper(compilerOptions.paths, { prefix: '/' }), }, - roots: ['/tests', '/src'], + roots: ['/tests-legacy', '/src'], preset: 'ts-jest', testMatch: ['**/?(*.)+(spec).(js|ts|tsx)'], testRunner: 'jest-circus/runner', diff --git a/jest.integration.config.js b/jest.integration.config.js index 883f0558..0687f55d 100644 --- a/jest.integration.config.js +++ b/jest.integration.config.js @@ -7,6 +7,6 @@ module.exports = { '^.+\\.tsx?$': '@swc-node/jest', }, testTimeout: 60000, - globalSetup: '/tests/global-setup.ts', - globalTeardown: '/tests/global-teardown.ts', + globalSetup: '/tests-legacy/global-setup.ts', + globalTeardown: '/tests-legacy/global-teardown.ts', }; diff --git a/package.json b/package.json index 8f88bf75..7fa10f65 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build:analyze": "cross-env ANALYZE=true NODE_ENV=production EXT_ENV=prod webpack --config webpack/webpack.config.prod.js", "build:dev": "cross-env NODE_ENV=development EXT_ENV=development webpack --config webpack/webpack.config.dev.js", "build:ext:test": "cross-env NODE_ENV=production TEST_ENV=true EXT_ENV=prod webpack --config webpack/webpack.config.prod.js", + "build:ext:test:watch": "cross-env NODE_ENV=production TEST_ENV=true EXT_ENV=prod webpack --config webpack/webpack.config.prod.js --watch", "build:test-app": "cross-env NODE_ENV=production EXT_ENV=prod webpack --config ./test-app/webpack/webpack.config.prod.js", "build:test": "concurrently 'yarn build:ext:test' 'yarn build:test-app'", "build:test-api": "concurrently 'yarn build:ext:test' 'yarn build:test-app'", @@ -20,18 +21,18 @@ "lint": "yarn lint:eslint && yarn lint:prettier && yarn lint:unused-exports && yarn lint:deps && yarn lint:remote-wallet-config", "lint:eslint": "eslint \"src/**/*.{ts,tsx}\"", "lint:fix": "eslint \"src/**/*.{ts,tsx}\" --fix", - "lint:prettier": "prettier --check \"{src,tests}/**/*.{ts,tsx}\" \"*.{js,json}\"", - "lint:prettier:fix": "prettier --write \"{src,tests}/**/*.{ts,tsx}\" *.js", + "lint:prettier": "prettier --check \"{src,tests,tests-legacy}/**/*.{ts,tsx}\" \"*.{js,json}\"", + "lint:prettier:fix": "prettier --write \"{src,tests,tests-legacy}/**/*.{ts,tsx}\" *.js", "lint:unused-exports": "ts-unused-exports tsconfig.json", "lint:remote-wallet-config": "npx ajv-cli validate -s config/wallet-config.schema.json -d config/wallet-config.json", "lint:deps": "dependency-cruise --config .dependency-cruiser.js \"src/**/*.{ts,tsx}\"", "prod:ext": "yarn build", "prod:analyze": "cross-env NODE_ENV=production ANALYZE=true webpack -p", - "test:integration": "jest --config=./jest.integration.config.js --verbose=true --runInBand --testPathPattern=./tests/integration/*", - "test:integration:ci": "jest --config=./jest.integration.config.js --testPathPattern=./tests/integration/*", - "test:integration-api": "jest --config=./jest.integration.config.js --verbose=true --runInBand --testPathPattern=./tests/test-api/*", - "test:integration-api:ci": "jest --config=./jest.integration.config.js --testPathPattern=./tests/test-api/*", - "test:unit": "cross-env TEST_ENV=true jest --forceExit --testPathIgnorePatterns=./tests/integration/*", + "test:integration": "jest --config=./jest.integration.config.js --verbose=true --runInBand --testPathPattern=./tests-legacy/integration/*", + "test:integration:ci": "jest --config=./jest.integration.config.js --testPathPattern=./tests-legacy/integration/*", + "test:integration-api": "jest --config=./jest.integration.config.js --verbose=true --runInBand --testPathPattern=./tests-legacy/test-api/*", + "test:integration-api:ci": "jest --config=./jest.integration.config.js --testPathPattern=./tests-legacy/test-api/*", + "test:unit": "cross-env TEST_ENV=true jest --forceExit --testPathIgnorePatterns=./tests-legacy/integration/*", "test": "NODE_ENV=test jest --verbose=true", "test:coverage": "NODE_ENV=test jest --collect-coverage", "test:watch": "NODE_ENV=test jest --watch", @@ -219,6 +220,7 @@ "@babel/runtime": "7.19.0", "@emotion/babel-preset-css-prop": "11.2.0", "@emotion/cache": "11.7.1", + "@playwright/test": "1.28.0", "@pmmmwh/react-refresh-webpack-plugin": "0.5.7", "@redux-devtools/cli": "1.0.7", "@redux-devtools/remote": "0.7.5", @@ -292,9 +294,7 @@ "jest-circus": "27.3.1", "jest-dev-server": "6.0.0", "msw": "0.31.0", - "playwright": "1.25.0", - "playwright-chromium": "1.25.0", - "playwright-core": "1.25.0", + "playwright": "1.28.0", "prettier": "2.7.1", "process": "0.11.10", "progress-bar-webpack-plugin": "2.1.0", @@ -308,7 +308,7 @@ "svg-url-loader": "7.1.1", "ts-jest": "27.0.7", "ts-loader": "9.3.1", - "ts-node": "10.4", + "ts-node": "10.9.1", "ts-unused-exports": "7.0.3", "tsconfig-paths-webpack-plugin": "4.0.0", "typescript": "4.8.2", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 00000000..b131a0fd --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,45 @@ +import type { PlaywrightTestConfig } from '@playwright/test'; +import { devices } from '@playwright/test'; + +/** + * See https://playwright.dev/docs/test-configuration. + */ +const config: PlaywrightTestConfig = { + testDir: './tests', + /* Maximum time one test can run for. */ + timeout: 30 * 1000, + expect: { + /** + * Maximum time expect() should wait for the condition to be met. + * For example in `await expect(locator).toHaveText();` + */ + timeout: 5000, + }, + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: [['html', { open: 'never' }]], + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + }, + }, + ], +}; + +export default config; diff --git a/src/app/common/persistence.ts b/src/app/common/persistence.ts index ea6a21de..73562598 100644 --- a/src/app/common/persistence.ts +++ b/src/app/common/persistence.ts @@ -11,6 +11,8 @@ export const queryClient = new QueryClient({ defaultOptions: { queries: { cacheTime: PERSISTENCE_CACHE_TIME, + // https://tanstack.com/query/v4/docs/guides/testing#turn-off-retries + retry: !IS_TEST_ENV, }, }, }); diff --git a/src/app/pages/send-tokens/components/recipient-field.tsx b/src/app/pages/send-tokens/components/recipient-field.tsx index 7b394154..dc91cb2e 100644 --- a/src/app/pages/send-tokens/components/recipient-field.tsx +++ b/src/app/pages/send-tokens/components/recipient-field.tsx @@ -81,7 +81,9 @@ function RecipientFieldBase(props: RecipientField) { {Boolean(resolvedBnsAddress) && ( - {truncateMiddle(resolvedBnsAddress, 4)} + + {truncateMiddle(resolvedBnsAddress, 4)} + @@ -101,6 +104,7 @@ function RecipientFieldBase(props: RecipientField) { size="12px" color={color('text-caption')} as={FiCopy} + data-testid={SendFormSelectors.ResolvedBnsAddressCopyToClipboard} /> diff --git a/src/app/query/stacks/fees/fees.hooks.ts b/src/app/query/stacks/fees/fees.hooks.ts index 455047ac..ea48ddb1 100644 --- a/src/app/query/stacks/fees/fees.hooks.ts +++ b/src/app/query/stacks/fees/fees.hooks.ts @@ -91,6 +91,13 @@ export function useFeeEstimations(txByteLength: number | null, txPayload: string }; } return { estimates: feeEstimations ?? [], calculation: FeeCalculationType.Api }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [txByteLength, txFeeEstimation]); + }, [ + feeEstimationsMaxValues, + feeEstimationsMinValues, + isError, + isLoading, + result, + txByteLength, + txFeeEstimation?.estimations, + ]); } diff --git a/tests/global-setup.ts b/tests-legacy/global-setup.ts similarity index 100% rename from tests/global-setup.ts rename to tests-legacy/global-setup.ts diff --git a/tests/global-teardown.ts b/tests-legacy/global-teardown.ts similarity index 100% rename from tests/global-teardown.ts rename to tests-legacy/global-teardown.ts diff --git a/tests/integration/asset.selectors.ts b/tests-legacy/integration/asset.selectors.ts similarity index 100% rename from tests/integration/asset.selectors.ts rename to tests-legacy/integration/asset.selectors.ts diff --git a/tests/integration/assets/decimal-tests.spec.ts b/tests-legacy/integration/assets/decimal-tests.spec.ts similarity index 100% rename from tests/integration/assets/decimal-tests.spec.ts rename to tests-legacy/integration/assets/decimal-tests.spec.ts diff --git a/tests/integration/balance.selectors.ts b/tests-legacy/integration/balance.selectors.ts similarity index 100% rename from tests/integration/balance.selectors.ts rename to tests-legacy/integration/balance.selectors.ts diff --git a/tests/integration/balance/balance.spec.ts b/tests-legacy/integration/balance/balance.spec.ts similarity index 100% rename from tests/integration/balance/balance.spec.ts rename to tests-legacy/integration/balance/balance.spec.ts diff --git a/tests/integration/contract-call/locked-wallet.spec.ts b/tests-legacy/integration/contract-call/locked-wallet.spec.ts similarity index 100% rename from tests/integration/contract-call/locked-wallet.spec.ts rename to tests-legacy/integration/contract-call/locked-wallet.spec.ts diff --git a/tests/integration/fund/fund.spec.ts b/tests-legacy/integration/fund/fund.spec.ts similarity index 100% rename from tests/integration/fund/fund.spec.ts rename to tests-legacy/integration/fund/fund.spec.ts diff --git a/tests/integration/network.selectors.ts b/tests-legacy/integration/network.selectors.ts similarity index 100% rename from tests/integration/network.selectors.ts rename to tests-legacy/integration/network.selectors.ts diff --git a/tests/integration/network/add-network.spec.ts b/tests-legacy/integration/network/add-network.spec.ts similarity index 100% rename from tests/integration/network/add-network.spec.ts rename to tests-legacy/integration/network/add-network.spec.ts diff --git a/tests/integration/onboarding/onboarding.selectors.ts b/tests-legacy/integration/onboarding/onboarding.selectors.ts similarity index 100% rename from tests/integration/onboarding/onboarding.selectors.ts rename to tests-legacy/integration/onboarding/onboarding.selectors.ts diff --git a/tests/integration/onboarding/onboarding.spec.ts b/tests-legacy/integration/onboarding/onboarding.spec.ts similarity index 100% rename from tests/integration/onboarding/onboarding.spec.ts rename to tests-legacy/integration/onboarding/onboarding.spec.ts diff --git a/tests/integration/send-tokens/send-tokens.spec.ts b/tests-legacy/integration/send-tokens/send-tokens.spec.ts similarity index 100% rename from tests/integration/send-tokens/send-tokens.spec.ts rename to tests-legacy/integration/send-tokens/send-tokens.spec.ts diff --git a/tests/integration/settings.selectors.ts b/tests-legacy/integration/settings.selectors.ts similarity index 100% rename from tests/integration/settings.selectors.ts rename to tests-legacy/integration/settings.selectors.ts diff --git a/tests/integration/settings/settings.spec.ts b/tests-legacy/integration/settings/settings.spec.ts similarity index 100% rename from tests/integration/settings/settings.spec.ts rename to tests-legacy/integration/settings/settings.spec.ts diff --git a/tests/integration/transactions/transactions.spec.ts b/tests-legacy/integration/transactions/transactions.spec.ts similarity index 100% rename from tests/integration/transactions/transactions.spec.ts rename to tests-legacy/integration/transactions/transactions.spec.ts diff --git a/tests/integration/user-area.selectors.ts b/tests-legacy/integration/user-area.selectors.ts similarity index 100% rename from tests/integration/user-area.selectors.ts rename to tests-legacy/integration/user-area.selectors.ts diff --git a/tests/integration/utils.ts b/tests-legacy/integration/utils.ts similarity index 100% rename from tests/integration/utils.ts rename to tests-legacy/integration/utils.ts diff --git a/tests/jest-unit.setup.js b/tests-legacy/jest-unit.setup.js similarity index 100% rename from tests/jest-unit.setup.js rename to tests-legacy/jest-unit.setup.js diff --git a/tests/mocks/heystack.ts b/tests-legacy/mocks/heystack.ts similarity index 100% rename from tests/mocks/heystack.ts rename to tests-legacy/mocks/heystack.ts diff --git a/tests/mocks/heystack/data.ts b/tests-legacy/mocks/heystack/data.ts similarity index 100% rename from tests/mocks/heystack/data.ts rename to tests-legacy/mocks/heystack/data.ts diff --git a/tests/mocks/index.ts b/tests-legacy/mocks/index.ts similarity index 100% rename from tests/mocks/index.ts rename to tests-legacy/mocks/index.ts diff --git a/tests/mocks/localStorage-mock.ts b/tests-legacy/mocks/localStorage-mock.ts similarity index 100% rename from tests/mocks/localStorage-mock.ts rename to tests-legacy/mocks/localStorage-mock.ts diff --git a/tests/mocks/playwright-mocks.ts b/tests-legacy/mocks/playwright-mocks.ts similarity index 96% rename from tests/mocks/playwright-mocks.ts rename to tests-legacy/mocks/playwright-mocks.ts index a00e1f12..692fa1ab 100644 --- a/tests/mocks/playwright-mocks.ts +++ b/tests-legacy/mocks/playwright-mocks.ts @@ -1,4 +1,4 @@ -import { BrowserContext } from 'playwright-core'; +import { BrowserContext } from 'playwright'; export const setupMocks = async (context: BrowserContext) => { await context.route('https://test-registrar.blockstack.org/register', route => { diff --git a/tests/page-objects/demo.page.ts b/tests-legacy/page-objects/demo.page.ts similarity index 100% rename from tests/page-objects/demo.page.ts rename to tests-legacy/page-objects/demo.page.ts diff --git a/tests/page-objects/fund.page.ts b/tests-legacy/page-objects/fund.page.ts similarity index 100% rename from tests/page-objects/fund.page.ts rename to tests-legacy/page-objects/fund.page.ts diff --git a/tests/page-objects/fund.selectors.ts b/tests-legacy/page-objects/fund.selectors.ts similarity index 100% rename from tests/page-objects/fund.selectors.ts rename to tests-legacy/page-objects/fund.selectors.ts diff --git a/tests/page-objects/home.selectors.ts b/tests-legacy/page-objects/home.selectors.ts similarity index 100% rename from tests/page-objects/home.selectors.ts rename to tests-legacy/page-objects/home.selectors.ts diff --git a/tests/page-objects/network-page.ts b/tests-legacy/page-objects/network-page.ts similarity index 100% rename from tests/page-objects/network-page.ts rename to tests-legacy/page-objects/network-page.ts diff --git a/tests/page-objects/send-form.page.ts b/tests-legacy/page-objects/send-form.page.ts similarity index 100% rename from tests/page-objects/send-form.page.ts rename to tests-legacy/page-objects/send-form.page.ts diff --git a/tests/page-objects/send-form.selectors.ts b/tests-legacy/page-objects/send-form.selectors.ts similarity index 84% rename from tests/page-objects/send-form.selectors.ts rename to tests-legacy/page-objects/send-form.selectors.ts index 1761f0f9..12b66662 100644 --- a/tests/page-objects/send-form.selectors.ts +++ b/tests-legacy/page-objects/send-form.selectors.ts @@ -34,4 +34,8 @@ export enum SendFormSelectors { StellaTokenOption = 'asset-stella-token', OptionAccount1 = 'account-account-1-0', + + ResolvedBnsAddressPreview = 'resolved-bns-address-preview', + ResolvedBnsAddressHoverInfoIcon = 'resolved-bns-address-hover-info-icon', + ResolvedBnsAddressCopyToClipboard = 'resolved-bns-address-copy-to-clipboard', } diff --git a/tests/page-objects/transaction-signing.page.ts b/tests-legacy/page-objects/transaction-signing.page.ts similarity index 100% rename from tests/page-objects/transaction-signing.page.ts rename to tests-legacy/page-objects/transaction-signing.page.ts diff --git a/tests/page-objects/transaction-signing.selectors.ts b/tests-legacy/page-objects/transaction-signing.selectors.ts similarity index 100% rename from tests/page-objects/transaction-signing.selectors.ts rename to tests-legacy/page-objects/transaction-signing.selectors.ts diff --git a/tests/page-objects/wallet.page.ts b/tests-legacy/page-objects/wallet.page.ts similarity index 100% rename from tests/page-objects/wallet.page.ts rename to tests-legacy/page-objects/wallet.page.ts diff --git a/tests/page-objects/wallet.selectors.ts b/tests-legacy/page-objects/wallet.selectors.ts similarity index 100% rename from tests/page-objects/wallet.selectors.ts rename to tests-legacy/page-objects/wallet.selectors.ts diff --git a/tests/state-utils.tsx b/tests-legacy/state-utils.tsx similarity index 100% rename from tests/state-utils.tsx rename to tests-legacy/state-utils.tsx diff --git a/tests-legacy/tsconfig.json b/tests-legacy/tsconfig.json new file mode 100644 index 00000000..e97cdcc6 --- /dev/null +++ b/tests-legacy/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "target": "ES2019", + "noEmit": true, + "rootDir": "../", + "esModuleInterop": true + }, + "include": ["./**/*", "../src/**/*"] +} diff --git a/tests/utils/transation-test-utils.ts b/tests-legacy/utils/transation-test-utils.ts similarity index 100% rename from tests/utils/transation-test-utils.ts rename to tests-legacy/utils/transation-test-utils.ts diff --git a/tests/punycode.spec.ts b/tests/punycode.spec.ts new file mode 100644 index 00000000..9d8b5488 --- /dev/null +++ b/tests/punycode.spec.ts @@ -0,0 +1,90 @@ +import { AddressNonces } from '@stacks/blockchain-api-client/lib/generated/models/AddressNonces'; +import { AddressBalanceResponse } from '@stacks/stacks-blockchain-api-types'; +import { + TokenTransferPayload, + addressToString, + deserializeTransaction, +} from '@stacks/transactions'; +import { SendFormSelectors } from '@tests/page-objects/send-form.selectors'; + +import { RouteUrls } from '@shared/route-urls'; + +import { json } from './utils/json'; +import { test } from './utils/testfn'; + +test('recipient address matches resolved bns name', async ({ page, extensionId }) => { + await page.route(/.*/, route => route.abort()); + await page.route(/chrome-extension/, route => route.continue()); + await page.route(/github/, route => route.fulfill(json({}))); + await page.route(/stacks.co.+balances$/, route => { + const res: AddressBalanceResponse = { + stx: { + balance: '1000000000', + total_sent: '0', + total_received: '0', + total_fees_sent: '0', + total_miner_rewards_received: '0', + lock_tx_id: '', + locked: '0', + lock_height: 0, + burnchain_lock_height: 0, + burnchain_unlock_height: 0, + }, + fungible_tokens: {}, + non_fungible_tokens: {}, + }; + return route.fulfill(json(res)); + }); + await page.route(/nonce/, route => { + const res: AddressNonces = { + last_executed_tx_nonce: 1, + last_mempool_tx_nonce: null, + possible_next_nonce: 2, + detected_missing_nonces: [], + }; + return route.fulfill(json(res)); + }); + const bnsName = 'example.bns'; + const address = 'SP11W6YAR16YN6P5N7425DMQV1HY5QZT959CKPVPW'; + await page.route(new RegExp(`stacks.co.+${bnsName}`), route => route.fulfill(json({ address }))); + + await page.goto(`chrome-extension://${extensionId}/index.html`); + + await page.getByTestId('analytics-deny-btn').click(); + await page.waitForURL('**' + RouteUrls.Onboarding); + + await page.getByTestId('sign-up-btn').click(); + await page.waitForURL('**' + RouteUrls.BackUpSecretKey); + + await page.getByTestId('back-up-secret-key-btn').click(); + await page.waitForURL('**' + RouteUrls.SetPassword); + + await page.getByTestId('set-or-enter-password-input').fill('my_s3cret_p@ssw0r4'); + await page.getByTestId('set-password-btn').click(); + await page.waitForURL('**' + RouteUrls.Home); + + await page.getByTestId('btn-send-tokens').click(); + await page.waitForURL('**' + RouteUrls.Send); + + await page.getByTestId('input-amount-field').fill('1'); + await page.getByTestId('input-recipient-field').fill(bnsName); + await page.getByTestId('memo-field').click(); + await page.getByTestId(SendFormSelectors.ResolvedBnsAddressPreview).waitFor(); + await page.getByTestId(SendFormSelectors.ResolvedBnsAddressHoverInfoIcon).hover(); + await page.getByText(address).waitFor(); + await page.getByTestId(SendFormSelectors.ResolvedBnsAddressCopyToClipboard).waitFor(); + + await page.getByTestId(SendFormSelectors.BtnPreviewSendTx).click(); + const [request] = await Promise.all([ + page.waitForRequest(/.*v2\/transactions/), + page.getByTestId(SendFormSelectors.SendToken).click(), + ]); + const serializedTx = request.postDataBuffer(); + if (serializedTx === null) throw new Error('Expected `serializedTx` to not be `null`.'); + const tx = deserializeTransaction(serializedTx); + + // May be able to avoid type assertion if following PR merged, + // https://github.com/hirosystems/stacks.js/pull/1395 + const payload = tx.payload as TokenTransferPayload; + test.expect(addressToString(payload.recipient.address)).toEqual(address); +}); diff --git a/tests/utils/json.ts b/tests/utils/json.ts new file mode 100644 index 00000000..06c323b2 --- /dev/null +++ b/tests/utils/json.ts @@ -0,0 +1,6 @@ +export function json(arg: unknown) { + return { + body: JSON.stringify(arg), + contentType: 'application/json', + }; +} diff --git a/tests/utils/testfn.ts b/tests/utils/testfn.ts new file mode 100644 index 00000000..758ba708 --- /dev/null +++ b/tests/utils/testfn.ts @@ -0,0 +1,33 @@ +import { BrowserContext, test as base, chromium } from '@playwright/test'; +import path from 'path'; + +/** + * Loads the extension into the browser context. Use this test function with + * Playwright to avoid having to manually load the extension into the browser + * context in each test. Created by following, + * https://playwright.dev/docs/chrome-extensions + */ +export const test = base.extend<{ + context: BrowserContext; + extensionId: string; +}>({ + context: async ({}, use) => { + const pathToExtension = path.join(__dirname, '../../dist'); + const context = await chromium.launchPersistentContext('', { + headless: false, + args: [ + `--disable-extensions-except=${pathToExtension}`, + `--load-extension=${pathToExtension}`, + ], + }); + await use(context); + await context.close(); + }, + extensionId: async ({ context }, use) => { + let [background] = context.backgroundPages(); + if (!background) background = await context.waitForEvent('backgroundpage'); + + const extensionId = background.url().split('/')[2]; + await use(extensionId); + }, +}); diff --git a/tsconfig.json b/tsconfig.json index 8a572f55..1e27c63b 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,13 +29,15 @@ "@inpage/*": ["inpage/*"], "@app/*": ["app/*"], "@tests/*": ["../tests/*"], - "@tests": ["../tests"] + "@tests": ["../tests"], + "@tests-new/*": ["../tests-legacy/*"], + "@tests-new": ["../tests-legacy"] }, "allowSyntheticDefaultImports": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "types": ["jest", "chrome", "@emotion/react/types/css-prop"] }, - "include": ["./src/**/*", "./tests/**/*"], + "include": ["./src/**/*", "./tests/**/*", "./tests-legacy/**/*", "./scripts-ts/**/*"], "exclude": ["test-app"] } diff --git a/yarn.lock b/yarn.lock index 69ee9cb5..fe1deabf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1314,17 +1314,12 @@ resolved "https://registry.yarnpkg.com/@coinbase/cbpay-js/-/cbpay-js-1.0.2.tgz#4975efa6b060868c0a6cda20bb6e6169f0d82b0b" integrity sha512-m95VmSQm9xfA5MmOFRcVIPtZxO6GhRJKPbbxKSxGoCYf4SpAm7mz3euU1kiRr7bPMa+3wvyT36n2bHoiyuwseg== -"@cspotcode/source-map-consumer@0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" - integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== - -"@cspotcode/source-map-support@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" - integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: - "@cspotcode/source-map-consumer" "0.8.0" + "@jridgewell/trace-mapping" "0.3.9" "@devicefarmer/adbkit-logcat@^2.1.2": version "2.1.2" @@ -2136,6 +2131,14 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping@^0.3.14", "@jridgewell/trace-mapping@^0.3.9": version "0.3.15" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" @@ -2431,6 +2434,14 @@ tiny-glob "^0.2.9" tslib "^2.4.0" +"@playwright/test@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.28.0.tgz#8de83f9d2291bba3f37883e33431b325661720d9" + integrity sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ== + dependencies: + "@types/node" "*" + playwright-core "1.28.0" + "@pmmmwh/react-refresh-webpack-plugin@0.5.7": version "0.5.7" resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.7.tgz#58f8217ba70069cc6a73f5d7e05e85b458c150e2" @@ -15813,24 +15824,17 @@ pkg-up@^3.1.0: dependencies: find-up "^3.0.0" -playwright-chromium@1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/playwright-chromium/-/playwright-chromium-1.25.0.tgz#e1f1ead715e93e4eb01620ace9ea93d8e21329f5" - integrity sha512-FH9ho3noAWVStCJx4XW78+D8QW0A99WDp53DDkYeVdEpJqCmAIKHCSE6dl5XtaDKrZPYC1ZG5hGXQh1K5H/p+g== - dependencies: - playwright-core "1.25.0" +playwright-core@1.28.0: + version "1.28.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.28.0.tgz#61df5c714f45139cca07095eccb4891e520e06f2" + integrity sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA== -playwright-core@1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.25.0.tgz#54dc867c6c2cc5e4233905e249206a02914d14f1" - integrity sha512-kZ3Jwaf3wlu0GgU0nB8UMQ+mXFTqBIFz9h1svTlNduNKjnbPXFxw7mJanLVjqxHJRn62uBfmgBj93YHidk2N5Q== - -playwright@1.25.0: - version "1.25.0" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.25.0.tgz#a5e317c8c207b921e7da17507ef9ec2983367970" - integrity sha512-Z+pQNWI17Qx/tHhnmgMmPsptsisXpKgAnUvYv98kctlHUJaqMt2400P8kTw9vEPoC0xdxqu0JhxO7pDTmaaIKw== +playwright@1.28.0: + version "1.28.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.28.0.tgz#eaec2e607858bd4c0bd7434ac01042720e6a39e3" + integrity sha512-kyOXGc5y1mgi+hgEcCIyE1P1+JumLrxS09nFHo5sdJNzrucxPRAGwM4A2X3u3SDOfdgJqx61yIoR6Av+5plJPg== dependencies: - playwright-core "1.25.0" + playwright-core "1.28.0" posix-character-classes@^0.1.0: version "0.1.1" @@ -18551,12 +18555,12 @@ ts-loader@9.3.1: micromatch "^4.0.0" semver "^7.3.4" -ts-node@10.4: - version "10.4.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7" - integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A== +ts-node@10.9.1: + version "10.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== dependencies: - "@cspotcode/source-map-support" "0.7.0" + "@cspotcode/source-map-support" "^0.8.0" "@tsconfig/node10" "^1.0.7" "@tsconfig/node12" "^1.0.7" "@tsconfig/node14" "^1.0.0" @@ -18567,6 +18571,7 @@ ts-node@10.4: create-require "^1.1.0" diff "^4.0.1" make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" yn "3.1.1" ts-unused-exports@7.0.3: @@ -19004,6 +19009,11 @@ uuid@^8.0.0, uuid@^8.3.0, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + v8-compile-cache@^2.0.3: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"