wip - claude --resume 742969c2-ab50-4a79-b7bd-3971e9fd314d
This commit is contained in:
@@ -82,5 +82,4 @@ jobs:
|
||||
- name: Check & compile i18n
|
||||
run: pnpm intl:build
|
||||
- name: Run tests
|
||||
run: |
|
||||
NODE_ENV=test pnpm test --forceExit
|
||||
run: pnpm test-ci
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, {type ReactNode} from 'react'
|
||||
import {FlatList, Modal, ScrollView, TextInput, View} from 'react-native'
|
||||
import {vi} from 'vitest'
|
||||
|
||||
const BottomSheetModalContext = React.createContext(null)
|
||||
BottomSheetModalContext.displayName = 'BottomSheetModalContext'
|
||||
@@ -33,12 +34,12 @@ const BottomSheetScrollView = (props: any) => <ScrollView {...props} />
|
||||
const BottomSheetFlatList = (props: any) => <FlatList {...props} />
|
||||
const BottomSheetTextInput = (props: any) => <TextInput {...props} />
|
||||
|
||||
const useBottomSheet = jest.fn()
|
||||
const useBottomSheetModal = jest.fn()
|
||||
const useBottomSheetSpringConfigs = jest.fn()
|
||||
const useBottomSheetTimingConfigs = jest.fn()
|
||||
const useBottomSheetInternal = jest.fn()
|
||||
const useBottomSheetDynamicSnapPoints = jest.fn()
|
||||
const useBottomSheet = vi.fn()
|
||||
const useBottomSheetModal = vi.fn()
|
||||
const useBottomSheetSpringConfigs = vi.fn()
|
||||
const useBottomSheetTimingConfigs = vi.fn()
|
||||
const useBottomSheetInternal = vi.fn()
|
||||
const useBottomSheetDynamicSnapPoints = vi.fn()
|
||||
|
||||
export {useBottomSheet}
|
||||
export {useBottomSheetModal}
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
export const getLocales = jest.fn().mockResolvedValue([])
|
||||
import {vi} from 'vitest'
|
||||
|
||||
export const getLocales = vi.fn().mockResolvedValue([])
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export const CID = jest.fn().mockImplementation(() => {
|
||||
import {vi} from 'vitest'
|
||||
|
||||
export const CID = vi.fn().mockImplementation(() => {
|
||||
return {}
|
||||
})
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
export const from = jest.fn().mockImplementation(() => {
|
||||
import {vi} from 'vitest'
|
||||
|
||||
export const from = vi.fn().mockImplementation(() => {
|
||||
return {
|
||||
digest: jest.fn().mockImplementation(() => {
|
||||
digest: vi.fn().mockImplementation(() => {
|
||||
return Promise.resolve('')
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
jest.mock('sentry-expo', () => ({
|
||||
init: () => jest.fn(),
|
||||
import {vi} from 'vitest'
|
||||
|
||||
vi.mock('sentry-expo', () => ({
|
||||
init: () => vi.fn(),
|
||||
}))
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {describe, expect, it} from 'vitest'
|
||||
|
||||
import {bundleAsync} from '../../../src/lib/async/bundle'
|
||||
|
||||
describe('bundle', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {describe, expect, it} from '@jest/globals'
|
||||
import {describe, expect, it} from 'vitest'
|
||||
import tldts from 'tldts'
|
||||
|
||||
import {isEmailMaybeInvalid} from '#/lib/strings/email'
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {describe, expect, it} from 'vitest'
|
||||
|
||||
import {isNetworkError} from '../../src/lib/strings/errors'
|
||||
|
||||
describe('isNetworkError', () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {createDownloadResumable, deleteAsync} from 'expo-file-system/legacy'
|
||||
import {manipulateAsync, SaveFormat} from 'expo-image-manipulator'
|
||||
import {afterEach, beforeEach, describe, expect, it, type Mock, vi} from 'vitest'
|
||||
|
||||
import {
|
||||
downloadAndResize,
|
||||
@@ -16,10 +17,10 @@ const mockResizedImage = {
|
||||
}
|
||||
|
||||
describe('downloadAndResize', () => {
|
||||
const errorSpy = jest.spyOn(global.console, 'error')
|
||||
const errorSpy = vi.spyOn(global.console, 'error')
|
||||
|
||||
beforeEach(() => {
|
||||
const mockedCreateResizedImage = manipulateAsync as jest.Mock
|
||||
const mockedCreateResizedImage = manipulateAsync as Mock
|
||||
mockedCreateResizedImage.mockResolvedValue({
|
||||
uri: 'file://resized-image.jpg',
|
||||
...mockResizedImage,
|
||||
@@ -27,13 +28,13 @@ describe('downloadAndResize', () => {
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks()
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('should return resized image for valid URI and options', async () => {
|
||||
const mockedFetch = createDownloadResumable as jest.Mock
|
||||
const mockedFetch = createDownloadResumable as Mock
|
||||
mockedFetch.mockReturnValue({
|
||||
cancelAsync: jest.fn(),
|
||||
cancelAsync: vi.fn(),
|
||||
downloadAsync: jest
|
||||
.fn()
|
||||
.mockResolvedValue({uri: 'file://resized-image.jpg'}),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {describe, expect, it} from 'vitest'
|
||||
|
||||
import {getLikelyType, LikelyType} from '../../src/lib/link-meta/link-meta'
|
||||
|
||||
describe('getLikelyType', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {describe, expect, it} from 'vitest'
|
||||
|
||||
import {clamp} from '../../src/lib/numbers'
|
||||
|
||||
describe('clamp', () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {RichText} from '@atproto/api'
|
||||
import {i18n} from '@lingui/core'
|
||||
import {describe, expect, it} from 'vitest'
|
||||
|
||||
import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player'
|
||||
import {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {describe, expect, it} from 'vitest'
|
||||
|
||||
import {type IsValidHandle, validateServiceHandle} from '#/lib/strings/handles'
|
||||
|
||||
describe('handle validation', () => {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {describe, expect, it} from 'vitest'
|
||||
|
||||
import {
|
||||
getMentionAt,
|
||||
insertMentionAt,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {describe, expect, it} from '@jest/globals'
|
||||
import {describe, expect, it} from 'vitest'
|
||||
|
||||
import {
|
||||
isPossiblyAUrl,
|
||||
|
||||
+1
-3
@@ -1,6 +1,5 @@
|
||||
module.exports = function (api) {
|
||||
api.cache(true)
|
||||
const isTestEnv = process.env.NODE_ENV === 'test'
|
||||
return {
|
||||
presets: [
|
||||
[
|
||||
@@ -9,8 +8,7 @@ module.exports = function (api) {
|
||||
lazyImports: true,
|
||||
native: {
|
||||
// Disable ESM -> CJS compilation because Metro takes care of it.
|
||||
// However, we need it in Jest tests since those run without Metro.
|
||||
disableImportExportTransform: !isTestEnv,
|
||||
disableImportExportTransform: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
const {RuleTester} = require('eslint')
|
||||
const tseslint = require('typescript-eslint')
|
||||
const avoidUnwrappedText = require('../avoid-unwrapped-text')
|
||||
import {RuleTester} from 'eslint'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import {describe, it} from 'vitest'
|
||||
|
||||
import avoidUnwrappedText from '../avoid-unwrapped-text.js'
|
||||
|
||||
RuleTester.describe = describe
|
||||
RuleTester.it = it
|
||||
RuleTester.itOnly = it.only
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
const {RuleTester} = require('eslint')
|
||||
const tseslint = require('typescript-eslint')
|
||||
const linguiMsgRule = require('../lingui-msg-rule')
|
||||
import {RuleTester} from 'eslint'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import {describe, it} from 'vitest'
|
||||
|
||||
import linguiMsgRule from '../lingui-msg-rule.js'
|
||||
|
||||
RuleTester.describe = describe
|
||||
RuleTester.it = it
|
||||
RuleTester.itOnly = it.only
|
||||
|
||||
const ruleTester = new RuleTester({
|
||||
languageOptions: {
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
/* global jest */
|
||||
import 'react-native-gesture-handler/jestSetup'
|
||||
|
||||
import {configure} from '@testing-library/react-native'
|
||||
|
||||
configure({asyncUtilTimeout: 20000})
|
||||
|
||||
jest.mock('@react-native-async-storage/async-storage', () =>
|
||||
require('@react-native-async-storage/async-storage/jest/async-storage-mock'),
|
||||
)
|
||||
jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter', () => {
|
||||
// eslint-disable-next-line import-x/no-nodejs-modules
|
||||
const {EventEmitter} = require('events')
|
||||
return {
|
||||
__esModule: true,
|
||||
default: EventEmitter,
|
||||
}
|
||||
})
|
||||
|
||||
jest.mock('@fortawesome/react-native-fontawesome', () => ({
|
||||
FontAwesomeIcon: '',
|
||||
}))
|
||||
|
||||
jest.mock('react-native-safe-area-context', () => {
|
||||
const inset = {top: 0, right: 0, bottom: 0, left: 0}
|
||||
return {
|
||||
SafeAreaProvider: jest.fn().mockImplementation(({children}) => children),
|
||||
SafeAreaConsumer: jest
|
||||
.fn()
|
||||
.mockImplementation(({children}) => children(inset)),
|
||||
useSafeAreaInsets: jest.fn().mockImplementation(() => inset),
|
||||
}
|
||||
})
|
||||
|
||||
jest.mock('expo-file-system/legacy', () => ({
|
||||
getInfoAsync: jest.fn().mockResolvedValue({exists: true, size: 100}),
|
||||
deleteAsync: jest.fn(),
|
||||
moveAsync: jest.fn().mockResolvedValue(undefined),
|
||||
createDownloadResumable: jest.fn(),
|
||||
}))
|
||||
|
||||
jest.mock('expo-image-manipulator', () => ({
|
||||
manipulateAsync: jest.fn().mockResolvedValue({
|
||||
uri: 'file://resized-image',
|
||||
}),
|
||||
SaveFormat: {
|
||||
JPEG: 'jpeg',
|
||||
WEBP: 'webp',
|
||||
},
|
||||
}))
|
||||
|
||||
jest.mock('expo-camera', () => ({
|
||||
Camera: {
|
||||
useCameraPermissions: jest.fn(() => [true]),
|
||||
},
|
||||
}))
|
||||
|
||||
jest.mock('expo-media-library', () => ({
|
||||
__esModule: true, // this property makes it work
|
||||
default: jest.fn(),
|
||||
usePermissions: jest.fn(() => [true]),
|
||||
}))
|
||||
|
||||
jest.mock('@bsky.app/expo-guess-language', () => ({
|
||||
guessLanguageSync: jest
|
||||
.fn()
|
||||
.mockReturnValue([{language: 'en', confidence: 1}]),
|
||||
guessLanguageAsync: jest
|
||||
.fn()
|
||||
.mockResolvedValue([{language: 'en', confidence: 1}]),
|
||||
}))
|
||||
|
||||
jest.mock('sentry-expo', () => ({
|
||||
init: () => jest.fn(),
|
||||
Native: {
|
||||
ReactNativeTracing: jest.fn().mockImplementation(() => ({
|
||||
start: jest.fn(),
|
||||
stop: jest.fn(),
|
||||
})),
|
||||
ReactNavigationInstrumentation: jest.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
jest.mock('crypto', () => ({}))
|
||||
|
||||
jest.mock('expo-application', () => ({
|
||||
nativeApplicationVersion: '1.0.0',
|
||||
nativeBuildVersion: '1',
|
||||
}))
|
||||
|
||||
jest.mock('expo-modules-core', () => ({
|
||||
requireNativeModule: jest.fn().mockImplementation(moduleName => {
|
||||
if (moduleName === 'ExpoPlatformInfo') {
|
||||
return {
|
||||
getIsReducedMotionEnabled: () => false,
|
||||
}
|
||||
}
|
||||
if (moduleName === 'BottomSheet') {
|
||||
return {
|
||||
dismissAll: () => {},
|
||||
}
|
||||
}
|
||||
}),
|
||||
requireNativeViewManager: jest.fn().mockImplementation(_ => {
|
||||
return () => null
|
||||
}),
|
||||
createPermissionHook: () => () => [true],
|
||||
}))
|
||||
|
||||
jest.mock('expo-localization', () => ({
|
||||
getLocales: () => [],
|
||||
}))
|
||||
+8
-48
@@ -44,10 +44,10 @@
|
||||
"build-embed": "cd bskyembed && yarn build && yarn build-snippet && cd .. && node ./scripts/post-embed-build.js",
|
||||
"start": "expo start --dev-client",
|
||||
"start:prod": "expo start --dev-client --no-dev --minify",
|
||||
"test": "NODE_ENV=test jest --forceExit --testTimeout=20000 --bail",
|
||||
"test-watch": "NODE_ENV=test jest --watchAll",
|
||||
"test-ci": "NODE_ENV=test jest --ci --forceExit --reporters=default --reporters=jest-junit",
|
||||
"test-coverage": "NODE_ENV=test jest --coverage",
|
||||
"test": "NODE_ENV=test vitest run --bail=1",
|
||||
"test-watch": "NODE_ENV=test vitest",
|
||||
"test-ci": "NODE_ENV=test vitest run --reporter=default --reporter=junit --outputFile.junit=./junit.xml",
|
||||
"test-coverage": "NODE_ENV=test vitest run --coverage",
|
||||
"lint": "eslint --cache --quiet src",
|
||||
"lint-native": "swiftlint ./modules && ktlint ./modules",
|
||||
"lint-native:fix": "swiftlint --fix ./modules && ktlint --format ./modules",
|
||||
@@ -226,7 +226,7 @@
|
||||
"react-native-uitextview": "^1.4.0",
|
||||
"react-native-uuid": "^2.0.3",
|
||||
"react-native-view-shot": "^4.0.3",
|
||||
"react-native-web": "^0.21.0",
|
||||
"react-native-web": "^0.21.2",
|
||||
"react-native-web-webview": "^1.0.2",
|
||||
"react-native-webview": "^13.15.0",
|
||||
"react-remove-scroll-bar": "^2.3.8",
|
||||
@@ -250,12 +250,11 @@
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@lingui/babel-plugin-lingui-macro": "^5.9.2",
|
||||
"@lingui/cli": "^5.9.2",
|
||||
"@lingui/vite-plugin": "^6.0.1",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
|
||||
"@react-native/babel-preset": "0.81.5",
|
||||
"@react-native/typescript-config": "^0.81.5",
|
||||
"@sentry/webpack-plugin": "^3.2.2",
|
||||
"@testing-library/react-native": "^13.2.0",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/lodash.chunk": "^4.2.7",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"@types/lodash.shuffle": "^4.2.7",
|
||||
@@ -263,7 +262,7 @@
|
||||
"@types/react": "^19.1.17",
|
||||
"@types/react-dom": "^19.1.11",
|
||||
"@typescript/native-preview": "^7.0.0-dev.20260428.1",
|
||||
"babel-jest": "^29.7.0",
|
||||
"@vitest/coverage-v8": "^4.0.0",
|
||||
"babel-plugin-module-resolver": "^5.0.2",
|
||||
"babel-plugin-react-compiler": "19.1.0-rc.3",
|
||||
"babel-preset-expo": "~54.0.10",
|
||||
@@ -282,9 +281,6 @@
|
||||
"globals": "^17.0.0",
|
||||
"husky": "^8.0.3",
|
||||
"is-ci": "^3.0.1",
|
||||
"jest": "^29.7.0",
|
||||
"jest-expo": "~54.0.17",
|
||||
"jest-junit": "^16.0.0",
|
||||
"lint-staged": "^13.2.3",
|
||||
"prettier": "^3.8.3",
|
||||
"react-native-dotenv": "^3.4.11",
|
||||
@@ -293,45 +289,9 @@
|
||||
"ts-plugin-sort-import-suggestions": "^1.0.4",
|
||||
"typescript": "^6.0.2",
|
||||
"typescript-eslint": "^8.58.0",
|
||||
"vitest": "^4.0.0",
|
||||
"webpack-bundle-analyzer": "^4.10.1"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "jest-expo/ios",
|
||||
"setupFilesAfterEnv": [
|
||||
"./jest/jestSetup.js"
|
||||
],
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js",
|
||||
"jsx",
|
||||
"json",
|
||||
"node"
|
||||
],
|
||||
"transform": {
|
||||
"\\.[jt]sx?$": "babel-jest"
|
||||
},
|
||||
"transformIgnorePatterns": [
|
||||
"node_modules/(?!((jest-)?react-native|@react-native(-community)?)|@discord|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|nanoid|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|normalize-url|react-native-svg|@sentry/.*|sentry-expo|bcp-47-match)"
|
||||
],
|
||||
"modulePathIgnorePatterns": [
|
||||
"__tests__/.*/__mocks__",
|
||||
"__e2e__/.*",
|
||||
"bskylink/.*"
|
||||
],
|
||||
"coveragePathIgnorePatterns": [
|
||||
"<rootDir>/node_modules/",
|
||||
"<rootDir>/src/platform",
|
||||
"<rootDir>/src/third-party",
|
||||
"<rootDir>/src/view/com/util",
|
||||
"<rootDir>/src/state/lib",
|
||||
"<rootDir>/__tests__/test-utils.js"
|
||||
],
|
||||
"reporters": [
|
||||
"default",
|
||||
"jest-junit"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
|
||||
Generated
+834
-1277
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
import {jest} from '@jest/globals'
|
||||
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
||||
|
||||
import {transparentifyColor} from '../colorGeneration'
|
||||
|
||||
describe('transparentifyColor', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('converts hsl() to hsla()', () => {
|
||||
|
||||
@@ -1,39 +1,41 @@
|
||||
jest.mock('#/storage', () => ({
|
||||
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
||||
|
||||
vi.mock('#/storage', () => ({
|
||||
device: {
|
||||
get: jest.fn(),
|
||||
set: jest.fn(),
|
||||
get: vi.fn(),
|
||||
set: vi.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
jest.mock('#/analytics/identifiers/util', () => ({
|
||||
isSessionIdExpired: jest.fn(),
|
||||
vi.mock('#/analytics/identifiers/util', () => ({
|
||||
isSessionIdExpired: vi.fn(),
|
||||
}))
|
||||
|
||||
jest.mock('#/lib/appState', () => ({
|
||||
onAppStateChange: jest.fn(() => ({remove: jest.fn()})),
|
||||
vi.mock('#/lib/appState', () => ({
|
||||
onAppStateChange: vi.fn(() => ({remove: vi.fn()})),
|
||||
}))
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules()
|
||||
jest.clearAllMocks()
|
||||
vi.resetModules()
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
function getMocks() {
|
||||
const {device} = require('#/storage')
|
||||
const {isSessionIdExpired} = require('#/analytics/identifiers/util')
|
||||
async function getMocks() {
|
||||
const {device} = await import('#/storage')
|
||||
const {isSessionIdExpired} = await import('#/analytics/identifiers/util')
|
||||
return {
|
||||
device: jest.mocked(device),
|
||||
isSessionIdExpired: jest.mocked(isSessionIdExpired),
|
||||
device: vi.mocked(device),
|
||||
isSessionIdExpired: vi.mocked(isSessionIdExpired),
|
||||
}
|
||||
}
|
||||
|
||||
describe('session initialization', () => {
|
||||
it('creates new session and sets timestamp when none exists', () => {
|
||||
const {device, isSessionIdExpired} = getMocks()
|
||||
it('creates new session and sets timestamp when none exists', async () => {
|
||||
const {device, isSessionIdExpired} = await getMocks()
|
||||
device.get.mockReturnValue(undefined)
|
||||
isSessionIdExpired.mockReturnValue(false)
|
||||
|
||||
const {getInitialSessionId} = require('./session')
|
||||
const {getInitialSessionId} = await import('./session')
|
||||
const id = getInitialSessionId()
|
||||
|
||||
expect(id).toBeDefined()
|
||||
@@ -45,8 +47,8 @@ describe('session initialization', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('reuses existing session when not expired', () => {
|
||||
const {device, isSessionIdExpired} = getMocks()
|
||||
it('reuses existing session when not expired', async () => {
|
||||
const {device, isSessionIdExpired} = await getMocks()
|
||||
const existingId = 'existing-session-id'
|
||||
device.get.mockImplementation((key: string[]) => {
|
||||
if (key[0] === 'nativeSessionId') return existingId
|
||||
@@ -55,13 +57,13 @@ describe('session initialization', () => {
|
||||
})
|
||||
isSessionIdExpired.mockReturnValue(false)
|
||||
|
||||
const {getInitialSessionId} = require('./session')
|
||||
const {getInitialSessionId} = await import('./session')
|
||||
|
||||
expect(getInitialSessionId()).toBe(existingId)
|
||||
})
|
||||
|
||||
it('creates new session when existing is expired', () => {
|
||||
const {device, isSessionIdExpired} = getMocks()
|
||||
it('creates new session when existing is expired', async () => {
|
||||
const {device, isSessionIdExpired} = await getMocks()
|
||||
const existingId = 'existing-session-id'
|
||||
device.get.mockImplementation((key: string[]) => {
|
||||
if (key[0] === 'nativeSessionId') return existingId
|
||||
@@ -70,7 +72,7 @@ describe('session initialization', () => {
|
||||
})
|
||||
isSessionIdExpired.mockReturnValue(true)
|
||||
|
||||
const {getInitialSessionId} = require('./session')
|
||||
const {getInitialSessionId} = await import('./session')
|
||||
const id = getInitialSessionId()
|
||||
|
||||
expect(id).not.toBe(existingId)
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
import {afterEach, beforeEach, describe, expect, it, type Mock, vi} from 'vitest'
|
||||
|
||||
import {MetricsClient} from './client'
|
||||
|
||||
let appStateCallback: (state: string) => void
|
||||
|
||||
jest.mock('#/lib/appState', () => ({
|
||||
onAppStateChange: jest.fn(cb => {
|
||||
vi.mock('#/lib/appState', () => ({
|
||||
onAppStateChange: vi.fn(cb => {
|
||||
appStateCallback = cb
|
||||
return {remove: jest.fn()}
|
||||
return {remove: vi.fn()}
|
||||
}),
|
||||
}))
|
||||
|
||||
jest.mock('#/logger', () => ({
|
||||
vi.mock('#/logger', () => ({
|
||||
Logger: {
|
||||
create: () => ({
|
||||
info: jest.fn(),
|
||||
debug: jest.fn(),
|
||||
error: jest.fn(),
|
||||
info: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
error: vi.fn(),
|
||||
}),
|
||||
Context: {Metric: 'metric'},
|
||||
},
|
||||
}))
|
||||
|
||||
jest.mock('#/env', () => ({
|
||||
vi.mock('#/env', () => ({
|
||||
METRICS_API_HOST: 'https://test.metrics.api',
|
||||
IS_WEB: false,
|
||||
}))
|
||||
@@ -31,13 +33,13 @@ type TestEvents = {
|
||||
}
|
||||
|
||||
describe('MetricsClient', () => {
|
||||
let fetchMock: jest.Mock
|
||||
let fetchMock: Mock
|
||||
let fetchRequests: {body: any}[]
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers({advanceTimers: true})
|
||||
vi.useFakeTimers({shouldAdvanceTime: true})
|
||||
fetchRequests = []
|
||||
fetchMock = jest.fn().mockImplementation(async (_url, options) => {
|
||||
fetchMock = vi.fn().mockImplementation(async (_url, options) => {
|
||||
const body = JSON.parse(options.body)
|
||||
fetchRequests.push({body})
|
||||
return {ok: true, status: 200}
|
||||
@@ -46,8 +48,8 @@ describe('MetricsClient', () => {
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers()
|
||||
jest.clearAllMocks()
|
||||
vi.useRealTimers()
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('flushes events on interval', async () => {
|
||||
@@ -58,7 +60,7 @@ describe('MetricsClient', () => {
|
||||
expect(fetchRequests).toHaveLength(0)
|
||||
|
||||
// Advance past the 10 second interval
|
||||
await jest.advanceTimersByTimeAsync(10_000)
|
||||
await vi.advanceTimersByTimeAsync(10_000)
|
||||
|
||||
expect(fetchRequests).toHaveLength(1)
|
||||
expect(fetchRequests[0].body.events).toHaveLength(2)
|
||||
@@ -81,7 +83,7 @@ describe('MetricsClient', () => {
|
||||
client.track('click', {button: 'btn-trigger'})
|
||||
|
||||
// Allow microtasks to run
|
||||
await jest.advanceTimersByTimeAsync(0)
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
|
||||
expect(fetchRequests).toHaveLength(1)
|
||||
expect(fetchRequests[0].body.events).toHaveLength(6)
|
||||
@@ -112,14 +114,14 @@ describe('MetricsClient', () => {
|
||||
client.track('click', {button: 'submit'})
|
||||
|
||||
// Trigger flush via interval
|
||||
await jest.advanceTimersByTimeAsync(10_000)
|
||||
await vi.advanceTimersByTimeAsync(10_000)
|
||||
|
||||
expect(requestCount).toBe(1)
|
||||
expect(fetchRequests).toHaveLength(0)
|
||||
|
||||
// Simulate app coming to foreground to trigger retry
|
||||
appStateCallback('active')
|
||||
await jest.advanceTimersByTimeAsync(0)
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
|
||||
expect(requestCount).toBe(2)
|
||||
expect(fetchRequests).toHaveLength(1)
|
||||
@@ -144,19 +146,19 @@ describe('MetricsClient', () => {
|
||||
client.track('click', {button: 'submit'})
|
||||
|
||||
// First flush fails
|
||||
await jest.advanceTimersByTimeAsync(10_000)
|
||||
await vi.advanceTimersByTimeAsync(10_000)
|
||||
|
||||
expect(requestCount).toBe(1)
|
||||
|
||||
// Retry also fails
|
||||
appStateCallback('active')
|
||||
await jest.advanceTimersByTimeAsync(0)
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
|
||||
expect(requestCount).toBe(2)
|
||||
|
||||
// Another foreground event should not retry again (events are dropped)
|
||||
appStateCallback('active')
|
||||
await jest.advanceTimersByTimeAsync(0)
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
|
||||
expect(requestCount).toBe(2) // No additional requests
|
||||
})
|
||||
@@ -169,7 +171,7 @@ describe('MetricsClient', () => {
|
||||
|
||||
// Simulate app going to background
|
||||
appStateCallback('background')
|
||||
await jest.advanceTimersByTimeAsync(0)
|
||||
await vi.advanceTimersByTimeAsync(0)
|
||||
|
||||
expect(fetchRequests).toHaveLength(1)
|
||||
})
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import {describe, test} from '@jest/globals'
|
||||
import {describe, expect, test, vi} from 'vitest'
|
||||
|
||||
import {
|
||||
computeCompletedState,
|
||||
syncCompletedState,
|
||||
} from '#/components/PolicyUpdateOverlay/usePolicyUpdateState'
|
||||
|
||||
jest.mock('../../../state/queries/nuxs')
|
||||
vi.mock('../../../state/queries/nuxs')
|
||||
|
||||
describe('computeCompletedState', () => {
|
||||
test(`initial state`, () => {
|
||||
@@ -67,8 +67,8 @@ describe('computeCompletedState', () => {
|
||||
describe('syncCompletedState', () => {
|
||||
describe('!nuxIsReady', () => {
|
||||
test(`!completedForDevice, no-op`, () => {
|
||||
const save = jest.fn()
|
||||
const setCompletedForDevice = jest.fn()
|
||||
const save = vi.fn()
|
||||
const setCompletedForDevice = vi.fn()
|
||||
syncCompletedState({
|
||||
nuxIsReady: false,
|
||||
nuxIsCompleted: false,
|
||||
@@ -83,8 +83,8 @@ describe('syncCompletedState', () => {
|
||||
})
|
||||
|
||||
test(`completedForDevice, no-op`, () => {
|
||||
const save = jest.fn()
|
||||
const setCompletedForDevice = jest.fn()
|
||||
const save = vi.fn()
|
||||
const setCompletedForDevice = vi.fn()
|
||||
syncCompletedState({
|
||||
nuxIsReady: false,
|
||||
nuxIsCompleted: false,
|
||||
@@ -103,8 +103,8 @@ describe('syncCompletedState', () => {
|
||||
describe(`!nuxIsCompleted`, () => {
|
||||
describe(`!nuxIsOptimisticallyCompleted`, () => {
|
||||
test(`!completedForDevice, no-op`, () => {
|
||||
const save = jest.fn()
|
||||
const setCompletedForDevice = jest.fn()
|
||||
const save = vi.fn()
|
||||
const setCompletedForDevice = vi.fn()
|
||||
syncCompletedState({
|
||||
nuxIsReady: true,
|
||||
nuxIsCompleted: false,
|
||||
@@ -119,8 +119,8 @@ describe('syncCompletedState', () => {
|
||||
})
|
||||
|
||||
test(`completedForDevice, syncs to server`, () => {
|
||||
const save = jest.fn()
|
||||
const setCompletedForDevice = jest.fn()
|
||||
const save = vi.fn()
|
||||
const setCompletedForDevice = vi.fn()
|
||||
syncCompletedState({
|
||||
nuxIsReady: true,
|
||||
nuxIsCompleted: false,
|
||||
@@ -141,8 +141,8 @@ describe('syncCompletedState', () => {
|
||||
*/
|
||||
describe(`nuxIsOptimisticallyCompleted`, () => {
|
||||
test(`completedForDevice, no-op`, () => {
|
||||
const save = jest.fn()
|
||||
const setCompletedForDevice = jest.fn()
|
||||
const save = vi.fn()
|
||||
const setCompletedForDevice = vi.fn()
|
||||
syncCompletedState({
|
||||
nuxIsReady: true,
|
||||
nuxIsCompleted: false,
|
||||
@@ -160,8 +160,8 @@ describe('syncCompletedState', () => {
|
||||
|
||||
describe(`nuxIsCompleted`, () => {
|
||||
test(`!completedForDevice, syncs to device`, () => {
|
||||
const save = jest.fn()
|
||||
const setCompletedForDevice = jest.fn()
|
||||
const save = vi.fn()
|
||||
const setCompletedForDevice = vi.fn()
|
||||
syncCompletedState({
|
||||
nuxIsReady: true,
|
||||
nuxIsCompleted: true,
|
||||
@@ -176,8 +176,8 @@ describe('syncCompletedState', () => {
|
||||
})
|
||||
|
||||
test(`completedForDevice, no-op`, () => {
|
||||
const save = jest.fn()
|
||||
const setCompletedForDevice = jest.fn()
|
||||
const save = vi.fn()
|
||||
const setCompletedForDevice = vi.fn()
|
||||
syncCompletedState({
|
||||
nuxIsReady: true,
|
||||
nuxIsCompleted: true,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {describe, expect, it} from '@jest/globals'
|
||||
import {describe, expect, it} from 'vitest'
|
||||
|
||||
import {parseLinkingUrl} from '../parseLinkingUrl'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {beforeEach, describe, expect, it, jest} from '@jest/globals'
|
||||
import {beforeEach, describe, expect, it, vi} from 'vitest'
|
||||
|
||||
jest.mock('@bsky.app/react-native-mmkv', () => ({
|
||||
vi.mock('@bsky.app/react-native-mmkv', () => ({
|
||||
MMKV: class MMKVMock {
|
||||
_store = new Map<string, string>()
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {describe, expect, it} from '@jest/globals'
|
||||
import {describe, expect, it} from 'vitest'
|
||||
import {addDays, subDays, subHours, subMinutes, subSeconds} from 'date-fns'
|
||||
|
||||
import {dateDiff} from '../useTimeAgo'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {expect, test} from '@jest/globals'
|
||||
import {expect, test} from 'vitest'
|
||||
|
||||
import {sanitizeAppLanguageSetting} from '#/locale/helpers'
|
||||
import {AppLanguage} from '#/locale/languages'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {expect, test} from '@jest/globals'
|
||||
import {expect, test} from 'vitest'
|
||||
|
||||
import {add, type ConsoleTransportEntry, getEntries} from '#/logger/logDump'
|
||||
import {LogContext, LogLevel} from '#/logger/types'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {beforeAll, describe, expect, jest, test} from '@jest/globals'
|
||||
import {beforeAll, describe, expect, test, vi} from 'vitest'
|
||||
import * as Sentry from '@sentry/react-native'
|
||||
import {nanoid} from 'nanoid/non-secure'
|
||||
|
||||
@@ -6,14 +6,14 @@ import {Logger} from '#/logger'
|
||||
import {sentryTransport} from '#/logger/transports/sentry'
|
||||
import {LogLevel} from '#/logger/types'
|
||||
|
||||
jest.mock('@sentry/react-native', () => ({
|
||||
addBreadcrumb: jest.fn(),
|
||||
captureException: jest.fn(),
|
||||
captureMessage: jest.fn(),
|
||||
vi.mock('@sentry/react-native', () => ({
|
||||
addBreadcrumb: vi.fn(),
|
||||
captureException: vi.fn(),
|
||||
captureMessage: vi.fn(),
|
||||
}))
|
||||
|
||||
beforeAll(() => {
|
||||
jest.useFakeTimers()
|
||||
vi.useFakeTimers()
|
||||
})
|
||||
|
||||
describe('general functionality', () => {
|
||||
@@ -41,7 +41,7 @@ describe('general functionality', () => {
|
||||
const timestamp = Date.now()
|
||||
const logger = new Logger({})
|
||||
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
|
||||
logger.addTransport(mockTransport)
|
||||
|
||||
@@ -63,7 +63,7 @@ describe('general functionality', () => {
|
||||
metadata: {bar: true},
|
||||
})
|
||||
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
|
||||
logger.addTransport(mockTransport)
|
||||
|
||||
@@ -83,7 +83,7 @@ describe('general functionality', () => {
|
||||
const timestamp = Date.now()
|
||||
const logger = new Logger({})
|
||||
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
|
||||
const remove = logger.addTransport(mockTransport)
|
||||
|
||||
@@ -181,7 +181,7 @@ describe('general functionality', () => {
|
||||
level: 'log',
|
||||
timestamp: sentryTimestamp,
|
||||
})
|
||||
jest.runAllTimers()
|
||||
vi.runAllTimers()
|
||||
expect(Sentry.captureMessage).toHaveBeenCalledWith(message, {
|
||||
level: 'log',
|
||||
tags: {category: 'logger'},
|
||||
@@ -203,7 +203,7 @@ describe('general functionality', () => {
|
||||
level: 'warning',
|
||||
timestamp: sentryTimestamp,
|
||||
})
|
||||
jest.runAllTimers()
|
||||
vi.runAllTimers()
|
||||
expect(Sentry.captureMessage).toHaveBeenCalledWith(message, {
|
||||
level: 'warning',
|
||||
tags: {category: 'logger'},
|
||||
@@ -262,7 +262,7 @@ describe('general functionality', () => {
|
||||
test('add/remove transport', () => {
|
||||
const timestamp = Date.now()
|
||||
const logger = new Logger({})
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
|
||||
const remove = logger.addTransport(mockTransport)
|
||||
|
||||
@@ -286,7 +286,7 @@ describe('general functionality', () => {
|
||||
|
||||
describe('create', () => {
|
||||
test('create', () => {
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
const timestamp = Date.now()
|
||||
const message = nanoid()
|
||||
const logger = Logger.create(Logger.Context.Default)
|
||||
@@ -306,7 +306,7 @@ describe('create', () => {
|
||||
|
||||
describe('debug contexts', () => {
|
||||
test('specific', () => {
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
const timestamp = Date.now()
|
||||
const message = nanoid()
|
||||
const logger = new Logger({
|
||||
@@ -328,7 +328,7 @@ describe('debug contexts', () => {
|
||||
})
|
||||
|
||||
test('namespaced', () => {
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
const timestamp = Date.now()
|
||||
const message = nanoid()
|
||||
const logger = new Logger({
|
||||
@@ -351,7 +351,7 @@ describe('debug contexts', () => {
|
||||
})
|
||||
|
||||
test('ignores inactive', () => {
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
const timestamp = Date.now()
|
||||
const message = nanoid()
|
||||
const logger = new Logger({
|
||||
@@ -380,7 +380,7 @@ describe('supports levels', () => {
|
||||
level: LogLevel.Debug,
|
||||
})
|
||||
const message = nanoid()
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
|
||||
logger.addTransport(mockTransport)
|
||||
|
||||
@@ -428,7 +428,7 @@ describe('supports levels', () => {
|
||||
level: LogLevel.Info,
|
||||
})
|
||||
const message = nanoid()
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
|
||||
logger.addTransport(mockTransport)
|
||||
|
||||
@@ -451,7 +451,7 @@ describe('supports levels', () => {
|
||||
level: LogLevel.Warn,
|
||||
})
|
||||
const message = nanoid()
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
|
||||
logger.addTransport(mockTransport)
|
||||
|
||||
@@ -477,7 +477,7 @@ describe('supports levels', () => {
|
||||
level: LogLevel.Error,
|
||||
})
|
||||
const message = nanoid()
|
||||
const mockTransport = jest.fn()
|
||||
const mockTransport = vi.fn()
|
||||
|
||||
logger.addTransport(mockTransport)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {describe, expect, it} from '@jest/globals'
|
||||
import {describe, expect, it} from 'vitest'
|
||||
|
||||
import {parseSearchQuery} from '#/screens/Search/utils'
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {describe, it} from '@jest/globals'
|
||||
import {describe, it} from 'vitest'
|
||||
|
||||
describe(`#/state/messages/convo`, () => {
|
||||
describe(`init`, () => {
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import {jest} from '@jest/globals'
|
||||
import {vi} from 'vitest'
|
||||
|
||||
export {Nux} from '#/state/queries/nuxs/definitions'
|
||||
|
||||
export const useNuxs = jest.fn(() => {
|
||||
export const useNuxs = vi.fn(() => {
|
||||
return {
|
||||
nuxs: undefined,
|
||||
status: 'loading' as const,
|
||||
}
|
||||
})
|
||||
|
||||
export const useNux = jest.fn((id: string) => {
|
||||
export const useNux = vi.fn((id: string) => {
|
||||
return {
|
||||
nux: undefined,
|
||||
status: 'loading' as const,
|
||||
}
|
||||
})
|
||||
|
||||
export const useSaveNux = jest.fn(() => {
|
||||
export const useSaveNux = vi.fn(() => {
|
||||
return {}
|
||||
})
|
||||
|
||||
export const useResetNuxs = jest.fn(() => {
|
||||
export const useResetNuxs = vi.fn(() => {
|
||||
return {}
|
||||
})
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import {BskyAgent} from '@atproto/api'
|
||||
import {describe, expect, it, jest} from '@jest/globals'
|
||||
import {describe, expect, it, vi} from 'vitest'
|
||||
|
||||
import {agentToSessionAccountOrThrow} from '../agent'
|
||||
import {type Action, getInitialState, reducer, type State} from '../reducer'
|
||||
|
||||
jest.mock('jwt-decode', () => ({
|
||||
vi.mock('jwt-decode', () => ({
|
||||
jwtDecode(_token: string) {
|
||||
return {}
|
||||
},
|
||||
}))
|
||||
|
||||
jest.mock('../../birthdate')
|
||||
jest.mock('../../../ageAssurance/data')
|
||||
jest.mock('../../../ageAssurance/state', () => ({
|
||||
vi.mock('../../birthdate')
|
||||
vi.mock('../../../ageAssurance/data')
|
||||
vi.mock('../../../ageAssurance/state', () => ({
|
||||
getAndComputeAgeAssuranceState: () => ({}),
|
||||
}))
|
||||
jest.mock('#/lib/notifications/notifications', () => ({
|
||||
vi.mock('#/lib/notifications/notifications', () => ({
|
||||
unregisterPushToken(_agents: BskyAgent[]) {
|
||||
return Promise.resolve()
|
||||
},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {beforeEach, expect, jest, test} from '@jest/globals'
|
||||
import {beforeEach, expect, test, vi} from 'vitest'
|
||||
|
||||
import {Storage} from '#/storage'
|
||||
|
||||
jest.mock('@bsky.app/react-native-mmkv', () => ({
|
||||
vi.mock('@bsky.app/react-native-mmkv', () => ({
|
||||
MMKV: class MMKVMock {
|
||||
_store = new Map()
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
"jsx": "react-jsx",
|
||||
"module": "esnext",
|
||||
"lib": ["dom", "esnext"],
|
||||
"types": ["node", "jest"],
|
||||
"types": ["node"],
|
||||
"paths": {
|
||||
"#/*": ["./src/*"],
|
||||
"crypto": ["./src/platform/crypto.ts"],
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
import {fileURLToPath} from 'node:url'
|
||||
|
||||
import {lingui} from '@lingui/vite-plugin'
|
||||
import {defineConfig} from 'vitest/config'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [lingui()],
|
||||
define: {
|
||||
__DEV__: 'true',
|
||||
},
|
||||
resolve: {
|
||||
tsconfigPaths: true,
|
||||
alias: {
|
||||
crypto: fileURLToPath(new URL('./src/platform/crypto.ts', import.meta.url)),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
globals: false,
|
||||
environment: 'node',
|
||||
setupFiles: ['./vitest/setup.ts'],
|
||||
include: [
|
||||
'__tests__/**/*.test.{ts,tsx,js,jsx}',
|
||||
'src/**/*.test.{ts,tsx}',
|
||||
'src/**/__tests__/**/*.{ts,tsx}',
|
||||
'eslint/**/*.test.{js,ts}',
|
||||
],
|
||||
exclude: [
|
||||
'**/node_modules/**',
|
||||
'**/__mocks__/**',
|
||||
'__e2e__/**',
|
||||
'bskylink/**',
|
||||
'bskyembed/**',
|
||||
],
|
||||
testTimeout: 20000,
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
exclude: [
|
||||
'node_modules/**',
|
||||
'src/platform/**',
|
||||
'src/third-party/**',
|
||||
'src/view/com/util/**',
|
||||
'src/state/lib/**',
|
||||
'__tests__/test-utils.js',
|
||||
],
|
||||
},
|
||||
server: {
|
||||
deps: {
|
||||
inline: [
|
||||
/^react-native($|\/)/,
|
||||
/^@react-native($|\/)/,
|
||||
/^expo($|-|\/)/,
|
||||
/^@expo($|\/)/,
|
||||
/^@react-navigation($|\/)/,
|
||||
/^react-native-svg($|\/)/,
|
||||
/^nanoid($|\/)/,
|
||||
/^@sentry($|\/)/,
|
||||
/^sentry-expo($|\/)/,
|
||||
/^bcp-47-match($|\/)/,
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
import {EventEmitter} from 'node:events'
|
||||
|
||||
import {vi} from 'vitest'
|
||||
|
||||
// react-native ships Flow syntax in its index.js entry point, which Vitest's
|
||||
// rolldown parser cannot handle. None of the tests exercise actual RN runtime
|
||||
// behavior, so stub the whole module to satisfy transitive imports.
|
||||
vi.mock('react-native', () => ({
|
||||
Platform: {OS: 'ios', select: (obj: any) => obj.ios ?? obj.default},
|
||||
StyleSheet: {create: (s: any) => s, flatten: (s: any) => s, hairlineWidth: 1},
|
||||
View: 'View',
|
||||
Text: 'Text',
|
||||
ScrollView: 'ScrollView',
|
||||
FlatList: 'FlatList',
|
||||
TextInput: 'TextInput',
|
||||
Modal: 'Modal',
|
||||
Image: 'Image',
|
||||
Pressable: 'Pressable',
|
||||
TouchableOpacity: 'TouchableOpacity',
|
||||
TouchableWithoutFeedback: 'TouchableWithoutFeedback',
|
||||
NativeModules: {},
|
||||
NativeEventEmitter: EventEmitter,
|
||||
AppState: {addEventListener: () => ({remove: () => {}}), currentState: 'active'},
|
||||
Linking: {openURL: vi.fn(), canOpenURL: vi.fn().mockResolvedValue(true)},
|
||||
Dimensions: {get: () => ({width: 375, height: 812}), addEventListener: () => ({remove: () => {}})},
|
||||
PixelRatio: {get: () => 2, getFontScale: () => 1},
|
||||
Keyboard: {addListener: () => ({remove: () => {}}), dismiss: () => {}},
|
||||
InteractionManager: {runAfterInteractions: (fn: () => void) => fn()},
|
||||
Animated: {View: 'AnimatedView', Value: class {}, timing: () => ({start: () => {}})},
|
||||
UIManager: {},
|
||||
}))
|
||||
|
||||
vi.mock('@react-native-async-storage/async-storage', () =>
|
||||
require('@react-native-async-storage/async-storage/jest/async-storage-mock'),
|
||||
)
|
||||
|
||||
vi.mock('react-native/Libraries/EventEmitter/NativeEventEmitter', () => ({
|
||||
__esModule: true,
|
||||
default: EventEmitter,
|
||||
}))
|
||||
|
||||
vi.mock('@fortawesome/react-native-fontawesome', () => ({
|
||||
FontAwesomeIcon: '',
|
||||
}))
|
||||
|
||||
vi.mock('react-native-safe-area-context', () => {
|
||||
const inset = {top: 0, right: 0, bottom: 0, left: 0}
|
||||
return {
|
||||
SafeAreaProvider: vi.fn().mockImplementation(({children}) => children),
|
||||
SafeAreaConsumer: vi
|
||||
.fn()
|
||||
.mockImplementation(({children}) => children(inset)),
|
||||
useSafeAreaInsets: vi.fn().mockImplementation(() => inset),
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('expo-file-system/legacy', () => ({
|
||||
getInfoAsync: vi.fn().mockResolvedValue({exists: true, size: 100}),
|
||||
deleteAsync: vi.fn(),
|
||||
moveAsync: vi.fn().mockResolvedValue(undefined),
|
||||
createDownloadResumable: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('expo-image-manipulator', () => ({
|
||||
manipulateAsync: vi.fn().mockResolvedValue({
|
||||
uri: 'file://resized-image',
|
||||
}),
|
||||
SaveFormat: {
|
||||
JPEG: 'jpeg',
|
||||
WEBP: 'webp',
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('expo-camera', () => ({
|
||||
Camera: {
|
||||
useCameraPermissions: vi.fn(() => [true]),
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('expo-media-library', () => ({
|
||||
__esModule: true,
|
||||
default: vi.fn(),
|
||||
usePermissions: vi.fn(() => [true]),
|
||||
}))
|
||||
|
||||
vi.mock('@bsky.app/expo-guess-language', () => ({
|
||||
guessLanguageSync: vi
|
||||
.fn()
|
||||
.mockReturnValue([{language: 'en', confidence: 1}]),
|
||||
guessLanguageAsync: vi
|
||||
.fn()
|
||||
.mockResolvedValue([{language: 'en', confidence: 1}]),
|
||||
}))
|
||||
|
||||
vi.mock('sentry-expo', () => ({
|
||||
init: () => vi.fn(),
|
||||
Native: {
|
||||
ReactNativeTracing: vi.fn().mockImplementation(() => ({
|
||||
start: vi.fn(),
|
||||
stop: vi.fn(),
|
||||
})),
|
||||
ReactNavigationInstrumentation: vi.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('crypto', () => ({}))
|
||||
|
||||
vi.mock('expo-application', () => ({
|
||||
nativeApplicationVersion: '1.0.0',
|
||||
nativeBuildVersion: '1',
|
||||
}))
|
||||
|
||||
vi.mock('expo-modules-core', () => ({
|
||||
requireNativeModule: vi.fn().mockImplementation(moduleName => {
|
||||
if (moduleName === 'ExpoPlatformInfo') {
|
||||
return {
|
||||
getIsReducedMotionEnabled: () => false,
|
||||
}
|
||||
}
|
||||
if (moduleName === 'BottomSheet') {
|
||||
return {
|
||||
dismissAll: () => {},
|
||||
}
|
||||
}
|
||||
}),
|
||||
requireNativeViewManager: vi.fn().mockImplementation(_ => {
|
||||
return () => null
|
||||
}),
|
||||
createPermissionHook: () => () => [true],
|
||||
}))
|
||||
|
||||
vi.mock('expo-localization', () => ({
|
||||
getLocales: () => [],
|
||||
}))
|
||||
Reference in New Issue
Block a user