diff --git a/.eslintrc.js b/.eslintrc.js
index 7c718a1374..a39a0051ce 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,11 +1,12 @@
module.exports = {
root: true,
- plugins: ['jest'],
- extends: ['@react-native', 'plugin:jest/recommended'],
-
+ extends: ['@react-native'],
overrides: [
{
- files: ['**/__tests__/**', '**/*.test.*', '**/*.spec.*'],
+ // Test files only
+ plugins: ['jest'],
+ files: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'],
+ extends: ['plugin:testing-library/react', 'plugin:jest/recommended'],
},
{
files: ['*.js', '*.jsx', '*.ts', '*.tsx'],
diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
new file mode 100644
index 0000000000..65d3c4b4a4
--- /dev/null
+++ b/.github/workflows/testing.yml
@@ -0,0 +1,48 @@
+name: Testing
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ build:
+ name: Test
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@v4
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+
+ - name: Setup pnpm
+ uses: pnpm/action-setup@v4
+
+ - name: Get pnpm Store Directory
+ shell: bash
+ run: |
+ echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
+
+ - name: Setup pnpm Cache
+ uses: actions/cache@v4
+ with:
+ path: ${{ env.STORE_PATH }}
+ key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
+ restore-keys: |
+ ${{ runner.os }}-pnpm-store-
+
+ - name: Install Dependencies
+ run: pnpm install --frozen-lockfile
+
+ - name: Run Tests
+ run: pnpm run test
diff --git a/TESTING.md b/TESTING.md
new file mode 100644
index 0000000000..21ae843b7e
--- /dev/null
+++ b/TESTING.md
@@ -0,0 +1,80 @@
+# Testing Guide for LNReader
+
+This guide explains how to write tests in this React Native project using Jest and React Testing Library.
+
+
+## Existing Mocks
+
+### Global Mocks
+
+The project has global mocks configured in Jest. These are automatically applied:
+
+- `__mocks__/` - Global mocks for native modules (react-native-mmkv, react-navigation, all database queries, etc.)
+- `src/hooks/__mocks__/index.ts` - Hook-specific mocks (showToast, getString, parseChapterNumber, etc.)
+- `src/hooks/__tests__/mocks.ts` - Extended mocks for persisted hooks
+
+### Using @test-utils
+
+There's a custom render wrapper at `__tests-modules__/test-utils.tsx` with:
+
+- `render` - wraps with GestureHandlerRootView, SafeAreaProvider, PaperProvider, etc.
+- `renderNovel` - includes NovelContextProvider
+- `AllTheProviders` - the full provider wrapper
+
+Usage:
+
+```typescript
+import { render, renderNovel } from '@test-utils';
+```
+
+## Common Issues
+
+### 1. ESM Modules Not Transforming
+
+If you see `Cannot use import statement outside a module`, you need to add mocks for the module:
+
+```typescript
+jest.mock('@hooks/persisted/usePlugins');
+// Add more specific mocks as needed
+```
+
+### 2. Mock Functions Not Working
+
+If `mockReturnValue` throws "not a function", create mock functions at module level:
+
+```typescript
+// CORRECT: Module-level mock functions
+const mockUseTheme = jest.fn();
+jest.mock('@hooks/persisted', () => ({
+ useTheme: () => mockUseTheme(),
+}));
+
+// INCORRECT: Trying to use jest.Mock type casting
+// (useTheme as jest.Mock).mockReturnValue(...) // This fails!
+```
+
+### 3. Test Isolation
+
+Tests must mock at module level, not in `beforeEach`:
+
+```typescript
+// CORRECT
+const mockFn = jest.fn();
+jest.mock('module', () => ({ useHook: () => mockFn() }));
+
+// INCORRECT - mocks get reset between tests
+jest.mock('module');
+beforeEach(() => {
+ // This doesn't work properly
+});
+```
+
+## Running Tests
+
+```bash
+pnpm test # Run all tests
+pnpm test:watch # Watch mode
+pnpm test:coverage # With coverage
+pnpm test:rn # React Native only
+pnpm test:db # Database only
+```
diff --git a/__mocks__/database.js b/__mocks__/database.js
new file mode 100644
index 0000000000..f023116ec2
--- /dev/null
+++ b/__mocks__/database.js
@@ -0,0 +1,66 @@
+jest.mock('@database/queries/NovelQueries', () => ({
+ getNovelByPath: jest.fn(),
+ deleteCachedNovels: jest.fn(),
+ getCachedNovels: jest.fn(),
+ insertNovelAndChapters: jest.fn(),
+}));
+
+jest.mock('@database/queries/CategoryQueries', () => ({
+ getCategoriesFromDb: jest.fn(),
+ getCategoriesWithCount: jest.fn(),
+ createCategory: jest.fn(),
+ deleteCategoryById: jest.fn(),
+ updateCategory: jest.fn(),
+ isCategoryNameDuplicate: jest.fn(),
+ updateCategoryOrderInDb: jest.fn(),
+ getAllNovelCategories: jest.fn(),
+ _restoreCategory: jest.fn(),
+}));
+
+jest.mock('@database/queries/ChapterQueries', () => ({
+ bookmarkChapter: jest.fn(),
+ markChapterRead: jest.fn(),
+ markChaptersRead: jest.fn(),
+ markPreviuschaptersRead: jest.fn(),
+ markPreviousChaptersUnread: jest.fn(),
+ markChaptersUnread: jest.fn(),
+ deleteChapter: jest.fn(),
+ deleteChapters: jest.fn(),
+ getPageChapters: jest.fn(),
+ insertChapters: jest.fn(),
+ getCustomPages: jest.fn(),
+ getChapterCount: jest.fn(),
+ getPageChaptersBatched: jest.fn(),
+ getFirstUnreadChapter: jest.fn(),
+ updateChapterProgress: jest.fn(),
+}));
+
+jest.mock('@database/queries/HistoryQueries', () => ({
+ getHistoryFromDb: jest.fn(),
+ insertHistory: jest.fn(),
+ deleteChapterHistory: jest.fn(),
+ deleteAllHistory: jest.fn(),
+}));
+
+jest.mock('@database/queries/LibraryQueries', () => ({
+ getLibraryNovelsFromDb: jest.fn(),
+ getLibraryWithCategory: jest.fn(),
+}));
+
+jest.mock('@database/queries/RepositoryQueries', () => ({
+ getRepositoriesFromDb: jest.fn(),
+ isRepoUrlDuplicated: jest.fn(),
+ createRepository: jest.fn(),
+ deleteRepositoryById: jest.fn(),
+ updateRepository: jest.fn(),
+}));
+
+jest.mock('@database/queries/StatsQueries', () => ({
+ getLibraryStatsFromDb: jest.fn(),
+ getChaptersTotalCountFromDb: jest.fn(),
+ getChaptersReadCountFromDb: jest.fn(),
+ getChaptersUnreadCountFromDb: jest.fn(),
+ getChaptersDownloadedCountFromDb: jest.fn(),
+ getNovelGenresFromDb: jest.fn(),
+ getNovelStatusFromDb: jest.fn(),
+}));
diff --git a/__mocks__/index.js b/__mocks__/index.js
new file mode 100644
index 0000000000..08a7b5dfce
--- /dev/null
+++ b/__mocks__/index.js
@@ -0,0 +1,4 @@
+require('./nativeModules');
+require('./react-native-mmkv');
+require('./database');
+require('./react-navigation');
diff --git a/__mocks__/nativeModules.js b/__mocks__/nativeModules.js
new file mode 100644
index 0000000000..fa3c82cdfd
--- /dev/null
+++ b/__mocks__/nativeModules.js
@@ -0,0 +1,67 @@
+// require('react-native-gesture-handler/jestSetup');
+// require('react-native-reanimated').setUpTests();
+
+jest.mock('@specs/NativeFile', () => ({
+ __esModule: true,
+ default: {
+ writeFile: jest.fn(),
+ readFile: jest.fn(() => ''),
+ copyFile: jest.fn(),
+ moveFile: jest.fn(),
+ exists: jest.fn(() => true),
+ mkdir: jest.fn(),
+ unlink: jest.fn(),
+ readDir: jest.fn(() => []),
+ downloadFile: jest.fn().mockResolvedValue(),
+ getConstants: jest.fn(() => ({
+ ExternalDirectoryPath: '/mock/external',
+ ExternalCachesDirectoryPath: '/mock/caches',
+ })),
+ },
+}));
+
+jest.mock('@specs/NativeEpub', () => ({
+ __esModule: true,
+ default: {
+ parseNovelAndChapters: jest.fn(() => ({
+ name: 'Mock Novel',
+ cover: null,
+ summary: null,
+ author: null,
+ artist: null,
+ chapters: [],
+ cssPaths: [],
+ imagePaths: [],
+ })),
+ },
+}));
+
+jest.mock('@specs/NativeTTSMediaControl', () => ({
+ __esModule: true,
+ default: {
+ showMediaNotification: jest.fn(),
+ updatePlaybackState: jest.fn(),
+ updateProgress: jest.fn(),
+ dismiss: jest.fn(),
+ addListener: jest.fn(),
+ removeListeners: jest.fn(),
+ },
+}));
+
+jest.mock('@specs/NativeVolumeButtonListener', () => ({
+ __esModule: true,
+ default: {
+ addListener: jest.fn(),
+ removeListeners: jest.fn(),
+ },
+}));
+
+jest.mock('@specs/NativeZipArchive', () => ({
+ __esModule: true,
+ default: {
+ zip: jest.fn().mockResolvedValue(),
+ unzip: jest.fn().mockResolvedValue(),
+ remoteUnzip: jest.fn().mockResolvedValue(),
+ remoteZip: jest.fn().mockResolvedValue(''),
+ },
+}));
diff --git a/__mocks__/react-native-mmkv.js b/__mocks__/react-native-mmkv.js
new file mode 100644
index 0000000000..fdb54351a5
--- /dev/null
+++ b/__mocks__/react-native-mmkv.js
@@ -0,0 +1,9 @@
+// Mock for react-native-mmkv (v3 uses NitroModules under the hood)
+module.exports = {
+ NitroModules: {
+ createHybridObject: jest.fn(() => {
+ // Return a mock object that won't be used since MMKV has its own mock
+ return {};
+ }),
+ },
+};
diff --git a/__mocks__/react-navigation.js b/__mocks__/react-navigation.js
new file mode 100644
index 0000000000..b3b856a46b
--- /dev/null
+++ b/__mocks__/react-navigation.js
@@ -0,0 +1,29 @@
+const mockNavigate = jest.fn();
+const mockSetOptions = jest.fn();
+
+jest.mock('react-native-worklets', () =>
+ require('react-native-worklets/src/mock'),
+);
+
+// Include this line for mocking react-native-gesture-handler
+require('react-native-gesture-handler/jestSetup');
+
+// Include this section for mocking react-native-reanimated
+const { setUpTests } = require('react-native-reanimated');
+
+setUpTests();
+
+jest.mock('@react-navigation/native', () => {
+ return {
+ useFocusEffect: jest.fn(),
+ useNavigation: () => ({
+ navigate: mockNavigate,
+ setOptions: mockSetOptions,
+ }),
+ useRoute: () => ({
+ params: {},
+ }),
+ };
+});
+
+module.exports = { mockNavigate, mockSetOptions };
diff --git a/__tests-modules__/test-utils.tsx b/__tests-modules__/test-utils.tsx
new file mode 100644
index 0000000000..9e16ced519
--- /dev/null
+++ b/__tests-modules__/test-utils.tsx
@@ -0,0 +1,48 @@
+import { render } from '@testing-library/react-native';
+import React from 'react';
+import { GestureHandlerRootView } from 'react-native-gesture-handler';
+import { SafeAreaProvider } from 'react-native-safe-area-context';
+import { Provider as PaperProvider } from 'react-native-paper';
+import { BottomSheetModalProvider } from '@gorhom/bottom-sheet';
+
+import AppErrorBoundary from '@components/AppErrorBoundary/AppErrorBoundary';
+import { NovelContextProvider } from '@screens/novel/NovelContext';
+import { NovelScreenProps, ChapterScreenProps } from '@navigators/types';
+
+const AllTheProviders = ({ children }: { children: React.ReactElement }) => {
+ return (
+
+
+
+
+ {children}
+
+
+
+
+ );
+};
+
+const customRender = (ui: React.ReactElement, options?: object) =>
+ render(ui, { wrapper: AllTheProviders, ...options });
+
+const renderNovel = (
+ ui: React.ReactElement,
+ options?: {
+ route?: NovelScreenProps['route'] | ChapterScreenProps['route'];
+ },
+) => {
+ const { route } = options || {};
+ return render(
+
+ {ui}
+ ,
+ { wrapper: AllTheProviders, ...options },
+ );
+};
+
+export * from '@testing-library/react-native';
+
+export { customRender as render, renderNovel, AllTheProviders };
diff --git a/__tests__/jest.setup.ts b/__tests__/jest.setup.ts
new file mode 100644
index 0000000000..c9d4e40363
--- /dev/null
+++ b/__tests__/jest.setup.ts
@@ -0,0 +1,3 @@
+process.env.EXPO_OS = 'android';
+
+global.IS_REACT_ACT_ENVIRONMENT = true;
diff --git a/babel.config.js b/babel.config.js
index bfffe2484d..842ceb57a6 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -26,6 +26,7 @@ module.exports = function (api) {
'@api': './src/api',
'@type': './src/type',
'@specs': './specs',
+ '@test-utils': './__tests-modules__/test-utils',
'react-native-vector-icons/MaterialCommunityIcons':
'@react-native-vector-icons/material-design-icons',
},
diff --git a/jest.config.js b/jest.config.js
index 40461025b7..5268de4553 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,57 +1,85 @@
-module.exports = {
- // Use node environment for database tests (no React Native needed)
- testEnvironment: 'node',
- roots: ['/src'],
- testMatch: ['**/__tests__/**/*.test.ts', '**/__tests__/**/*.test.tsx'],
- moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
-
- // Transform TypeScript and JavaScript files using Babel (uses babel.config.js)
- transform: {
- '^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
- },
+// jest.config.js
+const baseModuleNameMapper = {
+ '^@components$': '/src/components/index',
+ '^@components/(.*)$': '/src/components/$1',
+ '^@database/(.*)$': '/src/database/$1',
+ '^@hooks$': '/src/hooks/index',
+ '^@hooks/(.*)$': '/src/hooks/$1',
+ '^@screens/(.*)$': '/src/screens/$1',
+ '^@strings/(.*)$': '/strings/$1',
+ '^@theme/(.*)$': '/src/theme/$1',
+ '^@utils/(.*)$': '/src/utils/$1',
+ '^@plugins/(.*)$': '/src/plugins/$1',
+ '^@services/(.*)$': '/src/services/$1',
+ '^@navigators/(.*)$': '/src/navigators/$1',
+ '^@native/(.*)$': '/src/native/$1',
+ '^@api/(.*)$': '/src/api/$1',
+ '^@type/(.*)$': '/src/type/$1',
+ '^@specs/(.*)$': '/specs/$1',
+ '^@test-utils$': '/__tests-modules__/test-utils',
+ // Mock static assets
+ '\\.(jpg|jpeg|png|gif|webp|svg)$': '/__mocks__/fileMock.js',
+};
- // Transform node_modules packages that use ES modules
- // Exclude most packages, but include ones that need transformation
- // Note: The pattern uses negative lookahead - packages NOT matching this pattern are ignored
- transformIgnorePatterns: [
- 'node_modules/(?!(react-native|@react-native|@react-native-community|@react-navigation|expo|expo-.*|@expo|@op-engineering|drizzle-orm|lodash-es|@babel/runtime)/)',
- ],
+const baseTransform = {
+ '^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
+};
- // Module name mapping for path aliases
- moduleNameMapper: {
- '^@components$': '/src/components/index',
- '^@components/(.*)$': '/src/components/$1',
- '^@database/(.*)$': '/src/database/$1',
- '^@hooks$': '/src/hooks/index',
- '^@hooks/(.*)$': '/src/hooks/$1',
- '^@screens/(.*)$': '/src/screens/$1',
- '^@strings/(.*)$': '/strings/$1',
- '^@theme/(.*)$': '/src/theme/$1',
- '^@utils/(.*)$': '/src/utils/$1',
- '^@plugins/(.*)$': '/src/plugins/$1',
- '^@services/(.*)$': '/src/services/$1',
- '^@navigators/(.*)$': '/src/navigators/$1',
- '^@native/(.*)$': '/src/native/$1',
- '^@api/(.*)$': '/src/api/$1',
- '^@type/(.*)$': '/src/type/$1',
- '^@specs/(.*)$': '/specs/$1',
- },
+const baseTransformIgnorePatterns = [
+ // 'node_modules/(?!(.pnpm/|@op-engineering|drizzle-orm|lodash-es|@babel/runtime))',
+ 'node_modules/(?!(?:.pnpm/)?((jest-)?react-native|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg|color|@op-engineering|drizzle-orm|lodash-es))',
+];
- // Setup file runs after Jest environment is set up
- setupFilesAfterEnv: ['/src/database/queries/__tests__/setup.ts'],
+module.exports = {
+ moduleDirectories: ['node_modules', '__tests-modules__'],
+ projects: [
+ // --- Project 1: Database / pure logic tests (node environment) ---
+ {
+ displayName: 'db',
+ testEnvironment: 'node',
+ roots: ['/src/database'],
+ testMatch: ['**/__tests__/**/*.test.ts'],
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
+ transform: baseTransform,
+ transformIgnorePatterns: baseTransformIgnorePatterns,
+ moduleNameMapper: baseModuleNameMapper,
+ setupFilesAfterEnv: ['/src/database/queries/__tests__/setup.ts'],
+ collectCoverageFrom: [
+ 'src/database/queries/**/*.ts',
+ '!src/database/queries/**/__tests__/**',
+ ],
+ },
- // Coverage configuration
- collectCoverageFrom: [
- 'src/database/queries/**/*.ts',
- '!src/database/queries/**/__tests__/**',
+ // --- Project 2: React Native component / hook / integration tests ---
+ {
+ displayName: 'rn',
+ preset: 'jest-expo',
+ roots: ['/src'],
+ testMatch: [
+ '**/__tests__/**/*.test.tsx',
+ // Also pick up non-db .test.ts (hooks, utils, services)
+ '**/__tests__/**/*.test.ts',
+ ],
+ testPathIgnorePatterns: ['/node_modules/', '/src/database/'],
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
+ transform: baseTransform,
+ transformIgnorePatterns: baseTransformIgnorePatterns,
+ moduleNameMapper: baseModuleNameMapper,
+ setupFiles: ['/__mocks__/index.js'],
+ setupFilesAfterEnv: ['/__tests__/jest.setup.ts'],
+ collectCoverageFrom: [
+ 'src/**/*.{ts,tsx}',
+ '!src/database/queries/**/__tests__/**',
+ '!src/**/__tests__/**',
+ ],
+ },
],
+
+ // Global settings
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov', 'html'],
-
- // Test configuration
testTimeout: 10000,
clearMocks: true,
- resetMocks: true,
restoreMocks: true,
verbose: true,
};
diff --git a/package.json b/package.json
index c91ea2b763..c7f636cd54 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,8 @@
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"test:queries": "jest --testPathPattern=queries",
+ "test:db": "jest --selectProjects db",
+ "test:rn": "jest --selectProjects rn",
"lint": "eslint ./src --ext .js,.jsx,.ts,.tsx",
"lint:fix": "pnpm run lint -- --fix",
"format": "prettier --write \"./src/**/*.{js,jsx,ts,tsx}\" ./scripts",
@@ -127,6 +129,7 @@
"@react-native/eslint-plugin": "^0.83.2",
"@react-native/metro-config": "^0.81.6",
"@react-native/typescript-config": "^0.81.6",
+ "@testing-library/react-native": "^13.3.3",
"@types/better-sqlite3": "^7.6.13",
"@types/color": "^4.2.0",
"@types/jest": "^29.5.14",
@@ -146,11 +149,14 @@
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-native": "^5.0.0",
+ "eslint-plugin-testing-library": "^7.16.0",
"husky": "^7.0.4",
"jest": "^29.7.0",
+ "jest-expo": "^54.0.17",
"lint-staged": "^12.5.0",
"prettier": "2.8.8",
"react-native-dotenv": "^3.4.11",
+ "react-test-renderer": "19.1.4",
"typescript": "~5.9.3"
},
"lint-staged": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 54f94659db..00f9b98f03 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -249,6 +249,9 @@ importers:
'@react-native/typescript-config':
specifier: ^0.81.6
version: 0.81.6
+ '@testing-library/react-native':
+ specifier: ^13.3.3
+ version: 13.3.3(jest@29.7.0(@types/node@25.2.3))(react-native@0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4))(react-test-renderer@19.1.4(react@19.1.4))(react@19.1.4)
'@types/better-sqlite3':
specifier: ^7.6.13
version: 7.6.13
@@ -306,12 +309,18 @@ importers:
eslint-plugin-react-native:
specifier: ^5.0.0
version: 5.0.0(eslint@8.57.1)
+ eslint-plugin-testing-library:
+ specifier: ^7.16.0
+ version: 7.16.0(eslint@8.57.1)(typescript@5.9.3)
husky:
specifier: ^7.0.4
version: 7.0.4
jest:
specifier: ^29.7.0
version: 29.7.0(@types/node@25.2.3)
+ jest-expo:
+ specifier: ^54.0.17
+ version: 54.0.17(@babel/core@7.29.0)(expo@54.0.33(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4))(react@19.1.4))(react-native@0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4))(react@19.1.4))(jest@29.7.0(@types/node@25.2.3))(react-native@0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4))(react@19.1.4)
lint-staged:
specifier: ^12.5.0
version: 12.5.0
@@ -321,6 +330,9 @@ importers:
react-native-dotenv:
specifier: ^3.4.11
version: 3.4.11(@babel/runtime@7.28.6)
+ react-test-renderer:
+ specifier: 19.1.4
+ version: 19.1.4(react@19.1.4)
typescript:
specifier: ~5.9.3
version: 5.9.3
@@ -1510,6 +1522,10 @@ packages:
resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ '@jest/diff-sequences@30.0.1':
+ resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
'@jest/environment@29.7.0':
resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -1526,6 +1542,10 @@ packages:
resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ '@jest/get-type@30.1.0':
+ resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
'@jest/globals@29.7.0':
resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -1543,6 +1563,10 @@ packages:
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ '@jest/schemas@30.0.5':
+ resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
'@jest/source-map@29.6.3':
resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -1922,6 +1946,9 @@ packages:
'@sinclair/typebox@0.27.10':
resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==}
+ '@sinclair/typebox@0.34.48':
+ resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==}
+
'@sinonjs/commons@3.0.1':
resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
@@ -1931,6 +1958,22 @@ packages:
'@tediousjs/connection-string@0.5.0':
resolution: {integrity: sha512-7qSgZbincDDDFyRweCIEvZULFAw5iz/DeunhvuxpL31nfntX3P4Yd4HkHBRg9H8CdqY1e5WFN1PZIz/REL9MVQ==}
+ '@testing-library/react-native@13.3.3':
+ resolution: {integrity: sha512-k6Mjsd9dbZgvY4Bl7P1NIpePQNi+dfYtlJ5voi9KQlynxSyQkfOgJmYGCYmw/aSgH/rUcFvG8u5gd4npzgRDyg==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ jest: '>=29.0.0'
+ react: '>=18.2.0'
+ react-native: '>=0.71'
+ react-test-renderer: '>=18.2.0'
+ peerDependenciesMeta:
+ jest:
+ optional: true
+
+ '@tootallnate/once@2.0.0':
+ resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
+ engines: {node: '>= 10'}
+
'@types/babel__core@7.20.5':
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
@@ -1973,6 +2016,9 @@ packages:
'@types/jest@29.5.14':
resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==}
+ '@types/jsdom@20.0.1':
+ resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==}
+
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@@ -2003,6 +2049,9 @@ packages:
'@types/stack-utils@2.0.3':
resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
+ '@types/tough-cookie@4.0.5':
+ resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==}
+
'@types/yargs-parser@21.0.3':
resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
@@ -2175,6 +2224,10 @@ packages:
resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==}
engines: {node: '>=10.0.0'}
+ abab@2.0.6:
+ resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
+ deprecated: Use your platform's native atob() and btoa() methods instead
+
abort-controller@3.0.0:
resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==}
engines: {node: '>=6.5'}
@@ -2183,16 +2236,27 @@ packages:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'}
+ acorn-globals@7.0.1:
+ resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==}
+
acorn-jsx@5.3.2:
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+ acorn-walk@8.3.5:
+ resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==}
+ engines: {node: '>=0.4.0'}
+
acorn@8.15.0:
resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==}
engines: {node: '>=0.4.0'}
hasBin: true
+ agent-base@6.0.2:
+ resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
+ engines: {node: '>= 6.0.0'}
+
agent-base@7.1.4:
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
engines: {node: '>= 14'}
@@ -2211,6 +2275,10 @@ packages:
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
engines: {node: '>=8'}
+ ansi-escapes@6.2.1:
+ resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==}
+ engines: {node: '>=14.16'}
+
ansi-fragments@0.2.1:
resolution: {integrity: sha512-DykbNHxuXQwUDRv5ibc2b0x7uw7wmwOGLBUd5RmaQ5z8Lhx19vwvKV+FAsM5rEA6dEcHxX+/Ad5s9eF2k2bB+w==}
@@ -2314,6 +2382,9 @@ packages:
async-limiter@1.0.1:
resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==}
+ asynckit@0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+
available-typed-arrays@1.0.7:
resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}
engines: {node: '>= 0.4'}
@@ -2531,6 +2602,10 @@ packages:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
+ chalk@3.0.0:
+ resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==}
+ engines: {node: '>=8'}
+
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
@@ -2539,6 +2614,10 @@ packages:
resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
engines: {node: '>=10'}
+ char-regex@2.0.2:
+ resolution: {integrity: sha512-cbGOjAptfM2LVmWhwRFHEKTPkLwNddVmuqYZQt895yXwAsWsXObCG+YN4DGQ/JBtT4GP1a1lPPdio2z413LmTg==}
+ engines: {node: '>=12.20'}
+
cheerio-select@2.1.0:
resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
@@ -2658,6 +2737,10 @@ packages:
colorette@2.0.20:
resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==}
+ combined-stream@1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+
command-exists@1.2.9:
resolution: {integrity: sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==}
@@ -2738,9 +2821,23 @@ packages:
resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==}
engines: {node: '>= 6'}
+ cssom@0.3.8:
+ resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==}
+
+ cssom@0.5.0:
+ resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==}
+
+ cssstyle@2.3.0:
+ resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==}
+ engines: {node: '>=8'}
+
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
+ data-urls@3.0.2:
+ resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==}
+ engines: {node: '>=12'}
+
data-view-buffer@1.0.2:
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
engines: {node: '>= 0.4'}
@@ -2785,6 +2882,9 @@ packages:
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'}
+ decimal.js@10.6.0:
+ resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
+
decode-uri-component@0.2.2:
resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
engines: {node: '>=0.10'}
@@ -2846,6 +2946,10 @@ packages:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
+ delayed-stream@1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+
depd@2.0.0:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
@@ -2884,6 +2988,11 @@ packages:
domelementtype@2.3.0:
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+ domexception@4.0.0:
+ resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==}
+ engines: {node: '>=12'}
+ deprecated: Use your platform's native DOMException instead
+
domhandler@5.0.3:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
@@ -3141,6 +3250,11 @@ packages:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
+ escodegen@2.1.0:
+ resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
+ engines: {node: '>=6.0'}
+ hasBin: true
+
eslint-config-prettier@8.10.2:
resolution: {integrity: sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==}
hasBin: true
@@ -3226,6 +3340,12 @@ packages:
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7
+ eslint-plugin-testing-library@7.16.0:
+ resolution: {integrity: sha512-lHZI6/Olb2oZqxd1+s1nOLCtL2PXKrc1ERz6oDbUKS0xZAMFH3Fy6wJo75z3pXTop3BV6+loPi2MSjIYt3vpAg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+
eslint-scope@5.1.1:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
engines: {node: '>=8.0.0'}
@@ -3541,6 +3661,10 @@ packages:
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
engines: {node: '>= 0.4'}
+ form-data@4.0.5:
+ resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
+ engines: {node: '>= 6'}
+
freeport-async@2.0.0:
resolution: {integrity: sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==}
engines: {node: '>=8'}
@@ -3725,6 +3849,10 @@ packages:
resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==}
engines: {node: ^16.14.0 || >=18.0.0}
+ html-encoding-sniffer@3.0.0:
+ resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==}
+ engines: {node: '>=12'}
+
html-escaper@2.0.2:
resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
@@ -3738,10 +3866,18 @@ packages:
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
engines: {node: '>= 0.8'}
+ http-proxy-agent@5.0.0:
+ resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
+ engines: {node: '>= 6'}
+
http-proxy-agent@7.0.2:
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
engines: {node: '>= 14'}
+ https-proxy-agent@5.0.1:
+ resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
+ engines: {node: '>= 6'}
+
https-proxy-agent@7.0.6:
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
engines: {node: '>= 14'}
@@ -3941,6 +4077,9 @@ packages:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
engines: {node: '>=0.10.0'}
+ is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
is-regex@1.2.1:
resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}
engines: {node: '>= 0.4'}
@@ -4065,6 +4204,10 @@ packages:
resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ jest-diff@30.2.0:
+ resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
jest-docblock@29.7.0:
resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -4073,10 +4216,30 @@ packages:
resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ jest-environment-jsdom@29.7.0:
+ resolution: {integrity: sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==}
+ engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ canvas: ^2.5.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
jest-environment-node@29.7.0:
resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ jest-expo@54.0.17:
+ resolution: {integrity: sha512-LyIhrsP4xvHEEcR1R024u/LBj3uPpAgB+UljgV+YXWkEHjprnr0KpE4tROsMNYCVTM1pPlAnPuoBmn5gnAN9KA==}
+ hasBin: true
+ peerDependencies:
+ expo: '*'
+ react-native: '*'
+ react-server-dom-webpack: ~19.0.4 || ~19.1.5 || ~19.2.4
+ peerDependenciesMeta:
+ react-server-dom-webpack:
+ optional: true
+
jest-get-type@29.6.3:
resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -4093,6 +4256,10 @@ packages:
resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ jest-matcher-utils@30.2.0:
+ resolution: {integrity: sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
jest-message-util@29.7.0:
resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -4142,6 +4309,15 @@ packages:
resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ jest-watch-select-projects@2.0.0:
+ resolution: {integrity: sha512-j00nW4dXc2NiCW6znXgFLF9g8PJ0zP25cpQ1xRro/HU2GBfZQFZD0SoXnAlaoKkIY4MlfTMkKGbNXFpvCdjl1w==}
+
+ jest-watch-typeahead@2.2.1:
+ resolution: {integrity: sha512-jYpYmUnTzysmVnwq49TAxlmtOAwp8QIqvZyoofQFn8fiWhEDZj33ZXzg3JA4nGnzWFm1hbWf3ADpteUokvXgFA==}
+ engines: {node: ^14.17.0 || ^16.10.0 || >=18.0.0}
+ peerDependencies:
+ jest: ^27.0.0 || ^28.0.0 || ^29.0.0
+
jest-watcher@29.7.0:
resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -4190,6 +4366,15 @@ packages:
jsc-safe-url@0.2.4:
resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==}
+ jsdom@20.0.3:
+ resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==}
+ engines: {node: '>=14'}
+ peerDependencies:
+ canvas: ^2.5.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
@@ -4574,6 +4759,10 @@ packages:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
+ min-indent@1.0.1:
+ resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
+ engines: {node: '>=4'}
+
minimatch@10.2.1:
resolution: {integrity: sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A==}
engines: {node: 20 || >=22}
@@ -4695,6 +4884,9 @@ packages:
nullthrows@1.1.1:
resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==}
+ nwsapi@2.2.23:
+ resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==}
+
ob1@0.83.3:
resolution: {integrity: sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA==}
engines: {node: '>=20.19.4'}
@@ -4959,6 +5151,10 @@ packages:
resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
+ pretty-format@30.2.0:
+ resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==}
+ engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0}
+
proc-log@4.2.0:
resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -4985,6 +5181,9 @@ packages:
resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==}
engines: {node: '>=12.0.0'}
+ psl@1.15.0:
+ resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}
+
pump@3.0.3:
resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
@@ -5007,6 +5206,9 @@ packages:
resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==}
engines: {node: '>=6'}
+ querystringify@2.2.0:
+ resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -5225,6 +5427,16 @@ packages:
resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==}
engines: {node: '>=0.10.0'}
+ react-test-renderer@19.1.0:
+ resolution: {integrity: sha512-jXkSl3CpvPYEF+p/eGDLB4sPoDX8pKkYvRl9+rR8HxLY0X04vW7hCm1/0zHoUSjPZ3bDa+wXWNTDVIw/R8aDVw==}
+ peerDependencies:
+ react: ^19.1.0
+
+ react-test-renderer@19.1.4:
+ resolution: {integrity: sha512-dmcR2lSwouaNJKNRd53eeZHuWjF4YYZIq/q6wLiVz50ENrkU/Pds+pS+4XyJ/nwWmjA1ZhHxAp+vfR8A9PEcYQ==}
+ peerDependencies:
+ react: ^19.1.4
+
react@19.1.4:
resolution: {integrity: sha512-DHINL3PAmPUiK1uszfbKiXqfE03eszdt5BpVSuEAHb5nfmNPwnsy7g39h2t8aXFc/Bv99GH81s+j8dobtD+jOw==}
engines: {node: '>=0.10.0'}
@@ -5237,6 +5449,10 @@ packages:
resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ redent@3.0.0:
+ resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==}
+ engines: {node: '>=8'}
+
reflect.getprototypeof@1.0.10:
resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}
engines: {node: '>= 0.4'}
@@ -5284,6 +5500,9 @@ packages:
resolution: {integrity: sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==}
engines: {node: '>= 4.0.0'}
+ requires-port@1.0.0:
+ resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+
reselect@4.1.8:
resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==}
@@ -5381,6 +5600,10 @@ packages:
resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==}
engines: {node: '>=11.0.0'}
+ saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+
scheduler@0.26.0:
resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
@@ -5410,6 +5633,9 @@ packages:
resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==}
engines: {node: '>= 0.8.0'}
+ server-only@0.0.1:
+ resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==}
+
set-blocking@2.0.0:
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
@@ -5482,6 +5708,10 @@ packages:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
+ slash@5.1.0:
+ resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==}
+ engines: {node: '>=14.16'}
+
slice-ansi@2.1.0:
resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==}
engines: {node: '>=6'}
@@ -5512,6 +5742,10 @@ packages:
source-map-support@0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
+ source-map@0.5.6:
+ resolution: {integrity: sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==}
+ engines: {node: '>=0.10.0'}
+
source-map@0.5.7:
resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
engines: {node: '>=0.10.0'}
@@ -5530,6 +5764,9 @@ packages:
sprintf-js@1.1.3:
resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==}
+ stack-generator@2.0.10:
+ resolution: {integrity: sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==}
+
stack-utils@2.0.6:
resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
engines: {node: '>=10'}
@@ -5537,6 +5774,12 @@ packages:
stackframe@1.3.4:
resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==}
+ stacktrace-gps@3.1.2:
+ resolution: {integrity: sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==}
+
+ stacktrace-js@2.0.2:
+ resolution: {integrity: sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg==}
+
stacktrace-parser@0.1.11:
resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==}
engines: {node: '>=6'}
@@ -5572,6 +5815,10 @@ packages:
resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
engines: {node: '>=10'}
+ string-length@5.0.1:
+ resolution: {integrity: sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==}
+ engines: {node: '>=12.20'}
+
string-natural-compare@3.0.1:
resolution: {integrity: sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==}
@@ -5625,6 +5872,10 @@ packages:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
+ strip-indent@3.0.0:
+ resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
+ engines: {node: '>=8'}
+
strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
@@ -5668,6 +5919,9 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
+ symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
tar-fs@2.1.4:
resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==}
@@ -5739,6 +5993,14 @@ packages:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'}
+ tough-cookie@4.1.4:
+ resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
+ engines: {node: '>=6'}
+
+ tr46@3.0.0:
+ resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
+ engines: {node: '>=12'}
+
ts-api-utils@1.4.3:
resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==}
engines: {node: '>=16'}
@@ -5853,6 +6115,10 @@ packages:
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
engines: {node: '>= 4.0.0'}
+ universalify@0.2.0:
+ resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
+ engines: {node: '>= 4.0.0'}
+
unpipe@1.0.0:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
@@ -5866,6 +6132,9 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ url-parse@1.5.10:
+ resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+
urlencode@2.0.0:
resolution: {integrity: sha512-K4+koEq4II9FqKKdLyMwfVFiWvTLJsdsIihXCprumjlOwpviO44E4hAhLYBLb6CEVTZh9hXXMTQHIT+Hwv5BPw==}
@@ -5912,6 +6181,10 @@ packages:
vlq@1.0.1:
resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==}
+ w3c-xmlserializer@4.0.0:
+ resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==}
+ engines: {node: '>=14'}
+
walker@1.0.8:
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
@@ -5925,13 +6198,30 @@ packages:
resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==}
engines: {node: '>=8'}
+ webidl-conversions@7.0.0:
+ resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
+ engines: {node: '>=12'}
+
+ whatwg-encoding@2.0.0:
+ resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
+ engines: {node: '>=12'}
+ deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
+
whatwg-fetch@3.6.20:
resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==}
+ whatwg-mimetype@3.0.0:
+ resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
+ engines: {node: '>=12'}
+
whatwg-url-without-unicode@8.0.0-3:
resolution: {integrity: sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==}
engines: {node: '>=10'}
+ whatwg-url@11.0.0:
+ resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==}
+ engines: {node: '>=12'}
+
which-boxed-primitive@1.1.1:
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
engines: {node: '>= 0.4'}
@@ -6024,6 +6314,10 @@ packages:
resolution: {integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==}
engines: {node: '>=10.0.0'}
+ xml-name-validator@4.0.0:
+ resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
+ engines: {node: '>=12'}
+
xml2js@0.6.0:
resolution: {integrity: sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==}
engines: {node: '>=4.0.0'}
@@ -6036,6 +6330,9 @@ packages:
resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==}
engines: {node: '>=8.0'}
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
y18n@4.0.3:
resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
@@ -7677,6 +7974,8 @@ snapshots:
dependencies:
'@jest/types': 29.6.3
+ '@jest/diff-sequences@30.0.1': {}
+
'@jest/environment@29.7.0':
dependencies:
'@jest/fake-timers': 29.7.0
@@ -7704,6 +8003,8 @@ snapshots:
jest-mock: 29.7.0
jest-util: 29.7.0
+ '@jest/get-type@30.1.0': {}
+
'@jest/globals@29.7.0':
dependencies:
'@jest/environment': 29.7.0
@@ -7746,6 +8047,10 @@ snapshots:
dependencies:
'@sinclair/typebox': 0.27.10
+ '@jest/schemas@30.0.5':
+ dependencies:
+ '@sinclair/typebox': 0.34.48
+
'@jest/source-map@29.6.3':
dependencies:
'@jridgewell/trace-mapping': 0.3.31
@@ -8396,6 +8701,8 @@ snapshots:
'@sinclair/typebox@0.27.10': {}
+ '@sinclair/typebox@0.34.48': {}
+
'@sinonjs/commons@3.0.1':
dependencies:
type-detect: 4.0.8
@@ -8406,6 +8713,20 @@ snapshots:
'@tediousjs/connection-string@0.5.0': {}
+ '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@25.2.3))(react-native@0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4))(react-test-renderer@19.1.4(react@19.1.4))(react@19.1.4)':
+ dependencies:
+ jest-matcher-utils: 30.2.0
+ picocolors: 1.1.1
+ pretty-format: 30.2.0
+ react: 19.1.4
+ react-native: 0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4)
+ react-test-renderer: 19.1.4(react@19.1.4)
+ redent: 3.0.0
+ optionalDependencies:
+ jest: 29.7.0(@types/node@25.2.3)
+
+ '@tootallnate/once@2.0.0': {}
+
'@types/babel__core@7.20.5':
dependencies:
'@babel/parser': 7.29.0
@@ -8462,6 +8783,12 @@ snapshots:
expect: 29.7.0
pretty-format: 29.7.0
+ '@types/jsdom@20.0.1':
+ dependencies:
+ '@types/node': 25.2.3
+ '@types/tough-cookie': 4.0.5
+ parse5: 7.3.0
+
'@types/json-schema@7.0.15': {}
'@types/lodash-es@4.17.12':
@@ -8499,6 +8826,8 @@ snapshots:
'@types/stack-utils@2.0.3': {}
+ '@types/tough-cookie@4.0.5': {}
+
'@types/yargs-parser@21.0.3': {}
'@types/yargs@17.0.35':
@@ -8744,6 +9073,8 @@ snapshots:
'@xmldom/xmldom@0.8.11': {}
+ abab@2.0.6: {}
+
abort-controller@3.0.0:
dependencies:
event-target-shim: 5.0.1
@@ -8753,12 +9084,27 @@ snapshots:
mime-types: 2.1.35
negotiator: 0.6.3
+ acorn-globals@7.0.1:
+ dependencies:
+ acorn: 8.15.0
+ acorn-walk: 8.3.5
+
acorn-jsx@5.3.2(acorn@8.15.0):
dependencies:
acorn: 8.15.0
+ acorn-walk@8.3.5:
+ dependencies:
+ acorn: 8.15.0
+
acorn@8.15.0: {}
+ agent-base@6.0.2:
+ dependencies:
+ debug: 4.4.3(supports-color@9.4.0)
+ transitivePeerDependencies:
+ - supports-color
+
agent-base@7.1.4: {}
aggregate-error@3.1.0:
@@ -8779,6 +9125,8 @@ snapshots:
dependencies:
type-fest: 0.21.3
+ ansi-escapes@6.2.1: {}
+
ansi-fragments@0.2.1:
dependencies:
colorette: 1.4.0
@@ -8897,6 +9245,8 @@ snapshots:
async-limiter@1.0.1: {}
+ asynckit@0.4.0: {}
+
available-typed-arrays@1.0.7:
dependencies:
possible-typed-array-names: 1.1.0
@@ -9206,6 +9556,11 @@ snapshots:
escape-string-regexp: 1.0.5
supports-color: 5.5.0
+ chalk@3.0.0:
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+
chalk@4.1.2:
dependencies:
ansi-styles: 4.3.0
@@ -9213,6 +9568,8 @@ snapshots:
char-regex@1.0.2: {}
+ char-regex@2.0.2: {}
+
cheerio-select@2.1.0:
dependencies:
boolbase: 1.0.0
@@ -9348,6 +9705,10 @@ snapshots:
colorette@2.0.20: {}
+ combined-stream@1.0.8:
+ dependencies:
+ delayed-stream: 1.0.0
+
command-exists@1.2.9: {}
commander@11.1.0: {}
@@ -9439,8 +9800,22 @@ snapshots:
css-what@6.2.2: {}
+ cssom@0.3.8: {}
+
+ cssom@0.5.0: {}
+
+ cssstyle@2.3.0:
+ dependencies:
+ cssom: 0.3.8
+
csstype@3.2.3: {}
+ data-urls@3.0.2:
+ dependencies:
+ abab: 2.0.6
+ whatwg-mimetype: 3.0.0
+ whatwg-url: 11.0.0
+
data-view-buffer@1.0.2:
dependencies:
call-bound: 1.0.4
@@ -9477,6 +9852,8 @@ snapshots:
decamelize@1.2.0: {}
+ decimal.js@10.6.0: {}
+
decode-uri-component@0.2.2: {}
decompress-response@6.0.0:
@@ -9522,6 +9899,8 @@ snapshots:
has-property-descriptors: 1.0.2
object-keys: 1.1.1
+ delayed-stream@1.0.0: {}
+
depd@2.0.0: {}
destroy@1.2.0: {}
@@ -9552,6 +9931,10 @@ snapshots:
domelementtype@2.3.0: {}
+ domexception@4.0.0:
+ dependencies:
+ webidl-conversions: 7.0.0
+
domhandler@5.0.3:
dependencies:
domelementtype: 2.3.0
@@ -9782,6 +10165,14 @@ snapshots:
escape-string-regexp@4.0.0: {}
+ escodegen@2.1.0:
+ dependencies:
+ esprima: 4.0.1
+ estraverse: 5.3.0
+ esutils: 2.0.3
+ optionalDependencies:
+ source-map: 0.6.1
+
eslint-config-prettier@8.10.2(eslint@8.57.1):
dependencies:
eslint: 8.57.1
@@ -9877,6 +10268,15 @@ snapshots:
string.prototype.matchall: 4.0.12
string.prototype.repeat: 1.0.0
+ eslint-plugin-testing-library@7.16.0(eslint@8.57.1)(typescript@5.9.3):
+ dependencies:
+ '@typescript-eslint/scope-manager': 8.56.0
+ '@typescript-eslint/utils': 8.56.0(eslint@8.57.1)(typescript@5.9.3)
+ eslint: 8.57.1
+ transitivePeerDependencies:
+ - supports-color
+ - typescript
+
eslint-scope@5.1.1:
dependencies:
esrecurse: 4.3.0
@@ -10258,6 +10658,14 @@ snapshots:
dependencies:
is-callable: 1.2.7
+ form-data@4.0.5:
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ es-set-tostringtag: 2.1.0
+ hasown: 2.0.2
+ mime-types: 2.1.35
+
freeport-async@2.0.0: {}
fresh@0.5.2: {}
@@ -10446,6 +10854,10 @@ snapshots:
dependencies:
lru-cache: 10.4.3
+ html-encoding-sniffer@3.0.0:
+ dependencies:
+ whatwg-encoding: 2.0.0
+
html-escaper@2.0.2: {}
htmlparser2@10.1.0:
@@ -10470,6 +10882,14 @@ snapshots:
statuses: 2.0.2
toidentifier: 1.0.1
+ http-proxy-agent@5.0.0:
+ dependencies:
+ '@tootallnate/once': 2.0.0
+ agent-base: 6.0.2
+ debug: 4.4.3(supports-color@9.4.0)
+ transitivePeerDependencies:
+ - supports-color
+
http-proxy-agent@7.0.2:
dependencies:
agent-base: 7.1.4
@@ -10477,6 +10897,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ https-proxy-agent@5.0.1:
+ dependencies:
+ agent-base: 6.0.2
+ debug: 4.4.3(supports-color@9.4.0)
+ transitivePeerDependencies:
+ - supports-color
+
https-proxy-agent@7.0.6:
dependencies:
agent-base: 7.1.4
@@ -10654,6 +11081,8 @@ snapshots:
is-plain-object@5.0.0: {}
+ is-potential-custom-element-name@1.0.1: {}
+
is-regex@1.2.1:
dependencies:
call-bound: 1.0.4
@@ -10849,6 +11278,13 @@ snapshots:
jest-get-type: 29.6.3
pretty-format: 29.7.0
+ jest-diff@30.2.0:
+ dependencies:
+ '@jest/diff-sequences': 30.0.1
+ '@jest/get-type': 30.1.0
+ chalk: 4.1.2
+ pretty-format: 30.2.0
+
jest-docblock@29.7.0:
dependencies:
detect-newline: 3.1.0
@@ -10861,6 +11297,21 @@ snapshots:
jest-util: 29.7.0
pretty-format: 29.7.0
+ jest-environment-jsdom@29.7.0:
+ dependencies:
+ '@jest/environment': 29.7.0
+ '@jest/fake-timers': 29.7.0
+ '@jest/types': 29.6.3
+ '@types/jsdom': 20.0.1
+ '@types/node': 25.2.3
+ jest-mock: 29.7.0
+ jest-util: 29.7.0
+ jsdom: 20.0.3
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+
jest-environment-node@29.7.0:
dependencies:
'@jest/environment': 29.7.0
@@ -10870,6 +11321,33 @@ snapshots:
jest-mock: 29.7.0
jest-util: 29.7.0
+ jest-expo@54.0.17(@babel/core@7.29.0)(expo@54.0.33(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4))(react@19.1.4))(react-native@0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4))(react@19.1.4))(jest@29.7.0(@types/node@25.2.3))(react-native@0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4))(react@19.1.4):
+ dependencies:
+ '@expo/config': 12.0.13
+ '@expo/json-file': 10.0.8
+ '@jest/create-cache-key-function': 29.7.0
+ '@jest/globals': 29.7.0
+ babel-jest: 29.7.0(@babel/core@7.29.0)
+ expo: 54.0.33(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4))(react@19.1.4))(react-native@0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4))(react@19.1.4)
+ jest-environment-jsdom: 29.7.0
+ jest-snapshot: 29.7.0
+ jest-watch-select-projects: 2.0.0
+ jest-watch-typeahead: 2.2.1(jest@29.7.0(@types/node@25.2.3))
+ json5: 2.2.3
+ lodash: 4.17.23
+ react-native: 0.81.6(@babel/core@7.29.0)(@react-native-community/cli@20.1.1(typescript@5.9.3))(@react-native/metro-config@0.81.6(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.4)
+ react-test-renderer: 19.1.0(react@19.1.4)
+ server-only: 0.0.1
+ stacktrace-js: 2.0.2
+ transitivePeerDependencies:
+ - '@babel/core'
+ - bufferutil
+ - canvas
+ - jest
+ - react
+ - supports-color
+ - utf-8-validate
+
jest-get-type@29.6.3: {}
jest-haste-map@29.7.0:
@@ -10900,6 +11378,13 @@ snapshots:
jest-get-type: 29.6.3
pretty-format: 29.7.0
+ jest-matcher-utils@30.2.0:
+ dependencies:
+ '@jest/get-type': 30.1.0
+ chalk: 4.1.2
+ jest-diff: 30.2.0
+ pretty-format: 30.2.0
+
jest-message-util@29.7.0:
dependencies:
'@babel/code-frame': 7.29.0
@@ -11039,6 +11524,23 @@ snapshots:
leven: 3.1.0
pretty-format: 29.7.0
+ jest-watch-select-projects@2.0.0:
+ dependencies:
+ ansi-escapes: 4.3.2
+ chalk: 3.0.0
+ prompts: 2.4.2
+
+ jest-watch-typeahead@2.2.1(jest@29.7.0(@types/node@25.2.3)):
+ dependencies:
+ ansi-escapes: 6.2.1
+ chalk: 4.1.2
+ jest: 29.7.0(@types/node@25.2.3)
+ jest-regex-util: 29.6.3
+ jest-watcher: 29.7.0
+ slash: 5.1.0
+ string-length: 5.0.1
+ strip-ansi: 7.1.2
+
jest-watcher@29.7.0:
dependencies:
'@jest/test-result': 29.7.0
@@ -11098,6 +11600,39 @@ snapshots:
jsc-safe-url@0.2.4: {}
+ jsdom@20.0.3:
+ dependencies:
+ abab: 2.0.6
+ acorn: 8.15.0
+ acorn-globals: 7.0.1
+ cssom: 0.5.0
+ cssstyle: 2.3.0
+ data-urls: 3.0.2
+ decimal.js: 10.6.0
+ domexception: 4.0.0
+ escodegen: 2.1.0
+ form-data: 4.0.5
+ html-encoding-sniffer: 3.0.0
+ http-proxy-agent: 5.0.0
+ https-proxy-agent: 5.0.1
+ is-potential-custom-element-name: 1.0.1
+ nwsapi: 2.2.23
+ parse5: 7.3.0
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 4.1.4
+ w3c-xmlserializer: 4.0.0
+ webidl-conversions: 7.0.0
+ whatwg-encoding: 2.0.0
+ whatwg-mimetype: 3.0.0
+ whatwg-url: 11.0.0
+ ws: 8.19.0
+ xml-name-validator: 4.0.0
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+
jsesc@3.1.0: {}
json-buffer@3.0.1: {}
@@ -11572,6 +12107,8 @@ snapshots:
mimic-response@3.1.0: {}
+ min-indent@1.0.1: {}
+
minimatch@10.2.1:
dependencies:
brace-expansion: 5.0.2
@@ -11678,6 +12215,8 @@ snapshots:
nullthrows@1.1.1: {}
+ nwsapi@2.2.23: {}
+
ob1@0.83.3:
dependencies:
flow-enums-runtime: 0.0.6
@@ -11960,6 +12499,12 @@ snapshots:
ansi-styles: 5.2.0
react-is: 18.3.1
+ pretty-format@30.2.0:
+ dependencies:
+ '@jest/schemas': 30.0.5
+ ansi-styles: 5.2.0
+ react-is: 18.3.1
+
proc-log@4.2.0: {}
process@0.11.10: {}
@@ -11996,6 +12541,10 @@ snapshots:
'@types/node': 25.2.3
long: 5.3.2
+ psl@1.15.0:
+ dependencies:
+ punycode: 2.3.1
+
pump@3.0.3:
dependencies:
end-of-stream: 1.4.5
@@ -12018,6 +12567,8 @@ snapshots:
split-on-first: 1.1.0
strict-uri-encode: 2.0.0
+ querystringify@2.2.0: {}
+
queue-microtask@1.2.3: {}
queue@6.0.2:
@@ -12284,6 +12835,18 @@ snapshots:
react-refresh@0.14.2: {}
+ react-test-renderer@19.1.0(react@19.1.4):
+ dependencies:
+ react: 19.1.4
+ react-is: 19.2.4
+ scheduler: 0.26.0
+
+ react-test-renderer@19.1.4(react@19.1.4):
+ dependencies:
+ react: 19.1.4
+ react-is: 19.2.4
+ scheduler: 0.26.0
+
react@19.1.4: {}
readable-stream@3.6.2:
@@ -12300,6 +12863,11 @@ snapshots:
process: 0.11.10
string_decoder: 1.3.0
+ redent@3.0.0:
+ dependencies:
+ indent-string: 4.0.0
+ strip-indent: 3.0.0
+
reflect.getprototypeof@1.0.10:
dependencies:
call-bind: 1.0.8
@@ -12359,6 +12927,8 @@ snapshots:
rc: 1.2.8
resolve: 1.7.1
+ requires-port@1.0.0: {}
+
reselect@4.1.8: {}
resolve-cwd@3.0.0:
@@ -12460,6 +13030,10 @@ snapshots:
sax@1.4.4: {}
+ saxes@6.0.0:
+ dependencies:
+ xmlchars: 2.2.0
+
scheduler@0.26.0: {}
semver@6.3.1: {}
@@ -12497,6 +13071,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ server-only@0.0.1: {}
+
set-blocking@2.0.0: {}
set-function-length@1.2.2:
@@ -12585,6 +13161,8 @@ snapshots:
slash@3.0.0: {}
+ slash@5.1.0: {}
+
slice-ansi@2.1.0:
dependencies:
ansi-styles: 3.2.1
@@ -12622,6 +13200,8 @@ snapshots:
buffer-from: 1.1.2
source-map: 0.6.1
+ source-map@0.5.6: {}
+
source-map@0.5.7: {}
source-map@0.6.1: {}
@@ -12632,12 +13212,27 @@ snapshots:
sprintf-js@1.1.3: {}
+ stack-generator@2.0.10:
+ dependencies:
+ stackframe: 1.3.4
+
stack-utils@2.0.6:
dependencies:
escape-string-regexp: 2.0.0
stackframe@1.3.4: {}
+ stacktrace-gps@3.1.2:
+ dependencies:
+ source-map: 0.5.6
+ stackframe: 1.3.4
+
+ stacktrace-js@2.0.2:
+ dependencies:
+ error-stack-parser: 2.1.4
+ stack-generator: 2.0.10
+ stacktrace-gps: 3.1.2
+
stacktrace-parser@0.1.11:
dependencies:
type-fest: 0.7.1
@@ -12664,6 +13259,11 @@ snapshots:
char-regex: 1.0.2
strip-ansi: 6.0.1
+ string-length@5.0.1:
+ dependencies:
+ char-regex: 2.0.2
+ strip-ansi: 7.1.2
+
string-natural-compare@3.0.1: {}
string-width@4.2.3:
@@ -12742,6 +13342,10 @@ snapshots:
strip-final-newline@2.0.0: {}
+ strip-indent@3.0.0:
+ dependencies:
+ min-indent: 1.0.1
+
strip-json-comments@2.0.1: {}
strip-json-comments@3.1.1: {}
@@ -12781,6 +13385,8 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
+ symbol-tree@3.2.4: {}
+
tar-fs@2.1.4:
dependencies:
chownr: 1.1.4
@@ -12885,6 +13491,17 @@ snapshots:
toidentifier@1.0.1: {}
+ tough-cookie@4.1.4:
+ dependencies:
+ psl: 1.15.0
+ punycode: 2.3.1
+ universalify: 0.2.0
+ url-parse: 1.5.10
+
+ tr46@3.0.0:
+ dependencies:
+ punycode: 2.3.1
+
ts-api-utils@1.4.3(typescript@5.9.3):
dependencies:
typescript: 5.9.3
@@ -12990,6 +13607,8 @@ snapshots:
universalify@0.1.2: {}
+ universalify@0.2.0: {}
+
unpipe@1.0.0: {}
update-browserslist-db@1.2.3(browserslist@4.28.1):
@@ -13002,6 +13621,11 @@ snapshots:
dependencies:
punycode: 2.3.1
+ url-parse@1.5.10:
+ dependencies:
+ querystringify: 2.2.0
+ requires-port: 1.0.0
+
urlencode@2.0.0:
dependencies:
iconv-lite: 0.6.3
@@ -13042,6 +13666,10 @@ snapshots:
vlq@1.0.1: {}
+ w3c-xmlserializer@4.0.0:
+ dependencies:
+ xml-name-validator: 4.0.0
+
walker@1.0.8:
dependencies:
makeerror: 1.0.12
@@ -13054,14 +13682,27 @@ snapshots:
webidl-conversions@5.0.0: {}
+ webidl-conversions@7.0.0: {}
+
+ whatwg-encoding@2.0.0:
+ dependencies:
+ iconv-lite: 0.6.3
+
whatwg-fetch@3.6.20: {}
+ whatwg-mimetype@3.0.0: {}
+
whatwg-url-without-unicode@8.0.0-3:
dependencies:
buffer: 5.7.1
punycode: 2.3.1
webidl-conversions: 5.0.0
+ whatwg-url@11.0.0:
+ dependencies:
+ tr46: 3.0.0
+ webidl-conversions: 7.0.0
+
which-boxed-primitive@1.1.1:
dependencies:
is-bigint: 1.1.0
@@ -13153,6 +13794,8 @@ snapshots:
simple-plist: 1.3.1
uuid: 7.0.3
+ xml-name-validator@4.0.0: {}
+
xml2js@0.6.0:
dependencies:
sax: 1.4.4
@@ -13162,6 +13805,8 @@ snapshots:
xmlbuilder@15.1.1: {}
+ xmlchars@2.2.0: {}
+
y18n@4.0.3: {}
y18n@5.0.8: {}
diff --git a/src/components/Context/__mocks__/LibraryContext.tsx b/src/components/Context/__mocks__/LibraryContext.tsx
new file mode 100644
index 0000000000..f420e08b0d
--- /dev/null
+++ b/src/components/Context/__mocks__/LibraryContext.tsx
@@ -0,0 +1,35 @@
+import React from 'react';
+
+const defaultLibraryContext = {
+ library: [],
+ categories: [],
+ isLoading: false,
+ setCategories: jest.fn(),
+ refreshCategories: jest.fn().mockResolvedValue(undefined),
+ setLibrary: jest.fn(),
+ novelInLibrary: jest.fn(() => false),
+ switchNovelToLibrary: jest.fn().mockResolvedValue(undefined),
+ refetchLibrary: jest.fn(),
+ setLibrarySearchText: jest.fn(),
+ settings: {
+ sortOrder: undefined,
+ filter: undefined,
+ showDownloadBadges: false,
+ showUnreadBadges: false,
+ showNumberOfNovels: false,
+ displayMode: undefined,
+ novelsPerRow: undefined,
+ incognitoMode: false,
+ downloadedOnlyMode: false,
+ },
+};
+
+export const LibraryContextProvider = ({
+ children,
+}: {
+ children: React.ReactNode;
+}) => {
+ return <>{children}>;
+};
+
+export const useLibraryContext = jest.fn(() => defaultLibraryContext);
diff --git a/src/components/__tests__/Button.test.tsx b/src/components/__tests__/Button.test.tsx
new file mode 100644
index 0000000000..04ebea6565
--- /dev/null
+++ b/src/components/__tests__/Button.test.tsx
@@ -0,0 +1,65 @@
+import './mocks';
+import React from 'react';
+import { render, screen, fireEvent } from '@testing-library/react-native';
+import { Text } from 'react-native';
+import Button from '../Button/Button';
+
+const mockUseTheme = jest.fn();
+
+jest.mock('@hooks/persisted', () => ({
+ useTheme: () => mockUseTheme(),
+}));
+
+describe('Button', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ mockUseTheme.mockReturnValue({
+ primary: '#6200ee',
+ background: '#ffffff',
+ surface: '#f5f5f5',
+ onPrimary: '#ffffff',
+ onSurface: '#000000',
+ });
+ });
+
+ it('renders with title prop', () => {
+ render(