From a0ac410c73879cdfb3e0de5bce21fb5d528cc8b7 Mon Sep 17 00:00:00 2001 From: Roland Moldovan Date: Thu, 27 Nov 2025 14:48:08 +0200 Subject: [PATCH 01/13] Add E2E tests for provider connection and transaction signing; remove Cypress assets/tests --- .github/workflows/run-merge-e2e-tests.yml | 61 +++ .gitignore | 11 +- cypress/assets/globalData.ts | 4 - cypress/assets/index.ts | 1 - cypress/assets/testKeystore.json | 19 - cypress/constants/enums.ts | 38 -- cypress/constants/globalLinks.ts | 1 - .../BatchTransactions/BatchTransactions.cy.ts | 25 -- .../cancelBatchTransactions.cy.ts | 23 -- cypress/e2e/BatchTransactions/helpers.ts | 32 -- cypress/e2e/SCTransactions/SCActions.ts | 48 --- .../e2e/SCTransactions/SCTransaction.cy.ts | 45 --- .../e2e/SCTransactions/SCTransactionData.ts | 20 - cypress/e2e/Send/Send.cy.ts | 34 -- cypress/e2e/SignMessage/SignMessage.cy.ts | 39 -- cypress/e2e/Unlock/Unlock.cy.ts | 17 - cypress/support/commands.ts | 70 ---- cypress/support/e2e.ts | 1 - cypress/support/index.ts | 15 - package.json | 9 +- playwright.config.ts | 75 ++++ tests/config.ts | 14 + tests/connectWallet/memoryProvider.spec.ts | 30 ++ tests/connectWallet/metaMask.spec.ts | 94 +++++ tests/connectWallet/webWallet.spec.ts | 61 +++ tests/support/fs/downloadFileFromUrl.ts | 63 ++++ tests/support/fs/ensureDirectoryExists.ts | 9 + tests/support/fs/readValueFromFile.ts | 13 + tests/support/fs/writeValueToFile.ts | 37 ++ tests/support/metaMask/constants.ts | 7 + tests/support/metaMask/createPassword.ts | 43 +++ tests/support/metaMask/downloadMetaMask.ts | 55 +++ .../metaMask/fillSecretRecoveryPhrase.ts | 50 +++ tests/support/metaMask/handleMetaMaskSnap.ts | 150 ++++++++ tests/support/metaMask/handleMetrics.ts | 36 ++ tests/support/metaMask/importWallet.ts | 160 ++++++++ tests/support/metaMask/loadExtension.ts | 123 ++++++ tests/support/metaMask/prepareExtension.ts | 29 ++ tests/support/metaMask/setupMetaMaskWallet.ts | 113 ++++++ tests/support/metaMask/unzipArchive.ts | 81 ++++ tests/support/metaMask/waitForMetaMaskLoad.ts | 92 +++++ tests/support/template/checkBalanceUpdate.ts | 53 +++ tests/support/template/checkButtonStatus.ts | 27 ++ .../template/checkClipboardContains.ts | 41 ++ .../template/checkConnectionToWallet.ts | 12 + .../template/confirmPrivateKeyTransaction.ts | 10 + .../template/confirmWalletTransaction.ts | 38 ++ .../template/connectInMemoryProvider.ts | 32 ++ tests/support/template/connectWebWallet.ts | 120 ++++++ tests/support/template/constants.ts | 25 ++ .../template/extractBalanceFromContainer.ts | 39 ++ .../support/template/getPageAndWaitForLoad.ts | 78 ++++ tests/support/template/globalSetup.ts | 95 +++++ tests/support/template/handlePingPong.ts | 36 ++ tests/support/template/index.ts | 51 +++ tests/support/template/loadLocalEnv.ts | 17 + .../template/navigateToConnectWallet.ts | 18 + .../template/parseTransactionsTable.ts | 340 +++++++++++++++++ .../template/pasteStringFromClipboard.ts | 10 + .../support/template/signBatchTransactions.ts | 14 + tests/support/template/testIdSelector.ts | 7 + tests/support/template/testdata.ts | 119 ++++++ tests/support/template/types.ts | 183 +++++++++ .../template/waitForToastToBeClosed.ts | 7 + .../template/waitForToastToBeDisplayed.ts | 7 + .../template/waitForTransactionToastToShow.ts | 46 +++ tests/support/template/waitUntilStable.ts | 21 ++ tests/templateActions/nativeAuth.spec.ts | 56 +++ tests/templateActions/pingAndPongAbi.spec.ts | 104 +++++ .../templateActions/signAndSendBatch.spec.ts | 93 +++++ tests/templateActions/signMessage.spec.ts | 70 ++++ tests/templateActions/swapAndLock.ts | 95 +++++ yarn.lock | 354 +++++++++++++++++- 73 files changed, 3627 insertions(+), 439 deletions(-) create mode 100644 .github/workflows/run-merge-e2e-tests.yml delete mode 100644 cypress/assets/globalData.ts delete mode 100644 cypress/assets/index.ts delete mode 100644 cypress/assets/testKeystore.json delete mode 100644 cypress/constants/enums.ts delete mode 100644 cypress/constants/globalLinks.ts delete mode 100644 cypress/e2e/BatchTransactions/BatchTransactions.cy.ts delete mode 100644 cypress/e2e/BatchTransactions/cancelBatchTransactions.cy.ts delete mode 100644 cypress/e2e/BatchTransactions/helpers.ts delete mode 100644 cypress/e2e/SCTransactions/SCActions.ts delete mode 100644 cypress/e2e/SCTransactions/SCTransaction.cy.ts delete mode 100644 cypress/e2e/SCTransactions/SCTransactionData.ts delete mode 100644 cypress/e2e/Send/Send.cy.ts delete mode 100644 cypress/e2e/SignMessage/SignMessage.cy.ts delete mode 100644 cypress/e2e/Unlock/Unlock.cy.ts delete mode 100644 cypress/support/commands.ts delete mode 100644 cypress/support/e2e.ts delete mode 100644 cypress/support/index.ts create mode 100644 playwright.config.ts create mode 100644 tests/config.ts create mode 100644 tests/connectWallet/memoryProvider.spec.ts create mode 100644 tests/connectWallet/metaMask.spec.ts create mode 100644 tests/connectWallet/webWallet.spec.ts create mode 100644 tests/support/fs/downloadFileFromUrl.ts create mode 100644 tests/support/fs/ensureDirectoryExists.ts create mode 100644 tests/support/fs/readValueFromFile.ts create mode 100644 tests/support/fs/writeValueToFile.ts create mode 100644 tests/support/metaMask/constants.ts create mode 100644 tests/support/metaMask/createPassword.ts create mode 100644 tests/support/metaMask/downloadMetaMask.ts create mode 100644 tests/support/metaMask/fillSecretRecoveryPhrase.ts create mode 100644 tests/support/metaMask/handleMetaMaskSnap.ts create mode 100644 tests/support/metaMask/handleMetrics.ts create mode 100644 tests/support/metaMask/importWallet.ts create mode 100644 tests/support/metaMask/loadExtension.ts create mode 100644 tests/support/metaMask/prepareExtension.ts create mode 100644 tests/support/metaMask/setupMetaMaskWallet.ts create mode 100644 tests/support/metaMask/unzipArchive.ts create mode 100644 tests/support/metaMask/waitForMetaMaskLoad.ts create mode 100644 tests/support/template/checkBalanceUpdate.ts create mode 100644 tests/support/template/checkButtonStatus.ts create mode 100644 tests/support/template/checkClipboardContains.ts create mode 100644 tests/support/template/checkConnectionToWallet.ts create mode 100644 tests/support/template/confirmPrivateKeyTransaction.ts create mode 100644 tests/support/template/confirmWalletTransaction.ts create mode 100644 tests/support/template/connectInMemoryProvider.ts create mode 100644 tests/support/template/connectWebWallet.ts create mode 100644 tests/support/template/constants.ts create mode 100644 tests/support/template/extractBalanceFromContainer.ts create mode 100644 tests/support/template/getPageAndWaitForLoad.ts create mode 100644 tests/support/template/globalSetup.ts create mode 100644 tests/support/template/handlePingPong.ts create mode 100644 tests/support/template/index.ts create mode 100644 tests/support/template/loadLocalEnv.ts create mode 100644 tests/support/template/navigateToConnectWallet.ts create mode 100644 tests/support/template/parseTransactionsTable.ts create mode 100644 tests/support/template/pasteStringFromClipboard.ts create mode 100644 tests/support/template/signBatchTransactions.ts create mode 100644 tests/support/template/testIdSelector.ts create mode 100644 tests/support/template/testdata.ts create mode 100644 tests/support/template/types.ts create mode 100644 tests/support/template/waitForToastToBeClosed.ts create mode 100644 tests/support/template/waitForToastToBeDisplayed.ts create mode 100644 tests/support/template/waitForTransactionToastToShow.ts create mode 100644 tests/support/template/waitUntilStable.ts create mode 100644 tests/templateActions/nativeAuth.spec.ts create mode 100644 tests/templateActions/pingAndPongAbi.spec.ts create mode 100644 tests/templateActions/signAndSendBatch.spec.ts create mode 100644 tests/templateActions/signMessage.spec.ts create mode 100644 tests/templateActions/swapAndLock.ts diff --git a/.github/workflows/run-merge-e2e-tests.yml b/.github/workflows/run-merge-e2e-tests.yml new file mode 100644 index 0000000..2ddd1ec --- /dev/null +++ b/.github/workflows/run-merge-e2e-tests.yml @@ -0,0 +1,61 @@ +name: Playwright merge E2E Tests +on: + pull_request: + branches: [main] + workflow_dispatch: +jobs: + E2E-RUN: + runs-on: runner-dapp + env: + KEYSTORE1_JSON_B64: ${{ secrets.KEYSTORE1_JSON_B64 }} + KEYSTORE1_PASSWORD: ${{ secrets.KEYSTORE1_PASSWORD }} + KEYSTORE1_ADDRESS: ${{ secrets.KEYSTORE1_ADDRESS }} + + KEYSTORE2_JSON_B64: ${{ secrets.KEYSTORE2_JSON_B64 }} + KEYSTORE2_PASSWORD: ${{ secrets.KEYSTORE2_PASSWORD }} + KEYSTORE2_ADDRESS: ${{ secrets.KEYSTORE2_ADDRESS }} + + KEYSTORE3_JSON_B64: ${{ secrets.KEYSTORE3_JSON_B64 }} + KEYSTORE3_PASSWORD: ${{ secrets.KEYSTORE3_PASSWORD }} + KEYSTORE3_ADDRESS: ${{ secrets.KEYSTORE3_ADDRESS }} + + KEYSTORE4_JSON_B64: ${{ secrets.KEYSTORE4_JSON_B64 }} + KEYSTORE4_PASSWORD: ${{ secrets.KEYSTORE4_PASSWORD }} + KEYSTORE4_ADDRESS: ${{ secrets.KEYSTORE4_ADDRESS }} + + KEYSTORE5_PEM_B64: ${{ secrets.KEYSTORE5_PEM_B64 }} + KEYSTORE5_ADDRESS: ${{ secrets.KEYSTORE5_ADDRESS }} + + KEYSTORE6_PRIVATE_KEY_UTF8: ${{ secrets.KEYSTORE6_PRIVATE_KEY_UTF8 }} + KEYSTORE6_ADDRESS: ${{ secrets.KEYSTORE6_ADDRESS }} + + METAMASK_MNEMONIC: ${{ secrets.METAMASK_MNEMONIC }} + METAMASK_ADDRESS: ${{ secrets.METAMASK_ADDRESS }} + METAMASK_PASSWORD: ${{ secrets.METAMASK_PASSWORD }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Setup Yarn + run: npm install -g yarn + - name: Install Dependencies + uses: nick-fields/retry@v3 + with: + timeout_minutes: 120 + retry_on: error + max_attempts: 2 + command: yarn install --frozen-lockfile + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Run Playwright E2E Tests + run: xvfb-run yarn run run-playwright-test + - name: Upload Playwright test report + uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: playwright-report + path: playwright-report/ + retention-days: 1 diff --git a/.gitignore b/.gitignore index a85e034..d5d6897 100644 --- a/.gitignore +++ b/.gitignore @@ -43,8 +43,17 @@ yalc.lock .idea .yalc - #cypress cypress/reports/ cypress/screenshots/ cypress/videos/ + +# playwright +playwright-report/ +test-results/ + +# secrets (local only) +tests/support/wallets/ + +# metamask cache +.cache/ \ No newline at end of file diff --git a/cypress/assets/globalData.ts b/cypress/assets/globalData.ts deleted file mode 100644 index f3060f0..0000000 --- a/cypress/assets/globalData.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const userData = { - passsword: 'Develop13#', - adress: 'erd1z9ewlfndgp6dwu8s6cprl2e0xw70fyeazsmwa28xpwaga75qfquqmzjm29' -}; diff --git a/cypress/assets/index.ts b/cypress/assets/index.ts deleted file mode 100644 index 12d65e6..0000000 --- a/cypress/assets/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './globalData'; diff --git a/cypress/assets/testKeystore.json b/cypress/assets/testKeystore.json deleted file mode 100644 index 77b9ae7..0000000 --- a/cypress/assets/testKeystore.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": 4, - "id": "2c3ba9b9-0661-4e8b-85f7-7a56913e0ade", - "kind": "mnemonic", - "crypto": { - "ciphertext": "822daae637f8a77af71225ed3e54ad36cbdcb3526c5f3745462ca65b136f398678db5d4c847708b7f70a8e4edf014b03e43219454327ab4958e71ed5e9bd8d0c099f4bc89eea896f39f999de486a1811c0a6ec9bc166af130827826d77f89a8f2d4016ed1a6ebecda3cd472456204affbb8c417748a438ad5ec2f0d3b822d57d3b2c08ebb9d5542753a3c4571c348db0c6", - "cipherparams": { "iv": "7d1ff8e7e9b362c931a9e1d6113c7e39" }, - "cipher": "aes-128-ctr", - "kdf": "scrypt", - "kdfparams": { - "dklen": 32, - "salt": "1e598d67730fb6f93c62b9848f4cdb9c8dbe134f1080100d708c6124f7fb5781", - "n": 4096, - "r": 8, - "p": 1 - }, - "mac": "d1605f8a4de5d4e44b78f7bc5707f796e9a529316119cb60ca75fb807f3b81bf" - } -} diff --git a/cypress/constants/enums.ts b/cypress/constants/enums.ts deleted file mode 100644 index c9a2ec7..0000000 --- a/cypress/constants/enums.ts +++ /dev/null @@ -1,38 +0,0 @@ -export enum AssertionEnum { - contain = 'contain', - include = 'include', - beChecked = 'be.checked' -} - -export enum ErrorMessagesEnum { - invalidAddress = 'Invalid address', - required = 'Required' -} - -export enum RoutesEnum { - unlock = '/unlock', - send = '/send', - dashboard = '/dashboard' -} - -export enum WalletIDEnum { - unguardedWallet1 = 'check_0', - unguardedWallet2 = 'check_1', - unguardedWallet3 = 'check_2', - unguardedWallet4 = 'check_3', - guardedWallet = 'check_9' -} - -export const enum GlobalSelectorsEnum { - connect = 'Connect', - signAutoSend = 'sign-auto-send', - sendTransactions = 'send-transactions', - swapLock = 'swap-lock', - transactionToastTitle = 'transactionToastTitle', - ledgerLoginButton = 'ledgerLoginButton' -} - -export const enum GlobalDataEnum { - pendingToast = 'Processing', - confirmedToast = 'transactions successful' -} diff --git a/cypress/constants/globalLinks.ts b/cypress/constants/globalLinks.ts deleted file mode 100644 index 6809dd5..0000000 --- a/cypress/constants/globalLinks.ts +++ /dev/null @@ -1 +0,0 @@ -export const DEVNET_API = 'https://devnet-api.multiversx.com'; diff --git a/cypress/e2e/BatchTransactions/BatchTransactions.cy.ts b/cypress/e2e/BatchTransactions/BatchTransactions.cy.ts deleted file mode 100644 index 7fc46a6..0000000 --- a/cypress/e2e/BatchTransactions/BatchTransactions.cy.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { signTransactions } from './helpers'; -import { WalletIDEnum, GlobalSelectorsEnum } from '../../constants/enums'; - -describe('Batch Transaction', () => { - beforeEach(() => { - cy.login(WalletIDEnum.unguardedWallet1, 'Connect'); - cy.wait(5000); - }); - afterEach(() => { - cy.checkToast(); - cy.contains('Button', 'Close').click(); - }); - it('should successfully sign 5 transactions for auto-send batch', () => { - signTransactions(GlobalSelectorsEnum.signAutoSend); - }); - - it('should successfully sign 5 transactions for send-transactions', () => { - signTransactions(GlobalSelectorsEnum.sendTransactions); - }); - - it('should successfully sign 4 transactions for swap-lock', () => { - cy.wait(3000); - signTransactions(GlobalSelectorsEnum.swapLock); - }); -}); diff --git a/cypress/e2e/BatchTransactions/cancelBatchTransactions.cy.ts b/cypress/e2e/BatchTransactions/cancelBatchTransactions.cy.ts deleted file mode 100644 index 20cc188..0000000 --- a/cypress/e2e/BatchTransactions/cancelBatchTransactions.cy.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { cancelTransactions } from './helpers'; -import { WalletIDEnum } from '../../constants/enums'; - -describe('cancelTransactions', () => { - beforeEach(() => { - cy.login(WalletIDEnum.unguardedWallet1, 'Connect'); - cy.wait(5000); - }); - afterEach(() => { - cy.contains('Button', 'Close').click(); - }); - it('should return transaction canceled for auto-send batch ', () => { - cancelTransactions('sign-auto-send'); - }); - - it('should return transaction canceled for swap-lock', () => { - cancelTransactions('swap-lock'); - }); - - it('should return transaction canceled for send-transactions ', () => { - cancelTransactions('send-transactions'); - }); -}); diff --git a/cypress/e2e/BatchTransactions/helpers.ts b/cypress/e2e/BatchTransactions/helpers.ts deleted file mode 100644 index 74e0954..0000000 --- a/cypress/e2e/BatchTransactions/helpers.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { userData } from '../../assets/globalData'; -import { scSelectors } from '../SCTransactions/SCTransactionData'; - -export const signTransactions = (selector: string) => { - let i = selector === 'swap-lock' ? 1 : 0; - - const widgetInfo = [ - 'Hash', - 'Receiver', - 'Amount', - 'Gas price', - 'Gas limit', - 'Data' - ]; - - cy.getSelector(selector).click(); - cy.getSelector(scSelectors.accesPass).type(userData.passsword); - cy.getSelector(scSelectors.submitButton).click(); - for (i; i < 5; i++) { - cy.getSelector('signBtn').click(); - } - cy.contains('Processing transactions'); - cy.checkWidgetMsg(widgetInfo); -}; - -export const cancelTransactions = (selector: string) => { - cy.getSelector(selector).click(); - cy.getSelector(scSelectors.accesPass).type(userData.passsword); - cy.getSelector(scSelectors.submitButton).click(); - cy.getSelector('closeButton').click(); - cy.contains('Transaction canceled'); -}; diff --git a/cypress/e2e/SCTransactions/SCActions.ts b/cypress/e2e/SCTransactions/SCActions.ts deleted file mode 100644 index f8d36b6..0000000 --- a/cypress/e2e/SCTransactions/SCActions.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { scSelectors } from './SCTransactionData'; -import { userData } from '../../assets/globalData'; -import { AssertionEnum } from '../../constants/enums'; -// Custom function to make Ping or Pong transactions -export const scTransaction = (type: string) => { - cy.getSelector(type).then((btn) => { - cy.wait(1500); - if (btn.prop('disabled')) { - return; - } else { - cy.wait(1500); - cy.getSelector(type).click(); - cy.getSelector(scSelectors.accesPass).type(userData.passsword); - cy.getSelector(scSelectors.submitButton).click(); - cy.getSelector(scSelectors.signButton).click(); - checkPingDetails(); - } - }); -}; - -export const checkPingDetails = () => { - cy.get('p') - .should(AssertionEnum.contain, 'Contract') - .should(AssertionEnum.contain, 'Hash') - .should(AssertionEnum.contain, 'Receiver') - .should(AssertionEnum.contain, 'Amount') - .should(AssertionEnum.contain, 'Gas price') - .should(AssertionEnum.contain, 'Gas limit') - .should(AssertionEnum.contain, 'Data'); -}; - -export const pingPongHandler = (type: string) => { - cy.getSelector(`btnPing${type}`).then((btn) => { - cy.wait(1500); - if (btn.prop('disabled')) { - console.log('btn prop', btn.prop('disabled')); - scTransaction(`btnPong${type}`); - } else { - scTransaction(`btnPing${type}`); - } - }); -}; - -export const initTransaction = () => { - cy.getSelector('btnPongAbi').click(); - cy.getSelector(scSelectors.accesPass).type(userData.passsword); - cy.getSelector(scSelectors.submitButton).click(); -}; diff --git a/cypress/e2e/SCTransactions/SCTransaction.cy.ts b/cypress/e2e/SCTransactions/SCTransaction.cy.ts deleted file mode 100644 index 907984f..0000000 --- a/cypress/e2e/SCTransactions/SCTransaction.cy.ts +++ /dev/null @@ -1,45 +0,0 @@ -/// -import { initTransaction, pingPongHandler } from './SCActions'; -import { WalletIDEnum } from '../../constants/enums'; - -describe('Smart Contract Transactions', () => { - afterEach(() => { - cy.contains('Button', 'Close').click(); - }); - - it('should successfully execute the Ping & Pong ABI', () => { - cy.login(WalletIDEnum.unguardedWallet1, 'Connect'); - cy.wait(5000); - pingPongHandler('Abi'); - cy.checkToast(); - }); - - it('should successfully execute the Ping & Pong RAW ', () => { - cy.login(WalletIDEnum.unguardedWallet2, 'Connect'); - cy.wait(5000); - pingPongHandler('Raw'); - cy.checkToast(); - }); - - it('should successfully execute the Ping & Pong Service', () => { - cy.login(WalletIDEnum.unguardedWallet3, 'Connect'); - cy.wait(5000); - pingPongHandler('Service'); - cy.checkToast(); - }); - - it('should not execute ping&pong aciton', () => { - cy.login(WalletIDEnum.unguardedWallet4, 'Connect'); - cy.wait(5000); - initTransaction(); - cy.getSelector('closeButton').click(); - cy.contains('Transaction canceled'); - }); - - it('should display the guardian modal', () => { - cy.login(WalletIDEnum.guardedWallet, 'Connect'); - cy.wait(2000); - initTransaction(); - cy.contains('Verify Guardian'); - }); -}); diff --git a/cypress/e2e/SCTransactions/SCTransactionData.ts b/cypress/e2e/SCTransactions/SCTransactionData.ts deleted file mode 100644 index b299fae..0000000 --- a/cypress/e2e/SCTransactions/SCTransactionData.ts +++ /dev/null @@ -1,20 +0,0 @@ -export const SCTransactionData = { - confirmationMessage: 'transaction successful', - succesMessage: 'Ping transaction successful', - modalConfirmation: 'transactionToastTitle', - ping: 'Ping', - pong: 'Pong', - transactions: '/transactions' -}; -export const scSelectors = { - accesPass: 'accessPass', - submitButton: 'submitButton', - signButton: 'signBtn', - loginBtn: 'loginBtn', - webWalletLogin: 'webWalletLoginBtn', - btnPingAbi: 'btnPingAbi', - btnPongAbi: 'btnPongAbi', - btnPingRaw: 'btnPingRaw', - btnPongRaw: 'btnPongRaw', - transactionBtn: '[data-cy="transactionBtn"]' -}; diff --git a/cypress/e2e/Send/Send.cy.ts b/cypress/e2e/Send/Send.cy.ts deleted file mode 100644 index 3fb89cb..0000000 --- a/cypress/e2e/Send/Send.cy.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { userData } from '../../assets/globalData'; -import { AssertionEnum, RoutesEnum, WalletIDEnum } from '../../constants/enums'; -describe('Send', () => { - beforeEach(() => { - cy.login(WalletIDEnum.unguardedWallet1, 'Send transaction'); - }); - afterEach(() => { - cy.contains('Button', 'Close').click(); - }); - it('should successfully send a demo transaction', () => { - cy.checkUrl(RoutesEnum.send); - cy.getSelector('confirmData').should(AssertionEnum.contain, 'Hello_world'); - cy.getSelector('sendTrxBtn').click(); - cy.get('p') - .should(AssertionEnum.contain, 'Sender') - .should( - AssertionEnum.contain, - 'erd16xlzk48ftvhxp8dyq6d0kkfpgpfechlzycfm9xmdmwna66pvkymqvz4vzq' - ) - .should(AssertionEnum.contain, 'Transaction status') - .should(AssertionEnum.contain, 'succes'); - }); - - it('should display the cancelled status', () => { - cy.contains('Send transaction').click(); - cy.getSelector('accessPass').type(userData.passsword); - cy.getSelector('submitButton').click(); - - cy.getSelector('cancelTrxBtn').click(); - cy.get('p') - .should(AssertionEnum.contain, 'Transaction status') - .should(AssertionEnum.contain, 'cancelled'); - }); -}); diff --git a/cypress/e2e/SignMessage/SignMessage.cy.ts b/cypress/e2e/SignMessage/SignMessage.cy.ts deleted file mode 100644 index fa5e5be..0000000 --- a/cypress/e2e/SignMessage/SignMessage.cy.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { userData } from '../../assets/globalData'; -import { AssertionEnum, RoutesEnum, WalletIDEnum } from '../../constants/enums'; -import { scSelectors } from '../SCTransactions/SCTransactionData'; - -describe('Sign Message', () => { - beforeEach(() => { - cy.login(WalletIDEnum.unguardedWallet1, 'Connect'); - cy.wait(5000); - }); - afterEach(() => { - cy.contains('Button', 'Close').click(); - }); - it('should sign', () => { - const widgetInfo = ['Signature', 'Encoded message', 'Decoded message']; - cy.getSelector('signMsgBtn').should('be.disabled'); - cy.get('textarea').first().type('Test'); - cy.getSelector('signMsgBtn').click(); - cy.getSelector(scSelectors.accesPass).type(userData.passsword); - cy.getSelector(scSelectors.submitButton).click(); - cy.getSelector('message').should('have.value', 'Test'); - cy.getSelector('signButton').click(); - widgetInfo.forEach((element) => { - cy.get('label').should(AssertionEnum.contain, element); - }); - cy.getSelector('closeTransactionSuccessBtn').click(); - cy.getSelector('signMsgBtn').should('be.disabled'); - }); - - it('should not sign', () => { - cy.get('textarea').first().type('Test'); - cy.getSelector('signMsgBtn').click(); - cy.wait(2000); - cy.getSelector(scSelectors.accesPass).type(userData.passsword); - cy.getSelector(scSelectors.submitButton).click(); - cy.getSelector('closeBtn').click(); - cy.checkUrl(RoutesEnum.dashboard); - cy.contains('Transaction canceled'); - }); -}); diff --git a/cypress/e2e/Unlock/Unlock.cy.ts b/cypress/e2e/Unlock/Unlock.cy.ts deleted file mode 100644 index aafd800..0000000 --- a/cypress/e2e/Unlock/Unlock.cy.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { GlobalSelectorsEnum } from '../../constants/enums'; - -describe('Unlock', () => { - beforeEach(() => { - cy.visit('/'); - }); - - it('should open the xPortal modal', () => { - cy.contains('xPortal App').click(); - cy.contains('Scan the QR code using the xPortal App'); - }); - - it('should open the ledger modal', () => { - cy.getSelector(GlobalSelectorsEnum.ledgerLoginButton); - cy.contains('Connect Ledger'); - }); -}); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts deleted file mode 100644 index c8a211b..0000000 --- a/cypress/support/commands.ts +++ /dev/null @@ -1,70 +0,0 @@ -/// -import { userData } from '../assets/globalData'; -import { - AssertionEnum, - GlobalSelectorsEnum, - GlobalDataEnum -} from '../constants/enums'; -import { DEVNET_API } from '../constants/globalLinks'; - -// Check the url global function -Cypress.Commands.add('checkUrl', (url) => { - cy.url().should(AssertionEnum.include, url); -}); - -//Login with keystore global function -Cypress.Commands.add('login', (walletID, selector) => { - // cy.session(walletID, () => { - cy.visit('/'); - cy.contains(selector).click(); - if (selector === GlobalSelectorsEnum.connect) { - cy.getSelector('webWalletLoginBtn').click(); - } - cy.getSelector('keystoreBtn').click(); - cy.checkUrl('/unlock/keystore'); - cy.getSelector('submitButton').click(); - cy.checkUrl('/unlock/keystore'); - - cy.get('input[type=file]').selectFile('./cypress/assets/testKeystore.json', { - force: true - }); - cy.getSelector('accessPass').type(userData.passsword); - cy.getSelector('submitButton').click(); - - cy.getSelector(walletID).click(); - cy.getSelector('confirmBtn').click(); -}); -// }); - -Cypress.Commands.add('getSelector', (selector, ...cypressAction) => { - return cy.get(`[data-testid=${selector}]`, ...cypressAction); -}); - -// Add the custom command for api intercepts -Cypress.Commands.add('apiIntercept', (method, param) => { - cy.intercept(method, `${DEVNET_API}${param}`).as(param); -}); - -Cypress.on('uncaught:exception', () => { - // Do nothing or handle the exception as per your requirements - // You can remove the comment and add your custom handling logic here - // console.log('An uncaught exception occurred but will be ignored'); - return false; // Prevent Cypress from failing the test -}); -Cypress.Commands.add('checkWidgetMsg', (msgArr) => { - msgArr.forEach((element) => { - cy.get('p').should(AssertionEnum.contain, element); - }); -}); - -Cypress.Commands.add('checkToast', () => { - cy.getSelector(GlobalSelectorsEnum.transactionToastTitle).should( - AssertionEnum.contain, - GlobalDataEnum.pendingToast - ); - cy.wait(5000); - cy.getSelector(GlobalSelectorsEnum.transactionToastTitle).should( - AssertionEnum.contain, - GlobalDataEnum.confirmedToast - ); -}); diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts deleted file mode 100644 index 1221b17..0000000 --- a/cypress/support/e2e.ts +++ /dev/null @@ -1 +0,0 @@ -import './commands'; diff --git a/cypress/support/index.ts b/cypress/support/index.ts deleted file mode 100644 index 24f5588..0000000 --- a/cypress/support/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-namespace, @typescript-eslint/no-unused-vars -declare namespace Cypress { - interface Chainable { - checkUrl: (url: string) => void; - login: (walletID: string, selector: string) => void; - apiIntercept: (method: string, param: string) => void; - checkWidgetMsg: (msgArr: string[]) => void; - checkToast: () => void; - - getSelector: ( - selector: string, - ...cypressAction: [] - ) => Chainable>; - } -} diff --git a/package.json b/package.json index 3f9e4ea..91190c1 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "build:devnet": "yarn run copy-devnet-config & next build", "preview": "next start", "test": "jest", - "cy:run": "node scripts/cypress.ts" + "run-playwright-test": "playwright test", + "run-playwright-test-ui": "playwright test --ui" }, "dependencies": { "@fortawesome/fontawesome-svg-core": "6.5.1", @@ -28,18 +29,20 @@ "@multiversx/sdk-dapp": "^5.x", "@multiversx/sdk-dapp-ui": "^0.x", "@multiversx/sdk-dapp-utils": "3.0.2", + "@playwright/test": "^1.57.0", "axios": "^1.10.0", + "bignumber.js": "^9.x", "classnames": "2.3.2", "eslint": "8.50.0", "eslint-config-next": "13.5.3", - "bignumber.js": "^9.x", "moment": "2.29.4", "next": "13.5.4", "next-transpile-modules": "10.0.1", "protobufjs": "7.5.4", "react": "18.2.0", "react-dom": "18.2.0", - "typescript": "5.2.2" + "typescript": "5.2.2", + "vite": "^7.2.4" }, "devDependencies": { "@swc/core": "1.3.91", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..c4a60e3 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,75 @@ +import { defineConfig, devices } from '@playwright/test'; +import { TEST_CONFIG } from './tests/config'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + globalSetup: './tests/support/template/globalSetup.ts', + /* timeout for each test */ + timeout: TEST_CONFIG.timeout, + /* timeout for locators */ + expect: { timeout: TEST_CONFIG.expectTimeout }, + /* directory where the tests are located */ + testDir: './tests', + /* pattern to match the tests */ + testMatch: '**/*.spec.ts', + + /* Run tests in files in parallel */ + fullyParallel: TEST_CONFIG.fullyParallel, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: TEST_CONFIG.retries, + /* Parallel tests on CI only. */ + workers: TEST_CONFIG.workers, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* 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:3000', + ignoreHTTPSErrors: true, + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + // Default to headless mode; will be overridden by the environment variable + headless: true, + + /* Capture screenshot on test failure */ + screenshot: 'only-on-failure', + + /* Record video on any failure */ + video: 'retain-on-failure' + }, + + /* Configure projects for major browsers */ + projects: [ + { + use: { + ...devices['Desktop Chrome'], + launchOptions: { + args: [ + '--start-maximized', + '--disable-web-security', + '--disable-features=VizDisplayCompositor' + ] + } + } + } + ], + webServer: { + command: 'yarn next start', + url: 'http://localhost:3000', + timeout: 120 * 1000, + reuseExistingServer: !process.env.CI, + stdout: 'pipe', + stderr: 'pipe', + ignoreHTTPSErrors: true + } +}); diff --git a/tests/config.ts b/tests/config.ts new file mode 100644 index 0000000..74d7584 --- /dev/null +++ b/tests/config.ts @@ -0,0 +1,14 @@ +export const TEST_CONFIG = { + /* Retry on CI only */ + retries: process.env.CI ? 1 : 0, + /* Parallel tests on CI only. */ + workers: 5, + /* Timeout for each test */ + timeout: 120_000, + /* Timeout for locators */ + expectTimeout: 60_000, + /* Run tests in files in parallel */ + fullyParallel: false +} as const; + +export const WALLET_URL_TIMEOUT_MS = 10_000; diff --git a/tests/connectWallet/memoryProvider.spec.ts b/tests/connectWallet/memoryProvider.spec.ts new file mode 100644 index 0000000..2ddc7c4 --- /dev/null +++ b/tests/connectWallet/memoryProvider.spec.ts @@ -0,0 +1,30 @@ +import { test } from '@playwright/test'; +import * as TestActions from '../support/template'; +import { readValueFromFile } from '../support/template'; +import { TestDataEnums } from '../support/template/testdata'; + +const privateKeyConfig = { + address: TestDataEnums.keystoreWalletAddress6, + privateKey: readValueFromFile(TestDataEnums.keystoreFilePath6, 'utf8').trim() +}; + +test.describe('Connect a wallet', () => { + // Connect wallet tests verify wallet connection functionality + + test.beforeEach(async ({ page }) => { + await TestActions.navigateToConnectWallet(page); + }); + + test.describe('In Memory Provider Connection', () => { + test('should successfully connect with Address and Private Key', async ({ + page + }) => { + await TestActions.connectInMemoryProvider({ + page, + loginMethod: privateKeyConfig + }); + + await TestActions.checkConnectionToWallet(page, privateKeyConfig.address); + }); + }); +}); diff --git a/tests/connectWallet/metaMask.spec.ts b/tests/connectWallet/metaMask.spec.ts new file mode 100644 index 0000000..734bedf --- /dev/null +++ b/tests/connectWallet/metaMask.spec.ts @@ -0,0 +1,94 @@ +import { BrowserContext, expect, Page, test } from '@playwright/test'; +import { setupMetaMaskWallet } from '../support/metaMask/setupMetaMaskWallet'; +import * as TestActions from '../support/template'; +import { getPageAndWaitForLoad } from '../support/template/getPageAndWaitForLoad'; +import { OriginPageEnum, UrlRegex } from '../support/template/testdata'; +import { TEST_CONSTANTS } from '../support/template/constants'; + +// TODO: Load variables from .env.test.local when running locally +// Get password and address from environment variables +const METAMASK_MNEMONIC = process.env.METAMASK_MNEMONIC || ''; +const METAMASK_ADDRESS = process.env.METAMASK_ADDRESS || ''; +const METAMASK_PASSWORD = process.env.METAMASK_PASSWORD || ''; + +// Validate that required environment variables are present +if (!METAMASK_PASSWORD || !METAMASK_ADDRESS || !METAMASK_MNEMONIC) { + throw new Error( + 'METAMASK_PASSWORD, METAMASK_MNEMONIC, and METAMASK_ADDRESS environment variables are missing. Please set them in .env.test.local for local development or as a GitHub Secret for CI.' + ); +} + +test.describe('Connect a wallet', () => { + let metamaskContext: BrowserContext; + let extensionId: string; + let dAppPage: Page; + + test.beforeEach(async () => { + // Setup MetaMask for each test + const result = await setupMetaMaskWallet( + METAMASK_MNEMONIC, + METAMASK_PASSWORD + ); + metamaskContext = result.context; + extensionId = result.extensionId; + + // Create a page in the MetaMask context for the dApp + dAppPage = await metamaskContext.newPage(); + await TestActions.navigateToConnectWallet(dAppPage); + }); + + test.afterEach(async () => { + // Close the browser context to free up resources + if (metamaskContext) { + try { + await metamaskContext.close(); + // Wait a moment to ensure the context is fully closed + // Persistent contexts need a bit more time to release the userDataDir lock + await new Promise((resolve) => setTimeout(resolve, 2000)); + } catch (error) { + // Context might already be closed, ignore the error + } + } + }); + + test.describe('MetaMask Connection', () => { + test('should successfully connect with MetaMask', async () => { + // Use the MetaMask context and dApp page from beforeEach + const context = metamaskContext; + const page = dAppPage; + + // Click the connect MetaMask button + await page.getByTestId('metamask').click(); + + // Get the notification page and wait for it to load in the MetaMask context + const notificationPage = await getPageAndWaitForLoad( + context, + `chrome-extension://${extensionId}/notification.html`, + { + viewport: { width: 360, height: 592 } + } + ); + + // Handle MetaMask Snap privacy warning + await TestActions.handleMetaMaskSnap( + context, + extensionId, + notificationPage + ); + + // Switch to template page + const templatePage = await getPageAndWaitForLoad( + context, + OriginPageEnum.templateDashboard + ); + + // Verify template page opened + await expect(templatePage).toHaveURL(UrlRegex.templateDashboard, { + timeout: TEST_CONSTANTS.URL_NAVIGATION_TIMEOUT + }); + + // Verify connection using TestActions helper + await TestActions.checkConnectionToWallet(page, METAMASK_ADDRESS); + }); + }); +}); diff --git a/tests/connectWallet/webWallet.spec.ts b/tests/connectWallet/webWallet.spec.ts new file mode 100644 index 0000000..b449d69 --- /dev/null +++ b/tests/connectWallet/webWallet.spec.ts @@ -0,0 +1,61 @@ +import { expect, test } from '@playwright/test'; +import * as TestActions from '../support/template'; +import { TestDataEnums } from '../support/template/testdata'; + +const keystoreConfig = { + keystore: TestDataEnums.keystoreFilePath1, + password: TestDataEnums.keystorePassword1, + address: TestDataEnums.keystoreWalletAddress1 +}; + +const pemConfig = { + pem: TestDataEnums.keystoreFilePath5 +}; + +test.describe('Connect a wallet', () => { + // Connect wallet tests verify wallet connection functionality + + test.beforeEach(async ({ page }) => { + await TestActions.navigateToConnectWallet(page); + }); + + test.describe('Keystore Connection', () => { + test('should successfully connect with keystore file', async ({ page }) => { + await TestActions.connectWebWallet({ page, loginMethod: keystoreConfig }); + + await TestActions.checkConnectionToWallet( + page, + TestDataEnums.keystoreWalletAddress1 + ); + }); + }); + + test.describe('PEM Connection', () => { + test('should successfully connect with PEM file', async ({ page }) => { + await TestActions.connectWebWallet({ page, loginMethod: pemConfig }); + + await TestActions.checkConnectionToWallet( + page, + TestDataEnums.keystoreWalletAddress5 + ); + }); + }); + + test.describe('Connection Validation', () => { + test('should handle missing password for keystore', async ({ page }) => { + // Test with keystore but no password + const invalidKeystoreConfig = { + keystore: TestDataEnums.keystoreFilePath1, + password: undefined + }; + + // This should throw an error for missing password + await expect( + TestActions.connectWebWallet({ + page, + loginMethod: invalidKeystoreConfig + }) + ).rejects.toThrow('Password is required when using a keystore'); + }); + }); +}); diff --git a/tests/support/fs/downloadFileFromUrl.ts b/tests/support/fs/downloadFileFromUrl.ts new file mode 100644 index 0000000..53610b0 --- /dev/null +++ b/tests/support/fs/downloadFileFromUrl.ts @@ -0,0 +1,63 @@ +import { createWriteStream } from 'node:fs'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { pipeline } from 'stream/promises'; +import axios from 'axios'; + +type DownloaderOptions = { + url: string; + outputDir: string; + fileName: string; + overrideFile?: boolean; +}; + +type DownloadFileResult = { + filePath: string; + downloadSkipped: boolean; +}; + +export async function downloadFileFromUrl( + options: DownloaderOptions +): Promise { + try { + const { url, outputDir, fileName, overrideFile } = options; + const filePath = path.join(outputDir, fileName); + + await fs.mkdir(outputDir, { recursive: true }); + + const fileExists = await fileExistsSafe(filePath); + if (fileExists && !overrideFile) { + return { + filePath, + downloadSkipped: true + }; + } + + const response = await axios.get(url, { + responseType: 'stream' + }); + + const writer = createWriteStream(filePath); + await pipeline(response.data, writer); + + return { + filePath, + downloadSkipped: false + }; + } catch (error) { + throw new Error( + `Failed to download file: ${ + error instanceof Error ? error.message : 'Unknown error' + }` + ); + } +} + +async function fileExistsSafe(p: string): Promise { + try { + await fs.access(p); + return true; + } catch { + return false; + } +} diff --git a/tests/support/fs/ensureDirectoryExists.ts b/tests/support/fs/ensureDirectoryExists.ts new file mode 100644 index 0000000..8dfd7c8 --- /dev/null +++ b/tests/support/fs/ensureDirectoryExists.ts @@ -0,0 +1,9 @@ +import fs from 'fs'; +import path from 'path'; + +export const ensureDirectoryExists = (filePath: string) => { + const dir = path.dirname(filePath); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } +}; diff --git a/tests/support/fs/readValueFromFile.ts b/tests/support/fs/readValueFromFile.ts new file mode 100644 index 0000000..b72424e --- /dev/null +++ b/tests/support/fs/readValueFromFile.ts @@ -0,0 +1,13 @@ +import fs from 'fs'; + +export const readValueFromFile = ( + inPath: string, + encoding: 'utf8' | 'buffer' = 'utf8' +): string => { + if (encoding === 'buffer') { + const data = fs.readFileSync(inPath); + return data.toString('utf8'); + } + + return fs.readFileSync(inPath, 'utf8'); +}; diff --git a/tests/support/fs/writeValueToFile.ts b/tests/support/fs/writeValueToFile.ts new file mode 100644 index 0000000..a39dcbb --- /dev/null +++ b/tests/support/fs/writeValueToFile.ts @@ -0,0 +1,37 @@ +import fs from 'fs'; +import { ensureDirectoryExists } from './ensureDirectoryExists'; + +export type FileEncoding = 'base64' | 'utf8' | 'none'; + +export const writeValueToFile = ( + value: string, + outPath: string, + encoding: FileEncoding, + skipIfExists: boolean = false +) => { + // Check if file exists and skip if requested + if (skipIfExists && fs.existsSync(outPath)) { + return; + } + + // ensure directory exists + ensureDirectoryExists(outPath); + + switch (encoding) { + case 'base64': + fs.writeFileSync( + outPath, + Buffer.from(value, 'base64').toString('utf8'), + 'utf8' + ); + break; + case 'utf8': + fs.writeFileSync(outPath, value, 'utf8'); + break; + case 'none': + fs.writeFileSync(outPath, value); + break; + default: + throw new Error(`Unsupported encoding: ${encoding}`); + } +}; diff --git a/tests/support/metaMask/constants.ts b/tests/support/metaMask/constants.ts new file mode 100644 index 0000000..4daa969 --- /dev/null +++ b/tests/support/metaMask/constants.ts @@ -0,0 +1,7 @@ +export const DEFAULT_METAMASK_VERSION = '13.6.0'; + +export const resolveMetamaskVersion = () => + process.env.METAMASK_VERSION?.trim() || DEFAULT_METAMASK_VERSION; + +export const buildMetamaskZipUrl = (version: string) => + `https://github.com/MetaMask/metamask-extension/releases/download/v${version}/metamask-chrome-${version}.zip`; diff --git a/tests/support/metaMask/createPassword.ts b/tests/support/metaMask/createPassword.ts new file mode 100644 index 0000000..12118df --- /dev/null +++ b/tests/support/metaMask/createPassword.ts @@ -0,0 +1,43 @@ +import { Page } from '@playwright/test'; + +const DEFAULT_TIMEOUT = 10000; + +const createPasswordSelectors = { + newPasswordInput: '[data-testid="create-password-new-input"]', + confirmPasswordInput: '[data-testid="create-password-confirm-input"]', + termsCheckbox: '[data-testid="create-password-terms"]', + submitButton: '[data-testid="create-password-submit"]' +}; + +export async function createPassword(page: Page, password: string) { + await enterPassword(page, password); + await confirmPassword(page, password); + await acceptTerms(page); + await submitPasswordForm(page); +} + +async function enterPassword(page: Page, password: string) { + const passwordField = page.locator(createPasswordSelectors.newPasswordInput); + await passwordField.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await passwordField.fill(password); +} + +async function confirmPassword(page: Page, password: string) { + const confirmField = page.locator( + createPasswordSelectors.confirmPasswordInput + ); + await confirmField.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await confirmField.fill(password); +} + +async function acceptTerms(page: Page) { + const checkbox = page.locator(createPasswordSelectors.termsCheckbox); + await checkbox.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await checkbox.click(); +} + +async function submitPasswordForm(page: Page) { + const submitButton = page.locator(createPasswordSelectors.submitButton); + await submitButton.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await submitButton.click(); +} diff --git a/tests/support/metaMask/downloadMetaMask.ts b/tests/support/metaMask/downloadMetaMask.ts new file mode 100644 index 0000000..fea2626 --- /dev/null +++ b/tests/support/metaMask/downloadMetaMask.ts @@ -0,0 +1,55 @@ +// downloadFileFromUrl.ts +import { createWriteStream } from 'node:fs'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { pipeline } from 'stream/promises'; +import axios from 'axios'; + +type Options = { + url: string; + outputDir: string; + fileName: string; + overwrite?: boolean; +}; + +export async function downloadFileFromUrl({ + url, + outputDir, + fileName, + overwrite = false +}: Options): Promise<{ filePath: string; downloadSkipped: boolean }> { + const filePath = path.join(outputDir, fileName); + + await fs.mkdir(outputDir, { recursive: true }); + + if (!overwrite && (await exists(filePath))) { + return { filePath, downloadSkipped: true }; + } + + const response = await axios.get(url, { + responseType: 'stream', + validateStatus: () => true + }); + if (response.status !== 200) { + throw new Error(`Download failed (${response.status}) for ${url}`); + } + + const tmpPath = `${filePath}.part`; + await pipeline(response.data, createWriteStream(tmpPath)); + // remove target file if exists, then rename + try { + await fs.rm(filePath, { force: true }); + } catch {} + await fs.rename(tmpPath, filePath); + + return { filePath, downloadSkipped: false }; +} + +async function exists(p: string): Promise { + try { + await fs.access(p); + return true; + } catch { + return false; + } +} diff --git a/tests/support/metaMask/fillSecretRecoveryPhrase.ts b/tests/support/metaMask/fillSecretRecoveryPhrase.ts new file mode 100644 index 0000000..bf83a84 --- /dev/null +++ b/tests/support/metaMask/fillSecretRecoveryPhrase.ts @@ -0,0 +1,50 @@ +import { Page } from '@playwright/test'; + +const secretRecoverySelectors = { + wordInput: (index: number) => `[data-testid="import-srp__srp-word-${index}"]`, + confirmButton: '[data-testid="import-srp-confirm"]', + errorMessage: '[data-testid="import-srp__error"]' +}; + +export async function fillSecretRecoveryPhrase(page: Page, seedPhrase: string) { + const words = seedPhrase.split(' '); + await fillSeedWords(page, words); + await confirmSeedPhrase(page); +} + +async function fillSeedWords(page: Page, words: string[]) { + // Skip first word (already filled in the textarea) + const remainingWords = words.slice(1); + + for (const [index, word] of remainingWords.entries()) { + const inputSelector = secretRecoverySelectors.wordInput(index + 1); + await fillSingleWord(page, inputSelector, word); + } +} + +async function fillSingleWord(page: Page, selector: string, word: string) { + const input = page.locator(selector); + await input.fill(word); + await input.press('Enter'); +} + +async function confirmSeedPhrase(page: Page) { + const confirmButton = page.locator(secretRecoverySelectors.confirmButton); + + if (await confirmButton.isDisabled()) { + const errorText = await getErrorText(page); + throw new Error( + `[ConfirmSecretRecoveryPhrase] Invalid seed phrase. MetaMask error: ${errorText}` + ); + } + + await confirmButton.click(); +} + +async function getErrorText(page: Page): Promise { + return ( + (await page + .locator(secretRecoverySelectors.errorMessage) + .textContent({ timeout: 1000 })) || 'Unknown error' + ); +} diff --git a/tests/support/metaMask/handleMetaMaskSnap.ts b/tests/support/metaMask/handleMetaMaskSnap.ts new file mode 100644 index 0000000..bd2de34 --- /dev/null +++ b/tests/support/metaMask/handleMetaMaskSnap.ts @@ -0,0 +1,150 @@ +import { BrowserContext, Page } from '@playwright/test'; +import { getPageAndWaitForLoad } from '../template/getPageAndWaitForLoad'; +import { waitUntilStable } from '../template/waitUntilStable'; + +const RETRY_DELAY_BASE_MS = 500; +const CLICK_TIMEOUT_MS = 6000; + +const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +const snapSelectors = { + confirmationSubmitButton: '[data-testid="confirmation-submit-button"]', + actions: [ + { type: 'testId', name: 'snap-privacy-warning-scroll' }, + { type: 'button', name: 'Accept' }, + { type: 'button', name: 'Connect' }, + { type: 'button', name: 'Confirm' }, + { type: 'checkbox', name: 'MultiversX' }, + { type: 'testId', name: 'snap-install-warning-modal-confirm' }, + { type: 'button', name: 'Ok' }, + { type: 'button', name: 'Approve' } + ] as const +}; + +export async function handleMetaMaskSnap( + context: BrowserContext, + extensionId: string, + initialPage: Page, + maxRetries = 5 +): Promise { + let page = initialPage; + let attempt = 0; + let currentActionIndex = 0; + + while (attempt <= maxRetries) { + try { + await waitUntilStable(page); + + if (await clickIfConfirmationVisible(page)) return; + + for (let i = currentActionIndex; i < snapSelectors.actions.length; i++) { + const action = snapSelectors.actions[i]; + currentActionIndex = i; + await attemptClick(page, action); + } + + return; // All steps completed successfully + } catch (error: any) { + attempt++; + + console.warn( + `[MetaMaskSnap] Attempt ${attempt}/${maxRetries} failed: ${ + error?.message || error + }` + ); + console.warn( + '[MetaMaskSnap] Open pages at failure:', + context.pages().map((p) => p.url()) + ); + + if (attempt > maxRetries) { + throw new Error('[MetaMaskSnap] Max retries reached.'); + } + + page = await reacquireNotificationPage(context, extensionId); + await exponentialBackoff(attempt); + } + } + + throw new Error('[MetaMaskSnap] Unexpected end of flow.'); +} + +async function attemptClick( + page: Page, + action: { type: 'testId' | 'checkbox' | 'button'; name: string } +) { + const element = getLocator(page, action); + + try { + await element.waitFor({ state: 'visible', timeout: CLICK_TIMEOUT_MS }); + await element.click(); + } catch (error: any) { + console.error( + `[MetaMaskSnap] Failed to click "${action.name}": ${ + error?.message || error + }` + ); + console.error( + `[MetaMaskSnap] Page state -> closed: ${page.isClosed()}, url: ${page.url()}` + ); + throw error; + } +} + +function getLocator( + page: Page, + action: { type: 'testId' | 'checkbox' | 'button'; name: string } +) { + switch (action.type) { + case 'testId': + return page.getByTestId(action.name); + case 'checkbox': + return page.getByRole('checkbox', { name: action.name }); + case 'button': + return page.getByRole('button', { name: action.name }); + default: + throw new Error(`Unknown action type: ${action.type}`); + } +} + +async function clickIfConfirmationVisible(page: Page): Promise { + const confirmationButton = page.locator( + snapSelectors.confirmationSubmitButton + ); + const isVisible = await confirmationButton.isVisible().catch(() => false); + + if (isVisible) { + await confirmationButton.click(); + return true; + } + + return false; +} + +async function reacquireNotificationPage( + context: BrowserContext, + extensionId: string +): Promise { + try { + const page = await getPageAndWaitForLoad( + context, + `chrome-extension://${extensionId}/notification.html`, + { viewport: { width: 360, height: 592 } } + ); + await waitUntilStable(page); + console.warn('[MetaMaskSnap] Reacquired notification page.'); + return page; + } catch (error) { + throw new Error( + `[MetaMaskSnap] Failed to reacquire notification page: ${ + (error as Error).message + }` + ); + } +} + +async function exponentialBackoff(attempt: number) { + const delay = RETRY_DELAY_BASE_MS * 2 ** (attempt - 1); + console.warn(`[MetaMaskSnap] Retrying in ${delay}ms...`); + await sleep(delay); +} diff --git a/tests/support/metaMask/handleMetrics.ts b/tests/support/metaMask/handleMetrics.ts new file mode 100644 index 0000000..291af27 --- /dev/null +++ b/tests/support/metaMask/handleMetrics.ts @@ -0,0 +1,36 @@ +import { Page } from '@playwright/test'; + +const DEFAULT_TIMEOUT = 10000; + +const metaMetricsSelectors = { + checkbox: '#metametrics-opt-in', + continueButton: '[data-testid="metametrics-i-agree"]', + doneButton: '[data-testid="onboarding-complete-done"]' +}; + +export async function handleMetaMetrics(page: Page) { + await ensureMetaMetricsOptOut(page); + await clickContinue(page); + await clickDone(page); +} + +async function ensureMetaMetricsOptOut(page: Page) { + const checkbox = page.locator(metaMetricsSelectors.checkbox); + await checkbox.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + + if (await checkbox.isChecked()) { + await checkbox.click(); + } +} + +async function clickContinue(page: Page) { + const button = page.locator(metaMetricsSelectors.continueButton); + await button.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await button.click(); +} + +async function clickDone(page: Page) { + const button = page.locator(metaMetricsSelectors.doneButton); + await button.waitFor({ state: 'visible', timeout: DEFAULT_TIMEOUT }); + await button.click(); +} diff --git a/tests/support/metaMask/importWallet.ts b/tests/support/metaMask/importWallet.ts new file mode 100644 index 0000000..899f12b --- /dev/null +++ b/tests/support/metaMask/importWallet.ts @@ -0,0 +1,160 @@ +import path from 'node:path'; +import { chromium, ChromiumBrowserContext, Page } from '@playwright/test'; +import { METAMASK_CACHE_DIR_NAME } from '../template/constants'; +import { waitUntilStable } from '../template/waitUntilStable'; +import { prepareExtension } from './prepareExtension'; + +const DEFAULT_VIEWPORT = { width: 360, height: 592 }; +const CONTEXT_CLOSE_GRACE_MS = 1_000; +const EXT_ID_RETRIES = 5; +const EXT_ID_RETRY_DELAY_MS = 300; +const METAMASK_USER_DIR = 'metamask-user-data'; + +const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); + +function assertTruthy( + value: T, + msg: string +): asserts value is NonNullable { + if (value === null || value === undefined) { + throw new Error(msg); + } +} + +function toAbsolutePath(p: string) { + return path.resolve(p); +} + +function getUserDataDir(): string { + return path.join(process.cwd(), METAMASK_CACHE_DIR_NAME, METAMASK_USER_DIR); +} + +async function firstPageOrThrow( + context: ChromiumBrowserContext +): Promise { + const [page] = context.pages(); + assertTruthy(page, 'No pages were opened by the extension context.'); + return page; +} + +async function tryGetExtensionIdOnce( + context: ChromiumBrowserContext +): Promise { + // Prefer service workers (MV3); background pages are rare in MV3. + const sw = context.serviceWorkers(); + for (const worker of sw) { + try { + const url = worker.url(); + if (url.startsWith('chrome-extension://')) { + const id = url.split('/')[2]; + if (id) return id; + } + } catch { + // ignore and continue + } + } + + // Fallback: parse from any extension page if present + for (const page of context.pages()) { + try { + const url = page.url(); + if (url.startsWith('chrome-extension://')) { + const id = url.split('/')[2]; + if (id) return id; + } + } catch { + // ignore and continue + } + } + + return null; +} + +async function getExtensionIdWithRetry( + context: ChromiumBrowserContext +): Promise { + for (let attempt = 1; attempt <= EXT_ID_RETRIES; attempt++) { + const id = await tryGetExtensionIdOnce(context); + if (id) return id; + await sleep(EXT_ID_RETRY_DELAY_MS); + } + throw new Error( + 'Could not determine extension ID (service worker/background not ready).' + ); +} + +export async function createBrowserContextWithExtension( + extensionPath: string +): Promise { + assertTruthy(extensionPath, 'Extension path is required'); + + const absoluteExtensionPath = toAbsolutePath(extensionPath); + const userDataDir = getUserDataDir(); + + // Give any previous persistent context time to release file locks. + await sleep(CONTEXT_CLOSE_GRACE_MS); + + try { + const context = await chromium.launchPersistentContext(userDataDir, { + headless: false, + args: [ + `--disable-extensions-except=${absoluteExtensionPath}`, + `--load-extension=${absoluteExtensionPath}` + ], + viewport: DEFAULT_VIEWPORT + }); + + assertTruthy(context, 'Failed to create Chromium persistent context'); + return context; + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + if ( + msg.includes('Target page, context or browser has been closed') || + msg.includes('userDataDir') || + msg.includes('already in use') + ) { + throw new Error( + `Failed to create browser context: a previous persistent context may still be closing or userDataDir is locked. Original error: ${msg}` + ); + } + throw new Error(`Failed to create browser context: ${msg}`); + } +} + +export async function getExtensionId( + context: ChromiumBrowserContext, + _extensionName: string // kept for signature parity; reserved for future filtering +): Promise { + assertTruthy(context, 'Browser context is required'); + try { + return await getExtensionIdWithRetry(context); + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to get extension ID: ${msg}`); + } +} + +// Downloads (if needed), loads MetaMask as an extension, and returns the context + extensionId. +export async function setupMetaMaskExtension(): Promise<{ + context: ChromiumBrowserContext; + extensionId: string; +}> { + try { + const extensionPath = await prepareExtension(); + assertTruthy(extensionPath, 'Failed to prepare MetaMask extension'); + + const context = await createBrowserContextWithExtension(extensionPath); + + // Ensure the initial extension page is stable before querying workers/pages + const first = await firstPageOrThrow(context); + await waitUntilStable(first); + + const extensionId = await getExtensionId(context, 'MetaMask'); + assertTruthy(extensionId, 'Failed to resolve MetaMask extension ID'); + + return { context, extensionId }; + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to setup MetaMask extension: ${msg}`); + } +} diff --git a/tests/support/metaMask/loadExtension.ts b/tests/support/metaMask/loadExtension.ts new file mode 100644 index 0000000..6e1bd24 --- /dev/null +++ b/tests/support/metaMask/loadExtension.ts @@ -0,0 +1,123 @@ +import path from 'node:path'; +import { chromium, type ChromiumBrowserContext } from '@playwright/test'; +import { METAMASK_CACHE_DIR_NAME } from '../template/constants'; +import { waitUntilStable } from '../template/waitUntilStable'; +import { prepareExtension } from './prepareExtension'; + +const METAMASK_USER_DIR = 'metamask-user-data'; +const CONTEXT_RELEASE_GRACE_MS = 1000; +const SERVICE_WORKER_RETRIES = 3; +const SERVICE_WORKER_RETRY_DELAY_MS = 300; + +// Utility: delay +const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); + +// Utility: fail early with types preserved +function ensure(value: T | null | undefined, message: string): T { + if (value == null) throw new Error(message); + return value; +} + +// Extract extension id from a service worker url +function extractExtensionIdFromUrl(url: string): string | null { + if (!url.startsWith('chrome-extension://')) return null; + const id = url.split('/')[2]; + return id && id.length > 0 ? id : null; +} + +// Try to read the extension id from existing service workers (with a small retry window for CI flakiness). +export async function getExtensionId( + context: ChromiumBrowserContext, + _extensionName: string // kept for signature parity / future filtering if needed +): Promise { + if (!context) throw new Error('Browser context is required'); + + for (let attempt = 0; attempt <= SERVICE_WORKER_RETRIES; attempt++) { + const workers = context.serviceWorkers(); + for (const sw of workers) { + const id = extractExtensionIdFromUrl(sw.url()); + if (id) return id; + } + if (attempt < SERVICE_WORKER_RETRIES) { + await sleep(SERVICE_WORKER_RETRY_DELAY_MS); + } + } + + throw new Error( + 'Could not find extension ID from service workers. The extension may not be loaded yet.' + ); +} + +// Launch a persistent Chromium context with a single loaded extension. +export async function createBrowserContextWithExtension( + extensionPath: string +): Promise { + const absoluteExtensionPath = path.resolve( + ensure(extensionPath, 'Extension path is required') + ); + + const userDataDir = path.join( + process.cwd(), + METAMASK_CACHE_DIR_NAME, + METAMASK_USER_DIR + ); + + // Give the previous persistent context time to fully release its lock on userDataDir. + await sleep(CONTEXT_RELEASE_GRACE_MS); + + try { + const context = await chromium.launchPersistentContext(userDataDir, { + headless: false, + args: [ + `--disable-extensions-except=${absoluteExtensionPath}`, + `--load-extension=${absoluteExtensionPath}` + ] + }); + + return ensure(context, 'Failed to create browser context'); + } catch (error) { + const msg = error instanceof Error ? error.message : String(error); + const isBusy = + msg.includes('Target page, context or browser has been closed') || + msg.includes('userDataDir') || + msg.includes('already in use'); + + if (isBusy) { + throw new Error( + 'Failed to create browser context: previous persistent context may still be closing. ' + + `Ensure contexts are closed before launching a new one. Original error: ${msg}` + ); + } + throw new Error(`Failed to create browser context with extension: ${msg}`); + } +} + +// Prepare the MetaMask extension, start a browser context, stabilize, and return the context + extensionId. +export async function setupMetaMaskExtension(): Promise<{ + context: ChromiumBrowserContext; + extensionId: string; +}> { + // 1) Ensure extension bits exist on disk (download/unzip if needed). + const extensionPath = ensure( + await prepareExtension(), + 'Failed to prepare MetaMask extension' + ); + + // 2) Launch a persistent context with the extension. + const context = await createBrowserContextWithExtension(extensionPath); + + // 3) Wait for the first page to be interactive (extension often opens a tab). + const firstPage = ensure( + context.pages()[0], + 'Extension did not open an initial page' + ); + await waitUntilStable(firstPage); + + // 4) Resolve the extension id via service worker. + const extensionId = ensure( + await getExtensionId(context, 'MetaMask'), + 'Failed to get extension ID' + ); + + return { context, extensionId }; +} diff --git a/tests/support/metaMask/prepareExtension.ts b/tests/support/metaMask/prepareExtension.ts new file mode 100644 index 0000000..4d2e447 --- /dev/null +++ b/tests/support/metaMask/prepareExtension.ts @@ -0,0 +1,29 @@ +// prepareExtension.ts +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { downloadFileFromUrl } from '../fs/downloadFileFromUrl'; +import { buildMetamaskZipUrl, resolveMetamaskVersion } from './constants'; +import { unzipArchive } from './unzipArchive'; + +export async function prepareExtension(forceCache = true): Promise { + const version = resolveMetamaskVersion(); + + const outputDir = forceCache + ? path.join(process.cwd(), '.cache') + : path.resolve('./', 'downloads'); + + await fs.mkdir(outputDir, { recursive: true }); + + const fileName = `metamask-chrome-${version}.zip`; + const url = buildMetamaskZipUrl(version); + + const { filePath } = await downloadFileFromUrl({ + url, + outputDir, + fileName, + overrideFile: false + }); + + const { outputPath } = await unzipArchive({ archivePath: filePath }); + return outputPath; +} diff --git a/tests/support/metaMask/setupMetaMaskWallet.ts b/tests/support/metaMask/setupMetaMaskWallet.ts new file mode 100644 index 0000000..9d81cdf --- /dev/null +++ b/tests/support/metaMask/setupMetaMaskWallet.ts @@ -0,0 +1,113 @@ +import { Page } from '@playwright/test'; +import { handleMetaMetrics } from '../metaMask/handleMetrics'; +import { getPageAndWaitForLoad } from '../template/getPageAndWaitForLoad'; +import { waitUntilStable } from '../template/waitUntilStable'; +import { createPassword } from './createPassword'; +import { fillSecretRecoveryPhrase } from './fillSecretRecoveryPhrase'; +import { setupMetaMaskExtension } from './loadExtension'; + +const DEFAULT_PAGE_TIMEOUT = 10000; + +const metaMaskSelectors = { + unlockPasswordInput: '[data-testid="unlock-password"]', + importWalletButton: '[data-testid="onboarding-import-wallet"]', + importWithSRPButton: '[data-testid="onboarding-import-with-srp-button"]', + srpNoteInput: '[data-testid="srp-input-import__srp-note"]' +}; + +export async function setupMetaMaskWallet(mnemonic: string, password: string) { + try { + const { context, extensionId } = await initializeMetaMaskExtension(); + const metamaskPage = await openAndPrepareExtensionPage( + context, + extensionId + ); + + const onboardingState = await detectOnboardingState(metamaskPage); + + if (onboardingState === 'unlock') { + await unlockExistingWallet(metamaskPage, password); + return { context, extensionId, metamaskPage }; + } + + await importWalletFlow(metamaskPage, mnemonic, password); + await handleMetaMetrics(metamaskPage); + + return { context, extensionId, metamaskPage }; + } catch (error) { + throw new Error( + `Failed to setup MetaMask wallet: ${ + error instanceof Error ? error.message : 'Unknown error' + }` + ); + } +} + +async function initializeMetaMaskExtension() { + const { context, extensionId } = await setupMetaMaskExtension(); + if (!extensionId) throw new Error('Failed to get MetaMask extension ID'); + return { context, extensionId }; +} + +async function openAndPrepareExtensionPage(context: any, extensionId: string) { + const metamaskPage = await getPageAndWaitForLoad( + context, + `chrome-extension://${extensionId}/` + ); + await waitUntilStable(metamaskPage); + return metamaskPage; +} + +async function detectOnboardingState(page: Page) { + const unlockPassword = page.locator(metaMaskSelectors.unlockPasswordInput); + const importWallet = page.locator(metaMaskSelectors.importWalletButton); + + return Promise.race([ + unlockPassword + .waitFor({ state: 'visible', timeout: DEFAULT_PAGE_TIMEOUT }) + .then(() => 'unlock' as const), + importWallet + .waitFor({ state: 'visible', timeout: DEFAULT_PAGE_TIMEOUT }) + .then(() => 'import' as const) + ]).catch(() => { + throw new Error( + 'Neither "unlock-password" nor "onboarding-import-wallet" appeared within timeout' + ); + }); +} + +async function unlockExistingWallet(page: Page, password: string) { + const passwordInput = page.locator(metaMaskSelectors.unlockPasswordInput); + await passwordInput.fill(password); + await passwordInput.press('Enter'); +} + +async function importWalletFlow( + page: Page, + mnemonic: string, + password: string +) { + await startImportProcess(page); + await fillFirstSecretRecoveryPhraseWord(page, mnemonic); + await fillSecretRecoveryPhrase(page, mnemonic); + await createPassword(page, password); +} + +async function startImportProcess(page: Page) { + const importButton = page.locator(metaMaskSelectors.importWalletButton); + await importButton.click(); + + const srpButton = page.locator(metaMaskSelectors.importWithSRPButton); + await srpButton.waitFor({ state: 'visible', timeout: DEFAULT_PAGE_TIMEOUT }); + await srpButton.click(); +} + +async function fillFirstSecretRecoveryPhraseWord(page: Page, mnemonic: string) { + const srpInput = page.locator(metaMaskSelectors.srpNoteInput); + await srpInput.waitFor({ state: 'visible', timeout: DEFAULT_PAGE_TIMEOUT }); + await srpInput.click(); + + const [firstWord] = mnemonic.split(' '); + await srpInput.type(firstWord); + await srpInput.press('Enter'); +} diff --git a/tests/support/metaMask/unzipArchive.ts b/tests/support/metaMask/unzipArchive.ts new file mode 100644 index 0000000..ca1b9a6 --- /dev/null +++ b/tests/support/metaMask/unzipArchive.ts @@ -0,0 +1,81 @@ +import { execFile } from 'node:child_process'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { promisify } from 'node:util'; + +const execFileAsync = promisify(execFile); + +type UnzipArchiveOptions = { + archivePath: string; + overwrite?: boolean; +}; + +type UnzipArchiveResult = { + outputPath: string; + unzipSkipped: boolean; +}; + +// Unzips an archive using the system `unzip` command. +//Returns the extraction path and whether extraction was skipped due to cache. +export async function unzipArchive( + options: UnzipArchiveOptions +): Promise { + const { archivePath, overwrite = false } = options; + const outputPath = deriveOutputPath(archivePath); + + if (await shouldSkipUnzip(outputPath, overwrite)) { + return { outputPath, unzipSkipped: true }; + } + + await ensureCleanOutputDir(outputPath, overwrite); + await extractZipArchive(archivePath, outputPath); + + return { outputPath, unzipSkipped: false }; +} + +function deriveOutputPath(archivePath: string): string { + const { dir, name } = path.parse(archivePath); + return path.join(dir, name); +} + +async function shouldSkipUnzip( + outputPath: string, + overwrite: boolean +): Promise { + try { + await fs.access(outputPath); + return !overwrite; + } catch { + return false; + } +} + +async function ensureCleanOutputDir( + outputPath: string, + overwrite: boolean +): Promise { + try { + if (overwrite) { + await fs.rm(outputPath, { recursive: true, force: true }); + } + } catch { + // ignore + } + await fs.mkdir(outputPath, { recursive: true }); +} + +// Extracts a ZIP archive using the system `unzip` utility. +// Requires `unzip` to be available on the system (default on macOS/Linux, available via WSL on Windows). +async function extractZipArchive( + archivePath: string, + outputPath: string +): Promise { + try { + await execFileAsync('unzip', ['-o', archivePath, '-d', outputPath]); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + throw new Error( + `[unzipArchive] Failed to extract ${archivePath}: ${message}` + ); + } +} diff --git a/tests/support/metaMask/waitForMetaMaskLoad.ts b/tests/support/metaMask/waitForMetaMaskLoad.ts new file mode 100644 index 0000000..136f41b --- /dev/null +++ b/tests/support/metaMask/waitForMetaMaskLoad.ts @@ -0,0 +1,92 @@ +import { errors, Page } from '@playwright/test'; +import { WaitForMetaMaskLoadOptions } from '../template/types'; +import { waitUntilStable } from '../template/waitUntilStable'; + +const DEFAULT_TIMEOUT = 10_000; +const DEFAULT_CONCURRENCY = 3; + +const BASE_LOADING_SELECTORS: readonly string[] = [ + '.loading-logo', + '.loading-spinner', + '.loading-overlay', + '.loading-overlay__spinner', + '.loading-span', + '.loading-indicator', + '#loading__logo', + '#loading__spinner', + '.mm-button-base__icon-loading', + '.loading-swaps-quotes', + '.loading-heartbeat', + '.spinner' +]; + +/** + * Waits for MetaMask UI to be usable: + * 1) (optional) wait for page stability + * 2) wait for known loading indicators to hide (best-effort) + * 3) brief post delay (conditional) + */ +export async function waitForMetaMaskLoad( + page: Page, + options: WaitForMetaMaskLoadOptions +): Promise { + const { + selectorTimeoutMs = DEFAULT_TIMEOUT, + extraLoadingSelectors = [], + skipInitialStabilityWait = false, + concurrency = DEFAULT_CONCURRENCY // how many selectors to wait on in parallel + } = options; + + try { + if (!skipInitialStabilityWait) { + await waitUntilStable(page); + } + + const selectors = Array.from( + new Set([...BASE_LOADING_SELECTORS, ...extraLoadingSelectors]) + ); + + await waitSelectorsHiddenWithConcurrency( + page, + selectors, + selectorTimeoutMs, + concurrency + ); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + console.warn(`[waitForMetaMaskLoad] Non-fatal warning: ${msg}`); + } +} + +async function waitSelectorsHiddenWithConcurrency( + page: Page, + selectors: string[], + perSelectorTimeoutMs: number, + concurrency: number +) { + // One stability wait per batch, not per selector + await waitUntilStable(page); + + // Process selectors with a small concurrency to reduce polling in CI/CD + let i = 0; + while (i < selectors.length) { + const batch = selectors.slice(i, i + Math.max(1, concurrency)); + await Promise.all( + batch.map(async (selector) => { + try { + await page.waitForSelector(selector, { + state: 'hidden', + timeout: perSelectorTimeoutMs + }); + } catch (err) { + if (err instanceof errors.TimeoutError) { + // OK if a selector never appears on this screen + return; + } + throw err; + } + }) + ); + i += batch.length; + } +} diff --git a/tests/support/template/checkBalanceUpdate.ts b/tests/support/template/checkBalanceUpdate.ts new file mode 100644 index 0000000..68bdc1a --- /dev/null +++ b/tests/support/template/checkBalanceUpdate.ts @@ -0,0 +1,53 @@ +import { expect, Page } from '@playwright/test'; +import { TEST_CONSTANTS } from './constants'; +import { extractBalanceFromContainer } from './extractBalanceFromContainer'; +import { CheckBalanceUpdateType } from './types'; + +export const checkBalanceUpdate = async ({ + page, + containerSelector, + initialBalance, + expectedChange +}: CheckBalanceUpdateType) => { + const expectedBalance = initialBalance + expectedChange; + + const pollFunction = async () => { + const balance = await extractBalanceFromContainer({ + page, + containerSelector, + selectorType: 'testId' + }); + + return balance; + }; + + await expect + .poll(pollFunction, { + message: `Balance should reach ${expectedBalance} (change: ${expectedChange})`, + timeout: TEST_CONSTANTS.BALANCE_POLLING_TIMEOUT + }) + .toBeCloseTo(expectedBalance, TEST_CONSTANTS.BALANCE_PRECISION); +}; + +export const checkPingPongBalanceUpdate = async ({ + page, + containerSelector, + initialBalance, + isPing +}: { + page: Page; + containerSelector: string; + initialBalance: number; + isPing: boolean; +}) => { + const expectedChange = isPing + ? TEST_CONSTANTS.PING_BALANCE_CHANGE + : TEST_CONSTANTS.PONG_BALANCE_CHANGE; + + await checkBalanceUpdate({ + page, + containerSelector, + initialBalance, + expectedChange + }); +}; diff --git a/tests/support/template/checkButtonStatus.ts b/tests/support/template/checkButtonStatus.ts new file mode 100644 index 0000000..64c79ee --- /dev/null +++ b/tests/support/template/checkButtonStatus.ts @@ -0,0 +1,27 @@ +import { expect } from '@playwright/test'; +import { PingPongEnum } from './testdata'; +import { CheckButtonStatusType } from './types'; + +export const checkButtonStatus = async ({ + page, + type, + lastClickedButton +}: CheckButtonStatusType) => { + const container = page.locator(`#ping-pong-${type}`); + await container.scrollIntoViewIfNeeded(); + + const suffix = type === PingPongEnum.abi ? 'Abi' : 'Raw'; + const pingButton = container.getByTestId(`btnPing${suffix}`); + const pongButton = container.getByTestId(`btnPong${suffix}`); + + // Check that ping button became disabled by looking for disabled attribute + if (lastClickedButton === 'ping') { + await expect(pingButton).toHaveAttribute('disabled'); + return; + } + + if (lastClickedButton === 'pong') { + await expect(pongButton).toHaveAttribute('disabled'); + return; + } +}; diff --git a/tests/support/template/checkClipboardContains.ts b/tests/support/template/checkClipboardContains.ts new file mode 100644 index 0000000..1c9b9c8 --- /dev/null +++ b/tests/support/template/checkClipboardContains.ts @@ -0,0 +1,41 @@ +import { expect } from '@playwright/test'; +import { pasteStringFromClipboard } from './pasteStringFromClipboard'; +import { CheckClipboardContainsType } from './types'; + +export const checkClipboardContains = async ({ + page, + context, + text, + timeout = 5000 // 5 seconds +}: CheckClipboardContainsType) => { + const startTime = Date.now(); + const maxAttempts = 10; + let attempts = 0; + + while (attempts < maxAttempts) { + try { + const clipboardText = await pasteStringFromClipboard(page, context); + if (clipboardText.includes(text)) { + return; // Success - text found + } + } catch (error) { + // Retry + } + + attempts++; + + // Check if we've exceeded the timeout + if (Date.now() - startTime > timeout) { + throw new Error( + `Clipboard check timed out after ${timeout}ms. Expected text "${text}" was not found.` + ); + } + + // Wait a bit before the next attempt + await page.waitForTimeout(500); + } + + // Game over - we've exhausted all attempts + const finalClipboardText = await pasteStringFromClipboard(page, context); + expect(finalClipboardText).toContain(text); +}; diff --git a/tests/support/template/checkConnectionToWallet.ts b/tests/support/template/checkConnectionToWallet.ts new file mode 100644 index 0000000..f4cd674 --- /dev/null +++ b/tests/support/template/checkConnectionToWallet.ts @@ -0,0 +1,12 @@ +import { expect, Page } from '@playwright/test'; +import { SelectorsEnum } from './testdata'; + +// Check if the template is connected to the web wallet by veryfing that +// the template page contains the wallet address which confirms the connection +export const checkConnectionToWallet = async ( + page: Page, + walletAddress: string +) => { + const addressElement = await page.getByTestId(SelectorsEnum.accountAddress); + await expect(addressElement).toContainText(walletAddress); +}; diff --git a/tests/support/template/confirmPrivateKeyTransaction.ts b/tests/support/template/confirmPrivateKeyTransaction.ts new file mode 100644 index 0000000..b521a0c --- /dev/null +++ b/tests/support/template/confirmPrivateKeyTransaction.ts @@ -0,0 +1,10 @@ +import { Page } from '@playwright/test'; +import { SelectorsEnum } from './testdata'; + +export const confirmPrivateKeyTransaction = async ( + page: Page, + privateKey: string +) => { + await page.getByTestId(SelectorsEnum.privateKey).fill(privateKey); + await page.getByTestId(SelectorsEnum.submitButton).click(); +}; diff --git a/tests/support/template/confirmWalletTransaction.ts b/tests/support/template/confirmWalletTransaction.ts new file mode 100644 index 0000000..e5d284c --- /dev/null +++ b/tests/support/template/confirmWalletTransaction.ts @@ -0,0 +1,38 @@ +import { Page } from '@playwright/test'; +import { SelectorsEnum } from './testdata'; +import { getTestIdSelector } from './testIdSelector'; +import { WebWalletLoginMethodType } from './types'; + +const confirmWithKeystore = async (walletPage: Page, password: string) => { + await walletPage.getByTestId(SelectorsEnum.passwordInput).fill(password); + await walletPage.getByTestId(SelectorsEnum.submitButton).click(); +}; + +const confirmWithPem = async (walletPage: Page, pemPath: string) => { + await walletPage.setInputFiles( + getTestIdSelector(SelectorsEnum.walletFile), + pemPath + ); + await walletPage.getByTestId(SelectorsEnum.submitButton).click(); +}; + +export const confirmWalletTransaction = async ( + page: Page, + loginMethod: WebWalletLoginMethodType +) => { + switch (true) { + // Authenticate with keystore + case Boolean(loginMethod.keystore): + await confirmWithKeystore(page, loginMethod.password ?? ''); + return; + + // Authenticate with PEM + case Boolean(loginMethod.pem): + await confirmWithPem(page, loginMethod.pem!); + return; + + // No authentication method provided + default: + return; + } +}; diff --git a/tests/support/template/connectInMemoryProvider.ts b/tests/support/template/connectInMemoryProvider.ts new file mode 100644 index 0000000..5836976 --- /dev/null +++ b/tests/support/template/connectInMemoryProvider.ts @@ -0,0 +1,32 @@ +import { SelectorsEnum } from './testdata'; +import { InMemoryProviderType } from './types'; + +const authenticateWithInMemoryProvider = async ({ + page, + loginMethod +}: InMemoryProviderType) => { + await page.locator(SelectorsEnum.addressInput).fill(loginMethod.address); + await page + .locator(SelectorsEnum.privateKeyInput) + .fill(loginMethod.privateKey); + + await page.getByRole('button', { name: 'Submit' }).click(); +}; + +export const connectInMemoryProvider = async ({ + page, + loginMethod +}: InMemoryProviderType) => { + await page.getByTestId(SelectorsEnum.inMemoryButton).click(); + + if (!loginMethod.address || !loginMethod.privateKey) { + throw new Error( + 'Both address and private key are required when using an in memory provider.' + ); + } + + await authenticateWithInMemoryProvider({ + page, + loginMethod + }); +}; diff --git a/tests/support/template/connectWebWallet.ts b/tests/support/template/connectWebWallet.ts new file mode 100644 index 0000000..dd2dfaf --- /dev/null +++ b/tests/support/template/connectWebWallet.ts @@ -0,0 +1,120 @@ +import { TEST_CONSTANTS } from './constants'; +import { getPageAndWaitForLoad } from './getPageAndWaitForLoad'; +import { OriginPageEnum, SelectorsEnum } from './testdata'; +import { getTestIdSelector } from './testIdSelector'; +import { + AuthenticateWithKeystoreType, + AuthenticateWithPemType, + ConnectWebWalletType +} from './types'; + +const authenticateWithKeystore = async ({ + walletPage, + keystorePath, + keystorePassword +}: AuthenticateWithKeystoreType) => { + // Click the keystore button + await walletPage.getByTestId(SelectorsEnum.keystoreButton).click(); + + // Upload the keystore file + await walletPage.setInputFiles( + getTestIdSelector(SelectorsEnum.walletFile), + keystorePath + ); + + // Wait for file processing to complete + await walletPage.waitForLoadState(); + + // Fill the password input + const passwordInput = walletPage.getByTestId(SelectorsEnum.passwordInput); + await passwordInput.fill(keystorePassword); + + // Wait for file processing to complete + await walletPage.waitForLoadState(); + + // Click the submit button + await walletPage.getByTestId(SelectorsEnum.submitButton).click(); + + // Click the confirm button + await walletPage.getByTestId(SelectorsEnum.confirmButton).click(); +}; + +const authenticateWithPem = async ({ + walletPage, + pemPath +}: AuthenticateWithPemType) => { + // Click the PEM button + await walletPage.getByTestId(SelectorsEnum.pemButton).click(); + + // Upload the PEM file + await walletPage.setInputFiles( + getTestIdSelector(SelectorsEnum.walletFile), + pemPath + ); + + // Wait for file processing to complete + await walletPage.waitForLoadState(); + + // Click the submit button + await walletPage.getByTestId(SelectorsEnum.submitButton).click(); +}; + +export const connectWebWallet = async ({ + page, + loginMethod +}: ConnectWebWalletType) => { + // Click the cross-window button to open wallet + await page.getByTestId(SelectorsEnum.crossWindow).click(); + + // Wait for the web wallet page to be loaded which is the new tab + const walletPage = await getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); + + // If the web wallet page is not loaded, throw an error + if (!walletPage) { + throw new Error( + `Web wallet page containing ${OriginPageEnum.multiversxWallet} is not loaded.` + ); + } + + // Authenticate with keystore + if (loginMethod.keystore) { + if (!loginMethod.password) { + throw new Error('Password is required when using a keystore.'); + } + + await authenticateWithKeystore({ + walletPage, + keystorePath: loginMethod.keystore, + keystorePassword: loginMethod.password + }); + + try { + await walletPage.waitForEvent('close', { + timeout: TEST_CONSTANTS.PAGE_CLOSE_TIMEOUT + }); + } catch (error) { + // do nothing + } + return; + } + + // Authenticate with PEM + if (loginMethod.pem) { + await authenticateWithPem({ + walletPage, + pemPath: loginMethod.pem + }); + + try { + await walletPage.waitForEvent('close', { + timeout: TEST_CONSTANTS.PAGE_CLOSE_TIMEOUT + }); + } catch (error) { + // do nothing + } + return; + } +}; diff --git a/tests/support/template/constants.ts b/tests/support/template/constants.ts new file mode 100644 index 0000000..af40153 --- /dev/null +++ b/tests/support/template/constants.ts @@ -0,0 +1,25 @@ +export const PATHS = { + WALLETS_DIR: 'tests/support/wallets' +} as const; + +export const METAMASK_CACHE_DIR_NAME = '.cache'; + +export const TEST_CONSTANTS = { + MIN_BALANCE_FOR_PING_PONG: 1, // 1 EGLD + MIN_BALANCE_FOR_BATCH_TX: 5, // 5 EGLD + MIN_BALANCE_FOR_WRAP_AND_MULTI_TRANSFER: 4, // 4 EGLD + MIN_BALANCE_FOR_SWAP_AND_LOCK: 4, // 4 EGLD + + URL_NAVIGATION_TIMEOUT: 10000, // 10 seconds + BALANCE_POLLING_TIMEOUT: 90000, // 90 seconds + PAGE_WAIT_TIMEOUT: 30000, // 30 seconds + TOAST_WAIT_TIMEOUT: 60000, // 60 seconds + + PING_PONG_COOLDOWN: 3 * 60 * 1000, // 3 minutes in milliseconds + PING_BALANCE_CHANGE: -1.0, // Balance decreases by 1 EGLD + gas fees + PONG_BALANCE_CHANGE: 1.0, // Balance increases by 1 EGLD - gas fees + + BALANCE_PRECISION: 2, + + PAGE_CLOSE_TIMEOUT: 10000 // 10 seconds +} as const; diff --git a/tests/support/template/extractBalanceFromContainer.ts b/tests/support/template/extractBalanceFromContainer.ts new file mode 100644 index 0000000..df6a9ad --- /dev/null +++ b/tests/support/template/extractBalanceFromContainer.ts @@ -0,0 +1,39 @@ +import { expect } from '@playwright/test'; +import { SelectorsEnum } from './testdata'; +import { getTestIdSelector } from './testIdSelector'; +import { ExtractBalanceFromContainerType } from './types'; + +export const extractBalanceFromContainer = async ({ + page, + containerSelector, + selectorType = 'testId' +}: ExtractBalanceFromContainerType): Promise => { + const containerElement = + selectorType === 'testId' + ? page.getByTestId(containerSelector) + : page.locator(containerSelector); + + await containerElement.scrollIntoViewIfNeeded(); + + const balanceElement = containerElement.getByTestId(SelectorsEnum.balance); + await expect(balanceElement).toBeVisible(); + + // Integer part + const intText = ( + await balanceElement + .locator(getTestIdSelector(SelectorsEnum.formatAmountInt)) + .innerText() + )?.trim(); + + // Decimals part + const decimalsText = ( + await balanceElement + .locator(getTestIdSelector(SelectorsEnum.formatAmountDecimals)) + .innerText() + )?.trim(); + + // Combine with decimal point + const fullNumber = decimalsText ? `${intText}.${decimalsText}` : intText; + + return parseFloat(fullNumber || '0'); +}; diff --git a/tests/support/template/getPageAndWaitForLoad.ts b/tests/support/template/getPageAndWaitForLoad.ts new file mode 100644 index 0000000..86965a2 --- /dev/null +++ b/tests/support/template/getPageAndWaitForLoad.ts @@ -0,0 +1,78 @@ +import { BrowserContext, Page } from '@playwright/test'; +import { waitUntilStable } from './waitUntilStable'; + +const DEFAULT_WAIT_TIMEOUT = 15_000; + +export async function getPageAndWaitForLoad( + context: BrowserContext, + pageUrlFragment: string, + options?: { viewport?: { width: number; height: number }; timeout?: number } +): Promise { + let retries = 0; + const maxRetries = 3; + + while (retries < maxRetries) { + try { + const timeoutMs = options?.timeout || DEFAULT_WAIT_TIMEOUT; + + // Try to find an already open page or wait (by polling) for a page to + // navigate to the expected URL. Relying on the 'page' event can + // miss cases where the page already exists (about:blank) and then + // navigates later, or when navigation happens in the same tab. + const page = + context.pages().find((p) => p.url().includes(pageUrlFragment)) || + (await waitForPageByUrlFragment(context, pageUrlFragment, timeoutMs)); + + if (!page) throw new Error('Notification page not found'); + + if (options?.viewport) { + await page.setViewportSize(options.viewport); + } + + // Wait for the page to be stable + await waitUntilStable(page); + + return page; + } catch (error) { + retries++; + const message = error instanceof Error ? error.message : 'Unknown error'; + const openedPageUrls = context + .pages() + .map((p) => p.url()) + .filter(Boolean); + console.warn( + `[getPageAndWaitForLoad] Retry ${retries}/3 after error: ${message}. Open pages (${ + openedPageUrls.length + }): ${openedPageUrls.join(', ')}` + ); + + if (retries >= maxRetries) throw error; + await new Promise((r) => setTimeout(r, 1000 * retries)); + } + } + + throw new Error('getPageAndWaitForLoad: Unexpected end of retries'); +} + +async function waitForPageByUrlFragment( + context: BrowserContext, + fragment: string, + timeoutMs: number +): Promise { + const pollIntervalMs = 250; + const deadline = Date.now() + timeoutMs; + + while (Date.now() < deadline) { + const match = context.pages().find((p) => p.url().includes(fragment)); + if (match) return match; + + // Briefly wait for any new page to appear; ignore timeouts and keep polling. + try { + await context.waitForEvent('page', { timeout: pollIntervalMs }); + } catch { + // no-op; continue polling + } + } + + return null; +} diff --git a/tests/support/template/globalSetup.ts b/tests/support/template/globalSetup.ts new file mode 100644 index 0000000..5196214 --- /dev/null +++ b/tests/support/template/globalSetup.ts @@ -0,0 +1,95 @@ +// This global setup materializes secret keystore files from environment variables +// so Playwright tests can reference stable file paths without committing secrets. +// +// Secrets source: +// - On CI (GitHub Actions): injected via repository/environment Secrets +// (e.g. KEYSTORE1_JSON_B64, KEYSTORE{N}_PASSWORD, KEYSTORE{N}_ADDRESS). +// - Locally: provided via .env.test.local/.env and loaded here. +// +// Why base64? +// - JSON keystores are stored as KEYSTORE{N}_JSON_B64 to pass safely through +// CI env vars and avoid accidental logging. We decode and write them to +// WALLETS_DIR on startup. Passwords/addresses are read directly from env +// by the tests and are never written to disk. + +import path from 'path'; +import { loadLocalEnv } from './loadLocalEnv'; +import { writeValueToFile } from '../fs/writeValueToFile'; +import { type FileEncoding } from './types'; + +// Load environment variables for local runs; CI already has env set +loadLocalEnv('test'); + +// Write keystore files from environment variables +async function writeKeystoreFilesFromEnv( + defaultEncoding: FileEncoding = 'base64', + skipIfExists: boolean = false +) { + // Resolve wallets directory without relying on process.cwd + const walletsDir = process.env.WALLETS_DIR + ? path.resolve(process.env.WALLETS_DIR) + : path.resolve(__dirname, '..', 'wallets'); + + const mappings: Array<{ + envKey: string; + outPath: string; + encoding?: FileEncoding; + }> = [ + { + envKey: 'KEYSTORE1_JSON_B64', + outPath: `${walletsDir}/keystoreFile1.json`, + encoding: 'base64' + }, + { + envKey: 'KEYSTORE2_JSON_B64', + outPath: `${walletsDir}/keystoreFile2.json`, + encoding: 'base64' + }, + { + envKey: 'KEYSTORE3_JSON_B64', + outPath: `${walletsDir}/keystoreFile3.json`, + encoding: 'base64' + }, + { + envKey: 'KEYSTORE4_JSON_B64', + outPath: `${walletsDir}/keystoreFile4.json`, + encoding: 'base64' + }, + { + envKey: 'KEYSTORE5_PEM_B64', + outPath: `${walletsDir}/keystoreFile5.pem`, + encoding: 'base64' + }, + { + envKey: 'KEYSTORE6_PRIVATE_KEY_UTF8', + outPath: `${walletsDir}/keystoreFile6.key`, + encoding: 'none' + } + ]; + + // Write keystore files from environment variables + for (const { envKey, outPath, encoding } of mappings) { + const value = process.env[envKey]; + if (!value?.trim()) { + console.warn(`[globalSetup] Missing or empty env var: ${envKey}`); + continue; + } + + try { + writeValueToFile( + value, + outPath, + encoding ?? defaultEncoding, + skipIfExists + ); + console.log(`[globalSetup] Wrote ${outPath}`); + } catch (error) { + console.error(`[globalSetup] Failed to write ${outPath}:`, error); + } + } +} + +// Global setup function +export default async function globalSetup() { + await writeKeystoreFilesFromEnv('base64', true); +} diff --git a/tests/support/template/handlePingPong.ts b/tests/support/template/handlePingPong.ts new file mode 100644 index 0000000..fe5f9cb --- /dev/null +++ b/tests/support/template/handlePingPong.ts @@ -0,0 +1,36 @@ +import { TEST_CONSTANTS } from './constants'; +import { PingPongEnum } from './testdata'; +import { HandlePingPongType } from './types'; + +export const handlePingPong = async ({ page, type }: HandlePingPongType) => { + const container = page.locator(`#ping-pong-${type}`); + await container.scrollIntoViewIfNeeded(); + + const suffix = type === PingPongEnum.abi ? 'Abi' : 'Raw'; + const pingButton = container.getByTestId(`btnPing${suffix}`); + const pongButton = container.getByTestId(`btnPong${suffix}`); + + // Use Playwright's isDisabled() for clarity + const isPingEnabled = !(await pingButton.isDisabled()); + const isPongEnabled = !(await pongButton.isDisabled()); + + if (!isPingEnabled && !isPongEnabled) { + throw new Error('Neither Ping nor Pong button are enabled!'); + } + + if (isPingEnabled) { + await pingButton.click(); + return 'ping'; + } + + if (isPongEnabled) { + await pongButton.click(); + return 'pong'; + } + + throw new Error( + `Neither Ping nor Pong button are enabled! Did you send a Ping or Pong within ${ + TEST_CONSTANTS.PING_PONG_COOLDOWN / 1000 / 60 + } minutes?` + ); +}; diff --git a/tests/support/template/index.ts b/tests/support/template/index.ts new file mode 100644 index 0000000..f577492 --- /dev/null +++ b/tests/support/template/index.ts @@ -0,0 +1,51 @@ +export { checkBalanceUpdate } from './checkBalanceUpdate'; + +export { checkButtonStatus } from './checkButtonStatus'; + +export { checkClipboardContains } from './checkClipboardContains'; + +export { checkConnectionToWallet } from './checkConnectionToWallet'; + +export { checkPingPongBalanceUpdate } from './checkBalanceUpdate'; + +export { confirmWalletTransaction } from './confirmWalletTransaction'; + +export { connectInMemoryProvider } from './connectInMemoryProvider'; + +export { connectWebWallet } from './connectWebWallet'; + +export { countTransactions } from './parseTransactionsTable'; + +export { ensureDirectoryExists } from '../fs/ensureDirectoryExists'; + +export { extractBalanceFromContainer } from './extractBalanceFromContainer'; + +export { filterTransactions } from './parseTransactionsTable'; + +export { getTestIdSelector } from './testIdSelector'; + +export { handleMetaMaskSnap } from '../metaMask/handleMetaMaskSnap'; + +export { handlePingPong } from './handlePingPong'; + +export { navigateToConnectWallet } from './navigateToConnectWallet'; + +export { parseTransactionsTable } from './parseTransactionsTable'; + +export { pasteStringFromClipboard } from './pasteStringFromClipboard'; + +export { readValueFromFile } from '../fs/readValueFromFile'; + +export { signBatchTransactions } from './signBatchTransactions'; + +export { getPageAndWaitForLoad } from './getPageAndWaitForLoad'; + +export { waitForToastToBeClosed } from './waitForToastToBeClosed'; + +export { waitForToastToBeDisplayed } from './waitForToastToBeDisplayed'; + +export { waitForTransactionToastToContain } from './waitForTransactionToastToShow'; + +export { waitUntilStable } from './waitUntilStable'; + +export { writeValueToFile } from '../fs/writeValueToFile'; diff --git a/tests/support/template/loadLocalEnv.ts b/tests/support/template/loadLocalEnv.ts new file mode 100644 index 0000000..cafb2cf --- /dev/null +++ b/tests/support/template/loadLocalEnv.ts @@ -0,0 +1,17 @@ +import { loadEnv } from 'vite'; + +export function loadLocalEnv(modeDefault: string = 'test'): void { + try { + const mode = process.env.MODE || modeDefault; + const localEnv = loadEnv(mode, process.cwd(), ''); + for (const [key, value] of Object.entries(localEnv)) { + if (process.env[key] === undefined) { + process.env[key] = value; + } + } + } catch (_) { + // If vite's loadEnv isn't available, silently skip. + } +} + + diff --git a/tests/support/template/navigateToConnectWallet.ts b/tests/support/template/navigateToConnectWallet.ts new file mode 100644 index 0000000..d19919f --- /dev/null +++ b/tests/support/template/navigateToConnectWallet.ts @@ -0,0 +1,18 @@ +import { Page } from '@playwright/test'; + +export const navigateToConnectWallet = async (page: Page) => { + const maxRetries = 5; + for (let i = 0; i < maxRetries; i++) { + try { + await page.goto('/', { waitUntil: 'load', timeout: 60 * 1000 }); // Increase timeout + break; + } catch (error) { + console.warn( + `[navigateToConnectWallet] Attempt ${i + 1} failed: ${error.message}` + ); + if (i === maxRetries - 1) throw error; + await page.waitForTimeout(5000); // Increase wait time + } + } + await page.getByRole('button', { name: 'Connect' }).first().click(); +}; diff --git a/tests/support/template/parseTransactionsTable.ts b/tests/support/template/parseTransactionsTable.ts new file mode 100644 index 0000000..9b65d67 --- /dev/null +++ b/tests/support/template/parseTransactionsTable.ts @@ -0,0 +1,340 @@ +import { SelectorsEnum } from './testdata'; +import { getTestIdSelector } from './testIdSelector'; +import { + ParseTransactionsTableType, + TransactionFilter, + TransactionRow +} from './types'; + +// Function to count transactions with given filters +export const countTransactions = ( + transactions: TransactionRow[], + filter: TransactionFilter +): number => { + const filteredTransactions = filterTransactions(transactions, filter); + const count = filteredTransactions.length; + + if (filter.enableLogging) { + console.log( + `countTransactions: Found ${count} matching transactions out of ${transactions.length} total` + ); + } + + return count; +}; + +// Helper function to parse age text into minutes +const parseAge = (ageText: string): number => { + const match = ageText.match(/(\d+)\s*(sec|min|hr|day)/); + if (!match) { + return 0; + } + + const value = parseInt(match[1]); + const unit = match[2].toLowerCase(); + + // TODO: add more units if needed besides sec, min, hr, day + switch (unit) { + case 'sec': + return value / 60; // seconds to minutes + case 'min': + return value; + case 'hr': + return value * 60; // hours to minutes + case 'day': + return value * 24 * 60; // days to minutes + default: + return 1000; // default in case of unexpected unit + } +}; + +// Helper function to filter transactions +export const filterTransactions = ( + transactions: TransactionRow[], + filter: TransactionFilter +): TransactionRow[] => { + const enableLogging = filter.enableLogging || false; + + if (enableLogging) { + console.log( + `Filtering ${transactions.length} transactions with criteria:`, + { + exactValue: filter.exactValue, + methods: filter.methods, + maxAgeInMinutes: filter.maxAgeInMinutes, + minAgeInMinutes: filter.minAgeInMinutes, + onlySuccessful: filter.onlySuccessful, + onlyFailed: filter.onlyFailed, + fromAddress: filter.fromAddress, + toAddress: filter.toAddress + } + ); + } + + const filteredTransactions = transactions.filter((transaction, index) => { + let matches = true; + let reason = ''; + + // Age filter + if ( + filter.maxAgeInMinutes !== undefined && + transaction.ageInMinutes > filter.maxAgeInMinutes + ) { + matches = false; + reason = `age ${transaction.ageInMinutes} > max ${filter.maxAgeInMinutes}`; + } + if ( + matches && + filter.minAgeInMinutes !== undefined && + transaction.ageInMinutes < filter.minAgeInMinutes + ) { + matches = false; + reason = `age ${transaction.ageInMinutes} < min ${filter.minAgeInMinutes}`; + } + + // Method filter + if ( + matches && + filter.methods && + !filter.methods.includes(transaction.method) + ) { + matches = false; + reason = `method "${transaction.method}" not in [${filter.methods.join( + ', ' + )}]`; + } + + // Value filter + if ( + matches && + filter.exactValue !== undefined && + transaction.value !== filter.exactValue + ) { + matches = false; + reason = `value ${transaction.value} !== ${filter.exactValue}`; + } + + // Status filter + if (matches && filter.onlySuccessful && transaction.isFailed) { + matches = false; + reason = 'transaction failed but onlySuccessful=true'; + } + if (matches && filter.onlyFailed && !transaction.isFailed) { + matches = false; + reason = 'transaction successful but onlyFailed=true'; + } + + // Address filters + if ( + matches && + filter.fromAddress && + !transaction.fromAddress.includes(filter.fromAddress) + ) { + matches = false; + reason = `fromAddress "${transaction.fromAddress}" does not contain "${filter.fromAddress}"`; + } + if ( + matches && + filter.toAddress && + !transaction.toAddress.includes(filter.toAddress) + ) { + matches = false; + reason = `toAddress "${transaction.toAddress}" does not contain "${filter.toAddress}"`; + } + + if (enableLogging) { + console.log( + `Transaction ${index + 1}: ${ + matches ? 'MATCH' : 'FILTERED' + } - method="${transaction.method}", value=${transaction.value}, age=${ + transaction.ageInMinutes + }min${reason ? `, reason: ${reason}` : ''}` + ); + } + + return matches; + }); + + if (enableLogging) { + console.log( + `Filtered ${transactions.length} transactions down to ${filteredTransactions.length} matches` + ); + } + + return filteredTransactions; +}; + +export const parseTransactionsTable = async ({ + page, + tableSelector, + tableType, + maxRows, + enableLogging = false +}: ParseTransactionsTableType): Promise => { + // Set table selector based on table type + const defaultTableSelector = + tableType === 'ping-pong' + ? SelectorsEnum.transactionsPingPongTable + : SelectorsEnum.transactionsAllTable; + + const finalTableSelector = tableSelector || defaultTableSelector; + const table = page.locator(finalTableSelector); + await table.waitFor({ state: 'visible' }); + await table.scrollIntoViewIfNeeded(); + + // Get all table rows (excluding header) + const rows = table.locator(SelectorsEnum.transactionsTableBodyRow); + const totalRowCount = await rows.count(); + + // Limit the number of rows to process if maxRows is specified + const rowCount = maxRows ? Math.min(maxRows, totalRowCount) : totalRowCount; + + if (enableLogging) { + console.log( + `Found ${totalRowCount} transaction rows, processing ${rowCount} rows` + ); + } + + const transactions: TransactionRow[] = []; + + for (let i = 0; i < rowCount; i++) { + const row = rows.nth(i); + + try { + if (enableLogging) { + console.log(`Processing row ${i + 1}/${rowCount}`); + } + + // Extract transaction hash + const hashElement = row.locator( + getTestIdSelector(SelectorsEnum.transactionLink) + ); + const hash = await hashElement.getAttribute('href'); + const transactionHash = hash ? hash.split('/').pop() || '' : ''; + + // Extract age + const ageElement = row.locator( + getTestIdSelector(SelectorsEnum.transactionAge) + ); + const ageElementCount = await ageElement.count(); + + if (enableLogging) { + console.log(`Row ${i + 1} age element count: ${ageElementCount}`); + } + + let ageText = ''; + let age = 0; + + if (ageElementCount > 0) { + ageText = (await ageElement.textContent()) || ''; + age = parseAge(ageText); + if (enableLogging) { + console.log(`Row ${i + 1} age text: "${ageText}" -> ${age} minutes`); + } + } else if (enableLogging) { + console.log(`Row ${i + 1} age element not found`); + } + + // Extract shard info + const senderShardElement = row.locator( + getTestIdSelector(SelectorsEnum.senderShard) + ); + const receiverShardElement = row.locator( + getTestIdSelector(SelectorsEnum.receiverShard) + ); + const senderShard = (await senderShardElement.textContent()) || ''; + const receiverShard = (await receiverShardElement.textContent()) || ''; + + // Extract from/to addresses - use more flexible selectors + const senderElement = row.locator( + `${getTestIdSelector( + SelectorsEnum.transactionSender + )} ${getTestIdSelector(SelectorsEnum.trimFullAddress)}` + ); + const receiverElement = row.locator( + `${getTestIdSelector( + SelectorsEnum.transactionReceiver + )} ${getTestIdSelector(SelectorsEnum.receiverLink)}` + ); + + // Check if elements exist before trying to get text content + const fromAddress = + (await senderElement.count()) > 0 + ? (await senderElement.textContent()) || '' + : ''; + const toAddress = + (await receiverElement.count()) > 0 + ? (await receiverElement.textContent()) || '' + : ''; + + // Extract method + const methodElement = row.locator( + getTestIdSelector(SelectorsEnum.method) + ); + const method = (await methodElement.textContent()) || ''; + + // Extract value + const valueIntElement = row.locator( + getTestIdSelector(SelectorsEnum.formatAmountInt) + ); + const valueDecimalsElement = row.locator( + getTestIdSelector(SelectorsEnum.formatAmountDecimals) + ); + const valueSymbolElement = row.locator( + getTestIdSelector(SelectorsEnum.formatAmountSymbol) + ); + + // Check if elements exist before trying to get text content + const valueIntElementCount = await valueIntElement.count(); + const valueDecimalsElementCount = await valueDecimalsElement.count(); + const valueSymbolElementCount = await valueSymbolElement.count(); + + // Extract value components with fallbacks for missing elements + // Some transaction rows may not have all value elements (e.g., failed transactions) + const valueInt = + valueIntElementCount > 0 + ? (await valueIntElement.textContent()) || '0' + : '0'; + const valueDecimals = + valueDecimalsElementCount > 0 + ? (await valueDecimalsElement.textContent()) || '.00' + : '.00'; + const valueSymbol = + valueSymbolElementCount > 0 + ? (await valueSymbolElement.textContent()) || '' + : ''; + + const value = parseFloat(`${valueInt}${valueDecimals}`); + + // Check if transaction failed (has error icon) + const hasErrorIcon = + (await row.locator(SelectorsEnum.errorIcon).count()) > 0; + + transactions.push({ + hash: transactionHash, + age: ageText, + ageInMinutes: age, + senderShard, + receiverShard, + fromAddress, + toAddress, + method: method.toLowerCase(), + value, + symbol: valueSymbol, + isFailed: hasErrorIcon + }); + + if (enableLogging) { + console.log(`Successfully processed row ${i + 1}`); + } + } catch (error) { + if (enableLogging) { + console.log(`Error processing row ${i + 1}:`, error); + } + // Continue with next row instead of failing completely + continue; + } + } + + return transactions; +}; diff --git a/tests/support/template/pasteStringFromClipboard.ts b/tests/support/template/pasteStringFromClipboard.ts new file mode 100644 index 0000000..49cf581 --- /dev/null +++ b/tests/support/template/pasteStringFromClipboard.ts @@ -0,0 +1,10 @@ +import { BrowserContext, Page } from '@playwright/test'; + +export const pasteStringFromClipboard = async ( + page: Page, + context: BrowserContext +) => { + await context.grantPermissions(['clipboard-write', 'clipboard-read']); + const text = await page.evaluate(() => navigator.clipboard.readText()); + return text; +}; diff --git a/tests/support/template/signBatchTransactions.ts b/tests/support/template/signBatchTransactions.ts new file mode 100644 index 0000000..7d0650a --- /dev/null +++ b/tests/support/template/signBatchTransactions.ts @@ -0,0 +1,14 @@ +import { SelectorsEnum } from './testdata'; +import { SignBatchTransactionsType } from './types'; + +export const signBatchTransactions = async ({ + walletPage, + buttonSelector, + numberOfTransactions +}: SignBatchTransactionsType) => { + let i = buttonSelector === 'swap-lock' ? 1 : 0; + for (i; i < numberOfTransactions; i++) { + await walletPage.waitForLoadState(); + await walletPage.getByTestId(SelectorsEnum.signButton).click(); + } +}; diff --git a/tests/support/template/testIdSelector.ts b/tests/support/template/testIdSelector.ts new file mode 100644 index 0000000..1019495 --- /dev/null +++ b/tests/support/template/testIdSelector.ts @@ -0,0 +1,7 @@ +/** + * Helper function to create a data-testid selector string + * @param testId - The test ID value + * @returns CSS selector string for data-testid attribute + */ +export const getTestIdSelector = (testId: string): string => + `[data-testid="${testId}"]`; diff --git a/tests/support/template/testdata.ts b/tests/support/template/testdata.ts new file mode 100644 index 0000000..70b6098 --- /dev/null +++ b/tests/support/template/testdata.ts @@ -0,0 +1,119 @@ +import path from 'path'; +import { loadLocalEnv } from './loadLocalEnv'; + +// Ensure local .env files (e.g., .env.test.local) are loaded when running locally. +loadLocalEnv('test'); + +const walletsDir = process.env.WALLETS_DIR + ? path.resolve(process.env.WALLETS_DIR) + : path.resolve(__dirname, '..', 'wallets'); + +export const NA = 'N/A'; + +export enum OriginPageEnum { + multiversxWallet = 'devnet-wallet.multiversx.com', + templateHome = 'localhost:3000/home', + templateDashboard = 'localhost:3000/dashboard', + templateUnlock = 'localhost:3000/unlock' +} + +export const UrlRegex = { + templateDashboard: /localhost:3000\/dashboard/, + multiversxWallet: /devnet-wallet\.multiversx\.com/ +} as const; + +export enum PingPongEnum { + raw = 'raw', + abi = 'abi', + service = 'service' +} + +export enum SelectorsEnum { + // TODO: arange selectors by template dashboard, web wallet, transaction table, table containers + // Template dashboard selectors + walletFile = 'walletFile', + passwordInput = 'accessPass', + submitButton = 'submitButton', + confirmButton = 'confirmBtn', + keystoreCloseModalButton = 'keystoreCloseModalBtn', + signButton = 'signBtn', + topInfoContainer = 'topInfo', + crossWindow = 'crossWindow', + keystoreButton = 'keystoreBtn', + inMemoryButton = 'inMemoryProvider', + pemButton = 'pemBtn', + pingButton = 'btnPingRaw', + pongButton = 'btnPongRaw', + toastTitle = 'transactionToastTitle', + toastContent = 'transactionToastContent', + toastStatus = 'transactionDetailsStatus', + balance = 'balance', + formatAmountInt = 'formatAmountInt', + formatAmountDecimals = 'formatAmountDecimals', + signMsgButton = 'signMsgBtn', + signMsgWalletButton = 'signButton', + signAndBatchButton = 'sign-auto-send', + wrapAndMultiTransferButton = 'wrap-multi-transfer', + swapAndLockButton = 'swap-lock', + nativeAuthContainer = '#native-auth', + trimFullAddress = 'trimFullAddress', + pingPongAbiContainer = '#ping-pong-abi', + batchTransactionsContainer = '#batch-transactions', + signMessageContainer = '#sign-message', + accountAddress = 'accountAddress', + heroTag = 'heroTag', + shard = 'addressShard', + decodedMessage = 'decodedMessage', + addressInput = 'input[name="address"]', + privateKeyInput = 'input[name="privateKey"]', + cancelButton = 'cancelButton', + sidePanel = '#side-panel', + sidePanelCloseIcon = 'svg', + + // Web wallet selectors + signCancelButton = 'signCancelBtn', + + // Transaction table selectors + transactionLink = 'transactionLink', + transactionAge = 'transactionAge', + senderShard = 'senderShard', + receiverShard = 'receiverShard', + transactionSender = 'transactionSender', + transactionReceiver = 'transactionReceiver', + receiverLink = 'receiverLink', + method = 'method', + formatAmountSymbol = 'formatAmountSymbol', + errorIcon = '.mvx\\:text-error', + + // Table containers + transactionsAllTable = '#transactions-all table', + transactionsPingPongTable = '#transactions-ping-pong table', + transactionsTableBodyRow = 'tbody tr.transactions-table-body-row' +} + +// Test data is parameterized via environment variables so secrets (passwords, +// addresses, keystores) come from GitHub Secrets in CI or from local .env. +export const TestDataEnums = { + keystorePassword1: process.env.KEYSTORE1_PASSWORD || NA, + keystorePassword2: process.env.KEYSTORE2_PASSWORD || NA, + keystorePassword3: process.env.KEYSTORE3_PASSWORD || NA, + keystorePassword4: process.env.KEYSTORE4_PASSWORD || NA, + + keystoreWalletAddress1: process.env.KEYSTORE1_ADDRESS || NA, + keystoreWalletAddress2: process.env.KEYSTORE2_ADDRESS || NA, + keystoreWalletAddress3: process.env.KEYSTORE3_ADDRESS || NA, + keystoreWalletAddress4: process.env.KEYSTORE4_ADDRESS || NA, + keystoreWalletAddress5: process.env.KEYSTORE5_ADDRESS || NA, + keystoreWalletAddress6: process.env.KEYSTORE6_ADDRESS || NA, + + metamaskMnemonic: process.env.METAMASK_MNEMONIC, + metamaskAddress: process.env.METAMASK_ADDRESS, + metamaskPassword: process.env.METAMASK_PASSWORD, + + keystoreFilePath1: `${walletsDir}/keystoreFile1.json`, + keystoreFilePath2: `${walletsDir}/keystoreFile2.json`, + keystoreFilePath3: `${walletsDir}/keystoreFile3.json`, + keystoreFilePath4: `${walletsDir}/keystoreFile4.json`, + keystoreFilePath5: `${walletsDir}/keystoreFile5.pem`, + keystoreFilePath6: `${walletsDir}/keystoreFile6.key` +} as const; diff --git a/tests/support/template/types.ts b/tests/support/template/types.ts new file mode 100644 index 0000000..c986dc1 --- /dev/null +++ b/tests/support/template/types.ts @@ -0,0 +1,183 @@ +import { BrowserContext, Page } from '@playwright/test'; +import { PingPongEnum } from './testdata'; + +export type FileEncoding = 'base64' | 'utf8' | 'none'; + +export interface AuthenticateWithKeystoreType { + walletPage: Page; + keystorePath: string; + keystorePassword: string; +} + +export interface ConnectPasskeyWalletType { + page: Page; +} + +export interface InMemoryProviderType { + page: Page; + loginMethod: InMemoryProviderLoginMethodType; +} + +export interface AuthenticateWithPemType { + walletPage: Page; + pemPath: string; +} + +export interface CheckBalanceUpdateType { + page: Page; + containerSelector: string; + initialBalance: number; + expectedChange: number; +} + +export interface CheckButtonStatusType { + page: Page; + type: PingPongEnum; + lastClickedButton: 'ping' | 'pong'; +} + +export interface CheckClipboardContainsType { + page: Page; + context: BrowserContext; + text: string; + timeout?: number; +} + +export interface CheckConnectionToWalletType { + page: Page; + walletAddress: string; +} + +export interface CheckToastShowsTransactionsSignedType { + page: Page; + numberOfTransactions: number; +} + +export interface ConfirmWalletTransactionType { + page: Page; + loginMethod: WebWalletLoginMethodType; +} + +export interface ConnectWebWalletType { + page: Page; + loginMethod: WebWalletLoginMethodType; +} + +export interface CreateNotFoundErrorType { + urlSubstring: string; + timeout: number; + currentPageUrl: string; + availablePagesUrls: string; +} + +export interface ExtractBalanceFromContainerType { + page: Page; + containerSelector: string; + selectorType: 'testId' | 'locator'; +} + +export interface HandlePingPongType { + page: Page; + type: PingPongEnum; +} + +export interface WebWalletLoginMethodType { + keystore?: string; + password?: string; + pem?: string; +} + +export interface InMemoryProviderLoginMethodType { + address: string; + privateKey: string; +} +export interface NavigateToConnectWalletType { + page: Page; +} + +export interface ParseTransactionsTableType { + page: Page; + tableSelector?: string; + tableType: 'all' | 'ping-pong'; + maxRows?: number; + enableLogging?: boolean; +} + +export interface PasteStringFromClipboardType { + page: Page; + context: BrowserContext; +} + +export interface SignBatchTransactionsType { + walletPage: Page; + buttonSelector: string; + numberOfTransactions: number; +} + +export interface TransactionFilter { + maxAgeInMinutes?: number; + minAgeInMinutes?: number; + methods?: string[]; + exactValue?: number; + onlySuccessful?: boolean; + onlyFailed?: boolean; + fromAddress?: string; + toAddress?: string; + enableLogging?: boolean; +} + +export interface TransactionRow { + hash: string; + age: string; + ageInMinutes: number; + senderShard: string; + receiverShard: string; + fromAddress: string; + toAddress: string; + method: string; + value: number; + symbol: string; + isFailed: boolean; +} + +export interface WaitForToastToBeClosedType { + page: Page; +} + +export interface WaitForToastToBeDisplayedType { + page: Page; +} + +export interface WaitForTransactionToastToShowType { + page: Page; + toastTitle: string; + toastContent: string; +} + +export interface WaitForTransactionToastToContainType { + page: Page; + toastTitle?: string; + toastContent?: string; + toastStatus?: string; + toastIndex?: number; +} + +export interface GetPageAndWaitForLoadOptions { + maxRetries?: number; + timeout?: number; + viewport?: { width: number; height: number }; + waitForReady?: (page: Page) => Promise; +} + +export type GetPageAndWaitForLoad = ( + context: BrowserContext, + urlSubstring: string | RegExp, + options?: GetPageAndWaitForLoadOptions +) => Promise; + +export type WaitForMetaMaskLoadOptions = { + selectorTimeoutMs?: number; + extraLoadingSelectors?: string[]; + skipInitialStabilityWait?: boolean; + concurrency?: number; +}; diff --git a/tests/support/template/waitForToastToBeClosed.ts b/tests/support/template/waitForToastToBeClosed.ts new file mode 100644 index 0000000..8ad2ece --- /dev/null +++ b/tests/support/template/waitForToastToBeClosed.ts @@ -0,0 +1,7 @@ +import { Page } from '@playwright/test'; +import { SelectorsEnum } from './testdata'; + +export const waitForToastToBeClosed = async (page: Page) => { + const toast = page.getByTestId(SelectorsEnum.toastContent).first(); + await toast.waitFor({ state: 'hidden' }); +}; diff --git a/tests/support/template/waitForToastToBeDisplayed.ts b/tests/support/template/waitForToastToBeDisplayed.ts new file mode 100644 index 0000000..7a4b176 --- /dev/null +++ b/tests/support/template/waitForToastToBeDisplayed.ts @@ -0,0 +1,7 @@ +import { Page } from '@playwright/test'; +import { SelectorsEnum } from './testdata'; + +export const waitForToastToBeDisplayed = async (page: Page) => { + const toast = page.getByTestId(SelectorsEnum.toastContent).first(); + await toast.waitFor({ state: 'visible' }); +}; diff --git a/tests/support/template/waitForTransactionToastToShow.ts b/tests/support/template/waitForTransactionToastToShow.ts new file mode 100644 index 0000000..58b8c62 --- /dev/null +++ b/tests/support/template/waitForTransactionToastToShow.ts @@ -0,0 +1,46 @@ +import { expect } from '@playwright/test'; +import { TEST_CONSTANTS } from './constants'; +import { SelectorsEnum } from './testdata'; +import { WaitForTransactionToastToContainType } from './types'; + +export const waitForTransactionToastToContain = async ({ + page, + toastTitle, + toastContent, + toastStatus, + toastIndex = 0 +}: WaitForTransactionToastToContainType) => { + if (!toastTitle && !toastContent && !toastStatus) { + throw new Error('Either toast title, content or status must be provided'); + } + + const titleLocator = page.getByTestId(SelectorsEnum.toastTitle); + const contentLocator = page.getByTestId(SelectorsEnum.toastContent); + const statusLocator = page.getByTestId(SelectorsEnum.toastStatus); + + // Wait for toast visibility + await expect(contentLocator.nth(toastIndex)).toBeVisible({ + timeout: TEST_CONSTANTS.TOAST_WAIT_TIMEOUT + }); + + if (toastTitle) { + await expect(titleLocator.nth(toastIndex)).toContainText(toastTitle, { + timeout: TEST_CONSTANTS.TOAST_WAIT_TIMEOUT, + useInnerText: true + }); + } + + if (toastContent) { + await expect(contentLocator.nth(toastIndex)).toContainText(toastContent, { + timeout: TEST_CONSTANTS.TOAST_WAIT_TIMEOUT, + useInnerText: true + }); + } + + if (toastStatus) { + await expect(statusLocator.nth(toastIndex)).toContainText(toastStatus, { + timeout: TEST_CONSTANTS.TOAST_WAIT_TIMEOUT, + useInnerText: true + }); + } +}; diff --git a/tests/support/template/waitUntilStable.ts b/tests/support/template/waitUntilStable.ts new file mode 100644 index 0000000..d57887a --- /dev/null +++ b/tests/support/template/waitUntilStable.ts @@ -0,0 +1,21 @@ +import { Page } from '@playwright/test'; + +const DEFAULT_TIMEOUT = 10000; +const RESOURCES_LOAD_DELAY = 1000; // Extra delay for font resources to load + +export const waitUntilStable = async (page: Page) => { + try { + await page.waitForLoadState('domcontentloaded', { + timeout: DEFAULT_TIMEOUT + }); + await page.waitForLoadState('load', { timeout: DEFAULT_TIMEOUT }); + + await new Promise((resolve) => setTimeout(resolve, RESOURCES_LOAD_DELAY)); + } catch (error) { + throw new Error( + `Failed to wait for page stability: ${ + error instanceof Error ? error.message : 'Unknown error' + }` + ); + } +}; diff --git a/tests/templateActions/nativeAuth.spec.ts b/tests/templateActions/nativeAuth.spec.ts new file mode 100644 index 0000000..5854344 --- /dev/null +++ b/tests/templateActions/nativeAuth.spec.ts @@ -0,0 +1,56 @@ +import { expect, test } from '@playwright/test'; +import * as TestActions from '../support/template'; +import { extractBalanceFromContainer } from '../support/template'; +import { SelectorsEnum, TestDataEnums } from '../support/template/testdata'; + +const keystoreConfig = { + keystore: TestDataEnums.keystoreFilePath1, + password: TestDataEnums.keystorePassword1, + address: TestDataEnums.keystoreWalletAddress1 +}; + +// TODO: Unable to load profile error appears -> check if this is a known issue +// and then adjust the test accordingly (if necessary) +test.describe.skip('Native auth', () => { + test.beforeEach(async ({ page }) => { + await TestActions.navigateToConnectWallet(page); + await TestActions.connectWebWallet({ page, loginMethod: keystoreConfig }); + await TestActions.checkConnectionToWallet(page, keystoreConfig.address); + }); + + test('should display correct wallet address and balance in native auth', async ({ + page + }) => { + // Get account balance before any actions + const accountBalance = await TestActions.extractBalanceFromContainer({ + page, + containerSelector: SelectorsEnum.topInfoContainer, + selectorType: 'testId' + }); + + // Scroll to the native auth container into viewport + await page + .locator(SelectorsEnum.nativeAuthContainer) + .scrollIntoViewIfNeeded(); + + // Verify container is in viewport + const container = page.locator(SelectorsEnum.nativeAuthContainer); + await expect(container).toBeInViewport(); + + // Check that the address is displayed and matches the account address + const nativeAuthAddress = page + .locator(SelectorsEnum.nativeAuthContainer) + .getByTestId(SelectorsEnum.trimFullAddress); + + await expect(nativeAuthAddress).toHaveText(keystoreConfig.address); + + // Check that the balance is displayed and matches the account balance + const nativeAuthBalance = await extractBalanceFromContainer({ + page, + containerSelector: SelectorsEnum.nativeAuthContainer, + selectorType: 'locator' + }); + + await expect(nativeAuthBalance).toBe(accountBalance); + }); +}); diff --git a/tests/templateActions/pingAndPongAbi.spec.ts b/tests/templateActions/pingAndPongAbi.spec.ts new file mode 100644 index 0000000..5e5eb24 --- /dev/null +++ b/tests/templateActions/pingAndPongAbi.spec.ts @@ -0,0 +1,104 @@ +import { expect, test } from '@playwright/test'; +import * as TestActions from '../support/template'; +import { TEST_CONSTANTS } from '../support/template/constants'; +import { + OriginPageEnum, + PingPongEnum, + SelectorsEnum, + TestDataEnums, + UrlRegex +} from '../support/template/testdata'; +import { WALLET_URL_TIMEOUT_MS } from '../config'; + +const pemConfig = { + pem: TestDataEnums.keystoreFilePath5 +}; + +test.describe('Ping & Pong (ABI)', () => { + // Note: Ping/Pong buttons have a 3-minute cooldown period after being clicked + + test.beforeEach(async ({ page }) => { + await TestActions.navigateToConnectWallet(page); + await TestActions.connectWebWallet({ page, loginMethod: pemConfig }); + await TestActions.checkConnectionToWallet( + page, + TestDataEnums.keystoreWalletAddress5 + ); + }); + + test('should have sufficient balance for ping & pong operations', async ({ + page + }) => { + // Get account balance before any actions + const accountBalance = await TestActions.extractBalanceFromContainer({ + page, + containerSelector: SelectorsEnum.topInfoContainer, + selectorType: 'testId' + }); + + // Check that account balance is greater than 1 required for ping & pong + expect(accountBalance).toBeGreaterThan( + TEST_CONSTANTS.MIN_BALANCE_FOR_PING_PONG + ); + }); + + test('should complete full ping/pong transaction flow', async ({ page }) => { + // Get account balance before any actions + const accountBalance = await TestActions.extractBalanceFromContainer({ + page, + containerSelector: SelectorsEnum.topInfoContainer, + selectorType: 'testId' + }); + + // Scroll to the ping & pong container into viewport + await page + .locator(SelectorsEnum.pingPongAbiContainer) + .scrollIntoViewIfNeeded(); + + const clickedButton = await TestActions.handlePingPong({ + page, + type: PingPongEnum.abi + }); + + // Switch to web wallet page + const walletPage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); + + // Verify wallet page opened + await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet, { + timeout: WALLET_URL_TIMEOUT_MS + }); + + // Sign transaction by confirming with pem + await TestActions.confirmWalletTransaction(walletPage, pemConfig); + + // Click on Sign button to confirm the transaction in the web wallet + await walletPage.getByTestId(SelectorsEnum.signButton).click(); + + // Switch to template dashboard page + const templatePage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.templateDashboard + ); + + // Wait for transaction toast to be displayed + await TestActions.waitForToastToBeDisplayed(templatePage); + + // Check balance change based on the clicked button + await TestActions.checkPingPongBalanceUpdate({ + page: templatePage, + containerSelector: SelectorsEnum.topInfoContainer, + initialBalance: accountBalance, + isPing: clickedButton === 'ping' + }); + + // Check that the button status changed after the action + await TestActions.checkButtonStatus({ + page, + type: PingPongEnum.abi, + lastClickedButton: clickedButton + }); + }); +}); diff --git a/tests/templateActions/signAndSendBatch.spec.ts b/tests/templateActions/signAndSendBatch.spec.ts new file mode 100644 index 0000000..2134a21 --- /dev/null +++ b/tests/templateActions/signAndSendBatch.spec.ts @@ -0,0 +1,93 @@ +import { expect, test } from '@playwright/test'; +import * as TestActions from '../support/template'; +import { TEST_CONSTANTS } from '../support/template/constants'; +import { + OriginPageEnum, + SelectorsEnum, + TestDataEnums, + UrlRegex +} from '../support/template/testdata'; +import { WALLET_URL_TIMEOUT_MS } from '../config'; + +const keystoreConfig = { + keystore: TestDataEnums.keystoreFilePath2, + password: TestDataEnums.keystorePassword2 +}; + +test.describe('Sign & send batch', () => { + test.beforeEach(async ({ page }) => { + await TestActions.navigateToConnectWallet(page); + await TestActions.connectWebWallet({ page, loginMethod: keystoreConfig }); + await TestActions.checkConnectionToWallet( + page, + TestDataEnums.keystoreWalletAddress2 + ); + }); + + test('should have sufficient balance for batch transactions', async ({ + page + }) => { + // Get account balance before any actions + const accountBalance = await TestActions.extractBalanceFromContainer({ + page, + containerSelector: SelectorsEnum.topInfoContainer, + selectorType: 'testId' + }); + + // Check that account balance is greater than 5 required for batch transactions + expect(accountBalance).toBeGreaterThan( + TEST_CONSTANTS.MIN_BALANCE_FOR_BATCH_TX + ); + }); + + test('should complete full batch transaction flow', async ({ page }) => { + const numberOfTransactions = 5; + + // Scroll to the batch transactions container into viewport + await page + .locator(SelectorsEnum.batchTransactionsContainer) + .scrollIntoViewIfNeeded(); + + // Click on the sign and batch button + await page.getByTestId(SelectorsEnum.signAndBatchButton).click(); + + // Switch to web wallet page + const walletPage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); + + // Verify wallet page opened + await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet, { + timeout: WALLET_URL_TIMEOUT_MS + }); + + // Sign transaction by confirming with keystore in the web wallet + await TestActions.confirmWalletTransaction(walletPage, keystoreConfig); + + // Sign batch transactions in the web wallet + await TestActions.signBatchTransactions({ + walletPage, + buttonSelector: SelectorsEnum.signAndBatchButton, + numberOfTransactions + }); + + // Switch to template page + const templatePage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.templateDashboard + ); + + // Wait for transaction toast to be displayed + await TestActions.waitForToastToBeDisplayed(templatePage); + + // Check that the transaction toast shows that all transactions are signed + await TestActions.waitForTransactionToastToContain({ + page: templatePage, + toastStatus: '5 / 5 transactions processed' + }); + + // Wait for the transaction toast to be closed + await TestActions.waitForToastToBeClosed(templatePage); + }); +}); diff --git a/tests/templateActions/signMessage.spec.ts b/tests/templateActions/signMessage.spec.ts new file mode 100644 index 0000000..821222e --- /dev/null +++ b/tests/templateActions/signMessage.spec.ts @@ -0,0 +1,70 @@ +import { expect, test } from '@playwright/test'; +import * as TestActions from '../support/template'; +import { + OriginPageEnum, + SelectorsEnum, + TestDataEnums, + UrlRegex +} from '../support/template/testdata'; +import { WALLET_URL_TIMEOUT_MS } from '../config'; + +const keystoreConfig = { + keystore: TestDataEnums.keystoreFilePath1, + password: TestDataEnums.keystorePassword1 +}; + +test.describe('Sign Message', () => { + test.beforeEach(async ({ page }) => { + await TestActions.navigateToConnectWallet(page); + await TestActions.connectWebWallet({ page, loginMethod: keystoreConfig }); + await TestActions.checkConnectionToWallet( + page, + TestDataEnums.keystoreWalletAddress1 + ); + }); + + test('should complete full message signing flow', async ({ page }) => { + const message = 'mvx'; + + // Scroll to the sign message container into viewport + await page + .locator(SelectorsEnum.signMessageContainer) + .scrollIntoViewIfNeeded(); + + // Enter message + await page + .getByRole('textbox', { name: 'Write message here' }) + .fill(message); + + // Click on Sign button + await page.getByTestId(SelectorsEnum.signMsgButton).click(); + + // Switch to web wallet page + const walletPage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); + + // Verify wallet page opened + await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet, { + timeout: WALLET_URL_TIMEOUT_MS + }); + + // Sign transaction by confirming with keystore in the web wallet + await TestActions.confirmWalletTransaction(walletPage, keystoreConfig); + + // Click on Sign button to confirm the sign message in the web wallet + await walletPage.getByTestId(SelectorsEnum.signMsgWalletButton).click(); + + // Switch to template dashboard page + const templatePage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.templateDashboard + ); + + // Verify the decoded message contains the expected message + const decodedMessage = + 'cb0f0cbcf70e54e0e79fb2c1a48e01883e15fb3bb686773a7bb8b26ebb69447de75dd8c8645e9af1'; + await expect(templatePage.getByText(decodedMessage)).toBeVisible(); + }); +}); diff --git a/tests/templateActions/swapAndLock.ts b/tests/templateActions/swapAndLock.ts new file mode 100644 index 0000000..ab83689 --- /dev/null +++ b/tests/templateActions/swapAndLock.ts @@ -0,0 +1,95 @@ +import { expect, test } from '@playwright/test'; +import * as TestActions from '../support/template'; +import { TEST_CONSTANTS } from '../support/template/constants'; +import { + OriginPageEnum, + SelectorsEnum, + TestDataEnums, + UrlRegex +} from '../support/template/testdata'; +import { WALLET_URL_TIMEOUT_MS } from '../config'; + +const keystoreConfig = { + keystore: TestDataEnums.keystoreFilePath3, + password: TestDataEnums.keystorePassword3 +}; + +test.describe('Swap & Lock', () => { + test.beforeEach(async ({ page }) => { + await TestActions.navigateToConnectWallet(page); + await TestActions.connectWebWallet({ page, loginMethod: keystoreConfig }); + await TestActions.checkConnectionToWallet( + page, + TestDataEnums.keystoreWalletAddress3 + ); + }); + + test('should have sufficient balance for batch transactions', async ({ + page + }) => { + // Get account balance before any actions + const accountBalance = await TestActions.extractBalanceFromContainer({ + page, + containerSelector: SelectorsEnum.topInfoContainer, + selectorType: 'testId' + }); + + // Check that account balance is greater than 4 required for swap and lock + expect(accountBalance).toBeGreaterThan( + TEST_CONSTANTS.MIN_BALANCE_FOR_SWAP_AND_LOCK + ); + }); + + test('should complete full swap and lock transaction flow', async ({ + page + }) => { + const numberOfTransactions = 4; // 2 transactions for wrap, 1 for swap, 1 for multi-transfer + + // Scroll to the batch transactions container into viewport + await page + .locator(SelectorsEnum.batchTransactionsContainer) + .scrollIntoViewIfNeeded(); + + // Click on the swap and lock button + await page.getByTestId(SelectorsEnum.swapAndLockButton).click(); + + // Switch to web wallet page + const walletPage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.multiversxWallet + ); + + // Verify wallet page opened + await expect(walletPage).toHaveURL(UrlRegex.multiversxWallet, { + timeout: WALLET_URL_TIMEOUT_MS + }); + + // Sign transaction by confirming with keystore in the web wallet + await TestActions.confirmWalletTransaction(walletPage, keystoreConfig); + + // Sign swap and lock transactions in the web wallet + await TestActions.signBatchTransactions({ + walletPage, + buttonSelector: SelectorsEnum.signAndBatchButton, + numberOfTransactions + }); + + // Switch to template page + const templatePage = await TestActions.getPageAndWaitForLoad( + page.context(), + OriginPageEnum.templateDashboard + ); + + // Wait for transaction toast to be displayed + await TestActions.waitForToastToBeDisplayed(templatePage); + + // Check that the transaction toast shows that all transactions were signed + await TestActions.waitForTransactionToastToContain({ + page: templatePage, + toastStatus: '4 / 4 transactions processed' + }); + + // Wait for the transaction toast to be closed + await TestActions.waitForToastToBeClosed(templatePage); + }); +}); diff --git a/yarn.lock b/yarn.lock index 0e682c6..1501320 100644 --- a/yarn.lock +++ b/yarn.lock @@ -349,6 +349,136 @@ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== +"@esbuild/aix-ppc64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz#80fcbe36130e58b7670511e888b8e88a259ed76c" + integrity sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA== + +"@esbuild/android-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz#8aa4965f8d0a7982dc21734bf6601323a66da752" + integrity sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg== + +"@esbuild/android-arm@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz#300712101f7f50f1d2627a162e6e09b109b6767a" + integrity sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg== + +"@esbuild/android-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz#87dfb27161202bdc958ef48bb61b09c758faee16" + integrity sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg== + +"@esbuild/darwin-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz#79197898ec1ff745d21c071e1c7cc3c802f0c1fd" + integrity sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg== + +"@esbuild/darwin-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz#146400a8562133f45c4d2eadcf37ddd09718079e" + integrity sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA== + +"@esbuild/freebsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz#1c5f9ba7206e158fd2b24c59fa2d2c8bb47ca0fe" + integrity sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg== + +"@esbuild/freebsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz#ea631f4a36beaac4b9279fa0fcc6ca29eaeeb2b3" + integrity sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ== + +"@esbuild/linux-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz#e1066bce58394f1b1141deec8557a5f0a22f5977" + integrity sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ== + +"@esbuild/linux-arm@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz#452cd66b20932d08bdc53a8b61c0e30baf4348b9" + integrity sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw== + +"@esbuild/linux-ia32@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz#b24f8acc45bcf54192c7f2f3be1b53e6551eafe0" + integrity sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA== + +"@esbuild/linux-loong64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz#f9cfffa7fc8322571fbc4c8b3268caf15bd81ad0" + integrity sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng== + +"@esbuild/linux-mips64el@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz#575a14bd74644ffab891adc7d7e60d275296f2cd" + integrity sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw== + +"@esbuild/linux-ppc64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz#75b99c70a95fbd5f7739d7692befe60601591869" + integrity sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA== + +"@esbuild/linux-riscv64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz#2e3259440321a44e79ddf7535c325057da875cd6" + integrity sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w== + +"@esbuild/linux-s390x@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz#17676cabbfe5928da5b2a0d6df5d58cd08db2663" + integrity sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg== + +"@esbuild/linux-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz#0583775685ca82066d04c3507f09524d3cd7a306" + integrity sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw== + +"@esbuild/netbsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz#f04c4049cb2e252fe96b16fed90f70746b13f4a4" + integrity sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg== + +"@esbuild/netbsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz#77da0d0a0d826d7c921eea3d40292548b258a076" + integrity sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ== + +"@esbuild/openbsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz#6296f5867aedef28a81b22ab2009c786a952dccd" + integrity sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A== + +"@esbuild/openbsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz#f8d23303360e27b16cf065b23bbff43c14142679" + integrity sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw== + +"@esbuild/openharmony-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz#49e0b768744a3924be0d7fd97dd6ce9b2923d88d" + integrity sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg== + +"@esbuild/sunos-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz#a6ed7d6778d67e528c81fb165b23f4911b9b13d6" + integrity sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w== + +"@esbuild/win32-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz#9ac14c378e1b653af17d08e7d3ce34caef587323" + integrity sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg== + +"@esbuild/win32-ia32@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz#918942dcbbb35cc14fca39afb91b5e6a3d127267" + integrity sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ== + +"@esbuild/win32-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz#9bdad8176be7811ad148d1f8772359041f46c6c5" + integrity sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.9.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz#7308df158e064f0dd8b8fdb58aa14fa2a7f913b3" @@ -1096,6 +1226,13 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@playwright/test@^1.57.0": + version "1.57.0" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.57.0.tgz#a14720ffa9ed7ef7edbc1f60784fc6134acbb003" + integrity sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA== + dependencies: + playwright "1.57.0" + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -1149,46 +1286,156 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@rollup/rollup-android-arm-eabi@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz#7e478b66180c5330429dd161bf84dad66b59c8eb" + integrity sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w== + +"@rollup/rollup-android-arm64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz#2b025510c53a5e3962d3edade91fba9368c9d71c" + integrity sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w== + "@rollup/rollup-darwin-arm64@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz#363467bc49fd0b1e17075798ac8e9ad1e1e29535" integrity sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ== +"@rollup/rollup-darwin-arm64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz#3577c38af68ccf34c03e84f476bfd526abca10a0" + integrity sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA== + "@rollup/rollup-darwin-x64@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz#c2fe3d85fffe47f0ed0f076b3563ada22c8af19c" integrity sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q== +"@rollup/rollup-darwin-x64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz#2bf5f2520a1f3b551723d274b9669ba5b75ed69c" + integrity sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ== + +"@rollup/rollup-freebsd-arm64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz#4bb9cc80252564c158efc0710153c71633f1927c" + integrity sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w== + +"@rollup/rollup-freebsd-x64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz#2301289094d49415a380cf942219ae9d8b127440" + integrity sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q== + +"@rollup/rollup-linux-arm-gnueabihf@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz#1d03d776f2065e09fc141df7d143476e94acca88" + integrity sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw== + +"@rollup/rollup-linux-arm-musleabihf@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz#8623de0e040b2fd52a541c602688228f51f96701" + integrity sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg== + "@rollup/rollup-linux-arm64-gnu@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz#1015c9d07a99005025d13b8622b7600029d0b52f" integrity sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw== +"@rollup/rollup-linux-arm64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz#ce2d1999bc166277935dde0301cde3dd0417fb6e" + integrity sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w== + "@rollup/rollup-linux-arm64-musl@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz#8f895eb5577748fc75af21beae32439626e0a14c" integrity sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A== +"@rollup/rollup-linux-arm64-musl@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz#88c2523778444da952651a2219026416564a4899" + integrity sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A== + +"@rollup/rollup-linux-loong64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz#578ca2220a200ac4226c536c10c8cc6e4f276714" + integrity sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g== + +"@rollup/rollup-linux-ppc64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz#aa338d3effd4168a20a5023834a74ba2c3081293" + integrity sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw== + +"@rollup/rollup-linux-riscv64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz#16ba582f9f6cff58119aa242782209b1557a1508" + integrity sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g== + +"@rollup/rollup-linux-riscv64-musl@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz#e404a77ebd6378483888b8064c703adb011340ab" + integrity sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A== + +"@rollup/rollup-linux-s390x-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz#92ad52d306227c56bec43d96ad2164495437ffe6" + integrity sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg== + "@rollup/rollup-linux-x64-gnu@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz#7193cbd8d128212b8acda37e01b39d9e96259ef8" integrity sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A== +"@rollup/rollup-linux-x64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz#fd0dea3bb9aa07e7083579f25e1c2285a46cb9fa" + integrity sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w== + "@rollup/rollup-linux-x64-musl@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz#29a6867278ca0420b891574cfab98ecad70c59d1" integrity sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA== +"@rollup/rollup-linux-x64-musl@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz#37a3efb09f18d555f8afc490e1f0444885de8951" + integrity sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q== + +"@rollup/rollup-openharmony-arm64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz#c489bec9f4f8320d42c9b324cca220c90091c1f7" + integrity sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw== + "@rollup/rollup-win32-arm64-msvc@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz#89427dcac0c8e3a6d32b13a03a296a275d0de9a9" integrity sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q== +"@rollup/rollup-win32-arm64-msvc@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz#152832b5f79dc22d1606fac3db946283601b7080" + integrity sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw== + +"@rollup/rollup-win32-ia32-msvc@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz#54d91b2bb3bf3e9f30d32b72065a4e52b3a172a5" + integrity sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA== + +"@rollup/rollup-win32-x64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz#df9df03e61a003873efec8decd2034e7f135c71e" + integrity sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg== + "@rollup/rollup-win32-x64-msvc@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz#1973871850856ae72bc678aeb066ab952330e923" integrity sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw== +"@rollup/rollup-win32-x64-msvc@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz#38ae84f4c04226c1d56a3b17296ef1e0460ecdfe" + integrity sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ== + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" @@ -1448,6 +1695,11 @@ dependencies: "@babel/types" "^7.28.2" +"@types/estree@1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + "@types/graceful-fs@^4.1.3": version "4.1.9" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" @@ -3570,6 +3822,38 @@ es-toolkit@1.39.3: resolved "https://registry.yarnpkg.com/es-toolkit/-/es-toolkit-1.39.3.tgz#934b2cab9578c496dcbc0305cae687258cb14aee" integrity sha512-Qb/TCFCldgOy8lZ5uC7nLGdqJwSabkQiYQShmw4jyiPk1pZzaYWTwaYKYP7EgLccWYgZocMrtItrwh683voaww== +esbuild@^0.25.0: + version "0.25.12" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.12.tgz#97a1d041f4ab00c2fce2f838d2b9969a2d2a97a5" + integrity sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.12" + "@esbuild/android-arm" "0.25.12" + "@esbuild/android-arm64" "0.25.12" + "@esbuild/android-x64" "0.25.12" + "@esbuild/darwin-arm64" "0.25.12" + "@esbuild/darwin-x64" "0.25.12" + "@esbuild/freebsd-arm64" "0.25.12" + "@esbuild/freebsd-x64" "0.25.12" + "@esbuild/linux-arm" "0.25.12" + "@esbuild/linux-arm64" "0.25.12" + "@esbuild/linux-ia32" "0.25.12" + "@esbuild/linux-loong64" "0.25.12" + "@esbuild/linux-mips64el" "0.25.12" + "@esbuild/linux-ppc64" "0.25.12" + "@esbuild/linux-riscv64" "0.25.12" + "@esbuild/linux-s390x" "0.25.12" + "@esbuild/linux-x64" "0.25.12" + "@esbuild/netbsd-arm64" "0.25.12" + "@esbuild/netbsd-x64" "0.25.12" + "@esbuild/openbsd-arm64" "0.25.12" + "@esbuild/openbsd-x64" "0.25.12" + "@esbuild/openharmony-arm64" "0.25.12" + "@esbuild/sunos-x64" "0.25.12" + "@esbuild/win32-arm64" "0.25.12" + "@esbuild/win32-ia32" "0.25.12" + "@esbuild/win32-x64" "0.25.12" + escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" @@ -4095,7 +4379,12 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.2: +fsevents@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +fsevents@^2.3.2, fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -6324,6 +6613,20 @@ platform@1.3.6: resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== +playwright-core@1.57.0: + version "1.57.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.57.0.tgz#3dcc9a865af256fa9f0af0d67fc8dd54eecaebf5" + integrity sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ== + +playwright@1.57.0: + version "1.57.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.57.0.tgz#74d1dacff5048dc40bf4676940b1901e18ad0f46" + integrity sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw== + dependencies: + playwright-core "1.57.0" + optionalDependencies: + fsevents "2.3.2" + pngjs@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" @@ -6387,7 +6690,7 @@ postcss@8.4.31: picocolors "^1.0.0" source-map-js "^1.0.2" -postcss@^8.4.23: +postcss@^8.4.23, postcss@^8.5.6: version "8.5.6" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== @@ -6785,6 +7088,37 @@ ripemd160@^2.0.0, ripemd160@^2.0.1, ripemd160@^2.0.3: hash-base "^3.1.2" inherits "^2.0.4" +rollup@^4.43.0: + version "4.53.3" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.53.3.tgz#dbc8cd8743b38710019fb8297e8d7a76e3faa406" + integrity sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.53.3" + "@rollup/rollup-android-arm64" "4.53.3" + "@rollup/rollup-darwin-arm64" "4.53.3" + "@rollup/rollup-darwin-x64" "4.53.3" + "@rollup/rollup-freebsd-arm64" "4.53.3" + "@rollup/rollup-freebsd-x64" "4.53.3" + "@rollup/rollup-linux-arm-gnueabihf" "4.53.3" + "@rollup/rollup-linux-arm-musleabihf" "4.53.3" + "@rollup/rollup-linux-arm64-gnu" "4.53.3" + "@rollup/rollup-linux-arm64-musl" "4.53.3" + "@rollup/rollup-linux-loong64-gnu" "4.53.3" + "@rollup/rollup-linux-ppc64-gnu" "4.53.3" + "@rollup/rollup-linux-riscv64-gnu" "4.53.3" + "@rollup/rollup-linux-riscv64-musl" "4.53.3" + "@rollup/rollup-linux-s390x-gnu" "4.53.3" + "@rollup/rollup-linux-x64-gnu" "4.53.3" + "@rollup/rollup-linux-x64-musl" "4.53.3" + "@rollup/rollup-openharmony-arm64" "4.53.3" + "@rollup/rollup-win32-arm64-msvc" "4.53.3" + "@rollup/rollup-win32-ia32-msvc" "4.53.3" + "@rollup/rollup-win32-x64-gnu" "4.53.3" + "@rollup/rollup-win32-x64-msvc" "4.53.3" + fsevents "~2.3.2" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -7435,7 +7769,7 @@ through@^2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -tinyglobby@^0.2.13: +tinyglobby@^0.2.13, tinyglobby@^0.2.15: version "0.2.15" resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== @@ -7812,6 +8146,20 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vite@^7.2.4: + version "7.2.4" + resolved "https://registry.yarnpkg.com/vite/-/vite-7.2.4.tgz#a3a09c7e25487612ecc1119c7d412c73da35bd4e" + integrity sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w== + dependencies: + esbuild "^0.25.0" + fdir "^6.5.0" + picomatch "^4.0.3" + postcss "^8.5.6" + rollup "^4.43.0" + tinyglobby "^0.2.15" + optionalDependencies: + fsevents "~2.3.3" + w3c-xmlserializer@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073" From d94a1ebe02f69410fd30063c6293f445d7083c0b Mon Sep 17 00:00:00 2001 From: Roland Moldovan Date: Thu, 27 Nov 2025 14:55:52 +0200 Subject: [PATCH 02/13] Update fillSeedWords function to use Array.from for entries iteration --- tests/support/metaMask/fillSecretRecoveryPhrase.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/support/metaMask/fillSecretRecoveryPhrase.ts b/tests/support/metaMask/fillSecretRecoveryPhrase.ts index bf83a84..7c56eb6 100644 --- a/tests/support/metaMask/fillSecretRecoveryPhrase.ts +++ b/tests/support/metaMask/fillSecretRecoveryPhrase.ts @@ -16,7 +16,7 @@ async function fillSeedWords(page: Page, words: string[]) { // Skip first word (already filled in the textarea) const remainingWords = words.slice(1); - for (const [index, word] of remainingWords.entries()) { + for (const [index, word] of Array.from(remainingWords.entries())) { const inputSelector = secretRecoverySelectors.wordInput(index + 1); await fillSingleWord(page, inputSelector, word); } From 9e068058063a4f7070343a0bbd2d1d0b33cee184 Mon Sep 17 00:00:00 2001 From: Roland Moldovan Date: Thu, 27 Nov 2025 14:59:22 +0200 Subject: [PATCH 03/13] Update confirmPrivateKeyTransaction to use correct test ID for private key input --- tests/support/template/confirmPrivateKeyTransaction.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/support/template/confirmPrivateKeyTransaction.ts b/tests/support/template/confirmPrivateKeyTransaction.ts index b521a0c..adaf903 100644 --- a/tests/support/template/confirmPrivateKeyTransaction.ts +++ b/tests/support/template/confirmPrivateKeyTransaction.ts @@ -5,6 +5,6 @@ export const confirmPrivateKeyTransaction = async ( page: Page, privateKey: string ) => { - await page.getByTestId(SelectorsEnum.privateKey).fill(privateKey); + await page.getByTestId(SelectorsEnum.privateKeyInput).fill(privateKey); await page.getByTestId(SelectorsEnum.submitButton).click(); }; From c113e8b40794183a363d7f58a2e64bb8f27c9733 Mon Sep 17 00:00:00 2001 From: Roland Moldovan Date: Thu, 27 Nov 2025 15:07:27 +0200 Subject: [PATCH 04/13] Refactor error handling in MetaMask tests to improve clarity and remove deprecated waitForMetaMaskLoad function --- tests/support/metaMask/handleMetaMaskSnap.ts | 8 +- tests/support/metaMask/setupMetaMaskWallet.ts | 7 +- tests/support/metaMask/waitForMetaMaskLoad.ts | 92 ------------------- .../template/navigateToConnectWallet.ts | 4 +- tests/support/template/types.ts | 7 -- 5 files changed, 12 insertions(+), 106 deletions(-) delete mode 100644 tests/support/metaMask/waitForMetaMaskLoad.ts diff --git a/tests/support/metaMask/handleMetaMaskSnap.ts b/tests/support/metaMask/handleMetaMaskSnap.ts index bd2de34..afd5399 100644 --- a/tests/support/metaMask/handleMetaMaskSnap.ts +++ b/tests/support/metaMask/handleMetaMaskSnap.ts @@ -44,12 +44,12 @@ export async function handleMetaMaskSnap( } return; // All steps completed successfully - } catch (error: any) { + } catch (error) { attempt++; console.warn( `[MetaMaskSnap] Attempt ${attempt}/${maxRetries} failed: ${ - error?.message || error + error instanceof Error ? error.message : 'Unknown error' }` ); console.warn( @@ -78,10 +78,10 @@ async function attemptClick( try { await element.waitFor({ state: 'visible', timeout: CLICK_TIMEOUT_MS }); await element.click(); - } catch (error: any) { + } catch (error) { console.error( `[MetaMaskSnap] Failed to click "${action.name}": ${ - error?.message || error + error instanceof Error ? error.message : 'Unknown error' }` ); console.error( diff --git a/tests/support/metaMask/setupMetaMaskWallet.ts b/tests/support/metaMask/setupMetaMaskWallet.ts index 9d81cdf..7e2e8ef 100644 --- a/tests/support/metaMask/setupMetaMaskWallet.ts +++ b/tests/support/metaMask/setupMetaMaskWallet.ts @@ -1,4 +1,4 @@ -import { Page } from '@playwright/test'; +import { ChromiumBrowserContext, Page } from '@playwright/test'; import { handleMetaMetrics } from '../metaMask/handleMetrics'; import { getPageAndWaitForLoad } from '../template/getPageAndWaitForLoad'; import { waitUntilStable } from '../template/waitUntilStable'; @@ -49,7 +49,10 @@ async function initializeMetaMaskExtension() { return { context, extensionId }; } -async function openAndPrepareExtensionPage(context: any, extensionId: string) { +async function openAndPrepareExtensionPage( + context: ChromiumBrowserContext, + extensionId: string +) { const metamaskPage = await getPageAndWaitForLoad( context, `chrome-extension://${extensionId}/` diff --git a/tests/support/metaMask/waitForMetaMaskLoad.ts b/tests/support/metaMask/waitForMetaMaskLoad.ts deleted file mode 100644 index 136f41b..0000000 --- a/tests/support/metaMask/waitForMetaMaskLoad.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { errors, Page } from '@playwright/test'; -import { WaitForMetaMaskLoadOptions } from '../template/types'; -import { waitUntilStable } from '../template/waitUntilStable'; - -const DEFAULT_TIMEOUT = 10_000; -const DEFAULT_CONCURRENCY = 3; - -const BASE_LOADING_SELECTORS: readonly string[] = [ - '.loading-logo', - '.loading-spinner', - '.loading-overlay', - '.loading-overlay__spinner', - '.loading-span', - '.loading-indicator', - '#loading__logo', - '#loading__spinner', - '.mm-button-base__icon-loading', - '.loading-swaps-quotes', - '.loading-heartbeat', - '.spinner' -]; - -/** - * Waits for MetaMask UI to be usable: - * 1) (optional) wait for page stability - * 2) wait for known loading indicators to hide (best-effort) - * 3) brief post delay (conditional) - */ -export async function waitForMetaMaskLoad( - page: Page, - options: WaitForMetaMaskLoadOptions -): Promise { - const { - selectorTimeoutMs = DEFAULT_TIMEOUT, - extraLoadingSelectors = [], - skipInitialStabilityWait = false, - concurrency = DEFAULT_CONCURRENCY // how many selectors to wait on in parallel - } = options; - - try { - if (!skipInitialStabilityWait) { - await waitUntilStable(page); - } - - const selectors = Array.from( - new Set([...BASE_LOADING_SELECTORS, ...extraLoadingSelectors]) - ); - - await waitSelectorsHiddenWithConcurrency( - page, - selectors, - selectorTimeoutMs, - concurrency - ); - } catch (err) { - const msg = err instanceof Error ? err.message : String(err); - console.warn(`[waitForMetaMaskLoad] Non-fatal warning: ${msg}`); - } -} - -async function waitSelectorsHiddenWithConcurrency( - page: Page, - selectors: string[], - perSelectorTimeoutMs: number, - concurrency: number -) { - // One stability wait per batch, not per selector - await waitUntilStable(page); - - // Process selectors with a small concurrency to reduce polling in CI/CD - let i = 0; - while (i < selectors.length) { - const batch = selectors.slice(i, i + Math.max(1, concurrency)); - await Promise.all( - batch.map(async (selector) => { - try { - await page.waitForSelector(selector, { - state: 'hidden', - timeout: perSelectorTimeoutMs - }); - } catch (err) { - if (err instanceof errors.TimeoutError) { - // OK if a selector never appears on this screen - return; - } - throw err; - } - }) - ); - i += batch.length; - } -} diff --git a/tests/support/template/navigateToConnectWallet.ts b/tests/support/template/navigateToConnectWallet.ts index d19919f..03f303a 100644 --- a/tests/support/template/navigateToConnectWallet.ts +++ b/tests/support/template/navigateToConnectWallet.ts @@ -8,7 +8,9 @@ export const navigateToConnectWallet = async (page: Page) => { break; } catch (error) { console.warn( - `[navigateToConnectWallet] Attempt ${i + 1} failed: ${error.message}` + `[navigateToConnectWallet] Attempt ${i + 1} failed: ${ + error instanceof Error ? error.message : 'Unknown error' + }` ); if (i === maxRetries - 1) throw error; await page.waitForTimeout(5000); // Increase wait time diff --git a/tests/support/template/types.ts b/tests/support/template/types.ts index c986dc1..dfb5f4f 100644 --- a/tests/support/template/types.ts +++ b/tests/support/template/types.ts @@ -174,10 +174,3 @@ export type GetPageAndWaitForLoad = ( urlSubstring: string | RegExp, options?: GetPageAndWaitForLoadOptions ) => Promise; - -export type WaitForMetaMaskLoadOptions = { - selectorTimeoutMs?: number; - extraLoadingSelectors?: string[]; - skipInitialStabilityWait?: boolean; - concurrency?: number; -}; From c62978688cdc2add0642123750877df08341e0ee Mon Sep 17 00:00:00 2001 From: Roland Moldovan Date: Thu, 27 Nov 2025 15:14:31 +0200 Subject: [PATCH 05/13] Update E2E test workflow to trigger on both main and development branches --- .github/workflows/run-merge-e2e-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-merge-e2e-tests.yml b/.github/workflows/run-merge-e2e-tests.yml index 2ddd1ec..d0276e4 100644 --- a/.github/workflows/run-merge-e2e-tests.yml +++ b/.github/workflows/run-merge-e2e-tests.yml @@ -1,7 +1,7 @@ name: Playwright merge E2E Tests on: pull_request: - branches: [main] + branches: [main, development] workflow_dispatch: jobs: E2E-RUN: From e70d958fb71887068e8c90609fb0c7faea4f0216 Mon Sep 17 00:00:00 2001 From: Roland Moldovan Date: Thu, 27 Nov 2025 15:47:24 +0200 Subject: [PATCH 06/13] Enhance E2E test workflow by specifying Chromium for Playwright installation and adding Next.js build step --- .github/workflows/run-merge-e2e-tests.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-merge-e2e-tests.yml b/.github/workflows/run-merge-e2e-tests.yml index d0276e4..cc672f7 100644 --- a/.github/workflows/run-merge-e2e-tests.yml +++ b/.github/workflows/run-merge-e2e-tests.yml @@ -49,7 +49,9 @@ jobs: max_attempts: 2 command: yarn install --frozen-lockfile - name: Install Playwright Browsers - run: npx playwright install --with-deps + run: npx playwright install --with-deps chromium + - name: Build Next.js app + run: yarn next build - name: Run Playwright E2E Tests run: xvfb-run yarn run run-playwright-test - name: Upload Playwright test report From 950f43d004cf827d3636a261bf66552968c57211 Mon Sep 17 00:00:00 2001 From: Roland Moldovan Date: Thu, 27 Nov 2025 16:02:05 +0200 Subject: [PATCH 07/13] Update E2E test workflow to remove frozen lockfile option in yarn install command --- .github/workflows/run-merge-e2e-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-merge-e2e-tests.yml b/.github/workflows/run-merge-e2e-tests.yml index cc672f7..16f14ed 100644 --- a/.github/workflows/run-merge-e2e-tests.yml +++ b/.github/workflows/run-merge-e2e-tests.yml @@ -47,7 +47,7 @@ jobs: timeout_minutes: 120 retry_on: error max_attempts: 2 - command: yarn install --frozen-lockfile + command: yarn install - name: Install Playwright Browsers run: npx playwright install --with-deps chromium - name: Build Next.js app From 0c06a7b5a730bcc6b4dad49ef6fc196e60c2dfe0 Mon Sep 17 00:00:00 2001 From: Roland Moldovan Date: Thu, 27 Nov 2025 16:11:08 +0200 Subject: [PATCH 08/13] Add baseUrl configuration to tsconfig.json for improved module resolution --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index f40a4c6..5edab71 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,7 @@ "name": "next" } ], + "baseUrl": ".", "paths": { "@/*": ["./src/*"] } From ce8aa2eeb4e519818ae65d5b3c926a2f1e6f15e9 Mon Sep 17 00:00:00 2001 From: Roland Moldovan Date: Thu, 27 Nov 2025 16:15:24 +0200 Subject: [PATCH 09/13] Add jsconfig.json for module resolution and remove baseUrl from tsconfig.json --- jsconfig.json | 6 ++++++ tsconfig.json | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 jsconfig.json diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..18254f7 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { "@/*": ["./src/*"] } + } +} diff --git a/tsconfig.json b/tsconfig.json index 5edab71..f40a4c6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,6 @@ "name": "next" } ], - "baseUrl": ".", "paths": { "@/*": ["./src/*"] } From 9588e453a605fbfe0ebcd670e9c19677275ce933 Mon Sep 17 00:00:00 2001 From: Roland Moldovan Date: Thu, 27 Nov 2025 16:34:16 +0200 Subject: [PATCH 10/13] Remove jsconfig.json and update E2E test workflow to use 'yarn build:devnet' instead of 'yarn next build' --- .github/workflows/run-merge-e2e-tests.yml | 2 +- jsconfig.json | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 jsconfig.json diff --git a/.github/workflows/run-merge-e2e-tests.yml b/.github/workflows/run-merge-e2e-tests.yml index 16f14ed..b32ebc9 100644 --- a/.github/workflows/run-merge-e2e-tests.yml +++ b/.github/workflows/run-merge-e2e-tests.yml @@ -51,7 +51,7 @@ jobs: - name: Install Playwright Browsers run: npx playwright install --with-deps chromium - name: Build Next.js app - run: yarn next build + run: yarn build:devnet - name: Run Playwright E2E Tests run: xvfb-run yarn run run-playwright-test - name: Upload Playwright test report diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index 18254f7..0000000 --- a/jsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": ".", - "paths": { "@/*": ["./src/*"] } - } -} From 769e24d730871c90135da68f6aa6c0d7147e0ebb Mon Sep 17 00:00:00 2001 From: Iulia Cimpeanu <72752718+iuliacimpeanu@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:33:37 +0200 Subject: [PATCH 11/13] Fixed nativeAuth (#101) * Fixed nativeAuth * Updated nativeAuth * Removed unused import * Updated showLabel param --- .../widgets/NativeAuth/NativeAuth.tsx | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/app/dashboard/widgets/NativeAuth/NativeAuth.tsx b/src/app/dashboard/widgets/NativeAuth/NativeAuth.tsx index 883eefa..001c16b 100644 --- a/src/app/dashboard/widgets/NativeAuth/NativeAuth.tsx +++ b/src/app/dashboard/widgets/NativeAuth/NativeAuth.tsx @@ -6,27 +6,16 @@ import { OutputContainer } from '@/components/OutputContainer'; import { useGetLoginInfo, - useGetNetworkConfig, - MvxFormatAmount, - FormatAmountController, - DIGITS, - DECIMALS + useGetAccount, + FormatAmount } from '@/lib'; import { useGetProfile } from './hooks'; import { Username } from '../Account/components'; export const NativeAuth = () => { const { tokenLogin, isLoggedIn } = useGetLoginInfo(); + const { balance } = useGetAccount(); const { isLoading, profile, getProfile } = useGetProfile(); - const { network } = useGetNetworkConfig(); - - const { isValid, valueDecimal, valueInteger, label } = - FormatAmountController.getData({ - digits: DIGITS, - decimals: DECIMALS, - egldLabel: network.egldLabel, - input: profile?.balance ?? '0' - }); useEffect(() => { // On page refresh, tokenInfo is null which implies that we do not have access to loginInfo data @@ -62,12 +51,10 @@ export const NativeAuth = () => {
-
From 7ac1fe997c63bb6933b028e1d671c03efd679885 Mon Sep 17 00:00:00 2001 From: Roland Moldovan <46964104+rolandmoldovan@users.noreply.github.com> Date: Tue, 2 Dec 2025 16:05:30 +0200 Subject: [PATCH 12/13] re-enable native auth test after fix (#102) --- playwright.config.ts | 6 +++--- src/app/dashboard/page.tsx | 3 ++- tests/support/metaMask/setupMetaMaskWallet.ts | 2 +- tests/support/template/testdata.ts | 8 ++++---- tests/templateActions/nativeAuth.spec.ts | 13 +++++-------- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/playwright.config.ts b/playwright.config.ts index c4a60e3..bd79a2f 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -33,7 +33,7 @@ export default defineConfig({ /* 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:3000', + baseURL: 'https://localhost:3002', ignoreHTTPSErrors: true, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ @@ -64,8 +64,8 @@ export default defineConfig({ } ], webServer: { - command: 'yarn next start', - url: 'http://localhost:3000', + command: 'yarn start:devnet', + url: 'https://localhost:3002', timeout: 120 * 1000, reuseExistingServer: !process.env.CI, stdout: 'pipe', diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index a0c316b..fdcb0a7 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -58,7 +58,8 @@ const WIDGETS: WidgetType[] = [ widget: NativeAuth, description: 'A secure authentication token can be used to interact with the backend', - reference: 'https://github.com/multiversx/mx-sdk-js-native-auth-server' + reference: 'https://github.com/multiversx/mx-sdk-js-native-auth-server', + anchor: 'native-auth' }, { title: 'Batch Transactions', diff --git a/tests/support/metaMask/setupMetaMaskWallet.ts b/tests/support/metaMask/setupMetaMaskWallet.ts index 7e2e8ef..4eb5922 100644 --- a/tests/support/metaMask/setupMetaMaskWallet.ts +++ b/tests/support/metaMask/setupMetaMaskWallet.ts @@ -111,6 +111,6 @@ async function fillFirstSecretRecoveryPhraseWord(page: Page, mnemonic: string) { await srpInput.click(); const [firstWord] = mnemonic.split(' '); - await srpInput.type(firstWord); + await srpInput.fill(firstWord); await srpInput.press('Enter'); } diff --git a/tests/support/template/testdata.ts b/tests/support/template/testdata.ts index 70b6098..4451829 100644 --- a/tests/support/template/testdata.ts +++ b/tests/support/template/testdata.ts @@ -12,13 +12,13 @@ export const NA = 'N/A'; export enum OriginPageEnum { multiversxWallet = 'devnet-wallet.multiversx.com', - templateHome = 'localhost:3000/home', - templateDashboard = 'localhost:3000/dashboard', - templateUnlock = 'localhost:3000/unlock' + templateHome = 'https://localhost:3002/home', + templateDashboard = 'https://localhost:3002/dashboard', + templateUnlock = 'https://localhost:3002/unlock' } export const UrlRegex = { - templateDashboard: /localhost:3000\/dashboard/, + templateDashboard: /https:\/\/localhost:3002\/dashboard/, multiversxWallet: /devnet-wallet\.multiversx\.com/ } as const; diff --git a/tests/templateActions/nativeAuth.spec.ts b/tests/templateActions/nativeAuth.spec.ts index 5854344..a56e6a8 100644 --- a/tests/templateActions/nativeAuth.spec.ts +++ b/tests/templateActions/nativeAuth.spec.ts @@ -9,9 +9,7 @@ const keystoreConfig = { address: TestDataEnums.keystoreWalletAddress1 }; -// TODO: Unable to load profile error appears -> check if this is a known issue -// and then adjust the test accordingly (if necessary) -test.describe.skip('Native auth', () => { +test.describe('Native auth', () => { test.beforeEach(async ({ page }) => { await TestActions.navigateToConnectWallet(page); await TestActions.connectWebWallet({ page, loginMethod: keystoreConfig }); @@ -38,11 +36,10 @@ test.describe.skip('Native auth', () => { await expect(container).toBeInViewport(); // Check that the address is displayed and matches the account address - const nativeAuthAddress = page - .locator(SelectorsEnum.nativeAuthContainer) - .getByTestId(SelectorsEnum.trimFullAddress); - - await expect(nativeAuthAddress).toHaveText(keystoreConfig.address); + const addressRow = page.locator(`${SelectorsEnum.nativeAuthContainer} p`, { + hasText: 'Address:' + }); + await expect(addressRow).toContainText(keystoreConfig.address); // Check that the balance is displayed and matches the account balance const nativeAuthBalance = await extractBalanceFromContainer({ From d5e8fa0a34f67864604863487d7a8e9818e39ebf Mon Sep 17 00:00:00 2001 From: Tudor Morar Date: Tue, 13 Jan 2026 16:25:19 +0200 Subject: [PATCH 13/13] Update sdk-dapp --- src/app/unlock/page.tsx | 2 +- src/lib/sdkDappUI/sdkDappUI.components.ts | 3 +- yarn.lock | 1373 ++++++++++----------- 3 files changed, 632 insertions(+), 746 deletions(-) diff --git a/src/app/unlock/page.tsx b/src/app/unlock/page.tsx index f2b6555..56b9eeb 100644 --- a/src/app/unlock/page.tsx +++ b/src/app/unlock/page.tsx @@ -12,7 +12,7 @@ export default function Unlock() { loginHandler: () => { router.push(RouteNamesEnum.dashboard); }, - onClose: () => { + onClose: async () => { router.replace(RouteNamesEnum.home); } }); diff --git a/src/lib/sdkDappUI/sdkDappUI.components.ts b/src/lib/sdkDappUI/sdkDappUI.components.ts index ec5d3e6..e903982 100644 --- a/src/lib/sdkDappUI/sdkDappUI.components.ts +++ b/src/lib/sdkDappUI/sdkDappUI.components.ts @@ -2,6 +2,5 @@ export { MvxCopyButton, MvxExplorerLink, MvxFormatAmount, - MvxTransactionsTable, - MvxUnlockButton + MvxTransactionsTable } from '@multiversx/sdk-dapp-ui/react'; diff --git a/yarn.lock b/yarn.lock index 1501320..83f9d29 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,34 +12,34 @@ resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.27.1": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" - integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.28.6.tgz#72499312ec58b1e2245ba4a4f550c132be4982f7" + integrity sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q== dependencies: - "@babel/helper-validator-identifier" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" js-tokens "^4.0.0" picocolors "^1.1.1" -"@babel/compat-data@^7.27.2": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.5.tgz#a8a4962e1567121ac0b3b487f52107443b455c7f" - integrity sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA== +"@babel/compat-data@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.6.tgz#103f466803fa0f059e82ccac271475470570d74c" + integrity sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg== "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.5.tgz#4c81b35e51e1b734f510c99b07dfbc7bbbb48f7e" - integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw== - dependencies: - "@babel/code-frame" "^7.27.1" - "@babel/generator" "^7.28.5" - "@babel/helper-compilation-targets" "^7.27.2" - "@babel/helper-module-transforms" "^7.28.3" - "@babel/helpers" "^7.28.4" - "@babel/parser" "^7.28.5" - "@babel/template" "^7.27.2" - "@babel/traverse" "^7.28.5" - "@babel/types" "^7.28.5" + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.6.tgz#531bf883a1126e53501ba46eb3bb414047af507f" + integrity sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/generator" "^7.28.6" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helpers" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/template" "^7.28.6" + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" "@jridgewell/remapping" "^2.3.5" convert-source-map "^2.0.0" debug "^4.1.0" @@ -47,23 +47,23 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.28.5", "@babel/generator@^7.7.2": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.5.tgz#712722d5e50f44d07bc7ac9fe84438742dd61298" - integrity sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ== +"@babel/generator@^7.28.6", "@babel/generator@^7.7.2": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.6.tgz#48dcc65d98fcc8626a48f72b62e263d25fc3c3f1" + integrity sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw== dependencies: - "@babel/parser" "^7.28.5" - "@babel/types" "^7.28.5" + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" "@jridgewell/gen-mapping" "^0.3.12" "@jridgewell/trace-mapping" "^0.3.28" jsesc "^3.0.2" -"@babel/helper-compilation-targets@^7.27.2": - version "7.27.2" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" - integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== +"@babel/helper-compilation-targets@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" + integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA== dependencies: - "@babel/compat-data" "^7.27.2" + "@babel/compat-data" "^7.28.6" "@babel/helper-validator-option" "^7.27.1" browserslist "^4.24.0" lru-cache "^5.1.1" @@ -74,34 +74,34 @@ resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== -"@babel/helper-module-imports@^7.27.1": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" - integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== +"@babel/helper-module-imports@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c" + integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw== dependencies: - "@babel/traverse" "^7.27.1" - "@babel/types" "^7.27.1" + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" -"@babel/helper-module-transforms@^7.28.3": - version "7.28.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz#a2b37d3da3b2344fe085dab234426f2b9a2fa5f6" - integrity sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw== +"@babel/helper-module-transforms@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" + integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== dependencies: - "@babel/helper-module-imports" "^7.27.1" - "@babel/helper-validator-identifier" "^7.27.1" - "@babel/traverse" "^7.28.3" + "@babel/helper-module-imports" "^7.28.6" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/traverse" "^7.28.6" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.8.0": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" - integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.28.6", "@babel/helper-plugin-utils@^7.8.0": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8" + integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug== "@babel/helper-string-parser@^7.27.1": version "7.27.1" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== -"@babel/helper-validator-identifier@^7.27.1", "@babel/helper-validator-identifier@^7.28.5": +"@babel/helper-validator-identifier@^7.28.5": version "7.28.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== @@ -111,20 +111,20 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== -"@babel/helpers@^7.28.4": - version "7.28.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.4.tgz#fe07274742e95bdf7cf1443593eeb8926ab63827" - integrity sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w== +"@babel/helpers@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7" + integrity sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw== dependencies: - "@babel/template" "^7.27.2" - "@babel/types" "^7.28.4" + "@babel/template" "^7.28.6" + "@babel/types" "^7.28.6" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.27.2", "@babel/parser@^7.28.5": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.5.tgz#0b0225ee90362f030efd644e8034c99468893b08" - integrity sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.6.tgz#f01a8885b7fa1e56dd8a155130226cd698ef13fd" + integrity sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ== dependencies: - "@babel/types" "^7.28.5" + "@babel/types" "^7.28.6" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -155,11 +155,11 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-import-attributes@^7.24.7": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz#34c017d54496f9b11b61474e7ea3dfd5563ffe07" - integrity sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww== + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503" + integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw== dependencies: - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" @@ -176,11 +176,11 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c" - integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz#f8ca28bbd84883b5fea0e447c635b81ba73997ee" + integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w== dependencies: - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" @@ -239,43 +239,43 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": - version "7.27.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18" - integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz#c7b2ddf1d0a811145b1de800d1abd146af92e3a2" + integrity sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A== dependencies: - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/runtime@^7.12.5": - version "7.28.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.4.tgz#a70226016fabe25c5783b2f22d3e1c9bc5ca3326" - integrity sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ== - -"@babel/template@^7.27.2", "@babel/template@^7.3.3": - version "7.27.2" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" - integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== - dependencies: - "@babel/code-frame" "^7.27.1" - "@babel/parser" "^7.27.2" - "@babel/types" "^7.27.1" - -"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.3", "@babel/traverse@^7.28.5": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.5.tgz#450cab9135d21a7a2ca9d2d35aa05c20e68c360b" - integrity sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ== - dependencies: - "@babel/code-frame" "^7.27.1" - "@babel/generator" "^7.28.5" + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.6.tgz#d267a43cb1836dc4d182cce93ae75ba954ef6d2b" + integrity sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA== + +"@babel/template@^7.28.6", "@babel/template@^7.3.3": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" + integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/traverse@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.6.tgz#871ddc79a80599a5030c53b1cc48cbe3a5583c2e" + integrity sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/generator" "^7.28.6" "@babel/helper-globals" "^7.28.0" - "@babel/parser" "^7.28.5" - "@babel/template" "^7.27.2" - "@babel/types" "^7.28.5" + "@babel/parser" "^7.28.6" + "@babel/template" "^7.28.6" + "@babel/types" "^7.28.6" debug "^4.3.1" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.1", "@babel/types@^7.28.2", "@babel/types@^7.28.4", "@babel/types@^7.28.5", "@babel/types@^7.3.3": - version "7.28.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.5.tgz#10fc405f60897c35f07e85493c932c7b5ca0592b" - integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.2", "@babel/types@^7.28.6", "@babel/types@^7.3.3": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.6.tgz#c3e9377f1b155005bcc4c46020e7e394e13089df" + integrity sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg== dependencies: "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.28.5" @@ -291,9 +291,9 @@ integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== "@cypress/request@^3.0.0": - version "3.0.9" - resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.9.tgz#8ed6e08fea0c62998b5552301023af7268f11625" - integrity sha512-I3l7FdGRXluAS44/0NguwWlO83J18p0vlr2FYHrJkWdNYhgVoiYo61IXPqaOsL+vNxU1ZqMACzItGK3/KKDsdw== + version "3.0.10" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.10.tgz#e09c695e8460a82acafe6cfaf089cf2ca06dc054" + integrity sha512-hauBrOdvu08vOsagkZ/Aju5XuiZx6ldsLfByg1htFeldhex+PeMrYauANzFsMJeAA0+dyPLbDoX2OYuvVoLDkQ== dependencies: aws-sign2 "~0.7.0" aws4 "^1.8.0" @@ -308,7 +308,7 @@ json-stringify-safe "~5.0.1" mime-types "~2.1.19" performance-now "^2.1.0" - qs "6.14.0" + qs "~6.14.1" safe-buffer "^5.1.2" tough-cookie "^5.0.0" tunnel-agent "^0.6.0" @@ -323,17 +323,17 @@ lodash.once "^4.1.1" "@emnapi/core@^1.4.3": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.7.0.tgz#135de4e8858763989112281bdf38ca02439db7c3" - integrity sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw== + version "1.8.1" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.8.1.tgz#fd9efe721a616288345ffee17a1f26ac5dd01349" + integrity sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg== dependencies: "@emnapi/wasi-threads" "1.1.0" tslib "^2.4.0" "@emnapi/runtime@^1.4.3": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.7.0.tgz#d7ef3832df8564fe5903bf0567aedbd19538ecbe" - integrity sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q== + version "1.8.1" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.8.1.tgz#550fa7e3c0d49c5fb175a116e8cd70614f9a22a5" + integrity sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg== dependencies: tslib "^2.4.0" @@ -349,140 +349,140 @@ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== -"@esbuild/aix-ppc64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz#80fcbe36130e58b7670511e888b8e88a259ed76c" - integrity sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA== - -"@esbuild/android-arm64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz#8aa4965f8d0a7982dc21734bf6601323a66da752" - integrity sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg== - -"@esbuild/android-arm@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz#300712101f7f50f1d2627a162e6e09b109b6767a" - integrity sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg== - -"@esbuild/android-x64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz#87dfb27161202bdc958ef48bb61b09c758faee16" - integrity sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg== - -"@esbuild/darwin-arm64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz#79197898ec1ff745d21c071e1c7cc3c802f0c1fd" - integrity sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg== - -"@esbuild/darwin-x64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz#146400a8562133f45c4d2eadcf37ddd09718079e" - integrity sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA== - -"@esbuild/freebsd-arm64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz#1c5f9ba7206e158fd2b24c59fa2d2c8bb47ca0fe" - integrity sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg== - -"@esbuild/freebsd-x64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz#ea631f4a36beaac4b9279fa0fcc6ca29eaeeb2b3" - integrity sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ== - -"@esbuild/linux-arm64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz#e1066bce58394f1b1141deec8557a5f0a22f5977" - integrity sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ== - -"@esbuild/linux-arm@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz#452cd66b20932d08bdc53a8b61c0e30baf4348b9" - integrity sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw== - -"@esbuild/linux-ia32@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz#b24f8acc45bcf54192c7f2f3be1b53e6551eafe0" - integrity sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA== - -"@esbuild/linux-loong64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz#f9cfffa7fc8322571fbc4c8b3268caf15bd81ad0" - integrity sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng== - -"@esbuild/linux-mips64el@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz#575a14bd74644ffab891adc7d7e60d275296f2cd" - integrity sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw== - -"@esbuild/linux-ppc64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz#75b99c70a95fbd5f7739d7692befe60601591869" - integrity sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA== - -"@esbuild/linux-riscv64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz#2e3259440321a44e79ddf7535c325057da875cd6" - integrity sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w== - -"@esbuild/linux-s390x@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz#17676cabbfe5928da5b2a0d6df5d58cd08db2663" - integrity sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg== - -"@esbuild/linux-x64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz#0583775685ca82066d04c3507f09524d3cd7a306" - integrity sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw== - -"@esbuild/netbsd-arm64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz#f04c4049cb2e252fe96b16fed90f70746b13f4a4" - integrity sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg== - -"@esbuild/netbsd-x64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz#77da0d0a0d826d7c921eea3d40292548b258a076" - integrity sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ== - -"@esbuild/openbsd-arm64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz#6296f5867aedef28a81b22ab2009c786a952dccd" - integrity sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A== - -"@esbuild/openbsd-x64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz#f8d23303360e27b16cf065b23bbff43c14142679" - integrity sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw== - -"@esbuild/openharmony-arm64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz#49e0b768744a3924be0d7fd97dd6ce9b2923d88d" - integrity sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg== - -"@esbuild/sunos-x64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz#a6ed7d6778d67e528c81fb165b23f4911b9b13d6" - integrity sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w== - -"@esbuild/win32-arm64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz#9ac14c378e1b653af17d08e7d3ce34caef587323" - integrity sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg== - -"@esbuild/win32-ia32@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz#918942dcbbb35cc14fca39afb91b5e6a3d127267" - integrity sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ== - -"@esbuild/win32-x64@0.25.12": - version "0.25.12" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz#9bdad8176be7811ad148d1f8772359041f46c6c5" - integrity sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA== +"@esbuild/aix-ppc64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz#521cbd968dcf362094034947f76fa1b18d2d403c" + integrity sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw== + +"@esbuild/android-arm64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz#61ea550962d8aa12a9b33194394e007657a6df57" + integrity sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA== + +"@esbuild/android-arm@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.27.2.tgz#554887821e009dd6d853f972fde6c5143f1de142" + integrity sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA== + +"@esbuild/android-x64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.27.2.tgz#a7ce9d0721825fc578f9292a76d9e53334480ba2" + integrity sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A== + +"@esbuild/darwin-arm64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz#2cb7659bd5d109803c593cfc414450d5430c8256" + integrity sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg== + +"@esbuild/darwin-x64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz#e741fa6b1abb0cd0364126ba34ca17fd5e7bf509" + integrity sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA== + +"@esbuild/freebsd-arm64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz#2b64e7116865ca172d4ce034114c21f3c93e397c" + integrity sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g== + +"@esbuild/freebsd-x64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz#e5252551e66f499e4934efb611812f3820e990bb" + integrity sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA== + +"@esbuild/linux-arm64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz#dc4acf235531cd6984f5d6c3b13dbfb7ddb303cb" + integrity sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw== + +"@esbuild/linux-arm@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz#56a900e39240d7d5d1d273bc053daa295c92e322" + integrity sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw== + +"@esbuild/linux-ia32@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz#d4a36d473360f6870efcd19d52bbfff59a2ed1cc" + integrity sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w== + +"@esbuild/linux-loong64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz#fcf0ab8c3eaaf45891d0195d4961cb18b579716a" + integrity sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg== + +"@esbuild/linux-mips64el@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz#598b67d34048bb7ee1901cb12e2a0a434c381c10" + integrity sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw== + +"@esbuild/linux-ppc64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz#3846c5df6b2016dab9bc95dde26c40f11e43b4c0" + integrity sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ== + +"@esbuild/linux-riscv64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz#173d4475b37c8d2c3e1707e068c174bb3f53d07d" + integrity sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA== + +"@esbuild/linux-s390x@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz#f7a4790105edcab8a5a31df26fbfac1aa3dacfab" + integrity sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w== + +"@esbuild/linux-x64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz#2ecc1284b1904aeb41e54c9ddc7fcd349b18f650" + integrity sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA== + +"@esbuild/netbsd-arm64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz#e2863c2cd1501845995cb11adf26f7fe4be527b0" + integrity sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw== + +"@esbuild/netbsd-x64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz#93f7609e2885d1c0b5a1417885fba8d1fcc41272" + integrity sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA== + +"@esbuild/openbsd-arm64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz#a1985604a203cdc325fd47542e106fafd698f02e" + integrity sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA== + +"@esbuild/openbsd-x64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz#8209e46c42f1ffbe6e4ef77a32e1f47d404ad42a" + integrity sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg== + +"@esbuild/openharmony-arm64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz#8fade4441893d9cc44cbd7dcf3776f508ab6fb2f" + integrity sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag== + +"@esbuild/sunos-x64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz#980d4b9703a16f0f07016632424fc6d9a789dfc2" + integrity sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg== + +"@esbuild/win32-arm64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz#1c09a3633c949ead3d808ba37276883e71f6111a" + integrity sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg== + +"@esbuild/win32-ia32@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz#1b1e3a63ad4bef82200fef4e369e0fff7009eee5" + integrity sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ== + +"@esbuild/win32-x64@0.27.2": + version "0.27.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz#9e585ab6086bef994c6e8a5b3a0481219ada862b" + integrity sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.9.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz#7308df158e064f0dd8b8fdb58aa14fa2a7f913b3" - integrity sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g== + version "4.9.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595" + integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== dependencies: eslint-visitor-keys "^3.4.3" @@ -568,18 +568,6 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== -"@isaacs/cliui@^8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" - integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== - dependencies: - string-width "^5.1.2" - string-width-cjs "npm:string-width@^4.2.0" - strip-ansi "^7.0.1" - strip-ansi-cjs "npm:strip-ansi@^6.0.1" - wrap-ansi "^8.1.0" - wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" - "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -850,14 +838,14 @@ rxjs "6" semver "^7.3.5" -"@ledgerhq/devices@8.7.0", "@ledgerhq/devices@^8.0.7", "@ledgerhq/devices@^8.3.0": - version "8.7.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-8.7.0.tgz#39e011c484c4251c92769f92cf8c23b8a0b4ce39" - integrity sha512-3pSOULPUhClk2oOxa6UnoyXW8+05FK7r6cpq2WiTey4kyIUjmIraO7AX9lhz9IU73dGVtBMdU+NCPPO2RYJaTQ== +"@ledgerhq/devices@8.8.0", "@ledgerhq/devices@^8.0.7", "@ledgerhq/devices@^8.3.0": + version "8.8.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/devices/-/devices-8.8.0.tgz#479298de2b4dd059fe52fc2c627caf120b59923f" + integrity sha512-ZFRAQQaESxIK/8SYrrHyqb7pQjLPO8f62PI6H16SP0/uC9fdZKR8NqOGMvIf7I6K442SkiQATnC/kxUeUTfuHA== dependencies: - "@ledgerhq/errors" "^6.27.0" + "@ledgerhq/errors" "^6.28.0" "@ledgerhq/logs" "^6.13.0" - rxjs "^7.8.1" + rxjs "7.8.2" semver "^7.3.5" "@ledgerhq/errors@6.12.6": @@ -865,10 +853,10 @@ resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.12.6.tgz#f89c82c91c2930f34bc3e0d86a27ec7b6e6e4f5f" integrity sha512-D+r2B09vaRO06wfGoss+rNgwqWSoK0bCtsaJWzlD2hv1zxTtucqVtSztbRFypIqxWTCb3ix5Nh2dWHEJVTp2Xw== -"@ledgerhq/errors@^6.12.6", "@ledgerhq/errors@^6.14.0", "@ledgerhq/errors@^6.16.4", "@ledgerhq/errors@^6.27.0": - version "6.27.0" - resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.27.0.tgz#3acc978ed1dbbdd8049dcedccccf4a96968f583a" - integrity sha512-EE2hATONHdNP3YWFe3rZwwpSEzI5oN+q/xTjOulnjHZo84TLjungegEJ54A/Pzld0woulkkeVA27FbW5SAO1aA== +"@ledgerhq/errors@^6.12.6", "@ledgerhq/errors@^6.14.0", "@ledgerhq/errors@^6.16.4", "@ledgerhq/errors@^6.28.0": + version "6.28.0" + resolved "https://registry.yarnpkg.com/@ledgerhq/errors/-/errors-6.28.0.tgz#4a4ccea3b7ee28a54f4301053729c3804d8d0737" + integrity sha512-Rx6GN801GP/3gCfVmmiXFVZWmiaEGMuXVwjM6WOCX0dzw4v7KcB1nj4vrNC1plDI/xkPt/clYJPG7LgSt0mxlw== "@ledgerhq/hw-transport-web-ble@6.28.6": version "6.28.6" @@ -911,12 +899,12 @@ events "^3.3.0" "@ledgerhq/hw-transport@^6.30.6": - version "6.31.13" - resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.31.13.tgz#87e4a53bdcca257eeea6cbcc7a662c449a0cfa92" - integrity sha512-MrJRDk74wY980ofiFPRpTHQBbRw1wDuKbdag1zqlO1xtJglymwwY03K2kvBNvkm1RTSCPUp/nAoNG+WThZuuew== + version "6.31.15" + resolved "https://registry.yarnpkg.com/@ledgerhq/hw-transport/-/hw-transport-6.31.15.tgz#6df7c630b5e438900bbc70bf5d5849696a7283a0" + integrity sha512-I+hzH9XGFPaYq9K+iw+qWJUyVdhN9fdO00Df9zAkOCzju1W5Gc+cDJxbYnZApmY8oMd8mNoXTstEW3Ih5ikaVg== dependencies: - "@ledgerhq/devices" "8.7.0" - "@ledgerhq/errors" "^6.27.0" + "@ledgerhq/devices" "8.8.0" + "@ledgerhq/errors" "^6.28.0" "@ledgerhq/logs" "^6.13.0" events "^3.3.0" @@ -970,13 +958,14 @@ axios "^1.10.0" bip39 "3.1.0" -"@multiversx/sdk-dapp-ui@>=0.1.2 <0.2.0", "@multiversx/sdk-dapp-ui@^0.x": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-dapp-ui/-/sdk-dapp-ui-0.1.2.tgz#3acc08c126e9b01e7ccc2fc92bc2fbe74d2782b9" - integrity sha512-p6UeVVpGTY0JrpuPhEOeK4qLBQ5kcetRStJFrX5vK87xnswWU1k4DKITe89yXTPXWPlX1nRl9rcEQPO6Ht9D9g== +"@multiversx/sdk-dapp-ui@>=0.1.3 <0.2.0", "@multiversx/sdk-dapp-ui@^0.x": + version "0.1.9" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-dapp-ui/-/sdk-dapp-ui-0.1.9.tgz#fcd9f284c00fce84ad3e8ab761d1cb060b6ad675" + integrity sha512-PSROSftUpyYw+SAD4zG+ma8b7MhhCdteXs36T41lqPqxFoAL6cEL3u7AAYr/Cngqjxbf5aIoVF1WDIMUkQkYNA== dependencies: - "@stencil/core" "^4.36.2" + "@stencil/core" "4.38.1" "@stencil/react-output-target" "1.2.0" + "@stencil/vue-output-target" "0.11.8" classnames ">=2.5.1" lodash.capitalize "^4.2.1" lodash.inrange "^3.3.0" @@ -989,19 +978,18 @@ integrity sha512-x2b2Gz5j0mDPUV2UK0fyDideGq/tfznvFJUJIJUMfKRy9Frni26UXZuQXCN4ngs344fd+8XoJOeviNV6cXSFdw== "@multiversx/sdk-dapp@^5.x": - version "5.3.1" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-dapp/-/sdk-dapp-5.3.1.tgz#94870b044e3f933123e170286af15620c9bda325" - integrity sha512-AnbbzjIDAQxhd0nW5vU+NBMoOAp1+Y4yxUUSSc0GZkrRGelz+l1oOB/QBU/GWIqxm3em510e78ZlkJbfx0fZnA== + version "5.6.0" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-dapp/-/sdk-dapp-5.6.0.tgz#9e2042cb106c37a2207dcbd3d6611c5aecf9baa1" + integrity sha512-jLJb9ra9SJgb7z5W3gAWkwi78HwiisJIS/xHsNuuM/BxFF1FfERVV//6lkhscSL1P0uBV8hcnColWHjaxOJ5VQ== dependencies: "@lifeomic/axios-fetch" "3.0.1" - "@multiversx/sdk-extension-provider" "5.1.1" - "@multiversx/sdk-hw-provider" "8.1.1" + "@multiversx/sdk-extension-provider" "5.1.2" + "@multiversx/sdk-hw-provider" "8.1.2" "@multiversx/sdk-native-auth-client" "2.0.1" - "@multiversx/sdk-wallet-connect-provider" "6.1.3" - "@multiversx/sdk-web-wallet-cross-window-provider" "3.2.1" - "@multiversx/sdk-web-wallet-iframe-provider" "4.0.0" - "@multiversx/sdk-web-wallet-provider" "5.1.1" - "@multiversx/sdk-webview-provider" "3.2.5" + "@multiversx/sdk-wallet-connect-provider" "6.1.4" + "@multiversx/sdk-web-wallet-cross-window-provider" "3.2.2" + "@multiversx/sdk-web-wallet-iframe-provider" "4.0.1" + "@multiversx/sdk-webview-provider" "3.2.6" immer "10.1.1" linkifyjs "4.3.2" lodash.isempty "4.4.0" @@ -1013,17 +1001,17 @@ socket.io-client "4.7.5" zustand "4.4.7" optionalDependencies: - "@multiversx/sdk-dapp-ui" ">=0.1.2 <0.2.0" + "@multiversx/sdk-dapp-ui" ">=0.1.3 <0.2.0" -"@multiversx/sdk-extension-provider@5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-extension-provider/-/sdk-extension-provider-5.1.1.tgz#aa4a76bc681b53be3937fd65eb79b89f506d1557" - integrity sha512-q24eSFiXQ4SQG3UZU8FILGut/fw9WL9o6UjTSzF6CIUuFHtSQ/bLJnMIHM1ZHTeqhOYNfXhI6ozOIwtP3mR+xQ== +"@multiversx/sdk-extension-provider@5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-extension-provider/-/sdk-extension-provider-5.1.2.tgz#a44733ef0fe66cd3d0b1a25167d26687b12b3b6c" + integrity sha512-jxu18WKnc8ZLaLdl6ePcLStG2aZB1f9W0m2wPJt2UbHnPMhnk/okoYZYWlHfiF/L8WZGzQn8VXwcmras/vdwlw== -"@multiversx/sdk-hw-provider@8.1.1": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-hw-provider/-/sdk-hw-provider-8.1.1.tgz#642047762d8f1a2a0a3319bd6e578653cd8aa369" - integrity sha512-vrCoqTRPmXDFyR8LeRlEk/oyrUXhD1nk9tAltXyzJgRIUcuyPJJKd45pi8mumBP0DTmzICeJKgi+A8wHxogL8g== +"@multiversx/sdk-hw-provider@8.1.2": + version "8.1.2" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-hw-provider/-/sdk-hw-provider-8.1.2.tgz#24029d265ee3f6da156321fd06038952ae01c96c" + integrity sha512-Q/cIOi+3JiZ4/FV/608kEcaQAprv9NP2GmuxONdPW5YACIHGdS5WILsQTL6xqDxBsNEfN71DbbNHKEr7pqnq6Q== dependencies: "@ledgerhq/devices" "8.0.3" "@ledgerhq/errors" "6.12.6" @@ -1046,42 +1034,35 @@ dependencies: bech32 "^2.0.0" -"@multiversx/sdk-wallet-connect-provider@6.1.3": - version "6.1.3" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-wallet-connect-provider/-/sdk-wallet-connect-provider-6.1.3.tgz#fe2f014fad9c04ca910a124f71717e86ba0c9eab" - integrity sha512-hulgy2aXqE/nYt7sYjKKvkU+h3OSJM57+6WSdUUdyslp/J3Gqe5vc0mWMkkEMDr0pDEpMlLGMu3J1SjtbMd+9w== +"@multiversx/sdk-wallet-connect-provider@6.1.4": + version "6.1.4" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-wallet-connect-provider/-/sdk-wallet-connect-provider-6.1.4.tgz#b67affe59cb5cb4361043fe841dac478b64d46cc" + integrity sha512-uiRLQ9oBM4KAUxuYlh/QgbYGRjgJuxHTuvjtmDgh5GYbfdiPeXXkoQsUI01IYgCvMl/8iVv4ss4YAfgob6riOw== dependencies: "@walletconnect/sign-client" "2.22.4" "@walletconnect/utils" "2.22.4" bech32 "1.1.4" -"@multiversx/sdk-web-wallet-cross-window-provider@3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-cross-window-provider/-/sdk-web-wallet-cross-window-provider-3.2.1.tgz#9d778867f6cc669a3772c1780f82bf640fccd866" - integrity sha512-INWbQ+GXtGz+aIRZZcmFhTIfJPyf4F5X2HrG0BQu9riT31QxoIjpwSd8M91QyODbgUEJHUVCKppOe038/Xb1xw== +"@multiversx/sdk-web-wallet-cross-window-provider@3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-cross-window-provider/-/sdk-web-wallet-cross-window-provider-3.2.2.tgz#262eab62356cafd1ddee34ced7667668760fcd6b" + integrity sha512-CBMrf+oNKoBa/YFDTqzItLrERaW4n0pJIlGsP67H0Vr6bUlFLIlc30qsOGvWNoZvMDeDxvhvR7crayypETJSJw== dependencies: qs "6.11.2" -"@multiversx/sdk-web-wallet-iframe-provider@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-iframe-provider/-/sdk-web-wallet-iframe-provider-4.0.0.tgz#6739dcf3778fa4efd296b3db881ec2c98240eb16" - integrity sha512-V9eDWSublrau6yXASzQwCkdwr9ATxfQ8C8Ok27wSmx9Ok/JrSK1eCgN2XcrehFonn8nYnTHehYR1Qe0QZ6q+iw== +"@multiversx/sdk-web-wallet-iframe-provider@4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-iframe-provider/-/sdk-web-wallet-iframe-provider-4.0.1.tgz#95af41206474aff8cfdae4e9860960245fea3583" + integrity sha512-zIIKX4G1xYk7XSBQsHuihOag7pUAVGMZ1q3vug9XpwBwcQvgcSwC5RHzrYQusPpVdkTHIn3qa3JHqjwNj1VtGA== dependencies: "@types/jest" "^29.5.11" "@types/qs" "6.9.10" qs "6.11.2" -"@multiversx/sdk-web-wallet-provider@5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-web-wallet-provider/-/sdk-web-wallet-provider-5.1.1.tgz#ca5dbe03772df451feb733e11ffb8b5139d02ba1" - integrity sha512-3ZKA3vhOKPkPzmpcRZRoAATBWOXnO7kOu/9yC2TEHQImQi38CoLkWCUH1uHWOlccZ32ciDsp/YIfOP/DgG1KiQ== - dependencies: - qs "6.10.3" - -"@multiversx/sdk-webview-provider@3.2.5": - version "3.2.5" - resolved "https://registry.yarnpkg.com/@multiversx/sdk-webview-provider/-/sdk-webview-provider-3.2.5.tgz#20013a9a9a47ef8106e436457a30a1d0c8d8a8dd" - integrity sha512-mHpQfuJc7xVXcyMx9iz/BLxM6pBftdibfFU4RLEGivBuw57xxY2veCWyfYW/MpaN9qFa7XA/X9N5PhEb6zbRsQ== +"@multiversx/sdk-webview-provider@3.2.6": + version "3.2.6" + resolved "https://registry.yarnpkg.com/@multiversx/sdk-webview-provider/-/sdk-webview-provider-3.2.6.tgz#a1609b1b0707bb6b12700b2fcef2bc7430fdac43" + integrity sha512-Zq+mjdbPavnSLRvt4TuFqfIbnh0esADbEJgxs0lbGP6YxyL1zDbyxoDpWNpjYDb6o6X87buZMrO8qlHaInxQ6g== "@napi-rs/wasm-runtime@^0.2.11": version "0.2.12" @@ -1221,11 +1202,6 @@ resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== -"@pkgjs/parseargs@^0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" - integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== - "@playwright/test@^1.57.0": version "1.57.0" resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.57.0.tgz#a14720ffa9ed7ef7edbc1f60784fc6134acbb003" @@ -1286,155 +1262,170 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== -"@rollup/rollup-android-arm-eabi@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz#7e478b66180c5330429dd161bf84dad66b59c8eb" - integrity sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w== +"@rollup/rollup-android-arm-eabi@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz#76e0fef6533b3ce313f969879e61e8f21f0eeb28" + integrity sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg== -"@rollup/rollup-android-arm64@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz#2b025510c53a5e3962d3edade91fba9368c9d71c" - integrity sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w== +"@rollup/rollup-android-arm64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz#d3cfc675a40bbdec97bda6d7fe3b3b05f0e1cd93" + integrity sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg== "@rollup/rollup-darwin-arm64@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz#363467bc49fd0b1e17075798ac8e9ad1e1e29535" integrity sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ== -"@rollup/rollup-darwin-arm64@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz#3577c38af68ccf34c03e84f476bfd526abca10a0" - integrity sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA== +"@rollup/rollup-darwin-arm64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz#eb912b8f59dd47c77b3c50a78489013b1d6772b4" + integrity sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg== "@rollup/rollup-darwin-x64@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz#c2fe3d85fffe47f0ed0f076b3563ada22c8af19c" integrity sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q== -"@rollup/rollup-darwin-x64@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz#2bf5f2520a1f3b551723d274b9669ba5b75ed69c" - integrity sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ== +"@rollup/rollup-darwin-x64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz#e7d0839fdfd1276a1d34bc5ebbbd0dfd7d0b81a0" + integrity sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ== -"@rollup/rollup-freebsd-arm64@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz#4bb9cc80252564c158efc0710153c71633f1927c" - integrity sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w== +"@rollup/rollup-freebsd-arm64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz#7ff8118760f7351e48fd0cd3717ff80543d6aac8" + integrity sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg== -"@rollup/rollup-freebsd-x64@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz#2301289094d49415a380cf942219ae9d8b127440" - integrity sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q== +"@rollup/rollup-freebsd-x64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz#49d330dadbda1d4e9b86b4a3951b59928a9489a9" + integrity sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw== -"@rollup/rollup-linux-arm-gnueabihf@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz#1d03d776f2065e09fc141df7d143476e94acca88" - integrity sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw== +"@rollup/rollup-linux-arm-gnueabihf@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz#98c5f1f8b9776b4a36e466e2a1c9ed1ba52ef1b6" + integrity sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ== -"@rollup/rollup-linux-arm-musleabihf@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz#8623de0e040b2fd52a541c602688228f51f96701" - integrity sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg== +"@rollup/rollup-linux-arm-musleabihf@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz#b9acecd3672e742f70b0c8a94075c816a91ff040" + integrity sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg== "@rollup/rollup-linux-arm64-gnu@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz#1015c9d07a99005025d13b8622b7600029d0b52f" integrity sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw== -"@rollup/rollup-linux-arm64-gnu@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz#ce2d1999bc166277935dde0301cde3dd0417fb6e" - integrity sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w== +"@rollup/rollup-linux-arm64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz#7a6ab06651bc29e18b09a50ed1a02bc972977c9b" + integrity sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ== "@rollup/rollup-linux-arm64-musl@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz#8f895eb5577748fc75af21beae32439626e0a14c" integrity sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A== -"@rollup/rollup-linux-arm64-musl@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz#88c2523778444da952651a2219026416564a4899" - integrity sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A== - -"@rollup/rollup-linux-loong64-gnu@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz#578ca2220a200ac4226c536c10c8cc6e4f276714" - integrity sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g== - -"@rollup/rollup-linux-ppc64-gnu@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz#aa338d3effd4168a20a5023834a74ba2c3081293" - integrity sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw== - -"@rollup/rollup-linux-riscv64-gnu@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz#16ba582f9f6cff58119aa242782209b1557a1508" - integrity sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g== - -"@rollup/rollup-linux-riscv64-musl@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz#e404a77ebd6378483888b8064c703adb011340ab" - integrity sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A== - -"@rollup/rollup-linux-s390x-gnu@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz#92ad52d306227c56bec43d96ad2164495437ffe6" - integrity sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg== +"@rollup/rollup-linux-arm64-musl@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz#3c8c9072ba4a4d4ef1156b85ab9a2cbb57c1fad0" + integrity sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA== + +"@rollup/rollup-linux-loong64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz#17a7af13530f4e4a7b12cd26276c54307a84a8b0" + integrity sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g== + +"@rollup/rollup-linux-loong64-musl@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz#5cd7a900fd7b077ecd753e34a9b7ff1157fe70c1" + integrity sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw== + +"@rollup/rollup-linux-ppc64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz#03a097e70243ddf1c07b59d3c20f38e6f6800539" + integrity sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw== + +"@rollup/rollup-linux-ppc64-musl@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz#a5389873039d4650f35b4fa060d286392eb21a94" + integrity sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw== + +"@rollup/rollup-linux-riscv64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz#789e60e7d6e2b76132d001ffb24ba80007fb17d0" + integrity sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw== + +"@rollup/rollup-linux-riscv64-musl@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz#3556fa88d139282e9a73c337c9a170f3c5fe7aa4" + integrity sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg== + +"@rollup/rollup-linux-s390x-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz#c085995b10143c16747a67f1a5487512b2ff04b2" + integrity sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg== "@rollup/rollup-linux-x64-gnu@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz#7193cbd8d128212b8acda37e01b39d9e96259ef8" integrity sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A== -"@rollup/rollup-linux-x64-gnu@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz#fd0dea3bb9aa07e7083579f25e1c2285a46cb9fa" - integrity sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w== +"@rollup/rollup-linux-x64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz#9563a5419dd2604841bad31a39ccfdd2891690fb" + integrity sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg== "@rollup/rollup-linux-x64-musl@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz#29a6867278ca0420b891574cfab98ecad70c59d1" integrity sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA== -"@rollup/rollup-linux-x64-musl@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz#37a3efb09f18d555f8afc490e1f0444885de8951" - integrity sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q== +"@rollup/rollup-linux-x64-musl@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz#691bb06e6269a8959c13476b0cd2aa7458facb31" + integrity sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w== + +"@rollup/rollup-openbsd-x64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz#223e71224746a59ce6d955bbc403577bb5a8be9d" + integrity sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg== -"@rollup/rollup-openharmony-arm64@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz#c489bec9f4f8320d42c9b324cca220c90091c1f7" - integrity sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw== +"@rollup/rollup-openharmony-arm64@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz#0817e5d8ecbfeb8b7939bf58f8ce3c9dd67fce77" + integrity sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw== "@rollup/rollup-win32-arm64-msvc@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz#89427dcac0c8e3a6d32b13a03a296a275d0de9a9" integrity sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q== -"@rollup/rollup-win32-arm64-msvc@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz#152832b5f79dc22d1606fac3db946283601b7080" - integrity sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw== +"@rollup/rollup-win32-arm64-msvc@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz#de56d8f2013c84570ef5fb917aae034abda93e4a" + integrity sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g== -"@rollup/rollup-win32-ia32-msvc@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz#54d91b2bb3bf3e9f30d32b72065a4e52b3a172a5" - integrity sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA== +"@rollup/rollup-win32-ia32-msvc@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz#659aff5244312475aeea2c9479a6c7d397b517bf" + integrity sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA== -"@rollup/rollup-win32-x64-gnu@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz#df9df03e61a003873efec8decd2034e7f135c71e" - integrity sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg== +"@rollup/rollup-win32-x64-gnu@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz#2cb09549cbb66c1b979f9238db6dd454cac14a88" + integrity sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg== "@rollup/rollup-win32-x64-msvc@4.34.9": version "4.34.9" resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz#1973871850856ae72bc678aeb066ab952330e923" integrity sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw== -"@rollup/rollup-win32-x64-msvc@4.53.3": - version "4.53.3" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz#38ae84f4c04226c1d56a3b17296ef1e0460ecdfe" - integrity sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ== +"@rollup/rollup-win32-x64-msvc@4.55.1": + version "4.55.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz#f79437939020b83057faf07e98365b1fa51c458b" + integrity sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw== "@rtsao/scc@^1.1.0": version "1.1.0" @@ -1442,9 +1433,9 @@ integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== "@rushstack/eslint-patch@^1.3.3": - version "1.14.1" - resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.14.1.tgz#5f7c5c335643cff62ad8e6a9432d708a9c51e98c" - integrity sha512-jGTk8UD/RdjsNZW8qq10r0RBvxL8OWtoT+kImlzPDFilmozzM+9QmIJsmze9UiSBrFU45ZxhTYBypn9q9z/VfQ== + version "1.15.0" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.15.0.tgz#8184bcb37791e6d3c3c13a9bfbe4af263f66665f" + integrity sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw== "@scure/base@1.2.6", "@scure/base@~1.2.5": version "1.2.6" @@ -1492,10 +1483,10 @@ resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz#821f8442f4175d8f0467b9daf26e3a18e2d02af2" integrity sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA== -"@stencil/core@^4.36.2": - version "4.38.3" - resolved "https://registry.yarnpkg.com/@stencil/core/-/core-4.38.3.tgz#2743e29db3fcf02016c8b66693c6ffecb18a2ba8" - integrity sha512-rSDzGUfi58X8K79ySjlM6KlY+mq7D+ittzgNAdYHcsXHc70sBpdatFhnbOg25uVDiMf7xRAH9slP38pPdXnZOQ== +"@stencil/core@4.38.1": + version "4.38.1" + resolved "https://registry.yarnpkg.com/@stencil/core/-/core-4.38.1.tgz#7c98b71e9e9ef7ba5418ac16b058737ba692f359" + integrity sha512-qImplYLSp2wSZJo3oMZ3HrTaI+uULcRB4Knrua7UT9VjN/va+TDfk4JAKwDyDfTDkD2laDPcy6QJP2S3hVxZFQ== optionalDependencies: "@rollup/rollup-darwin-arm64" "4.34.9" "@rollup/rollup-darwin-x64" "4.34.9" @@ -1516,6 +1507,11 @@ react-style-stringify "^1.2.0" ts-morph "^22.0.0" +"@stencil/vue-output-target@0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@stencil/vue-output-target/-/vue-output-target-0.11.8.tgz#34d50cd25b230cf603de1e415db6b41d2b81c4d1" + integrity sha512-R/kQoN15irgL7NJxWaUNSmwDLfoDBZjlYaXNnW3LHlF30TYfyez6pRgD7ZglSSTVktMtCXz6ZPhg0uq59VkhOw== + "@swc/core-darwin-arm64@1.3.91": version "1.3.91" resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.91.tgz#3bb751899cd208be261c48190b75c87171be79b4" @@ -1762,9 +1758,9 @@ form-data "^4.0.4" "@types/node@*", "@types/node@>=13.7.0": - version "24.10.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-24.10.0.tgz#6b79086b0dfc54e775a34ba8114dcc4e0221f31f" - integrity sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A== + version "25.0.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-25.0.7.tgz#afd2f0d34358631a287c6726dabe0c845abc2bae" + integrity sha512-C/er7DlIZgRJO7WtTdYovjIFzGsz0I95UlMyR9anTb4aCpBSRWe5Jc1/RvLKUfzmOxHPGjSE5+63HgLtndxU4w== dependencies: undici-types "~7.16.0" @@ -1808,11 +1804,11 @@ integrity sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ== "@types/react@*": - version "19.2.2" - resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.2.tgz#ba123a75d4c2a51158697160a4ea2ff70aa6bf36" - integrity sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA== + version "19.2.8" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.8.tgz#307011c9f5973a6abab8e17d0293f48843627994" + integrity sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg== dependencies: - csstype "^3.0.2" + csstype "^3.2.2" "@types/react@18.2.24": version "18.2.24" @@ -1859,16 +1855,16 @@ integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^16.0.0": - version "16.0.10" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.10.tgz#2376eed83bc9dbda3d7253a44e18328fc0854477" - integrity sha512-0xbOE6Ht/oj0MTVVXCCdEZzUk7adwW3YB1Tg1ZBm95jrkrUMI0VA4sf3SgxC1TG8p5aKkn3jxT9A2BDw1mM/TQ== + version "16.0.11" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.11.tgz#de958fb62e77fc383fa6cd8066eabdd13da88f04" + integrity sha512-sbtvk8wDN+JvEdabmZExoW/HNr1cB7D/j4LT08rMiuikfA7m/JNJg7ATQcgzs34zHnoScDkY0ZRSl29Fkmk36g== dependencies: "@types/yargs-parser" "*" "@types/yargs@^17.0.8": - version "17.0.34" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.34.tgz#1c2f9635b71d5401827373a01ce2e8a7670ea839" - integrity sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A== + version "17.0.35" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.35.tgz#07013e46aa4d7d7d50a49e15604c1c5340d4eb24" + integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg== dependencies: "@types/yargs-parser" "*" @@ -2302,9 +2298,9 @@ abab@^2.0.6: integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== abitype@^1.0.9: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.1.1.tgz#b50ed400f8bfca5452eb4033445c309d3e1117c8" - integrity sha512-Loe5/6tAgsBukY95eGaPSDmQHIjRZYQq8PB1MpsNccDIK8WiV+Uw6WzaIXipvaxTEL2yEB0OpEaQv3gs8pkS9Q== + version "1.2.3" + resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.2.3.tgz#bec3e09dea97d99ef6c719140bee663a329ad1f4" + integrity sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg== acorn-globals@^7.0.0: version "7.0.1" @@ -2395,11 +2391,6 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -ansi-styles@^6.1.0: - version "6.2.3" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.3.tgz#c044d5dcc521a076413472597a1acb1f103c4041" - integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== - any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" @@ -2620,9 +2611,9 @@ aws4@^1.8.0: integrity sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw== axe-core@^4.10.0: - version "4.11.0" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.11.0.tgz#16f74d6482e343ff263d4f4503829e9ee91a86b6" - integrity sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ== + version "4.11.1" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.11.1.tgz#052ff9b2cbf543f5595028b583e4763b40c78ea7" + integrity sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A== axios@^1.10.0: version "1.13.2" @@ -2716,10 +2707,10 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -baseline-browser-mapping@^2.8.19: - version "2.8.25" - resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.8.25.tgz#947dc6f81778e0fa0424a2ab9ea09a3033e71109" - integrity sha512-2NovHVesVF5TXefsGX1yzx1xgr7+m9JQenvz6FQY3qd+YXkKkYiv+vTCc7OriP9mcDZpTC5mAOYN4ocd29+erA== +baseline-browser-mapping@^2.9.0: + version "2.9.14" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz#3b6af0bc032445bca04de58caa9a87cfe921cbb3" + integrity sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg== bcrypt-pbkdf@^1.0.0: version "1.0.2" @@ -2818,15 +2809,15 @@ braces@^3.0.3, braces@~3.0.2: fill-range "^7.1.1" browserslist@^4.21.10, browserslist@^4.24.0: - version "4.27.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.27.0.tgz#755654744feae978fbb123718b2f139bc0fa6697" - integrity sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw== + version "4.28.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95" + integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== dependencies: - baseline-browser-mapping "^2.8.19" - caniuse-lite "^1.0.30001751" - electron-to-chromium "^1.5.238" - node-releases "^2.0.26" - update-browserslist-db "^1.1.4" + baseline-browser-mapping "^2.9.0" + caniuse-lite "^1.0.30001759" + electron-to-chromium "^1.5.263" + node-releases "^2.0.27" + update-browserslist-db "^1.2.0" bs-logger@0.x: version "0.2.6" @@ -2940,10 +2931,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001751: - version "1.0.30001754" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001754.tgz#7758299d9a72cce4e6b038788a15b12b44002759" - integrity sha512-x6OeBXueoAceOmotzx3PO4Zpt4rzpeIFsSr6AAePTZxSkXiYDUmpypEl7e2+8NCd9bD7bXjqyef8CJYPC1jfxg== +caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001759: + version "1.0.30001764" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz#03206c56469f236103b90f9ae10bcb8b9e1f6005" + integrity sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g== caseless@~0.12.0: version "0.12.0" @@ -3201,7 +3192,7 @@ create-jest@^29.7.0: jest-util "^29.7.0" prompts "^2.0.1" -cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6: +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -3239,10 +3230,10 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -csstype@^3.0.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" - integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== +csstype@^3.0.2, csstype@^3.2.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a" + integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ== cypress-mochawesome-reporter@3.7.0: version "3.7.0" @@ -3362,7 +3353,7 @@ dayjs@^1.10.4: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.19.tgz#15dc98e854bb43917f12021806af897c58ae2938" integrity sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw== -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0, debug@~4.4.1: version "4.4.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== @@ -3394,9 +3385,9 @@ decimal.js@^10.4.2: integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg== dedent@^1.0.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.7.0.tgz#c1f9445335f0175a96587be245a282ff451446ca" - integrity sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ== + version "1.7.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.7.1.tgz#364661eea3d73f3faba7089214420ec2f8f13e15" + integrity sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg== deep-equal@^2.0.5: version "2.2.3" @@ -3572,11 +3563,6 @@ dunder-proto@^1.0.0, dunder-proto@^1.0.1: es-errors "^1.3.0" gopd "^1.2.0" -eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -3601,10 +3587,10 @@ ed2curve@0.3.0: dependencies: tweetnacl "1.x.x" -electron-to-chromium@^1.5.238: - version "1.5.248" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.248.tgz#e69941494efbc69ebf2803517f4e85d016013d4b" - integrity sha512-zsur2yunphlyAO4gIubdJEXCK6KOVvtpiuDfCIqbM9FjcnMYiyn0ICa3hWfPr0nc41zcLWobgy1iL7VvoOyA2Q== +electron-to-chromium@^1.5.263: + version "1.5.267" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz#5d84f2df8cdb6bfe7e873706bb21bd4bfb574dc7" + integrity sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw== emittery@^0.13.1: version "0.13.1" @@ -3645,9 +3631,9 @@ engine.io-parser@~5.2.1: integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q== enhanced-resolve@^5.10.0: - version "5.18.3" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz#9b5f4c5c076b8787c78fe540392ce76a88855b44" - integrity sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww== + version "5.18.4" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz#c22d33055f3952035ce6a144ce092447c525f828" + integrity sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -3677,10 +3663,10 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0: - version "1.24.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.0.tgz#c44732d2beb0acc1ed60df840869e3106e7af328" - integrity sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg== +es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0, es-abstract@^1.24.1: + version "1.24.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.1.tgz#f0c131ed5ea1bb2411134a8dd94def09c46c7899" + integrity sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw== dependencies: array-buffer-byte-length "^1.0.2" arraybuffer.prototype.slice "^1.0.4" @@ -3763,25 +3749,25 @@ es-get-iterator@^1.1.3: stop-iteration-iterator "^1.0.0" es-iterator-helpers@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz#d1dd0f58129054c0ad922e6a9a1e65eef435fe75" - integrity sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w== + version "1.2.2" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz#d979a9f686e2b0b72f88dbead7229924544720bc" + integrity sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w== dependencies: call-bind "^1.0.8" - call-bound "^1.0.3" + call-bound "^1.0.4" define-properties "^1.2.1" - es-abstract "^1.23.6" + es-abstract "^1.24.1" es-errors "^1.3.0" - es-set-tostringtag "^2.0.3" + es-set-tostringtag "^2.1.0" function-bind "^1.1.2" - get-intrinsic "^1.2.6" + get-intrinsic "^1.3.0" globalthis "^1.0.4" gopd "^1.2.0" has-property-descriptors "^1.0.2" has-proto "^1.2.0" has-symbols "^1.1.0" internal-slot "^1.1.0" - iterator.prototype "^1.1.4" + iterator.prototype "^1.1.5" safe-array-concat "^1.1.3" es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: @@ -3791,7 +3777,7 @@ es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: dependencies: es-errors "^1.3.0" -es-set-tostringtag@^2.0.3, es-set-tostringtag@^2.1.0: +es-set-tostringtag@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== @@ -3822,37 +3808,37 @@ es-toolkit@1.39.3: resolved "https://registry.yarnpkg.com/es-toolkit/-/es-toolkit-1.39.3.tgz#934b2cab9578c496dcbc0305cae687258cb14aee" integrity sha512-Qb/TCFCldgOy8lZ5uC7nLGdqJwSabkQiYQShmw4jyiPk1pZzaYWTwaYKYP7EgLccWYgZocMrtItrwh683voaww== -esbuild@^0.25.0: - version "0.25.12" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.12.tgz#97a1d041f4ab00c2fce2f838d2b9969a2d2a97a5" - integrity sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg== +esbuild@^0.27.0: + version "0.27.2" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.27.2.tgz#d83ed2154d5813a5367376bb2292a9296fc83717" + integrity sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw== optionalDependencies: - "@esbuild/aix-ppc64" "0.25.12" - "@esbuild/android-arm" "0.25.12" - "@esbuild/android-arm64" "0.25.12" - "@esbuild/android-x64" "0.25.12" - "@esbuild/darwin-arm64" "0.25.12" - "@esbuild/darwin-x64" "0.25.12" - "@esbuild/freebsd-arm64" "0.25.12" - "@esbuild/freebsd-x64" "0.25.12" - "@esbuild/linux-arm" "0.25.12" - "@esbuild/linux-arm64" "0.25.12" - "@esbuild/linux-ia32" "0.25.12" - "@esbuild/linux-loong64" "0.25.12" - "@esbuild/linux-mips64el" "0.25.12" - "@esbuild/linux-ppc64" "0.25.12" - "@esbuild/linux-riscv64" "0.25.12" - "@esbuild/linux-s390x" "0.25.12" - "@esbuild/linux-x64" "0.25.12" - "@esbuild/netbsd-arm64" "0.25.12" - "@esbuild/netbsd-x64" "0.25.12" - "@esbuild/openbsd-arm64" "0.25.12" - "@esbuild/openbsd-x64" "0.25.12" - "@esbuild/openharmony-arm64" "0.25.12" - "@esbuild/sunos-x64" "0.25.12" - "@esbuild/win32-arm64" "0.25.12" - "@esbuild/win32-ia32" "0.25.12" - "@esbuild/win32-x64" "0.25.12" + "@esbuild/aix-ppc64" "0.27.2" + "@esbuild/android-arm" "0.27.2" + "@esbuild/android-arm64" "0.27.2" + "@esbuild/android-x64" "0.27.2" + "@esbuild/darwin-arm64" "0.27.2" + "@esbuild/darwin-x64" "0.27.2" + "@esbuild/freebsd-arm64" "0.27.2" + "@esbuild/freebsd-x64" "0.27.2" + "@esbuild/linux-arm" "0.27.2" + "@esbuild/linux-arm64" "0.27.2" + "@esbuild/linux-ia32" "0.27.2" + "@esbuild/linux-loong64" "0.27.2" + "@esbuild/linux-mips64el" "0.27.2" + "@esbuild/linux-ppc64" "0.27.2" + "@esbuild/linux-riscv64" "0.27.2" + "@esbuild/linux-s390x" "0.27.2" + "@esbuild/linux-x64" "0.27.2" + "@esbuild/netbsd-arm64" "0.27.2" + "@esbuild/netbsd-x64" "0.27.2" + "@esbuild/openbsd-arm64" "0.27.2" + "@esbuild/openbsd-x64" "0.27.2" + "@esbuild/openharmony-arm64" "0.27.2" + "@esbuild/sunos-x64" "0.27.2" + "@esbuild/win32-arm64" "0.27.2" + "@esbuild/win32-ia32" "0.27.2" + "@esbuild/win32-x64" "0.27.2" escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" @@ -4085,9 +4071,9 @@ esprima@^4.0.0, esprima@^4.0.1: integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esquery@^1.4.2: - version "1.6.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" - integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + version "1.7.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" + integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== dependencies: estraverse "^5.1.0" @@ -4229,9 +4215,9 @@ fast-levenshtein@^2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastq@^1.6.0: - version "1.19.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" - integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + version "1.20.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.20.1.tgz#ca750a10dc925bc8b18839fd203e3ef4b3ced675" + integrity sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw== dependencies: reusify "^1.0.4" @@ -4317,23 +4303,15 @@ for-each@^0.3.3, for-each@^0.3.5: dependencies: is-callable "^1.2.7" -foreground-child@^3.1.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" - integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== - dependencies: - cross-spawn "^7.0.6" - signal-exit "^4.0.1" - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== form-data@^4.0.0, form-data@^4.0.4, form-data@~4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.4.tgz#784cdcce0669a9d68e94d11ac4eea98088edd2c4" - integrity sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow== + version "4.0.5" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" + integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" @@ -4533,18 +4511,6 @@ glob@7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^10.3.10: - version "10.4.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" - integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== - dependencies: - foreground-child "^3.1.0" - jackspeak "^3.1.2" - minimatch "^9.0.4" - minipass "^7.1.2" - package-json-from-dist "^1.0.0" - path-scurry "^1.11.1" - glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -4674,10 +4640,10 @@ hasown@^2.0.2: dependencies: function-bind "^1.1.2" -html-dom-parser@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-5.1.1.tgz#9efb2cfa055f6a71de1bb2f07c5b019db5004f9e" - integrity sha512-+o4Y4Z0CLuyemeccvGN4bAO20aauB2N9tFEAep5x4OW34kV4PTarBHm6RL02afYt2BMKcr0D2Agep8S3nJPIBg== +html-dom-parser@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-5.1.2.tgz#0fceac1b8e7d917de6e883991b7d71f0b3fd63b9" + integrity sha512-9nD3Rj3/FuQt83AgIa1Y3ruzspwFFA54AJbQnohXN+K6fL1/bhcDQJJY5Ne4L4A163ADQFVESd/0TLyNoV0mfg== dependencies: domhandler "5.0.3" htmlparser2 "10.0.0" @@ -4695,14 +4661,14 @@ html-escaper@^2.0.0: integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== html-react-parser@^5.2.2: - version "5.2.8" - resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-5.2.8.tgz#96bc08c669c8ffb1f24e1f256924eaa1de52e4b6" - integrity sha512-09WaI81tbpwhXWeMe1m9VptZVJUcigo0l59zVt+2HUIQT7+baU38/oNhllj6MKhOuGXqh0nrlwOgxbxbm6xXHw== + version "5.2.11" + resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-5.2.11.tgz#7d36b16468e7b5400f183380a1e77a916ca3f465" + integrity sha512-WnSQVn/D1UTj64nSz5y8MriL+MrbsZH80Ytr1oqKqs8DGZnphWY1R1pl3t7TY3rpqTSu+FHA21P80lrsmrdNBA== dependencies: domhandler "5.0.3" - html-dom-parser "5.1.1" + html-dom-parser "5.1.2" react-property "2.0.2" - style-to-js "1.1.19" + style-to-js "1.1.21" htmlparser2@10.0.0: version "10.0.0" @@ -4821,10 +4787,10 @@ ini@2.0.0: resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== -inline-style-parser@0.2.6: - version "0.2.6" - resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.6.tgz#e6bbb5288a635f6284a6249ce754da55c4bd1ff5" - integrity sha512-gtGXVaBdl5mAes3rPcMedEBm12ibjt1kDMFfheul1wUAOVEJW60voNdMVzVkfLN06O7ZaD/rxhfKgtlgtTbMjg== +inline-style-parser@0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.7.tgz#b1fc68bfc0313b8685745e4464e37f9376b9c909" + integrity sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA== internal-slot@^1.1.0: version "1.1.0" @@ -5173,7 +5139,7 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -iterator.prototype@^1.1.4: +iterator.prototype@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.5.tgz#12c959a29de32de0aa3bbbb801f4d777066dae39" integrity sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g== @@ -5185,15 +5151,6 @@ iterator.prototype@^1.1.4: has-symbols "^1.1.0" set-function-name "^2.0.2" -jackspeak@^3.1.2: - version "3.4.3" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" - integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== - dependencies: - "@isaacs/cliui" "^8.0.2" - optionalDependencies: - "@pkgjs/parseargs" "^0.11.0" - jest-changed-files@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" @@ -5595,17 +5552,17 @@ jiti@^1.18.2: integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + version "3.14.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.2.tgz#77485ce1dd7f33c061fd1b16ecea23b55fcb04b0" + integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg== dependencies: argparse "^1.0.7" esprima "^4.0.0" js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + version "4.1.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== dependencies: argparse "^2.0.1" @@ -5950,7 +5907,7 @@ loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -lru-cache@^10.2.0, lru-cache@^10.4.3: +lru-cache@^10.4.3: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== @@ -6049,7 +6006,7 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^9.0.3, minimatch@^9.0.4: +minimatch@^9.0.3: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== @@ -6061,11 +6018,6 @@ minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" - integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== - mkdirp@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" @@ -6235,11 +6187,11 @@ node-int64@^0.4.0: integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== node-mock-http@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.3.tgz#4e55e093267a3b910cded7354389ce2d02c89e77" - integrity sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog== + version "1.0.4" + resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.4.tgz#21f2ab4ce2fe4fbe8a660d7c5195a1db85e042a4" + integrity sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ== -node-releases@^2.0.26: +node-releases@^2.0.27: version "2.0.27" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e" integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA== @@ -6262,9 +6214,9 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1: path-key "^3.0.0" nwsapi@^2.2.2: - version "2.2.22" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.22.tgz#109f9530cda6c156d6a713cdf5939e9f0de98b9d" - integrity sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ== + version "2.2.23" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.23.tgz#59712c3a88e6de2bb0b6ccc1070397267019cf6c" + integrity sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ== object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" @@ -6345,7 +6297,7 @@ object.values@^1.1.6, object.values@^1.2.1: define-properties "^1.2.1" es-object-atoms "^1.0.0" -ofetch@^1.5.0: +ofetch@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.5.1.tgz#5c43cc56e03398b273014957060344254505c5c7" integrity sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA== @@ -6458,11 +6410,6 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -package-json-from-dist@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" - integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -6512,14 +6459,6 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" - integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== - dependencies: - lru-cache "^10.2.0" - minipass "^5.0.0 || ^6.0.2 || ^7.0.0" - path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -6575,9 +6514,9 @@ pino-abstract-transport@^2.0.0: split2 "^4.0.0" pino-std-serializers@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz#7c625038b13718dbbd84ab446bd673dc52259e3b" - integrity sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA== + version "7.1.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz#a7b0cd65225f29e92540e7853bd73b07479893fc" + integrity sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw== pino@10.0.0: version "10.0.0" @@ -6826,13 +6765,6 @@ qrcode@>=1.5.4: pngjs "^5.0.0" yargs "^15.3.1" -qs@6.10.3: - version "6.10.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" - integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== - dependencies: - side-channel "^1.0.4" - qs@6.11.2: version "6.11.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" @@ -6840,10 +6772,10 @@ qs@6.11.2: dependencies: side-channel "^1.0.4" -qs@6.14.0: - version "6.14.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" - integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== +qs@~6.14.1: + version "6.14.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.1.tgz#a41d85b9d3902f31d27861790506294881871159" + integrity sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ== dependencies: side-channel "^1.1.0" @@ -7089,34 +7021,37 @@ ripemd160@^2.0.0, ripemd160@^2.0.1, ripemd160@^2.0.3: inherits "^2.0.4" rollup@^4.43.0: - version "4.53.3" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.53.3.tgz#dbc8cd8743b38710019fb8297e8d7a76e3faa406" - integrity sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA== + version "4.55.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.55.1.tgz#4ec182828be440648e7ee6520dc35e9f20e05144" + integrity sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A== dependencies: "@types/estree" "1.0.8" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.53.3" - "@rollup/rollup-android-arm64" "4.53.3" - "@rollup/rollup-darwin-arm64" "4.53.3" - "@rollup/rollup-darwin-x64" "4.53.3" - "@rollup/rollup-freebsd-arm64" "4.53.3" - "@rollup/rollup-freebsd-x64" "4.53.3" - "@rollup/rollup-linux-arm-gnueabihf" "4.53.3" - "@rollup/rollup-linux-arm-musleabihf" "4.53.3" - "@rollup/rollup-linux-arm64-gnu" "4.53.3" - "@rollup/rollup-linux-arm64-musl" "4.53.3" - "@rollup/rollup-linux-loong64-gnu" "4.53.3" - "@rollup/rollup-linux-ppc64-gnu" "4.53.3" - "@rollup/rollup-linux-riscv64-gnu" "4.53.3" - "@rollup/rollup-linux-riscv64-musl" "4.53.3" - "@rollup/rollup-linux-s390x-gnu" "4.53.3" - "@rollup/rollup-linux-x64-gnu" "4.53.3" - "@rollup/rollup-linux-x64-musl" "4.53.3" - "@rollup/rollup-openharmony-arm64" "4.53.3" - "@rollup/rollup-win32-arm64-msvc" "4.53.3" - "@rollup/rollup-win32-ia32-msvc" "4.53.3" - "@rollup/rollup-win32-x64-gnu" "4.53.3" - "@rollup/rollup-win32-x64-msvc" "4.53.3" + "@rollup/rollup-android-arm-eabi" "4.55.1" + "@rollup/rollup-android-arm64" "4.55.1" + "@rollup/rollup-darwin-arm64" "4.55.1" + "@rollup/rollup-darwin-x64" "4.55.1" + "@rollup/rollup-freebsd-arm64" "4.55.1" + "@rollup/rollup-freebsd-x64" "4.55.1" + "@rollup/rollup-linux-arm-gnueabihf" "4.55.1" + "@rollup/rollup-linux-arm-musleabihf" "4.55.1" + "@rollup/rollup-linux-arm64-gnu" "4.55.1" + "@rollup/rollup-linux-arm64-musl" "4.55.1" + "@rollup/rollup-linux-loong64-gnu" "4.55.1" + "@rollup/rollup-linux-loong64-musl" "4.55.1" + "@rollup/rollup-linux-ppc64-gnu" "4.55.1" + "@rollup/rollup-linux-ppc64-musl" "4.55.1" + "@rollup/rollup-linux-riscv64-gnu" "4.55.1" + "@rollup/rollup-linux-riscv64-musl" "4.55.1" + "@rollup/rollup-linux-s390x-gnu" "4.55.1" + "@rollup/rollup-linux-x64-gnu" "4.55.1" + "@rollup/rollup-linux-x64-musl" "4.55.1" + "@rollup/rollup-openbsd-x64" "4.55.1" + "@rollup/rollup-openharmony-arm64" "4.55.1" + "@rollup/rollup-win32-arm64-msvc" "4.55.1" + "@rollup/rollup-win32-ia32-msvc" "4.55.1" + "@rollup/rollup-win32-x64-gnu" "4.55.1" + "@rollup/rollup-win32-x64-msvc" "4.55.1" fsevents "~2.3.2" run-parallel@^1.1.9: @@ -7133,7 +7068,7 @@ rxjs@6: dependencies: tslib "^1.9.0" -rxjs@^7.5.1, rxjs@^7.8.1: +rxjs@7.8.2, rxjs@^7.5.1, rxjs@^7.8.1: version "7.8.2" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b" integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== @@ -7319,11 +7254,6 @@ signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -signal-exit@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" - integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== - sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -7373,12 +7303,12 @@ socket.io-client@4.7.5: socket.io-parser "~4.2.4" socket.io-parser@~4.2.4: - version "4.2.4" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83" - integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew== + version "4.2.5" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.5.tgz#3f41b8d369129a93268f2abecba94b5292850099" + integrity sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ== dependencies: "@socket.io/component-emitter" "~3.1.0" - debug "~4.3.1" + debug "~4.4.1" sonic-boom@^4.0.1: version "4.2.0" @@ -7471,15 +7401,6 @@ string-length@^5.0.1: char-regex "^2.0.0" strip-ansi "^7.0.1" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -7489,15 +7410,6 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.1, string-width@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - string.prototype.includes@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz#eceef21283640761a81dbe16d6c7171a4edf7d92" @@ -7580,13 +7492,6 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -7621,19 +7526,19 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -style-to-js@1.1.19: - version "1.1.19" - resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.19.tgz#f3f671e74764c1e8eebfba95a9a672acf5c19011" - integrity sha512-Ev+SgeqiNGT1ufsXyVC5RrJRXdrkRJ1Gol9Qw7Pb72YCKJXrBvP0ckZhBeVSrw2m06DJpei2528uIpjMb4TsoQ== +style-to-js@1.1.21: + version "1.1.21" + resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.21.tgz#2908941187f857e79e28e9cd78008b9a0b3e0e8d" + integrity sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ== dependencies: - style-to-object "1.0.12" + style-to-object "1.0.14" -style-to-object@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.12.tgz#03a30e7f4e555bf50845f8b55c7d5bc2248e03f0" - integrity sha512-ddJqYnoT4t97QvN2C95bCgt+m7AAgXjVnkk/jxAfmp7EAB8nnqqZYEbMd3em7/vEomDb2LAQKAy1RFfv41mdNw== +style-to-object@1.0.14: + version "1.0.14" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.14.tgz#1d22f0e7266bb8c6d8cae5caf4ec4f005e08f611" + integrity sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw== dependencies: - inline-style-parser "0.2.6" + inline-style-parser "0.2.7" styled-jsx@5.1.1: version "5.1.1" @@ -7643,16 +7548,16 @@ styled-jsx@5.1.1: client-only "0.0.1" sucrase@^3.32.0: - version "3.35.0" - resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" - integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== + version "3.35.1" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.1.tgz#4619ea50393fe8bd0ae5071c26abd9b2e346bfe1" + integrity sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw== dependencies: "@jridgewell/gen-mapping" "^0.3.2" commander "^4.0.0" - glob "^10.3.10" lines-and-columns "^1.1.6" mz "^2.7.0" pirates "^4.0.1" + tinyglobby "^0.2.11" ts-interface-checker "^0.1.9" supports-color@^7.1.0: @@ -7769,7 +7674,7 @@ through@^2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -tinyglobby@^0.2.13, tinyglobby@^0.2.15: +tinyglobby@^0.2.11, tinyglobby@^0.2.13, tinyglobby@^0.2.15: version "0.2.15" resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== @@ -7981,9 +7886,9 @@ typescript@5.2.2: integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== ufo@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b" - integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== + version "1.6.2" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.2.tgz#aaf4d46b98425b2fb5031abe8d65ca069e93e755" + integrity sha512-heMioaxBcG9+Znsda5Q8sQbWnLJSl98AFDXTO80wELWEzX3hordXsTdxrIfMQoO9IY1MEnoGoPjpoKpMj+Yx0Q== uint8arrays@3.1.1, uint8arrays@^3.0.0: version "3.1.1" @@ -8060,9 +7965,9 @@ unrs-resolver@^1.6.2: "@unrs/resolver-binding-win32-x64-msvc" "1.11.1" unstorage@^1.9.0: - version "1.17.2" - resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.17.2.tgz#543d06f24e5b2005b2e9c15ea4180782df987a11" - integrity sha512-cKEsD6iBWJgOMJ6vW1ID/SYuqNf8oN4yqRk8OYqaVQ3nnkJXOT1PSpaMh2QfzLs78UN5kSNRD2c/mgjT8tX7+w== + version "1.17.3" + resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.17.3.tgz#805acbeab7f7b97f0d0492427af18e650eda4e57" + integrity sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q== dependencies: anymatch "^3.1.3" chokidar "^4.0.3" @@ -8070,7 +7975,7 @@ unstorage@^1.9.0: h3 "^1.15.4" lru-cache "^10.4.3" node-fetch-native "^1.6.7" - ofetch "^1.5.0" + ofetch "^1.5.1" ufo "^1.6.1" untildify@^4.0.0: @@ -8078,10 +7983,10 @@ untildify@^4.0.0: resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== -update-browserslist-db@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz#7802aa2ae91477f255b86e0e46dbc787a206ad4a" - integrity sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A== +update-browserslist-db@^1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d" + integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w== dependencies: escalade "^3.2.0" picocolors "^1.1.1" @@ -8133,9 +8038,9 @@ v8-to-istanbul@^9.0.1: convert-source-map "^2.0.0" validator@^13.6.0: - version "13.15.20" - resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.20.tgz#054e9238109538a1bf46ae3e1290845a64fa2186" - integrity sha512-KxPOq3V2LmfQPP4eqf3Mq/zrT0Dqp2Vmx2Bn285LwVahLc+CsxOM0crBHczm8ijlcjZ0Q5Xd6LW3z3odTPnlrw== + version "13.15.26" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.15.26.tgz#36c3deeab30e97806a658728a155c66fcaa5b944" + integrity sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA== verror@1.10.0: version "1.10.0" @@ -8147,11 +8052,11 @@ verror@1.10.0: extsprintf "^1.2.0" vite@^7.2.4: - version "7.2.4" - resolved "https://registry.yarnpkg.com/vite/-/vite-7.2.4.tgz#a3a09c7e25487612ecc1119c7d412c73da35bd4e" - integrity sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w== + version "7.3.1" + resolved "https://registry.yarnpkg.com/vite/-/vite-7.3.1.tgz#7f6cfe8fb9074138605e822a75d9d30b814d6507" + integrity sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA== dependencies: - esbuild "^0.25.0" + esbuild "^0.27.0" fdir "^6.5.0" picomatch "^4.0.3" postcss "^8.5.6" @@ -8282,15 +8187,6 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -8309,15 +8205,6 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" - integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== - dependencies: - ansi-styles "^6.1.0" - string-width "^5.0.1" - strip-ansi "^7.0.1" - wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -8337,9 +8224,9 @@ ws@^7.5.1: integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== ws@^8.11.0: - version "8.18.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.3.tgz#b56b88abffde62791c639170400c93dcb0c95472" - integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg== + version "8.19.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.19.0.tgz#ddc2bdfa5b9ad860204f5a72a4863a8895fd8c8b" + integrity sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg== ws@~8.17.1: version "8.17.1" @@ -8377,9 +8264,9 @@ yallist@^3.0.2: integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yaml@^2.3.4: - version "2.8.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79" - integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== + version "2.8.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.2.tgz#5694f25eca0ce9c3e7a9d9e00ce0ddabbd9e35c5" + integrity sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A== yargs-parser@^18.1.2: version "18.1.3"