156 lines
5.3 KiB
TypeScript
156 lines
5.3 KiB
TypeScript
import {fileURLToPath} from 'node:url'
|
|
|
|
import babel from 'vite-plugin-babel'
|
|
import {defineConfig} from 'vitest/config'
|
|
|
|
const r = (p: string) => fileURLToPath(new URL(p, import.meta.url))
|
|
|
|
export default defineConfig({
|
|
plugins: [
|
|
/*
|
|
* esbuild handles TS/JSX transpilation; babel runs only for the lingui
|
|
* macro, which must be expanded in every .ts/.tsx file that uses it (not
|
|
* just JSX files). We deliberately omit react-compiler, reanimated/plugin,
|
|
* and react-native-dotenv - those matter for render semantics and
|
|
* native/build output, none of which our tests exercise.
|
|
*/
|
|
babel({
|
|
include: /\.[jt]sx?$/,
|
|
exclude: /node_modules/,
|
|
babelConfig: {
|
|
babelrc: false,
|
|
configFile: false,
|
|
/*
|
|
* The plugin runs with enforce: 'pre', so babel receives raw
|
|
* TypeScript before esbuild strips types - it needs the TS preset to
|
|
* parse it. preset-typescript auto-enables JSX for .tsx filenames.
|
|
*/
|
|
/*
|
|
* Default onlyRemoveTypeImports: false so babel elides imports whose
|
|
* specifiers are all types (e.g. `import {type X} from '...'`).
|
|
* Otherwise such imports survive as side-effect imports and drag whole
|
|
* runtime module graphs (and their native deps) into tests.
|
|
*/
|
|
presets: ['@babel/preset-typescript'],
|
|
plugins: [
|
|
'@lingui/babel-plugin-lingui-macro',
|
|
'@babel/plugin-transform-class-static-block',
|
|
],
|
|
},
|
|
}),
|
|
],
|
|
resolve: {
|
|
tsconfigPaths: true,
|
|
/*
|
|
* Mirror Metro's platform-specific resolution so Component.native.ts /
|
|
* Component.ios.ts win over Component.ts (matching the jest-expo/ios
|
|
* preset, which resolves ios then native). Without this, files like
|
|
* PlatformInfo/index.ts (which throws NotImplementedError) load instead of
|
|
* index.native.ts (which uses the stubbed requireNativeModule).
|
|
*/
|
|
extensions: [
|
|
'.ios.ts',
|
|
'.ios.tsx',
|
|
'.ios.js',
|
|
'.ios.jsx',
|
|
'.native.ts',
|
|
'.native.tsx',
|
|
'.native.js',
|
|
'.native.jsx',
|
|
'.ts',
|
|
'.tsx',
|
|
'.mjs',
|
|
'.js',
|
|
'.jsx',
|
|
'.json',
|
|
],
|
|
alias: [
|
|
/*
|
|
* react-native's real entry is Flow-typed and boots a native runtime.
|
|
* Redirect it (and deep Libraries/* subpaths some packages import) to a
|
|
* small stub. Aliasing at resolution time is more robust than a
|
|
* setup-file vi.mock, which doesn't reach imports from externalized CJS
|
|
* deps like @bsky.app/react-native-mmkv.
|
|
*/
|
|
{find: /^react-native$/, replacement: r('./vitest/react-native-stub.ts')},
|
|
{
|
|
find: /^react-native\/.*$/,
|
|
replacement: r('./vitest/react-native-stub.ts'),
|
|
},
|
|
|
|
/*
|
|
* Native MMKV module - binds to a native lib and imports react-native.
|
|
* Stubbed so transitive importers (#/storage) load. Tests that exercise
|
|
* storage logic still vi.mock this with their own in-memory impl, which
|
|
* takes precedence over the alias.
|
|
*/
|
|
{
|
|
find: /^@bsky\.app\/react-native-mmkv$/,
|
|
replacement: r('./vitest/mmkv-stub.ts'),
|
|
},
|
|
|
|
/*
|
|
* @sentry/react-native is CJS and requires react-native internally.
|
|
* Stubbed so modules that pull it in via #/logger load. logger.test.ts
|
|
* still vi.mocks it directly to assert on calls.
|
|
*/
|
|
{
|
|
find: /^@sentry\/react-native$/,
|
|
replacement: r('./vitest/sentry-stub.ts'),
|
|
},
|
|
|
|
/*
|
|
* expo-application pulls in the `expo` package's native winter runtime,
|
|
* which does bare CJS requires that don't resolve under Vitest.
|
|
*/
|
|
{
|
|
find: /^expo-application$/,
|
|
replacement: r('./vitest/expo-application-stub.ts'),
|
|
},
|
|
|
|
/*
|
|
* The bare `expo` package's entry runs the winter runtime side-effect on
|
|
* import (bare CJS requires that don't resolve under node). Stub it to
|
|
* the named exports test-reachable code uses.
|
|
*/
|
|
{find: /^expo$/, replacement: r('./vitest/expo-stub.ts')},
|
|
|
|
/*
|
|
* async-storage references `window` at module load, undefined under
|
|
* node. Stubbed with an in-memory implementation.
|
|
*/
|
|
{
|
|
find: /^@react-native-async-storage\/async-storage$/,
|
|
replacement: r('./vitest/async-storage-stub.ts'),
|
|
},
|
|
],
|
|
},
|
|
/*
|
|
* Match jest's effective environment: under jest __DEV__ was true but
|
|
* JEST_WORKER_ID was set, so dev-only branches guarded by
|
|
* `__DEV__ && !process.env.JEST_WORKER_ID` took the production path. Setting
|
|
* __DEV__ to false reproduces that for the equivalent branches in Vitest.
|
|
*/
|
|
define: {__DEV__: 'false'},
|
|
test: {
|
|
globals: true,
|
|
environment: 'node',
|
|
setupFiles: ['./vitest/vitestSetup.ts'],
|
|
/*
|
|
* Only the app's own tests, which live under __tests__/ and src/. The
|
|
* sibling packages (bskyembed, bskyogcard, dev-env, bskylink) have their
|
|
* own runners and must not be swept up.
|
|
*/
|
|
include: ['__tests__/**/*.test.{ts,tsx}', 'src/**/*.test.{ts,tsx}'],
|
|
exclude: [
|
|
'**/node_modules/**',
|
|
// Stale duplicate test trees live here - must not be picked up.
|
|
'.claude/worktrees/**',
|
|
'__e2e__/**',
|
|
'**/__mocks__/**',
|
|
],
|
|
reporters: process.env.CI ? ['default', 'junit'] : ['default'],
|
|
outputFile: {junit: './junit.xml'},
|
|
},
|
|
})
|