diff --git a/apps/desktop-e2e/src/helpers/AccountGroup.ts b/apps/desktop-e2e/src/helpers/AccountGroup.ts index 05671a2395..7f8baaf8ae 100644 --- a/apps/desktop-e2e/src/helpers/AccountGroup.ts +++ b/apps/desktop-e2e/src/helpers/AccountGroup.ts @@ -1,5 +1,5 @@ import { InMemorySigner } from "@taquito/signer"; -import { type RawPkh, derivePublicKeyPair, getFingerPrint, makeDerivationPath } from "@umami/tezos"; +import { type RawPkh, derivePublicKeyPair, makeDerivationPath } from "@umami/tezos"; import lodash from "lodash"; export type AccountGroup = { @@ -46,12 +46,11 @@ export class AccountGroupBuilder { this.derivationPathTemplate = derivationPathTemplate; } - async setSeedPhrase(seedPhrase: string[]): Promise { + setSeedPhrase(seedPhrase: string[]): void { if (this.accountGroup.type !== "mnemonic") { throw new Error(`Seed phrase is not used for ${this.accountGroup.type} accounts}`); } this.seedPhrase = seedPhrase; - this.accountGroup.label = `Seedphrase ${await getFingerPrint(seedPhrase.join(" "))}`; } getSeedPhrase = () => this.seedPhrase; diff --git a/apps/desktop-e2e/src/helpers/backedupAccountGroups.ts b/apps/desktop-e2e/src/helpers/backedupAccountGroups.ts index 2f3e1e0755..465b0fd359 100644 --- a/apps/desktop-e2e/src/helpers/backedupAccountGroups.ts +++ b/apps/desktop-e2e/src/helpers/backedupAccountGroups.ts @@ -5,18 +5,18 @@ import { type AccountGroup, AccountGroupBuilder } from "./AccountGroup"; export const v1BackedupAccountGroups = async () => { const expectedGroups: AccountGroup[] = []; - // Seedphrase 5fd091e1 + let accountGroupBuilder = new AccountGroupBuilder("mnemonic", 1); accountGroupBuilder.setAllAccountNames("Account"); - await accountGroupBuilder.setSeedPhrase(mnemonic1.split(" ")); + accountGroupBuilder.setSeedPhrase(mnemonic1.split(" ")); accountGroupBuilder.setDerivationPathTemplate(DEFAULT_DERIVATION_PATH_TEMPLATE.value); expectedGroups.push(await accountGroupBuilder.build()); - // Seedphrase 1b406abf + const mnemonic = "top skirt fan helmet ankle pave original ivory push song bridge broom hawk food parade nation involve sunny rely security ladder beach gown imitate"; accountGroupBuilder = new AccountGroupBuilder("mnemonic", 1); accountGroupBuilder.setAllAccountNames("Account"); - await accountGroupBuilder.setSeedPhrase(mnemonic.split(" ")); + accountGroupBuilder.setSeedPhrase(mnemonic.split(" ")); accountGroupBuilder.setDerivationPathTemplate(DEFAULT_DERIVATION_PATH_TEMPLATE.value); expectedGroups.push(await accountGroupBuilder.build()); // TODO: add related multisig accounts. @@ -32,7 +32,7 @@ export const v2BackedupAccountGroups = async () => { accountGroupBuilder.setAccountName("Restored account 2", 2); accountGroupBuilder.setAccountName("htrthrh", 3); accountGroupBuilder.setAccountName("12asd", 4); - await accountGroupBuilder.setSeedPhrase(mnemonic1.split(" ")); + accountGroupBuilder.setSeedPhrase(mnemonic1.split(" ")); accountGroupBuilder.setDerivationPathTemplate(DEFAULT_DERIVATION_PATH_TEMPLATE.value); expectedGroups.push(await accountGroupBuilder.build()); // Seedphrase fa3f3982 @@ -40,7 +40,7 @@ export const v2BackedupAccountGroups = async () => { "cluster umbrella blade second miss margin jazz joke blur column bulk monkey wrestle spell day produce noble front alley kangaroo auction sight truck other"; accountGroupBuilder = new AccountGroupBuilder("mnemonic", 1); accountGroupBuilder.setAccountName("test"); - await accountGroupBuilder.setSeedPhrase(mnemonic2.split(" ")); + accountGroupBuilder.setSeedPhrase(mnemonic2.split(" ")); accountGroupBuilder.setDerivationPathTemplate(DEFAULT_DERIVATION_PATH_TEMPLATE.value); expectedGroups.push(await accountGroupBuilder.build()); // Seedphrase 2263e19b @@ -48,7 +48,7 @@ export const v2BackedupAccountGroups = async () => { "few gauge word visa april now grace allow ozone box loop pudding clap barely loud casino ugly demise bottom urge toast fan wedding exclude"; accountGroupBuilder = new AccountGroupBuilder("mnemonic", 1); accountGroupBuilder.setAccountName("test2"); - await accountGroupBuilder.setSeedPhrase(mnemonic3.split(" ")); + accountGroupBuilder.setSeedPhrase(mnemonic3.split(" ")); accountGroupBuilder.setDerivationPathTemplate(DEFAULT_DERIVATION_PATH_TEMPLATE.value); expectedGroups.push(await accountGroupBuilder.build()); // TODO: add ledger account diff --git a/apps/desktop-e2e/src/pages/AccountsPage.ts b/apps/desktop-e2e/src/pages/AccountsPage.ts index 9ee88555a8..e1a1f68173 100644 --- a/apps/desktop-e2e/src/pages/AccountsPage.ts +++ b/apps/desktop-e2e/src/pages/AccountsPage.ts @@ -32,34 +32,28 @@ export class AccountsPage { }; } - async getGroup(groupTitle: string): Promise { - const group = this.page.getByTestId(`account-group-${groupTitle}`); - - const label = await group.getByTestId("account-group-title").innerText(); - - const accountTiles = await group.getByTestId("account-identifier").all(); - const accounts: Account[] = []; - for (const accountTile of accountTiles) { - const name = await accountTile.getByRole("heading", { level: 2 }).innerText(); - const pkh = await accountTile.getByTestId("short-address").innerText(); - - // pkh here will be a shortened version of the real pkh - accounts.push({ name, pkh }); + async getAllGroups(): Promise { + const groupElements = await this.page.getByTestId(/account-group-.*/).all(); + const groups = []; + for (const groupElement of groupElements) { + groups.push(await buildGroup(groupElement)); } + return groups; + } - const groupType = /Secret Key/.test(label) ? "secret_key" : "mnemonic"; - - return { - type: groupType, - label, - accounts, - }; + async getGroup(groupTitle: string): Promise { + const group = this.page.getByTestId(`account-group-${groupTitle}`); + return buildGroup(group); } async checkAccountGroup(expectedGroup: AccountGroup): Promise { - const group = await this.getGroup(expectedGroup.label); + const allGroups = await this.getAllGroups(); + + const group = allGroups.find(group => + group.accounts.some(acc => acc.pkh === formatPkh(expectedGroup.accounts[0].pkh)) + )!; - expect(group.label).toEqual(expectedGroup.label); + expect(group).not.toBeUndefined(); expect(group.accounts.length).toEqual(expectedGroup.accounts.length); for (let i = 0; i < group.accounts.length; i++) { expect(group.accounts[i].name).toEqual(expectedGroup.accounts[i].name); @@ -67,3 +61,25 @@ export class AccountsPage { } } } + +const buildGroup = async (groupElement: Locator): Promise => { + const label = await groupElement.getByTestId("group-title").innerText(); + + const accountTiles = await groupElement.getByTestId("account-identifier").all(); + const accounts: Account[] = []; + for (const accountTile of accountTiles) { + const name = await accountTile.getByRole("heading", { level: 2 }).innerText(); + const pkh = await accountTile.getByTestId("short-address").innerText(); + + // pkh here will be a shortened version of the real pkh + accounts.push({ name, pkh }); + } + + const groupType = /Secret Key/.test(label) ? "secret_key" : "mnemonic"; + + return { + type: groupType, + label, + accounts, + }; +}; diff --git a/apps/desktop-e2e/src/steps/onboarding.ts b/apps/desktop-e2e/src/steps/onboarding.ts index 2455d985c3..6ff0358d25 100644 --- a/apps/desktop-e2e/src/steps/onboarding.ts +++ b/apps/desktop-e2e/src/steps/onboarding.ts @@ -32,7 +32,7 @@ Then("I record generated seedphrase", async function (this: CustomWorld) { for (let i = 0; i < 24; i++) { words.push(await this.page.getByTestId(`mnemonic-word-${i}`).innerText()); } - await accountGroupBuilder.setSeedPhrase(words); + accountGroupBuilder.setSeedPhrase(words); }); When("I enter recorded seedphrase", async function (this: CustomWorld) { @@ -46,7 +46,7 @@ When("I enter recorded seedphrase", async function (this: CustomWorld) { }); When("I enter existing seedphrase", async function (this: CustomWorld) { - await accountGroupBuilder.setSeedPhrase(existingSeedphrase.split(" ")); + accountGroupBuilder.setSeedPhrase(existingSeedphrase.split(" ")); for (let i = 0; i < 24; i++) { await this.page.getByRole("textbox").nth(i).fill(accountGroupBuilder.getSeedPhrase()[i]); } diff --git a/apps/desktop/src/views/home/AccountGroup.tsx b/apps/desktop/src/views/home/AccountGroup.tsx index 32bee829a1..b24541927a 100644 --- a/apps/desktop/src/views/home/AccountGroup.tsx +++ b/apps/desktop/src/views/home/AccountGroup.tsx @@ -69,7 +69,7 @@ export const AccountGroup = ({ return (
- + {groupLabel} diff --git a/apps/desktop/src/views/home/AccountsList.test.tsx b/apps/desktop/src/views/home/AccountsList.test.tsx index 06dc0361fc..b13f0f6e98 100644 --- a/apps/desktop/src/views/home/AccountsList.test.tsx +++ b/apps/desktop/src/views/home/AccountsList.test.tsx @@ -136,7 +136,7 @@ describe("", () => { restore(); render(, { store }); expect(screen.getAllByTestId("account-tile-container")).toHaveLength(7); - expect(screen.getAllByTestId(/account-group-title/)).toHaveLength(4); + expect(screen.getAllByTestId(/group-title/)).toHaveLength(4); const socialAccounts = screen.getByTestId(/account-group-social/i); expect(within(socialAccounts).getAllByTestId("account-tile-container")).toHaveLength(2); diff --git a/packages/state/src/hooks/mnemonic.test.ts b/packages/state/src/hooks/mnemonic.test.ts index 7c09d2b192..8a1f20198d 100644 --- a/packages/state/src/hooks/mnemonic.test.ts +++ b/packages/state/src/hooks/mnemonic.test.ts @@ -8,8 +8,8 @@ import { mnemonic1 } from "@umami/test-utils"; import { MAINNET, defaultDerivationPathTemplate, + generateHash, getDefaultDerivationPath, - getFingerPrint, isAccountRevealed, } from "@umami/tezos"; @@ -21,7 +21,7 @@ import { addTestAccount, fakeIsAccountRevealed, renderHook } from "../testUtils" jest.mock("@umami/tezos", () => ({ ...jest.requireActual("@umami/tezos"), isAccountRevealed: jest.fn(), - getFingerPrint: jest.fn(), + generateHash: jest.fn(), })); let store: UmamiStore; @@ -75,7 +75,7 @@ const testPublicKeys = { }; beforeEach(() => { - jest.mocked(getFingerPrint).mockResolvedValue("mockFingerPrint"); + jest.mocked(generateHash).mockResolvedValue("mockFingerPrint"); }); describe.each(["ed25519", "secp256k1", "p256"] as const)("with %s curve", curve => { diff --git a/packages/state/src/hooks/mnemonic.ts b/packages/state/src/hooks/mnemonic.ts index f6b95692cd..71184532a0 100644 --- a/packages/state/src/hooks/mnemonic.ts +++ b/packages/state/src/hooks/mnemonic.ts @@ -4,7 +4,7 @@ import { type Network, type PublicKeyPair, derivePublicKeyPair, - getFingerPrint, + generateHash, isAccountRevealed, makeDerivationPath, } from "@umami/tezos"; @@ -89,7 +89,7 @@ export const useRestoreRevealedMnemonicAccounts = () => { curve, network ); - const seedFingerPrint = await getFingerPrint(mnemonic); + const seedFingerPrint = await generateHash(); const accountLabels = getNextAvailableAccountLabels(label, pubKeyPairs.length); return pubKeyPairs.map(({ pk, pkh }, accountIndex) => ({ diff --git a/packages/state/src/hooks/setAccountData.test.ts b/packages/state/src/hooks/setAccountData.test.ts index 2bea59bf6c..d120371a6b 100644 --- a/packages/state/src/hooks/setAccountData.test.ts +++ b/packages/state/src/hooks/setAccountData.test.ts @@ -12,7 +12,7 @@ import { mnemonic1 } from "@umami/test-utils"; import { AVAILABLE_DERIVATION_PATH_TEMPLATES, derivePublicKeyPair, - getFingerPrint, + generateHash, isAccountRevealed, makeDerivationPath, } from "@umami/tezos"; @@ -47,7 +47,7 @@ jest.mock("@umami/crypto", () => ({ })); jest.mock("@umami/tezos", () => ({ ...jest.requireActual("@umami/tezos"), - getFingerPrint: jest.fn(), + generateHash: jest.fn(), isAccountRevealed: jest.fn(), })); @@ -94,7 +94,7 @@ describe.each(["ed25519", "secp256k1", "p256"] as const)( describe("useRestoreFromMnemonic", () => { beforeEach(() => { - jest.mocked(getFingerPrint).mockResolvedValue(MOCK_FINGERPRINT); + jest.mocked(generateHash).mockResolvedValue(MOCK_FINGERPRINT); jest.mocked(encrypt).mockReturnValue(Promise.resolve(MOCK_ENCRYPTED)); }); @@ -118,7 +118,7 @@ describe.each(["ed25519", "secp256k1", "p256"] as const)( expect(store.getState().accounts.seedPhrases).toEqual({ [MOCK_FINGERPRINT]: MOCK_ENCRYPTED, }); - expect(getFingerPrint).toHaveBeenCalledWith(mnemonic1); + expect(generateHash).toHaveBeenCalledTimes(1); // Encrypts given mnemonic with the given password. expect(encrypt).toHaveBeenCalledWith(mnemonic1, PASSWORD); }); @@ -159,7 +159,7 @@ describe.each(["ed25519", "secp256k1", "p256"] as const)( expect(store.getState().accounts.seedPhrases).toEqual({ [MOCK_FINGERPRINT]: MOCK_ENCRYPTED, }); - expect(getFingerPrint).toHaveBeenCalledWith(mnemonic1); + expect(generateHash).toHaveBeenCalledTimes(1); // Encrypts given mnemonic with the given password. expect(encrypt).toHaveBeenCalledWith(mnemonic1, PASSWORD); }); diff --git a/packages/state/src/hooks/setAccountData.ts b/packages/state/src/hooks/setAccountData.ts index 2ac3fc893a..5a5de17238 100644 --- a/packages/state/src/hooks/setAccountData.ts +++ b/packages/state/src/hooks/setAccountData.ts @@ -8,7 +8,7 @@ import { } from "@umami/core"; import { decrypt, encrypt } from "@umami/crypto"; import { type IDP } from "@umami/social-auth"; -import { derivePublicKeyPair, getFingerPrint, makeDerivationPath } from "@umami/tezos"; +import { derivePublicKeyPair, makeDerivationPath } from "@umami/tezos"; import { useCallback } from "react"; import { useDispatch } from "react-redux"; @@ -62,7 +62,6 @@ export const useRestoreFromMnemonic = () => { curve: Curves; isVerified?: boolean; }) => { - const seedFingerprint = await getFingerPrint(mnemonic); const accounts = await restoreRevealedMnemonicAccounts( mnemonic, network, @@ -75,7 +74,7 @@ export const useRestoreFromMnemonic = () => { dispatch( accountsActions.addMnemonicAccounts({ - seedFingerprint, + seedFingerprint: accounts[0].seedFingerPrint, accounts, encryptedMnemonic, }) @@ -91,7 +90,7 @@ export const useRestoreFromMnemonic = () => { * * New account is added to the {@link accountsSlice}. * - * @param fingerPrint - Hash of the mnemonic. Generated with {@link getFingerPrint}. We use it to group together accounts derived from the same mnemonic + * @param fingerPrint - Hash of the mnemonic. Generated with {@link generateHash}. We use it to group together accounts derived from the same mnemonic * @param password - User's password, used for decrypting the mnemonic. * @param label - Account name prefix, used to create a unique account name. */ diff --git a/packages/state/src/thunks/changeMnemonicPassword.test.ts b/packages/state/src/thunks/changeMnemonicPassword.test.ts index c0af0d7d89..e9e178cd8d 100644 --- a/packages/state/src/thunks/changeMnemonicPassword.test.ts +++ b/packages/state/src/thunks/changeMnemonicPassword.test.ts @@ -1,7 +1,7 @@ import { type MnemonicAccount, mockImplicitAccount } from "@umami/core"; import { type EncryptedData, decrypt, encrypt } from "@umami/crypto"; import { mnemonic1, mnemonic2 } from "@umami/test-utils"; -import { getFingerPrint } from "@umami/tezos"; +import { generateHash } from "@umami/tezos"; import { changeMnemonicPassword } from "./changeMnemonicPassword"; import { accountsActions } from "../slices/accounts/accounts"; @@ -16,8 +16,15 @@ beforeEach(() => { store = makeStore(); }); +let fingerPrint1: string; +let fingerPrint2: string; + +beforeAll(async () => { + fingerPrint1 = await generateHash(); + fingerPrint2 = await generateHash(); +}); + beforeEach(async () => { - const fingerPrint1 = await getFingerPrint(mnemonic1); store.dispatch( accountsActions.addMnemonicAccounts({ seedFingerprint: fingerPrint1, @@ -29,7 +36,6 @@ beforeEach(async () => { }) ); - const fingerPrint2 = await getFingerPrint(mnemonic2); store.dispatch( accountsActions.addMnemonicAccounts({ seedFingerprint: fingerPrint2, @@ -43,9 +49,6 @@ beforeEach(async () => { describe("changeMnemonicPassword", () => { it("should update password", async () => { - const fingerPrint1 = await getFingerPrint(mnemonic1); - const fingerPrint2 = await getFingerPrint(mnemonic2); - const action = await store.dispatch( changeMnemonicPassword({ currentPassword, newPassword }) ); @@ -64,9 +67,6 @@ describe("changeMnemonicPassword", () => { }); it("should throw with old password", async () => { - const fingerPrint1 = await getFingerPrint(mnemonic1); - const fingerPrint2 = await getFingerPrint(mnemonic2); - const action: { type: string; payload: { newEncryptedMnemonics: Record }; diff --git a/packages/tezos/package.json b/packages/tezos/package.json index a9e0b0d7dc..88c92ba665 100644 --- a/packages/tezos/package.json +++ b/packages/tezos/package.json @@ -27,6 +27,7 @@ "eslint": "^8.57.0", "jest": "^29.7.0", "madge": "^8.0.0", + "mockdate": "^3.0.5", "prettier": "^3.3.2", "rimraf": "^6.0.1", "tsup": "^8.3.0", diff --git a/packages/tezos/src/helpers.test.ts b/packages/tezos/src/helpers.test.ts index 5d2561b45d..395d6dee47 100644 --- a/packages/tezos/src/helpers.test.ts +++ b/packages/tezos/src/helpers.test.ts @@ -3,6 +3,7 @@ import { DerivationType, LedgerSigner } from "@taquito/ledger-signer"; import { InMemorySigner } from "@taquito/signer"; import { mnemonic1 } from "@umami/test-utils"; import axios from "axios"; +import MockDate from "mockdate"; import { defaultDerivationPathTemplate, getDefaultDerivationPath } from "./derivationPathUtils"; import { isAccountRevealed } from "./fetch"; @@ -11,7 +12,7 @@ import { decryptSecretKey, derivePublicKeyPair, deriveSecretKey, - getFingerPrint, + generateHash, getIPFSurl, getPublicKeyPairFromSk, isValidMichelson, @@ -88,8 +89,9 @@ describe("helpers", () => { }); }); - test("getFingerPrint", async () => { - expect(await getFingerPrint("asd")).toEqual("688787d8"); + test("generateHash", async () => { + MockDate.set("2022-12-27T14:15:49.760Z"); + expect(await generateHash()).toEqual("a321a5e0"); }); describe("curveToDerivationPath", () => { diff --git a/packages/tezos/src/helpers.ts b/packages/tezos/src/helpers.ts index 29f9378cc5..f9d5a1cbcc 100644 --- a/packages/tezos/src/helpers.ts +++ b/packages/tezos/src/helpers.ts @@ -7,10 +7,8 @@ import { TezosToolkit } from "@taquito/taquito"; import { FakeSigner } from "./fakeSigner"; import { type PublicKeyPair, type SignerConfig } from "./types"; -// Temporary solution for generating fingerprint for seedphrase -// https://remarkablemark.medium.com/how-to-generate-a-sha-256-hash-with-javascript-d3b2696382fd -export const getFingerPrint = async (seedPhrase: string): Promise => { - const utf8 = new TextEncoder().encode(seedPhrase); +export const generateHash = async (): Promise => { + const utf8 = new TextEncoder().encode(Date.now().toString()); const hashBuffer = await crypto.subtle.digest("SHA-256", utf8); const hashArray = Array.from(new Uint8Array(hashBuffer)); const hashHex = hashArray diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3afb1d08ed..c684d3ba60 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -876,7 +876,7 @@ importers: version: 2.5.2 jest-transformer-svg: specifier: ^2.0.2 - version: 2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0))(react@18.3.1) + version: 2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)))(react@18.3.1) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1006,7 +1006,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) lodash: specifier: ^4.17.21 version: 4.17.21 @@ -1109,7 +1109,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1167,7 +1167,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1282,7 +1282,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1333,13 +1333,13 @@ importers: version: 2.30.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) eslint-plugin-jest: specifier: ^28.8.3 - version: 28.8.3(@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4) + version: 28.8.3(@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4) eslint-plugin-jest-dom: specifier: ^5.4.0 version: 5.4.0(@testing-library/dom@10.4.0)(eslint@8.57.0) eslint-plugin-playwright: specifier: ^1.6.2 - version: 1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4))(eslint@8.57.0) + version: 1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4))(eslint@8.57.0) eslint-plugin-react: specifier: ^7.37.0 version: 7.37.0(eslint@8.57.0) @@ -1366,7 +1366,7 @@ importers: devDependencies: jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) rimraf: specifier: ^6.0.1 version: 6.0.1 @@ -1442,7 +1442,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1500,7 +1500,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1651,7 +1651,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1712,7 +1712,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -1794,10 +1794,13 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) + mockdate: + specifier: ^3.0.5 + version: 3.0.5 prettier: specifier: ^3.3.2 version: 3.3.3 @@ -1875,7 +1878,7 @@ importers: version: 8.57.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + version: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) madge: specifier: ^8.0.0 version: 8.0.0(typescript@5.5.4) @@ -12794,6 +12797,41 @@ snapshots: - supports-color - ts-node + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.14.11 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.7 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + '@jest/environment@29.7.0': dependencies: '@jest/fake-timers': 29.7.0 @@ -15847,6 +15885,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-require@1.1.1: {} cross-env@7.0.3: @@ -16645,23 +16698,23 @@ snapshots: optionalDependencies: '@testing-library/dom': 10.4.0 - eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4): + eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4): dependencies: '@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) eslint: 8.57.0 optionalDependencies: '@typescript-eslint/eslint-plugin': 8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) - jest: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) + jest: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) transitivePeerDependencies: - supports-color - typescript - eslint-plugin-playwright@1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4))(eslint@8.57.0): + eslint-plugin-playwright@1.6.2(eslint-plugin-jest@28.8.3(@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4))(eslint@8.57.0): dependencies: eslint: 8.57.0 globals: 13.24.0 optionalDependencies: - eslint-plugin-jest: 28.8.3(@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(babel-plugin-macros@3.1.0))(typescript@5.5.4) + eslint-plugin-jest: 28.8.3(@typescript-eslint/eslint-plugin@8.7.0(@typescript-eslint/parser@8.7.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)))(typescript@5.5.4) eslint-plugin-react-hooks@4.6.2(eslint@8.57.0): dependencies: @@ -17859,6 +17912,25 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest-config@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)): dependencies: '@babel/core': 7.25.2 @@ -17890,6 +17962,68 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@babel/core': 7.25.2 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.25.2) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.7 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.14.11 + ts-node: 10.9.2(@types/node@22.1.0)(typescript@5.5.4) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@babel/core': 7.25.2 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.25.2) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.7 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.1.0 + ts-node: 10.9.2(@types/node@22.1.0)(typescript@5.5.4) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-diff@29.7.0: dependencies: chalk: 4.1.2 @@ -18086,7 +18220,7 @@ snapshots: transitivePeerDependencies: - supports-color - jest-transformer-svg@2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0))(react@18.3.1): + jest-transformer-svg@2.0.2(jest@29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)))(react@18.3.1): dependencies: jest: 29.7.0(@types/node@20.14.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.14.11)(typescript@5.5.4)) react: 18.3.1 @@ -18150,6 +18284,18 @@ snapshots: - supports-color - ts-node + jest@29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)): + dependencies: + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.1.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jiti@1.21.6: {} jju@1.4.0: {} @@ -20460,6 +20606,25 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + ts-node@10.9.2(@types/node@22.1.0)(typescript@5.5.4): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.1.0 + acorn: 8.12.1 + acorn-walk: 8.3.3 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.5.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29