diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 5090b2f9a5..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,12 +0,0 @@ -node_modules/ -coverage/ -docs/dist/ -docs/build/ -docs/public/ -docs/static/ -web-build/ -jest/testSetup.js -__fixtures__/ - -# generated by bob -lib/ diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 223dd94031..0000000000 --- a/.eslintrc +++ /dev/null @@ -1,79 +0,0 @@ -{ - "env": { - "browser": true - }, - - "extends": "@callstack", - - "plugins": ["eslint-plugin-local-rules"], - - "rules": { - "local-rules/no-import-react-forwardref": "error", - "local-rules/no-react-forwardref-usage": "error", - - "one-var": "off", - "no-multi-assign": "off", - "no-nested-ternary": "off", - "no-undef": "off", - "global-require": "off", - "react/react-in-jsx-scope": "off", - "react/jsx-uses-react": "off", - - "import/no-extraneous-dependencies": "off", - "import/first": "off", - "import/order": [ - "error", - { - "groups": [ - ["external", "builtin"], - "internal", - ["sibling", "parent"], - "index" - ], - "pathGroups": [ - { - "pattern": "@(react|react-native)", - "group": "external", - "position": "before" - }, - { - "pattern": "@src/**", - "group": "internal" - } - ], - "pathGroupsExcludedImportTypes": ["internal", "react"], - "newlines-between": "always", - "alphabetize": { - "order": "asc", - "caseInsensitive": true - } - } - ], - - "react-native/no-unused-styles": "error", - "react-native/split-platform-components": "off", - "react-native/no-raw-text": "off", - "react-native-a11y/has-valid-accessibility-descriptors": "off" - }, - - "overrides": [ - { - "files": ["*.test.js", "*.test.tsx"], - "rules": { - "local-rules/no-react-forwardref-usage": "off" - } - } - ], - - "settings": { - "import/extensions": [".js", ".ts", ".tsx"], - "import/parsers": { - "@typescript-eslint/parser": [".ts", ".tsx"] - }, - "import/resolver": { - "node": { - "extensions": [".js", ".ts", ".tsx"] - } - } - } -} diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f14817e3d1..2168fac68d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -13,4 +13,4 @@ - + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8096174f9a..852bb6bd97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,10 +18,10 @@ jobs: uses: ./.github/actions/setup - name: Lint - run: yarn lint-no-fix + run: yarn lint - typescript: - name: TypeScript + typecheck: + name: Typecheck runs-on: ubuntu-latest steps: - name: Checkout @@ -31,7 +31,7 @@ jobs: uses: ./.github/actions/setup - name: Check types - run: yarn typescript + run: yarn typecheck unit-tests: name: Unit tests @@ -73,7 +73,20 @@ jobs: - name: Build package run: | yarn prepack - node ./scripts/typescript-output-lint + node ./scripts/typescript-output-lint.ts + + build-example: + name: Build example + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Setup + uses: ./.github/actions/setup + + - name: Build example + run: yarn example expo export --platform all build-docs: name: Build docs diff --git a/.gitignore b/.gitignore index 6ece42c049..ca1e88e763 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,11 @@ yarn-error.log # coverage/ cache/jest/ +__ts-tests__/ + +# ESLint +# +.eslintcache # BUCK # @@ -63,12 +68,10 @@ CHANGELOG.md # generated by bob lib/ -.expo - # Yarn .yarn/* !.yarn/patches !.yarn/plugins !.yarn/releases !.yarn/sdks -!.yarn/versions \ No newline at end of file +!.yarn/versions diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a4cf09cd56..78b2b45937 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,9 +32,9 @@ Our pre-commit hooks verify that your commit message matches this format when co ### Linting and tests -We use `typescript` for type checking, `eslint` with `prettier` for linting and formatting the code, and `jest` for testing. Our pre-commit hooks verify that the linter and tests pass when commiting. You can also run the following commands manually: +We use `typescript` for type checking, `eslint` with `prettier` for linting and formatting the code, and `jest` for testing. Our pre-commit hooks verify that type checking, linting, and tests pass when committing. You can also run the following commands manually: -- `yarn typescript`: type-check files with `tsc`. +- `yarn typecheck`: type-check files with `tsc`. - `yarn lint`: lint files with `eslint` and `prettier`. - `yarn test`: run unit tests with `jest`. @@ -43,7 +43,7 @@ We use `typescript` for type checking, `eslint` with `prettier` for linting and When you're sending a pull request: - Prefer small pull requests focused on one change. -- Verify that `typescript`, `eslint` and all tests are passing. +- Verify that `typecheck`, `lint` and all tests are passing. - Preview the documentation to make sure it looks good. - Follow the pull request template when opening a pull request. @@ -58,7 +58,7 @@ When you're working on a component: The example app uses [Expo](https://expo.dev/) for the React Native example. You will need to install the Expo app for [Android](https://play.google.com/store/apps/details?id=host.exp.exponent) and [iOS](https://itunes.apple.com/app/apple-store/id982107779) to start developing. -> [!IMPORTANT] +> [!IMPORTANT] > The example app is built with `react-native@0.77.x` and Expo SDK 52, which isn’t compatible with Expo Go. To run the app, you have to create a [development build](https://docs.expo.dev/develop/development-builds/create-a-build/). After you're done, you can run `yarn example start` in the project root (or `npx expo start` in the `example/` folder) and scan the QR code to launch it on your device. @@ -72,7 +72,7 @@ If you want to test the changes brought by a pull request, you can do so by poin ```json { "dependencies": { - "react-native-paper": "git+https://github.com/callstack/react-native-paper.git#", + "react-native-paper": "git+https://github.com/callstack/react-native-paper.git#" } } ``` diff --git a/docs/.eslintrc b/docs/.eslintrc deleted file mode 100644 index bba456d680..0000000000 --- a/docs/.eslintrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../.eslintrc", - - "settings": { - "import/core-modules": ["react-native-paper"] - }, - - "rules": { - "react/prop-types": "off", - "import/no-unresolved": [ - 2, - {"ignore": ["^@docusaurus", "^@theme", "@^site"]} - ] - } -} diff --git a/docs/component-docs-plugin/generatePageMDX.js b/docs/component-docs-plugin/generatePageMDX.js index 0165ecdb8d..5d07def6ef 100644 --- a/docs/component-docs-plugin/generatePageMDX.js +++ b/docs/component-docs-plugin/generatePageMDX.js @@ -5,7 +5,6 @@ const { baseUrl, customFields } = config; function renderBadge(annotation) { const [annotType, ...annotLabel] = annotation.split(' '); - // eslint-disable-next-line prettier/prettier return `${annotLabel.join(' ')}`; } diff --git a/docs/component-docs-plugin/index.js b/docs/component-docs-plugin/index.js index af66c75aa0..ae6f470b0e 100644 --- a/docs/component-docs-plugin/index.js +++ b/docs/component-docs-plugin/index.js @@ -8,7 +8,7 @@ const generatePageMDX = require('./generatePageMDX'); const pluginName = 'component-docs-plugin'; -async function componentsPlugin(_, options) { +function componentsPlugin(_, options) { const { docsRootDir, libsRootDir, pages } = options; function clean() { @@ -55,7 +55,7 @@ async function componentsPlugin(_, options) { return { name: pluginName, - async loadContent() { + loadContent() { // Clean up docs directory. clean(); // Create root components category. @@ -80,7 +80,7 @@ async function componentsPlugin(_, options) { return docs; }, - async contentLoaded({ content: docs, actions }) { + contentLoaded({ content: docs, actions }) { // Store component docs global data so it can be used in `PropsTable` component. actions.setGlobalData({ docs, diff --git a/docs/package.json b/docs/package.json index ded467eb2b..89c447287c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -20,6 +20,7 @@ "@docusaurus/core": "^2.3.6", "@docusaurus/preset-classic": "^2.3.6", "@docusaurus/remark-plugin-npm2yarn": "^2.3.6", + "@docusaurus/theme-common": "^2.3.6", "@easyops-cn/docusaurus-search-local": "^0.33.4", "@material/material-color-utilities": "0.2.4", "@mdx-js/react": "^1.6.22", @@ -39,13 +40,13 @@ }, "devDependencies": { "@docusaurus/module-type-aliases": "^2.3.6", - "@jest/globals": "^29.7.0", "@tsconfig/docusaurus": "^1.0.6", "@types/marked": "^4.0.7", "@types/react-color": "^3.0.6", "component-docs": "^0.24.0", "patch-package": "^6.5.0", - "typescript": "^4.8.4" + "typescript": "^4.8.4", + "webpack": "^5.73.0" }, "browserslist": { "production": [ diff --git a/docs/src/components/DynamicColorTheme.tsx b/docs/src/components/DynamicColorTheme.tsx index 19f37f8d6b..1203992e7d 100644 --- a/docs/src/components/DynamicColorTheme.tsx +++ b/docs/src/components/DynamicColorTheme.tsx @@ -3,7 +3,6 @@ import type { ReactNode } from 'react'; import Color from 'color'; //@ts-ignore -// eslint-disable-next-line import/no-unresolved import { BlockPicker } from 'react-color'; import Switch from './Switch'; @@ -161,7 +160,7 @@ const CodePreview = ({ }; const onCopy = () => { - navigator.clipboard.writeText(getColorScheme()); + void navigator.clipboard.writeText(getColorScheme()); setCopied(true); setTimeout(() => setCopied(false), 1000); diff --git a/docs/src/components/PropTable.tsx b/docs/src/components/PropTable.tsx index 39980fb703..9e073b14fe 100644 --- a/docs/src/components/PropTable.tsx +++ b/docs/src/components/PropTable.tsx @@ -1,5 +1,4 @@ // @ts-ignore -// eslint-disable-next-line import/no-unresolved import useDoc from '@site/component-docs-plugin/useDocs'; import Markdown from './Markdown'; @@ -27,7 +26,6 @@ const typeDefinitions = { const renderBadge = (annotation: string) => { const [annotType, ...annotLabel] = annotation.split(' '); - // eslint-disable-next-line prettier/prettier return ` { const parentStatus: Status = allChecked ? 'checked' : noneChecked - ? 'unchecked' - : 'indeterminate'; + ? 'unchecked' + : 'indeterminate'; const toggleAll = () => { const next = !allChecked; setChild1(next); diff --git a/example/src/RootNavigator.tsx b/example/src/RootNavigator.tsx index 5631de73d2..b64fd1d802 100644 --- a/example/src/RootNavigator.tsx +++ b/example/src/RootNavigator.tsx @@ -54,7 +54,7 @@ const Root = createNativeStackNavigator({ ( Object.entries(examplesWithoutParams) as [ ExampleRouteName, - (typeof examplesWithoutParams)[ExampleRouteName] + (typeof examplesWithoutParams)[ExampleRouteName], ][] ).map(([id, screen]) => [ id, diff --git a/example/src/index.tsx b/example/src/index.tsx index 688297b059..afa3941044 100644 --- a/example/src/index.tsx +++ b/example/src/index.tsx @@ -105,8 +105,8 @@ export default function PaperExample() { ? DynamicDarkTheme : DynamicLightTheme : isDarkMode - ? DarkTheme - : LightTheme; + ? DarkTheme + : LightTheme; const direction = rtl ? 'rtl' : 'ltr'; @@ -130,7 +130,7 @@ export default function PaperExample() { } }; - restorePrefs(); + void restorePrefs(); }, []); React.useEffect(() => { @@ -159,12 +159,12 @@ export default function PaperExample() { I18nManager.forceRTL(rtl); if (Platform.OS !== 'web') { - Updates.reloadAsync(); + await Updates.reloadAsync(); } } }; - savePrefs(); + void savePrefs(); }, [direction, isDarkMode, isReady, rtl]); const preferences = React.useMemo( @@ -230,7 +230,7 @@ export default function PaperExample() { }, }} onReady={() => { - SplashScreen.hideAsync(); + void SplashScreen.hideAsync(); }} /> {Platform.OS !== 'web' ? ( diff --git a/jest/jest-native.d.ts b/jest/jest-native.d.ts deleted file mode 100644 index d5dc396a76..0000000000 --- a/jest/jest-native.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import '@jest/expect'; -import type { JestNativeMatchers } from '@testing-library/jest-native/extend-expect'; -import 'expect'; - -declare module 'expect' { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - interface Matchers, T = unknown> - extends JestNativeMatchers {} -} diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000000..ab4ecdb2f7 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,17 @@ +commit-msg: + jobs: + - name: commitlint + run: yarn commitlint --edit {1} + +pre-commit: + parallel: true + commands: + lint: + glob: '*.{js,mjs,ts,tsx}' + run: yarn lint {staged_files} + typecheck: + glob: '*.{json,js,mjs,ts,tsx}' + run: yarn typecheck + test: + glob: '*.{json,js,mjs,ts,tsx}' + run: yarn test diff --git a/package.json b/package.json index 570fbb066e..e183be6c56 100644 --- a/package.json +++ b/package.json @@ -35,11 +35,11 @@ "docs" ], "scripts": { - "typescript": "tsc --noEmit", - "lint": "yarn lint-no-fix --fix", - "lint-no-fix": "eslint --ext '.js,.ts,.tsx' .", + "lint": "eslint", + "typecheck": "tsc", "test": "jest", - "prepack": "bob build && node ./scripts/generate-mappings.js", + "prepack": "bob build", + "generate-mappings": "node ./scripts/generate-mappings.ts", "release": "release-it --only-version", "docs": "yarn --cwd docs", "example": "yarn --cwd example" @@ -54,54 +54,43 @@ }, "devDependencies": { "@babel/core": "^7.29.0", + "@babel/parser": "^7.29.0", "@babel/plugin-proposal-export-namespace-from": "^7.18.9", - "@babel/runtime": "^7.29.0", - "@callstack/eslint-config": "^13.0.2", + "@babel/types": "^7.29.0", + "@callstack/eslint-config": "^15.0.0", "@commitlint/config-conventional": "^8.3.4", + "@eslint/js": "9.39.4", "@jest/globals": "^29.7.0", "@react-native-vector-icons/material-design-icons": "^12.0.0", "@react-native/babel-preset": "^0.85.3", "@react-native/jest-preset": "^0.85.3", "@react-navigation/native": "^8.0.0-alpha.28", "@release-it/conventional-changelog": "^1.1.0", - "@testing-library/jest-native": "^5.4.1", - "@testing-library/react-native": "11.5.0", + "@testing-library/react-native": "^14.0.0", "@types/color": "^3.0.0", - "@types/jest": "^29.2.1", - "@types/node": "^13.1.0", - "@types/react-dom": "^19.1.1", - "@types/react-native-vector-icons": "^6.4.18", - "@types/react-test-renderer": "^19.1.0", - "@typescript-eslint/eslint-plugin": "^5.41.0", - "@typescript-eslint/parser": "^5.41.0", + "@types/node": "^24.0.0", + "@types/react": "^19.2.7", "all-contributors-cli": "^6.24.0", - "babel-cli": "^6.26.0", - "babel-core": "^7.0.0-bridge.0", "babel-jest": "^29.6.3", - "babel-loader": "^8.2.3", "babel-test": "^0.1.1", - "chalk": "^4.0.0", "commitlint": "^8.3.4", - "conventional-changelog-cli": "^2.0.11", - "dedent": "^0.7.0", - "eslint": "8.31.0", + "eslint": "9.39.4", "eslint-plugin-flowtype": "^8.0.3", - "eslint-plugin-local-rules": "^1.3.2", - "glob": "^7.1.3", - "husky": "^1.3.1", + "eslint-plugin-testing-library": "^7.16.2", "jest": "^29.6.3", "jest-file-snapshot": "^0.3.2", + "lefthook": "^2.1.9", + "prettier": "^3.8.4", "react": "19.2.3", - "react-dom": "19.2.3", "react-native": "0.85.3", "react-native-builder-bob": "^0.42.1", "react-native-reanimated": "4.3.1", "react-native-safe-area-context": "5.7.0", "react-native-worklets": "0.8.3", - "react-test-renderer": "19.2.3", "release-it": "^13.4.0", - "rimraf": "^3.0.2", - "typescript": "5.8.3" + "test-renderer": "1.2.0", + "typescript": "5.8.3", + "typescript-eslint": "^8.61.1" }, "peerDependencies": { "react": "*", @@ -110,12 +99,6 @@ "react-native-safe-area-context": "*", "react-native-worklets": ">=0.8.1" }, - "husky": { - "hooks": { - "commit-msg": "commitlint -E HUSKY_GIT_PARAMS", - "pre-commit": "yarn lint-no-fix && yarn typescript && yarn test" - } - }, "jest": { "preset": "@react-native/jest-preset", "setupFiles": [ @@ -123,7 +106,7 @@ ], "setupFilesAfterEnv": [ "/jest/jestSetupAfterEnv.js", - "@testing-library/jest-native/extend-expect" + "@testing-library/react-native" ], "cacheDirectory": "./cache/jest", "testPathIgnorePatterns": [ @@ -146,10 +129,7 @@ "react", "react-dom", "react-native", - "react-test-renderer", "@types/react-native", - "@types/jest", - "husky", "eslint" ] }, @@ -163,6 +143,13 @@ { "project": "tsconfig.build.json" } + ], + [ + "custom", + { + "script": "generate-mappings", + "clean": "lib/mappings.json" + } ] ] }, diff --git a/scripts/generate-component-docs.ts b/scripts/generate-component-docs.ts index cc0ff5d93d..c4adcbeb52 100644 --- a/scripts/generate-component-docs.ts +++ b/scripts/generate-component-docs.ts @@ -1,7 +1,9 @@ -const childProcess = require('child_process'); -const fs = require('fs'); -const os = require('os'); -const path = require('path'); +import * as childProcess from 'node:child_process'; +import * as fs from 'node:fs'; +import { createRequire } from 'node:module'; +import * as os from 'node:os'; +import * as path from 'node:path'; +import { fileURLToPath } from 'node:url'; type PluginOptions = { docsRootDir: string; @@ -21,6 +23,9 @@ type PluginFactory = ( const isRecord = (value: unknown): value is { [key: string]: unknown } => typeof value === 'object' && value !== null; +const isPluginFactory = (value: unknown): value is PluginFactory => + typeof value === 'function'; + const normalizeDocs = (value: unknown, sourceDir: string): unknown => { if (Array.isArray(value)) { return value.map((item) => normalizeDocs(item, sourceDir)); @@ -74,7 +79,11 @@ const main = async () => { return; } - const rootDir = path.resolve(__dirname, '..'); + const requireFromScript = createRequire(import.meta.url); + const rootDir = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '..' + ); const tempDir = fs.mkdtempSync( path.join(os.tmpdir(), 'react-native-paper-docs-') ); @@ -118,7 +127,7 @@ const main = async () => { } const configPath = path.join(sourceDir, 'docs', 'docusaurus.config.js'); - const config = require(configPath); + const config: unknown = requireFromScript(configPath); if (!isRecord(config) || !Array.isArray(config.plugins)) { throw new Error(`Unable to read plugins from ${configPath}`); @@ -139,11 +148,19 @@ const main = async () => { ); } - const pluginFactory: PluginFactory = require(path.join( + const pluginFactoryPath = path.join( sourceDir, 'docs', 'component-docs-plugin' - )); + ); + const pluginFactory: unknown = requireFromScript(pluginFactoryPath); + + if (!isPluginFactory(pluginFactory)) { + throw new Error( + `Unable to read component docs plugin from ${pluginFactoryPath}` + ); + } + const plugin = await pluginFactory({}, pluginConfig[1]); const docs = await plugin.loadContent(); const destination = path.resolve(rootDir, outputPath); diff --git a/scripts/generate-mappings.js b/scripts/generate-mappings.js deleted file mode 100644 index 12ed00ffc2..0000000000 --- a/scripts/generate-mappings.js +++ /dev/null @@ -1,64 +0,0 @@ -const parser = require('@babel/parser'); -const types = require('babel-types'); -const fs = require('fs'); -const path = require('path'); - -const packageJson = require('../package.json'); -const root = path.resolve(__dirname, '..'); -const output = path.join(root, 'lib/mappings.json'); -const source = fs.readFileSync(path.resolve(root, 'src', 'index.tsx'), 'utf8'); -const ast = parser.parse(source, { - sourceType: 'module', - plugins: [ - 'jsx', - 'typescript', - 'objectRestSpread', - 'classProperties', - 'asyncGenerators', - ], -}); - -const index = packageJson.main; -const relative = (value /* : string */) => - path.relative(root, path.resolve(path.dirname(index), value)); - -const mappings = ast.program.body.reduce((acc, declaration, index, self) => { - if (types.isExportNamedDeclaration(declaration)) { - if (declaration.source) { - declaration.specifiers.forEach((specifier) => { - acc[specifier.exported.name] = { - path: relative(declaration.source.value), - name: specifier.local.name, - }; - }); - } else { - declaration.specifiers.forEach((specifier) => { - const name = specifier.exported.name; - - self.forEach((it) => { - if ( - types.isImportDeclaration(it) && - it.specifiers.some( - (s) => - types.isImportNamespaceSpecifier(s) && - s.local.name === specifier.local.name - ) - ) { - acc[name] = { - path: relative(it.source.value), - name: '*', - }; - } - }); - }); - } - } - - return acc; -}, {}); - -fs.existsSync(path.dirname(output)) || fs.mkdirSync(path.dirname(output)); -fs.writeFileSync( - output, - JSON.stringify({ name: packageJson.name, index, mappings }, null, 2) -); diff --git a/scripts/generate-mappings.ts b/scripts/generate-mappings.ts new file mode 100644 index 0000000000..b6a172e7c6 --- /dev/null +++ b/scripts/generate-mappings.ts @@ -0,0 +1,111 @@ +import { parse } from '@babel/parser'; +import * as types from '@babel/types'; +import type { Identifier, StringLiteral } from '@babel/types'; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { dirname, join, relative as relativePath, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +type PackageJson = { + name: string; + main: string; +}; + +type Mapping = { + path: string; + name: string; +}; + +const isRecord = (value: unknown): value is { [key: string]: unknown } => + typeof value === 'object' && value !== null; + +const readPackageJson = (path: string): PackageJson => { + const packageJson: unknown = JSON.parse(readFileSync(path, 'utf8')); + + if ( + !isRecord(packageJson) || + typeof packageJson.name !== 'string' || + typeof packageJson.main !== 'string' + ) { + throw new Error(`Unable to read package name and main from ${path}`); + } + + return { + name: packageJson.name, + main: packageJson.main, + }; +}; + +const getName = (node: Identifier | StringLiteral) => + types.isIdentifier(node) ? node.name : node.value; + +const scriptDir = dirname(fileURLToPath(import.meta.url)); +const root = resolve(scriptDir, '..'); +const packageJson = readPackageJson(resolve(root, 'package.json')); +const output = join(root, 'lib/mappings.json'); +const source = readFileSync(resolve(root, 'src', 'index.tsx'), 'utf8'); +const ast = parse(source, { + sourceType: 'module', + plugins: ['jsx', 'typescript'], +}); + +const index = packageJson.main; +const relative = (value: string) => + relativePath(root, resolve(root, dirname(index), value)); + +const mappings = ast.program.body.reduce<{ [key: string]: Mapping }>( + (acc, declaration, _index, self) => { + if (types.isExportNamedDeclaration(declaration)) { + const declarationSource = declaration.source; + + if (declarationSource) { + declaration.specifiers.forEach((specifier) => { + if (!types.isExportSpecifier(specifier)) { + return; + } + + acc[getName(specifier.exported)] = { + path: relative(declarationSource.value), + name: getName(specifier.local), + }; + }); + } else { + declaration.specifiers.forEach((specifier) => { + if (!types.isExportSpecifier(specifier)) { + return; + } + + const name = getName(specifier.exported); + const localName = getName(specifier.local); + + self.forEach((it) => { + if ( + types.isImportDeclaration(it) && + it.specifiers.some( + (s) => + types.isImportNamespaceSpecifier(s) && + s.local.name === localName + ) + ) { + acc[name] = { + path: relative(it.source.value), + name: '*', + }; + } + }); + }); + } + } + + return acc; + }, + {} +); + +if (!existsSync(dirname(output))) { + mkdirSync(dirname(output)); +} + +writeFileSync( + output, + JSON.stringify({ name: packageJson.name, index, mappings }, null, 2) +); diff --git a/scripts/generate-ts-tests.js b/scripts/generate-ts-tests.js deleted file mode 100644 index f0e5ef98be..0000000000 --- a/scripts/generate-ts-tests.js +++ /dev/null @@ -1,51 +0,0 @@ -const { readFileSync, writeFileSync, mkdirSync } = require('fs'); -const glob = require('glob'); -const path = require('path'); -const rimraf = require('rimraf'); - -const SOURCE_FILES_PATTERN = './src/**/*.js'; -const DESTINATION_DIR = './__ts-tests__'; -const EXAMPLE_REGEX = /(## Usage\n \* ```js)([\S\s]*?)(```)/g; -const JS_EXT = '.js'; -const TS_TEST_EXT = '.test.tsx'; - -const transformContent = (content) => - content - .replace("'react-native-paper'", "'..'") - .split('\n') - .map((e) => e.slice(3)) - .join('\n'); - -const getFiles = () => - glob - .sync(SOURCE_FILES_PATTERN) - .map((filePath) => { - const content = readFileSync(filePath, 'utf-8'); - const match = EXAMPLE_REGEX.exec(content); - // JS regexp is stateful, you need to reset lastIndex each time - EXAMPLE_REGEX.lastIndex = 0; - return match - ? { - path: filePath, - content: transformContent(match[2]), - } - : null; - }) - .filter(Boolean); - -const writeFiles = (files) => { - mkdirSync(DESTINATION_DIR); - - files.forEach((f) => - writeFileSync( - path.join( - DESTINATION_DIR, - `${path.basename(f.path, JS_EXT)}${TS_TEST_EXT}` - ), - f.content - ) - ); -}; - -rimraf.sync(DESTINATION_DIR); -writeFiles(getFiles()); diff --git a/scripts/generate-ts-tests.ts b/scripts/generate-ts-tests.ts new file mode 100644 index 0000000000..2223cc7386 --- /dev/null +++ b/scripts/generate-ts-tests.ts @@ -0,0 +1,67 @@ +import { + mkdirSync, + readdirSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { basename, join } from 'node:path'; + +type SourceFile = { + path: string; + content: string; +}; + +const SOURCE_DIR = './src'; +const DESTINATION_DIR = './__ts-tests__'; +const EXAMPLE_REGEX = /(## Usage\n \* ```js)([\S\s]*?)(```)/g; +const JS_EXT = '.js'; +const TS_TEST_EXT = '.test.tsx'; + +const transformContent = (content: string) => + content + .replace("'react-native-paper'", "'..'") + .split('\n') + .map((e) => e.slice(3)) + .join('\n'); + +const getSourceFiles = (directory: string): string[] => + readdirSync(directory, { withFileTypes: true }).flatMap((entry) => { + const filePath = join(directory, entry.name); + + if (entry.isDirectory()) { + return getSourceFiles(filePath); + } + + return entry.isFile() && filePath.endsWith(JS_EXT) ? [filePath] : []; + }); + +const getFiles = () => + getSourceFiles(SOURCE_DIR) + .map((filePath) => { + const content = readFileSync(filePath, 'utf-8'); + const match = EXAMPLE_REGEX.exec(content); + // JS regexp is stateful, you need to reset lastIndex each time + EXAMPLE_REGEX.lastIndex = 0; + return match + ? { + path: filePath, + content: transformContent(match[2]), + } + : null; + }) + .filter((file): file is SourceFile => file !== null); + +const writeFiles = (files: SourceFile[]) => { + mkdirSync(DESTINATION_DIR); + + files.forEach((f) => + writeFileSync( + join(DESTINATION_DIR, `${basename(f.path, JS_EXT)}${TS_TEST_EXT}`), + f.content + ) + ); +}; + +rmSync(DESTINATION_DIR, { recursive: true, force: true }); +writeFiles(getFiles()); diff --git a/scripts/package.json b/scripts/package.json new file mode 100644 index 0000000000..3dbc1ca591 --- /dev/null +++ b/scripts/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/scripts/typescript-output-lint.js b/scripts/typescript-output-lint.ts similarity index 86% rename from scripts/typescript-output-lint.js rename to scripts/typescript-output-lint.ts index 16eacdf249..3781890211 100644 --- a/scripts/typescript-output-lint.js +++ b/scripts/typescript-output-lint.ts @@ -1,8 +1,9 @@ -const { promises: fs } = require('fs'); -const path = require('path'); +import { promises as fs } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; -const root = path.resolve(__dirname, '..'); -const output = path.join(root, 'lib', 'typescript'); +const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); +const output = join(root, 'lib', 'typescript'); /** * List of React Native props not used by React Native Paper. @@ -76,10 +77,10 @@ const unusedViewProps = [ 'unstable_pressDelay', ]; -async function* getFiles(directory) { +async function* getFiles(directory: string): AsyncGenerator { const entries = await fs.readdir(directory, { withFileTypes: true }); for (const entry of entries) { - const res = path.resolve(directory, entry.name); + const res = resolve(directory, entry.name); if (entry.isDirectory()) { yield* getFiles(res); } else { @@ -94,7 +95,7 @@ async function main() { for (const prop of unusedViewProps) { if (content.includes(prop)) { throw new Error( - `Found text '${prop}' in '${file}'. Please use the wrapped 'forwardRef' in 'src/utils/forwardRef.ts', export some return types, or modify 'scripts/typescript-output-lint.js'` + `Found text '${prop}' in '${file}'. Please use the wrapped 'forwardRef' in 'src/utils/forwardRef.ts', export some return types, or modify 'scripts/typescript-output-lint.ts'` ); } } diff --git a/src/babel/.eslintrc b/src/babel/.eslintrc deleted file mode 100644 index 1aad9bfc83..0000000000 --- a/src/babel/.eslintrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "rules": { - "no-unused-vars": "off", - "import/no-duplicates": "off", - "import/no-unresolved": "off", - } -} diff --git a/src/babel/__tests__/index.js b/src/babel/__tests__/index.js index 113788881f..159e2a5f71 100644 --- a/src/babel/__tests__/index.js +++ b/src/babel/__tests__/index.js @@ -1,3 +1,4 @@ +const { expect } = require('@jest/globals'); const { create } = require('babel-test'); const { spawnSync } = require('child_process'); const { toMatchFile } = require('jest-file-snapshot'); @@ -6,7 +7,7 @@ const path = require('path'); expect.extend({ toMatchFile }); spawnSync('node', [ - path.resolve(__dirname, '../../../scripts/generate-mappings.js'), + path.resolve(__dirname, '../../../scripts/generate-mappings.ts'), ]); const { fixtures } = create({ diff --git a/src/babel/index.js b/src/babel/index.js index f93f07e01e..2fc478bacb 100644 --- a/src/babel/index.js +++ b/src/babel/index.js @@ -3,8 +3,9 @@ const SKIP = Symbol('SKIP'); module.exports = function rewire(babel, options) { const t = babel.types; - const { name, index, mappings } = require(options.mappings || - '../../mappings.json'); + const { name, index, mappings } = require( + options.mappings || '../../mappings.json' + ); return { visitor: { diff --git a/src/components/ActivityIndicator.tsx b/src/components/ActivityIndicator.tsx index 9436979208..8faa54de58 100644 --- a/src/components/ActivityIndicator.tsx +++ b/src/components/ActivityIndicator.tsx @@ -130,8 +130,8 @@ const ActivityIndicator = ({ ? 24 : 48 : indicatorSize - ? indicatorSize - : 24; + ? indicatorSize + : 24; const frames = (60 * DURATION) / 1000; const easing = Easing.bezier(0.4, 0.0, 0.7, 1.0); diff --git a/src/components/Appbar/AppbarAction.tsx b/src/components/Appbar/AppbarAction.tsx index 0826372c8f..5d63fd642c 100644 --- a/src/components/Appbar/AppbarAction.tsx +++ b/src/components/Appbar/AppbarAction.tsx @@ -91,8 +91,8 @@ const AppbarAction = ({ const actionIconColor = iconColor ? iconColor : isLeading - ? colors.onSurface - : colors.onSurfaceVariant; + ? colors.onSurface + : colors.onSurfaceVariant; return ( {actions.map(({ label, ...others }, i) => ( ).toJSON(); +it('renders text button by default', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders text button with mode', () => { - const tree = render().toJSON(); +it('renders text button with mode', async () => { + const tree = ( + await render() + ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders outlined button with mode', () => { - const tree = render( - +it('renders outlined button with mode', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders contained contained with mode', () => { - const tree = render( - +it('renders contained contained with mode', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders button with icon', () => { - const tree = render().toJSON(); +it('renders button with icon', async () => { + const tree = ( + await render() + ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders button with icon in reverse order', () => { - const tree = render( - +it('renders button with icon in reverse order', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders loading button', () => { - const tree = render().toJSON(); +it('renders loading button', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders disabled button', () => { - const tree = render().toJSON(); +it('renders disabled button', async () => { + const tree = ( + await render() + ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders disabled button if there is no touch handler passed', () => { - const { getByTestId } = render( - - ); +it('renders disabled button if there is no touch handler passed', async () => { + await render(); - expect(getByTestId('disabled-button').props.accessibilityState).toMatchObject( - { - disabled: true, - } - ); + expect(screen.getByTestId('disabled-button')).toBeDisabled(); }); -it('renders active button if only onLongPress handler is passed', () => { - const { getByTestId } = render( +it('renders active button if only onLongPress handler is passed', async () => { + await render( ); - expect(getByTestId('active-button').props.accessibilityState).toMatchObject({ - disabled: false, - }); + expect(screen.getByTestId('active-button')).toBeEnabled(); }); -it('renders button with color', () => { - const tree = render( - +it('renders button with color', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders button with button color', () => { - const tree = render( - +it('renders button with button color', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders button with custom testID', () => { - const tree = render( - +it('renders button with custom testID', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders button with an accessibility label', () => { - const tree = render( - +it('renders button with an accessibility label', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders button with an accessibility hint', () => { - const tree = render( - +it('renders button with an accessibility hint', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders button with custom border radius', () => { - const { getByTestId } = render( +it('renders button with custom border radius', async () => { + await render( ); - expect(getByTestId('custom-radius-container')).toHaveStyle( + expect(screen.getByTestId('custom-radius-container')).toHaveStyle( styles.customRadius ); - expect(getByTestId('custom-radius')).toHaveStyle(styles.customRadius); + expect(screen.getByTestId('custom-radius')).toHaveStyle(styles.customRadius); }); -it('renders outlined button with custom border radius', () => { - const { getByTestId } = render( +it('renders outlined button with custom border radius', async () => { + await render( ); - expect(getByTestId('custom-radius-container')).toHaveStyle( + expect(screen.getByTestId('custom-radius-container')).toHaveStyle( styles.customRadius ); - expect(getByTestId('custom-radius')).toHaveStyle({ + expect(screen.getByTestId('custom-radius')).toHaveStyle({ borderTopLeftRadius: 15, // styles.customRadius - 1px outline borderTopRightRadius: 0, borderBottomLeftRadius: 0, @@ -184,77 +190,79 @@ it('renders outlined button with custom border radius', () => { }); }); -it('renders button without border radius', () => { - const { getByTestId } = render( +it('renders button without border radius', async () => { + await render( ); - expect(getByTestId('custom-radius-container')).toHaveStyle(styles.noRadius); - expect(getByTestId('custom-radius')).toHaveStyle(styles.noRadius); + expect(screen.getByTestId('custom-radius-container')).toHaveStyle( + styles.noRadius + ); + expect(screen.getByTestId('custom-radius')).toHaveStyle(styles.noRadius); }); -it('should execute onPressIn', () => { +it('should execute onPressIn', async () => { const onPressInMock = jest.fn(); const onPress = jest.fn(); - const { getByTestId } = render( + await render( ); - fireEvent(getByTestId('button'), 'onPressIn'); + await userEvent.press(screen.getByTestId('button')); expect(onPressInMock).toHaveBeenCalledTimes(1); }); -it('should execute onPressOut', () => { +it('should execute onPressOut', async () => { const onPressOutMock = jest.fn(); const onPress = jest.fn(); - const { getByTestId } = render( + await render( ); - fireEvent(getByTestId('button'), 'onPressOut'); + await userEvent.press(screen.getByTestId('button')); expect(onPressOutMock).toHaveBeenCalledTimes(1); }); describe('button text styles', () => { - it('applies uppercase styles if uppercase prop is truthy', () => { - const { getByTestId } = render( + it('applies uppercase styles if uppercase prop is truthy', async () => { + await render( ); - expect(getByTestId('button-text')).toHaveStyle({ + expect(screen.getByTestId('button-text')).toHaveStyle({ textTransform: 'uppercase', }); }); - it('does not apply uppercase styles if uppercase prop is falsy', () => { - const { getByTestId } = render( + it('does not apply uppercase styles if uppercase prop is falsy', async () => { + await render( ); - expect(getByTestId('button-text')).not.toHaveStyle({ + expect(screen.getByTestId('button-text')).not.toHaveStyle({ textTransform: 'uppercase', }); }); }); describe('button icon styles', () => { - it('should return correct icon styles for compact text button', () => { - const { getByTestId } = render( + it('should return correct icon styles for compact text button', async () => { + await render( ); - expect(getByTestId('compact-button-icon-container')).toHaveStyle({ + expect(screen.getByTestId('compact-button-icon-container')).toHaveStyle({ marginLeft: 6, marginRight: 0, }); @@ -262,26 +270,28 @@ describe('button icon styles', () => { (['outlined', 'contained', 'contained-tonal', 'elevated'] as const).forEach( (mode) => - it(`should return correct icon styles for compact ${mode} button`, () => { - const { getByTestId } = render( + it(`should return correct icon styles for compact ${mode} button`, async () => { + await render( ); - expect(getByTestId('compact-button-icon-container')).toHaveStyle({ - marginLeft: 8, - marginRight: 0, - }); + expect(screen.getByTestId('compact-button-icon-container')).toHaveStyle( + { + marginLeft: 8, + marginRight: 0, + } + ); }) ); - it('should return correct icon styles for text button', () => { - const { getByTestId } = render( + it('should return correct icon styles for text button', async () => { + await render( ); - expect(getByTestId('compact-button-icon-container')).toHaveStyle({ + expect(screen.getByTestId('compact-button-icon-container')).toHaveStyle({ marginLeft: 12, marginRight: -8, }); @@ -289,16 +299,18 @@ describe('button icon styles', () => { (['outlined', 'contained', 'contained-tonal', 'elevated'] as const).forEach( (mode) => - it(`should return correct icon styles for compact ${mode} button`, () => { - const { getByTestId } = render( + it(`should return correct icon styles for compact ${mode} button`, async () => { + await render( ); - expect(getByTestId('compact-button-icon-container')).toHaveStyle({ - marginLeft: 16, - marginRight: -16, - }); + expect(screen.getByTestId('compact-button-icon-container')).toHaveStyle( + { + marginLeft: 16, + marginRight: -16, + } + ); }) ); }); @@ -698,9 +710,9 @@ describe('getButtonColors - border width', () => { ); }); -it('animated value changes correctly', () => { +it('animated value changes correctly', async () => { const value = new Animated.Value(1); - const { getByTestId } = render( + await render( ); - expect(getByTestId('button-container-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('button-container-outer-layer')).toHaveStyle({ transform: [{ scale: 1 }], }); @@ -720,10 +732,10 @@ it('animated value changes correctly', () => { duration: 200, }).start(); - act(() => { + await act(() => { jest.advanceTimersByTime(200); }); - expect(getByTestId('button-container-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('button-container-outer-layer')).toHaveStyle({ transform: [{ scale: 1.5 }], }); }); diff --git a/src/components/__tests__/Card/Card.test.tsx b/src/components/__tests__/Card/Card.test.tsx index 267cb65abb..61659c8a24 100644 --- a/src/components/__tests__/Card/Card.test.tsx +++ b/src/components/__tests__/Card/Card.test.tsx @@ -4,7 +4,7 @@ import { describe, expect, it, jest } from '@jest/globals'; import { act } from '@testing-library/react-native'; import { getTheme } from '../../../core/theming'; -import { render } from '../../../test-utils'; +import { render, screen } from '../../../test-utils'; import { Palette } from '../../../theme/tokens'; import Button from '../../Button/Button'; import Card from '../../Card/Card'; @@ -26,14 +26,14 @@ const styles = StyleSheet.create({ }); describe('Card', () => { - it('renders an outlined card', () => { - const tree = render({null}).toJSON(); + it('renders an outlined card', async () => { + const tree = (await render({null})).toJSON(); expect(tree).toMatchSnapshot(); }); - it('renders an outlined card with custom border radius and color', () => { - const { getByTestId } = render( + it('renders an outlined card with custom border radius and color', async () => { + await render( { ); - expect(getByTestId('card-outline')).toHaveStyle({ + expect(screen.getByTestId('card-outline')).toHaveStyle({ borderRadius: 32, borderColor: 'purple', }); }); - it('renders an outlined card with custom border color', () => { - const { getByLabelText } = render( + it('renders an outlined card with custom border color', async () => { + await render( { ); - expect(getByLabelText('card')).toHaveStyle({ + expect(screen.getByLabelText('card')).toHaveStyle({ borderColor: Palette.error50, }); }); - it('renders with a custom theme', () => { - const { getByLabelText } = render( + it('renders with a custom theme', async () => { + await render( { ); - expect(getByLabelText('card')).toHaveStyle({ + expect(screen.getByLabelText('card')).toHaveStyle({ backgroundColor: '#0000FF', }); }); - it('renders with a content style', () => { - const { getByTestId } = render( + it('renders with a content style', async () => { + await render( Content ); - expect(getByTestId('card')).toHaveStyle(styles.contentStyle); + expect(screen.getByTestId('card')).toHaveStyle(styles.contentStyle); }); - it('does not render a disabled accessibility state', () => { - const { getByTestId } = render({null}); + it('does not render a disabled accessibility state', async () => { + await render({null}); - expect( - getByTestId('card').props.accessibilityState || {} - ).not.toMatchObject({ - disabled: true, - }); + expect(screen.getByTestId('card')).toBeEnabled(); }); - it('does render a disabled accessibility state', () => { - const { getByA11yState } = render( + it('does render a disabled accessibility state', async () => { + await render( {}} disabled> {null} ); - expect(getByA11yState({ disabled: true })).toBeOnTheScreen(); + expect(screen.getByTestId('card')).toBeDisabled(); }); }); describe('CardCover', () => { - it('renders with custom border radius', () => { - const { getByTestId } = render( + it('renders with custom border radius', async () => { + await render( { ); - expect(getByTestId('card-cover')).toHaveStyle(styles.customCoverRadius); + expect(screen.getByTestId('card-cover')).toHaveStyle( + styles.customCoverRadius + ); }); }); describe('CardActions', () => { - it('renders button with passed mode', () => { - const { getByTestId } = render( + it('renders button with passed mode', async () => { + await render( @@ -137,13 +135,14 @@ describe('CardActions', () => { ); - expect(getByTestId('card-actions').props.children[0].props.mode).toBe( - 'contained' - ); + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('card-actions').props.children[0].props.mode + ).toBe('contained'); }); - it('renders button with custom styles', () => { - const { getByTestId } = render( + it('renders button with custom styles', async () => { + await render( ); - expect(getByTestId('button-cancel')).toBeDefined(); - expect(getByTestId('button-ok')).toBeDefined(); + expect(screen.getByTestId('button-cancel')).toBeOnTheScreen(); + expect(screen.getByTestId('button-ok')).toBeOnTheScreen(); }); - it('should apply default styles', () => { - const { getByTestId } = render( + it('should apply default styles', async () => { + await render( ); - const dialogActionsContainer = getByTestId('dialog-actions'); + const dialogActionsContainer = screen.getByTestId('dialog-actions'); const dialogActionButtons = dialogActionsContainer.children; expect(dialogActionsContainer).toHaveStyle({ @@ -138,15 +140,15 @@ describe('DialogActions', () => { expect(dialogActionButtons[1]).toHaveStyle({ marginRight: 0 }); }); - it('should apply custom styles', () => { - const { getByTestId } = render( + it('should apply custom styles', async () => { + await render( ); - const dialogActionsContainer = getByTestId('dialog-actions'); + const dialogActionsContainer = screen.getByTestId('dialog-actions'); const dialogActionButtons = dialogActionsContainer.children; expect(dialogActionButtons[0]).toHaveStyle({ margin: 10 }); diff --git a/src/components/__tests__/Drawer/DrawerCollapsedItem.test.tsx b/src/components/__tests__/Drawer/DrawerCollapsedItem.test.tsx index 9538fcc56e..3df20be862 100644 --- a/src/components/__tests__/Drawer/DrawerCollapsedItem.test.tsx +++ b/src/components/__tests__/Drawer/DrawerCollapsedItem.test.tsx @@ -1,11 +1,11 @@ import { describe, expect, it } from '@jest/globals'; -import { render } from '../../../test-utils'; +import { render, screen } from '../../../test-utils'; import DrawerCollapsedItem from '../../Drawer/DrawerCollapsedItem'; describe('DrawerCollapsedItem', () => { - it('should have regular outline if label is specified', () => { - const { getByTestId } = render( + it('should have regular outline if label is specified', async () => { + await render( { /> ); - expect(getByTestId('drawer-collapsed-item-outline')).toHaveStyle({ + expect(screen.getByTestId('drawer-collapsed-item-outline')).toHaveStyle({ height: 32, }); }); - it('should have rounded outline if label is not specified', () => { - const { getByTestId } = render( + it('should have rounded outline if label is not specified', async () => { + await render( ); - expect(getByTestId('drawer-collapsed-item-outline')).toHaveStyle({ + expect(screen.getByTestId('drawer-collapsed-item-outline')).toHaveStyle({ height: 56, }); }); - it('should display unfocused icon in inactive state, if unfocused icon is specified', () => { - const { getByTestId } = render( + it('should display unfocused icon in inactive state, if unfocused icon is specified', async () => { + await render( ); expect( - getByTestId('drawer-collapsed-item-container').props.children[1].props - .source + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('drawer-collapsed-item-container').props.children[1] + .props.source ).toBe('star-outline'); }); - it('should display focused icon in inactive state, if unfocused icon is not specified', () => { - const { getByTestId } = render(); + it('should display focused icon in inactive state, if unfocused icon is not specified', async () => { + await render(); expect( - getByTestId('drawer-collapsed-item-container').props.children[1].props - .source + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('drawer-collapsed-item-container').props.children[1] + .props.source ).toBe('star'); }); - it('should display focused icon in active state', () => { - const { getByTestId } = render( + it('should display focused icon in active state', async () => { + await render( { ); expect( - getByTestId('drawer-collapsed-item-container').props.children[1].props - .source + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('drawer-collapsed-item-container').props.children[1] + .props.source ).toBe('star'); }); }); diff --git a/src/components/__tests__/Drawer/DrawerSection.test.tsx b/src/components/__tests__/Drawer/DrawerSection.test.tsx index 08283ba7a2..9b19f0ef25 100644 --- a/src/components/__tests__/Drawer/DrawerSection.test.tsx +++ b/src/components/__tests__/Drawer/DrawerSection.test.tsx @@ -6,11 +6,13 @@ import { render } from '../../../test-utils'; import DrawerSection from '../../Drawer/DrawerSection'; describe('DrawerSection', () => { - it('renders properly', () => { - const tree = render( - - - + it('renders properly', async () => { + const tree = ( + await render( + + + + ) ).toJSON(); expect(tree).toMatchSnapshot(); diff --git a/src/components/__tests__/DrawerItem.test.tsx b/src/components/__tests__/DrawerItem.test.tsx index 375d1c460b..a47bbc043b 100644 --- a/src/components/__tests__/DrawerItem.test.tsx +++ b/src/components/__tests__/DrawerItem.test.tsx @@ -3,25 +3,25 @@ import { expect, it } from '@jest/globals'; import { render } from '../../test-utils'; import DrawerItem from '../Drawer/DrawerItem'; -it('renders basic DrawerItem', () => { - const tree = render( - {}} label="Example item" /> +it('renders basic DrawerItem', async () => { + const tree = ( + await render( {}} label="Example item" />) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders DrawerItem with icon', () => { - const tree = render( - +it('renders DrawerItem with icon', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders active DrawerItem', () => { - const tree = render( - +it('renders active DrawerItem', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); diff --git a/src/components/__tests__/FAB.test.tsx b/src/components/__tests__/FAB.test.tsx index 38ee6308b6..2e233eaa63 100644 --- a/src/components/__tests__/FAB.test.tsx +++ b/src/components/__tests__/FAB.test.tsx @@ -1,94 +1,100 @@ import { expect, it, jest } from '@jest/globals'; -import { fireEvent } from '@testing-library/react-native'; +import { fireEvent, userEvent } from '@testing-library/react-native'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import FAB from '../FAB'; -it('renders FAB with default props', () => { - const tree = render().toJSON(); +it('renders FAB with default props', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB with primary variant', () => { - const tree = render().toJSON(); +it('renders FAB with primary variant', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB with secondary variant', () => { - const tree = render().toJSON(); +it('renders FAB with secondary variant', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB with tertiary variant', () => { - const tree = render().toJSON(); +it('renders FAB with tertiary variant', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB with tonalSecondary variant', () => { - const tree = render().toJSON(); +it('renders FAB with tonalSecondary variant', async () => { + const tree = ( + await render() + ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB with tonalTertiary variant', () => { - const tree = render().toJSON(); +it('renders FAB with tonalTertiary variant', async () => { + const tree = ( + await render() + ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB medium size', () => { - const tree = render().toJSON(); +it('renders FAB medium size', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB large size', () => { - const tree = render().toJSON(); +it('renders FAB large size', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB with containerColor override', () => { - const tree = render().toJSON(); +it('renders FAB with containerColor override', async () => { + const tree = ( + await render() + ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB with containerColor and contentColor overrides', () => { - const tree = render( - +it('renders FAB with containerColor and contentColor overrides', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB with accessibilityLabel', () => { - const tree = render( - +it('renders FAB with accessibilityLabel', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB transitioning to not visible', () => { - const { update, toJSON } = render(); - update(); +it('renders FAB transitioning to not visible', async () => { + const { rerender, toJSON } = await render(); + await rerender(); expect(toJSON()).toMatchSnapshot(); }); -it('renders FAB transitioning to visible', () => { - const { update, toJSON } = render(); - update(); +it('renders FAB transitioning to visible', async () => { + const { rerender, toJSON } = await render( + + ); + await rerender(); expect(toJSON()).toMatchSnapshot(); }); -it('calls onPress when FAB is pressed', () => { +it('calls onPress when FAB is pressed', async () => { const onPress = jest.fn(); - const { getByTestId } = render( - - ); - fireEvent.press(getByTestId('fab')); + await render(); + await userEvent.press(screen.getByTestId('fab')); expect(onPress).toHaveBeenCalledTimes(1); }); -it('forwards event object to onPress', () => { +it('forwards event object to onPress', async () => { const onPress = jest.fn(); - const { getByTestId } = render( - - ); - fireEvent(getByTestId('fab'), 'onPress', { key: 'value' }); + await render(); + await fireEvent(screen.getByTestId('fab'), 'onPress', { key: 'value' }); expect(onPress).toHaveBeenCalledWith({ key: 'value' }); }); diff --git a/src/components/__tests__/FABExtended.test.tsx b/src/components/__tests__/FABExtended.test.tsx index e3c1490f65..2d24e0a038 100644 --- a/src/components/__tests__/FABExtended.test.tsx +++ b/src/components/__tests__/FABExtended.test.tsx @@ -1,54 +1,64 @@ import { expect, it, jest } from '@jest/globals'; -import { fireEvent } from '@testing-library/react-native'; +import { fireEvent, userEvent } from '@testing-library/react-native'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import FAB from '../FAB'; -it('renders extended FAB expanded', () => { - const tree = render( - +it('renders extended FAB expanded', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders extended FAB collapsed', () => { - const tree = render( - +it('renders extended FAB collapsed', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders extended FAB not visible', () => { - const tree = render( - +it('renders extended FAB not visible', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders extended FAB medium size', () => { - const tree = render( - +it('renders extended FAB medium size', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders extended FAB large size', () => { - const tree = render( - +it('renders extended FAB large size', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders extended FAB transitioning to collapsed', () => { - const { update, toJSON } = render( +it('renders extended FAB transitioning to collapsed', async () => { + const { rerender, toJSON } = await render( ); - update(); + await rerender( + + ); expect(toJSON()).toMatchSnapshot(); }); -it('uses label as default accessibilityLabel', () => { - const { getByTestId } = render( +it('uses label as default accessibilityLabel', async () => { + await render( { testID="extended-fab" /> ); - expect(getByTestId('extended-fab').props.accessibilityLabel).toBe( - 'New message' - ); + + expect(screen.getByLabelText('New message')).toBeOnTheScreen(); }); -it('respects explicit accessibilityLabel', () => { - const { getByTestId } = render( +it('respects explicit accessibilityLabel', async () => { + await render( { testID="extended-fab" /> ); - expect(getByTestId('extended-fab').props.accessibilityLabel).toBe( - 'Create new message' - ); + + expect(screen.getByLabelText('Create new message')).toBeOnTheScreen(); }); -it('calls onPress when pressed', () => { +it('calls onPress when pressed', async () => { const onPress = jest.fn(); - const { getByTestId } = render( + await render( { testID="extended-fab" /> ); - fireEvent.press(getByTestId('extended-fab')); + await userEvent.press(screen.getByTestId('extended-fab')); expect(onPress).toHaveBeenCalledTimes(1); }); -it('forwards event object to onPress', () => { +it('forwards event object to onPress', async () => { const onPress = jest.fn(); - const { getByTestId } = render( + await render( { testID="extended-fab" /> ); - fireEvent(getByTestId('extended-fab'), 'onPress', { key: 'value' }); + await fireEvent(screen.getByTestId('extended-fab'), 'onPress', { + key: 'value', + }); expect(onPress).toHaveBeenCalledWith({ key: 'value' }); }); diff --git a/src/components/__tests__/FABMenu.test.tsx b/src/components/__tests__/FABMenu.test.tsx index 87b3b38f2f..50135634d7 100644 --- a/src/components/__tests__/FABMenu.test.tsx +++ b/src/components/__tests__/FABMenu.test.tsx @@ -1,119 +1,131 @@ import { expect, it, jest } from '@jest/globals'; -import { fireEvent } from '@testing-library/react-native'; +import { fireEvent, userEvent } from '@testing-library/react-native'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import FAB from '../FAB'; +import type { MenuItemProps } from '../FAB/Menu'; const makeItems = ( onItemPress = jest.fn<(event?: unknown) => void>() -): [ - { label: string; onPress: typeof onItemPress; testID: string }, - { label: string; onPress: typeof onItemPress; testID: string } -] => [ +): [MenuItemProps, MenuItemProps] => [ { label: 'Send email', onPress: onItemPress, testID: 'item-0' }, { label: 'Set reminder', onPress: onItemPress, testID: 'item-1' }, ]; -it('renders FAB.Menu closed', () => { - const tree = render( - +it('renders FAB.Menu closed', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB.Menu open', () => { - const tree = render( - +it('renders FAB.Menu open', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB.Menu with 6 items', () => { - const tree = render( - +it('renders FAB.Menu with 6 items', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB.Menu with start alignment', () => { - const tree = render( - +it('renders FAB.Menu with start alignment', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB.Menu with center alignment', () => { - const tree = render( - +it('renders FAB.Menu with center alignment', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB.Menu with items having icons', () => { - const tree = render( - +it('renders FAB.Menu with items having icons', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders FAB.Menu not expanded when trigger is not visible', () => { - const tree = render( - +it('renders FAB.Menu not expanded when trigger is not visible', async () => { + const tree = ( + await render( + + ) ).toJSON(); // effectiveExpanded = visible && expanded = false expect(tree).toMatchSnapshot(); }); -it('calls item onPress when menu item is pressed', () => { +it('calls item onPress when menu item is pressed', async () => { const onItemPress = jest.fn(); - const { getByTestId } = render( + await render( { items={makeItems(onItemPress)} /> ); - fireEvent.press(getByTestId('item-0')); + await userEvent.press(screen.getByTestId('item-0')); expect(onItemPress).toHaveBeenCalledTimes(1); }); -it('forwards event object to item onPress', () => { +it('forwards event object to item onPress', async () => { const onItemPress = jest.fn(); - const { getByTestId } = render( + await render( { items={makeItems(onItemPress)} /> ); - fireEvent(getByTestId('item-0'), 'onPress', { key: 'value' }); + await fireEvent(screen.getByTestId('item-0'), 'onPress', { key: 'value' }); expect(onItemPress).toHaveBeenCalledWith({ key: 'value' }); }); -it('calls onDismiss when menu item is pressed', () => { +it('calls onDismiss when menu item is pressed', async () => { const onDismiss = jest.fn(); - const { getByTestId } = render( + await render( { items={makeItems()} /> ); - fireEvent.press(getByTestId('item-0')); + await userEvent.press(screen.getByTestId('item-0')); expect(onDismiss).toHaveBeenCalledTimes(1); }); -it('calls trigger onPress when menu is closed', () => { +it('calls trigger onPress when menu is closed', async () => { const onTriggerPress = jest.fn(); - const { getByTestId } = render( + await render( { /> ); // Shell's TouchableRipple uses the default testID 'fab-shell' - fireEvent.press(getByTestId('fab-shell')); + await userEvent.press(screen.getByTestId('fab-shell')); expect(onTriggerPress).toHaveBeenCalledTimes(1); }); -it('calls onDismiss when trigger is pressed while menu is open', () => { +it('calls onDismiss when trigger is pressed while menu is open', async () => { const onDismiss = jest.fn(); - const { getByTestId } = render( + await render( { items={makeItems()} /> ); - fireEvent.press(getByTestId('fab-shell')); + await userEvent.press(screen.getByTestId('fab-shell')); expect(onDismiss).toHaveBeenCalledTimes(1); }); diff --git a/src/components/__tests__/Icon.test.tsx b/src/components/__tests__/Icon.test.tsx index 940637e1a3..d1d280a63f 100644 --- a/src/components/__tests__/Icon.test.tsx +++ b/src/components/__tests__/Icon.test.tsx @@ -2,35 +2,37 @@ import { Image } from 'react-native'; import { describe, expect, it } from '@jest/globals'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import Icon from '../Icon'; const ICON_SIZE = 24; describe('Icon Component', () => { - it('renders correctly with image source', () => { + it('renders correctly with image source', async () => { const source = { uri: 'https://picsum.photos/700' }; - const { getByTestId } = render( - - ); - const imageIcon = getByTestId('image-icon'); + await render(); + const imageIcon = screen.getByTestId('image-icon', { + includeHiddenElements: true, + }); expect(imageIcon).toBeOnTheScreen(); expect(imageIcon).toHaveStyle({ width: ICON_SIZE, height: ICON_SIZE }); }); - it('renders correctly with string source', () => { + it('renders correctly with string source', async () => { const source = 'camera'; - const { getByTestId } = render( + await render( ); - const icon = getByTestId('camera-icon'); + const icon = screen.getByTestId('camera-icon', { + includeHiddenElements: true, + }); expect(icon).toBeOnTheScreen(); expect(icon).toHaveStyle({ fontSize: ICON_SIZE, lineHeight: ICON_SIZE }); }); - it('renders correctly with function source', () => { + it('renders correctly with function source', async () => { const source = ({ size, testID }: { size: number; testID: string }) => ( { testID={testID} /> ); - const { getByTestId } = render( + await render( ); - const functionIcon = getByTestId('function-icon'); + const functionIcon = screen.getByTestId('function-icon', { + includeHiddenElements: true, + }); expect(functionIcon).toHaveStyle({ width: ICON_SIZE, height: ICON_SIZE }); expect(functionIcon).toBeOnTheScreen(); diff --git a/src/components/__tests__/IconButton.test.tsx b/src/components/__tests__/IconButton.test.tsx index e61594509e..b28456c5ce 100644 --- a/src/components/__tests__/IconButton.test.tsx +++ b/src/components/__tests__/IconButton.test.tsx @@ -4,7 +4,7 @@ import { describe, expect, it, jest } from '@jest/globals'; import { act } from '@testing-library/react-native'; import { getTheme } from '../../core/theming'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import { pink500 } from '../../theme/colors'; import { tokens } from '../../theme/tokens'; import IconButton from '../IconButton/IconButton'; @@ -21,40 +21,40 @@ const styles = StyleSheet.create({ }, }); -it('renders icon button by default', () => { - const tree = render().toJSON(); +it('renders icon button by default', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders icon button with color', () => { - const tree = render( - +it('renders icon button with color', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders icon button with size', () => { - const tree = render().toJSON(); +it('renders icon button with size', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders disabled icon button', () => { - const tree = render().toJSON(); +it('renders disabled icon button', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders icon change animated', () => { - const tree = render().toJSON(); +it('renders icon change animated', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders icon button with custom border radius', () => { - const { getByTestId } = render( +it('renders icon button with custom border radius', async () => { + await render( { /> ); - expect(getByTestId('icon-button-container')).toHaveStyle({ borderRadius: 0 }); + expect(screen.getByTestId('icon-button-container')).toHaveStyle({ + borderRadius: 0, + }); }); -it('renders icon button with small border radius', () => { - const { getByTestId } = render( +it('renders icon button with small border radius', async () => { + await render( { /> ); - expect(getByTestId('icon-button-container')).toHaveStyle({ borderRadius: 4 }); + expect(screen.getByTestId('icon-button-container')).toHaveStyle({ + borderRadius: 4, + }); }); describe('getIconButtonColor - icon color', () => { @@ -315,16 +319,16 @@ describe('getIconButtonColor - border color', () => { }); }); -it('action animated value changes correctly', () => { +it('action animated value changes correctly', async () => { const value = new Animated.Value(1); - const { getByTestId } = render( + await render( ); - expect(getByTestId('icon-button-container-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('icon-button-container-outer-layer')).toHaveStyle({ transform: [{ scale: 1 }], }); @@ -334,10 +338,10 @@ it('action animated value changes correctly', () => { duration: 200, }).start(); - act(() => { + await act(() => { jest.advanceTimersByTime(200); }); - expect(getByTestId('icon-button-container-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('icon-button-container-outer-layer')).toHaveStyle({ transform: [{ scale: 1.5 }], }); }); diff --git a/src/components/__tests__/ListAccordion.test.tsx b/src/components/__tests__/ListAccordion.test.tsx index b1e4ac79d2..ad1783ec52 100644 --- a/src/components/__tests__/ListAccordion.test.tsx +++ b/src/components/__tests__/ListAccordion.test.tsx @@ -17,75 +17,85 @@ const styles = StyleSheet.create({ }, }); -it('renders list accordion with children', () => { - const tree = render( - } - title="Expandable list item" - > - - +it('renders list accordion with children', async () => { + const tree = ( + await render( + } + title="Expandable list item" + > + + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders multiline list accordion', () => { - const tree = render( - - - +it('renders multiline list accordion', async () => { + const tree = ( + await render( + + + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders list accordion with left items', () => { - const tree = render( - } - title="Accordion item 1" - > - } - title="List item 1" - /> - +it('renders list accordion with left items', async () => { + const tree = ( + await render( + } + title="Accordion item 1" + > + } + title="List item 1" + /> + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders expanded accordion', () => { - const tree = render( - - - +it('renders expanded accordion', async () => { + const tree = ( + await render( + + + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders list accordion with custom title and description styles', () => { - const tree = render( - - - +it('renders list accordion with custom title and description styles', async () => { + const tree = ( + await render( + + + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); describe('ListAccordion', () => { - it('should not throw an error when id={0}', () => { + it('should not throw an error when id={0}', async () => { const ListAccordionTest = () => ( @@ -94,12 +104,10 @@ describe('ListAccordion', () => { ); - expect(() => render()).not.toThrow( - 'List.Accordion is used inside a List.AccordionGroup without specifying an id prop.' - ); + await expect(render()).resolves.toBeDefined(); }); - it('should throw an error when id={""}', () => { + it('should throw an error when id={""}', async () => { const ListAccordionTest = () => ( @@ -108,7 +116,7 @@ describe('ListAccordion', () => { ); - expect(() => render()).toThrow( + await expect(render()).rejects.toThrow( 'List.Accordion is used inside a List.AccordionGroup without specifying an id prop.' ); }); diff --git a/src/components/__tests__/ListImage.test.tsx b/src/components/__tests__/ListImage.test.tsx index 96c524467a..8aa7e9b54d 100644 --- a/src/components/__tests__/ListImage.test.tsx +++ b/src/components/__tests__/ListImage.test.tsx @@ -2,7 +2,7 @@ import { StyleSheet } from 'react-native'; import { expect, it } from '@jest/globals'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import ListImage from '../List/ListImage'; const styles = StyleSheet.create({ @@ -23,45 +23,49 @@ const styles = StyleSheet.create({ const testID = 'list-image'; -it('renders ListImage with default variant', () => { - const tree = render( - +it('renders ListImage with default variant', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders ListImage with default variant & styles', () => { - const tree = render( - +it('renders ListImage with default variant & styles', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders ListImage with `image` variant', () => { - const tree = render( +it('renders ListImage with `image` variant', async () => { + await render( ); - expect(tree.getByTestId(testID)).toHaveStyle(styles.image); + expect(screen.getByTestId(testID)).toHaveStyle(styles.image); }); -it('renders ListImage with `video` variant', () => { - const tree = render( +it('renders ListImage with `video` variant', async () => { + await render( ); - expect(tree.getByTestId(testID)).toHaveStyle(styles.video); + expect(screen.getByTestId(testID)).toHaveStyle(styles.video); }); diff --git a/src/components/__tests__/ListItem.test.tsx b/src/components/__tests__/ListItem.test.tsx index 088be073fc..b50f4e7d3f 100644 --- a/src/components/__tests__/ListItem.test.tsx +++ b/src/components/__tests__/ListItem.test.tsx @@ -3,9 +3,9 @@ import { Platform, StyleSheet } from 'react-native'; import { Text, View } from 'react-native'; import { expect, it, jest } from '@jest/globals'; -import { fireEvent } from '@testing-library/react-native'; +import { userEvent } from '@testing-library/react-native'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import { red500 } from '../../theme/colors'; import Chip from '../Chip/Chip'; import IconButton from '../IconButton/IconButton'; @@ -26,117 +26,131 @@ const styles = StyleSheet.create({ const testID = 'list-item'; -it('renders list item with title and description', () => { - const tree = render( - +it('renders list item with title and description', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders list item with left item', () => { - const tree = render( - } - /> +it('renders list item with left item', async () => { + const tree = ( + await render( + } + /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders list item with right item', () => { - const tree = render( - GG} - /> +it('renders list item with right item', async () => { + const tree = ( + await render( + GG} + /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders list item with left and right items', () => { - const tree = render( - GG} - right={(props) => } - /> +it('renders list item with left and right items', async () => { + const tree = ( + await render( + GG} + right={(props) => } + /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders list item with custom title and description styles', () => { - const tree = render( - +it('renders list item with custom title and description styles', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders list item with custom description', () => { - const tree = render( - ( - - - React Native Paper is a high-quality, standard-compliant Design - Design library that has you covered in all major use-cases. - +it('renders list item with custom description', async () => { + const tree = ( + await render( + ( - {}}> - DOCS.pdf - + + React Native Paper is a high-quality, standard-compliant Design + Design library that has you covered in all major use-cases. + + + {}}> + DOCS.pdf + + - - )} - testID={testID} - /> + )} + testID={testID} + /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders with a description with typeof number', () => { - const tree = render( - +it('renders with a description with typeof number', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('calling onPress on ListItem right component', () => { +it('calling onPress on ListItem right component', async () => { Platform.OS = 'web'; const onPress = jest.fn<(event: GestureResponderEvent) => void>(); - const { getByTestId } = render( + await render( { /> ); - fireEvent(getByTestId('icon-button'), 'onPress'); + await userEvent.press(screen.getByTestId('icon-button')); expect(onPress).toHaveBeenCalledTimes(1); }); -it('renders list item with custom content style', () => { - const { getByTestId } = render( +it('renders list item with custom content style', async () => { + await render( { /> ); - expect(getByTestId('list-item-content')).toHaveStyle(styles.content); + expect(screen.getByTestId('list-item-content')).toHaveStyle(styles.content); }); diff --git a/src/components/__tests__/ListSection.test.tsx b/src/components/__tests__/ListSection.test.tsx index 545b3b830e..7afe889182 100644 --- a/src/components/__tests__/ListSection.test.tsx +++ b/src/components/__tests__/ListSection.test.tsx @@ -17,59 +17,65 @@ const styles = StyleSheet.create({ const testID = 'list-item'; -it('renders list section without subheader', () => { - const tree = render( - - } - /> - } - /> - +it('renders list section without subheader', async () => { + const tree = ( + await render( + + } + /> + } + /> + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders list section with subheader', () => { - const tree = render( - - Some title - } - /> - } - /> - +it('renders list section with subheader', async () => { + const tree = ( + await render( + + Some title + } + /> + } + /> + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders list section with custom title style', () => { - const tree = render( - - } - /> - } - /> - +it('renders list section with custom title style', async () => { + const tree = ( + await render( + + } + /> + } + /> + + ) ).toJSON(); expect(tree).toMatchSnapshot(); diff --git a/src/components/__tests__/Menu.test.tsx b/src/components/__tests__/Menu.test.tsx index 412b744047..128fb87cdb 100644 --- a/src/components/__tests__/Menu.test.tsx +++ b/src/components/__tests__/Menu.test.tsx @@ -17,63 +17,69 @@ const styles = StyleSheet.create({ }, }); -it('renders visible menu', () => { - const tree = render( - - Open menu} - > - - - - +it('renders visible menu', async () => { + const tree = ( + await render( + + Open menu} + > + + + + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders not visible menu', () => { - const tree = render( - - Open menu} - > - - - - +it('renders not visible menu', async () => { + const tree = ( + await render( + + Open menu} + > + + + + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders menu with content styles', () => { - const tree = render( - - Open menu} - contentStyle={styles.contentStyle} - > - - - - +it('renders menu with content styles', async () => { + const tree = ( + await render( + + Open menu} + contentStyle={styles.contentStyle} + > + + + + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); ([0, 1, 2, 3, 4, 5] as Elevation[]).forEach((elevation) => - it(`renders menu with background color based on elevation value = ${elevation}`, () => { + it(`renders menu with background color based on elevation value = ${elevation}`, async () => { const theme = getTheme(); - const { getByTestId } = render( + await render( { ); - expect(getByTestId('menu-surface')).toHaveStyle({ + expect(screen.getByTestId('menu-surface')).toHaveStyle({ backgroundColor: theme.colors.elevation[`level${elevation}`], }); }) @@ -124,14 +130,14 @@ it('uses the default anchorPosition of top', async () => { ); } - render(makeMenu(false)); + const { rerender } = await render(makeMenu(false)); // You must update instead of creating directly and using it because // componentDidUpdate isn't called by default in jest. Forcing the update // than triggers measureInWindow, which is how Menu decides where to show // itself. await act(async () => { - screen.update(makeMenu(true)); + await rerender(makeMenu(true)); // Menu waits a tick for Portal refs to be up-to-date. await Promise.resolve(); }); @@ -181,10 +187,10 @@ it('respects anchorPosition bottom', async () => { ); } - render(makeMenu(false)); + const { rerender } = await render(makeMenu(false)); await act(async () => { - screen.update(makeMenu(true)); + await rerender(makeMenu(true)); // Menu waits a tick for Portal refs to be up-to-date. await Promise.resolve(); }); @@ -202,9 +208,9 @@ it('respects anchorPosition bottom', async () => { dimensionsSpy.mockRestore(); }); -it('animated value changes correctly', () => { +it('animated value changes correctly', async () => { const value = new Animated.Value(1); - const { getByTestId } = render( + await render( { ); - expect(getByTestId('menu-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('menu-surface-outer-layer')).toHaveStyle({ transform: [{ scale: 1 }], }); @@ -227,16 +233,16 @@ it('animated value changes correctly', () => { duration: 200, }).start(); - act(() => { + await act(() => { jest.advanceTimersByTime(200); }); - expect(getByTestId('menu-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('menu-surface-outer-layer')).toHaveStyle({ transform: [{ scale: 1.5 }], }); }); -it('renders menu with mode "elevated"', () => { - const { getByTestId } = render( +it('renders menu with mode "elevated"', async () => { + await render( { ); - const menuSurface = getByTestId('menu-surface'); + const menuSurface = screen.getByTestId('menu-surface'); // Get flattened styles + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. const styles = StyleSheet.flatten(menuSurface.props.style); expect(styles).toHaveProperty('shadowColor'); expect(styles).toHaveProperty('shadowOpacity'); }); -it('renders menu with mode "flat"', () => { - const { getByTestId } = render( +it('renders menu with mode "flat"', async () => { + await render( { ); - const menuSurface = getByTestId('menu-surface'); + const menuSurface = screen.getByTestId('menu-surface'); // Get flattened styles + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. const styles = StyleSheet.flatten(menuSurface.props.style); expect(styles).not.toHaveProperty('shadowColor'); diff --git a/src/components/__tests__/MenuItem.test.tsx b/src/components/__tests__/MenuItem.test.tsx index db7b30bc21..e4f683fa52 100644 --- a/src/components/__tests__/MenuItem.test.tsx +++ b/src/components/__tests__/MenuItem.test.tsx @@ -1,7 +1,7 @@ import { describe, expect, it } from '@jest/globals'; import { getTheme } from '../../core/theming'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import { tokens } from '../../theme/tokens'; import Menu from '../Menu/Menu'; import { getMenuItemColor } from '../Menu/utils'; @@ -9,34 +9,36 @@ import { getMenuItemColor } from '../Menu/utils'; const stateOpacity = tokens.md.sys.state.opacity; describe('Menu Item', () => { - it('renders menu item', () => { - const tree = render( - <> - {}} title="Redo" /> - {}} title="Undo" /> - {}} - title="Cut" - disabled - /> - {}} - title="Copy" - disabled - /> - {}} title="Paste" /> - + it('renders menu item', async () => { + const tree = ( + await render( + <> + {}} title="Redo" /> + {}} title="Undo" /> + {}} + title="Cut" + disabled + /> + {}} + title="Copy" + disabled + /> + {}} title="Paste" /> + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); - it('should have titleMaxFontSizeMultiplier passed to title', () => { + it('should have titleMaxFontSizeMultiplier passed to title', async () => { const labelMaxFontSizeMultiplier = 2; - const { getByTestId } = render( + await render( { /> ); - expect(getByTestId('menu-item-title').props.maxFontSizeMultiplier).toBe( - labelMaxFontSizeMultiplier - ); + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('menu-item-title').props.maxFontSizeMultiplier + ).toBe(labelMaxFontSizeMultiplier); }); - it('accepts different values for accessibilityState', () => { - const { getByTestId } = render( + it('accepts different values for accessibilityState', async () => { + await render( { /> ); - expect(getByTestId('touchable').props.accessibilityState).toMatchObject({ + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('touchable').props.accessibilityState + ).toMatchObject({ checked: true, }); }); diff --git a/src/components/__tests__/Modal.test.tsx b/src/components/__tests__/Modal.test.tsx index 2cf6020c36..2009f3d444 100644 --- a/src/components/__tests__/Modal.test.tsx +++ b/src/components/__tests__/Modal.test.tsx @@ -2,9 +2,9 @@ import { Animated, BackHandler as RNBackHandler, Text } from 'react-native'; import type { BackHandlerStatic as RNBackHandlerStatic } from 'react-native'; import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals'; -import { act, fireEvent } from '@testing-library/react-native'; +import { act, userEvent } from '@testing-library/react-native'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import { LightTheme } from '../../theme/schemes'; import { tokens } from '../../theme/tokens'; import Modal from '../Modal'; @@ -37,30 +37,30 @@ describe('Modal', () => { }); describe('by default', () => { - it('should render passed children', () => { - const { getByTestId } = render( + it('should render passed children', async () => { + await render( Children ); - expect(getByTestId('modal')).toHaveTextContent('Children'); + expect(screen.getByTestId('modal')).toHaveTextContent('Children'); }); - it("should render a backdrop in default theme's color", () => { - const { getByTestId } = render( + it("should render a backdrop in default theme's color", async () => { + await render( {null} ); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ backgroundColor: LightTheme.colors.scrim, }); }); - it('should render a custom backdrop color if specified', () => { - const { getByTestId } = render( + it('should render a custom backdrop color if specified', async () => { + await render( { ); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ backgroundColor: 'transparent', }); }); - it('should receive appropriate top and bottom insets', () => { - const { getByTestId } = render( + it('should receive appropriate top and bottom insets', async () => { + await render( {null} ); - expect(getByTestId('modal-wrapper')).toHaveStyle({ + expect(screen.getByTestId('modal-wrapper')).toHaveStyle({ marginTop: 37, marginBottom: 44, }); @@ -94,9 +94,9 @@ describe('Modal', () => { }); describe('when open', () => { describe('if backdrop touched', () => { - it('should invoke the onDismiss function immediately', () => { + it('should invoke the onDismiss function immediately', async () => { const onDismiss = jest.fn(); - const { getByTestId } = render( + await render( {null} @@ -104,25 +104,23 @@ describe('Modal', () => { expect(onDismiss).not.toHaveBeenCalled(); - act(() => { - fireEvent.press(getByTestId('modal-backdrop')); - }); + await userEvent.press(screen.getByTestId('modal-backdrop')); expect(onDismiss).toHaveBeenCalled(); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { + await act(() => { jest.runAllTimers(); }); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); @@ -130,78 +128,78 @@ describe('Modal', () => { }); }); - it('runs the closing animation if visible toggled', () => { - const { getByTestId, queryByTestId, rerender } = render( + it('runs the closing animation if visible toggled', async () => { + const { rerender } = await render( {}}> {null} ); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { - fireEvent.press(getByTestId('modal-backdrop')); - }); + await userEvent.press(screen.getByTestId('modal-backdrop')); - rerender( + await rerender( {}}> {null} ); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { + await act(() => { jest.runAllTimers(); }); - expect(queryByTestId('modal-surface-outer-layer')).not.toBeOnTheScreen(); + expect( + screen.queryByTestId('modal-surface-outer-layer') + ).not.toBeOnTheScreen(); - expect(queryByTestId('modal-backdrop')).not.toBeOnTheScreen(); + expect(screen.queryByTestId('modal-backdrop')).not.toBeOnTheScreen(); }); describe('if closed via Android back button', () => { it('invokes onDismiss', async () => { const onDismiss = jest.fn(); - const { getByTestId } = render( + await render( {null} ); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { + await act(() => { BackHandler.mockPressBack(); }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { + await act(() => { jest.runAllTimers(); }); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); @@ -213,7 +211,7 @@ describe('Modal', () => { describe('when open as non-dismissible modal', () => { describe('if closed via touching backdrop', () => { it('will run the animation but not fade out', async () => { - const { getByTestId } = render( + await render( { ); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { - fireEvent.press(getByTestId('modal-backdrop')); - }); + await userEvent.press(screen.getByTestId('modal-backdrop')); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { + await act(() => { jest.runAllTimers(); }); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); }); - it('should not invoke onDismiss', () => { + it('should not invoke onDismiss', async () => { const onDismiss = jest.fn(); - const { getByTestId } = render( + await render( { expect(onDismiss).not.toHaveBeenCalled(); - act(() => { - fireEvent.press(getByTestId('modal-backdrop')); - }); + await userEvent.press(screen.getByTestId('modal-backdrop')); expect(onDismiss).not.toHaveBeenCalled(); - act(() => { + await act(() => { jest.runAllTimers(); }); @@ -280,7 +274,7 @@ describe('Modal', () => { describe('if closed via Android back button', () => { it('will run the animation but not fade out', async () => { - const { getByTestId } = render( + await render( { ); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { + await act(() => { BackHandler.mockPressBack(); }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { + await act(() => { jest.runAllTimers(); }); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); }); - it('should not invoke onDismiss', () => { + it('should not invoke onDismiss', async () => { const onDismiss = jest.fn(); - render( + await render( { expect(onDismiss).not.toHaveBeenCalled(); - act(() => { + await act(() => { BackHandler.mockPressBack(); }); expect(onDismiss).not.toHaveBeenCalled(); - act(() => { + await act(() => { jest.runAllTimers(); }); @@ -349,36 +343,36 @@ describe('Modal', () => { describe('when visible prop changes', () => { describe('from false to true (closed to open)', () => { - it('should run fade-in animation on opening', () => { - const { queryByTestId, getByTestId, rerender } = render( + it('should run fade-in animation on opening', async () => { + const { rerender } = await render( {null} ); - expect(queryByTestId('modal')).toBe(null); + expect(screen.queryByTestId('modal')).not.toBeOnTheScreen(); - rerender( + await rerender( {null} ); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: 0, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 0, }); - act(() => { + await act(() => { jest.runAllTimers(); }); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); }); @@ -386,43 +380,43 @@ describe('Modal', () => { describe('from true to false (open to closed)', () => { it('should run fade-out animation on closing', async () => { - const { queryByTestId, getByTestId, rerender } = render( + const { rerender } = await render( {null} ); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - rerender( + await rerender( {null} ); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { + await act(() => { jest.runAllTimers(); }); - expect(queryByTestId('modal')).toBe(null); + expect(screen.queryByTestId('modal')).not.toBeOnTheScreen(); }); it('should not invoke onDismiss', async () => { const onDismiss = jest.fn(); - const { rerender } = render( + const { rerender } = await render( {null} @@ -430,7 +424,7 @@ describe('Modal', () => { expect(onDismiss).not.toHaveBeenCalled(); - rerender( + await rerender( {null} @@ -438,7 +432,7 @@ describe('Modal', () => { expect(onDismiss).not.toHaveBeenCalled(); - act(() => { + await act(() => { jest.runAllTimers(); }); @@ -446,144 +440,144 @@ describe('Modal', () => { }); it('should close even if the dialog is not dismissible', async () => { - const { queryByTestId, getByTestId, rerender } = render( + const { rerender } = await render( {null} ); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - rerender( + await rerender( {null} ); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { + await act(() => { jest.runAllTimers(); }); - expect(queryByTestId('modal')).toBe(null); + expect(screen.queryByTestId('modal')).not.toBeOnTheScreen(); }); }); }); describe('when visible prop changes again during the open/close animation', () => { describe('while closing, back to true (visible)', () => { - it('should keep the modal open', () => { - const { getByTestId, rerender } = render( + it('should keep the modal open', async () => { + const { rerender } = await render( {null} ); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - rerender( + await rerender( {null} ); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); - act(() => { + await act(() => { // Not a real seconds, this depends on how frequently // requestAnimationFrame is called jest.advanceTimersToNextTimer(1000); }); - rerender( + await rerender( {null} ); - act(() => { + await act(() => { jest.runAllTimers(); }); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: scrimAlpha, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 1, }); }); }); describe('while opening, back to false (hidden)', () => { - it('should keep the modal closed', () => { - const { queryByTestId, getByTestId, rerender } = render( + it('should keep the modal closed', async () => { + const { rerender } = await render( {null} ); - expect(queryByTestId('modal-backdrop')).toBe(null); + expect(screen.queryByTestId('modal-backdrop')).not.toBeOnTheScreen(); - rerender( + await rerender( {null} ); - expect(getByTestId('modal-backdrop')).toHaveStyle({ + expect(screen.getByTestId('modal-backdrop')).toHaveStyle({ opacity: 0, }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ opacity: 0, }); - act(() => { + await act(() => { // Not a real seconds, this depends on how frequently // requestAnimationFrame is called jest.advanceTimersToNextTimer(1000); }); - expect(queryByTestId('modal-backdrop')).not.toBe(null); + expect(screen.getByTestId('modal-backdrop')).toBeOnTheScreen(); - rerender( + await rerender( {null} ); - act(() => { + await act(() => { jest.runAllTimers(); }); - expect(queryByTestId('modal-backdrop')).toBe(null); + expect(screen.queryByTestId('modal-backdrop')).not.toBeOnTheScreen(); }); }); }); - it('animated value changes correctly', () => { + it('animated value changes correctly', async () => { const value = new Animated.Value(1); - const { getByTestId } = render( + await render( { {null} ); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ transform: [{ scale: 1 }], }); @@ -602,11 +596,11 @@ describe('Modal', () => { duration: 200, }).start(); - act(() => { + await act(() => { jest.runAllTimers(); }); - expect(getByTestId('modal-surface-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('modal-surface-outer-layer')).toHaveStyle({ transform: [{ scale: 1.5 }], }); }); diff --git a/src/components/__tests__/Portal.test.tsx b/src/components/__tests__/Portal.test.tsx index afaabeac07..14f07c141b 100644 --- a/src/components/__tests__/Portal.test.tsx +++ b/src/components/__tests__/Portal.test.tsx @@ -1,15 +1,14 @@ import { Text } from 'react-native'; import { expect, it, jest } from '@jest/globals'; -import { waitFor } from '@testing-library/react-native'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import Portal from '../Portal/Portal'; jest.useRealTimers(); it('renders portal with siblings', async () => { - const { toJSON, getByTestId } = render( + const { toJSON } = await render( Outside content @@ -18,7 +17,7 @@ it('renders portal with siblings', async () => { ); - await waitFor(() => getByTestId('content')); + await screen.findByTestId('content'); expect(toJSON()).toMatchSnapshot(); }); diff --git a/src/components/__tests__/ProgressBar.test.tsx b/src/components/__tests__/ProgressBar.test.tsx index c3a89c8749..db2a2bf600 100644 --- a/src/components/__tests__/ProgressBar.test.tsx +++ b/src/components/__tests__/ProgressBar.test.tsx @@ -2,9 +2,9 @@ import * as React from 'react'; import { Animated, Platform, StyleSheet } from 'react-native'; import { afterEach, expect, it } from '@jest/globals'; -import { act } from '@testing-library/react-native'; +import { fireEvent } from '@testing-library/react-native'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import ProgressBar from '../ProgressBar'; import type { Props } from '../ProgressBar'; @@ -23,12 +23,8 @@ const styles = StyleSheet.create({ }); const a11yRole = 'progressbar'; -const triggerLayout = async ( - tree: ReturnType -): Promise => { - await act(async () => { - tree.getByRole(a11yRole).props.onLayout(layoutEvent); - }); +const triggerLayout = async (): Promise => { + await fireEvent(screen.getByRole(a11yRole), 'layout', layoutEvent); }; class ClassProgressBar extends React.Component { @@ -44,59 +40,59 @@ afterEach(() => { }); it('renders progress bar with animated value', async () => { - const tree = render(); - await triggerLayout(tree); + const view = await render(); + await triggerLayout(); - tree.update(); + await view.rerender(); - expect(tree.getByRole(a11yRole)).toBeTruthy(); + expect(screen.getByRole(a11yRole)).toBeOnTheScreen(); }); it('renders progress bar with specific progress', async () => { - const tree = render(); - await triggerLayout(tree); + const view = await render(); + await triggerLayout(); - expect(tree.toJSON()).toMatchSnapshot(); + expect(view.toJSON()).toMatchSnapshot(); }); it('renders hidden progress bar', async () => { - const tree = render(); - await triggerLayout(tree); + const view = await render(); + await triggerLayout(); - expect(tree.toJSON()).toMatchSnapshot(); + expect(view.toJSON()).toMatchSnapshot(); }); it('renders colored progress bar', async () => { - const tree = render(); - await triggerLayout(tree); + const view = await render(); + await triggerLayout(); - expect(tree.toJSON()).toMatchSnapshot(); + expect(view.toJSON()).toMatchSnapshot(); }); it('renders indeterminate progress bar', async () => { - const tree = render(); - await triggerLayout(tree); + const view = await render(); + await triggerLayout(); - expect(tree.toJSON()).toMatchSnapshot(); + expect(view.toJSON()).toMatchSnapshot(); }); -it('renders progress bar with full height on web', () => { +it('renders progress bar with full height on web', async () => { Platform.OS = 'web'; - const tree = render(); + await render(); - expect(tree.getByRole(a11yRole)).toHaveStyle({ + expect(screen.getByRole(a11yRole)).toHaveStyle({ width: '100%', height: '100%', }); }); it('renders progress bar with custom style of filled part', async () => { - const tree = render( + await render( ); - await triggerLayout(tree); + await triggerLayout(); - expect(tree.getByTestId('progress-bar-fill')).toHaveStyle({ + expect(screen.getByTestId('progress-bar-fill')).toHaveStyle({ borderRadius: 4, }); }); diff --git a/src/components/__tests__/RadioButton/RadioButton.test.tsx b/src/components/__tests__/RadioButton/RadioButton.test.tsx index 75497ea77e..da8a04375d 100644 --- a/src/components/__tests__/RadioButton/RadioButton.test.tsx +++ b/src/components/__tests__/RadioButton/RadioButton.test.tsx @@ -27,8 +27,8 @@ describe('RadioButton', () => { }); }); - it('renders properly', () => { - const tree = render().toJSON(); + it('renders properly', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); @@ -50,21 +50,23 @@ describe('RadioButton', () => { }); }); - it('renders properly', () => { - const tree = render().toJSON(); + it('renders properly', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); }); describe('when RadioButton is wrapped by RadioButtonContext.Provider', () => { - it('renders properly', () => { - const tree = render( - {} }} - > - - + it('renders properly', async () => { + const tree = ( + await render( + {} }} + > + + + ) ).toJSON(); expect(tree).toMatchSnapshot(); @@ -72,9 +74,9 @@ describe('RadioButton', () => { }); describe('RadioButton with custom testID', () => { - it('renders properly', () => { - const tree = render( - + it('renders properly', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); diff --git a/src/components/__tests__/RadioButton/RadioButtonGroup.test.tsx b/src/components/__tests__/RadioButton/RadioButtonGroup.test.tsx index b4fe69463e..15bf4aa442 100644 --- a/src/components/__tests__/RadioButton/RadioButtonGroup.test.tsx +++ b/src/components/__tests__/RadioButton/RadioButtonGroup.test.tsx @@ -4,11 +4,13 @@ import { render } from '../../../test-utils'; import RadioButton from '../../RadioButton'; describe('RadioButtonGroup', () => { - it('renders properly', () => { - const tree = render( - {}}> - - + it('renders properly', async () => { + const tree = ( + await render( + {}}> + + + ) ).toJSON(); expect(tree).toMatchSnapshot(); diff --git a/src/components/__tests__/RadioButton/RadioButtonItem.test.tsx b/src/components/__tests__/RadioButton/RadioButtonItem.test.tsx index b8714367bb..821d9ebc5b 100644 --- a/src/components/__tests__/RadioButton/RadioButtonItem.test.tsx +++ b/src/components/__tests__/RadioButton/RadioButtonItem.test.tsx @@ -1,69 +1,77 @@ import { Platform } from 'react-native'; import { expect, it, jest } from '@jest/globals'; -import { act, fireEvent } from '@testing-library/react-native'; +import { userEvent } from '@testing-library/react-native'; -import { render } from '../../../test-utils'; +import { render, screen } from '../../../test-utils'; import RadioButton from '../../RadioButton'; -it('renders unchecked', () => { - const tree = render( - +it('renders unchecked', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('can render the iOS radio button on different platforms', () => { +it('can render the iOS radio button on different platforms', async () => { Platform.OS = 'android'; - const tree = render( - + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('can render the Android radio button on different platforms', () => { +it('can render the Android radio button on different platforms', async () => { Platform.OS = 'ios'; - const tree = render( - + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('can render leading radio button control', () => { +it('can render leading radio button control', async () => { Platform.OS = 'ios'; - const tree = render( - + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('should execute onLongPress', () => { +it('should execute onLongPress', async () => { const onLongPress = jest.fn(); - const { getByTestId } = render( + await render( { /> ); - act(() => { - fireEvent(getByTestId('radio-button-item'), 'longPress', { key: 'value' }); - }); + await userEvent.longPress(screen.getByTestId('radio-button-item')); expect(onLongPress).toHaveBeenCalledTimes(1); }); diff --git a/src/components/__tests__/Searchbar.test.tsx b/src/components/__tests__/Searchbar.test.tsx index 12b66e5d11..0671263277 100644 --- a/src/components/__tests__/Searchbar.test.tsx +++ b/src/components/__tests__/Searchbar.test.tsx @@ -1,82 +1,87 @@ import { Animated } from 'react-native'; import { expect, it, jest } from '@jest/globals'; -import { act, fireEvent } from '@testing-library/react-native'; +import { act, userEvent } from '@testing-library/react-native'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import * as Avatar from '../Avatar/Avatar'; import Searchbar from '../Searchbar'; -it('renders with placeholder', () => { - const tree = render().toJSON(); +it('renders with placeholder', async () => { + const tree = ( + await render() + ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders with text', () => { - const tree = render( - +it('renders with text', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('activity indicator snapshot test', () => { - const tree = render().toJSON(); +it('activity indicator snapshot test', async () => { + const tree = (await render()).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders with ActivityIndicator', () => { - const tree = render(); +it('renders with ActivityIndicator', async () => { + await render(); - expect(tree.getByTestId('activity-indicator')).toBeTruthy(); + expect(screen.getByTestId('activity-indicator')).toBeOnTheScreen(); }); -it('renders without ActivityIndicator', () => { - const { getByTestId } = render(); +it('renders without ActivityIndicator', async () => { + await render(); - expect(() => getByTestId('activity-indicator')).toThrow(); + expect(screen.queryByTestId('activity-indicator')).not.toBeOnTheScreen(); }); -it('renders clear icon with custom color', () => { - const { getByTestId } = render( +it('renders clear icon with custom color', async () => { + await render( ); - const iconComponent = getByTestId('search-bar-icon-wrapper').props.children; + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + const iconComponent = screen.getByTestId('search-bar-icon-wrapper').props + .children; + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(iconComponent.props.iconColor).toBe('purple'); }); -it('renders clear icon wrapper, which can be the target of touch events, if search has value', () => { - const { getByTestId } = render( - - ); +it('renders clear icon wrapper, which can be the target of touch events, if search has value', async () => { + await render(); - expect(getByTestId('search-bar-icon-wrapper').props.pointerEvents).toBe( - 'auto' - ); + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('search-bar-icon-wrapper').props.pointerEvents + ).toBe('auto'); }); -it('renders clear icon wrapper, which is never target of touch events, if search has no value', () => { - const { getByTestId } = render(); +it('renders clear icon wrapper, which is never target of touch events, if search has no value', async () => { + await render(); - expect(getByTestId('search-bar-icon-wrapper').props.pointerEvents).toBe( - 'none' - ); + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('search-bar-icon-wrapper').props.pointerEvents + ).toBe('none'); }); -it('animated value changes correctly', () => { +it('animated value changes correctly', async () => { const value = new Animated.Value(1); - const { getByTestId } = render( + await render( ); - expect(getByTestId('search-bar-container-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('search-bar-container-outer-layer')).toHaveStyle({ transform: [{ scale: 1 }], }); @@ -86,41 +91,37 @@ it('animated value changes correctly', () => { duration: 200, }).start(); - act(() => { + await act(() => { jest.advanceTimersByTime(200); }); - expect(getByTestId('search-bar-container-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('search-bar-container-outer-layer')).toHaveStyle({ transform: [{ scale: 1.5 }], }); }); -it('defines onClearIconPress action and checks if it is called when close button is pressed', () => { +it('defines onClearIconPress action and checks if it is called when close button is pressed', async () => { const onClearIconPressMock = jest.fn(); - const { getByTestId } = render( + await render( ); - const iconComponent = getByTestId('search-bar-icon-wrapper').props.children; - - fireEvent(iconComponent, 'onPress'); + await userEvent.press(screen.getByTestId('search-bar-clear-icon')); expect(onClearIconPressMock).toHaveBeenCalledTimes(1); }); -it('renders clear icon wrapper, with appropriate style for v3', () => { - const { getByTestId, update } = render( - - ); +it('renders clear icon wrapper, with appropriate style for v3', async () => { + const { rerender } = await render(); - expect(getByTestId('search-bar-icon-wrapper')).toHaveStyle({ + expect(screen.getByTestId('search-bar-icon-wrapper')).toHaveStyle({ position: 'absolute', right: 0, marginLeft: 16, }); - update( + await rerender( { /> ); - expect(getByTestId('search-bar-icon-wrapper')).toHaveStyle({ - display: 'none', - }); + expect( + screen.getByTestId('search-bar-icon-wrapper', { + includeHiddenElements: true, + }) + ).toHaveStyle({ display: 'none' }); }); -it('renders trailering icon when mode is set to "bar"', () => { - const { getByTestId } = render( +it('renders trailering icon when mode is set to "bar"', async () => { + await render( { /> ); - expect(getByTestId('search-bar-trailering-icon')).toBeTruthy(); + expect(screen.getByTestId('search-bar-trailering-icon')).toBeOnTheScreen(); }); -it('renders trailering icon with press functionality', () => { +it('renders trailering icon with press functionality', async () => { const onTraileringIconPressMock = jest.fn(); - const { getByTestId } = render( + await render( { /> ); - fireEvent(getByTestId('search-bar-trailering-icon'), 'onPress'); + await userEvent.press(screen.getByTestId('search-bar-trailering-icon')); expect(onTraileringIconPressMock).toHaveBeenCalledTimes(1); }); -it('renders clear icon instead of trailering icon', () => { - const { getByTestId, update, queryByTestId } = render( +it('renders clear icon instead of trailering icon', async () => { + const { rerender } = await render( { /> ); - expect(getByTestId('search-bar-trailering-icon')).toBeTruthy(); + expect(screen.getByTestId('search-bar-trailering-icon')).toBeOnTheScreen(); - update( + await rerender( { /> ); - expect(queryByTestId('search-bar-trailering-icon')).toBeNull(); - expect(getByTestId('search-bar-icon-wrapper')).toBeTruthy(); + expect( + screen.queryByTestId('search-bar-trailering-icon') + ).not.toBeOnTheScreen(); + expect(screen.getByTestId('search-bar-icon-wrapper')).toBeOnTheScreen(); }); -it('renders searchbar in "view" mode', () => { - const { getByTestId } = render( - - ); +it('renders searchbar in "view" mode', async () => { + await render(); - expect(getByTestId('search-bar-container')).toHaveStyle({ borderRadius: 0 }); + expect(screen.getByTestId('search-bar-container')).toHaveStyle({ + borderRadius: 0, + }); }); diff --git a/src/components/__tests__/SegmentedButton.test.tsx b/src/components/__tests__/SegmentedButton.test.tsx index 144f12992e..ce950f671f 100644 --- a/src/components/__tests__/SegmentedButton.test.tsx +++ b/src/components/__tests__/SegmentedButton.test.tsx @@ -1,7 +1,7 @@ import { describe, expect, it, jest } from '@jest/globals'; import { getTheme } from '../../core/theming'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import { tokens } from '../../theme/tokens'; import SegmentedButtons from '../SegmentedButtons/SegmentedButtons'; import { @@ -11,25 +11,29 @@ import { const stateOpacity = tokens.md.sys.state.opacity; -it('renders segmented button', () => { - const tree = render( - {}} - value={'walk'} - buttons={[{ value: 'walk' }, { value: 'ride' }]} - /> +it('renders segmented button', async () => { + const tree = ( + await render( + {}} + value={'walk'} + buttons={[{ value: 'walk' }, { value: 'ride' }]} + /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); it('renders disabled segmented button', async () => { - const tree = render( - {}} - value={'walk'} - buttons={[{ value: 'walk' }, { value: 'ride', disabled: true }]} - /> + const tree = ( + await render( + {}} + value={'walk'} + buttons={[{ value: 'walk' }, { value: 'ride', disabled: true }]} + /> + ) ).toJSON(); process.nextTick(() => { @@ -38,15 +42,17 @@ it('renders disabled segmented button', async () => { }); it('renders checked segmented button with selected check', async () => { - const tree = render( - {}} - value={'walk'} - buttons={[ - { value: 'walk', showSelectedCheck: true }, - { value: 'ride', disabled: true }, - ]} - /> + const tree = ( + await render( + {}} + value={'walk'} + buttons={[ + { value: 'walk', showSelectedCheck: true }, + { value: 'ride', disabled: true }, + ]} + /> + ) ).toJSON(); process.nextTick(() => { @@ -266,8 +272,8 @@ describe('getDisabledSegmentedButtonBorderWidth', () => { }); describe('should render icon when', () => { - it('icon prop is passed', () => { - const { getByTestId } = render( + it('icon prop is passed', async () => { + await render( { /> ); - expect(getByTestId('walking-button-icon')).toBeTruthy(); - expect(getByTestId('driving-button-icon')).toBeTruthy(); + expect(screen.getByTestId('walking-button-icon')).toBeOnTheScreen(); + expect(screen.getByTestId('driving-button-icon')).toBeOnTheScreen(); }); - it('icon prop is passed along with label, no matter if button is checked', () => { - const { getByTestId } = render( + it('icon prop is passed along with label, no matter if button is checked', async () => { + await render( { /> ); - expect(getByTestId('walking-button-icon')).toBeTruthy(); - expect(getByTestId('driving-button-icon')).toBeTruthy(); + expect(screen.getByTestId('walking-button-icon')).toBeOnTheScreen(); + expect(screen.getByTestId('driving-button-icon')).toBeOnTheScreen(); }); - it('icon prop is passed along with label, button is checked, showSelectedCheck is false', () => { - const { getByTestId } = render( + it('icon prop is passed along with label, button is checked, showSelectedCheck is false', async () => { + await render( { /> ); - expect(getByTestId('walking-button-icon')).toBeTruthy(); - expect(getByTestId('driving-button-icon')).toBeTruthy(); + expect(screen.getByTestId('walking-button-icon')).toBeOnTheScreen(); + expect(screen.getByTestId('driving-button-icon')).toBeOnTheScreen(); }); }); describe('should not render icon when', () => { - it('icon prop is not passed', () => { - const { queryByTestId } = render( + it('icon prop is not passed', async () => { + await render( { /> ); - expect(queryByTestId('walking-button-icon')).toBeNull(); - expect(queryByTestId('driving-button-icon')).toBeNull(); + expect(screen.queryByTestId('walking-button-icon')).not.toBeOnTheScreen(); + expect(screen.queryByTestId('driving-button-icon')).not.toBeOnTheScreen(); }); - it('icon prop is passed along with label, button is checked, showSelectedCheck is true', () => { - const { getByTestId, queryByTestId } = render( + it('icon prop is passed along with label, button is checked, showSelectedCheck is true', async () => { + await render( { /> ); - expect(queryByTestId('walking-button-icon')).toBeNull(); - expect(getByTestId('walking-button-check-icon')).toBeTruthy(); - expect(getByTestId('driving-button-icon')).toBeTruthy(); + expect(screen.queryByTestId('walking-button-icon')).not.toBeOnTheScreen(); + expect(screen.getByTestId('walking-button-check-icon')).toBeOnTheScreen(); + expect(screen.getByTestId('driving-button-icon')).toBeOnTheScreen(); }); }); describe('should have `accessibilityState={ checked: true }` when selected', () => { - it('should have two button selected', () => { + it('should have two button selected', async () => { const onValueChange = jest.fn(); - const { getAllByA11yState } = render( + await render( multiSelect value={['walk', 'transit']} @@ -414,14 +420,26 @@ describe('should have `accessibilityState={ checked: true }` when selected', () /> ); - const checkedButtons = getAllByA11yState({ checked: true }); - expect(checkedButtons).toHaveLength(2); + const buttons = screen.getAllByRole('button'); + + expect(buttons[0]).toHaveProp( + 'accessibilityState', + expect.objectContaining({ checked: true }) + ); + expect(buttons[1]).toHaveProp( + 'accessibilityState', + expect.objectContaining({ checked: true }) + ); + expect(buttons[2]).toHaveProp( + 'accessibilityState', + expect.objectContaining({ checked: false }) + ); }); - it('show selected check icon should be shown', () => { + it('show selected check icon should be shown', async () => { const onValueChange = jest.fn(); - const { getByTestId } = render( + await render( multiSelect value={['walk', 'transit']} @@ -439,13 +457,13 @@ describe('should have `accessibilityState={ checked: true }` when selected', () /> ); - expect(getByTestId('walking-check-icon')).toBeDefined(); + expect(screen.getByTestId('walking-check-icon')).toBeOnTheScreen(); }); }); describe('labelStyle is handled', () => { - it('when labelStyle is given', () => { - const { getByTestId } = render( + it('when labelStyle is given', async () => { + await render( { /> ); - expect(getByTestId('walking-button-label')).toHaveStyle({ fontSize: 10 }); - expect(getByTestId('driving-button-label')).toHaveStyle({ fontSize: 12 }); + expect(screen.getByTestId('walking-button-label')).toHaveStyle({ + fontSize: 10, + }); + expect(screen.getByTestId('driving-button-label')).toHaveStyle({ + fontSize: 12, + }); }); - it('when labelStyle is omitted', () => { - const { getByTestId } = render( + it('when labelStyle is omitted', async () => { + await render( { /> ); - expect(getByTestId('walking-button-label')).toHaveStyle({ fontSize: 14 }); + expect(screen.getByTestId('walking-button-label')).toHaveStyle({ + fontSize: 14, + }); }); }); diff --git a/src/components/__tests__/Snackbar.test.tsx b/src/components/__tests__/Snackbar.test.tsx index 129db058e5..16b118da09 100644 --- a/src/components/__tests__/Snackbar.test.tsx +++ b/src/components/__tests__/Snackbar.test.tsx @@ -3,7 +3,7 @@ import { Animated, StyleSheet, Text, View } from 'react-native'; import { expect, it, jest } from '@jest/globals'; import { act } from '@testing-library/react-native'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import { red200, white } from '../../theme/colors'; import Snackbar from '../Snackbar'; @@ -23,69 +23,79 @@ jest.mock('react-native-safe-area-context', () => ({ useSafeAreaInsets: () => ({ bottom: 34, left: 0, right: 0, top: 47 }), })); -it('renders snackbar with content', () => { - const tree = render( - - Snackbar content - +it('renders snackbar with content', async () => { + const tree = ( + await render( + + Snackbar content + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders not visible snackbar with content wrapper but no actual content', () => { - const tree = render( - - Snackbar content - +it('renders not visible snackbar with content wrapper but no actual content', async () => { + const tree = ( + await render( + + Snackbar content + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders snackbar with Text as a child', () => { - const tree = render( - - Snackbar content - +it('renders snackbar with Text as a child', async () => { + const tree = ( + await render( + + Snackbar content + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders snackbar with action button', () => { - const tree = render( - {}} - action={{ label: 'Undo', onPress: jest.fn() }} - > - Snackbar content - +it('renders snackbar with action button', async () => { + const tree = ( + await render( + {}} + action={{ label: 'Undo', onPress: jest.fn() }} + > + Snackbar content + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders snackbar with View & Text as a child', () => { - const tree = render( - - - - - Error Message which is veryyyyyyyyyyyy longggggggg Error Message which - is veryyyyyyyyyyyy longggggggg - - - +it('renders snackbar with View & Text as a child', async () => { + const tree = ( + await render( + + + + + Error Message which is veryyyyyyyyyyyy longggggggg Error Message + which is veryyyyyyyyyyyy longggggggg + + + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('animated value changes correctly', () => { +it('animated value changes correctly', async () => { const value = new Animated.Value(1); - const { getByTestId } = render( + await render( { Snackbar content ); - expect(getByTestId('snack-bar-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('snack-bar-outer-layer')).toHaveStyle({ transform: [{ scale: 1 }], }); @@ -105,10 +115,10 @@ it('animated value changes correctly', () => { duration: 200, }).start(); - act(() => { + await act(() => { jest.advanceTimersByTime(200); }); - expect(getByTestId('snack-bar-outer-layer')).toHaveStyle({ + expect(screen.getByTestId('snack-bar-outer-layer')).toHaveStyle({ transform: [{ scale: 1.5 }], }); }); diff --git a/src/components/__tests__/Surface.test.tsx b/src/components/__tests__/Surface.test.tsx index 879f5b48ee..1a9ebc8a45 100644 --- a/src/components/__tests__/Surface.test.tsx +++ b/src/components/__tests__/Surface.test.tsx @@ -5,7 +5,7 @@ import { Platform } from 'react-native'; import { describe, expect, it } from '@jest/globals'; import { getTheme } from '../../core/theming'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import Surface from '../Surface'; type StyleCase = { @@ -14,14 +14,15 @@ type StyleCase = { }; describe('Surface', () => { - it('should properly render passed props', () => { + it('should properly render passed props', async () => { const testID = 'surface-container'; - const { getByTestId } = render( + await render( {null} ); - expect(getByTestId(testID).props.pointerEvents).toBe('box-none'); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId(testID).props.pointerEvents).toBe('box-none'); }); describe('on iOS', () => { @@ -46,8 +47,8 @@ describe('Surface', () => { }, }); - it('should render Surface with appropriate bg color but without shadow, if mode is set to "flat"', () => { - const { getByTestId } = render( + it('should render Surface with appropriate bg color but without shadow, if mode is set to "flat"', async () => { + await render( { ); - expect(getByTestId('surface-test')).not.toHaveStyle({ + expect(screen.getByTestId('surface-test')).not.toHaveStyle({ shadowColor: '#000', shadowOpacity: 0.3, shadowOffset: { width: 0, height: 4 }, shadowRadius: 4, }); - expect(getByTestId('surface-test-outer-layer')).not.toHaveStyle({ + expect(screen.getByTestId('surface-test-outer-layer')).not.toHaveStyle({ shadowColor: '#000', shadowOpacity: 0.15, shadowOffset: { width: 0, height: 8 }, shadowRadius: 12, }); - expect(getByTestId('surface-test')).toHaveStyle({ + expect(screen.getByTestId('surface-test')).toHaveStyle({ backgroundColor: getTheme().colors.surfaceContainerHighest, }); }); @@ -98,17 +99,19 @@ describe('Surface', () => { { property: 'flex', value: 6 }, ] satisfies StyleCase[])( 'applies $property to outer layer only', - ({ property, value }) => { + async ({ property, value }) => { const style = { [property]: value }; - const { getByTestId } = render( + await render( {null} ); - expect(getByTestId('surface-test-outer-layer')).toHaveStyle(style); - expect(getByTestId('surface-test')).not.toHaveStyle(style); + expect(screen.getByTestId('surface-test-outer-layer')).toHaveStyle( + style + ); + expect(screen.getByTestId('surface-test')).not.toHaveStyle(style); } ); @@ -124,17 +127,19 @@ describe('Surface', () => { { property: 'borderColor', value: 'black' }, ] satisfies StyleCase[])( 'applies $property to inner layer only', - ({ property, value }) => { + async ({ property, value }) => { const style = { [property]: value }; - const { getByTestId } = render( + await render( {null} ); - expect(getByTestId('surface-test-outer-layer')).not.toHaveStyle(style); - expect(getByTestId('surface-test')).toHaveStyle(style); + expect(screen.getByTestId('surface-test-outer-layer')).not.toHaveStyle( + style + ); + expect(screen.getByTestId('surface-test')).toHaveStyle(style); } ); @@ -147,81 +152,85 @@ describe('Surface', () => { { property: 'backgroundColor', value: 'rgb(4, 5, 6)' }, ] satisfies StyleCase[])( 'applies $property to every layer', - ({ property, value }) => { + async ({ property, value }) => { const style = { [property]: value }; - const { getByTestId } = render( + await render( {null} ); - expect(getByTestId('surface-test-outer-layer')).toHaveStyle(style); - expect(getByTestId('surface-test')).toHaveStyle(style); + expect(screen.getByTestId('surface-test-outer-layer')).toHaveStyle( + style + ); + expect(screen.getByTestId('surface-test')).toHaveStyle(style); } ); describe('outer layer', () => { - it('should not render rest style', () => { + it('should not render rest style', async () => { const testID = 'surface-test'; - const { getByTestId } = render( + await render( {null} ); - expect(getByTestId(`${testID}-outer-layer`)).not.toHaveStyle( + expect(screen.getByTestId(`${testID}-outer-layer`)).not.toHaveStyle( styles.restStyle ); }); - it('should render absolute position properties on outer layer', () => { + it('should render absolute position properties on outer layer', async () => { const testID = 'surface-test'; - const { getByTestId } = render( + await render( {null} ); - expect(getByTestId(`${testID}-outer-layer`)).toHaveStyle( + expect(screen.getByTestId(`${testID}-outer-layer`)).toHaveStyle( styles.absoluteStyles ); }); - it('should render absolute position properties on the outer layer', () => { + it('should render absolute position properties on the outer layer', async () => { const testID = 'surface-test'; - const { getByTestId } = render( + await render( {null} ); - expect(getByTestId(`${testID}-outer-layer`)).toHaveStyle( + expect(screen.getByTestId(`${testID}-outer-layer`)).toHaveStyle( styles.absoluteStyles ); }); }); describe('inner layer', () => { - it('should render inner layer styles on the inner layer', () => { + it('should render inner layer styles on the inner layer', async () => { const testID = 'surface-test'; - const { getByTestId } = render( + await render( {null} ); - expect(getByTestId(testID)).toHaveStyle(styles.innerLayerViewStyle); + expect(screen.getByTestId(testID)).toHaveStyle( + styles.innerLayerViewStyle + ); }); }); - it('applies backgroundColor to every layer', () => { + it('applies backgroundColor to every layer', async () => { const backgroundColor = 'rgb(1, 2, 3)'; - const { getByTestId } = render( + await render( { ); const style = { backgroundColor }; - expect(getByTestId('surface-test-outer-layer')).toHaveStyle(style); - expect(getByTestId('surface-test')).toHaveStyle(style); + expect(screen.getByTestId('surface-test-outer-layer')).toHaveStyle(style); + expect(screen.getByTestId('surface-test')).toHaveStyle(style); }); describe('children wrapper', () => { - it('should render rest styles', () => { + it('should render rest styles', async () => { const testID = 'surface-test'; const combinedStyles = [styles.innerLayerViewStyle, styles.restStyle]; - const { getByTestId } = render( + await render( {null} ); - expect(getByTestId(testID)).toHaveStyle(combinedStyles); + expect(screen.getByTestId(testID)).toHaveStyle(combinedStyles); }); }); }); describe('on Android', () => { - it('should render Surface with appropriate bg color but without shadow, if mode is set to "flat"', () => { + it('should render Surface with appropriate bg color but without shadow, if mode is set to "flat"', async () => { Platform.OS = 'android'; const testID = 'surface-container'; - const { getByTestId } = render( + await render( { ); - expect(getByTestId(testID)).not.toHaveStyle({ elevation: 5 }); - expect(getByTestId(testID)).toHaveStyle({ + expect(screen.getByTestId(testID)).not.toHaveStyle({ elevation: 5 }); + expect(screen.getByTestId(testID)).toHaveStyle({ backgroundColor: getTheme().colors.surfaceContainerHighest, }); }); diff --git a/src/components/__tests__/Switch.test.tsx b/src/components/__tests__/Switch.test.tsx index bdc34ca48a..5e1f44f174 100644 --- a/src/components/__tests__/Switch.test.tsx +++ b/src/components/__tests__/Switch.test.tsx @@ -1,67 +1,65 @@ import { describe, expect, it, jest } from '@jest/globals'; -import { fireEvent, render } from '../../test-utils'; +import { render, screen, userEvent } from '../../test-utils'; import Switch from '../Switch/Switch'; describe('Switch render', () => { - it('renders on', () => { - expect(render().toJSON()).toMatchSnapshot(); + it('renders on', async () => { + expect((await render()).toJSON()).toMatchSnapshot(); }); - it('renders off', () => { - expect(render().toJSON()).toMatchSnapshot(); + it('renders off', async () => { + expect((await render()).toJSON()).toMatchSnapshot(); }); - it('renders disabled on', () => { - expect(render().toJSON()).toMatchSnapshot(); + it('renders disabled on', async () => { + expect( + (await render()).toJSON() + ).toMatchSnapshot(); }); - it('renders disabled off', () => { + it('renders disabled off', async () => { expect( - render().toJSON() + (await render()).toJSON() ).toMatchSnapshot(); }); - it('renders with checked icon', () => { + it('renders with checked icon', async () => { expect( - render().toJSON() + (await render()).toJSON() ).toMatchSnapshot(); }); - it('renders with per-state icons', () => { + it('renders with per-state icons', async () => { expect( - render( - + ( + await render() ).toJSON() ).toMatchSnapshot(); }); }); describe('Switch interaction', () => { - it('toggles to true when off and pressed', () => { + it('toggles to true when off and pressed', async () => { const onValueChange = jest.fn(); - const { getByRole } = render( - - ); - fireEvent.press(getByRole('switch')); + await render(); + await userEvent.press(screen.getByRole('switch')); expect(onValueChange).toHaveBeenCalledWith(true); }); - it('toggles to false when on and pressed', () => { + it('toggles to false when on and pressed', async () => { const onValueChange = jest.fn(); - const { getByRole } = render( - - ); - fireEvent.press(getByRole('switch')); + await render(); + await userEvent.press(screen.getByRole('switch')); expect(onValueChange).toHaveBeenCalledWith(false); }); - it('does not fire onValueChange when disabled', () => { + it('does not fire onValueChange when disabled', async () => { const onValueChange = jest.fn(); - const { getByRole } = render( + await render( ); - fireEvent.press(getByRole('switch')); + await userEvent.press(screen.getByRole('switch')); expect(onValueChange).not.toHaveBeenCalled(); }); }); diff --git a/src/components/__tests__/TextInput.test.tsx b/src/components/__tests__/TextInput.test.tsx index 14ded21b21..6a0fe19768 100644 --- a/src/components/__tests__/TextInput.test.tsx +++ b/src/components/__tests__/TextInput.test.tsx @@ -1,10 +1,5 @@ import * as React from 'react'; -import { - I18nManager, - StyleSheet, - TextInput as NativeTextInput, - View, -} from 'react-native'; +import { I18nManager, TextInput as NativeTextInput, View } from 'react-native'; import type { GestureResponderEvent } from 'react-native'; import { @@ -15,8 +10,9 @@ import { it, jest, } from '@jest/globals'; +import type { TestInstance } from 'test-renderer'; -import { act, fireEvent, render } from '../../test-utils'; +import { act, fireEvent, render, screen, userEvent } from '../../test-utils'; import { tokens } from '../../theme/tokens'; import TextInput from '../TextInput'; import type { @@ -28,6 +24,24 @@ import type { TextInputAccessoryProps } from '../TextInput/TextInputIcon'; const stateOpacity = tokens.md.sys.state.opacity; const defaultI18nIsRTL = I18nManager.isRTL; +const includeHiddenElements = { includeHiddenElements: true }; + +const getOuterTextInputPressable = (root: TestInstance | null) => { + const [pressable] = + // eslint-disable-next-line no-restricted-syntax -- TODO: replace non-accessible outer Pressable lookup with a public behavior assertion. + root?.queryAll( + (instance) => + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + instance.props.role === 'none' && instance.props.accessible === false, + { includeSelf: true } + ) ?? []; + + if (!pressable) { + throw new Error('Expected outer TextInput Pressable'); + } + + return pressable; +}; const getConstantsOriginal = I18nManager.getConstants.bind(I18nManager); @@ -57,106 +71,118 @@ function firstIndexOfTextChildArrayInTree(tree: unknown, text: string): number { return JSON.stringify(tree).indexOf(JSON.stringify([text])); } -it('renders filled TextInput with label and value', () => { - const tree = render( - {}} /> +it('renders filled TextInput with label and value', async () => { + const tree = ( + await render( + {}} /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders outlined TextInput with label and value', () => { - const tree = render( - {}} - /> +it('renders outlined TextInput with label and value', async () => { + const tree = ( + await render( + {}} + /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders filled TextInput with TextInput.Icon accessories', () => { - const tree = render( - {}} - startAccessory={(props: TextInputAccessoryProps) => ( - - )} - endAccessory={(props: TextInputAccessoryProps) => ( - - )} - /> +it('renders filled TextInput with TextInput.Icon accessories', async () => { + const tree = ( + await render( + {}} + startAccessory={(props: TextInputAccessoryProps) => ( + + )} + endAccessory={(props: TextInputAccessoryProps) => ( + + )} + /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders outlined TextInput with TextInput.Icon accessories', () => { - const tree = render( - {}} - startAccessory={(props: TextInputAccessoryProps) => ( - - )} - endAccessory={(props: TextInputAccessoryProps) => ( - - )} - /> +it('renders outlined TextInput with TextInput.Icon accessories', async () => { + const tree = ( + await render( + {}} + startAccessory={(props: TextInputAccessoryProps) => ( + + )} + endAccessory={(props: TextInputAccessoryProps) => ( + + )} + /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders filled TextInput with TextInput.Icon accessories when error is true', () => { - const tree = render( - {}} - error - startAccessory={(props: TextInputAccessoryProps) => ( - - )} - endAccessory={(props: TextInputAccessoryProps) => ( - {}} /> - )} - /> +it('renders filled TextInput with TextInput.Icon accessories when error is true', async () => { + const tree = ( + await render( + {}} + error + startAccessory={(props: TextInputAccessoryProps) => ( + + )} + endAccessory={(props: TextInputAccessoryProps) => ( + {}} /> + )} + /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders outlined TextInput with TextInput.Icon accessories when error is true', () => { - const tree = render( - {}} - error - startAccessory={(props: TextInputAccessoryProps) => ( - - )} - endAccessory={(props: TextInputAccessoryProps) => ( - {}} /> - )} - /> +it('renders outlined TextInput with TextInput.Icon accessories when error is true', async () => { + const tree = ( + await render( + {}} + error + startAccessory={(props: TextInputAccessoryProps) => ( + + )} + endAccessory={(props: TextInputAccessoryProps) => ( + {}} /> + )} + /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('fires onPress on TextInput.Icon end accessory', () => { +it('fires onPress on TextInput.Icon end accessory', async () => { const onClear = jest.fn<(event: GestureResponderEvent) => void>(); - const { getAllByTestId } = render( + await render( { /> ); - fireEvent.press(getAllByTestId('icon-button')[1]); + await userEvent.press(screen.getAllByTestId('icon-button')[1]); expect(onClear).toHaveBeenCalledTimes(1); }); -it('disables TextInput.Icon when the field is disabled', () => { - const { getAllByTestId } = render( +it('disables TextInput.Icon when the field is disabled', async () => { + await render( { /> ); - const buttons = getAllByTestId('icon-button'); + const buttons = screen.getAllByTestId('icon-button'); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(buttons[0].props.accessibilityState?.disabled).toBe(true); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(buttons[1].props.accessibilityState?.disabled).toBe(true); }); -it('does not disable TextInput.Icon when the field is read-only (editable false)', () => { - const { getAllByTestId } = render( +it('does not disable TextInput.Icon when the field is read-only (editable false)', async () => { + await render( ); - const buttons = getAllByTestId('icon-button'); + const buttons = screen.getAllByTestId('icon-button'); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(buttons[0].props.accessibilityState?.disabled).not.toBe(true); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(buttons[1].props.accessibilityState?.disabled).not.toBe(true); }); -it('renders supporting text below the field', () => { - const { getByText } = render( +it('renders supporting text below the field', async () => { + await render( { /> ); - expect(getByText('Use a valid address')).toBeTruthy(); + expect( + screen.getByText('Use a valid address', includeHiddenElements) + ).toBeOnTheScreen(); }); -it('uses polite aria-live on error supporting text', () => { - const { getByText, getByTestId } = render( +it('uses polite aria-live on error supporting text', async () => { + await render( { /> ); - expect(getByText('Invalid').props['aria-live']).toBe('polite'); - expect(getByTestId('tf-input').props.accessibilityState?.invalid).toBe(true); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByText('Invalid').props['aria-live']).toBe('polite'); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('tf-input').props.accessibilityState?.invalid).toBe( + true + ); }); -it('marks the input invalid when error is true without supporting text', () => { - const { getByTestId } = render( +it('marks the input invalid when error is true without supporting text', async () => { + await render( { /> ); - expect(getByTestId('tf-input').props.accessibilityState?.invalid).toBe(true); - expect(getByTestId('tf-input').props.accessibilityHint).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('tf-input').props.accessibilityState?.invalid).toBe( + true + ); + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('tf-input').props.accessibilityHint + ).toBeUndefined(); }); -it('hides helper supporting text from the accessibility tree and omits aria-live', () => { - const { getByText, getByTestId } = render( +it('hides helper supporting text from the accessibility tree and omits aria-live', async () => { + await render( ); - expect(getByText('Optional').props['aria-hidden']).toBe(true); - expect(getByText('Optional').props['aria-live']).toBeUndefined(); - expect(getByTestId('tf-input').props['aria-label']).toBe('Email, Optional'); + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByText('Optional', includeHiddenElements).props['aria-hidden'] + ).toBe(true); + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByText('Optional', includeHiddenElements).props['aria-live'] + ).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('tf-input').props['aria-label']).toBe( + 'Email, Optional' + ); }); -it('includes supporting text in aria-label when label is omitted', () => { - const { getByTestId } = render( +it('includes supporting text in aria-label when label is omitted', async () => { + await render( {}} @@ -292,11 +343,14 @@ it('includes supporting text in aria-label when label is omitted', () => { /> ); - expect(getByTestId('tf-input').props['aria-label']).toBe('Helper only'); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('tf-input').props['aria-label']).toBe( + 'Helper only' + ); }); -it('does not mark the input as aria-disabled when editable is false (read-only)', () => { - const { getByTestId } = render( +it('does not mark the input as aria-disabled when editable is false (read-only)', async () => { + await render( ); - expect(getByTestId('tf-input').props.accessibilityState?.disabled).not.toBe( - true - ); + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('tf-input').props.accessibilityState?.disabled + ).not.toBe(true); }); -it('marks the input as disabled in accessibilityState when disabled is true', () => { - const { getByTestId } = render( +it('marks the input as disabled in accessibilityState when disabled is true', async () => { + await render( ); - expect(getByTestId('tf-input').props.accessibilityState?.disabled).toBe(true); + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('tf-input').props.accessibilityState?.disabled + ).toBe(true); }); -it('renders the input via render with merged props', () => { +it('renders the input via render with merged props', async () => { const renderInput = jest.fn((props: TextInputRenderProps) => ( )); - const { getByTestId } = render( + await render( { /> ); - expect(getByTestId('custom-input')).toBeTruthy(); + expect(screen.getByTestId('custom-input')).toBeOnTheScreen(); expect(renderInput).toHaveBeenCalled(); const merged = renderInput.mock.calls[0]?.[0] as TextInputRenderProps; expect(merged['aria-label']).toBe('Pin'); expect(merged.value).toBe('12'); }); -it('does not apply disabled opacity to the TextInput when editable is false (filled)', () => { - const { getByTestId } = render( +it('does not apply disabled opacity to the TextInput when editable is false (filled)', async () => { + await render( ); - expect( - StyleSheet.flatten(getByTestId('tf-input-ro').props.style) - ).not.toMatchObject({ opacity: stateOpacity.disabled }); + expect(screen.getByTestId('tf-input-ro')).not.toHaveStyle({ + opacity: stateOpacity.disabled, + }); }); -it('does not apply disabled opacity to the TextInput when editable is false (outlined)', () => { - const { getByTestId } = render( +it('does not apply disabled opacity to the TextInput when editable is false (outlined)', async () => { + await render( ); - expect( - StyleSheet.flatten(getByTestId('tf-input-ro-out').props.style) - ).not.toMatchObject({ opacity: stateOpacity.disabled }); + expect(screen.getByTestId('tf-input-ro-out')).not.toHaveStyle({ + opacity: stateOpacity.disabled, + }); }); -it('applies disabled opacity to the TextInput when disabled is true (filled)', () => { - const { getByTestId } = render( +it('applies disabled opacity to the TextInput when disabled is true (filled)', async () => { + await render( ); - expect( - StyleSheet.flatten(getByTestId('tf-input-dis').props.style) - ).toMatchObject({ opacity: stateOpacity.disabled }); + expect(screen.getByTestId('tf-input-dis')).toHaveStyle({ + opacity: stateOpacity.disabled, + }); }); -it('applies disabled opacity to the TextInput when disabled is true (outlined)', () => { - const { getByTestId } = render( +it('applies disabled opacity to the TextInput when disabled is true (outlined)', async () => { + await render( ); - expect( - StyleSheet.flatten(getByTestId('tf-input-dis-out').props.style) - ).toMatchObject({ opacity: stateOpacity.disabled }); + expect(screen.getByTestId('tf-input-dis-out')).toHaveStyle({ + opacity: stateOpacity.disabled, + }); }); -it('forwards TextInput props such as testID', () => { - const { getByTestId } = render( +it('forwards TextInput props such as testID', async () => { + await render( { /> ); - expect(getByTestId('email-input')).toBeTruthy(); + expect(screen.getByTestId('email-input')).toBeOnTheScreen(); }); /* TextInput peels these before spreading onto TextInput (see TextInput.tsx). * Custom layout / sub-component styling props are intentionally not supported. */ -it('does not pass TextInput-only props through to TextInput', () => { - const { getByTestId } = render( +it('does not pass TextInput-only props through to TextInput', async () => { + await render( { /> ); - const input = getByTestId('tf-native'); + const input = screen.getByTestId('tf-native'); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.variant).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.theme).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.startAccessory).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.endAccessory).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.label).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.supportingText).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.prefix).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.suffix).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.counter).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.error).toBeUndefined(); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.disabled).toBeUndefined(); }); -it('shows a character counter when counter is true and maxLength is set (filled)', () => { - const { getByText, queryByText } = render( +it('shows a character counter when counter is true and maxLength is set (filled)', async () => { + await render( ); - expect(getByText('5/100')).toBeTruthy(); - expect(queryByText('0/100')).toBeNull(); + expect(screen.getByText('5/100')).toBeOnTheScreen(); + expect(screen.queryByText('0/100')).not.toBeOnTheScreen(); }); -it('shows a character counter when counter is true and maxLength is set (outlined)', () => { - const { getByText } = render( +it('shows a character counter when counter is true and maxLength is set (outlined)', async () => { + await render( ); - expect(getByText('0/50')).toBeTruthy(); + expect(screen.getByText('0/50')).toBeOnTheScreen(); }); -it('updates the character counter when the value changes', () => { - const { getByText, rerender } = render( +it('updates the character counter when the value changes', async () => { + const { rerender } = await render( { /> ); - expect(getByText('1/10')).toBeTruthy(); + expect(screen.getByText('1/10')).toBeOnTheScreen(); - rerender( + await rerender( { /> ); - expect(getByText('4/10')).toBeTruthy(); + expect(screen.getByText('4/10')).toBeOnTheScreen(); }); -it('does not show a character counter when counter is false', () => { - const { queryByText } = render( +it('does not show a character counter when counter is false', async () => { + await render( { /> ); - expect(queryByText('5/100')).toBeNull(); + expect(screen.queryByText('5/100')).not.toBeOnTheScreen(); }); -it('does not show a character counter when maxLength is missing', () => { - const { queryByText } = render( +it('does not show a character counter when maxLength is missing', async () => { + await render( {}} counter /> ); - expect(queryByText('5/100')).toBeNull(); - expect(queryByText(/\//)).toBeNull(); + expect(screen.queryByText('5/100')).not.toBeOnTheScreen(); + expect(screen.queryByText(/\//)).not.toBeOnTheScreen(); }); -it('invokes onFocus and onBlur on the TextInput', () => { +it('invokes onFocus and onBlur on the TextInput', async () => { const onFocus = jest.fn(); const onBlur = jest.fn(); - const { getByTestId } = render( + await render( { /> ); - const input = getByTestId('tf-input'); - fireEvent(input, 'focus'); - fireEvent(input, 'blur'); + const input = screen.getByTestId('tf-input'); + await fireEvent(input, 'focus'); + await fireEvent(input, 'blur'); expect(onFocus).toHaveBeenCalledTimes(1); expect(onBlur).toHaveBeenCalledTimes(1); }); -it('focuses the TextInput when the outer Pressable is pressed', () => { +it('focuses the TextInput when the outer Pressable is pressed', async () => { const focusSpy = jest.spyOn(NativeTextInput.prototype, 'focus'); - const { UNSAFE_getByProps, getByTestId } = render( + const { root } = await render( { /> ); - expect(getByTestId('tf-input')).toBeTruthy(); + expect(screen.getByTestId('tf-input')).toBeOnTheScreen(); - /* Pressable is not exposed as a distinct type in the test renderer; match its props. */ - const pressable = UNSAFE_getByProps({ role: 'none', accessible: false }); - fireEvent.press(pressable); + await userEvent.press(getOuterTextInputPressable(root)); expect(focusSpy).toHaveBeenCalled(); focusSpy.mockRestore(); }); -it('does not focus the TextInput when disabled and the Pressable is pressed', () => { +it('does not focus the TextInput when disabled and the Pressable is pressed', async () => { const focusSpy = jest.spyOn(NativeTextInput.prototype, 'focus'); - const { UNSAFE_getByProps } = render( + const { root } = await render( {}} disabled /> ); - const pressable = UNSAFE_getByProps({ role: 'none', accessible: false }); - fireEvent.press(pressable); + await userEvent.press(getOuterTextInputPressable(root)); expect(focusSpy).not.toHaveBeenCalled(); focusSpy.mockRestore(); }); -it('focuses the TextInput when read-only and the Pressable is pressed', () => { +it('focuses the TextInput when read-only and the Pressable is pressed', async () => { const focusSpy = jest.spyOn(NativeTextInput.prototype, 'focus'); - const { UNSAFE_getByProps } = render( + const { root } = await render( { /> ); - const pressable = UNSAFE_getByProps({ role: 'none', accessible: false }); - fireEvent.press(pressable); + await userEvent.press(getOuterTextInputPressable(root)); expect(focusSpy).toHaveBeenCalled(); focusSpy.mockRestore(); }); -it('exposes the TextInput instance via ref prop', () => { +it('exposes the TextInput instance via ref prop', async () => { const ref = React.createRef(); - render( + await render( { expect(typeof ref.current?.setSelection).toBe('function'); }); -it('passes error, disabled, and multiline to accessories', () => { +it('passes error, disabled, and multiline to accessories', async () => { const startAccessoryProps: TextInputAccessoryProps[] = []; const endAccessoryProps: TextInputAccessoryProps[] = []; @@ -645,7 +710,7 @@ it('passes error, disabled, and multiline to accessories', () => { return ; } - const { getByTestId } = render( + await render( { /> ); - expect(getByTestId('start-accessory')).toBeTruthy(); - expect(getByTestId('end-accessory')).toBeTruthy(); + expect(screen.getByTestId('start-accessory')).toBeOnTheScreen(); + expect(screen.getByTestId('end-accessory')).toBeOnTheScreen(); expect(startAccessoryProps[0]).toMatchObject({ error: true, disabled: true, @@ -672,7 +737,7 @@ it('passes error, disabled, and multiline to accessories', () => { }); }); -it('passes error to accessories when the field is disabled', () => { +it('passes error to accessories when the field is disabled', async () => { const startAccessoryProps: TextInputAccessoryProps[] = []; function StartAccessory(props: TextInputAccessoryProps) { @@ -680,7 +745,7 @@ it('passes error to accessories when the field is disabled', () => { return ; } - const { getByTestId } = render( + await render( { /> ); - expect(getByTestId('start-acc-error-disabled')).toBeTruthy(); + expect(screen.getByTestId('start-acc-error-disabled')).toBeOnTheScreen(); expect(startAccessoryProps[0].error).toBe(true); expect(startAccessoryProps[0].disabled).toBe(true); }); -it('renders supporting text as a Text child', () => { - const { getByText } = render( +it('renders supporting text as a Text child', async () => { + await render( { /> ); - expect(getByText('Hint')).toBeTruthy(); + expect(screen.getByText('Hint', includeHiddenElements)).toBeOnTheScreen(); }); -it('renders the counter as a Text child', () => { - const { getByText } = render( +it('renders the counter as a Text child', async () => { + await render( { /> ); - expect(getByText('2/80')).toBeTruthy(); + expect(screen.getByText('2/80')).toBeOnTheScreen(); }); -it('renders supporting text and counter separately when both are shown', () => { - const { getByText } = render( +it('renders supporting text and counter separately when both are shown', async () => { + await render( { /> ); - expect(getByText('Help text')).toBeTruthy(); - expect(getByText('1/10')).toBeTruthy(); + expect( + screen.getByText('Help text', includeHiddenElements) + ).toBeOnTheScreen(); + expect(screen.getByText('1/10')).toBeOnTheScreen(); }); -it('applies RTL text alignment and writing direction to the TextInput (filled)', () => { +it('applies RTL text alignment and writing direction to the TextInput (filled)', async () => { I18nManager.isRTL = true; - const { getByTestId } = render( + await render( ); - expect(StyleSheet.flatten(getByTestId('tf-input-rtl').props.style)).toEqual( - expect.objectContaining({ - textAlign: 'right', - writingDirection: 'rtl', - }) - ); + expect(screen.getByTestId('tf-input-rtl')).toHaveStyle({ + textAlign: 'right', + writingDirection: 'rtl', + }); }); -it('applies RTL text alignment and writing direction to the TextInput (outlined)', () => { +it('applies RTL text alignment and writing direction to the TextInput (outlined)', async () => { I18nManager.isRTL = true; - const { getByTestId } = render( + await render( ); - expect( - StyleSheet.flatten(getByTestId('tf-input-rtl-outlined').props.style) - ).toEqual( - expect.objectContaining({ - textAlign: 'right', - writingDirection: 'rtl', - }) - ); + expect(screen.getByTestId('tf-input-rtl-outlined')).toHaveStyle({ + textAlign: 'right', + writingDirection: 'rtl', + }); }); -it('applies RTL writing direction to supporting text', () => { +it('applies RTL writing direction to supporting text', async () => { I18nManager.isRTL = true; - const { getByText } = render( + await render( { /> ); - expect(StyleSheet.flatten(getByText('Hint').props.style)).toEqual( - expect.objectContaining({ - writingDirection: 'rtl', - }) - ); + expect(screen.getByText('Hint', includeHiddenElements)).toHaveStyle({ + writingDirection: 'rtl', + }); }); -it('places EndAccessory before StartAccessory in the tree when RTL', () => { +it('places EndAccessory before StartAccessory in the tree when RTL', async () => { I18nManager.isRTL = true; function StartAccessory() { @@ -812,7 +871,7 @@ it('places EndAccessory before StartAccessory in the tree when RTL', () => { return ; } - const { toJSON } = render( + const { toJSON } = await render( { ); }); -it('places StartAccessory before EndAccessory in the tree when LTR', () => { +it('places StartAccessory before EndAccessory in the tree when LTR', async () => { I18nManager.isRTL = false; function StartAccessory() { @@ -840,7 +899,7 @@ it('places StartAccessory before EndAccessory in the tree when LTR', () => { return ; } - const { toJSON } = render( + const { toJSON } = await render( { ).toBeLessThan(firstIndexOfTestIdInTree(tree, 'ltr-acc-from-end-prop')); }); -it('does not expose the placeholder string when the TextInput is not focused', () => { - const { getByTestId } = render( +it('does not expose the placeholder string when the TextInput is not focused', async () => { + await render( { - const { getByTestId } = render( +it('shows placeholder when unfocused and no label is given', async () => { + await render( {}} @@ -882,11 +942,14 @@ it('shows placeholder when unfocused and no label is given', () => { /> ); - expect(getByTestId('tf-input-no-label').props.placeholder).toBe('Search'); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('tf-input-no-label').props.placeholder).toBe( + 'Search' + ); }); -it('shows placeholder when the TextInput is focused', () => { - const { getByTestId } = render( +it('shows placeholder when the TextInput is focused', async () => { + await render( { /> ); - fireEvent(getByTestId('tf-input'), 'focus'); + await fireEvent(screen.getByTestId('tf-input'), 'focus'); - expect(getByTestId('tf-input').props.placeholder).toBe( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('tf-input').props.placeholder).toBe( 'e.g. user@example.com' ); }); -it('shows placeholder on multiline TextInput when focused', () => { - const { getByTestId } = render( +it('shows placeholder on multiline TextInput when focused', async () => { + await render( { /> ); - expect(getByTestId('tf-multiline').props.placeholder).toBe(' '); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('tf-multiline').props.placeholder).toBe(' '); - fireEvent(getByTestId('tf-multiline'), 'focus'); + await fireEvent(screen.getByTestId('tf-multiline'), 'focus'); - expect(getByTestId('tf-multiline').props.placeholder).toBe('Add a note…'); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('tf-multiline').props.placeholder).toBe( + 'Add a note…' + ); }); -it('does not expose the placeholder string again after the TextInput loses focus', () => { - const { getByTestId } = render( +it('does not expose the placeholder string again after the TextInput loses focus', async () => { + await render( ); - fireEvent(getByTestId('tf-input'), 'focus'); - fireEvent(getByTestId('tf-input'), 'blur'); + await fireEvent(screen.getByTestId('tf-input'), 'focus'); + await fireEvent(screen.getByTestId('tf-input'), 'blur'); - expect(getByTestId('tf-input').props.placeholder).toBe(' '); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('tf-input').props.placeholder).toBe(' '); }); -it('maps a lone StartAccessory to leading in LTR and trailing in RTL (tree order)', () => { +it('maps a lone StartAccessory to leading in LTR and trailing in RTL (tree order)', async () => { function LoneStartAccessory() { return ; } I18nManager.isRTL = false; - const { toJSON: toJsonLtr } = render( + const { toJSON: toJsonLtr } = await render( { - const { getByTestId, getByText, queryByText, rerender } = render( +it('shows prefix and suffix when the field is floating and hides them after value is cleared while blurred', async () => { + const { rerender } = await render( ); - expect(getByText('$')).toBeTruthy(); - expect(getByText('/100')).toBeTruthy(); + expect(screen.getByText('$')).toBeOnTheScreen(); + expect(screen.getByText('/100')).toBeOnTheScreen(); - rerender( + await rerender( ); - expect(queryByText('$')).toBeNull(); - expect(queryByText('/100')).toBeNull(); - expect(getByTestId('tf-ps')).toBeTruthy(); + expect(screen.queryByText('$')).not.toBeOnTheScreen(); + expect(screen.queryByText('/100')).not.toBeOnTheScreen(); + expect(screen.getByTestId('tf-ps')).toBeOnTheScreen(); }); -it('renders prefix and suffix while focused even when value is empty', () => { - const { getByTestId, getByText, queryByText } = render( +it('renders prefix and suffix while focused even when value is empty', async () => { + await render( { /> ); - expect(queryByText('$')).toBeNull(); - expect(queryByText(' kg')).toBeNull(); + expect(screen.queryByText('$')).not.toBeOnTheScreen(); + expect(screen.queryByText(' kg')).not.toBeOnTheScreen(); - fireEvent(getByTestId('tf-ps-focus'), 'focus'); + await fireEvent(screen.getByTestId('tf-ps-focus'), 'focus'); - expect(getByText('$')).toBeTruthy(); - expect(getByText(' kg')).toBeTruthy(); + expect(screen.getByText('$')).toBeOnTheScreen(); + expect(screen.getByText(' kg')).toBeOnTheScreen(); }); -it('places prefix Text before the TextInput and suffix Text after it', () => { - const { toJSON } = render( +it('places prefix Text before the TextInput and suffix Text after it', async () => { + const { toJSON } = await render( { ); }); -it('aligns input text toward the suffix when suffix is active (LTR)', () => { - const { getByTestId } = render( +it('aligns input text toward the suffix when suffix is active (LTR)', async () => { + await render( { /> ); - expect( - StyleSheet.flatten(getByTestId('tf-suffix-align-ltr').props.style) - ).toEqual( - expect.objectContaining({ - textAlign: 'right', - writingDirection: 'ltr', - }) - ); + expect(screen.getByTestId('tf-suffix-align-ltr')).toHaveStyle({ + textAlign: 'right', + writingDirection: 'ltr', + }); }); -it('aligns input text toward the suffix when suffix is active (RTL)', () => { +it('aligns input text toward the suffix when suffix is active (RTL)', async () => { I18nManager.isRTL = true; - const { getByTestId } = render( + await render( { /> ); - expect( - StyleSheet.flatten(getByTestId('tf-suffix-align-rtl').props.style) - ).toEqual( - expect.objectContaining({ - textAlign: 'left', - writingDirection: 'rtl', - }) - ); + expect(screen.getByTestId('tf-suffix-align-rtl')).toHaveStyle({ + textAlign: 'left', + writingDirection: 'rtl', + }); }); -it('uses default horizontal alignment when suffix prop exists but suffix is not shown yet (LTR)', () => { - const { getByTestId } = render( +it('uses default horizontal alignment when suffix prop exists but suffix is not shown yet (LTR)', async () => { + await render( ); - expect( - StyleSheet.flatten(getByTestId('tf-no-suffix-yet').props.style) - ).toEqual( - expect.objectContaining({ - textAlign: 'left', - writingDirection: 'ltr', - }) - ); + expect(screen.getByTestId('tf-no-suffix-yet')).toHaveStyle({ + textAlign: 'left', + writingDirection: 'ltr', + }); }); -it('does not apply the TextInput style prop to prefix or suffix Text', () => { - const { getByTestId, getByText } = render( +it('does not apply the TextInput style prop to prefix or suffix Text', async () => { + await render( { /> ); - const inputFlat = StyleSheet.flatten( - getByTestId('tf-input-style').props.style - ); - expect(inputFlat).toEqual( - expect.objectContaining({ fontSize: 40, letterSpacing: 9 }) - ); - - const prefixFlat = StyleSheet.flatten(getByText('$').props.style); - const suffixFlat = StyleSheet.flatten(getByText(']').props.style); + expect(screen.getByTestId('tf-input-style')).toHaveStyle({ + fontSize: 40, + letterSpacing: 9, + }); - expect(prefixFlat.fontSize).not.toBe(40); - expect(prefixFlat.letterSpacing).toBeUndefined(); - expect(suffixFlat.fontSize).not.toBe(40); - expect(suffixFlat.letterSpacing).toBeUndefined(); + expect(screen.getByText('$')).not.toHaveStyle({ fontSize: 40 }); + expect(screen.getByText('$')).not.toHaveStyle({ letterSpacing: 9 }); + expect(screen.getByText(']')).not.toHaveStyle({ fontSize: 40 }); + expect(screen.getByText(']')).not.toHaveStyle({ letterSpacing: 9 }); }); -it('passes defaultValue to the native input when uncontrolled without counter', () => { - const { getByTestId } = render( +it('passes defaultValue to the native input when uncontrolled without counter', async () => { + await render( ); - const input = getByTestId('tf-uncontrolled'); + const input = screen.getByTestId('tf-uncontrolled'); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.defaultValue).toBe('hello'); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.value).toBeUndefined(); }); -it('updates the character counter for an uncontrolled field with counter enabled', () => { +it('updates the character counter for an uncontrolled field with counter enabled', async () => { const onChangeText = jest.fn(); - const { getByTestId, getByText } = render( + await render( ); - expect(getByText('1/10')).toBeTruthy(); + expect(screen.getByText('1/10')).toBeOnTheScreen(); - fireEvent.changeText(getByTestId('tf-uncontrolled-counter'), 'abcd'); + await userEvent.type(screen.getByTestId('tf-uncontrolled-counter'), 'bcd'); expect(onChangeText).toHaveBeenCalledWith('abcd'); - expect(getByText('4/10')).toBeTruthy(); + expect(screen.getByText('4/10')).toBeOnTheScreen(); }); -it('resets counter and hides prefix/suffix when clear() is called on uncontrolled field while blurred', () => { +it('resets counter and hides prefix/suffix when clear() is called on uncontrolled field while blurred', async () => { const ref = React.createRef(); - const { getByText, queryByText } = render( + await render( ); - expect(getByText('3/200')).toBeTruthy(); - expect(getByText('$')).toBeTruthy(); - expect(getByText('/100')).toBeTruthy(); + expect(screen.getByText('3/200')).toBeOnTheScreen(); + expect(screen.getByText('$')).toBeOnTheScreen(); + expect(screen.getByText('/100')).toBeOnTheScreen(); - act(() => { + await act(() => { ref.current?.clear(); }); - expect(getByText('0/200')).toBeTruthy(); - expect(queryByText('$')).toBeNull(); - expect(queryByText('/100')).toBeNull(); + expect(screen.getByText('0/200', includeHiddenElements)).toBeOnTheScreen(); + expect(screen.queryByText('$')).not.toBeOnTheScreen(); + expect(screen.queryByText('/100')).not.toBeOnTheScreen(); }); -it('resets counter but keeps prefix/suffix visible when clear() is called on uncontrolled field while focused', () => { +it('resets counter but keeps prefix/suffix visible when clear() is called on uncontrolled field while focused', async () => { const ref = React.createRef(); - const { getByTestId, getByText } = render( + await render( ); - expect(getByText('2/100')).toBeTruthy(); - expect(getByText('$')).toBeTruthy(); - expect(getByText(' kg')).toBeTruthy(); + expect(screen.getByText('2/100', includeHiddenElements)).toBeOnTheScreen(); + expect(screen.getByText('$', includeHiddenElements)).toBeOnTheScreen(); + expect(screen.getByText(' kg', includeHiddenElements)).toBeOnTheScreen(); - fireEvent(getByTestId('tf-clear-focused'), 'focus'); + await fireEvent(screen.getByTestId('tf-clear-focused'), 'focus'); - act(() => { + await act(() => { ref.current?.clear(); }); - expect(getByText('0/100')).toBeTruthy(); - expect(getByText('$')).toBeTruthy(); - expect(getByText(' kg')).toBeTruthy(); + expect(screen.getByText('0/100', includeHiddenElements)).toBeOnTheScreen(); + expect(screen.getByText('$', includeHiddenElements)).toBeOnTheScreen(); + expect(screen.getByText(' kg', includeHiddenElements)).toBeOnTheScreen(); }); -it('notifies the parent via onChangeText when clear() is called on a controlled field', () => { +it('notifies the parent via onChangeText when clear() is called on a controlled field', async () => { const ref = React.createRef(); const onChangeText = jest.fn(); - const { getByTestId } = render( + await render( ); - const input = getByTestId('tf-controlled'); + const input = screen.getByTestId('tf-controlled', includeHiddenElements); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. expect(input.props.value).toBe('test@example.com'); - act(() => { + await act(() => { ref.current?.clear(); }); @@ -1263,9 +1318,9 @@ it('notifies the parent via onChangeText when clear() is called on a controlled expect(onChangeText).toHaveBeenCalledTimes(1); }); -it('hides prefix/suffix when blurring after clear() was called while focused', () => { +it('hides prefix/suffix when blurring after clear() was called while focused', async () => { const ref = React.createRef(); - const { getByTestId, getByText, queryByText } = render( + await render( ); - expect(getByText('$')).toBeTruthy(); - expect(getByText('/100')).toBeTruthy(); + expect(screen.getByText('$', includeHiddenElements)).toBeOnTheScreen(); + expect(screen.getByText('/100', includeHiddenElements)).toBeOnTheScreen(); - fireEvent(getByTestId('tf-clear-then-blur'), 'focus'); + await fireEvent(screen.getByTestId('tf-clear-then-blur'), 'focus'); - act(() => { + await act(() => { ref.current?.clear(); }); // While focused, prefix/suffix stay visible - expect(getByText('$')).toBeTruthy(); - expect(getByText('/100')).toBeTruthy(); + expect(screen.getByText('$', includeHiddenElements)).toBeOnTheScreen(); + expect(screen.getByText('/100', includeHiddenElements)).toBeOnTheScreen(); - fireEvent(getByTestId('tf-clear-then-blur'), 'blur'); + await fireEvent(screen.getByTestId('tf-clear-then-blur'), 'blur'); // After blur with no text, prefix/suffix should be hidden - expect(queryByText('$')).toBeNull(); - expect(queryByText('/100')).toBeNull(); + expect(screen.queryByText('$')).not.toBeOnTheScreen(); + expect(screen.queryByText('/100')).not.toBeOnTheScreen(); }); diff --git a/src/components/__tests__/ToggleButton.test.tsx b/src/components/__tests__/ToggleButton.test.tsx index 994b976523..1ea9e20bae 100644 --- a/src/components/__tests__/ToggleButton.test.tsx +++ b/src/components/__tests__/ToggleButton.test.tsx @@ -4,29 +4,33 @@ import { describe, expect, it, jest } from '@jest/globals'; import { act } from '@testing-library/react-native'; import { getTheme } from '../../core/theming'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import ToggleButton from '../ToggleButton'; import { getToggleButtonColor } from '../ToggleButton/utils'; -it('renders toggle button', () => { - const tree = render( - {}} icon="heart" /> +it('renders toggle button', async () => { + const tree = ( + await render( + {}} icon="heart" /> + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders disabled toggle button', () => { - const tree = render( - +it('renders disabled toggle button', async () => { + const tree = ( + await render( + + ) ).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders unchecked toggle button', () => { - const tree = render( - +it('renders unchecked toggle button', async () => { + const tree = ( + await render() ).toJSON(); expect(tree).toMatchSnapshot(); @@ -52,9 +56,9 @@ describe('getToggleButtonColor', () => { }); }); -it('animated value changes correctly', () => { +it('animated value changes correctly', async () => { const value = new Animated.Value(1); - const { getByTestId } = render( + await render( { style={[{ transform: [{ scale: value }] }]} /> ); - expect(getByTestId('toggle-button-container-outer-layer')).toHaveStyle({ - transform: [{ scale: 1 }], - }); + expect(screen.getByTestId('toggle-button-container-outer-layer')).toHaveStyle( + { + transform: [{ scale: 1 }], + } + ); Animated.timing(value, { toValue: 1.5, @@ -73,10 +79,12 @@ it('animated value changes correctly', () => { duration: 200, }).start(); - act(() => { + await act(() => { jest.advanceTimersByTime(200); }); - expect(getByTestId('toggle-button-container-outer-layer')).toHaveStyle({ - transform: [{ scale: 1.5 }], - }); + expect(screen.getByTestId('toggle-button-container-outer-layer')).toHaveStyle( + { + transform: [{ scale: 1.5 }], + } + ); }); diff --git a/src/components/__tests__/Tooltip.test.tsx b/src/components/__tests__/Tooltip.test.tsx index 62666e9d7c..75b4a18cf7 100644 --- a/src/components/__tests__/Tooltip.test.tsx +++ b/src/components/__tests__/Tooltip.test.tsx @@ -11,8 +11,7 @@ import { it, jest, } from '@jest/globals'; -import { act, fireEvent } from '@testing-library/react-native'; -import type { ReactTestInstance } from 'react-test-renderer'; +import { act, fireEvent, userEvent } from '@testing-library/react-native'; import PaperProvider from '../../core/PaperProvider'; import { render } from '../../test-utils'; @@ -38,11 +37,22 @@ const DummyComponent = ({ ); describe('Tooltip', () => { - const getTrigger = (getByText: (text: string) => ReactTestInstance) => - getByText('dummy component').parent as ReactTestInstance; + const getTrigger = ( + getByText: Awaited>['getByText'] + ) => { + const trigger = getByText('dummy component', { + includeHiddenElements: true, + }).parent; + + if (!trigger) { + throw new Error('Expected Tooltip trigger wrapper'); + } - const runTimers = (ms?: number) => { - act(() => { + return trigger; + }; + + const runTimers = async (ms?: number) => { + await act(() => { if (ms === undefined) { jest.runOnlyPendingTimers(); } else { @@ -51,7 +61,7 @@ describe('Tooltip', () => { }); }; - const setup = ( + const setup = async ( propOverrides?: Partial>, measure = {} ) => { @@ -75,7 +85,7 @@ describe('Tooltip', () => { .spyOn(View.prototype, 'measure') .mockImplementation((cb) => cb(x, y, width, height, pageX, pageY)); - const wrapper = render( + const wrapper = await render( @@ -102,11 +112,11 @@ describe('Tooltip', () => { it('removes hideTooltipTimer when the component unmounts', async () => { const { wrapper: { getByText, unmount }, - } = setup({ enterTouchDelay: 5000 }); + } = await setup({ enterTouchDelay: 5000 }); - fireEvent(getTrigger(getByText), 'pressOut'); + await fireEvent(getTrigger(getByText), 'pressOut'); - unmount(); + await unmount(); expect(global.clearTimeout).toHaveBeenCalledTimes(1); }); @@ -114,13 +124,13 @@ describe('Tooltip', () => { it('removes Dimensions listener when the component unmount', async () => { const { wrapper: { getByText, findByText, unmount }, - } = setup(); + } = await setup(); - fireEvent(getTrigger(getByText), 'longPress'); + await userEvent.longPress(getTrigger(getByText)); await findByText('some tooltip text'); - unmount(); + await unmount(); expect(mockedRemoveEventListener).toHaveBeenCalled(); }); @@ -134,37 +144,34 @@ describe('Tooltip', () => { jest.clearAllMocks(); }); - it('clears the hide timer when the user start pressing the component again', () => { + it('clears the hide timer when the user start pressing the component again', async () => { jest.spyOn(global, 'clearTimeout'); const { wrapper: { getByText }, - } = setup(); + } = await setup(); const trigger = getTrigger(getByText); - fireEvent(trigger, 'longPress'); - fireEvent(trigger, 'pressOut'); - fireEvent(trigger, 'longPress'); + await userEvent.longPress(trigger); + await userEvent.longPress(trigger); expect(global.clearTimeout).toHaveBeenCalledTimes(1); }); }); describe('pressOut', () => { - // eslint-disable-next-line jest/valid-title it('hides the tooltip when the user stop pressing the component', async () => { const { wrapper: { queryByText, getByText, findByText }, - } = setup({ enterTouchDelay: 50, leaveTouchDelay: 0 }); + } = await setup({ enterTouchDelay: 50, leaveTouchDelay: 0 }); - fireEvent(getTrigger(getByText), 'longPress'); + await userEvent.longPress(getTrigger(getByText)); await findByText('some tooltip text'); - fireEvent(getTrigger(getByText), 'pressOut'); - runTimers(); + await runTimers(); - expect(queryByText('some tooltip text')).toBeNull(); + expect(queryByText('some tooltip text')).not.toBeOnTheScreen(); }); }); @@ -187,23 +194,20 @@ describe('Tooltip', () => { it('centers the tooltip in the middle of the children component', async () => { const { wrapper: { getByText, getByTestId, findByText }, - } = setup(); + } = await setup(); - fireEvent(getTrigger(getByText), 'longPress'); + await userEvent.longPress(getTrigger(getByText)); - fireEvent(await findByText('some tooltip text'), 'layout', { + await fireEvent(await findByText('some tooltip text'), 'layout', { nativeEvent: { layout: { width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT }, }, }); - expect(getByTestId('tooltip-container').props.style).toMatchObject([ - {}, - { - left: 210, // pageX (220) + (width (80) - TOOLTIP_WIDTH (100)) / 2 = 210 - top: 250, // pageY (200) + height (50) - }, - ]); + expect(getByTestId('tooltip-container')).toHaveStyle({ + left: 210, // pageX (220) + (width (80) - TOOLTIP_WIDTH (100)) / 2 = 210 + top: 250, // pageY (200) + height (50) + }); }); }); @@ -211,23 +215,20 @@ describe('Tooltip', () => { it('renders the tooltip with the right placement', async () => { const { wrapper: { getByText, getByTestId, findByText }, - } = setup({}, { pageX: 0 }); // Component starting at the starting 0 X coord + } = await setup({}, { pageX: 0 }); // Component starting at the starting 0 X coord - fireEvent(getTrigger(getByText), 'longPress'); + await userEvent.longPress(getTrigger(getByText)); - fireEvent(await findByText('some tooltip text'), 'layout', { + await fireEvent(await findByText('some tooltip text'), 'layout', { nativeEvent: { layout: { width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT }, }, }); - expect(getByTestId('tooltip-container').props.style).toMatchObject([ - {}, - { - left: 0, // Tooltip renders starting from children's x coord - top: 250, - }, - ]); + expect(getByTestId('tooltip-container')).toHaveStyle({ + left: 0, // Tooltip renders starting from children's x coord + top: 250, + }); }); }); @@ -235,23 +236,20 @@ describe('Tooltip', () => { it('renders the tooltip with the right placement', async () => { const { wrapper: { getByText, getByTestId, findByText }, - } = setup({}, { pageX: 900, width: 150 }); // Component close to the screen limit + } = await setup({}, { pageX: 900, width: 150 }); // Component close to the screen limit - fireEvent(getTrigger(getByText), 'longPress'); + await userEvent.longPress(getTrigger(getByText)); - fireEvent(await findByText('some tooltip text'), 'layout', { + await fireEvent(await findByText('some tooltip text'), 'layout', { nativeEvent: { layout: { width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT }, }, }); - expect(getByTestId('tooltip-container').props.style).toMatchObject([ - {}, - { - left: 950, // pageX (900) + width (150) - 100 (TOOLTIP_WIDTH) // Tooltip is placed from right to left without going offscreen - top: 250, - }, - ]); + expect(getByTestId('tooltip-container')).toHaveStyle({ + left: 950, // pageX (900) + width (150) - 100 (TOOLTIP_WIDTH) // Tooltip is placed from right to left without going offscreen + top: 250, + }); }); }); @@ -259,23 +257,20 @@ describe('Tooltip', () => { it('renders the tooltip with the right placement', async () => { const { wrapper: { getByText, getByTestId, findByText }, - } = setup({}, { pageY: 600, height: 50 }); + } = await setup({}, { pageY: 600, height: 50 }); - fireEvent(getTrigger(getByText), 'longPress'); + await userEvent.longPress(getTrigger(getByText)); - fireEvent(await findByText('some tooltip text'), 'layout', { + await fireEvent(await findByText('some tooltip text'), 'layout', { nativeEvent: { layout: { width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT }, }, }); - expect(getByTestId('tooltip-container').props.style).toMatchObject([ - {}, - { - left: 210, - top: 500, // pageY (600) - TOOLTIP_HEIGHT (100) // Tooltip is placed at the top of the component, - }, - ]); + expect(getByTestId('tooltip-container')).toHaveStyle({ + left: 210, + top: 500, // pageY (600) - TOOLTIP_HEIGHT (100) // Tooltip is placed at the top of the component, + }); }); }); }); @@ -296,11 +291,11 @@ describe('Tooltip', () => { it('removes showTooltipTimer when the component unmounts', async () => { const { wrapper: { getByText, unmount }, - } = setup({ enterTouchDelay: 5000 }); + } = await setup({ enterTouchDelay: 5000 }); - fireEvent(getTrigger(getByText), 'hoverIn'); + await fireEvent(getTrigger(getByText), 'hoverIn'); - unmount(); + await unmount(); expect(global.clearTimeout).toHaveBeenCalledTimes(1); }); @@ -308,11 +303,11 @@ describe('Tooltip', () => { it('removes hideTooltipTimer when the component unmounts', async () => { const { wrapper: { getByText, unmount }, - } = setup({ enterTouchDelay: 5000 }); + } = await setup({ enterTouchDelay: 5000 }); - fireEvent(getTrigger(getByText), 'hoverOut'); + await fireEvent(getTrigger(getByText), 'hoverOut'); - unmount(); + await unmount(); expect(global.clearTimeout).toHaveBeenCalledTimes(1); }); @@ -320,14 +315,14 @@ describe('Tooltip', () => { it('removes Dimensions listener when the component unmount', async () => { const { wrapper: { getByText, findByText, unmount }, - } = setup(); + } = await setup(); - fireEvent(getTrigger(getByText), 'hoverIn'); - runTimers(500); + await fireEvent(getTrigger(getByText), 'hoverIn'); + await runTimers(500); await findByText('some tooltip text'); - unmount(); + await unmount(); expect(mockedRemoveEventListener).toHaveBeenCalled(); }); @@ -341,38 +336,37 @@ describe('Tooltip', () => { jest.clearAllMocks(); }); - it('clears the hide timer when the user start hovering the component again', () => { + it('clears the hide timer when the user start hovering the component again', async () => { jest.spyOn(global, 'clearTimeout'); const { wrapper: { getByText }, - } = setup(); + } = await setup(); const trigger = getTrigger(getByText); - fireEvent(trigger, 'hoverIn'); - fireEvent(trigger, 'hoverOut'); - fireEvent(trigger, 'hoverIn'); + await fireEvent(trigger, 'hoverIn'); + await fireEvent(trigger, 'hoverOut'); + await fireEvent(trigger, 'hoverIn'); expect(global.clearTimeout).toHaveBeenCalledTimes(2); }); }); describe('hoverOut', () => { - // eslint-disable-next-line jest/valid-title it('hides the tooltip when the user stops hovering the component', async () => { const { wrapper: { queryByText, getByText, findByText }, - } = setup({ enterTouchDelay: 50, leaveTouchDelay: 0 }); + } = await setup({ enterTouchDelay: 50, leaveTouchDelay: 0 }); - fireEvent(getTrigger(getByText), 'hoverIn'); - runTimers(50); + await fireEvent(getTrigger(getByText), 'hoverIn'); + await runTimers(50); await findByText('some tooltip text'); - fireEvent(getTrigger(getByText), 'hoverOut'); - runTimers(); + await fireEvent(getTrigger(getByText), 'hoverOut'); + await runTimers(); - expect(queryByText('some tooltip text')).toBeNull(); + expect(queryByText('some tooltip text')).not.toBeOnTheScreen(); }); }); @@ -395,24 +389,21 @@ describe('Tooltip', () => { it('centers the tooltip in the middle of the children component', async () => { const { wrapper: { getByText, getByTestId, findByText }, - } = setup(); + } = await setup(); - fireEvent(getTrigger(getByText), 'hoverIn'); - runTimers(500); + await fireEvent(getTrigger(getByText), 'hoverIn'); + await runTimers(500); - fireEvent(await findByText('some tooltip text'), 'layout', { + await fireEvent(await findByText('some tooltip text'), 'layout', { nativeEvent: { layout: { width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT }, }, }); - expect(getByTestId('tooltip-container').props.style).toMatchObject([ - {}, - { - left: 210, // pageX (220) + (width (80) - TOOLTIP_WIDTH (100)) / 2 = 210 - top: 250, // pageY (200) + height (50) - }, - ]); + expect(getByTestId('tooltip-container')).toHaveStyle({ + left: 210, // pageX (220) + (width (80) - TOOLTIP_WIDTH (100)) / 2 = 210 + top: 250, // pageY (200) + height (50) + }); }); }); @@ -420,24 +411,21 @@ describe('Tooltip', () => { it('renders the tooltip with the right placement', async () => { const { wrapper: { getByText, getByTestId, findByText }, - } = setup({}, { pageX: 0 }); // Component starting at the starting 0 X coord + } = await setup({}, { pageX: 0 }); // Component starting at the starting 0 X coord - fireEvent(getTrigger(getByText), 'hoverIn'); - runTimers(500); + await fireEvent(getTrigger(getByText), 'hoverIn'); + await runTimers(500); - fireEvent(await findByText('some tooltip text'), 'layout', { + await fireEvent(await findByText('some tooltip text'), 'layout', { nativeEvent: { layout: { width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT }, }, }); - expect(getByTestId('tooltip-container').props.style).toMatchObject([ - {}, - { - left: 0, // Tooltip renders starting from children's x coord - top: 250, - }, - ]); + expect(getByTestId('tooltip-container')).toHaveStyle({ + left: 0, // Tooltip renders starting from children's x coord + top: 250, + }); }); }); @@ -445,24 +433,21 @@ describe('Tooltip', () => { it('renders the tooltip with the right placement', async () => { const { wrapper: { getByText, getByTestId, findByText }, - } = setup({}, { pageX: 900, width: 150 }); // Component close to the screen limit + } = await setup({}, { pageX: 900, width: 150 }); // Component close to the screen limit - fireEvent(getTrigger(getByText), 'hoverIn'); - runTimers(500); + await fireEvent(getTrigger(getByText), 'hoverIn'); + await runTimers(500); - fireEvent(await findByText('some tooltip text'), 'layout', { + await fireEvent(await findByText('some tooltip text'), 'layout', { nativeEvent: { layout: { width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT }, }, }); - expect(getByTestId('tooltip-container').props.style).toMatchObject([ - {}, - { - left: 950, // pageX (900) + width (150) - 100 (TOOLTIP_WIDTH) // Tooltip is placed from right to left without going offscreen - top: 250, - }, - ]); + expect(getByTestId('tooltip-container')).toHaveStyle({ + left: 950, // pageX (900) + width (150) - 100 (TOOLTIP_WIDTH) // Tooltip is placed from right to left without going offscreen + top: 250, + }); }); }); @@ -470,24 +455,21 @@ describe('Tooltip', () => { it('renders the tooltip with the right placement', async () => { const { wrapper: { getByText, getByTestId, findByText }, - } = setup({}, { pageY: 600, height: 50 }); + } = await setup({}, { pageY: 600, height: 50 }); - fireEvent(getTrigger(getByText), 'hoverIn'); - runTimers(500); + await fireEvent(getTrigger(getByText), 'hoverIn'); + await runTimers(500); - fireEvent(await findByText('some tooltip text'), 'layout', { + await fireEvent(await findByText('some tooltip text'), 'layout', { nativeEvent: { layout: { width: TOOLTIP_WIDTH, height: TOOLTIP_HEIGHT }, }, }); - expect(getByTestId('tooltip-container').props.style).toMatchObject([ - {}, - { - left: 210, - top: 500, // pageY (600) - TOOLTIP_HEIGHT (100) // Tooltip is placed at the top of the component, - }, - ]); + expect(getByTestId('tooltip-container')).toHaveStyle({ + left: 210, + top: 500, // pageY (600) - TOOLTIP_HEIGHT (100) // Tooltip is placed at the top of the component, + }); }); }); }); diff --git a/src/components/__tests__/TouchableRipple.test.tsx b/src/components/__tests__/TouchableRipple.test.tsx index 4448301244..f3c4cb1168 100644 --- a/src/components/__tests__/TouchableRipple.test.tsx +++ b/src/components/__tests__/TouchableRipple.test.tsx @@ -2,44 +2,44 @@ import { Platform, Text } from 'react-native'; import type { GestureResponderEvent } from 'react-native'; import { describe, expect, it, jest } from '@jest/globals'; -import { fireEvent } from '@testing-library/react-native'; +import { userEvent } from '@testing-library/react-native'; -import { render } from '../../test-utils'; +import { render, screen } from '../../test-utils'; import TouchableRipple from '../TouchableRipple/TouchableRipple.native'; describe('TouchableRipple', () => { - it('renders children correctly', () => { - const { getByText } = render( + it('renders children correctly', async () => { + await render( Button ); - expect(getByText('Button')).toBeTruthy(); + expect(screen.getByText('Button')).toBeOnTheScreen(); }); - it('calls onPress when pressed', () => { + it('calls onPress when pressed', async () => { const onPress = jest.fn<(event: GestureResponderEvent) => void>(); - const { getByText } = render( + await render( Button ); - fireEvent.press(getByText('Button')); + await userEvent.press(screen.getByText('Button')); expect(onPress).toHaveBeenCalledTimes(1); }); - it('disables the button when disabled prop is true', () => { + it('disables the button when disabled prop is true', async () => { const onPress = jest.fn<(event: GestureResponderEvent) => void>(); - const { getByText } = render( + await render( Button ); - fireEvent.press(getByText('Button')); + await userEvent.press(screen.getByText('Button')); expect(onPress).not.toHaveBeenCalled(); }); @@ -47,25 +47,25 @@ describe('TouchableRipple', () => { describe('on iOS', () => { Platform.OS = 'ios'; - it('displays the underlay when pressed', () => { - const { getByTestId } = render( + it('displays the underlay when pressed', async () => { + await render( Press me! ); - const underlay = getByTestId('touchable-ripple-underlay'); - expect(underlay).toBeDefined(); + const underlay = screen.getByTestId('touchable-ripple-underlay'); + expect(underlay).toBeOnTheScreen(); }); - it('renders custom underlay color', () => { - const { getByTestId } = render( + it('renders custom underlay color', async () => { + await render( Press me! ); - const underlay = getByTestId('touchable-ripple-underlay'); + const underlay = screen.getByTestId('touchable-ripple-underlay'); expect(underlay).toHaveStyle({ backgroundColor: 'purple' }); }); }); diff --git a/src/components/__tests__/Typography/Text.test.tsx b/src/components/__tests__/Typography/Text.test.tsx index c861343135..b470f47f32 100644 --- a/src/components/__tests__/Typography/Text.test.tsx +++ b/src/components/__tests__/Typography/Text.test.tsx @@ -1,7 +1,7 @@ import { expect, it, jest } from '@jest/globals'; import PaperProvider from '../../../core/PaperProvider'; -import { render } from '../../../test-utils'; +import { render, screen } from '../../../test-utils'; import configureFonts from '../../../theme/fonts'; import { LightTheme } from '../../../theme/schemes'; import { tokens } from '../../../theme/tokens'; @@ -9,7 +9,7 @@ import Text, { customText } from '../../Typography/Text'; const content = 'Something rendered as a child content'; -it('renders every variant of Text with children as content', () => { +it('renders every variant of Text with children as content', async () => { const variants = ( <> {content} @@ -34,24 +34,22 @@ it('renders every variant of Text with children as content', () => { ); - const tree = render(variants).toJSON(); + const tree = (await render(variants)).toJSON(); expect(tree).toMatchSnapshot(); }); -it('renders v3 Text component without variant with default fontWeight and fontFamily', () => { - const { getByTestId } = render( - {content} - ); +it('renders v3 Text component without variant with default fontWeight and fontFamily', async () => { + await render({content}); const { brandRegular, weightRegular } = tokens.md.ref.typeface; - expect(getByTestId('text-without-variant')).toHaveStyle({ + expect(screen.getByTestId('text-without-variant')).toHaveStyle({ fontFamily: brandRegular, fontWeight: weightRegular, }); }); -it('renders v3 Text component with custom variant correctly', () => { +it('renders v3 Text component with custom variant correctly', async () => { const fontConfig = { customVariant: { fontFamily: 'Montserrat-Regular', @@ -67,7 +65,7 @@ it('renders v3 Text component with custom variant correctly', () => { fonts: configureFonts({ config: fontConfig }), }; const Text = customText<'customVariant'>(); - const { getByTestId } = render( + await render( {content} @@ -75,49 +73,56 @@ it('renders v3 Text component with custom variant correctly', () => { ); - expect(getByTestId('text-with-custom-variant').props.style).toMatchSnapshot(); + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('text-with-custom-variant').props.style + ).toMatchSnapshot(); }); -it("nested text with variant should override parent's variant", () => { - const { getByTestId } = render( +it("nested text with variant should override parent's variant", async () => { + await render( Test ); - expect(getByTestId('parent-text')).toHaveStyle(LightTheme.fonts.displayLarge); + expect(screen.getByTestId('parent-text')).toHaveStyle( + LightTheme.fonts.displayLarge + ); }); -it("nested non-text component should not override parent's variant", () => { +it("nested non-text component should not override parent's variant", async () => { const ChildComponent = () => <>{content}; - const { getByTestId } = render( + await render( ); - expect(getByTestId('parent-text')).toHaveStyle(LightTheme.fonts.displayLarge); + expect(screen.getByTestId('parent-text')).toHaveStyle( + LightTheme.fonts.displayLarge + ); }); -it("nested text without variant, but with styles, should override parent's styles", () => { +it("nested text without variant, but with styles, should override parent's styles", async () => { const customStyle = { fontSize: 50, lineHeight: 70 }; - const { getByTestId } = render( + await render( Test ); - expect(getByTestId('parent-text')).toHaveStyle(customStyle); + expect(screen.getByTestId('parent-text')).toHaveStyle(customStyle); }); -it('throws when custom variant not provided', () => { +it('throws when custom variant not provided', async () => { jest.spyOn(console, 'error').mockImplementation(() => {}); const Text = customText<'myCustomVariant'>(); - expect(() => + await expect( render({content}) - ).toThrow(/myCustomVariant was not provided/); + ).rejects.toThrow(/myCustomVariant was not provided/); jest.clearAllMocks(); }); diff --git a/src/components/__tests__/Typography/__snapshots__/Text.test.tsx.snap b/src/components/__tests__/Typography/__snapshots__/Text.test.tsx.snap index 21130dee07..a69b0061c6 100644 --- a/src/components/__tests__/Typography/__snapshots__/Text.test.tsx.snap +++ b/src/components/__tests__/Typography/__snapshots__/Text.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders every variant of Text with children as content 1`] = ` -[ +<> Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , + Something rendered as a child content - , -] + + `; exports[`renders v3 Text component with custom variant correctly 1`] = ` diff --git a/src/components/__tests__/__snapshots__/BottomNavigation.test.tsx.snap b/src/components/__tests__/__snapshots__/BottomNavigation.test.tsx.snap index 7b5d8ad45e..b772a50b60 100644 --- a/src/components/__tests__/__snapshots__/BottomNavigation.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/BottomNavigation.test.tsx.snap @@ -66,7 +66,9 @@ exports[`allows customizing Route's type via generics 1`] = ` } } > - First + + First + @@ -733,7 +735,9 @@ exports[`hides labels in non-shifting bottom navigation 1`] = ` } } > - Route: 0 + + Route: 0 + @@ -1474,7 +1478,9 @@ exports[`hides labels in shifting bottom navigation 1`] = ` } } > - Route: 0 + + Route: 0 + @@ -2215,7 +2221,9 @@ exports[`renders bottom navigation with getLazy 1`] = ` } } > - Route: 0 + + Route: 0 + - Route: 1 + + Route: 1 + - Route: 3 + + Route: 3 + - Route: 4 + + Route: 4 + @@ -4076,7 +4090,9 @@ exports[`renders bottom navigation with scene animation 1`] = ` } } > - Route: 0 + + Route: 0 + @@ -5550,7 +5566,9 @@ exports[`renders custom icon and label in non-shifting bottom navigation 1`] = ` } } > - Route: 0 + + Route: 0 + @@ -5789,11 +5807,15 @@ exports[`renders custom icon and label in non-shifting bottom navigation 1`] = ` } } > - Route: 0 - + - Route: 0 - + @@ -5970,11 +5996,15 @@ exports[`renders custom icon and label in non-shifting bottom navigation 1`] = ` } } > - Route: 1 - + - Route: 1 - + @@ -6151,11 +6185,15 @@ exports[`renders custom icon and label in non-shifting bottom navigation 1`] = ` } } > - Route: 2 - + - Route: 2 - + @@ -6252,7 +6294,9 @@ exports[`renders custom icon and label in shifting bottom navigation 1`] = ` } } > - Route: 0 + + Route: 0 + @@ -6496,11 +6540,15 @@ exports[`renders custom icon and label in shifting bottom navigation 1`] = ` } } > - Route: 0 - + @@ -6663,11 +6711,15 @@ exports[`renders custom icon and label in shifting bottom navigation 1`] = ` } } > - Route: 1 - + @@ -6830,11 +6882,15 @@ exports[`renders custom icon and label in shifting bottom navigation 1`] = ` } } > - Route: 2 - + @@ -6997,11 +7053,15 @@ exports[`renders custom icon and label in shifting bottom navigation 1`] = ` } } > - Route: 3 - + @@ -7164,11 +7224,15 @@ exports[`renders custom icon and label in shifting bottom navigation 1`] = ` } } > - Route: 4 - + @@ -7246,7 +7310,9 @@ exports[`renders custom icon and label with custom colors in non-shifting bottom } } > - Route: 0 + + Route: 0 + @@ -8347,7 +8413,9 @@ exports[`renders custom icon and label with custom colors in shifting bottom nav } } > - Route: 0 + + Route: 0 + @@ -9295,7 +9363,9 @@ exports[`renders non-shifting bottom navigation 1`] = ` } } > - Route: 0 + + Route: 0 + @@ -10396,7 +10466,9 @@ exports[`renders shifting bottom navigation 1`] = ` } } > - Route: 0 + + Route: 0 + diff --git a/src/components/__tests__/__snapshots__/FABExtended.test.tsx.snap b/src/components/__tests__/__snapshots__/FABExtended.test.tsx.snap index 48d20d29eb..7f33de6094 100644 --- a/src/components/__tests__/__snapshots__/FABExtended.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/FABExtended.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders extended FAB collapsed 1`] = ` -[ +<> - , + New message - , -] + + `; exports[`renders extended FAB expanded 1`] = ` -[ +<> - , + New message - , -] + + `; exports[`renders extended FAB large size 1`] = ` -[ +<> - , + New message - , -] + + `; exports[`renders extended FAB medium size 1`] = ` -[ +<> - , + New message - , -] + + `; exports[`renders extended FAB not visible 1`] = ` -[ +<> - , + New message - , -] + + `; exports[`renders extended FAB transitioning to collapsed 1`] = ` -[ +<> - , + New message - , -] + + `; diff --git a/src/components/__tests__/__snapshots__/Menu.test.tsx.snap b/src/components/__tests__/__snapshots__/Menu.test.tsx.snap index ee711c93f8..90a52d83a0 100644 --- a/src/components/__tests__/__snapshots__/Menu.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/Menu.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders menu with content styles 1`] = ` -[ +<> - , + - , -] + + `; exports[`renders not visible menu 1`] = ` @@ -732,7 +732,7 @@ exports[`renders not visible menu 1`] = ` `; exports[`renders visible menu 1`] = ` -[ +<> - , + - , -] + + `; diff --git a/src/components/__tests__/__snapshots__/MenuItem.test.tsx.snap b/src/components/__tests__/__snapshots__/MenuItem.test.tsx.snap index 9b1babef34..d5101a1b26 100644 --- a/src/components/__tests__/__snapshots__/MenuItem.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/MenuItem.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Menu Item renders menu item 1`] = ` -[ +<> - , + - , + - , + - , + - , -] + + `; diff --git a/src/components/__tests__/__snapshots__/Portal.test.tsx.snap b/src/components/__tests__/__snapshots__/Portal.test.tsx.snap index d4a8f49b9d..7168f606d8 100644 --- a/src/components/__tests__/__snapshots__/Portal.test.tsx.snap +++ b/src/components/__tests__/__snapshots__/Portal.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders portal with siblings 1`] = ` -[ +<> Outside content - , + Portal content - , -] + + `; diff --git a/src/core/PaperProvider.tsx b/src/core/PaperProvider.tsx index 8c1343dbd9..5149efcd6f 100644 --- a/src/core/PaperProvider.tsx +++ b/src/core/PaperProvider.tsx @@ -32,7 +32,9 @@ const PaperProvider = (props: Props) => { const theme = React.useMemo(() => { const isDark = props.theme?.dark ?? colorScheme === 'dark'; const base = defaultThemes[isDark ? 'dark' : 'light']; - const scale = resolvedReduceMotion ? 0 : props.theme?.animation?.scale ?? 1; + const scale = resolvedReduceMotion + ? 0 + : (props.theme?.animation?.scale ?? 1); return { ...base, diff --git a/src/core/__tests__/PaperProvider.test.tsx b/src/core/__tests__/PaperProvider.test.tsx index 70d90a3ecf..1c5d821ebe 100644 --- a/src/core/__tests__/PaperProvider.test.tsx +++ b/src/core/__tests__/PaperProvider.test.tsx @@ -8,7 +8,7 @@ import { it, jest as mockJest, } from '@jest/globals'; -import { render, act } from '@testing-library/react-native'; +import { act, render, screen } from '@testing-library/react-native'; import { useReduceMotion } from '../../theme/accessibility/ReduceMotionContext'; import { DarkTheme, DynamicLightTheme, LightTheme } from '../../theme/schemes'; @@ -96,7 +96,7 @@ const mockAccessibilityInfo = () => { removeEventListener: mockJest.fn((cb: (enabled: boolean) => void) => { listeners.push(cb); }), - isReduceMotionEnabled: mockJest.fn(() => Promise.resolve(false)), + isReduceMotionEnabled: mockJest.fn(() => Promise.resolve(undefined)), __internalListeners: listeners, }, }; @@ -111,7 +111,7 @@ const FakeChild = () => { const createProvider = (theme?: ThemeProp) => { return ( - + ); @@ -130,12 +130,14 @@ describe('PaperProvider', () => { it('handles theme change', async () => { mockAppearance(); - const { getByTestId } = render(createProvider()); - expect(getByTestId('provider-child-view').props.theme).toStrictEqual( + await render(createProvider()); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('provider-child-view').props.theme).toStrictEqual( ExtendedLightTheme ); - act(() => Appearance.__internalListeners[0]({ colorScheme: 'dark' })); - expect(getByTestId('provider-child-view').props.theme).toStrictEqual( + await act(() => Appearance.__internalListeners[0]({ colorScheme: 'dark' })); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('provider-child-view').props.theme).toStrictEqual( ExtendedDarkTheme ); }); @@ -144,13 +146,18 @@ describe('PaperProvider', () => { mockAppearance(); mockAccessibilityInfo(); - const { getByTestId } = render(createProvider()); + await render( + + + + ); expect(AccessibilityInfo.addEventListener).toHaveBeenCalled(); - act(() => AccessibilityInfo.__internalListeners[0](true)); + await act(() => AccessibilityInfo.__internalListeners[0](true)); expect( - getByTestId('provider-child-view').props.theme.animation.scale + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('provider-child-view').props.theme.animation.scale ).toStrictEqual(0); }); @@ -163,26 +170,32 @@ describe('PaperProvider', () => { return ; }; - const { getByTestId, rerender } = render( + const { rerender } = await render( ); - expect(getByTestId('reduce-motion-probe').props.reduceMotion).toBe(true); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('reduce-motion-probe').props.reduceMotion).toBe( + true + ); - rerender( + await rerender( ); - expect(getByTestId('reduce-motion-probe').props.reduceMotion).toBe(false); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('reduce-motion-probe').props.reduceMotion).toBe( + false + ); }); it('removes the AccessibilityInfo listener when reduceMotion switches from "auto" to "off"', async () => { mockAppearance(); mockAccessibilityInfo(); - const { rerender } = render( + const { rerender } = await render( @@ -191,7 +204,7 @@ describe('PaperProvider', () => { expect(AccessibilityInfo.addEventListener).toHaveBeenCalledTimes(1); expect(AccessibilityInfo.removeEventListener).not.toHaveBeenCalled(); - rerender( + await rerender( @@ -203,7 +216,7 @@ describe('PaperProvider', () => { it('does not subscribe to AccessibilityInfo when reduceMotion is "off"', async () => { mockAppearance(); mockAccessibilityInfo(); - const { getByTestId } = render( + await render( @@ -211,14 +224,15 @@ describe('PaperProvider', () => { expect(AccessibilityInfo.addEventListener).not.toHaveBeenCalled(); expect( - getByTestId('provider-child-view').props.theme.animation.scale + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('provider-child-view').props.theme.animation.scale ).toStrictEqual(1); }); it('forces animation.scale to 0 when reduceMotion is "on" without subscribing', async () => { mockAppearance(); mockAccessibilityInfo(); - const { getByTestId } = render( + await render( @@ -226,7 +240,8 @@ describe('PaperProvider', () => { expect(AccessibilityInfo.addEventListener).not.toHaveBeenCalled(); expect( - getByTestId('provider-child-view').props.theme.animation.scale + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('provider-child-view').props.theme.animation.scale ).toStrictEqual(0); }); @@ -237,22 +252,24 @@ describe('PaperProvider', () => { it('should set Appearance listeners, if there is no theme', async () => { mockAppearance(); - const { getByTestId } = render(createProvider()); + await render(createProvider()); expect(Appearance.addChangeListener).toHaveBeenCalled(); - act(() => Appearance.__internalListeners[0]({ colorScheme: 'dark' })); - expect(getByTestId('provider-child-view').props.theme).toStrictEqual( + await act(() => Appearance.__internalListeners[0]({ colorScheme: 'dark' })); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('provider-child-view').props.theme).toStrictEqual( ExtendedDarkTheme ); }); it('should not set Appearance listeners, if the theme is passed', async () => { mockAppearance(); - const { getByTestId } = render(createProvider(ExtendedLightTheme)); + await render(createProvider(ExtendedLightTheme)); expect(Appearance.addChangeListener).not.toHaveBeenCalled(); expect(Appearance.removeChangeListener).not.toHaveBeenCalled(); - expect(getByTestId('provider-child-view').props.theme).toStrictEqual( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('provider-child-view').props.theme).toStrictEqual( ExtendedLightTheme ); }); @@ -261,9 +278,10 @@ describe('PaperProvider', () => { mockJest.mock('react-native/Libraries/Utilities/Appearance', () => { return null; }); - const { getByTestId } = render(createProvider()); + await render(createProvider()); expect(Appearance).toEqual(null); - expect(getByTestId('provider-child-view').props.theme).toStrictEqual( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('provider-child-view').props.theme).toStrictEqual( ExtendedLightTheme ); }); @@ -288,10 +306,11 @@ describe('PaperProvider', () => { async ({ theme, colorScheme }) => { mockAppearance(); mockJest.mocked(Appearance.getColorScheme).mockReturnValue(colorScheme); - const { getByTestId } = render(createProvider()); - expect(getByTestId('provider-child-view').props.theme).toStrictEqual( - theme - ); + await render(createProvider()); + expect( + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + screen.getByTestId('provider-child-view').props.theme + ).toStrictEqual(theme); } ); @@ -304,8 +323,9 @@ describe('PaperProvider', () => { primary: 'tomato', }, } as ThemeProp; - const { getByTestId } = render(createProvider(customTheme)); - expect(getByTestId('provider-child-view').props.theme).toStrictEqual( + await render(createProvider(customTheme)); + // eslint-disable-next-line no-restricted-syntax -- TODO: replace TestInstance props access with a user-visible assertion. + expect(screen.getByTestId('provider-child-view').props.theme).toStrictEqual( customTheme ); }); diff --git a/src/core/useSystemColorScheme.ts b/src/core/useSystemColorScheme.ts index 3dd7a50821..12c2ab793c 100644 --- a/src/core/useSystemColorScheme.ts +++ b/src/core/useSystemColorScheme.ts @@ -12,7 +12,7 @@ import type { ColorSchemeName } from 'react-native'; */ export function useSystemColorScheme(enabled: boolean): ColorSchemeName { const [colorScheme, setColorScheme] = React.useState(() => - enabled ? Appearance?.getColorScheme() ?? 'light' : 'light' + enabled ? (Appearance?.getColorScheme() ?? 'light') : 'light' ); React.useEffect(() => { diff --git a/src/theme/__tests__/fonts.test.js b/src/theme/__tests__/fonts.test.js index 6650c4f098..23e0f794ae 100644 --- a/src/theme/__tests__/fonts.test.js +++ b/src/theme/__tests__/fonts.test.js @@ -1,3 +1,5 @@ +import { afterEach, describe, expect, it, jest } from '@jest/globals'; + const customFont = { displayLarge: { fontFamily: 'NotoSans', diff --git a/src/theme/fonts.tsx b/src/theme/fonts.tsx index e380655486..847f62637c 100644 --- a/src/theme/fonts.tsx +++ b/src/theme/fonts.tsx @@ -38,7 +38,6 @@ function configureFontsConfig( ); } -// eslint-disable-next-line no-redeclare export default function configureFonts(params?: { config?: Partial; }): Typescale; diff --git a/src/theme/provider.tsx b/src/theme/provider.tsx index a8ecf34c34..b4101eaa0f 100644 --- a/src/theme/provider.tsx +++ b/src/theme/provider.tsx @@ -81,7 +81,6 @@ export const getTheme = ( return defaultThemes[scheme]; }; -// eslint-disable-next-line no-redeclare export function adaptNavigationTheme(themes: { reactNavigationLight: T; materialLight?: Theme; @@ -98,7 +97,7 @@ export function adaptNavigationTheme(themes: { // eslint-disable-next-line no-redeclare export function adaptNavigationTheme< TLight extends NavigationTheme, - TDark extends NavigationTheme + TDark extends NavigationTheme, >(themes: { reactNavigationLight: TLight; reactNavigationDark: TDark; diff --git a/src/theme/schemes/DynamicTheme.android.tsx b/src/theme/schemes/DynamicTheme.android.tsx index 097109ea09..07cc9f93d2 100644 --- a/src/theme/schemes/DynamicTheme.android.tsx +++ b/src/theme/schemes/DynamicTheme.android.tsx @@ -7,6 +7,7 @@ import type { Theme, ThemeColors } from '../types'; const apiLevel = Platform.Version as number; +// eslint-disable-next-line @react-native/platform-colors const ac = (name: string) => PlatformColor(`@android:color/${name}`); /** @@ -23,8 +24,8 @@ const pick = (api34: string, api31: string | null, ref: string): ColorValue => apiLevel >= 34 ? ac(api34) : apiLevel >= 31 && api31 !== null - ? ac(api31) - : ref; + ? ac(api31) + : ref; // Known limitation: surface/container roles on API 31-33 use // @color/m3_ref_palette_dynamic_neutral_variant* (MCL resources that require a diff --git a/src/theme/tokens/sys/elevation.ts b/src/theme/tokens/sys/elevation.ts index 9fcc7cb4fe..de797183d4 100644 --- a/src/theme/tokens/sys/elevation.ts +++ b/src/theme/tokens/sys/elevation.ts @@ -74,7 +74,6 @@ const getShadowColor = (shadowColor: ColorValue, shadowOpacity: number) => { const getBoxShadowValue = (elevation: number, shadowColor: string) => `0px ${shadowLayers[0].height[elevation]}px ${shadowLayers[0].shadowRadius[elevation]}px ${shadowColor}`; -// eslint-disable-next-line no-redeclare export function shadow(elevation: number, shadowColor: ColorValue): ViewStyle; // eslint-disable-next-line no-redeclare export function shadow( diff --git a/src/utils/__tests__/addEventListener.js b/src/utils/__tests__/addEventListener.js deleted file mode 100644 index 6446ccf733..0000000000 --- a/src/utils/__tests__/addEventListener.js +++ /dev/null @@ -1,62 +0,0 @@ -import { BackHandler, Keyboard } from 'react-native'; - -import { addEventListener, addListener } from '../addEventListener'; - -const mockModule = jest.fn(); -const handler = jest.fn(); - -describe('addEventListener', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('assigns subscription', () => { - BackHandler.addEventListener = mockModule; - addEventListener(BackHandler, 'hardwareBackPress', handler); - expect(BackHandler.addEventListener).toHaveBeenCalledWith( - 'hardwareBackPress', - handler - ); - }); - - it('removes subscription', () => { - const subscription = addEventListener( - BackHandler, - 'hardwareBackPress', - handler - ); - BackHandler.removeEventListener = mockModule; - subscription.remove(); - - expect(BackHandler.removeEventListener).toHaveBeenCalledWith( - 'hardwareBackPress', - handler - ); - }); -}); - -describe('addListener', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('assigns subscription', () => { - Keyboard.addListener = mockModule; - addListener(Keyboard, 'keyboardWillShow', handler); - expect(Keyboard.addListener).toHaveBeenCalledWith( - 'keyboardWillShow', - handler - ); - }); - - it('removes subscription', () => { - const subscription = addListener(Keyboard, 'keyboardWillShow', handler); - Keyboard.removeEventListener = mockModule; - subscription.remove(); - - expect(Keyboard.removeEventListener).toHaveBeenCalledWith( - 'keyboardWillShow', - handler - ); - }); -}); diff --git a/src/utils/__tests__/addEventListener.test.tsx b/src/utils/__tests__/addEventListener.test.tsx new file mode 100644 index 0000000000..af1a33cc11 --- /dev/null +++ b/src/utils/__tests__/addEventListener.test.tsx @@ -0,0 +1,77 @@ +import { beforeEach, describe, expect, it, jest } from '@jest/globals'; + +import { addEventListener, addListener } from '../addEventListener'; + +type LegacyEventModule = { + addEventListener: (eventName: string, handler: () => void) => undefined; + removeEventListener: (eventName: string, handler: () => void) => void; +}; + +type LegacyListenerModule = { + addListener: (eventName: string, handler: () => void) => undefined; + removeEventListener: (eventName: string, handler: () => void) => void; +}; + +const handler = jest.fn(); + +describe('addEventListener', () => { + const module: LegacyEventModule = { + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('assigns subscription', () => { + addEventListener(module, 'hardwareBackPress', handler); + + expect(module.addEventListener).toHaveBeenCalledWith( + 'hardwareBackPress', + handler + ); + }); + + it('removes subscription', () => { + const subscription = addEventListener(module, 'hardwareBackPress', handler); + + subscription.remove(); + + expect(module.removeEventListener).toHaveBeenCalledWith( + 'hardwareBackPress', + handler + ); + }); +}); + +describe('addListener', () => { + const module: LegacyListenerModule = { + addListener: jest.fn(), + removeEventListener: jest.fn(), + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('assigns subscription', () => { + addListener(module, 'keyboardWillShow', handler); + + expect(module.addListener).toHaveBeenCalledWith( + 'keyboardWillShow', + handler + ); + }); + + it('removes subscription', () => { + const subscription = addListener(module, 'keyboardWillShow', handler); + + subscription.remove(); + + expect(module.removeEventListener).toHaveBeenCalledWith( + 'keyboardWillShow', + handler + ); + }); +}); diff --git a/src/utils/addEventListener.tsx b/src/utils/addEventListener.tsx index 40bb4508b3..dce970c6b7 100644 --- a/src/utils/addEventListener.tsx +++ b/src/utils/addEventListener.tsx @@ -7,10 +7,10 @@ export function addEventListener< T extends { addEventListener: ( ...args: any - ) => NativeEventSubscription | EmitterSubscription; + ) => NativeEventSubscription | EmitterSubscription | undefined; } & { removeEventListener?: (...args: any) => void } & { remove?: (...args: any) => void; - } + }, >(Module: T, ...rest: Parameters) { const [eventName, handler] = rest; @@ -33,9 +33,9 @@ export function addEventListener< export function addListener< T extends { - addListener: (...args: any) => EmitterSubscription; + addListener: (...args: any) => EmitterSubscription | undefined; removeEventListener: (...args: any) => void; - } + }, >(Module: T, ...rest: Parameters) { const [eventName, handler] = rest; diff --git a/src/utils/splitStyles.ts b/src/utils/splitStyles.ts index 9c1f42df34..d6b490e45a 100644 --- a/src/utils/splitStyles.ts +++ b/src/utils/splitStyles.ts @@ -55,6 +55,6 @@ export function splitStyles( // Convert arrays of entries into objects return newStyles.map((styles) => Object.fromEntries(styles)) as unknown as [ ViewStyle, - ...MappedTuple + ...MappedTuple, ]; } diff --git a/tsconfig.json b/tsconfig.json index 9241305a80..2c3227b757 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,9 +2,7 @@ "compilerOptions": { "rootDir": ".", "paths": { - "react-native-paper": [ - "./src/index" - ] + "react-native-paper": ["./src/index"] }, "noEmit": true, "customConditions": ["react-native-paper-source"], @@ -14,10 +12,7 @@ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "jsx": "react-jsx", - "lib": [ - "esnext", - "dom" - ], + "lib": ["esnext", "dom"], "moduleSuffixes": [".ios", ".native", ".android", ""], "module": "preserve", "moduleResolution": "bundler", @@ -35,7 +30,5 @@ "types": ["node"], "verbatimModuleSyntax": true }, - "exclude": [ - "lib/**/*" - ] + "exclude": ["lib/**/*"] } diff --git a/yarn.lock b/yarn.lock index cdea0b5acd..e74b5f06e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -398,6 +398,17 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/code-frame@npm:7.29.7" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.29.7" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.1.1" + checksum: 10c0/169fc2080169a40c1760155eaaaf739bcb882df0bec76a83adbda5493645bc17270a3434b8848c494b1933e96fe1d147370001e3cda09a39f43ae30f08ef2069 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.27.2, @babel/compat-data@npm:^7.27.7, @babel/compat-data@npm:^7.28.5": version: 7.28.5 resolution: "@babel/compat-data@npm:7.28.5" @@ -412,6 +423,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/compat-data@npm:7.29.7" + checksum: 10c0/47913f05e08a45a1c9df38c02b4b49e391005085b489432647a1abe112e5d9c75e3be8ea5972b7f6da4ec5d1339922ceb9ea02b8a25d4ed1cb8636e5261f344e + languageName: node + linkType: hard + "@babel/core@npm:7.12.9": version: 7.12.9 resolution: "@babel/core@npm:7.12.9" @@ -436,7 +454,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.16.0, @babel/core@npm:^7.18.6, @babel/core@npm:^7.19.6, @babel/core@npm:^7.20.0, @babel/core@npm:^7.23.9, @babel/core@npm:^7.25.2, @babel/core@npm:^7.7.5": +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.18.6, @babel/core@npm:^7.19.6, @babel/core@npm:^7.20.0, @babel/core@npm:^7.23.9, @babel/core@npm:^7.25.2, @babel/core@npm:^7.7.5": version: 7.28.5 resolution: "@babel/core@npm:7.28.5" dependencies: @@ -459,6 +477,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.22.20": + version: 7.29.7 + resolution: "@babel/core@npm:7.29.7" + dependencies: + "@babel/code-frame": "npm:^7.29.7" + "@babel/generator": "npm:^7.29.7" + "@babel/helper-compilation-targets": "npm:^7.29.7" + "@babel/helper-module-transforms": "npm:^7.29.7" + "@babel/helpers": "npm:^7.29.7" + "@babel/parser": "npm:^7.29.7" + "@babel/template": "npm:^7.29.7" + "@babel/traverse": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + "@jridgewell/remapping": "npm:^2.3.5" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/112fb09c24de7a1de64d1de2c31fe65c4e6af4cb2fb6e6d99ea5373e6fc51e75b88581c0efae4c4c68f119a02a988c7106e95011a41530a2fb8ed793c7eaa07b + languageName: node + linkType: hard + "@babel/core@npm:^7.29.0": version: 7.29.0 resolution: "@babel/core@npm:7.29.0" @@ -482,9 +523,9 @@ __metadata: languageName: node linkType: hard -"@babel/eslint-parser@npm:^7.16.3": - version: 7.28.5 - resolution: "@babel/eslint-parser@npm:7.28.5" +"@babel/eslint-parser@npm:^7.22.15": + version: 7.29.7 + resolution: "@babel/eslint-parser@npm:7.29.7" dependencies: "@nicolo-ribaudo/eslint-scope-5-internals": "npm:5.1.1-v1" eslint-visitor-keys: "npm:^2.1.0" @@ -492,7 +533,7 @@ __metadata: peerDependencies: "@babel/core": ^7.11.0 eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 - checksum: 10c0/4d13f765434b6be83ab3917f06ad712dedf0d5bfa80fe54cd6cea44adac6a0d2519020ad307d66b4490e46a435874829eac6a9fd3a9cad54d7616c47d288aaed + checksum: 10c0/c24dcd941b0a149b197a9e9c3297a01d621775ac71cdf2e1134b1097c1691b46ce969355e1be3676d83b88f62c43ed33cf3a499da21ea11a5eb07339ce64ac20 languageName: node linkType: hard @@ -522,6 +563,19 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/generator@npm:7.29.7" + dependencies: + "@babel/parser": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + "@jridgewell/gen-mapping": "npm:^0.3.12" + "@jridgewell/trace-mapping": "npm:^0.3.28" + jsesc: "npm:^3.0.2" + checksum: 10c0/9bf72b01b5bd0ea5b1288a0e37dbd360bff2f2b1ce73342c0d40fb3db2ec3dc004ada5ffa925c5e12939a416eed59e600d562b8ecd938ce0d27dfd0eb6c6c2b7 + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.27.1, @babel/helper-annotate-as-pure@npm:^7.27.3": version: 7.27.3 resolution: "@babel/helper-annotate-as-pure@npm:7.27.3" @@ -531,6 +585,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-annotate-as-pure@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-annotate-as-pure@npm:7.29.7" + dependencies: + "@babel/types": "npm:^7.29.7" + checksum: 10c0/c56536b52d17632d89d49db2063ed6102f0e3bbadf6a0ccb74e6599d6a77173b644c7fe8c3ef17c7a162709d55b75ee5145ef6db917d16ba7f375fbffcf2e942 + languageName: node + linkType: hard + "@babel/helper-compilation-targets@npm:^7.20.7, @babel/helper-compilation-targets@npm:^7.27.1, @babel/helper-compilation-targets@npm:^7.27.2": version: 7.27.2 resolution: "@babel/helper-compilation-targets@npm:7.27.2" @@ -557,6 +620,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-compilation-targets@npm:7.29.7" + dependencies: + "@babel/compat-data": "npm:^7.29.7" + "@babel/helper-validator-option": "npm:^7.29.7" + browserslist: "npm:^4.24.0" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10c0/4c15fd4c69a0a7047799a28a88460c19cede0a0ee8af994ea169114986f4af48b92c7393a4a3fee0456c11a656eece3448a6ed06354453d6c27cccf17195453b + languageName: node + linkType: hard + "@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.27.1, @babel/helper-create-class-features-plugin@npm:^7.28.3, @babel/helper-create-class-features-plugin@npm:^7.28.5": version: 7.28.5 resolution: "@babel/helper-create-class-features-plugin@npm:7.28.5" @@ -641,6 +717,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-globals@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-globals@npm:7.29.7" + checksum: 10c0/f38417c40b1129a1b2b519ca961b9040c8827d1444fd74068702286b91b77089431dc76b6b9d5c1496e5da2a4f3ad329c6946e688ba3fa0d1d0b3d2b4f34f36a + languageName: node + linkType: hard + "@babel/helper-member-expression-to-functions@npm:^7.27.1, @babel/helper-member-expression-to-functions@npm:^7.28.5": version: 7.28.5 resolution: "@babel/helper-member-expression-to-functions@npm:7.28.5" @@ -671,6 +754,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-module-imports@npm:7.29.7" + dependencies: + "@babel/traverse": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10c0/6adf60d97356027413342a092f818d9678c4f5caff716a33e3284b5ae14e47a9e88059d421dde4ee4894691260039a12602c0e7becadc175602194b40dfa345d + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.12.1, @babel/helper-module-transforms@npm:^7.27.1, @babel/helper-module-transforms@npm:^7.28.3": version: 7.28.3 resolution: "@babel/helper-module-transforms@npm:7.28.3" @@ -697,6 +790,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-module-transforms@npm:7.29.7" + dependencies: + "@babel/helper-module-imports": "npm:^7.29.7" + "@babel/helper-validator-identifier": "npm:^7.29.7" + "@babel/traverse": "npm:^7.29.7" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/ee5a2172c24a42be696836f4b0d947489c9729d8adf5821885cf77d1ad5333e3c447368e9a71f67df1099570490553dccf9f888ef0a92a48aa63cb086bd8c7e1 + languageName: node + linkType: hard + "@babel/helper-optimise-call-expression@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-optimise-call-expression@npm:7.27.1" @@ -727,6 +833,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-plugin-utils@npm:7.29.7" + checksum: 10c0/380477a06133274a2759f9355929cb60a95e8b8fee624a1ae1fa349e1d1645b89daca456f72833f6d1062bffa12ee4271c5bf0cc5a61c0166cdc24c7591e2408 + languageName: node + linkType: hard + "@babel/helper-remap-async-to-generator@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-remap-async-to-generator@npm:7.27.1" @@ -783,6 +896,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-string-parser@npm:7.29.7" + checksum: 10c0/194bc0f1716e396d5ffde56ad6119745fb9557662c98611590e5e454906783a4ccb21ce93056b8eb69a4909044834e45d96e50ac695bbe9e3221648fe033c06c + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.27.1, @babel/helper-validator-identifier@npm:^7.28.5": version: 7.28.5 resolution: "@babel/helper-validator-identifier@npm:7.28.5" @@ -790,6 +910,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-validator-identifier@npm:7.29.7" + checksum: 10c0/4795354e7ae0dcafa72de1cd04ec51252dc1498517170beaf019e03effc5b7bf13c6b21a3949a77e07b8125be7f106ed1131350d8ebd4566ae874094a726d62b + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.27.1": version: 7.27.1 resolution: "@babel/helper-validator-option@npm:7.27.1" @@ -797,6 +924,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helper-validator-option@npm:7.29.7" + checksum: 10c0/d2a06c6d0ac40ba4a2f219fc2cab249c7a94bacdb2686273b7f9598571c908809b48468ff588915a346e6cc7296f60b581023d1d498b747fed06f779d335c2cc + languageName: node + linkType: hard + "@babel/helper-wrap-function@npm:^7.27.1": version: 7.28.3 resolution: "@babel/helper-wrap-function@npm:7.28.3" @@ -828,6 +962,16 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/helpers@npm:7.29.7" + dependencies: + "@babel/template": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10c0/218e8d10953647c9f44775f5a022b227a182674853b5ea8631889deb7e1a3e4bc870388aaecf59bb8bd92a87f9a96220ed3f70a35bffec6bcf9169ecb67891ac + languageName: node + linkType: hard + "@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.12.7, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.18.8, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.5": version: 7.28.5 resolution: "@babel/parser@npm:7.28.5" @@ -850,6 +994,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/parser@npm:7.29.7" + dependencies: + "@babel/types": "npm:^7.29.7" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/65133038f80b54a714d6027cb77cee3f9a6b5c4c6842ce674301e13947cbcbfa8055e63acaf1b84c085d34226a14425b2c2b97b829e0e226d2e8f1299942a51d + languageName: node + linkType: hard + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.28.5": version: 7.28.5 resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.28.5" @@ -1106,7 +1261,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-flow@npm:^7.12.1, @babel/plugin-syntax-flow@npm:^7.18.6, @babel/plugin-syntax-flow@npm:^7.27.1": +"@babel/plugin-syntax-flow@npm:^7.12.1, @babel/plugin-syntax-flow@npm:^7.27.1": version: 7.27.1 resolution: "@babel/plugin-syntax-flow@npm:7.27.1" dependencies: @@ -1117,6 +1272,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-flow@npm:^7.22.5": + version: 7.29.7 + resolution: "@babel/plugin-syntax-flow@npm:7.29.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.29.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/b2e330dd0dc535c7364937ce2b29a06065e60b1d523db75f36ab4fb89e4ba664e2230cbb1937b35712c9a0ebafc3358f323d6e6b22247d5ebad12fdd3e1f6e98 + languageName: node + linkType: hard + "@babel/plugin-syntax-import-assertions@npm:^7.27.1": version: 7.27.1 resolution: "@babel/plugin-syntax-import-assertions@npm:7.27.1" @@ -1216,6 +1382,17 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-jsx@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/plugin-syntax-jsx@npm:7.29.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.29.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/1736000de183538ba8eef34520105508860e48b0c763254ba9158af5e814ed8bbceeedbb4281fbda33de787ae5b3870e92f60c6ae7131e7d322e451d57387896 + languageName: node + linkType: hard + "@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4": version: 7.10.4 resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" @@ -2139,7 +2316,22 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-jsx@npm:^7.18.10, @babel/plugin-transform-react-jsx@npm:^7.25.2, @babel/plugin-transform-react-jsx@npm:^7.27.1": +"@babel/plugin-transform-react-jsx@npm:^7.22.15": + version: 7.29.7 + resolution: "@babel/plugin-transform-react-jsx@npm:7.29.7" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.29.7" + "@babel/helper-module-imports": "npm:^7.29.7" + "@babel/helper-plugin-utils": "npm:^7.29.7" + "@babel/plugin-syntax-jsx": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/ae6487c3deafcffda8a2c1b1eb77e0b7121630fa1a9646cecd73dbbdd8271532a0f7f0e8c01f69b6d39a36d8d79eb67e2d51031369c9055f18f7d8e70d9b5446 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx@npm:^7.25.2, @babel/plugin-transform-react-jsx@npm:^7.27.1": version: 7.27.1 resolution: "@babel/plugin-transform-react-jsx@npm:7.27.1" dependencies: @@ -2668,13 +2860,6 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.29.0": - version: 7.29.2 - resolution: "@babel/runtime@npm:7.29.2" - checksum: 10c0/30b80a0140d16467792e1bbeb06f655b0dab70407da38dfac7fedae9c859f9ae9d846ef14ad77bd3814c064295fe9b1bc551f1541ea14646ae9f22b71a8bc17a - languageName: node - linkType: hard - "@babel/template@npm:>=7, @babel/template@npm:^7.12.7, @babel/template@npm:^7.27.1, @babel/template@npm:^7.27.2, @babel/template@npm:^7.3.3": version: 7.27.2 resolution: "@babel/template@npm:7.27.2" @@ -2697,6 +2882,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/template@npm:7.29.7" + dependencies: + "@babel/code-frame": "npm:^7.29.7" + "@babel/parser": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + checksum: 10c0/8bb7f900dcab0e9e1c5ffbc33ca10e0d26b7b2e2ca804becb73ee771b9c4ed6e2908a4ae4a14c08560febb45d2b6b9a173955e42ad404d05f8b04840a14d9c58 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.1.6, @babel/traverse@npm:^7.12.9, @babel/traverse@npm:^7.18.8, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.0, @babel/traverse@npm:^7.28.3, @babel/traverse@npm:^7.28.4, @babel/traverse@npm:^7.28.5": version: 7.28.5 resolution: "@babel/traverse@npm:7.28.5" @@ -2727,6 +2923,21 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/traverse@npm:7.29.7" + dependencies: + "@babel/code-frame": "npm:^7.29.7" + "@babel/generator": "npm:^7.29.7" + "@babel/helper-globals": "npm:^7.29.7" + "@babel/parser": "npm:^7.29.7" + "@babel/template": "npm:^7.29.7" + "@babel/types": "npm:^7.29.7" + debug: "npm:^4.3.1" + checksum: 10c0/e256a1fbdb956555b76f3c285b1e453f6bedec8b3afb61751d99d933efd11c7d79caf5ddf2493570058a9f7deaa1b48324380d7c1aa1443fd9508becbf56331a + languageName: node + linkType: hard + "@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.7, @babel/types@npm:^7.2.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.26.0, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.2, @babel/types@npm:^7.28.4, @babel/types@npm:^7.28.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": version: 7.28.5 resolution: "@babel/types@npm:7.28.5" @@ -2747,6 +2958,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.29.7": + version: 7.29.7 + resolution: "@babel/types@npm:7.29.7" + dependencies: + "@babel/helper-string-parser": "npm:^7.29.7" + "@babel/helper-validator-identifier": "npm:^7.29.7" + checksum: 10c0/b6623994c69717fa27294f5fa46d59140338e2d86c6c1c13085c84ef7d53086ee357fbf4fe9abe3dd3da75734dc77c4c0df2f90fb29e667558bb3b3fb705e88f + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -2754,31 +2975,34 @@ __metadata: languageName: node linkType: hard -"@callstack/eslint-config@npm:^13.0.2": - version: 13.0.2 - resolution: "@callstack/eslint-config@npm:13.0.2" +"@callstack/eslint-config@npm:^15.0.0": + version: 15.0.0 + resolution: "@callstack/eslint-config@npm:15.0.0" dependencies: - "@babel/core": "npm:^7.16.0" - "@babel/eslint-parser": "npm:^7.16.3" - "@babel/plugin-syntax-flow": "npm:^7.18.6" - "@babel/plugin-transform-react-jsx": "npm:^7.18.10" - "@typescript-eslint/eslint-plugin": "npm:^5.36.2" - "@typescript-eslint/parser": "npm:^5.36.2" - eslint-config-prettier: "npm:^8.3.0" + "@babel/core": "npm:^7.22.20" + "@babel/eslint-parser": "npm:^7.22.15" + "@babel/plugin-syntax-flow": "npm:^7.22.5" + "@babel/plugin-transform-react-jsx": "npm:^7.22.15" + "@eslint/compat": "npm:^1.1.1" + "@react-native/eslint-plugin": "npm:^0.74.0 || ^0.73.0 || ^0.72.0" + "@typescript-eslint/eslint-plugin": "npm:^8.0.1" + "@typescript-eslint/parser": "npm:^8.0.1" + eslint-config-prettier: "npm:^9.0.0" eslint-plugin-flowtype: "npm:^8.0.3" - eslint-plugin-import: "npm:^2.25.3" - eslint-plugin-jest: "npm:^27.0.1" - eslint-plugin-prettier: "npm:^4.0.0" - eslint-plugin-promise: "npm:^6.0.1" - eslint-plugin-react: "npm:^7.27.1" - eslint-plugin-react-hooks: "npm:^4.3.0" - eslint-plugin-react-native: "npm:^4.0.0" - eslint-plugin-react-native-a11y: "npm:^3.2.1" + eslint-plugin-import: "npm:^2.28.1" + eslint-plugin-jest: "npm:^28.7.0" + eslint-plugin-prettier: "npm:^5.2.1" + eslint-plugin-promise: "npm:^7.1.0" + eslint-plugin-react: "npm:^7.35.0" + eslint-plugin-react-hooks: "npm:^4.6.0" + eslint-plugin-react-native: "npm:^4.1.0" + eslint-plugin-react-native-a11y: "npm:^3.4.1" eslint-restricted-globals: "npm:^0.2.0" - prettier: "npm:^2.4.1" + globals: "npm:^15.9.0" + prettier: "npm:^3.0.3" peerDependencies: eslint: ">=8.1.0" - checksum: 10c0/12daf8fe2cd96d8a1ef72a4af5b789b979036063aac02f571c5d3bcd56537db3f43be412d79a14fedba599f8fac9a3c2e5bd54244ae4b786aab0aabc18a0d5fc + checksum: 10c0/f99d38f625f00d9224519872a8a657474d044540f79de024cec0e90d2d5f3c30dff7310e8cba49740b6a15dac443af12491be4c3a00b7ae679024d2e7961826a languageName: node linkType: hard @@ -3406,7 +3630,7 @@ __metadata: languageName: node linkType: hard -"@docusaurus/theme-common@npm:2.4.3": +"@docusaurus/theme-common@npm:2.4.3, @docusaurus/theme-common@npm:^2.3.6": version: 2.4.3 resolution: "@docusaurus/theme-common@npm:2.4.3" dependencies: @@ -3636,7 +3860,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0": +"@eslint-community/eslint-utils@npm:^4.4.0, @eslint-community/eslint-utils@npm:^4.8.0, @eslint-community/eslint-utils@npm:^4.9.1": version: 4.9.1 resolution: "@eslint-community/eslint-utils@npm:4.9.1" dependencies: @@ -3647,27 +3871,94 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.4.0": +"@eslint-community/regexpp@npm:^4.12.1, @eslint-community/regexpp@npm:^4.12.2": version: 4.12.2 resolution: "@eslint-community/regexpp@npm:4.12.2" checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d languageName: node linkType: hard -"@eslint/eslintrc@npm:^1.4.1": +"@eslint/compat@npm:^1.1.1": version: 1.4.1 - resolution: "@eslint/eslintrc@npm:1.4.1" + resolution: "@eslint/compat@npm:1.4.1" dependencies: - ajv: "npm:^6.12.4" + "@eslint/core": "npm:^0.17.0" + peerDependencies: + eslint: ^8.40 || 9 + peerDependenciesMeta: + eslint: + optional: true + checksum: 10c0/46f5ff884873c2e2366df55dd7b2d6b12f7f852bfba8e2a48dae4819cc5e58756deefa9b7f87f1b107af725ee883a05fcc02caf969b58fb142e790c6036a0450 + languageName: node + linkType: hard + +"@eslint/config-array@npm:^0.21.2": + version: 0.21.2 + resolution: "@eslint/config-array@npm:0.21.2" + dependencies: + "@eslint/object-schema": "npm:^2.1.7" + debug: "npm:^4.3.1" + minimatch: "npm:^3.1.5" + checksum: 10c0/89dfe815d18456177c0a1f238daf4593107fd20298b3598e0103054360d3b8d09d967defd8318f031185d68df1f95cfa68becf1390a9c5c6887665f1475142e3 + languageName: node + linkType: hard + +"@eslint/config-helpers@npm:^0.4.2": + version: 0.4.2 + resolution: "@eslint/config-helpers@npm:0.4.2" + dependencies: + "@eslint/core": "npm:^0.17.0" + checksum: 10c0/92efd7a527b2d17eb1a148409d71d80f9ac160b565ac73ee092252e8bf08ecd08670699f46b306b94f13d22e88ac88a612120e7847570dd7cdc72f234d50dcb4 + languageName: node + linkType: hard + +"@eslint/core@npm:^0.17.0": + version: 0.17.0 + resolution: "@eslint/core@npm:0.17.0" + dependencies: + "@types/json-schema": "npm:^7.0.15" + checksum: 10c0/9a580f2246633bc752298e7440dd942ec421860d1946d0801f0423830e67887e4aeba10ab9a23d281727a978eb93d053d1922a587d502942a713607f40ed704e + languageName: node + linkType: hard + +"@eslint/eslintrc@npm:^3.3.5": + version: 3.3.5 + resolution: "@eslint/eslintrc@npm:3.3.5" + dependencies: + ajv: "npm:^6.14.0" debug: "npm:^4.3.2" - espree: "npm:^9.4.0" - globals: "npm:^13.19.0" + espree: "npm:^10.0.1" + globals: "npm:^14.0.0" ignore: "npm:^5.2.0" import-fresh: "npm:^3.2.1" - js-yaml: "npm:^4.1.0" - minimatch: "npm:^3.1.2" + js-yaml: "npm:^4.1.1" + minimatch: "npm:^3.1.5" strip-json-comments: "npm:^3.1.1" - checksum: 10c0/1030e1a4a355f8e4629e19d3d45448a05a8e65ecf49154bebc66599d038f155e830498437cbfc7246e8084adc1f814904f696c2461707cc8c73be961e2e8ae5a + checksum: 10c0/9fb9f1ca65e46d6173966e3aaa5bd353e3a65d7f1f582bebf77f578fab7d7960a399fac1ecfb1e7d52bd61f5cefd6531087ca52a3a3c388f2e1b4f1ebd3da8b7 + languageName: node + linkType: hard + +"@eslint/js@npm:9.39.4": + version: 9.39.4 + resolution: "@eslint/js@npm:9.39.4" + checksum: 10c0/5aa7dea2cbc5decf7f5e3b0c6f86a084ccee0f792d288ca8e839f8bc1b64e03e227068968e49b26096e6f71fd857ab6e42691d1b993826b9a3883f1bdd7a0e46 + languageName: node + linkType: hard + +"@eslint/object-schema@npm:^2.1.7": + version: 2.1.7 + resolution: "@eslint/object-schema@npm:2.1.7" + checksum: 10c0/936b6e499853d1335803f556d526c86f5fe2259ed241bc665000e1d6353828edd913feed43120d150adb75570cae162cf000b5b0dfc9596726761c36b82f4e87 + languageName: node + linkType: hard + +"@eslint/plugin-kit@npm:^0.4.1": + version: 0.4.1 + resolution: "@eslint/plugin-kit@npm:0.4.1" + dependencies: + "@eslint/core": "npm:^0.17.0" + levn: "npm:^0.4.1" + checksum: 10c0/51600f78b798f172a9915dffb295e2ffb44840d583427bc732baf12ecb963eb841b253300e657da91d890f4b323d10a1bd12934bf293e3018d8bb66fdce5217b languageName: node linkType: hard @@ -3777,6 +4068,27 @@ __metadata: languageName: node linkType: hard +"@expo/config-plugins@npm:~56.0.8": + version: 56.0.9 + resolution: "@expo/config-plugins@npm:56.0.9" + dependencies: + "@expo/config-types": "npm:^56.0.6" + "@expo/json-file": "npm:~10.2.0" + "@expo/plist": "npm:^0.7.0" + "@expo/require-utils": "npm:^56.1.3" + "@expo/sdk-runtime-versions": "npm:^1.0.0" + chalk: "npm:^4.1.2" + debug: "npm:^4.3.5" + getenv: "npm:^2.0.0" + glob: "npm:^13.0.0" + semver: "npm:^7.5.4" + slugify: "npm:^1.6.6" + xcode: "npm:^3.0.1" + xml2js: "npm:0.6.0" + checksum: 10c0/401be0071d0bdc1e86431a8dd2b19dfa117ad04b2c58c583b62a5ab5ebb93be3eed26857bdbec9433cb9f554771dda32ea2b7aa5aabf45b8037e6ce7cd705dee + languageName: node + linkType: hard + "@expo/config-types@npm:^56.0.5": version: 56.0.5 resolution: "@expo/config-types@npm:56.0.5" @@ -3784,6 +4096,13 @@ __metadata: languageName: node linkType: hard +"@expo/config-types@npm:^56.0.6": + version: 56.0.6 + resolution: "@expo/config-types@npm:56.0.6" + checksum: 10c0/fa5d8b6a755a5ffa4ee4a138e7a3273f2f3fb7d1a84c4986ecc804f40656e18da89209cf85f3f93d4b3ca730c1a2688e5dc620a1ffd20dc9781834f3b426853f + languageName: node + linkType: hard + "@expo/config@npm:~56.0.8": version: 56.0.8 resolution: "@expo/config@npm:56.0.8" @@ -3802,6 +4121,24 @@ __metadata: languageName: node linkType: hard +"@expo/config@npm:~56.0.9": + version: 56.0.9 + resolution: "@expo/config@npm:56.0.9" + dependencies: + "@expo/config-plugins": "npm:~56.0.8" + "@expo/config-types": "npm:^56.0.5" + "@expo/json-file": "npm:^10.2.0" + "@expo/require-utils": "npm:^56.1.3" + deepmerge: "npm:^4.3.1" + getenv: "npm:^2.0.0" + glob: "npm:^13.0.0" + resolve-workspace-root: "npm:^2.0.0" + semver: "npm:^7.6.0" + slugify: "npm:^1.3.4" + checksum: 10c0/ef643ee063229e1cfba67998f2fd63c5e75781110af0bef99e8730e541fe5599cc8616c571d03918f2b21988652d108e6d0116b8a0d0599f21e7988d3e59f9c4 + languageName: node + linkType: hard + "@expo/devcert@npm:^1.2.1": version: 1.2.1 resolution: "@expo/devcert@npm:1.2.1" @@ -3939,6 +4276,42 @@ __metadata: languageName: node linkType: hard +"@expo/metro-config@npm:~56.0.0": + version: 56.0.14 + resolution: "@expo/metro-config@npm:56.0.14" + dependencies: + "@babel/code-frame": "npm:^7.20.0" + "@babel/core": "npm:^7.20.0" + "@babel/generator": "npm:^7.20.5" + "@expo/config": "npm:~56.0.9" + "@expo/env": "npm:~2.3.0" + "@expo/json-file": "npm:~10.2.0" + "@expo/metro": "npm:~56.0.0" + "@expo/require-utils": "npm:^56.1.3" + "@expo/spawn-async": "npm:^1.8.0" + "@jridgewell/gen-mapping": "npm:^0.3.13" + "@jridgewell/remapping": "npm:^2.3.5" + "@jridgewell/sourcemap-codec": "npm:^1.5.5" + browserslist: "npm:^4.25.0" + chalk: "npm:^4.1.0" + debug: "npm:^4.3.2" + getenv: "npm:^2.0.0" + glob: "npm:^13.0.0" + hermes-parser: "npm:^0.33.3" + jsc-safe-url: "npm:^0.2.4" + lightningcss: "npm:^1.30.1" + picomatch: "npm:^4.0.4" + postcss: "npm:^8.5.14" + resolve-from: "npm:^5.0.0" + peerDependencies: + expo: "*" + peerDependenciesMeta: + expo: + optional: true + checksum: 10c0/3abbcd28d746be0afd21dfbf9be21ecea8471fded8df98bd381bf16c555c21a11617deda38b2586856a09eec1dd9f5edcea04a24ddcf7fca734fd3da1373e9db + languageName: node + linkType: hard + "@expo/metro-config@npm:~56.0.11": version: 56.0.11 resolution: "@expo/metro-config@npm:56.0.11" @@ -4079,6 +4452,22 @@ __metadata: languageName: node linkType: hard +"@expo/require-utils@npm:^56.1.3": + version: 56.1.3 + resolution: "@expo/require-utils@npm:56.1.3" + dependencies: + "@babel/code-frame": "npm:^7.20.0" + "@babel/core": "npm:^7.25.2" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.8" + peerDependencies: + typescript: ^5.0.0 || ^5.0.0-0 || ^6.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/b0fc61db4e45507508bf01524f42770a5bf1f53fab9b244a7dc6c9d8acce0e912940d9945716b8f0c747a07262d34128150c78d00bbe996b2efc5d522c45d874 + languageName: node + linkType: hard + "@expo/router-server@npm:^56.0.10": version: 56.0.10 resolution: "@expo/router-server@npm:56.0.10" @@ -4173,14 +4562,30 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.11.8": - version: 0.11.14 - resolution: "@humanwhocodes/config-array@npm:0.11.14" +"@humanfs/core@npm:^0.19.2": + version: 0.19.2 + resolution: "@humanfs/core@npm:0.19.2" dependencies: - "@humanwhocodes/object-schema": "npm:^2.0.2" - debug: "npm:^4.3.1" - minimatch: "npm:^3.0.5" - checksum: 10c0/66f725b4ee5fdd8322c737cb5013e19fac72d4d69c8bf4b7feb192fcb83442b035b92186f8e9497c220e58b2d51a080f28a73f7899bc1ab288c3be172c467541 + "@humanfs/types": "npm:^0.15.0" + checksum: 10c0/d0a1d52d7b30c27d49475a53072d1510b81c5803e44b342fb8faf3887f1aa27593a1e6dc76a45268e7892d3f4e198146659281f6b6d55eacf3fd5a38bac30c5c + languageName: node + linkType: hard + +"@humanfs/node@npm:^0.16.6": + version: 0.16.8 + resolution: "@humanfs/node@npm:0.16.8" + dependencies: + "@humanfs/core": "npm:^0.19.2" + "@humanfs/types": "npm:^0.15.0" + "@humanwhocodes/retry": "npm:^0.4.0" + checksum: 10c0/56140579db811af4e160b195d45d0f29acf644d192c93fe24c9e594ebf06f19dfc157494a07c84540b8a071c0e4b37209c2362765d31734f4d0be869c2422e25 + languageName: node + linkType: hard + +"@humanfs/types@npm:^0.15.0": + version: 0.15.0 + resolution: "@humanfs/types@npm:0.15.0" + checksum: 10c0/fc26b9a024b0e55f7eaf64036df94345bf5d36d6a41ef80ef38e78f1f7430ce26cf435af736adae58913baae18eac3f38c18739054a3d379102015978eae862e languageName: node linkType: hard @@ -4191,10 +4596,10 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^2.0.2": - version: 2.0.3 - resolution: "@humanwhocodes/object-schema@npm:2.0.3" - checksum: 10c0/80520eabbfc2d32fe195a93557cef50dfe8c8905de447f022675aaf66abc33ae54098f5ea78548d925aa671cd4ab7c7daa5ad704fe42358c9b5e7db60f80696c +"@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2": + version: 0.4.3 + resolution: "@humanwhocodes/retry@npm:0.4.3" + checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42 languageName: node linkType: hard @@ -4337,6 +4742,13 @@ __metadata: languageName: node linkType: hard +"@jest/diff-sequences@npm:30.4.0": + version: 30.4.0 + resolution: "@jest/diff-sequences@npm:30.4.0" + checksum: 10c0/b4358b1b885098b905cb777f58788ddd45f90c4ebc3ce2c04fb1d4c9516f35ac2d9daef8263cd21c537bd7a52ab320f03e4ba9521677959ae20e3d405356b420 + languageName: node + linkType: hard + "@jest/environment@npm:^29.7.0": version: 29.7.0 resolution: "@jest/environment@npm:29.7.0" @@ -4382,6 +4794,13 @@ __metadata: languageName: node linkType: hard +"@jest/get-type@npm:30.1.0": + version: 30.1.0 + resolution: "@jest/get-type@npm:30.1.0" + checksum: 10c0/3e65fd5015f551c51ec68fca31bbd25b466be0e8ee8075d9610fa1c686ea1e70a942a0effc7b10f4ea9a338c24337e1ad97ff69d3ebacc4681b7e3e80d1b24ac + languageName: node + linkType: hard + "@jest/globals@npm:^29.7.0": version: 29.7.0 resolution: "@jest/globals@npm:29.7.0" @@ -4431,6 +4850,15 @@ __metadata: languageName: node linkType: hard +"@jest/schemas@npm:30.4.1": + version: 30.4.1 + resolution: "@jest/schemas@npm:30.4.1" + dependencies: + "@sinclair/typebox": "npm:^0.34.0" + checksum: 10c0/96f388ebfc1974457fcbde2ad36c40a0b549cba3f624fe8d9d6e5903a152dc75e4043f4ac9ac7668622f2ecb0f9a4dcb9a38edf3bc0d52b82045b2bb2b69b72a + languageName: node + linkType: hard + "@jest/schemas@npm:^29.6.3": version: 29.6.3 resolution: "@jest/schemas@npm:29.6.3" @@ -4904,7 +5332,7 @@ __metadata: languageName: node linkType: hard -"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": +"@nodelib/fs.walk@npm:^1.2.3": version: 1.2.8 resolution: "@nodelib/fs.walk@npm:1.2.8" dependencies: @@ -5067,6 +5495,13 @@ __metadata: languageName: node linkType: hard +"@pkgr/core@npm:^0.3.6": + version: 0.3.6 + resolution: "@pkgr/core@npm:0.3.6" + checksum: 10c0/153f0f4563f505faeba13c733efa0e05e467ce1c6b941055a5fd3b4560da60fbf1dff4b11da0075f034ddda11f2842b90395f60895dde5825875b616edccc11c + languageName: node + linkType: hard + "@polka/url@npm:^1.0.0-next.24": version: 1.0.0-next.29 resolution: "@polka/url@npm:1.0.0-next.29" @@ -5265,6 +5700,13 @@ __metadata: languageName: node linkType: hard +"@react-native/eslint-plugin@npm:^0.74.0 || ^0.73.0 || ^0.72.0": + version: 0.74.89 + resolution: "@react-native/eslint-plugin@npm:0.74.89" + checksum: 10c0/7e24c13d9869320b011bcef7901b080438d6a182720135f443c62dd565ee8e8b57e8bb709fee86095f5956cdaeb45a96a4c2334e22b048b20eb8bdea12cfd34d + languageName: node + linkType: hard + "@react-native/gradle-plugin@npm:0.85.3": version: 0.85.3 resolution: "@react-native/gradle-plugin@npm:0.85.3" @@ -5378,7 +5820,7 @@ __metadata: languageName: node linkType: hard -"@react-navigation/elements@npm:^3.0.0-alpha.31": +"@react-navigation/elements@npm:3.0.0-alpha.31, @react-navigation/elements@npm:^3.0.0-alpha.31": version: 3.0.0-alpha.31 resolution: "@react-navigation/elements@npm:3.0.0-alpha.31" dependencies: @@ -5488,6 +5930,13 @@ __metadata: languageName: node linkType: hard +"@sinclair/typebox@npm:^0.34.0": + version: 0.34.49 + resolution: "@sinclair/typebox@npm:0.34.49" + checksum: 10c0/16b7d87f039a49b68c10bb4cdcae2ce5242b2472228851fd6483731616aba4ef977690aa517b230a8d20da8185bb416eb34e326f30568b3963c1cf26b05d1ad8 + languageName: node + linkType: hard + "@sindresorhus/is@npm:^0.14.0": version: 0.14.0 resolution: "@sindresorhus/is@npm:0.14.0" @@ -5712,37 +6161,23 @@ __metadata: languageName: node linkType: hard -"@testing-library/jest-native@npm:^5.4.1": - version: 5.4.3 - resolution: "@testing-library/jest-native@npm:5.4.3" +"@testing-library/react-native@npm:^14.0.0": + version: 14.0.0 + resolution: "@testing-library/react-native@npm:14.0.0" dependencies: - chalk: "npm:^4.1.2" - jest-diff: "npm:^29.0.1" - jest-matcher-utils: "npm:^29.0.1" - pretty-format: "npm:^29.0.3" + jest-matcher-utils: "npm:^30.4.1" + picocolors: "npm:^1.1.1" + pretty-format: "npm:^30.4.1" redent: "npm:^3.0.0" peerDependencies: - react: ">=16.0.0" - react-native: ">=0.59" - react-test-renderer: ">=16.0.0" - checksum: 10c0/9315989dc0377a778f7ec9317b98c1dab9a7e2ebe0ca20a5c75f9dba3a4b486c02452b4399dd1aeef9ebf0007247594c6357f62089f095fde5280ce0344f5e65 - languageName: node - linkType: hard - -"@testing-library/react-native@npm:11.5.0": - version: 11.5.0 - resolution: "@testing-library/react-native@npm:11.5.0" - dependencies: - pretty-format: "npm:^29.0.0" - peerDependencies: - jest: ">=28.0.0" - react: ">=16.0.0" - react-native: ">=0.59" - react-test-renderer: ">=16.0.0" + jest: ">=29.0.0" + react: ">=19.0.0" + react-native: ">=0.78" + test-renderer: ^1.0.0 peerDependenciesMeta: jest: optional: true - checksum: 10c0/2b5a1c18fa69d6b38b937b70a60fb300db4c88d0c73205fb84f61075819075937715f029b3e623cdd88e752460aaf8b65d3f716ae1209d8b8cff5ec6501ebc98 + checksum: 10c0/1c19b1d8e1b66757b38904ddddb54c24185b4969faafcbd6b3888841f8597c4a1d87fbff68f3a950bcf051b2ef16adbdb395f44aad1cbc4ba7eaeca900ffc984 languageName: node linkType: hard @@ -5912,6 +6347,13 @@ __metadata: languageName: node linkType: hard +"@types/estree@npm:^1.0.6": + version: 1.0.9 + resolution: "@types/estree@npm:1.0.9" + checksum: 10c0/3ad3286ca2988cd550dafb8f2ad599c8474868e954fa601a36655bdfefd8039f7c714b8c1c7f2ae219ffbd58bd4660e66fa7479a0120fc02d4777057d4865387 + languageName: node + linkType: hard + "@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^5.0.0": version: 5.1.0 resolution: "@types/express-serve-static-core@npm:5.1.0" @@ -6056,16 +6498,6 @@ __metadata: languageName: node linkType: hard -"@types/jest@npm:^29.2.1": - version: 29.5.14 - resolution: "@types/jest@npm:29.5.14" - dependencies: - expect: "npm:^29.0.0" - pretty-format: "npm:^29.0.0" - checksum: 10c0/18e0712d818890db8a8dab3d91e9ea9f7f19e3f83c2e50b312f557017dc81466207a71f3ed79cf4428e813ba939954fa26ffa0a9a7f153181ba174581b1c2aed - languageName: node - linkType: hard - "@types/json-schema@npm:*, @types/json-schema@npm:^7.0.15, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": version: 7.0.15 resolution: "@types/json-schema@npm:7.0.15" @@ -6137,13 +6569,6 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^13.1.0": - version: 13.13.52 - resolution: "@types/node@npm:13.13.52" - checksum: 10c0/9224aaea219fe7f8b903039bb146d4c38b391d0166a8226a1efa2d43a35b5b7dddfe021c32941bb454a1543da94921c112687934da88e2a019f4bd44f9d517b5 - languageName: node - linkType: hard - "@types/node@npm:^17.0.5": version: 17.0.45 resolution: "@types/node@npm:17.0.45" @@ -6151,6 +6576,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^24.0.0": + version: 24.13.2 + resolution: "@types/node@npm:24.13.2" + dependencies: + undici-types: "npm:~7.18.0" + checksum: 10c0/d7d48a88a4feb0a6aac3cbfaf9ef3b12752b4b09447f88dd0b4c77c03b281e3d4330fe6982a99aedcd63fc16c7540a0c248b91eb2abb0b3edd884d7fe684e9ea + languageName: node + linkType: hard + "@types/normalize-package-data@npm:^2.4.0": version: 2.4.4 resolution: "@types/normalize-package-data@npm:2.4.4" @@ -6197,31 +6631,12 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:^19.1.1": - version: 19.2.3 - resolution: "@types/react-dom@npm:19.2.3" +"@types/react-reconciler@npm:~0.33.0": + version: 0.33.0 + resolution: "@types/react-reconciler@npm:0.33.0" peerDependencies: - "@types/react": ^19.2.0 - checksum: 10c0/b486ebe0f4e2fb35e2e108df1d8fc0927ca5d6002d5771e8a739de11239fe62d0e207c50886185253c99eb9dedfeeb956ea7429e5ba17f6693c7acb4c02f8cd1 - languageName: node - linkType: hard - -"@types/react-native-vector-icons@npm:^6.4.18": - version: 6.4.18 - resolution: "@types/react-native-vector-icons@npm:6.4.18" - dependencies: - "@types/react": "npm:*" - "@types/react-native": "npm:^0.70" - checksum: 10c0/b27f2295c5baaba9ce2ff9ade6e505e4d1fe4f40a628df13dc26d0e1b3ccee9775846f3613a443d91cfe86844703b81e9e64a10cc4b7fac1edfde96cb82c893b - languageName: node - linkType: hard - -"@types/react-native@npm:^0.70": - version: 0.70.19 - resolution: "@types/react-native@npm:0.70.19" - dependencies: - "@types/react": "npm:*" - checksum: 10c0/09a5191dd0f3b85abfa8939df585860ba11a666d888846c7fd7d8d5d1cd72a39224e154403f90a5b82f1dc6c896fa3447e4f5061b2d3e102d0ce798e559d7f13 + "@types/react": "*" + checksum: 10c0/190c203d93c0df9a42fabd693ce059dbdf6c53e15eb14502d9e5b946c981231c5846b867de15522ff61368e9218a8508a9db5476f3e47b5d664bbb2c84b31ac7 languageName: node linkType: hard @@ -6275,6 +6690,15 @@ __metadata: languageName: node linkType: hard +"@types/react@npm:^19.2.7": + version: 19.2.17 + resolution: "@types/react@npm:19.2.17" + dependencies: + csstype: "npm:^3.2.2" + checksum: 10c0/bc2c4af96b3e480604424de70d5ebda90c5f4b485df471858c0bc2d7d70364b606ec3c4d8579f94f01aa0c6c0591f56bcf14cba5689f5eea4b74250ccdc3a232 + languageName: node + linkType: hard + "@types/reactcss@npm:*": version: 1.2.13 resolution: "@types/reactcss@npm:1.2.13" @@ -6309,13 +6733,6 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:^7.3.12": - version: 7.7.1 - resolution: "@types/semver@npm:7.7.1" - checksum: 10c0/c938aef3bf79a73f0f3f6037c16e2e759ff40c54122ddf0b2583703393d8d3127130823facb880e694caa324eb6845628186aac1997ee8b31dc2d18fafe26268 - languageName: node - linkType: hard - "@types/send@npm:*": version: 1.2.1 resolution: "@types/send@npm:1.2.1" @@ -6450,124 +6867,138 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.36.2, @typescript-eslint/eslint-plugin@npm:^5.41.0": - version: 5.62.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.62.0" +"@typescript-eslint/eslint-plugin@npm:8.61.1, @typescript-eslint/eslint-plugin@npm:^8.0.1": + version: 8.61.1 + resolution: "@typescript-eslint/eslint-plugin@npm:8.61.1" dependencies: - "@eslint-community/regexpp": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:5.62.0" - "@typescript-eslint/type-utils": "npm:5.62.0" - "@typescript-eslint/utils": "npm:5.62.0" - debug: "npm:^4.3.4" - graphemer: "npm:^1.4.0" - ignore: "npm:^5.2.0" - natural-compare-lite: "npm:^1.4.0" - semver: "npm:^7.3.7" - tsutils: "npm:^3.21.0" + "@eslint-community/regexpp": "npm:^4.12.2" + "@typescript-eslint/scope-manager": "npm:8.61.1" + "@typescript-eslint/type-utils": "npm:8.61.1" + "@typescript-eslint/utils": "npm:8.61.1" + "@typescript-eslint/visitor-keys": "npm:8.61.1" + ignore: "npm:^7.0.5" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^2.5.0" peerDependencies: - "@typescript-eslint/parser": ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/3f40cb6bab5a2833c3544e4621b9fdacd8ea53420cadc1c63fac3b89cdf5c62be1e6b7bcf56976dede5db4c43830de298ced3db60b5494a3b961ca1b4bff9f2a + "@typescript-eslint/parser": ^8.61.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/3cb445622907283fb23e78f8bde4d1b04cca96da181a0c549b2775954c5dfa59f20e34c27f73ae3e189420e36637f59145bd97ce45c55017a6c3ac1871197951 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.36.2, @typescript-eslint/parser@npm:^5.41.0": - version: 5.62.0 - resolution: "@typescript-eslint/parser@npm:5.62.0" +"@typescript-eslint/parser@npm:8.61.1, @typescript-eslint/parser@npm:^8.0.1": + version: 8.61.1 + resolution: "@typescript-eslint/parser@npm:8.61.1" dependencies: - "@typescript-eslint/scope-manager": "npm:5.62.0" - "@typescript-eslint/types": "npm:5.62.0" - "@typescript-eslint/typescript-estree": "npm:5.62.0" - debug: "npm:^4.3.4" + "@typescript-eslint/scope-manager": "npm:8.61.1" + "@typescript-eslint/types": "npm:8.61.1" + "@typescript-eslint/typescript-estree": "npm:8.61.1" + "@typescript-eslint/visitor-keys": "npm:8.61.1" + debug: "npm:^4.4.3" peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/315194b3bf39beb9bd16c190956c46beec64b8371e18d6bb72002108b250983eb1e186a01d34b77eb4045f4941acbb243b16155fbb46881105f65e37dc9e24d4 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/6515afed5df24fd56fd0c96f94b2fc951236fc805e5d5ec925cbcae1319e5a41caea44284cd35b21f5ce7b812e567185c9dfe0882607135b947895509f23b253 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/scope-manager@npm:5.62.0" +"@typescript-eslint/project-service@npm:8.61.1": + version: 8.61.1 + resolution: "@typescript-eslint/project-service@npm:8.61.1" dependencies: - "@typescript-eslint/types": "npm:5.62.0" - "@typescript-eslint/visitor-keys": "npm:5.62.0" - checksum: 10c0/861253235576c1c5c1772d23cdce1418c2da2618a479a7de4f6114a12a7ca853011a1e530525d0931c355a8fd237b9cd828fac560f85f9623e24054fd024726f + "@typescript-eslint/tsconfig-utils": "npm:^8.61.1" + "@typescript-eslint/types": "npm:^8.61.1" + debug: "npm:^4.4.3" + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/4ced4f96cbe6b4b1f1f53d02e0e5d1efcb6ca02316d8ea11f9b328f7b3783a76e59b72ebbe233a00452de7466ac176f9836afe8a99c63acc94e8e2d1d31d370b languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/type-utils@npm:5.62.0" +"@typescript-eslint/scope-manager@npm:8.61.1, @typescript-eslint/scope-manager@npm:^8.56.0": + version: 8.61.1 + resolution: "@typescript-eslint/scope-manager@npm:8.61.1" dependencies: - "@typescript-eslint/typescript-estree": "npm:5.62.0" - "@typescript-eslint/utils": "npm:5.62.0" - debug: "npm:^4.3.4" - tsutils: "npm:^3.21.0" + "@typescript-eslint/types": "npm:8.61.1" + "@typescript-eslint/visitor-keys": "npm:8.61.1" + checksum: 10c0/8558b56629acc28da1b90a8254eaf9862a38bf49c0a04680c767ea542f49d683c8c60c43676e0348491d1eac9af25cc67abe0a1bb3cfe90add42523faf48b029 + languageName: node + linkType: hard + +"@typescript-eslint/tsconfig-utils@npm:8.61.1, @typescript-eslint/tsconfig-utils@npm:^8.61.1": + version: 8.61.1 + resolution: "@typescript-eslint/tsconfig-utils@npm:8.61.1" peerDependencies: - eslint: "*" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/93112e34026069a48f0484b98caca1c89d9707842afe14e08e7390af51cdde87378df29d213d3bbd10a7cfe6f91b228031b56218515ce077bdb62ddea9d9f474 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/ab732f3c329f0ee8ea9e7d6c7c7d91b508cc0cf6c48c17d95e5df348d3e475730bd7ce63ac1f90260c80a9339a8a6f2eec8f2a35e1793e956a447130291bb5e3 languageName: node linkType: hard -"@typescript-eslint/types@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/types@npm:5.62.0" - checksum: 10c0/7febd3a7f0701c0b927e094f02e82d8ee2cada2b186fcb938bc2b94ff6fbad88237afc304cbaf33e82797078bbbb1baf91475f6400912f8b64c89be79bfa4ddf +"@typescript-eslint/type-utils@npm:8.61.1": + version: 8.61.1 + resolution: "@typescript-eslint/type-utils@npm:8.61.1" + dependencies: + "@typescript-eslint/types": "npm:8.61.1" + "@typescript-eslint/typescript-estree": "npm:8.61.1" + "@typescript-eslint/utils": "npm:8.61.1" + debug: "npm:^4.4.3" + ts-api-utils: "npm:^2.5.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/c6d112e80e82de3ad5a4f8a875c5caf267fa856df2eb97e3ef945de7b62ad07eff02e1dd9e8943cc2e1388180d4f31f1d97e0300d2e5e662245e322205af67dc + languageName: node + linkType: hard + +"@typescript-eslint/types@npm:8.61.1, @typescript-eslint/types@npm:^8.61.1": + version: 8.61.1 + resolution: "@typescript-eslint/types@npm:8.61.1" + checksum: 10c0/165c3f0d3f4e1d04b310fe2a918c1012d037a0f0913895096eed40895fa72638e414a69e36182fc1bcc78efb9a4b7d81654b8768d8f1c3f43f3f2792694dfa49 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.62.0" +"@typescript-eslint/typescript-estree@npm:8.61.1": + version: 8.61.1 + resolution: "@typescript-eslint/typescript-estree@npm:8.61.1" dependencies: - "@typescript-eslint/types": "npm:5.62.0" - "@typescript-eslint/visitor-keys": "npm:5.62.0" - debug: "npm:^4.3.4" - globby: "npm:^11.1.0" - is-glob: "npm:^4.0.3" - semver: "npm:^7.3.7" - tsutils: "npm:^3.21.0" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/d7984a3e9d56897b2481940ec803cb8e7ead03df8d9cfd9797350be82ff765dfcf3cfec04e7355e1779e948da8f02bc5e11719d07a596eb1cb995c48a95e38cf + "@typescript-eslint/project-service": "npm:8.61.1" + "@typescript-eslint/tsconfig-utils": "npm:8.61.1" + "@typescript-eslint/types": "npm:8.61.1" + "@typescript-eslint/visitor-keys": "npm:8.61.1" + debug: "npm:^4.4.3" + minimatch: "npm:^10.2.2" + semver: "npm:^7.7.3" + tinyglobby: "npm:^0.2.15" + ts-api-utils: "npm:^2.5.0" + peerDependencies: + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/cc3f15e8e30dee0522e9f8b5879824cfe3d98aad6a64e863bf0a21c26eedb3b0e5c82c2b73d59f9d5bc1b66f67305132c7c71f11a542e04e152f92b58599b358 languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.62.0, @typescript-eslint/utils@npm:^5.10.0": - version: 5.62.0 - resolution: "@typescript-eslint/utils@npm:5.62.0" +"@typescript-eslint/utils@npm:8.61.1, @typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.56.0": + version: 8.61.1 + resolution: "@typescript-eslint/utils@npm:8.61.1" dependencies: - "@eslint-community/eslint-utils": "npm:^4.2.0" - "@types/json-schema": "npm:^7.0.9" - "@types/semver": "npm:^7.3.12" - "@typescript-eslint/scope-manager": "npm:5.62.0" - "@typescript-eslint/types": "npm:5.62.0" - "@typescript-eslint/typescript-estree": "npm:5.62.0" - eslint-scope: "npm:^5.1.1" - semver: "npm:^7.3.7" + "@eslint-community/eslint-utils": "npm:^4.9.1" + "@typescript-eslint/scope-manager": "npm:8.61.1" + "@typescript-eslint/types": "npm:8.61.1" + "@typescript-eslint/typescript-estree": "npm:8.61.1" peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 10c0/f09b7d9952e4a205eb1ced31d7684dd55cee40bf8c2d78e923aa8a255318d97279825733902742c09d8690f37a50243f4c4d383ab16bd7aefaf9c4b438f785e1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/afb5e6f39da3ee34c11cfc73a64045a0e5dadd74ae2a2fcf01d9494e3be00c849a3b9ca8b23570f596726611f00598a198d66cd82e3753f63b8bde69ead0e507 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.62.0" +"@typescript-eslint/visitor-keys@npm:8.61.1": + version: 8.61.1 + resolution: "@typescript-eslint/visitor-keys@npm:8.61.1" dependencies: - "@typescript-eslint/types": "npm:5.62.0" - eslint-visitor-keys: "npm:^3.3.0" - checksum: 10c0/7c3b8e4148e9b94d9b7162a596a1260d7a3efc4e65199693b8025c71c4652b8042501c0bc9f57654c1e2943c26da98c0f77884a746c6ae81389fcb0b513d995d + "@typescript-eslint/types": "npm:8.61.1" + eslint-visitor-keys: "npm:^5.0.0" + checksum: 10c0/fa2075b891076fe640cfc36fd68299985f35c9b6782ff35cf231c1418e38dba56b28412bc6fced7fb8fabbd91444a02643f62e1ebe424aa45a885b8a8e60fbfd languageName: node linkType: hard @@ -6832,7 +7263,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.0.4, acorn@npm:^8.11.0, acorn@npm:^8.15.0, acorn@npm:^8.9.0": +"acorn@npm:^8.0.4, acorn@npm:^8.11.0, acorn@npm:^8.15.0": version: 8.15.0 resolution: "acorn@npm:8.15.0" bin: @@ -6906,7 +7337,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.10.0, ajv@npm:^6.12.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5": +"ajv@npm:^6.12.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -6918,6 +7349,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^6.14.0": + version: 6.15.0 + resolution: "ajv@npm:6.15.0" + dependencies: + fast-deep-equal: "npm:^3.1.1" + fast-json-stable-stringify: "npm:^2.0.0" + json-schema-traverse: "npm:^0.4.1" + uri-js: "npm:^4.2.2" + checksum: 10c0/67966499dd272ecde1c2e467084411132891523d057487587879d39ac04207f4351b7b2324c83198013967fbfa632c1612adc960114a30770fbe07a0773b32c2 + languageName: node + linkType: hard + "ajv@npm:^8.0.0, ajv@npm:^8.9.0": version: 8.17.1 resolution: "ajv@npm:8.17.1" @@ -7044,13 +7487,6 @@ __metadata: languageName: node linkType: hard -"ansi-regex@npm:^2.0.0": - version: 2.1.1 - resolution: "ansi-regex@npm:2.1.1" - checksum: 10c0/78cebaf50bce2cb96341a7230adf28d804611da3ce6bf338efa7b72f06cc6ff648e29f80cd95e582617ba58d5fdbec38abfeed3500a98bce8381a9daec7c548b - languageName: node - linkType: hard - "ansi-regex@npm:^4.0.0, ansi-regex@npm:^4.1.0": version: 4.1.1 resolution: "ansi-regex@npm:4.1.1" @@ -7072,13 +7508,6 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^2.2.1": - version: 2.2.1 - resolution: "ansi-styles@npm:2.2.1" - checksum: 10c0/7c68aed4f1857389e7a12f85537ea5b40d832656babbf511cc7ecd9efc52889b9c3e5653a71a6aade783c3c5e0aa223ad4ff8e83c27ac8a666514e6c79068cab - languageName: node - linkType: hard - "ansi-styles@npm:^3.2.0, ansi-styles@npm:^3.2.1": version: 3.2.1 resolution: "ansi-styles@npm:3.2.1" @@ -7097,7 +7526,7 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^5.0.0": +"ansi-styles@npm:^5.0.0, ansi-styles@npm:^5.2.0": version: 5.2.0 resolution: "ansi-styles@npm:5.2.0" checksum: 10c0/9c4ca80eb3c2fb7b33841c210d2f20807f40865d27008d7c3f707b7f95cab7d67462a565e2388ac3285b71cb3d9bb2173de8da37c57692a362885ec34d6e27df @@ -7111,16 +7540,6 @@ __metadata: languageName: node linkType: hard -"anymatch@npm:^1.3.0": - version: 1.3.2 - resolution: "anymatch@npm:1.3.2" - dependencies: - micromatch: "npm:^2.1.5" - normalize-path: "npm:^2.0.0" - checksum: 10c0/aa1eae8ef5076cfecefef1983811b4666b365513d60dfcb30756556cc7e8547fae2654328509beedb812b211da4785df5d42ca720aa24d52e745509ad3a4b2a8 - languageName: node - linkType: hard - "anymatch@npm:^2.0.0": version: 2.0.0 resolution: "anymatch@npm:2.0.0" @@ -7191,15 +7610,6 @@ __metadata: languageName: node linkType: hard -"arr-diff@npm:^2.0.0": - version: 2.0.0 - resolution: "arr-diff@npm:2.0.0" - dependencies: - arr-flatten: "npm:^1.0.1" - checksum: 10c0/d79592bf2b621b9c038e7a697357174409fceb63658529ea3b2d2d53a2918160e6bebb2e6ae756eb53330f07c11b052752377905d743a8928f9d3858598cafa2 - languageName: node - linkType: hard - "arr-diff@npm:^4.0.0": version: 4.0.0 resolution: "arr-diff@npm:4.0.0" @@ -7207,7 +7617,7 @@ __metadata: languageName: node linkType: hard -"arr-flatten@npm:^1.0.1, arr-flatten@npm:^1.1.0": +"arr-flatten@npm:^1.1.0": version: 1.1.0 resolution: "arr-flatten@npm:1.1.0" checksum: 10c0/bef53be02ed3bc58f202b3861a5b1eb6e1ae4fecf39c3ad4d15b1e0433f941077d16e019a33312d820844b0661777322acbb7d0c447b04d9bdf7d6f9c532548a @@ -7275,13 +7685,6 @@ __metadata: languageName: node linkType: hard -"array-unique@npm:^0.2.1": - version: 0.2.1 - resolution: "array-unique@npm:0.2.1" - checksum: 10c0/e72f4c45a432b44f9785b24bb5742648ed68f074a74f7bcf65b3f47630cd6aea05e532ab921f1a5f57266512a02183440b42f683dab95636bb81c8d6e2758641 - languageName: node - linkType: hard - "array-unique@npm:^0.3.2": version: 0.3.2 resolution: "array-unique@npm:0.3.2" @@ -7407,13 +7810,6 @@ __metadata: languageName: node linkType: hard -"async-each@npm:^1.0.0": - version: 1.0.6 - resolution: "async-each@npm:1.0.6" - checksum: 10c0/d4e45e8f077e20e015952c065ceae75f82b30ee2d4a8e56a5c454ae44331aaa009d8c94fe043ba254c177bffae9f6ebeefebb7daf9f7ce4d27fac0274dc328ae - languageName: node - linkType: hard - "async-function@npm:^1.0.0": version: 1.0.0 resolution: "async-function@npm:1.0.0" @@ -7502,110 +7898,6 @@ __metadata: languageName: node linkType: hard -"babel-cli@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-cli@npm:6.26.0" - dependencies: - babel-core: "npm:^6.26.0" - babel-polyfill: "npm:^6.26.0" - babel-register: "npm:^6.26.0" - babel-runtime: "npm:^6.26.0" - chokidar: "npm:^1.6.1" - commander: "npm:^2.11.0" - convert-source-map: "npm:^1.5.0" - fs-readdir-recursive: "npm:^1.0.0" - glob: "npm:^7.1.2" - lodash: "npm:^4.17.4" - output-file-sync: "npm:^1.1.2" - path-is-absolute: "npm:^1.0.1" - slash: "npm:^1.0.0" - source-map: "npm:^0.5.6" - v8flags: "npm:^2.1.1" - dependenciesMeta: - chokidar: - optional: true - bin: - babel: ./bin/babel.js - babel-doctor: ./bin/babel-doctor.js - babel-external-helpers: ./bin/babel-external-helpers.js - babel-node: ./bin/babel-node.js - checksum: 10c0/8b83a100a5e7ea121141c7305dba06d9acf607f545687b9d331adc881beec2ed6ce2a0b0d8d4e75a4d3138eee82a26922841c75f6ff2f94db42331b513008de7 - languageName: node - linkType: hard - -"babel-code-frame@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-code-frame@npm:6.26.0" - dependencies: - chalk: "npm:^1.1.3" - esutils: "npm:^2.0.2" - js-tokens: "npm:^3.0.2" - checksum: 10c0/7fecc128e87578cf1b96e78d2b25e0b260e202bdbbfcefa2eac23b7f8b7b2f7bc9276a14599cde14403cc798cc2a38e428e2cab50b77658ab49228b09ae92473 - languageName: node - linkType: hard - -"babel-core@npm:^6.26.0": - version: 6.26.3 - resolution: "babel-core@npm:6.26.3" - dependencies: - babel-code-frame: "npm:^6.26.0" - babel-generator: "npm:^6.26.0" - babel-helpers: "npm:^6.24.1" - babel-messages: "npm:^6.23.0" - babel-register: "npm:^6.26.0" - babel-runtime: "npm:^6.26.0" - babel-template: "npm:^6.26.0" - babel-traverse: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - babylon: "npm:^6.18.0" - convert-source-map: "npm:^1.5.1" - debug: "npm:^2.6.9" - json5: "npm:^0.5.1" - lodash: "npm:^4.17.4" - minimatch: "npm:^3.0.4" - path-is-absolute: "npm:^1.0.1" - private: "npm:^0.1.8" - slash: "npm:^1.0.0" - source-map: "npm:^0.5.7" - checksum: 10c0/10292649779f8c33d1908f5671c92ca9df036c9e1b9f35f97e7f62c9da9e3a146ee069f94fc401283ce129ba980f34a30339f137c512f3e62ddd354653b2da0e - languageName: node - linkType: hard - -"babel-core@npm:^7.0.0-bridge.0": - version: 7.0.0-bridge.0 - resolution: "babel-core@npm:7.0.0-bridge.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/f57576e30267be4607d163b7288031d332cf9200ea35efe9fb33c97f834e304376774c28c1f9d6928d6733fcde7041e4010f1248a0519e7730c590d4b07b9608 - languageName: node - linkType: hard - -"babel-generator@npm:^6.26.0": - version: 6.26.1 - resolution: "babel-generator@npm:6.26.1" - dependencies: - babel-messages: "npm:^6.23.0" - babel-runtime: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - detect-indent: "npm:^4.0.0" - jsesc: "npm:^1.3.0" - lodash: "npm:^4.17.4" - source-map: "npm:^0.5.7" - trim-right: "npm:^1.0.1" - checksum: 10c0/d5f9d20c6f7d8644dc41ee57d48c98a78d24d5b74dc305cc518d6e0872d4fa73c5fd8d47ec00e3515858eaf3c3e512a703cdbc184ff0061af5979bc206618555 - languageName: node - linkType: hard - -"babel-helpers@npm:^6.24.1": - version: 6.24.1 - resolution: "babel-helpers@npm:6.24.1" - dependencies: - babel-runtime: "npm:^6.22.0" - babel-template: "npm:^6.24.1" - checksum: 10c0/bbd082e42adaa9c584242515e8c5b1e861108e03ed9517f0b600189e1c1041376ab6a15c71265a2cc095c5af4bd15cfc97158e30ce95a81cbfcea1bfd81ce3e6 - languageName: node - linkType: hard - "babel-jest@npm:^29.6.3, babel-jest@npm:^29.7.0": version: 29.7.0 resolution: "babel-jest@npm:29.7.0" @@ -7623,7 +7915,7 @@ __metadata: languageName: node linkType: hard -"babel-loader@npm:^8.1.0, babel-loader@npm:^8.2.3, babel-loader@npm:^8.2.5": +"babel-loader@npm:^8.1.0, babel-loader@npm:^8.2.5": version: 8.4.1 resolution: "babel-loader@npm:8.4.1" dependencies: @@ -7638,15 +7930,6 @@ __metadata: languageName: node linkType: hard -"babel-messages@npm:^6.23.0": - version: 6.23.0 - resolution: "babel-messages@npm:6.23.0" - dependencies: - babel-runtime: "npm:^6.22.0" - checksum: 10c0/d4fd6414ee5bb1aa0dad6d8d2c4ffaa66331ec5a507959e11f56b19a683566e2c1e7a4d0b16cfef58ea4cc07db8acf5ff3dc8b25c585407cff2e09ac60553401 - languageName: node - linkType: hard - "babel-plugin-apply-mdx-type-prop@npm:1.6.22": version: 1.6.22 resolution: "babel-plugin-apply-mdx-type-prop@npm:1.6.22" @@ -7824,7 +8107,7 @@ __metadata: languageName: node linkType: hard -"babel-polyfill@npm:6.26.0, babel-polyfill@npm:^6.26.0": +"babel-polyfill@npm:6.26.0": version: 6.26.0 resolution: "babel-polyfill@npm:6.26.0" dependencies: @@ -7996,22 +8279,7 @@ __metadata: languageName: node linkType: hard -"babel-register@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-register@npm:6.26.0" - dependencies: - babel-core: "npm:^6.26.0" - babel-runtime: "npm:^6.26.0" - core-js: "npm:^2.5.0" - home-or-tmp: "npm:^2.0.0" - lodash: "npm:^4.17.4" - mkdirp: "npm:^0.5.1" - source-map-support: "npm:^0.4.15" - checksum: 10c0/4ffbc1bfa60a817fb306c98d1a6d10852b0130a614dae3a91e45f391dbebdc95f428d95b489943d85724e046527d2aac3bafb74d3c24f62143492b5f606e2e04 - languageName: node - linkType: hard - -"babel-runtime@npm:^6.22.0, babel-runtime@npm:^6.23.0, babel-runtime@npm:^6.26.0": +"babel-runtime@npm:^6.23.0, babel-runtime@npm:^6.26.0": version: 6.26.0 resolution: "babel-runtime@npm:6.26.0" dependencies: @@ -8021,19 +8289,6 @@ __metadata: languageName: node linkType: hard -"babel-template@npm:^6.24.1, babel-template@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-template@npm:6.26.0" - dependencies: - babel-runtime: "npm:^6.26.0" - babel-traverse: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - babylon: "npm:^6.18.0" - lodash: "npm:^4.17.4" - checksum: 10c0/67bc875f19d289dabb1830a1cde93d7f1e187e4599dac9b1d16392fd47f1d12b53fea902dacf7be360acd09807d440faafe0f7907758c13275b1a14d100b68e4 - languageName: node - linkType: hard - "babel-test@npm:^0.1.1": version: 0.1.6 resolution: "babel-test@npm:0.1.6" @@ -8046,44 +8301,6 @@ __metadata: languageName: node linkType: hard -"babel-traverse@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-traverse@npm:6.26.0" - dependencies: - babel-code-frame: "npm:^6.26.0" - babel-messages: "npm:^6.23.0" - babel-runtime: "npm:^6.26.0" - babel-types: "npm:^6.26.0" - babylon: "npm:^6.18.0" - debug: "npm:^2.6.8" - globals: "npm:^9.18.0" - invariant: "npm:^2.2.2" - lodash: "npm:^4.17.4" - checksum: 10c0/dca71b23d07e3c00833c3222d7998202e687105f461048107afeb2b4a7aa2507efab1bd5a6e3e724724ebb9b1e0b14f0113621e1d8c25b4ffdb829392b54b8de - languageName: node - linkType: hard - -"babel-types@npm:^6.26.0": - version: 6.26.0 - resolution: "babel-types@npm:6.26.0" - dependencies: - babel-runtime: "npm:^6.26.0" - esutils: "npm:^2.0.2" - lodash: "npm:^4.17.4" - to-fast-properties: "npm:^1.0.3" - checksum: 10c0/cabe371de1b32c4bbb1fd4ed0fe8a8726d42e5ad7d5cefb83cdae6de0f0a152dce591e4026719743fdf3aa45f84fea2c8851fb822fbe29b0c78a1f0094b67418 - languageName: node - linkType: hard - -"babylon@npm:^6.18.0": - version: 6.18.0 - resolution: "babylon@npm:6.18.0" - bin: - babylon: ./bin/babylon.js - checksum: 10c0/9b1bf946e16782deadb1f5414c1269efa6044eb1e97a3de2051f09a3f2a54e97be3542d4242b28d23de0ef67816f519d38ce1ec3ddb7be306131c39a60e5a667 - languageName: node - linkType: hard - "bail@npm:^1.0.0": version: 1.0.5 resolution: "bail@npm:1.0.5" @@ -8180,13 +8397,6 @@ __metadata: languageName: node linkType: hard -"binary-extensions@npm:^1.0.0": - version: 1.13.1 - resolution: "binary-extensions@npm:1.13.1" - checksum: 10c0/2d616938ac23d828ec3fbe0dea429b566fd2c137ddc38f166f16561ccd58029deac3fa9fddb489ab13d679c8fb5f1bd0e82824041299e5e39d8dd3cc68fbb9f9 - languageName: node - linkType: hard - "binary-extensions@npm:^2.0.0": version: 2.3.0 resolution: "binary-extensions@npm:2.3.0" @@ -8194,15 +8404,6 @@ __metadata: languageName: node linkType: hard -"bindings@npm:^1.5.0": - version: 1.5.0 - resolution: "bindings@npm:1.5.0" - dependencies: - file-uri-to-path: "npm:1.0.0" - checksum: 10c0/3dab2491b4bb24124252a91e656803eac24292473e56554e35bbfe3cc1875332cfa77600c3bac7564049dc95075bf6fcc63a4609920ff2d64d0fe405fcf0d4ba - languageName: node - linkType: hard - "bl@npm:^4.1.0": version: 4.1.0 resolution: "bl@npm:4.1.0" @@ -8345,17 +8546,6 @@ __metadata: languageName: node linkType: hard -"braces@npm:^1.8.2": - version: 1.8.5 - resolution: "braces@npm:1.8.5" - dependencies: - expand-range: "npm:^1.8.1" - preserve: "npm:^0.2.0" - repeat-element: "npm:^1.1.2" - checksum: 10c0/41092fe0f5dbb522f013963fa4432fbef3323a92ee8c1a6b9b6681fc05525b8541968b525632aa9df217daa6307fe526e9ce994054d4308abd0627a7d26e4745 - languageName: node - linkType: hard - "braces@npm:^2.3.1": version: 2.3.2 resolution: "braces@npm:2.3.2" @@ -8752,19 +8942,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^1.1.3": - version: 1.1.3 - resolution: "chalk@npm:1.1.3" - dependencies: - ansi-styles: "npm:^2.2.1" - escape-string-regexp: "npm:^1.0.2" - has-ansi: "npm:^2.0.0" - strip-ansi: "npm:^3.0.0" - supports-color: "npm:^2.0.0" - checksum: 10c0/28c3e399ec286bb3a7111fd4225ebedb0d7b813aef38a37bca7c498d032459c265ef43404201d5fbb8d888d29090899c95335b4c0cda13e8b126ff15c541cef8 - languageName: node - linkType: hard - "chalk@npm:^3.0.0": version: 3.0.0 resolution: "chalk@npm:3.0.0" @@ -8893,26 +9070,6 @@ __metadata: languageName: node linkType: hard -"chokidar@npm:^1.6.1": - version: 1.7.0 - resolution: "chokidar@npm:1.7.0" - dependencies: - anymatch: "npm:^1.3.0" - async-each: "npm:^1.0.0" - fsevents: "npm:^1.0.0" - glob-parent: "npm:^2.0.0" - inherits: "npm:^2.0.1" - is-binary-path: "npm:^1.0.0" - is-glob: "npm:^2.0.0" - path-is-absolute: "npm:^1.0.0" - readdirp: "npm:^2.0.0" - dependenciesMeta: - fsevents: - optional: true - checksum: 10c0/d3f82bc7fba1d5793a05ae494c30536cf6e4b23364a610e8bee8ae49dbaf963a67f70c627a943ab538cab252f6ac1862c6012885bccd06a10487438de5ae8a15 - languageName: node - linkType: hard - "chokidar@npm:^3.4.2, chokidar@npm:^3.5.3": version: 3.6.0 resolution: "chokidar@npm:3.6.0" @@ -9314,7 +9471,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^2.11.0, commander@npm:^2.19.0, commander@npm:^2.20.0": +"commander@npm:^2.19.0, commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" checksum: 10c0/74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288 @@ -9597,21 +9754,6 @@ __metadata: languageName: node linkType: hard -"conventional-changelog-cli@npm:^2.0.11": - version: 2.2.2 - resolution: "conventional-changelog-cli@npm:2.2.2" - dependencies: - add-stream: "npm:^1.0.0" - conventional-changelog: "npm:^3.1.24" - lodash: "npm:^4.17.15" - meow: "npm:^8.0.0" - tempfile: "npm:^3.0.0" - bin: - conventional-changelog: cli.js - checksum: 10c0/f78790778b3e35c0f16d8299af98b03fd6376222047996cbfd2503a45ee86e3462f3276403ff6ee0cdaf7dcd90a2e230e16fc01fa7f64f5b5019a0dd34052ff4 - languageName: node - linkType: hard - "conventional-changelog-codemirror@npm:^2.0.8": version: 2.0.8 resolution: "conventional-changelog-codemirror@npm:2.0.8" @@ -9737,7 +9879,7 @@ __metadata: languageName: node linkType: hard -"conventional-changelog@npm:^3.1.24, conventional-changelog@npm:^3.1.8": +"conventional-changelog@npm:^3.1.8": version: 3.1.25 resolution: "conventional-changelog@npm:3.1.25" dependencies: @@ -9800,7 +9942,7 @@ __metadata: languageName: node linkType: hard -"convert-source-map@npm:^1.5.0, convert-source-map@npm:^1.5.1, convert-source-map@npm:^1.7.0": +"convert-source-map@npm:^1.7.0": version: 1.9.0 resolution: "convert-source-map@npm:1.9.0" checksum: 10c0/281da55454bf8126cbc6625385928c43479f2060984180c42f3a86c8b8c12720a24eac260624a7d1e090004028d2dee78602330578ceec1a08e27cb8bb0a8a5b @@ -9924,7 +10066,7 @@ __metadata: languageName: node linkType: hard -"cosmiconfig@npm:^5.0.7, cosmiconfig@npm:^5.1.0, cosmiconfig@npm:^5.2.0": +"cosmiconfig@npm:^5.1.0, cosmiconfig@npm:^5.2.0": version: 5.2.1 resolution: "cosmiconfig@npm:5.2.1" dependencies: @@ -10028,7 +10170,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6": version: 7.0.6 resolution: "cross-spawn@npm:7.0.6" dependencies: @@ -10363,7 +10505,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:2.6.9, debug@npm:^2.2.0, debug@npm:^2.3.3, debug@npm:^2.6.0, debug@npm:^2.6.8, debug@npm:^2.6.9": +"debug@npm:2.6.9, debug@npm:^2.2.0, debug@npm:^2.3.3, debug@npm:^2.6.0, debug@npm:^2.6.9": version: 2.6.9 resolution: "debug@npm:2.6.9" dependencies: @@ -10687,15 +10829,6 @@ __metadata: languageName: node linkType: hard -"detect-indent@npm:^4.0.0": - version: 4.0.0 - resolution: "detect-indent@npm:4.0.0" - dependencies: - repeating: "npm:^2.0.0" - checksum: 10c0/066a0d13eadebb1e7d2ba395fdf9f3956f31f8383a6db263320108c283e2230250a102f4871f54926cc8a77c6323ac7103f30550a4ac3d6518aa1b934c041295 - languageName: node - linkType: hard - "detect-libc@npm:^2.0.1, detect-libc@npm:^2.0.3": version: 2.1.2 resolution: "detect-libc@npm:2.1.2" @@ -10810,8 +10943,8 @@ __metadata: "@docusaurus/module-type-aliases": "npm:^2.3.6" "@docusaurus/preset-classic": "npm:^2.3.6" "@docusaurus/remark-plugin-npm2yarn": "npm:^2.3.6" + "@docusaurus/theme-common": "npm:^2.3.6" "@easyops-cn/docusaurus-search-local": "npm:^0.33.4" - "@jest/globals": "npm:^29.7.0" "@material/material-color-utilities": "npm:0.2.4" "@mdx-js/react": "npm:^1.6.22" "@react-native-vector-icons/material-design-icons": "npm:^12.0.0" @@ -10833,6 +10966,7 @@ __metadata: react-native-web: "npm:^0.18.12" typescript: "npm:^4.8.4" use-latest-callback: "npm:^0.1.7" + webpack: "npm:^5.73.0" languageName: unknown linkType: soft @@ -11413,14 +11547,14 @@ __metadata: languageName: node linkType: hard -"eslint-config-prettier@npm:^8.3.0": - version: 8.10.2 - resolution: "eslint-config-prettier@npm:8.10.2" +"eslint-config-prettier@npm:^9.0.0": + version: 9.1.2 + resolution: "eslint-config-prettier@npm:9.1.2" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: 10c0/b5953cf7a86f685e1218b16707bf36643b525513d08495226a6820caccd8b7bfc6b9aa64ac7cb2415dbe2c1f7dc4995832148bdc53ad45777f75a8ded1073b29 + checksum: 10c0/d2e9dc913b1677764a4732433d83d258f40820458c65d0274cb9e3eaf6559b39f2136446f310c05abed065a4b3c2e901807ccf583dff76c6227eaebf4132c39a languageName: node linkType: hard @@ -11461,7 +11595,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.25.3": +"eslint-plugin-import@npm:^2.28.1": version: 2.32.0 resolution: "eslint-plugin-import@npm:2.32.0" dependencies: @@ -11490,56 +11624,56 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jest@npm:^27.0.1": - version: 27.9.0 - resolution: "eslint-plugin-jest@npm:27.9.0" +"eslint-plugin-jest@npm:^28.7.0": + version: 28.14.0 + resolution: "eslint-plugin-jest@npm:28.14.0" dependencies: - "@typescript-eslint/utils": "npm:^5.10.0" + "@typescript-eslint/utils": "npm:^6.0.0 || ^7.0.0 || ^8.0.0" peerDependencies: - "@typescript-eslint/eslint-plugin": ^5.0.0 || ^6.0.0 || ^7.0.0 - eslint: ^7.0.0 || ^8.0.0 + "@typescript-eslint/eslint-plugin": ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 jest: "*" peerDependenciesMeta: "@typescript-eslint/eslint-plugin": optional: true jest: optional: true - checksum: 10c0/b8b09f7d8ba3d84a8779a6e95702a6e4dce45ab034e4edf5ddb631e77cd38dcdf791dfd9228e0a0d1d80d1eb2d278deb62ad2ec39f10fb8fd43cec07304e0c38 - languageName: node - linkType: hard - -"eslint-plugin-local-rules@npm:^1.3.2": - version: 1.3.2 - resolution: "eslint-plugin-local-rules@npm:1.3.2" - checksum: 10c0/a6677d0d7ad1e8cf08c175046fe13508c018f0d9294de42905769848aef2fdab9541272177b8b1af59b2ee6650b81a9ea3c5f4be3815be27829c79da2645529d + checksum: 10c0/da9c99dd8a1a80aa0c126ff4558882451dcee61b7e4c88e2407ac27d0c86fad2951384a4b037748e26f8743890b4628c6917b0760b01b7017c53fb29768584bc languageName: node linkType: hard -"eslint-plugin-prettier@npm:^4.0.0": - version: 4.2.5 - resolution: "eslint-plugin-prettier@npm:4.2.5" +"eslint-plugin-prettier@npm:^5.2.1": + version: 5.5.6 + resolution: "eslint-plugin-prettier@npm:5.5.6" dependencies: - prettier-linter-helpers: "npm:^1.0.0" + prettier-linter-helpers: "npm:^1.0.1" + synckit: "npm:^0.11.13" peerDependencies: - eslint: ">=7.28.0" - prettier: ">=2.0.0" + "@types/eslint": ">=8.0.0" + eslint: ">=8.0.0" + eslint-config-prettier: ">= 7.0.0 <10.0.0 || >=10.1.0" + prettier: ">=3.0.0" peerDependenciesMeta: + "@types/eslint": + optional: true eslint-config-prettier: optional: true - checksum: 10c0/75b3cdc90328aacf4cc7fabc522e651bd8208d40634c9b2772274332a696548136dac4608b141863bc462500c5a8012fbc2495623f684f631ddb62c2f5bca0a3 + checksum: 10c0/af37126c947ff3e87ff1ea76408db8cb1c7da966ebdaba68c6dd5924da7eb1b43b1abc4796d753a97b1bc26ea94c5497093e6ab9f8588fffe558d5a554e19bbf languageName: node linkType: hard -"eslint-plugin-promise@npm:^6.0.1": - version: 6.6.0 - resolution: "eslint-plugin-promise@npm:6.6.0" +"eslint-plugin-promise@npm:^7.1.0": + version: 7.3.0 + resolution: "eslint-plugin-promise@npm:7.3.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.4.0" peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - checksum: 10c0/93a667dbc9ff15c4d586b0d40a31c7828314cbbb31b2b9a75802aa4ef536e9457bb3e1a89b384b07aa336dd61b315ae8b0aadc0870210378023dd018819b59b3 + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 + checksum: 10c0/417d3ab57895143bd687aa840804d0d7bbe70227242530eea7d4af7ae680a67d6872ce3a2adcc36dec29009d1861c63717c5887c30da1887153c8e5a181f3eb5 languageName: node linkType: hard -"eslint-plugin-react-hooks@npm:^4.3.0": +"eslint-plugin-react-hooks@npm:^4.6.0": version: 4.6.2 resolution: "eslint-plugin-react-hooks@npm:4.6.2" peerDependencies: @@ -11548,7 +11682,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-native-a11y@npm:^3.2.1": +"eslint-plugin-react-native-a11y@npm:^3.4.1": version: 3.5.1 resolution: "eslint-plugin-react-native-a11y@npm:3.5.1" dependencies: @@ -11568,7 +11702,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react-native@npm:^4.0.0": +"eslint-plugin-react-native@npm:^4.1.0": version: 4.1.0 resolution: "eslint-plugin-react-native@npm:4.1.0" dependencies: @@ -11579,7 +11713,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-react@npm:^7.27.1": +"eslint-plugin-react@npm:^7.35.0": version: 7.37.5 resolution: "eslint-plugin-react@npm:7.37.5" dependencies: @@ -11607,6 +11741,18 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-testing-library@npm:^7.16.2": + version: 7.16.2 + resolution: "eslint-plugin-testing-library@npm:7.16.2" + dependencies: + "@typescript-eslint/scope-manager": "npm:^8.56.0" + "@typescript-eslint/utils": "npm:^8.56.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + checksum: 10c0/ea99f41eee929e0b139d927f8a89bef7ffe3bd33c51fc3c2c93d8e9d146e146395e1f7bb8a34d4b5bd9a1ffe7a1879959fc171e952c731e1e8310b079d9d5c97 + languageName: node + linkType: hard + "eslint-restricted-globals@npm:^0.2.0": version: 0.2.0 resolution: "eslint-restricted-globals@npm:0.2.0" @@ -11614,7 +11760,7 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1": +"eslint-scope@npm:5.1.1": version: 5.1.1 resolution: "eslint-scope@npm:5.1.1" dependencies: @@ -11624,98 +11770,101 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:^7.1.1": - version: 7.2.2 - resolution: "eslint-scope@npm:7.2.2" +"eslint-scope@npm:^8.4.0": + version: 8.4.0 + resolution: "eslint-scope@npm:8.4.0" dependencies: esrecurse: "npm:^4.3.0" estraverse: "npm:^5.2.0" - checksum: 10c0/613c267aea34b5a6d6c00514e8545ef1f1433108097e857225fed40d397dd6b1809dffd11c2fde23b37ca53d7bf935fe04d2a18e6fc932b31837b6ad67e1c116 - languageName: node - linkType: hard - -"eslint-utils@npm:^3.0.0": - version: 3.0.0 - resolution: "eslint-utils@npm:3.0.0" - dependencies: - eslint-visitor-keys: "npm:^2.0.0" - peerDependencies: - eslint: ">=5" - checksum: 10c0/45aa2b63667a8d9b474c98c28af908d0a592bed1a4568f3145cd49fb5d9510f545327ec95561625290313fe126e6d7bdfe3fdbdb6f432689fab6b9497d3bfb52 + checksum: 10c0/407f6c600204d0f3705bd557f81bd0189e69cd7996f408f8971ab5779c0af733d1af2f1412066b40ee1588b085874fc37a2333986c6521669cdbdd36ca5058e0 languageName: node linkType: hard -"eslint-visitor-keys@npm:^2.0.0, eslint-visitor-keys@npm:^2.1.0": +"eslint-visitor-keys@npm:^2.1.0": version: 2.1.0 resolution: "eslint-visitor-keys@npm:2.1.0" checksum: 10c0/9f0e3a2db751d84067d15977ac4b4472efd6b303e369e6ff241a99feac04da758f46d5add022c33d06b53596038dbae4b4aceb27c7e68b8dfc1055b35e495787 languageName: node linkType: hard -"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": +"eslint-visitor-keys@npm:^3.4.3": version: 3.4.3 resolution: "eslint-visitor-keys@npm:3.4.3" checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 languageName: node linkType: hard -"eslint@npm:8.31.0": - version: 8.31.0 - resolution: "eslint@npm:8.31.0" - dependencies: - "@eslint/eslintrc": "npm:^1.4.1" - "@humanwhocodes/config-array": "npm:^0.11.8" +"eslint-visitor-keys@npm:^4.2.1": + version: 4.2.1 + resolution: "eslint-visitor-keys@npm:4.2.1" + checksum: 10c0/fcd43999199d6740db26c58dbe0c2594623e31ca307e616ac05153c9272f12f1364f5a0b1917a8e962268fdecc6f3622c1c2908b4fcc2e047a106fe6de69dc43 + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^5.0.0": + version: 5.0.1 + resolution: "eslint-visitor-keys@npm:5.0.1" + checksum: 10c0/16190bdf2cbae40a1109384c94450c526a79b0b9c3cb21e544256ed85ac48a4b84db66b74a6561d20fe6ab77447f150d711c2ad5ad74df4fcc133736bce99678 + languageName: node + linkType: hard + +"eslint@npm:9.39.4": + version: 9.39.4 + resolution: "eslint@npm:9.39.4" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.8.0" + "@eslint-community/regexpp": "npm:^4.12.1" + "@eslint/config-array": "npm:^0.21.2" + "@eslint/config-helpers": "npm:^0.4.2" + "@eslint/core": "npm:^0.17.0" + "@eslint/eslintrc": "npm:^3.3.5" + "@eslint/js": "npm:9.39.4" + "@eslint/plugin-kit": "npm:^0.4.1" + "@humanfs/node": "npm:^0.16.6" "@humanwhocodes/module-importer": "npm:^1.0.1" - "@nodelib/fs.walk": "npm:^1.2.8" - ajv: "npm:^6.10.0" + "@humanwhocodes/retry": "npm:^0.4.2" + "@types/estree": "npm:^1.0.6" + ajv: "npm:^6.14.0" chalk: "npm:^4.0.0" - cross-spawn: "npm:^7.0.2" + cross-spawn: "npm:^7.0.6" debug: "npm:^4.3.2" - doctrine: "npm:^3.0.0" escape-string-regexp: "npm:^4.0.0" - eslint-scope: "npm:^7.1.1" - eslint-utils: "npm:^3.0.0" - eslint-visitor-keys: "npm:^3.3.0" - espree: "npm:^9.4.0" - esquery: "npm:^1.4.0" + eslint-scope: "npm:^8.4.0" + eslint-visitor-keys: "npm:^4.2.1" + espree: "npm:^10.4.0" + esquery: "npm:^1.5.0" esutils: "npm:^2.0.2" fast-deep-equal: "npm:^3.1.3" - file-entry-cache: "npm:^6.0.1" + file-entry-cache: "npm:^8.0.0" find-up: "npm:^5.0.0" glob-parent: "npm:^6.0.2" - globals: "npm:^13.19.0" - grapheme-splitter: "npm:^1.0.4" ignore: "npm:^5.2.0" - import-fresh: "npm:^3.0.0" imurmurhash: "npm:^0.1.4" is-glob: "npm:^4.0.0" - is-path-inside: "npm:^3.0.3" - js-sdsl: "npm:^4.1.4" - js-yaml: "npm:^4.1.0" json-stable-stringify-without-jsonify: "npm:^1.0.1" - levn: "npm:^0.4.1" lodash.merge: "npm:^4.6.2" - minimatch: "npm:^3.1.2" + minimatch: "npm:^3.1.5" natural-compare: "npm:^1.4.0" - optionator: "npm:^0.9.1" - regexpp: "npm:^3.2.0" - strip-ansi: "npm:^6.0.1" - strip-json-comments: "npm:^3.1.0" - text-table: "npm:^0.2.0" + optionator: "npm:^0.9.3" + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true bin: eslint: bin/eslint.js - checksum: 10c0/55c32aeeb9b5d6d7417a9c5e5789aa5486ffd31cc0cf498ebaa945f2492964ea2372c38eff084eb99948d81d69cc387ca62ddf58e5824fac3c1d0162a53a76f7 + checksum: 10c0/1955067c2d991f0c84f4c4abfafe31bb47fa3b717a7fd3e43fe1e511c6f859d7700cbca969f85661dc4c130f7aeced5e5444884314198a54428f5e5141db9337 languageName: node linkType: hard -"espree@npm:^9.4.0": - version: 9.6.1 - resolution: "espree@npm:9.6.1" +"espree@npm:^10.0.1, espree@npm:^10.4.0": + version: 10.4.0 + resolution: "espree@npm:10.4.0" dependencies: - acorn: "npm:^8.9.0" + acorn: "npm:^8.15.0" acorn-jsx: "npm:^5.3.2" - eslint-visitor-keys: "npm:^3.4.1" - checksum: 10c0/1a2e9b4699b715347f62330bcc76aee224390c28bb02b31a3752e9d07549c473f5f986720483c6469cf3cfb3c9d05df612ffc69eb1ee94b54b739e67de9bb460 + eslint-visitor-keys: "npm:^4.2.1" + checksum: 10c0/c63fe06131c26c8157b4083313cb02a9a54720a08e21543300e55288c40e06c3fc284bdecf108d3a1372c5934a0a88644c98714f38b6ae8ed272b40d9ea08d6b languageName: node linkType: hard @@ -11729,7 +11878,7 @@ __metadata: languageName: node linkType: hard -"esquery@npm:^1.4.0": +"esquery@npm:^1.5.0": version: 1.7.0 resolution: "esquery@npm:1.7.0" dependencies: @@ -11911,15 +12060,6 @@ __metadata: languageName: node linkType: hard -"expand-brackets@npm:^0.1.4": - version: 0.1.5 - resolution: "expand-brackets@npm:0.1.5" - dependencies: - is-posix-bracket: "npm:^0.1.0" - checksum: 10c0/49b7fc1250f5f60ffe640be03777471ce63420eaa9850ce897b32bcf874e7be16b00917c7e2266a310e674ddb4ffe499ca964115bbc3f8c881288a280740aa6f - languageName: node - linkType: hard - "expand-brackets@npm:^2.1.4": version: 2.1.4 resolution: "expand-brackets@npm:2.1.4" @@ -11935,16 +12075,7 @@ __metadata: languageName: node linkType: hard -"expand-range@npm:^1.8.1": - version: 1.8.2 - resolution: "expand-range@npm:1.8.2" - dependencies: - fill-range: "npm:^2.1.0" - checksum: 10c0/ad7911af12f026953c57e3d7b7fe9f750ce2a1d45f7f7d717de890ed6429baf5e8a7224540cd648eeb603d409be0b7a7df09f951693cc83e98dcdc1e0043c23e - languageName: node - linkType: hard - -"expect@npm:^29.0.0, expect@npm:^29.7.0": +"expect@npm:^29.7.0": version: 29.7.0 resolution: "expect@npm:29.7.0" dependencies: @@ -11983,6 +12114,18 @@ __metadata: languageName: node linkType: hard +"expo-constants@npm:~56.0.18": + version: 56.0.18 + resolution: "expo-constants@npm:56.0.18" + dependencies: + "@expo/env": "npm:~2.3.0" + peerDependencies: + expo: "*" + react-native: "*" + checksum: 10c0/4a8c35f4eeeb078c0feb3d5b55da403ef1d151a35b9b3a4e17505cedfb7ddd78cc02d670ebc5b7c9fb11d42052fd1b0c143cd0a652d22fa6a3730685b19ca0b2 + languageName: node + linkType: hard + "expo-crypto@npm:~56.0.3": version: 56.0.3 resolution: "expo-crypto@npm:56.0.3" @@ -12358,15 +12501,6 @@ __metadata: languageName: node linkType: hard -"extglob@npm:^0.3.1": - version: 0.3.2 - resolution: "extglob@npm:0.3.2" - dependencies: - is-extglob: "npm:^1.0.0" - checksum: 10c0/9fcca7651e5c50fc970ec402476fb7a150e27cc2d8b415de8a6719fc111b2e03a9fabbff4fbed51221853f720ad734e842dfaef087ef57bdeb2456dcf0369029 - languageName: node - linkType: hard - "extglob@npm:^2.0.4": version: 2.0.4 resolution: "extglob@npm:2.0.4" @@ -12542,12 +12676,12 @@ __metadata: languageName: node linkType: hard -"file-entry-cache@npm:^6.0.1": - version: 6.0.1 - resolution: "file-entry-cache@npm:6.0.1" +"file-entry-cache@npm:^8.0.0": + version: 8.0.0 + resolution: "file-entry-cache@npm:8.0.0" dependencies: - flat-cache: "npm:^3.0.4" - checksum: 10c0/58473e8a82794d01b38e5e435f6feaf648e3f36fdb3a56e98f417f4efae71ad1c0d4ebd8a9a7c50c3ad085820a93fc7494ad721e0e4ebc1da3573f4e1c3c7cdd + flat-cache: "npm:^4.0.0" + checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638 languageName: node linkType: hard @@ -12575,20 +12709,6 @@ __metadata: languageName: node linkType: hard -"file-uri-to-path@npm:1.0.0": - version: 1.0.0 - resolution: "file-uri-to-path@npm:1.0.0" - checksum: 10c0/3b545e3a341d322d368e880e1c204ef55f1d45cdea65f7efc6c6ce9e0c4d22d802d5629320eb779d006fe59624ac17b0e848d83cc5af7cd101f206cb704f5519 - languageName: node - linkType: hard - -"filename-regex@npm:^2.0.0": - version: 2.0.1 - resolution: "filename-regex@npm:2.0.1" - checksum: 10c0/c669fe758641e4830641a9df1d387f14080d96ddde0ef9525439c6d16f4492ea167109362ea69eedd0eef39ae2739586b71daf5f4dab0847d1d07a01a1190ab3 - languageName: node - linkType: hard - "filename-reserved-regex@npm:^2.0.0": version: 2.0.0 resolution: "filename-reserved-regex@npm:2.0.0" @@ -12614,19 +12734,6 @@ __metadata: languageName: node linkType: hard -"fill-range@npm:^2.1.0": - version: 2.2.4 - resolution: "fill-range@npm:2.2.4" - dependencies: - is-number: "npm:^2.1.0" - isobject: "npm:^2.0.0" - randomatic: "npm:^3.0.0" - repeat-element: "npm:^1.1.2" - repeat-string: "npm:^1.5.2" - checksum: 10c0/1cfd1329311d778a844d5806bd06a5d297047e5ff352c45b4f9fadcda68eb272c8ef2196f1c44224f3fe66c672234453ce89aca94fb00122874bdb3978de5f71 - languageName: node - linkType: hard - "fill-range@npm:^4.0.0": version: 4.0.0 resolution: "fill-range@npm:4.0.0" @@ -12782,14 +12889,13 @@ __metadata: languageName: node linkType: hard -"flat-cache@npm:^3.0.4": - version: 3.2.0 - resolution: "flat-cache@npm:3.2.0" +"flat-cache@npm:^4.0.0": + version: 4.0.1 + resolution: "flat-cache@npm:4.0.1" dependencies: flatted: "npm:^3.2.9" - keyv: "npm:^4.5.3" - rimraf: "npm:^3.0.2" - checksum: 10c0/b76f611bd5f5d68f7ae632e3ae503e678d205cf97a17c6ab5b12f6ca61188b5f1f7464503efae6dc18683ed8f0b41460beb48ac4b9ac63fe6201296a91ba2f75 + keyv: "npm:^4.5.4" + checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc languageName: node linkType: hard @@ -12854,22 +12960,13 @@ __metadata: languageName: node linkType: hard -"for-in@npm:^1.0.1, for-in@npm:^1.0.2": +"for-in@npm:^1.0.2": version: 1.0.2 resolution: "for-in@npm:1.0.2" checksum: 10c0/42bb609d564b1dc340e1996868b67961257fd03a48d7fdafd4f5119530b87f962be6b4d5b7e3a3fc84c9854d149494b1d358e0b0ce9837e64c4c6603a49451d6 languageName: node linkType: hard -"for-own@npm:^0.1.4": - version: 0.1.5 - resolution: "for-own@npm:0.1.5" - dependencies: - for-in: "npm:^1.0.1" - checksum: 10c0/3f82c2ea489ce2eb74c0eb8634d89b30a620801c2cb5f2a83d2d797fe6990d40c1aeac8968783e157b1404cf35bac9acb0a6c46065ec37b38a21b5d896e500bd - languageName: node - linkType: hard - "foreground-child@npm:^2.0.0": version: 2.0.0 resolution: "foreground-child@npm:2.0.0" @@ -13022,13 +13119,6 @@ __metadata: languageName: node linkType: hard -"fs-readdir-recursive@npm:^1.0.0": - version: 1.1.0 - resolution: "fs-readdir-recursive@npm:1.1.0" - checksum: 10c0/7e190393952143e674b6d1ad4abcafa1b5d3e337fcc21b0cb051079a7140a54617a7df193d562ef9faf21bd7b2148a38601b3d5c16261fa76f278d88dc69989c - languageName: node - linkType: hard - "fs.realpath@npm:^1.0.0": version: 1.0.0 resolution: "fs.realpath@npm:1.0.0" @@ -13036,17 +13126,6 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:^1.0.0": - version: 1.2.13 - resolution: "fsevents@npm:1.2.13" - dependencies: - bindings: "npm:^1.5.0" - nan: "npm:^2.12.1" - checksum: 10c0/4427ff08db9ee7327f2c3ad58ec56f9096a917eed861bfffaa2e2be419479cdf37d00750869ab9ecbf5f59f32ad999bd59577d73fc639193e6c0ce52bb253e02 - conditions: os=darwin - languageName: node - linkType: hard - "fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": version: 2.3.3 resolution: "fsevents@npm:2.3.3" @@ -13057,16 +13136,6 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@npm%3A^1.0.0#optional!builtin": - version: 1.2.13 - resolution: "fsevents@patch:fsevents@npm%3A1.2.13#optional!builtin::version=1.2.13&hash=d11327" - dependencies: - bindings: "npm:^1.5.0" - nan: "npm:^2.12.1" - conditions: os=darwin - languageName: node - linkType: hard - "fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" @@ -13198,13 +13267,6 @@ __metadata: languageName: node linkType: hard -"get-stdin@npm:^6.0.0": - version: 6.0.0 - resolution: "get-stdin@npm:6.0.0" - checksum: 10c0/c8971d27ffb72e4aae0f18ba792d2bfec872f662e98e13b182d8611a36f38396b79f43563884f597e667c7bb9ab98f337ee958ae278af5fa7c310ca62845e56b - languageName: node - linkType: hard - "get-stream@npm:^4.0.0, get-stream@npm:^4.1.0": version: 4.1.0 resolution: "get-stream@npm:4.1.0" @@ -13327,25 +13389,6 @@ __metadata: languageName: node linkType: hard -"glob-base@npm:^0.3.0": - version: 0.3.0 - resolution: "glob-base@npm:0.3.0" - dependencies: - glob-parent: "npm:^2.0.0" - is-glob: "npm:^2.0.0" - checksum: 10c0/4ce785c1dac2ff1e4660c010fa43ed2f1b38993dfd004023a3e7080b20bc61f29fbfe5d265b7e64cc84096ecf44e8ca876c7c1aad8f1f995d4c0f33034f3ae8c - languageName: node - linkType: hard - -"glob-parent@npm:^2.0.0": - version: 2.0.0 - resolution: "glob-parent@npm:2.0.0" - dependencies: - is-glob: "npm:^2.0.0" - checksum: 10c0/b9d59dc532d47aaaa4841046ff631b325a707f738445300b83b7a1ee603dd060c041a378e8a195c887d479bb703685cee4725c8f54b8dacef65355375f57d32a - languageName: node - linkType: hard - "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -13393,7 +13436,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.0.0, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": +"glob@npm:^7.0.0, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -13454,19 +13497,17 @@ __metadata: languageName: node linkType: hard -"globals@npm:^13.19.0": - version: 13.24.0 - resolution: "globals@npm:13.24.0" - dependencies: - type-fest: "npm:^0.20.2" - checksum: 10c0/d3c11aeea898eb83d5ec7a99508600fbe8f83d2cf00cbb77f873dbf2bcb39428eff1b538e4915c993d8a3b3473fa71eeebfe22c9bb3a3003d1e26b1f2c8a42cd +"globals@npm:^14.0.0": + version: 14.0.0 + resolution: "globals@npm:14.0.0" + checksum: 10c0/b96ff42620c9231ad468d4c58ff42afee7777ee1c963013ff8aabe095a451d0ceeb8dcd8ef4cbd64d2538cef45f787a78ba3a9574f4a634438963e334471302d languageName: node linkType: hard -"globals@npm:^9.18.0": - version: 9.18.0 - resolution: "globals@npm:9.18.0" - checksum: 10c0/5ab74cb67cf060a9fceede4a0f2babc4c2c0b90dbb13847d2659defdf2121c60035ef23823c8417ce8c11bdaa7b412396077f2b3d2a7dedab490a881a0a96754 +"globals@npm:^15.9.0": + version: 15.15.0 + resolution: "globals@npm:15.15.0" + checksum: 10c0/f9ae80996392ca71316495a39bec88ac43ae3525a438b5626cd9d5ce9d5500d0a98a266409605f8cd7241c7acf57c354a48111ea02a767ba4f374b806d6861fe languageName: node linkType: hard @@ -13580,27 +13621,13 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.4, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.3, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.11, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 languageName: node linkType: hard -"grapheme-splitter@npm:^1.0.4": - version: 1.0.4 - resolution: "grapheme-splitter@npm:1.0.4" - checksum: 10c0/108415fb07ac913f17040dc336607772fcea68c7f495ef91887edddb0b0f5ff7bc1d1ab181b125ecb2f0505669ef12c9a178a3bbd2dd8e042d8c5f1d7c90331a - languageName: node - linkType: hard - -"graphemer@npm:^1.4.0": - version: 1.4.0 - resolution: "graphemer@npm:1.4.0" - checksum: 10c0/e951259d8cd2e0d196c72ec711add7115d42eb9a8146c8eeda5b8d3ac91e5dd816b9cd68920726d9fd4490368e7ed86e9c423f40db87e2d8dfafa00fa17c3a31 - languageName: node - linkType: hard - "gray-matter@npm:^4.0.3": version: 4.0.3 resolution: "gray-matter@npm:4.0.3" @@ -13654,15 +13681,6 @@ __metadata: languageName: node linkType: hard -"has-ansi@npm:^2.0.0": - version: 2.0.0 - resolution: "has-ansi@npm:2.0.0" - dependencies: - ansi-regex: "npm:^2.0.0" - checksum: 10c0/f54e4887b9f8f3c4bfefd649c48825b3c093987c92c27880ee9898539e6f01aed261e82e73153c3f920fde0db5bf6ebd58deb498ed1debabcb4bc40113ccdf05 - languageName: node - linkType: hard - "has-bigints@npm:^1.0.2": version: 1.1.0 resolution: "has-bigints@npm:1.1.0" @@ -14066,16 +14084,6 @@ __metadata: languageName: node linkType: hard -"home-or-tmp@npm:^2.0.0": - version: 2.0.0 - resolution: "home-or-tmp@npm:2.0.0" - dependencies: - os-homedir: "npm:^1.0.0" - os-tmpdir: "npm:^1.0.1" - checksum: 10c0/a0e0d26db09dc0b3245f52a9159d3e970e628ddc22d69842e8413ea42f81d5a29c3808f9b08ea4d48db084e4e693193cc238c114775aa92d753bf95a9daa10fb - languageName: node - linkType: hard - "hosted-git-info@npm:^2.1.4": version: 2.8.9 resolution: "hosted-git-info@npm:2.8.9" @@ -14334,26 +14342,6 @@ __metadata: languageName: node linkType: hard -"husky@npm:^1.3.1": - version: 1.3.1 - resolution: "husky@npm:1.3.1" - dependencies: - cosmiconfig: "npm:^5.0.7" - execa: "npm:^1.0.0" - find-up: "npm:^3.0.0" - get-stdin: "npm:^6.0.0" - is-ci: "npm:^2.0.0" - pkg-dir: "npm:^3.0.0" - please-upgrade-node: "npm:^3.1.1" - read-pkg: "npm:^4.0.1" - run-node: "npm:^1.0.0" - slash: "npm:^2.0.0" - bin: - husky-upgrade: ./lib/upgrader/bin.js - checksum: 10c0/5151906792ef9421536db0a23f922c6f8cb01872a75f0e9a82b22647202350f3791eaf9036cbf68ba911a4c2f3bc601b7507141bd6d9e28ba3222bef8b2679ad - languageName: node - linkType: hard - "hyphenate-style-name@npm:^1.0.3": version: 1.1.0 resolution: "hyphenate-style-name@npm:1.1.0" @@ -14409,7 +14397,7 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^7.0.3": +"ignore@npm:^7.0.3, ignore@npm:^7.0.5": version: 7.0.5 resolution: "ignore@npm:7.0.5" checksum: 10c0/ae00db89fe873064a093b8999fe4cc284b13ef2a178636211842cceb650b9c3e390d3339191acb145d81ed5379d2074840cf0c33a20bdbd6f32821f79eb4ad5d @@ -14636,7 +14624,7 @@ __metadata: languageName: node linkType: hard -"invariant@npm:^2.2.2, invariant@npm:^2.2.4": +"invariant@npm:^2.2.4": version: 2.2.4 resolution: "invariant@npm:2.2.4" dependencies: @@ -14739,15 +14727,6 @@ __metadata: languageName: node linkType: hard -"is-binary-path@npm:^1.0.0": - version: 1.0.1 - resolution: "is-binary-path@npm:1.0.1" - dependencies: - binary-extensions: "npm:^1.0.0" - checksum: 10c0/16e456fa3782eaf3d8e28d382b750507e3d54ff6694df8a1b2c6498da321e2ead311de9c42e653d8fb3213de72bac204b5f97e4a110cda8a72f17b1c1b4eb643 - languageName: node - linkType: hard - "is-binary-path@npm:~2.1.0": version: 2.1.0 resolution: "is-binary-path@npm:2.1.0" @@ -14881,22 +14860,6 @@ __metadata: languageName: node linkType: hard -"is-dotfile@npm:^1.0.0": - version: 1.0.3 - resolution: "is-dotfile@npm:1.0.3" - checksum: 10c0/aa6bb345aa06555f46eedd491bdd039b95d3fa80b899ee7d6b30628e309d705d403e445fd8a126ff70962adc1252171dbe0d72884afa323fb3c817387faf10ed - languageName: node - linkType: hard - -"is-equal-shallow@npm:^0.1.3": - version: 0.1.3 - resolution: "is-equal-shallow@npm:0.1.3" - dependencies: - is-primitive: "npm:^2.0.0" - checksum: 10c0/ae623698cdfeeec0688b2e6128d76cabe1cc5957d533bf7f7596caf3f2993d4c50a20c97420e60a0d58745fc4b2709dfb62e653e054cf948c5834615b715f05f - languageName: node - linkType: hard - "is-extendable@npm:^0.1.0, is-extendable@npm:^0.1.1": version: 0.1.1 resolution: "is-extendable@npm:0.1.1" @@ -14913,13 +14876,6 @@ __metadata: languageName: node linkType: hard -"is-extglob@npm:^1.0.0": - version: 1.0.0 - resolution: "is-extglob@npm:1.0.0" - checksum: 10c0/1ce5366d19958f36069a45ca996c1e51ab607f42a01eb0505f0ccffe8f9c91f5bcba6e971605efd8b4d4dfd0111afa3c8df3e1746db5b85b9a8f933f5e7286b7 - languageName: node - linkType: hard - "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" @@ -14936,13 +14892,6 @@ __metadata: languageName: node linkType: hard -"is-finite@npm:^1.0.0": - version: 1.1.0 - resolution: "is-finite@npm:1.1.0" - checksum: 10c0/ca6bc7a0321b339f098e657bd4cbf4bb2410f5a11f1b9adb1a1a9ab72288b64368e8251326cb1f74e985f2779299cec3e1f1e558b68ce7e1e2c9be17b7cfd626 - languageName: node - linkType: hard - "is-fullwidth-code-point@npm:^2.0.0": version: 2.0.0 resolution: "is-fullwidth-code-point@npm:2.0.0" @@ -14977,15 +14926,6 @@ __metadata: languageName: node linkType: hard -"is-glob@npm:^2.0.0, is-glob@npm:^2.0.1": - version: 2.0.1 - resolution: "is-glob@npm:2.0.1" - dependencies: - is-extglob: "npm:^1.0.0" - checksum: 10c0/ef156806af0924983325c9218a8b8a838fa50e1a104ed2a11fe94829a5b27c1b05a4c8cf98d96cb3a7fea539c21f14ae2081e1a248f3d5a9eea62f2d4e9f8b0c - languageName: node - linkType: hard - "is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1": version: 4.0.3 resolution: "is-glob@npm:4.0.3" @@ -15076,15 +15016,6 @@ __metadata: languageName: node linkType: hard -"is-number@npm:^2.1.0": - version: 2.1.0 - resolution: "is-number@npm:2.1.0" - dependencies: - kind-of: "npm:^3.0.2" - checksum: 10c0/f9d2079a0dbfbce6f9f3b6644f6eb60d0211ee56bb26db3963ef4d514e2444f87e3f56c8169896c90544c501ed5e510c5b83abae6748a57d15f6ac8d85efd602 - languageName: node - linkType: hard - "is-number@npm:^3.0.0": version: 3.0.0 resolution: "is-number@npm:3.0.0" @@ -15094,13 +15025,6 @@ __metadata: languageName: node linkType: hard -"is-number@npm:^4.0.0": - version: 4.0.0 - resolution: "is-number@npm:4.0.0" - checksum: 10c0/bb17a331f357eb59a7f8db848086c41886715b2ea1db03f284a99d14001cda094083a5b6a7b343b5bcf410ccef668a70bc626d07bc2032cc4ab46dd264cea244 - languageName: node - linkType: hard - "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" @@ -15136,7 +15060,7 @@ __metadata: languageName: node linkType: hard -"is-path-inside@npm:^3.0.1, is-path-inside@npm:^3.0.2, is-path-inside@npm:^3.0.3": +"is-path-inside@npm:^3.0.1, is-path-inside@npm:^3.0.2": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" checksum: 10c0/cf7d4ac35fb96bab6a1d2c3598fe5ebb29aafb52c0aaa482b5a3ed9d8ba3edc11631e3ec2637660c44b3ce0e61a08d54946e8af30dec0b60a7c27296c68ffd05 @@ -15187,20 +15111,6 @@ __metadata: languageName: node linkType: hard -"is-posix-bracket@npm:^0.1.0": - version: 0.1.1 - resolution: "is-posix-bracket@npm:0.1.1" - checksum: 10c0/13ef3f466700fd63c1c348e647edfa22b73bb89cf8d993fb7820824ea2ddc7119975e64861fe1d52c3c4e881a7dcf2538faa05e3f700e9d2ea56eeeb4ba26a25 - languageName: node - linkType: hard - -"is-primitive@npm:^2.0.0": - version: 2.0.0 - resolution: "is-primitive@npm:2.0.0" - checksum: 10c0/bb84a2f05eca29f560aafc3bca9173e4c06d74dc24a6fc7faee6e61c70a00bae95e08f0d3d217d61e646b521378d4326103d124bb469d1de0240c8722b56a3fd - languageName: node - linkType: hard - "is-regex@npm:^1.2.1": version: 1.2.1 resolution: "is-regex@npm:1.2.1" @@ -15645,6 +15555,18 @@ __metadata: languageName: node linkType: hard +"jest-diff@npm:30.4.1": + version: 30.4.1 + resolution: "jest-diff@npm:30.4.1" + dependencies: + "@jest/diff-sequences": "npm:30.4.0" + "@jest/get-type": "npm:30.1.0" + chalk: "npm:^4.1.2" + pretty-format: "npm:30.4.1" + checksum: 10c0/787e11f0ea27e94815479d6c5415e4173da1e74bede34c1515b8515fc9d1fe053e2ad25a3c31f9998a7292c186a0e4d395ed82e0e149d57d7708ee6759b442e9 + languageName: node + linkType: hard + "jest-diff@npm:^24.8.0": version: 24.9.0 resolution: "jest-diff@npm:24.9.0" @@ -15657,7 +15579,7 @@ __metadata: languageName: node linkType: hard -"jest-diff@npm:^29.0.1, jest-diff@npm:^29.7.0": +"jest-diff@npm:^29.7.0": version: 29.7.0 resolution: "jest-diff@npm:29.7.0" dependencies: @@ -15764,7 +15686,7 @@ __metadata: languageName: node linkType: hard -"jest-matcher-utils@npm:^29.0.1, jest-matcher-utils@npm:^29.7.0": +"jest-matcher-utils@npm:^29.7.0": version: 29.7.0 resolution: "jest-matcher-utils@npm:29.7.0" dependencies: @@ -15776,6 +15698,18 @@ __metadata: languageName: node linkType: hard +"jest-matcher-utils@npm:^30.4.1": + version: 30.4.1 + resolution: "jest-matcher-utils@npm:30.4.1" + dependencies: + "@jest/get-type": "npm:30.1.0" + chalk: "npm:^4.1.2" + jest-diff: "npm:30.4.1" + pretty-format: "npm:30.4.1" + checksum: 10c0/ddbb0c7075def27ba30160883c327cb3fd13f561f5789d00a1edca1b48b0651f8ea23a1c51bcfcb6413a68c47d658bcf47a34701b8a39ce135dd28d87a3117af + languageName: node + linkType: hard + "jest-message-util@npm:^29.7.0": version: 29.7.0 resolution: "jest-message-util@npm:29.7.0" @@ -16052,13 +15986,6 @@ __metadata: languageName: node linkType: hard -"js-sdsl@npm:^4.1.4": - version: 4.4.2 - resolution: "js-sdsl@npm:4.4.2" - checksum: 10c0/50707728fc31642164f4d83c8087f3750aaa99c450b008b19e236a1f190c9e48f9fc799615c341f9ca2c0803b15ab6f48d92a9cc3e6ffd20065cba7d7e742b92 - languageName: node - linkType: hard - "js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -16066,13 +15993,6 @@ __metadata: languageName: node linkType: hard -"js-tokens@npm:^3.0.2": - version: 3.0.2 - resolution: "js-tokens@npm:3.0.2" - checksum: 10c0/e3c3ee4d12643d90197628eb022a2884a15f08ea7dcac1ce97fdeee43031fbfc7ede674f2cdbbb582dcd4c94388b22e52d56c6cbeb2ac7d1b57c2f33c405e2ba - languageName: node - linkType: hard - "js-yaml@npm:^3.13.1": version: 3.14.2 resolution: "js-yaml@npm:3.14.2" @@ -16096,6 +16016,17 @@ __metadata: languageName: node linkType: hard +"js-yaml@npm:^4.1.1": + version: 4.2.0 + resolution: "js-yaml@npm:4.2.0" + dependencies: + argparse: "npm:^2.0.1" + bin: + js-yaml: bin/js-yaml.js + checksum: 10c0/1916456c118746603b067d74bbcbb0445d9a1d5e474ad4ae775e7b20525bed902e01d9d97dd0c81fcd8d4f596162309d0eb057f4aa38f3e9647f14075e9dea45 + languageName: node + linkType: hard + "jsc-safe-url@npm:^0.2.2, jsc-safe-url@npm:^0.2.4": version: 0.2.4 resolution: "jsc-safe-url@npm:0.2.4" @@ -16103,15 +16034,6 @@ __metadata: languageName: node linkType: hard -"jsesc@npm:^1.3.0": - version: 1.3.0 - resolution: "jsesc@npm:1.3.0" - bin: - jsesc: bin/jsesc - checksum: 10c0/62420889dd46b4cdba4df20fe6ffdefa6eeab7532fb4079170ea1b53c45d5a6abcb485144905833e5a69cc1735db12319b1e0b0f9a556811ec926b57a22318a7 - languageName: node - linkType: hard - "jsesc@npm:^3.0.2, jsesc@npm:~3.1.0": version: 3.1.0 resolution: "jsesc@npm:3.1.0" @@ -16188,15 +16110,6 @@ __metadata: languageName: node linkType: hard -"json5@npm:^0.5.1": - version: 0.5.1 - resolution: "json5@npm:0.5.1" - bin: - json5: lib/cli.js - checksum: 10c0/aca0ab7ccf1883d3fc2ecc16219bc389716a773f774552817deaadb549acc0bb502e317a81946fc0a48f9eb6e0822cf1dc5a097009203f2c94de84c8db02a1f3 - languageName: node - linkType: hard - "json5@npm:^1.0.1, json5@npm:^1.0.2": version: 1.0.2 resolution: "json5@npm:1.0.2" @@ -16270,7 +16183,7 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^4.0.0, keyv@npm:^4.5.3": +"keyv@npm:^4.0.0, keyv@npm:^4.5.4": version: 4.5.4 resolution: "keyv@npm:4.5.4" dependencies: @@ -16336,22 +16249,133 @@ __metadata: languageName: node linkType: hard -"latest-version@npm:^5.0.0, latest-version@npm:^5.1.0": - version: 5.1.0 - resolution: "latest-version@npm:5.1.0" - dependencies: - package-json: "npm:^6.3.0" - checksum: 10c0/6219631d8651467c54c58ef1b5d5c5c53e146f5ae2b0ecbb78b202da3eaad55b05b043db2d2d6f1d4230ee071b2ae8c2f85089e01377e4338bad97fa76a963b7 +"latest-version@npm:^5.0.0, latest-version@npm:^5.1.0": + version: 5.1.0 + resolution: "latest-version@npm:5.1.0" + dependencies: + package-json: "npm:^6.3.0" + checksum: 10c0/6219631d8651467c54c58ef1b5d5c5c53e146f5ae2b0ecbb78b202da3eaad55b05b043db2d2d6f1d4230ee071b2ae8c2f85089e01377e4338bad97fa76a963b7 + languageName: node + linkType: hard + +"launch-editor@npm:^2.6.0": + version: 2.12.0 + resolution: "launch-editor@npm:2.12.0" + dependencies: + picocolors: "npm:^1.1.1" + shell-quote: "npm:^1.8.3" + checksum: 10c0/fac5e7ad90bf185594cad4c831a52419eef50e667c4eddb5b0a58eb5f944e16d947636ee767b9896ffd46a51db34925edd3b854c48efb47f6d767ffd7d904e71 + languageName: node + linkType: hard + +"lefthook-darwin-arm64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-darwin-arm64@npm:2.1.9" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"lefthook-darwin-x64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-darwin-x64@npm:2.1.9" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"lefthook-freebsd-arm64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-freebsd-arm64@npm:2.1.9" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"lefthook-freebsd-x64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-freebsd-x64@npm:2.1.9" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"lefthook-linux-arm64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-linux-arm64@npm:2.1.9" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"lefthook-linux-x64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-linux-x64@npm:2.1.9" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"lefthook-openbsd-arm64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-openbsd-arm64@npm:2.1.9" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"lefthook-openbsd-x64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-openbsd-x64@npm:2.1.9" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"lefthook-windows-arm64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-windows-arm64@npm:2.1.9" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"lefthook-windows-x64@npm:2.1.9": + version: 2.1.9 + resolution: "lefthook-windows-x64@npm:2.1.9" + conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"launch-editor@npm:^2.6.0": - version: 2.12.0 - resolution: "launch-editor@npm:2.12.0" +"lefthook@npm:^2.1.9": + version: 2.1.9 + resolution: "lefthook@npm:2.1.9" dependencies: - picocolors: "npm:^1.1.1" - shell-quote: "npm:^1.8.3" - checksum: 10c0/fac5e7ad90bf185594cad4c831a52419eef50e667c4eddb5b0a58eb5f944e16d947636ee767b9896ffd46a51db34925edd3b854c48efb47f6d767ffd7d904e71 + lefthook-darwin-arm64: "npm:2.1.9" + lefthook-darwin-x64: "npm:2.1.9" + lefthook-freebsd-arm64: "npm:2.1.9" + lefthook-freebsd-x64: "npm:2.1.9" + lefthook-linux-arm64: "npm:2.1.9" + lefthook-linux-x64: "npm:2.1.9" + lefthook-openbsd-arm64: "npm:2.1.9" + lefthook-openbsd-x64: "npm:2.1.9" + lefthook-windows-arm64: "npm:2.1.9" + lefthook-windows-x64: "npm:2.1.9" + dependenciesMeta: + lefthook-darwin-arm64: + optional: true + lefthook-darwin-x64: + optional: true + lefthook-freebsd-arm64: + optional: true + lefthook-freebsd-x64: + optional: true + lefthook-linux-arm64: + optional: true + lefthook-linux-x64: + optional: true + lefthook-openbsd-arm64: + optional: true + lefthook-openbsd-x64: + optional: true + lefthook-windows-arm64: + optional: true + lefthook-windows-x64: + optional: true + bin: + lefthook: bin/index.js + checksum: 10c0/676d9798942439d1cd5373bb0b2c9907f6a8097b29c05cc028d87d897d2a2cfe15a8f7e4f40b02fa93cd1ae0f02528f24053a10fb5c5967210a9c23f3c7b5059 languageName: node linkType: hard @@ -16718,7 +16742,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:4.17.21, lodash@npm:^4.0.1, lodash@npm:^4.11.2, lodash@npm:^4.17.11, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:^4.17.5, lodash@npm:^4.2.1": +"lodash@npm:4.17.21, lodash@npm:^4.0.1, lodash@npm:^4.11.2, lodash@npm:^4.17.11, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.5, lodash@npm:^4.2.1": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c @@ -17012,13 +17036,6 @@ __metadata: languageName: node linkType: hard -"math-random@npm:^1.0.1": - version: 1.0.4 - resolution: "math-random@npm:1.0.4" - checksum: 10c0/7b0ddc17f5dfe3b426c1e92505122e6a32f884dd50f5e0bb3898e5ce2da60b4ffb47c9b607809cf0beb5b8bf253b9dcc3b6f7331b20ce59b8bd7e8dbbbb1e347 - languageName: node - linkType: hard - "mdast-squeeze-paragraphs@npm:^3.0.0": version: 3.0.5 resolution: "mdast-squeeze-paragraphs@npm:3.0.5" @@ -17458,28 +17475,7 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^2.1.5": - version: 2.3.11 - resolution: "micromatch@npm:2.3.11" - dependencies: - arr-diff: "npm:^2.0.0" - array-unique: "npm:^0.2.1" - braces: "npm:^1.8.2" - expand-brackets: "npm:^0.1.4" - extglob: "npm:^0.3.1" - filename-regex: "npm:^2.0.0" - is-extglob: "npm:^1.0.0" - is-glob: "npm:^2.0.1" - kind-of: "npm:^3.0.2" - normalize-path: "npm:^2.0.1" - object.omit: "npm:^2.0.0" - parse-glob: "npm:^3.0.4" - regex-cache: "npm:^0.4.2" - checksum: 10c0/56864f45f5a76523a3b3fe7c07c1a19cb9e6a2078b1e5dd036bacdd6e65f5d8adc00679ebb785ab88d577fce80197f2d8fd6f5565188643f87d8a47f64f6127a - languageName: node - linkType: hard - -"micromatch@npm:^3.1.10, micromatch@npm:^3.1.4": +"micromatch@npm:^3.1.4": version: 3.1.10 resolution: "micromatch@npm:3.1.10" dependencies: @@ -17684,6 +17680,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^3.1.5": + version: 3.1.5 + resolution: "minimatch@npm:3.1.5" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: 10c0/2ecbdc0d33f07bddb0315a8b5afbcb761307a8778b48f0b312418ccbced99f104a2d17d8aca7573433c70e8ccd1c56823a441897a45e384ea76ef401a26ace70 + languageName: node + linkType: hard + "minimist-options@npm:4.1.0": version: 4.1.0 resolution: "minimist-options@npm:4.1.0" @@ -17929,15 +17934,6 @@ __metadata: languageName: node linkType: hard -"nan@npm:^2.12.1": - version: 2.24.0 - resolution: "nan@npm:2.24.0" - dependencies: - node-gyp: "npm:latest" - checksum: 10c0/6f9828a15464999ccefcae61b0f94f1f37067048a56363966e892cc6a194e3500966ae6964dd5a6a8acc5e1a849d60d620b120a84bc66c60445379a930c5b0f8 - languageName: node - linkType: hard - "nanoid@npm:^3.3.11": version: 3.3.11 resolution: "nanoid@npm:3.3.11" @@ -17975,13 +17971,6 @@ __metadata: languageName: node linkType: hard -"natural-compare-lite@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare-lite@npm:1.4.0" - checksum: 10c0/f6cef26f5044515754802c0fc475d81426f3b90fe88c20fabe08771ce1f736ce46e0397c10acb569a4dd0acb84c7f1ee70676122f95d5bfdd747af3a6c6bbaa8 - languageName: node - linkType: hard - "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" @@ -18178,7 +18167,7 @@ __metadata: languageName: node linkType: hard -"normalize-path@npm:^2.0.0, normalize-path@npm:^2.0.1, normalize-path@npm:^2.1.1": +"normalize-path@npm:^2.1.1": version: 2.1.1 resolution: "normalize-path@npm:2.1.1" dependencies: @@ -18379,16 +18368,6 @@ __metadata: languageName: node linkType: hard -"object.omit@npm:^2.0.0": - version: 2.0.1 - resolution: "object.omit@npm:2.0.1" - dependencies: - for-own: "npm:^0.1.4" - is-extendable: "npm:^0.1.1" - checksum: 10c0/219549087650a1dce1990bbb9c207aa9e0c5302372cbcb363b4a7a36a7b1655a80287d290bebcaff5ae4b5ab7e5859a57f49e3f766cade65bc149fe15c0ba38d - languageName: node - linkType: hard - "object.pick@npm:^1.3.0": version: 1.3.0 resolution: "object.pick@npm:1.3.0" @@ -18508,7 +18487,7 @@ __metadata: languageName: node linkType: hard -"optionator@npm:^0.9.1": +"optionator@npm:^0.9.3": version: 0.9.4 resolution: "optionator@npm:0.9.4" dependencies: @@ -18553,13 +18532,6 @@ __metadata: languageName: node linkType: hard -"os-homedir@npm:^1.0.0": - version: 1.0.2 - resolution: "os-homedir@npm:1.0.2" - checksum: 10c0/6be4aa67317ee247b8d46142e243fb4ef1d2d65d3067f54bfc5079257a2f4d4d76b2da78cba7af3cb3f56dbb2e4202e0c47f26171d11ca1ed4008d842c90363f - languageName: node - linkType: hard - "os-name@npm:4.0.0": version: 4.0.0 resolution: "os-name@npm:4.0.0" @@ -18570,24 +18542,13 @@ __metadata: languageName: node linkType: hard -"os-tmpdir@npm:^1.0.1, os-tmpdir@npm:~1.0.1, os-tmpdir@npm:~1.0.2": +"os-tmpdir@npm:~1.0.1, os-tmpdir@npm:~1.0.2": version: 1.0.2 resolution: "os-tmpdir@npm:1.0.2" checksum: 10c0/f438450224f8e2687605a8dd318f0db694b6293c5d835ae509a69e97c8de38b6994645337e5577f5001115470414638978cc49da1cdcc25106dad8738dc69990 languageName: node linkType: hard -"output-file-sync@npm:^1.1.2": - version: 1.1.2 - resolution: "output-file-sync@npm:1.1.2" - dependencies: - graceful-fs: "npm:^4.1.4" - mkdirp: "npm:^0.5.1" - object-assign: "npm:^4.1.0" - checksum: 10c0/b77185cb61fe209061898180eefab0d2c619e87cf5f6de14fa2c043a38795c8f00109624b017966a4528a2eab8b5f34e37a81cb48f31e1ebad5193f00e8fe8a4 - languageName: node - linkType: hard - "own-keys@npm:^1.0.1": version: 1.0.1 resolution: "own-keys@npm:1.0.1" @@ -18816,18 +18777,6 @@ __metadata: languageName: node linkType: hard -"parse-glob@npm:^3.0.4": - version: 3.0.4 - resolution: "parse-glob@npm:3.0.4" - dependencies: - glob-base: "npm:^0.3.0" - is-dotfile: "npm:^1.0.0" - is-extglob: "npm:^1.0.0" - is-glob: "npm:^2.0.0" - checksum: 10c0/4faf2e81ca85bc545777a1210ab770e0305c9e095680c219e5635e1a439d763feaf761e055b136425c3d6dcd3ec9431b77fd20f7411525b21031620125dc1dbc - languageName: node - linkType: hard - "parse-json@npm:5.2.0, parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" @@ -19027,7 +18976,7 @@ __metadata: languageName: node linkType: hard -"path-is-absolute@npm:^1.0.0, path-is-absolute@npm:^1.0.1": +"path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" checksum: 10c0/127da03c82172a2a50099cddbf02510c1791fc2cc5f7713ddb613a56838db1e8168b121a920079d052e0936c23005562059756d653b7c544c53185efe53be078 @@ -19234,15 +19183,6 @@ __metadata: languageName: node linkType: hard -"please-upgrade-node@npm:^3.1.1": - version: 3.2.0 - resolution: "please-upgrade-node@npm:3.2.0" - dependencies: - semver-compare: "npm:^1.0.0" - checksum: 10c0/222514d2841022be4b843f38d415beadcc6409c0545d6d153778d71c601bba7bbf1cd5827d650c7fae6a9a2ba7cf00f4b6729b40d015a3a5ba2937e57bc1c435 - languageName: node - linkType: hard - "plist@npm:^3.0.5, plist@npm:^3.1.0": version: 3.1.0 resolution: "plist@npm:3.1.0" @@ -19788,14 +19728,7 @@ __metadata: languageName: node linkType: hard -"preserve@npm:^0.2.0": - version: 0.2.0 - resolution: "preserve@npm:0.2.0" - checksum: 10c0/21154ae0e53e3a338bcdf61dd6859a62f12f198961509fe07ac4f7f59b6f97de0b60c0dda2cce18e57894c77fa22544c8941c4e6f41fc30ed36753763fba6f19 - languageName: node - linkType: hard - -"prettier-linter-helpers@npm:^1.0.0": +"prettier-linter-helpers@npm:^1.0.1": version: 1.0.1 resolution: "prettier-linter-helpers@npm:1.0.1" dependencies: @@ -19804,7 +19737,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^2, prettier@npm:^2.4.1": +"prettier@npm:^2": version: 2.8.8 resolution: "prettier@npm:2.8.8" bin: @@ -19813,6 +19746,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^3.0.3, prettier@npm:^3.8.4": + version: 3.8.4 + resolution: "prettier@npm:3.8.4" + bin: + prettier: bin/prettier.cjs + checksum: 10c0/b90a0cbe75b88ac0af9c13fe0f359bd19926fabccd88483227b21f71f0c1cc42da056fc1ac3a361e665577c568371d5ccfb2c62c31c8a1186f8d1bd531a063e9 + languageName: node + linkType: hard + "pretty-error@npm:^4.0.0": version: 4.0.0 resolution: "pretty-error@npm:4.0.0" @@ -19823,6 +19765,18 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:30.4.1, pretty-format@npm:^30.4.1": + version: 30.4.1 + resolution: "pretty-format@npm:30.4.1" + dependencies: + "@jest/schemas": "npm:30.4.1" + ansi-styles: "npm:^5.2.0" + react-is-18: "npm:react-is@^18.3.1" + react-is-19: "npm:react-is@^19.2.5" + checksum: 10c0/c7e6633740cd2f6d382f188c00c8b4b3f2bee3cda16db6753471c6bb4b94f76531358d3a7793062a0fb00d72ebfb934e8ae1d4f5ced6bb34c8e7f60996f90076 + languageName: node + linkType: hard + "pretty-format@npm:^24.9.0": version: 24.9.0 resolution: "pretty-format@npm:24.9.0" @@ -19835,7 +19789,7 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.0.3, pretty-format@npm:^29.7.0": +"pretty-format@npm:^29.7.0": version: 29.7.0 resolution: "pretty-format@npm:29.7.0" dependencies: @@ -19876,13 +19830,6 @@ __metadata: languageName: node linkType: hard -"private@npm:^0.1.8": - version: 0.1.8 - resolution: "private@npm:0.1.8" - checksum: 10c0/829a23723e5fd3105c72b2dadeeb65743a430f7e6967a8a6f3e49392a1b3ea52975a255376d8c513b0c988bdf162f1a5edf9d9bac27d1ab11f8dba8cdb58880e - languageName: node - linkType: hard - "proc-log@npm:^4.0.0": version: 4.2.0 resolution: "proc-log@npm:4.2.0" @@ -20140,17 +20087,6 @@ __metadata: languageName: node linkType: hard -"randomatic@npm:^3.0.0": - version: 3.1.1 - resolution: "randomatic@npm:3.1.1" - dependencies: - is-number: "npm:^4.0.0" - kind-of: "npm:^6.0.0" - math-random: "npm:^1.0.1" - checksum: 10c0/4b1da4b8e234d3d0bd2294a42541dfa03edbde85ee06fa0722e2b004e845da197d72fa7995723d32ea7d7402823ea62550034118cf22e94638560a509cec5bfc - languageName: node - linkType: hard - "randombytes@npm:^2.1.0": version: 2.1.0 resolution: "randombytes@npm:2.1.0" @@ -20367,6 +20303,20 @@ __metadata: languageName: node linkType: hard +"react-is-18@npm:react-is@^18.3.1, react-is@npm:^18.0.0": + version: 18.3.1 + resolution: "react-is@npm:18.3.1" + checksum: 10c0/f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072 + languageName: node + linkType: hard + +"react-is-19@npm:react-is@^19.2.5": + version: 19.2.7 + resolution: "react-is@npm:19.2.7" + checksum: 10c0/419fe54d5bd7fdf5414a5bb7bd9a1e0e36f9fae28ffb4cb73290fbe342bde15d8584a90d1db62547f6aa03018dce517b178a041abb522136cd4b4b51b4e94c83 + languageName: node + linkType: hard + "react-is@npm:^16.13.1, react-is@npm:^16.6.0, react-is@npm:^16.7.0, react-is@npm:^16.8.3, react-is@npm:^16.8.4": version: 16.13.1 resolution: "react-is@npm:16.13.1" @@ -20374,13 +20324,6 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^18.0.0": - version: 18.3.1 - resolution: "react-is@npm:18.3.1" - checksum: 10c0/f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072 - languageName: node - linkType: hard - "react-is@npm:^19.1.0": version: 19.2.3 resolution: "react-is@npm:19.2.3" @@ -20388,13 +20331,6 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^19.2.3": - version: 19.2.6 - resolution: "react-is@npm:19.2.6" - checksum: 10c0/263177f370fc156b279d22570dd6e922a0ad641a4a426a4cb70284b8003b00ef532d59f2beca1d22a1ca0b37f85f9077d7733ca5d344ebecd2942e9bc2a2a3c0 - languageName: node - linkType: hard - "react-json-view@npm:^1.21.3": version: 1.21.3 resolution: "react-json-view@npm:1.21.3" @@ -20527,14 +20463,17 @@ __metadata: resolution: "react-native-paper-example@workspace:example" dependencies: "@babel/core": "npm:^7.29.0" + "@expo/metro-config": "npm:~56.0.0" "@react-native-async-storage/async-storage": "npm:2.2.0" "@react-native-masked-view/masked-view": "npm:0.3.2" "@react-navigation/bottom-tabs": "npm:^8.0.0-alpha.33" "@react-navigation/drawer": "npm:^8.0.0-alpha.34" + "@react-navigation/elements": "npm:3.0.0-alpha.31" "@react-navigation/native": "npm:^8.0.0-alpha.28" "@react-navigation/native-stack": "npm:^8.0.0-alpha.34" babel-preset-expo: "npm:~56.0.0" expo: "npm:~56.0.0" + expo-constants: "npm:~56.0.18" expo-crypto: "npm:~56.0.3" expo-dev-client: "npm:~56.0.13" expo-font: "npm:~56.0.5" @@ -20561,56 +20500,45 @@ __metadata: resolution: "react-native-paper@workspace:." dependencies: "@babel/core": "npm:^7.29.0" + "@babel/parser": "npm:^7.29.0" "@babel/plugin-proposal-export-namespace-from": "npm:^7.18.9" - "@babel/runtime": "npm:^7.29.0" - "@callstack/eslint-config": "npm:^13.0.2" + "@babel/types": "npm:^7.29.0" + "@callstack/eslint-config": "npm:^15.0.0" "@callstack/react-theme-provider": "npm:^3.0.9" "@commitlint/config-conventional": "npm:^8.3.4" + "@eslint/js": "npm:9.39.4" "@jest/globals": "npm:^29.7.0" "@react-native-vector-icons/material-design-icons": "npm:^12.0.0" "@react-native/babel-preset": "npm:^0.85.3" "@react-native/jest-preset": "npm:^0.85.3" "@react-navigation/native": "npm:^8.0.0-alpha.28" "@release-it/conventional-changelog": "npm:^1.1.0" - "@testing-library/jest-native": "npm:^5.4.1" - "@testing-library/react-native": "npm:11.5.0" + "@testing-library/react-native": "npm:^14.0.0" "@types/color": "npm:^3.0.0" - "@types/jest": "npm:^29.2.1" - "@types/node": "npm:^13.1.0" - "@types/react-dom": "npm:^19.1.1" - "@types/react-native-vector-icons": "npm:^6.4.18" - "@types/react-test-renderer": "npm:^19.1.0" - "@typescript-eslint/eslint-plugin": "npm:^5.41.0" - "@typescript-eslint/parser": "npm:^5.41.0" + "@types/node": "npm:^24.0.0" + "@types/react": "npm:^19.2.7" all-contributors-cli: "npm:^6.24.0" - babel-cli: "npm:^6.26.0" - babel-core: "npm:^7.0.0-bridge.0" babel-jest: "npm:^29.6.3" - babel-loader: "npm:^8.2.3" babel-test: "npm:^0.1.1" - chalk: "npm:^4.0.0" color: "npm:^3.1.2" commitlint: "npm:^8.3.4" - conventional-changelog-cli: "npm:^2.0.11" - dedent: "npm:^0.7.0" - eslint: "npm:8.31.0" + eslint: "npm:9.39.4" eslint-plugin-flowtype: "npm:^8.0.3" - eslint-plugin-local-rules: "npm:^1.3.2" - glob: "npm:^7.1.3" - husky: "npm:^1.3.1" + eslint-plugin-testing-library: "npm:^7.16.2" jest: "npm:^29.6.3" jest-file-snapshot: "npm:^0.3.2" + lefthook: "npm:^2.1.9" + prettier: "npm:^3.8.4" react: "npm:19.2.3" - react-dom: "npm:19.2.3" react-native: "npm:0.85.3" react-native-builder-bob: "npm:^0.42.1" react-native-reanimated: "npm:4.3.1" react-native-safe-area-context: "npm:5.7.0" react-native-worklets: "npm:0.8.3" - react-test-renderer: "npm:19.2.3" release-it: "npm:^13.4.0" - rimraf: "npm:^3.0.2" + test-renderer: "npm:1.2.0" typescript: "npm:5.8.3" + typescript-eslint: "npm:^8.61.1" use-latest-callback: "npm:^0.2.3" peerDependencies: react: "*" @@ -20780,6 +20708,17 @@ __metadata: languageName: node linkType: hard +"react-reconciler@npm:~0.33.0": + version: 0.33.0 + resolution: "react-reconciler@npm:0.33.0" + dependencies: + scheduler: "npm:^0.27.0" + peerDependencies: + react: ^19.2.0 + checksum: 10c0/3f7b27ea8d0ff4c8bf0e402a285e1af9b7d0e6f4c1a70a28f4384938bc1130bc82a90a31df0b79ef5e380e2e55e2598bd90b4dbf802b1203d735ba0355817d3a + languageName: node + linkType: hard + "react-refresh@npm:^0.14.0, react-refresh@npm:^0.14.2": version: 0.14.2 resolution: "react-refresh@npm:0.14.2" @@ -20835,18 +20774,6 @@ __metadata: languageName: node linkType: hard -"react-test-renderer@npm:19.2.3": - version: 19.2.3 - resolution: "react-test-renderer@npm:19.2.3" - dependencies: - react-is: "npm:^19.2.3" - scheduler: "npm:^0.27.0" - peerDependencies: - react: ^19.2.3 - checksum: 10c0/842b82239dbddbc536083a6260c3e1b0507c02a3400bd05879fc19160468fd0f8ab79fec5dceffa6113b131835cc7621212f8415b46ea5156ab66bbfd7e24297 - languageName: node - linkType: hard - "react-textarea-autosize@npm:^8.3.2": version: 8.5.9 resolution: "react-textarea-autosize@npm:8.5.9" @@ -20930,17 +20857,6 @@ __metadata: languageName: node linkType: hard -"read-pkg@npm:^4.0.1": - version: 4.0.1 - resolution: "read-pkg@npm:4.0.1" - dependencies: - normalize-package-data: "npm:^2.3.2" - parse-json: "npm:^4.0.0" - pify: "npm:^3.0.0" - checksum: 10c0/70c934969aba7267a229871345fe1714e1416085c3db9cba8f7fcd78fba3bd38cef7f08a9d661880e552a5722baf8feaf792875b3108d251a5b6dd94369c752d - languageName: node - linkType: hard - "readable-stream@npm:3, readable-stream@npm:^3.0.0, readable-stream@npm:^3.0.2, readable-stream@npm:^3.0.6, readable-stream@npm:^3.4.0": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" @@ -20952,7 +20868,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^2.0.1, readable-stream@npm:^2.0.2, readable-stream@npm:~2.3.6": +"readable-stream@npm:^2.0.1, readable-stream@npm:~2.3.6": version: 2.3.8 resolution: "readable-stream@npm:2.3.8" dependencies: @@ -20967,17 +20883,6 @@ __metadata: languageName: node linkType: hard -"readdirp@npm:^2.0.0": - version: 2.2.1 - resolution: "readdirp@npm:2.2.1" - dependencies: - graceful-fs: "npm:^4.1.11" - micromatch: "npm:^3.1.10" - readable-stream: "npm:^2.0.2" - checksum: 10c0/770d177372ff2212d382d425d55ca48301fcbf3231ab3827257bbcca7ff44fb51fe4af6acc2dda8512dc7f29da390e9fbea5b2b3fc724b86e85cc828395b7797 - languageName: node - linkType: hard - "readdirp@npm:~3.6.0": version: 3.6.0 resolution: "readdirp@npm:3.6.0" @@ -21123,15 +21028,6 @@ __metadata: languageName: node linkType: hard -"regex-cache@npm:^0.4.2": - version: 0.4.4 - resolution: "regex-cache@npm:0.4.4" - dependencies: - is-equal-shallow: "npm:^0.1.3" - checksum: 10c0/d3e374638b577ae560a445c7f36b801cab4815f7d25e1a9afc2328c01d5c0d203ea0d24e95635843e25ebc54e061f1790f7d47aa3839c49f67bbc53358ad9066 - languageName: node - linkType: hard - "regex-not@npm:^1.0.0, regex-not@npm:^1.0.2": version: 1.0.2 resolution: "regex-not@npm:1.0.2" @@ -21156,13 +21052,6 @@ __metadata: languageName: node linkType: hard -"regexpp@npm:^3.2.0": - version: 3.2.0 - resolution: "regexpp@npm:3.2.0" - checksum: 10c0/d1da82385c8754a1681416b90b9cca0e21b4a2babef159099b88f640637d789c69011d0bc94705dacab85b81133e929d027d85210e8b8b03f8035164dbc14710 - languageName: node - linkType: hard - "regexpu-core@npm:^6.3.1": version: 6.4.0 resolution: "regexpu-core@npm:6.4.0" @@ -21417,22 +21306,13 @@ __metadata: languageName: node linkType: hard -"repeat-string@npm:^1.5.2, repeat-string@npm:^1.5.4, repeat-string@npm:^1.6.1": +"repeat-string@npm:^1.5.4, repeat-string@npm:^1.6.1": version: 1.6.1 resolution: "repeat-string@npm:1.6.1" checksum: 10c0/87fa21bfdb2fbdedc44b9a5b118b7c1239bdd2c2c1e42742ef9119b7d412a5137a1d23f1a83dc6bb686f4f27429ac6f542e3d923090b44181bafa41e8ac0174d languageName: node linkType: hard -"repeating@npm:^2.0.0": - version: 2.0.1 - resolution: "repeating@npm:2.0.1" - dependencies: - is-finite: "npm:^1.0.0" - checksum: 10c0/7f5cd293ec47d9c074ef0852800d5ff5c49028ce65242a7528d84f32bd2fe200b142930562af58c96d869c5a3046e87253030058e45231acaa129c1a7087d2e7 - languageName: node - linkType: hard - "replace-ext@npm:1.0.0": version: 1.0.0 resolution: "replace-ext@npm:1.0.0" @@ -21777,15 +21657,6 @@ __metadata: languageName: node linkType: hard -"run-node@npm:^1.0.0": - version: 1.0.0 - resolution: "run-node@npm:1.0.0" - bin: - run-node: run-node - checksum: 10c0/ab32a065194903e5cd2e4c01e4a5568d22720b4eaa5c853d5386e8d116c59c313e84591f0375913dbe6cc973c2181aed4f54d6b32dba9f7d0d5d01a762de8b6b - languageName: node - linkType: hard - "run-parallel@npm:^1.1.9": version: 1.2.0 resolution: "run-parallel@npm:1.2.0" @@ -22004,13 +21875,6 @@ __metadata: languageName: node linkType: hard -"semver-compare@npm:^1.0.0": - version: 1.0.0 - resolution: "semver-compare@npm:1.0.0" - checksum: 10c0/9ef4d8b81847556f0865f46ddc4d276bace118c7cb46811867af82e837b7fc473911981d5a0abc561fa2db487065572217e5b06e18701c4281bcdd2a1affaff1 - languageName: node - linkType: hard - "semver-diff@npm:^3.1.1": version: 3.1.1 resolution: "semver-diff@npm:3.1.1" @@ -22437,13 +22301,6 @@ __metadata: languageName: node linkType: hard -"slash@npm:^1.0.0": - version: 1.0.0 - resolution: "slash@npm:1.0.0" - checksum: 10c0/3944659885d905480f98810542fd314f3e1006eaad25ec78227a7835a469d9ed66fc3dd90abc7377dd2e71f4b5473e8f766bd08198fdd25152a80792e9ed464c - languageName: node - linkType: hard - "slash@npm:^2.0.0": version: 2.0.0 resolution: "slash@npm:2.0.0" @@ -22616,15 +22473,6 @@ __metadata: languageName: node linkType: hard -"source-map-support@npm:^0.4.15": - version: 0.4.18 - resolution: "source-map-support@npm:0.4.18" - dependencies: - source-map: "npm:^0.5.6" - checksum: 10c0/cd9f0309c1632b1e01a7715a009e0b036d565f3af8930fa8cda2a06aeec05ad1d86180e743b7e1f02cc3c97abe8b6d8de7c3878c2d8e01e86e17f876f7ecf98e - languageName: node - linkType: hard - "source-map-support@npm:^0.5.16, source-map-support@npm:~0.5.20": version: 0.5.21 resolution: "source-map-support@npm:0.5.21" @@ -22649,7 +22497,7 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.5.0, source-map@npm:^0.5.6, source-map@npm:^0.5.7": +"source-map@npm:^0.5.0, source-map@npm:^0.5.6": version: 0.5.7 resolution: "source-map@npm:0.5.7" checksum: 10c0/904e767bb9c494929be013017380cbba013637da1b28e5943b566031e29df04fba57edf3f093e0914be094648b577372bd8ad247fa98cfba9c600794cd16b599 @@ -23075,15 +22923,6 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^3.0.0": - version: 3.0.1 - resolution: "strip-ansi@npm:3.0.1" - dependencies: - ansi-regex: "npm:^2.0.0" - checksum: 10c0/f6e7fbe8e700105dccf7102eae20e4f03477537c74b286fd22cfc970f139002ed6f0d9c10d0e21aa9ed9245e0fa3c9275930e8795c5b947da136e4ecb644a70f - languageName: node - linkType: hard - "strip-ansi@npm:^5.0.0, strip-ansi@npm:^5.1.0, strip-ansi@npm:^5.2.0": version: 5.2.0 resolution: "strip-ansi@npm:5.2.0" @@ -23171,7 +23010,7 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": +"strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd @@ -23254,13 +23093,6 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^2.0.0": - version: 2.0.0 - resolution: "supports-color@npm:2.0.0" - checksum: 10c0/570e0b63be36cccdd25186350a6cb2eaad332a95ff162fa06d9499982315f2fe4217e69dd98e862fbcd9c81eaff300a825a1fe7bf5cc752e5b84dfed042b0dda - languageName: node - linkType: hard - "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -23330,6 +23162,15 @@ __metadata: languageName: node linkType: hard +"synckit@npm:^0.11.13": + version: 0.11.13 + resolution: "synckit@npm:0.11.13" + dependencies: + "@pkgr/core": "npm:^0.3.6" + checksum: 10c0/5a6c19f4f79045aaa7994106401bff6dbe7cca23a6d0a0723ff14eb8b1bebeb4a71729118f6914905598e304ea2fa13509885e11ba07d92e7cb68a06740cb328 + languageName: node + linkType: hard + "tapable@npm:^1.0.0": version: 1.1.3 resolution: "tapable@npm:1.1.3" @@ -23357,23 +23198,6 @@ __metadata: languageName: node linkType: hard -"temp-dir@npm:^2.0.0": - version: 2.0.0 - resolution: "temp-dir@npm:2.0.0" - checksum: 10c0/b1df969e3f3f7903f3426861887ed76ba3b495f63f6d0c8e1ce22588679d9384d336df6064210fda14e640ed422e2a17d5c40d901f60e161c99482d723f4d309 - languageName: node - linkType: hard - -"tempfile@npm:^3.0.0": - version: 3.0.0 - resolution: "tempfile@npm:3.0.0" - dependencies: - temp-dir: "npm:^2.0.0" - uuid: "npm:^3.3.2" - checksum: 10c0/1547e7b5c199868f9b8bf0e321f4cbdc3c57c05c03ff0b1a93deae94edc529ac1499ec7b6d7ebf4e79f469194262c4606785b47ec77d979eaece42c46db72932 - languageName: node - linkType: hard - "term-size@npm:^2.1.0": version: 2.2.1 resolution: "term-size@npm:2.2.1" @@ -23438,6 +23262,18 @@ __metadata: languageName: node linkType: hard +"test-renderer@npm:1.2.0": + version: 1.2.0 + resolution: "test-renderer@npm:1.2.0" + dependencies: + "@types/react-reconciler": "npm:~0.33.0" + react-reconciler: "npm:~0.33.0" + peerDependencies: + react: ^19.0.0 + checksum: 10c0/f6ac10a7906d46fd67e3a2ece1964a71f31ca15d70e8e18e2d06170fa355f8e042599f8956ae55b2b5ce15644d5574c580e1fe751954341ac9327a631215d77e + languageName: node + linkType: hard + "text-extensions@npm:^1.0.0": version: 1.9.0 resolution: "text-extensions@npm:1.9.0" @@ -23568,13 +23404,6 @@ __metadata: languageName: node linkType: hard -"to-fast-properties@npm:^1.0.3": - version: 1.0.3 - resolution: "to-fast-properties@npm:1.0.3" - checksum: 10c0/78974a4f4528700d18e4c2bbf0b1fb1b19862dcc20a18dc5ed659843dea2dff4f933d167a11d3819865c1191042003aea65f7f035791af9e65d070f2e05af787 - languageName: node - linkType: hard - "to-object-path@npm:^0.3.0": version: 0.3.0 resolution: "to-object-path@npm:0.3.0" @@ -23687,13 +23516,6 @@ __metadata: languageName: node linkType: hard -"trim-right@npm:^1.0.1": - version: 1.0.1 - resolution: "trim-right@npm:1.0.1" - checksum: 10c0/71989ec179c6b42a56e03db68e60190baabf39d32d4e1252fa1501c4e478398ae29d7191beffe015b9d9dc76f04f4b3a946bdb9949ad6b0c0b0c5db65f3eb672 - languageName: node - linkType: hard - "trim-trailing-lines@npm:^1.0.0": version: 1.1.4 resolution: "trim-trailing-lines@npm:1.1.4" @@ -23715,6 +23537,15 @@ __metadata: languageName: node linkType: hard +"ts-api-utils@npm:^2.5.0": + version: 2.5.0 + resolution: "ts-api-utils@npm:2.5.0" + peerDependencies: + typescript: ">=4.8.4" + checksum: 10c0/767849383c114e7f1971fa976b20e73ac28fd0c70d8d65c0004790bf4d8f89888c7e4cf6d5949f9c1beae9bc3c64835bef77bbe27fddf45a3c7b60cebcf85c8c + languageName: node + linkType: hard + "tsconfig-paths@npm:^3.15.0": version: 3.15.0 resolution: "tsconfig-paths@npm:3.15.0" @@ -23727,7 +23558,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1.8.1, tslib@npm:^1.9.0": +"tslib@npm:^1.9.0": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: 10c0/69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2 @@ -23741,17 +23572,6 @@ __metadata: languageName: node linkType: hard -"tsutils@npm:^3.21.0": - version: 3.21.0 - resolution: "tsutils@npm:3.21.0" - dependencies: - tslib: "npm:^1.8.1" - peerDependencies: - typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - checksum: 10c0/02f19e458ec78ead8fffbf711f834ad8ecd2cc6ade4ec0320790713dccc0a412b99e7fd907c4cda2a1dc602c75db6f12e0108e87a5afad4b2f9e90a24cabd5a2 - languageName: node - linkType: hard - "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -23896,6 +23716,21 @@ __metadata: languageName: node linkType: hard +"typescript-eslint@npm:^8.61.1": + version: 8.61.1 + resolution: "typescript-eslint@npm:8.61.1" + dependencies: + "@typescript-eslint/eslint-plugin": "npm:8.61.1" + "@typescript-eslint/parser": "npm:8.61.1" + "@typescript-eslint/typescript-estree": "npm:8.61.1" + "@typescript-eslint/utils": "npm:8.61.1" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: ">=4.8.4 <6.1.0" + checksum: 10c0/cf27a5c25a6d492a77ee72d98ff0e708b25553c4450483c627018556bee5b7b17066c0696947aa968ed24fd07ebc095b449dea79f8a7a4c65bccdb6aaf8dc09d + languageName: node + linkType: hard + "typescript@npm:5.8.3": version: 5.8.3 resolution: "typescript@npm:5.8.3" @@ -23993,6 +23828,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~7.18.0": + version: 7.18.2 + resolution: "undici-types@npm:7.18.2" + checksum: 10c0/85a79189113a238959d7a647368e4f7c5559c3a404ebdb8fc4488145ce9426fcd82252a844a302798dfc0e37e6fb178ff481ed03bc4caf634c5757d9ef43521d + languageName: node + linkType: hard + "undici@npm:^7.12.0": version: 7.18.2 resolution: "undici@npm:7.18.2" @@ -24524,15 +24366,6 @@ __metadata: languageName: node linkType: hard -"user-home@npm:^1.1.1": - version: 1.1.1 - resolution: "user-home@npm:1.1.1" - bin: - user-home: cli.js - checksum: 10c0/9d80a5df3bfea008e4d17b1465e8eb4ac7472ba02766feb242e84349b877f74e302838c85a622d4ba78665c2378b654fe1b0d27cf912c917b5536eb4778f8804 - languageName: node - linkType: hard - "util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" @@ -24570,15 +24403,6 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^3.3.2": - version: 3.4.0 - resolution: "uuid@npm:3.4.0" - bin: - uuid: ./bin/uuid - checksum: 10c0/1c13950df865c4f506ebfe0a24023571fa80edf2e62364297a537c80af09c618299797bbf2dbac6b1f8ae5ad182ba474b89db61e0e85839683991f7e08795347 - languageName: node - linkType: hard - "uuid@npm:^7.0.3": version: 7.0.3 resolution: "uuid@npm:7.0.3" @@ -24599,15 +24423,6 @@ __metadata: languageName: node linkType: hard -"v8flags@npm:^2.1.1": - version: 2.1.1 - resolution: "v8flags@npm:2.1.1" - dependencies: - user-home: "npm:^1.1.1" - checksum: 10c0/ab5e478e661826a16c261515367091befa2edcdf0819d3a2f25013f80328e5998aed05429d2b28c1bc58e7df0eedc8377dc5829ba44811626fbadd5f6877c31f - languageName: node - linkType: hard - "validate-npm-package-license@npm:^3.0.1": version: 3.0.4 resolution: "validate-npm-package-license@npm:3.0.4"