From b4d34b804c65f9ff7c6b2893a3db3eb727080fa5 Mon Sep 17 00:00:00 2001 From: No-Cash-7970 <105998824+No-Cash-7970@users.noreply.github.com> Date: Thu, 9 Jan 2025 20:49:14 -0800 Subject: [PATCH] test(e2e): add examples and docs for end-to-end testing (#331) --- .gitignore | 6 + docs/fundamentals/supported-wallets.md | 2 +- docs/guides/end-to-end-testing.md | 103 ++++++++++++++ examples/e2e-tests/FakeAlgodResponses.ts | 132 ++++++++++++++++++ examples/e2e-tests/example.spec.ts | 42 ++++++ examples/nextjs/package.json | 3 +- examples/nextjs/playwright.config.ts | 75 ++++++++++ examples/nextjs/src/app/providers.tsx | 3 +- examples/nuxt/package.json | 3 +- examples/nuxt/playwright.config.ts | 75 ++++++++++ examples/nuxt/plugins/walletManager.client.ts | 3 +- examples/react-ts/package.json | 3 +- examples/react-ts/playwright.config.ts | 75 ++++++++++ examples/react-ts/src/App.tsx | 3 +- examples/solid-ts/package.json | 3 +- examples/solid-ts/playwright.config.ts | 75 ++++++++++ examples/solid-ts/src/App.tsx | 3 +- examples/vanilla-ts/package.json | 3 +- examples/vanilla-ts/playwright.config.ts | 75 ++++++++++ examples/vanilla-ts/src/main.ts | 3 +- examples/vue-ts/package.json | 3 +- examples/vue-ts/playwright.config.ts | 75 ++++++++++ examples/vue-ts/src/main.ts | 3 +- package.json | 2 + pnpm-lock.yaml | 66 +++++++-- 25 files changed, 814 insertions(+), 25 deletions(-) create mode 100644 docs/guides/end-to-end-testing.md create mode 100644 examples/e2e-tests/FakeAlgodResponses.ts create mode 100644 examples/e2e-tests/example.spec.ts create mode 100644 examples/nextjs/playwright.config.ts create mode 100644 examples/nuxt/playwright.config.ts create mode 100644 examples/react-ts/playwright.config.ts create mode 100644 examples/solid-ts/playwright.config.ts create mode 100644 examples/vanilla-ts/playwright.config.ts create mode 100644 examples/vue-ts/playwright.config.ts diff --git a/.gitignore b/.gitignore index 9e494df1..36567a8b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,9 @@ dist *.code-workspace .nvmrc coverage + +# Playwright +**/test-results/ +**/playwright-report/ +**/blob-report/ +**/playwright/.cache/ diff --git a/docs/fundamentals/supported-wallets.md b/docs/fundamentals/supported-wallets.md index 5c90e432..e8790928 100644 --- a/docs/fundamentals/supported-wallets.md +++ b/docs/fundamentals/supported-wallets.md @@ -130,7 +130,7 @@ KMD Documentation ## Mnemonic -The Mnemonic wallet provider is a specialized tool designed for testing purposes, particularly for integration tests. It should only be used in a test environment for running automated tests that require wallet interactions. (Documentation coming soon) +The Mnemonic wallet provider is a specialized tool designed for testing purposes, particularly for end-to-end and integration tests. It should only be used in a test environment for running automated tests that require wallet interactions. Refer to the [End-to-End Testing guide](../guides/end-to-end-testing.md) for more information about how to use the Mnemonic wallet provider for automated end-to-end testing. {% hint style="danger" %} **Warning:** The Mnemonic wallet provider is strictly for testing and development purposes. It will not function if the active network is set to MainNet. Any accounts used with the Mnemonic wallet should be considered insecure and should never hold MainNet ALGO or ASAs with any real value. diff --git a/docs/guides/end-to-end-testing.md b/docs/guides/end-to-end-testing.md new file mode 100644 index 00000000..140a0649 --- /dev/null +++ b/docs/guides/end-to-end-testing.md @@ -0,0 +1,103 @@ +--- +description: Guide for end-to-end testing +--- + +# 🎯 End-to-End Testing + +End-to-end (E2E) testing consists of creating and running automated tests that simulate the user going through various usage scenarios of the software from start (one end) to finish (the other end).[^1] E2E testing is also known as "system testing" because the tests are intended to test the system (software) as a whole.[^2] It does not replace unit testing, integration testing or manual testing. Instead, E2E testing should complement other types of testing. + +In web development, an E2E test framework controls a web browser to test the web application. [Selenium WebDriver](https://www.selenium.dev/documentation/webdriver/), [Playwright](https://playwright.dev/) and [Cypress](https://www.cypress.io/) are common E2E test frameworks for web development. The best way of using an E2E test framework depends on the software requirements, code structure, and what other development tools are used. + +## Wallet for E2E Testing + +Most wallet applications, such as [Defly](../fundamentals/supported-wallets.md#defly) or [Pera](../fundamentals/supported-wallets.md#pera), do not allow for automated testing of decentralized apps (dApps) because they designed to require interaction from the human user. Requiring interaction from the human user is a critical part of the security of those wallet applications provide for users. However, this security is not needed for testing. + +Fortunately, the [Mnemonic wallet provider](../fundamentals/supported-wallets.md#mnemonic) solves this problem, but at a heavy cost to the security of the accounts used. The Memonic wallet provider allows for an account's mnemonic ("seed phrase") to be entered directly. To automate the interaction with the Mnemonic wallet, a mnemonic **used only for testing** is often placed within the test _in plain text_. + +### Setting Up Mnemonic Wallet + +{% hint style="danger" %} +**Warning:** The Mnemonic wallet provider is strictly for testing and development purposes. It will not function if the active network is set to MainNet. Any accounts used with the Mnemonic wallet should be considered insecure and should never hold MainNet ALGO or ASAs with any real value. +{% endhint %} + +To enable the Mnemonic wallet provider, add it to the list of wallets in the use-wallet [configuration](../fundamentals/get-started/configuration.md). The configuration should look something like the following code: + +```typescript +import { NetworkId, WalletId, WalletManager } from '@txnlab/use-wallet' + +const walletManager = new WalletManager({ + wallets: [ + WalletId.DEFLY, + WalletId.PERA, + { + id: WalletId.LUTE, + options: { siteName: '' } + }, + WalletId.MNEMONIC, // <-- Add this + ], + network: NetworkId.TESTNET +}) +``` + +#### Persisting to Storage + +By default for security reasons, the Mnemonic wallet provider does not save the mnemonic into local storage after it is entered and accepted. As a result, the wallet session is lost when reloading or exiting the page. The user needs to reconnect to the wallet by entering the mnemonic every time the page loads or reloads. This behavior is unlike most of the other wallet providers where the wallet session is immediately loaded and resumed when the loading the page. + +The default behavior can be changed, but at an additional cost of security of the mnemonic and the account it is for. If you need the behavior of the Mnemonic wallet provider to be similar to the behavior of most of the other wallet providers in your tests, then enable persisting the mnemonic to storage. This way, **the mnemonic is stored into local storage indefinitely** and the saved wallet session can be loaded and resumed. The user enters the mnemonic once and only needs to enter it again after explicitly disconnecting from the wallet. + +{% hint style="danger" %} +**Warning:** The mnemonic is stored into the local storage **in plain text**. Any mnemonic entered with persisting to storage enabled should be considered as compromised. Persisting the mnemonic to storage is strictly for testing and development purposes. +{% endhint %} + +To enable persisting the mnemonic to storage, set the `persistToStorage` option for the Mnemonic wallet provider in the use-wallet [configuration](../fundamentals/get-started/configuration.md): + +```typescript +import { NetworkId, WalletId, WalletManager } from '@txnlab/use-wallet' + +const walletManager = new WalletManager({ + wallets: [ + WalletId.DEFLY, + WalletId.PERA, + { + id: WalletId.LUTE, + options: { siteName: '' } + }, + { + id: WalletId.MNEMONIC, + options: { persistToStorage: true } // <-- Set this + }, + ], + network: NetworkId.TESTNET +}) +``` + +## Testing with Playwright + +[Playwright](https://playwright.dev/) can be used to test a web app built with any library or framework, such as React, Vue, Solid.js, or vanilla Javascript (no library or framework). + +### Setting Up Playwright + +To install Playwright, follow the instructions in Playwright's documentation: + +After installing Playwright, you can tweak its configuration for your project. There is an example `playwright.config.ts` file for each use-wallet example (in the [`examples/`](https://github.com/TxnLab/use-wallet/tree/main/examples) folder). For more information about how to configure Playwright, refer to its documentation: + +### Writing and Running Playwright Tests + +Writing and running Playwright tests is the same for any web app, with or without use-wallet. Learn how to write and run tests in Playwright's documentation: . + +There is an example Playwright E2E test in the [`examples/e2e-tests/` folder](https://github.com/TxnLab/use-wallet/tree/main/examples/e2e-tests). This single test can be run for any of the examples. To run the E2E test for an example, go to the chosen example folder (`vanilla-ts`, `react-ts`, etc.) and run `pnpm test`. For example, to run the E2E test for the vanilla TypeScript example, do the following: + +```bash +cd examples/vanilla-ts +pnpm test:e2e +``` + +### Best Practices for Testing with Playwright + +- For more consistent and predictable tests, mock the responses of API requests. Mocking also prevents overwhelming the API provider (like [Nodely](https://nodely.io/)) with test requests. An example of mocking responses to Algorand node (Algod) API requests is in the [`examples/e2e-tests/` folder](https://github.com/TxnLab/use-wallet/tree/main/examples/e2e-tests). +- More best practices: + +## References + +[^1]: +[^2]: diff --git a/examples/e2e-tests/FakeAlgodResponses.ts b/examples/e2e-tests/FakeAlgodResponses.ts new file mode 100644 index 00000000..0a7fec27 --- /dev/null +++ b/examples/e2e-tests/FakeAlgodResponses.ts @@ -0,0 +1,132 @@ +/** @file Algod node responses used to fake responses to requests */ + +import { type Page } from '@playwright/test' + +/* NOTE: + * It is best for all test responses be exact data of actual responses from an Algod node. Doing so + * makes the fake responses as close as possible to what would most likely happen in the real world. + */ + +// GET /v2/transactions/params on testnet +export const suggParams = JSON.stringify({ + 'consensus-version': + 'https://github.com/algorandfoundation/specs/tree/925a46433742afb0b51bb939354bd907fa88bf95', + fee: 0, + 'genesis-hash': 'SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=', + 'genesis-id': 'testnet-v1.0', + 'last-round': 44440857, + 'min-fee': 1000 +}) + +// POST /v2/transactions on testnet +export const sendTxn = JSON.stringify({ + txId: 'NC63ESPZOQI6P6DSVZWG5K2FJFFKI3VAZITE5KRW5SV5GXQDIXMA' +}) + +// GET /v2/status on testnet +export const nodeStatus = JSON.stringify({ + catchpoint: '', + 'catchpoint-acquired-blocks': 0, + 'catchpoint-processed-accounts': 0, + 'catchpoint-processed-kvs': 0, + 'catchpoint-total-accounts': 0, + 'catchpoint-total-blocks': 0, + 'catchpoint-total-kvs': 0, + 'catchpoint-verified-accounts': 0, + 'catchpoint-verified-kvs': 0, + 'catchup-time': 0, + 'last-catchpoint': '', + 'last-round': 44440860, + 'last-version': + 'https://github.com/algorandfoundation/specs/tree/925a46433742afb0b51bb939354bd907fa88bf95', + 'next-version': + 'https://github.com/algorandfoundation/specs/tree/925a46433742afb0b51bb939354bd907fa88bf95', + 'next-version-round': 44440861, + 'next-version-supported': true, + 'stopped-at-unsupported-round': false, + 'time-since-last-round': 1753631441 +}) + +// GET /v2/transactions/pending/NC63ESPZOQI6P6DSVZWG5K2FJFFKI3VAZITE5KRW5SV5GXQDIXMA?format=msgpack +// content-type: application/msgpack +// on testnet +export const pendingTxn1 = Buffer.from( + 'gqpwb29sLWVycm9yoKN0eG6Co3NpZ8RAiG8Nhiruhncf2es5ozYnVfiFY4EAvLiGODPZf2n0eI4X1VtBZScF+3WQwn2RsIkdMyHbG0FNb5sQ93R03WTgAqN0eG6Io2ZlZc0D6KJmds4Cph0Zo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToiomx2zgKmIQGjcmN2xCDZdlfb2YQwPyRi+VSoHaataICjLqI7Z8kkOGIA5HFvlqNzbmTEINl2V9vZhDA/JGL5VKgdpq1ogKMuojtnySQ4YgDkcW+WpHR5cGWjcGF5', + 'base64' +) + +// GET /v2/transactions/pending/NC63ESPZOQI6P6DSVZWG5K2FJFFKI3VAZITE5KRW5SV5GXQDIXMA?format=msgpack +// content-type: application/msgpack +// on testnet +export const pendingTxn2 = Buffer.from( + 'g69jb25maXJtZWQtcm91bmTOAqYdHqpwb29sLWVycm9yoKN0eG6Co3NpZ8RAiG8Nhiruhncf2es5ozYnVfiFY4EAvLiGODPZf2n0eI4X1VtBZScF+3WQwn2RsIkdMyHbG0FNb5sQ93R03WTgAqN0eG6Io2ZlZc0D6KJmds4Cph0Zo2dlbqx0ZXN0bmV0LXYxLjCiZ2jEIEhjtRiks8hOyBDyLU8QgcsPcfBZp6wg3sYvf3DlCToiomx2zgKmIQGjcmN2xCDZdlfb2YQwPyRi+VSoHaataICjLqI7Z8kkOGIA5HFvlqNzbmTEINl2V9vZhDA/JGL5VKgdpq1ogKMuojtnySQ4YgDkcW+WpHR5cGWjcGF5', + 'base64' +) + +// GET /v2/status/wait-for-block-after/44440861 +export const waitForBlock = JSON.stringify({ + catchpoint: '', + 'catchpoint-acquired-blocks': 0, + 'catchpoint-processed-accounts': 0, + 'catchpoint-processed-kvs': 0, + 'catchpoint-total-accounts': 0, + 'catchpoint-total-blocks': 0, + 'catchpoint-total-kvs': 0, + 'catchpoint-verified-accounts': 0, + 'catchpoint-verified-kvs': 0, + 'catchup-time': 0, + 'last-catchpoint': '', + 'last-round': 44440862, + 'last-version': + 'https://github.com/algorandfoundation/specs/tree/925a46433742afb0b51bb939354bd907fa88bf95', + 'next-version': + 'https://github.com/algorandfoundation/specs/tree/925a46433742afb0b51bb939354bd907fa88bf95', + 'next-version-round': 44440863, + 'next-version-supported': true, + 'stopped-at-unsupported-round': false, + 'time-since-last-round': 567756 +}) + +/** Fake the responses to a series of Algod requests for sending a simple transaction. The faked + * responses are actual responses from an Algod node when sending a real transaction on TestNet. + * + * Faking the responses of an Algod node makes the tests more consistent, puts less strain on an + * actual Algod node, and removes the requirement of a real Algod node being available before + * running the tests. + * + * NOTE: For the faked responses to work, this function must be run after the page is loaded (e.g. + * after `page.goto("/")`). + */ +export async function fakeTxnResponses(page: Page) { + await page.route('*/**/v2/transactions/params', async (route) => { + await route.fulfill({ body: suggParams, contentType: 'application/json' }) + }) + + await page.route('*/**/v2/transactions', async (route, request) => { + if (request.method() === 'OPTIONS') { + await route.fulfill() + } else { + await route.fulfill({ body: sendTxn, contentType: 'application/json' }) + } + }) + + await page.route('*/**/v2/status', async (route) => { + await route.fulfill({ body: nodeStatus, contentType: 'application/json' }) + }) + + let pendingTxnCount = 0 + await page.route('*/**/v2/transactions/pending/*', async (route) => { + if (pendingTxnCount === 0) { + // First time + await route.fulfill({ body: pendingTxn1, contentType: 'application/msgpack' }) + pendingTxnCount++ + } else { + // Second time + await route.fulfill({ body: pendingTxn2, contentType: 'application/msgpack' }) + } + }) + + await page.route('*/**/v2/status/wait-for-block-after/*', async (route) => { + await route.fulfill({ body: waitForBlock, contentType: 'application/json' }) + }) +} diff --git a/examples/e2e-tests/example.spec.ts b/examples/e2e-tests/example.spec.ts new file mode 100644 index 00000000..650f2b6e --- /dev/null +++ b/examples/e2e-tests/example.spec.ts @@ -0,0 +1,42 @@ +import { test, expect } from '@playwright/test' +import { fakeTxnResponses } from './FakeAlgodResponses' + +test('it works', async ({ page }) => { + // Load and set up the page + await page.goto('/') + await fakeTxnResponses(page) + // Whenever a prompt appears, enter the mnemonic + page.on('dialog', (dialog) => + dialog.accept( + // !! WARN !! + // THIS ACCOUNT AND ITS MNEMONIC ARE COMPROMISED. + // They are to be used for testing only. + // !! WARN !! + 'sugar bronze century excuse animal jacket what rail biology symbol want craft annual soul increase question army win execute slim girl chief exhaust abstract wink' + ) + ) + + // Check mnemonic wallet is activated + await expect(page.getByRole('heading', { name: 'Mnemonic' })).toBeVisible() + + // Click the "Connect" button for the Mnemonic wallet + await page + .locator('.wallet-group', { + has: page.locator('h4', { hasText: 'Mnemonic' }) + }) + .getByRole('button', { name: 'Connect', exact: true }) + .click() + + // Check wallet is connected + await expect(page.getByRole('heading', { name: 'Mnemonic [active]' })).toBeVisible() + await expect(page.getByRole('combobox')).toHaveValue( + '3F3FPW6ZQQYD6JDC7FKKQHNGVVUIBIZOUI5WPSJEHBRABZDRN6LOTBMFEY' + ) + + // Click button to send a transaction + await page.getByRole('button', { name: 'Send Transaction' }).click() + + // There is no visual feedback of the outcome of sending the transaction. Only a message is + // printed in the console. So, we will wait a little bit for transaction to complete + await page.waitForTimeout(500) +}) diff --git a/examples/nextjs/package.json b/examples/nextjs/package.json index 28d2cd3b..44c72ff5 100644 --- a/examples/nextjs/package.json +++ b/examples/nextjs/package.json @@ -5,7 +5,8 @@ "build": "next build", "start": "next start", "lint": "next lint", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "test:e2e": "playwright test" }, "dependencies": { "@blockshake/defly-connect": "^1.1.6", diff --git a/examples/nextjs/playwright.config.ts b/examples/nextjs/playwright.config.ts new file mode 100644 index 00000000..5e34574e --- /dev/null +++ b/examples/nextjs/playwright.config.ts @@ -0,0 +1,75 @@ +import { defineConfig, devices } from '@playwright/test' + +// Use process.env.PORT by default and fallback to port 3000 +const PORT = process.env.PORT || 3000 + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: '../e2e-tests', + /* 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: 'list', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: `http://localhost:${PORT}`, + + /* 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'] } + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] } + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] } + } + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'pnpm build && pnpm start', + url: `http://localhost:${PORT}`, + reuseExistingServer: !process.env.CI, + stdout: 'pipe' + } +}) diff --git a/examples/nextjs/src/app/providers.tsx b/examples/nextjs/src/app/providers.tsx index cf4eaf61..fdc51a01 100644 --- a/examples/nextjs/src/app/providers.tsx +++ b/examples/nextjs/src/app/providers.tsx @@ -24,7 +24,8 @@ const walletManager = new WalletManager({ { id: WalletId.MAGIC, options: { apiKey: 'pk_live_D17FD8D89621B5F3' } - } + }, + WalletId.MNEMONIC ], network: NetworkId.TESTNET }) diff --git a/examples/nuxt/package.json b/examples/nuxt/package.json index 271fdbdc..2c328c74 100644 --- a/examples/nuxt/package.json +++ b/examples/nuxt/package.json @@ -8,7 +8,8 @@ "preview": "nuxt preview", "postinstall": "nuxt prepare", "lint": "eslint -c \"../../.eslintrc.json\" \"**/*.{js,ts}\"", - "typecheck": "npx nuxi typecheck" + "typecheck": "npx nuxi typecheck", + "test:e2e": "playwright test" }, "dependencies": { "@algorandfoundation/liquid-auth-use-wallet-client": "1.1.0", diff --git a/examples/nuxt/playwright.config.ts b/examples/nuxt/playwright.config.ts new file mode 100644 index 00000000..f75e8b51 --- /dev/null +++ b/examples/nuxt/playwright.config.ts @@ -0,0 +1,75 @@ +import { defineConfig, devices } from '@playwright/test' + +// Use process.env.PORT by default and fallback to port 3000 +const PORT = process.env.PORT || 3000 + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: '../e2e-tests', + /* 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: 'list', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: `http://localhost:${PORT}`, + + /* 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'] } + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] } + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] } + } + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'pnpm build && pnpm preview', + url: `http://localhost:${PORT}`, + reuseExistingServer: !process.env.CI, + stdout: 'pipe' + } +}) diff --git a/examples/nuxt/plugins/walletManager.client.ts b/examples/nuxt/plugins/walletManager.client.ts index 1333131a..6220b773 100644 --- a/examples/nuxt/plugins/walletManager.client.ts +++ b/examples/nuxt/plugins/walletManager.client.ts @@ -25,7 +25,8 @@ export default defineNuxtPlugin((nuxtApp) => { { id: WalletId.MAGIC, options: { apiKey: 'pk_live_D17FD8D89621B5F3' } - } + }, + WalletId.MNEMONIC ], network: NetworkId.TESTNET }) diff --git a/examples/react-ts/package.json b/examples/react-ts/package.json index 6a3ad7ee..a3cb69d7 100644 --- a/examples/react-ts/package.json +++ b/examples/react-ts/package.json @@ -6,7 +6,8 @@ "preview": "vite preview", "build": "tsc && vite build", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "test:e2e": "playwright test" }, "dependencies": { "@algorandfoundation/liquid-auth-use-wallet-client": "1.1.0", diff --git a/examples/react-ts/playwright.config.ts b/examples/react-ts/playwright.config.ts new file mode 100644 index 00000000..ca63ed6d --- /dev/null +++ b/examples/react-ts/playwright.config.ts @@ -0,0 +1,75 @@ +import { defineConfig, devices } from '@playwright/test' + +// Use process.env.PORT by default and fallback to port 4173 +const PORT = process.env.PORT || 4173 + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: '../e2e-tests', + /* 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: 'list', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: `http://localhost:${PORT}`, + + /* 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'] } + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] } + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] } + } + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'pnpm build && pnpm preview', + url: `http://localhost:${PORT}`, + reuseExistingServer: !process.env.CI, + stdout: 'pipe' + } +}) diff --git a/examples/react-ts/src/App.tsx b/examples/react-ts/src/App.tsx index 7ded7944..b851dcd4 100644 --- a/examples/react-ts/src/App.tsx +++ b/examples/react-ts/src/App.tsx @@ -27,7 +27,8 @@ const walletManager = new WalletManager({ { id: WalletId.MAGIC, options: { apiKey: 'pk_live_D17FD8D89621B5F3' } - } + }, + WalletId.MNEMONIC ], network: NetworkId.TESTNET }) diff --git a/examples/solid-ts/package.json b/examples/solid-ts/package.json index 91e39903..0f4fdcaa 100644 --- a/examples/solid-ts/package.json +++ b/examples/solid-ts/package.json @@ -7,7 +7,8 @@ "preview": "vite preview", "lint": "eslint -c \"../../.eslintrc.json\" \"**/*.{js,ts}\"", "prettier": "prettier --check \"**/*.{js,ts}\"", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "test:e2e": "playwright test" }, "dependencies": { "@algorandfoundation/liquid-auth-use-wallet-client": "1.1.0", diff --git a/examples/solid-ts/playwright.config.ts b/examples/solid-ts/playwright.config.ts new file mode 100644 index 00000000..ca63ed6d --- /dev/null +++ b/examples/solid-ts/playwright.config.ts @@ -0,0 +1,75 @@ +import { defineConfig, devices } from '@playwright/test' + +// Use process.env.PORT by default and fallback to port 4173 +const PORT = process.env.PORT || 4173 + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: '../e2e-tests', + /* 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: 'list', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: `http://localhost:${PORT}`, + + /* 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'] } + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] } + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] } + } + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'pnpm build && pnpm preview', + url: `http://localhost:${PORT}`, + reuseExistingServer: !process.env.CI, + stdout: 'pipe' + } +}) diff --git a/examples/solid-ts/src/App.tsx b/examples/solid-ts/src/App.tsx index 7b66aa82..965eecf1 100644 --- a/examples/solid-ts/src/App.tsx +++ b/examples/solid-ts/src/App.tsx @@ -27,7 +27,8 @@ const walletManager = new WalletManager({ { id: WalletId.MAGIC, options: { apiKey: 'pk_live_D17FD8D89621B5F3' } - } + }, + WalletId.MNEMONIC ], network: NetworkId.TESTNET }) diff --git a/examples/vanilla-ts/package.json b/examples/vanilla-ts/package.json index 67345976..f9a6fe21 100644 --- a/examples/vanilla-ts/package.json +++ b/examples/vanilla-ts/package.json @@ -6,7 +6,8 @@ "build": "tsc && vite build", "preview": "vite preview", "lint": "eslint -c \"../../.eslintrc.json\" \"**/*.{js,ts}\"", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "test:e2e": "playwright test" }, "devDependencies": { "@walletconnect/types": "2.17.2", diff --git a/examples/vanilla-ts/playwright.config.ts b/examples/vanilla-ts/playwright.config.ts new file mode 100644 index 00000000..ca63ed6d --- /dev/null +++ b/examples/vanilla-ts/playwright.config.ts @@ -0,0 +1,75 @@ +import { defineConfig, devices } from '@playwright/test' + +// Use process.env.PORT by default and fallback to port 4173 +const PORT = process.env.PORT || 4173 + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: '../e2e-tests', + /* 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: 'list', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: `http://localhost:${PORT}`, + + /* 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'] } + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] } + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] } + } + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'pnpm build && pnpm preview', + url: `http://localhost:${PORT}`, + reuseExistingServer: !process.env.CI, + stdout: 'pipe' + } +}) diff --git a/examples/vanilla-ts/src/main.ts b/examples/vanilla-ts/src/main.ts index 36b8254c..c91fe645 100644 --- a/examples/vanilla-ts/src/main.ts +++ b/examples/vanilla-ts/src/main.ts @@ -28,7 +28,8 @@ const walletManager = new WalletManager({ { id: WalletId.MAGIC, options: { apiKey: 'pk_live_D17FD8D89621B5F3' } - } + }, + WalletId.MNEMONIC ], network: NetworkId.TESTNET }) diff --git a/examples/vue-ts/package.json b/examples/vue-ts/package.json index 61f75930..bcb80c56 100644 --- a/examples/vue-ts/package.json +++ b/examples/vue-ts/package.json @@ -6,7 +6,8 @@ "preview": "vite preview", "build": "vue-tsc && vite build", "lint": "eslint -c \"../../.eslintrc.json\" \"**/*.{js,ts}\"", - "typecheck": "vue-tsc --noEmit" + "typecheck": "vue-tsc --noEmit", + "test:e2e": "playwright test" }, "dependencies": { "@algorandfoundation/liquid-auth-use-wallet-client": "1.1.0", diff --git a/examples/vue-ts/playwright.config.ts b/examples/vue-ts/playwright.config.ts new file mode 100644 index 00000000..ca63ed6d --- /dev/null +++ b/examples/vue-ts/playwright.config.ts @@ -0,0 +1,75 @@ +import { defineConfig, devices } from '@playwright/test' + +// Use process.env.PORT by default and fallback to port 4173 +const PORT = process.env.PORT || 4173 + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: '../e2e-tests', + /* 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: 'list', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + baseURL: `http://localhost:${PORT}`, + + /* 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'] } + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] } + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] } + } + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { ...devices['Pixel 5'] }, + // }, + // { + // name: 'Mobile Safari', + // use: { ...devices['iPhone 12'] }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { ...devices['Desktop Edge'], channel: 'msedge' }, + // }, + // { + // name: 'Google Chrome', + // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, + // }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'pnpm build && pnpm preview', + url: `http://localhost:${PORT}`, + reuseExistingServer: !process.env.CI, + stdout: 'pipe' + } +}) diff --git a/examples/vue-ts/src/main.ts b/examples/vue-ts/src/main.ts index 98295e5c..36f46a0b 100644 --- a/examples/vue-ts/src/main.ts +++ b/examples/vue-ts/src/main.ts @@ -28,7 +28,8 @@ app.use(WalletManagerPlugin, { { id: WalletId.MAGIC, options: { apiKey: 'pk_live_D17FD8D89621B5F3' } - } + }, + WalletId.MNEMONIC ], network: NetworkId.TESTNET }) diff --git a/package.json b/package.json index ade29cef..e2ab7cdb 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,10 @@ "example:nuxt": "pnpm --filter \"./examples/nuxt\" dev" }, "devDependencies": { + "@playwright/test": "1.49.1", "@testing-library/jest-dom": "6.6.3", "@testing-library/react": "16.0.1", + "@types/node": "20.11.30", "@typescript-eslint/eslint-plugin": "8.16.0", "@typescript-eslint/parser": "8.16.0", "@vitejs/plugin-react": "4.3.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e6cc8e58..d03fa28a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,12 +8,18 @@ importers: .: devDependencies: + '@playwright/test': + specifier: 1.49.1 + version: 1.49.1 '@testing-library/jest-dom': specifier: 6.6.3 version: 6.6.3 '@testing-library/react': specifier: 16.0.1 version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@types/node': + specifier: 20.11.30 + version: 20.11.30 '@typescript-eslint/eslint-plugin': specifier: 8.16.0 version: 8.16.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) @@ -82,7 +88,7 @@ importers: version: 1.4.1 next: specifier: 14.2.18 - version: 14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 14.2.18(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: specifier: 18.3.1 version: 18.3.1 @@ -562,9 +568,9 @@ packages: '@algorandfoundation/liquid-auth-use-wallet-client@1.1.0': resolution: {integrity: sha512-pGTHq9RXT4qN81mF0TGcTl+EBvnOiYGI42BHkIHDF43StogM0ueFRh/qvO6ei+aYRxKaFogqfhgB1twm9afcuQ==} - '@algorandfoundation/liquid-client@https://codeload.github.com/algorandfoundation/liquid-auth-js/tar.gz/c89fe0f17c4d16ed17299d7f524f044a2687a680': - resolution: {tarball: https://codeload.github.com/algorandfoundation/liquid-auth-js/tar.gz/c89fe0f17c4d16ed17299d7f524f044a2687a680} - version: 0.0.1 + '@algorandfoundation/liquid-client@https://codeload.github.com/algorandfoundation/liquid-auth-js/tar.gz/0958cb96627b5ead1ef5cfbdc4f47fe43a2e4908': + resolution: {tarball: https://codeload.github.com/algorandfoundation/liquid-auth-js/tar.gz/0958cb96627b5ead1ef5cfbdc4f47fe43a2e4908} + version: 1.0.0-canary.3 '@algorandfoundation/provider@https://codeload.github.com/algorandfoundation/wallet-provider-ts/tar.gz/28c80f5b9e0259b8e83e65c65d802d8123de9046': resolution: {tarball: https://codeload.github.com/algorandfoundation/wallet-provider-ts/tar.gz/28c80f5b9e0259b8e83e65c65d802d8123de9046} @@ -1496,6 +1502,11 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@playwright/test@1.49.1': + resolution: {integrity: sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==} + engines: {node: '>=18'} + hasBin: true + '@polka/url@1.0.0-next.28': resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} @@ -3479,6 +3490,11 @@ packages: fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -4712,6 +4728,16 @@ packages: pkg-types@1.2.1: resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} + playwright-core@1.49.1: + resolution: {integrity: sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.49.1: + resolution: {integrity: sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==} + engines: {node: '>=18'} + hasBin: true + pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -6393,7 +6419,7 @@ snapshots: '@algorandfoundation/liquid-auth-use-wallet-client@1.1.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: - '@algorandfoundation/liquid-client': https://codeload.github.com/algorandfoundation/liquid-auth-js/tar.gz/c89fe0f17c4d16ed17299d7f524f044a2687a680(bufferutil@4.0.8)(utf-8-validate@5.0.10) + '@algorandfoundation/liquid-client': https://codeload.github.com/algorandfoundation/liquid-auth-js/tar.gz/0958cb96627b5ead1ef5cfbdc4f47fe43a2e4908(bufferutil@4.0.8)(utf-8-validate@5.0.10) '@algorandfoundation/provider': https://codeload.github.com/algorandfoundation/wallet-provider-ts/tar.gz/28c80f5b9e0259b8e83e65c65d802d8123de9046 algosdk: 2.9.0 cbor-x: 1.6.0 @@ -6403,7 +6429,7 @@ snapshots: - supports-color - utf-8-validate - '@algorandfoundation/liquid-client@https://codeload.github.com/algorandfoundation/liquid-auth-js/tar.gz/c89fe0f17c4d16ed17299d7f524f044a2687a680(bufferutil@4.0.8)(utf-8-validate@5.0.10)': + '@algorandfoundation/liquid-client@https://codeload.github.com/algorandfoundation/liquid-auth-js/tar.gz/0958cb96627b5ead1ef5cfbdc4f47fe43a2e4908(bufferutil@4.0.8)(utf-8-validate@5.0.10)': dependencies: '@algorandfoundation/qr-code-styling': https://codeload.github.com/algorandfoundation/qr-code-styling/tar.gz/ce8541ee1cb3b0ab2acd9926f3092d4ab217e276 canvas: 2.11.2 @@ -7502,6 +7528,10 @@ snapshots: '@pkgr/core@0.1.1': {} + '@playwright/test@1.49.1': + dependencies: + playwright: 1.49.1 + '@polka/url@1.0.0-next.28': {} '@redocly/ajv@8.11.2': @@ -9802,7 +9832,7 @@ snapshots: '@typescript-eslint/parser': 8.16.0(eslint@8.57.1)(typescript@5.6.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) eslint-plugin-react: 7.37.2(eslint@8.57.1) @@ -9826,7 +9856,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1): + eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7(supports-color@9.4.0) @@ -9842,14 +9872,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: '@typescript-eslint/parser': 8.16.0(eslint@8.57.1)(typescript@5.6.3) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@8.57.1) + eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color @@ -9864,7 +9894,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.16.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -10218,6 +10248,9 @@ snapshots: fs.realpath@1.0.0: {} + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -11130,7 +11163,7 @@ snapshots: next-tick@1.1.0: {} - next@14.2.18(@babel/core@7.26.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + next@14.2.18(@babel/core@7.26.0)(@playwright/test@1.49.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@next/env': 14.2.18 '@swc/helpers': 0.5.5 @@ -11151,6 +11184,7 @@ snapshots: '@next/swc-win32-arm64-msvc': 14.2.18 '@next/swc-win32-ia32-msvc': 14.2.18 '@next/swc-win32-x64-msvc': 14.2.18 + '@playwright/test': 1.49.1 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros @@ -11660,6 +11694,14 @@ snapshots: mlly: 1.7.3 pathe: 1.1.2 + playwright-core@1.49.1: {} + + playwright@1.49.1: + dependencies: + playwright-core: 1.49.1 + optionalDependencies: + fsevents: 2.3.2 + pluralize@8.0.0: {} pngjs@5.0.0: {}