Files
paseo/packages/app/vitest.config.ts
T
paseo-bot[bot]andIvan Malison b412374f0c Run React tests when the shell uses NODE_ENV=production (#6572)
* fix(tests): run React tests from production shells

Vitest preserves an inherited NODE_ENV, selecting React without its test APIs. Pin the environment before dependency resolution and worker startup in both test entry points.

Co-authored-by: Ivan Malison <IvanMalison@gmail.com>

* test(app): expect zero edits for a pure staged rename

The rename patch correction on main preserves unchanged content. Keep the discard journey intact and update its obsolete added-line assertion.

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Ivan Malison <IvanMalison@gmail.com>
2026-10-11 11:52:50 +02:00

209 lines
7.3 KiB
TypeScript

import { defineConfig, configDefaults } from "vitest/config";
import { playwright } from "@vitest/browser-playwright";
import path from "path";
import fs from "fs";
// Set this before Vite resolves dependencies and Vitest starts its workers.
process.env.NODE_ENV = "test";
const appNodeModules = path.resolve(__dirname, "node_modules");
const rootNodeModules = path.resolve(__dirname, "../../node_modules");
const resolvePackageEntry = (packageName: string) => {
const appPackagePath = path.resolve(appNodeModules, packageName);
return fs.existsSync(appPackagePath)
? appPackagePath
: path.resolve(rootNodeModules, packageName);
};
export default defineConfig({
test: {
environment: "node",
exclude: [...configDefaults.exclude, "e2e/**"],
projects: [
{
extends: true,
test: {
name: "unit",
environment: "node",
include: [
"src/**/*.{test,spec}.{ts,tsx}",
"native-release-version.test.ts",
"app.config.test.ts",
"vitest-environment.test.ts",
],
setupFiles: [path.resolve(__dirname, "vitest.setup.ts")],
exclude: [...configDefaults.exclude, "e2e/**", "src/**/*.browser.{test,spec}.{ts,tsx}"],
},
},
{
extends: true,
test: {
name: "browser",
fileParallelism: false,
include: ["src/**/*.browser.{test,spec}.{ts,tsx}"],
browser: {
enabled: true,
provider: playwright(),
headless: true,
connectTimeout: 180_000,
instances: [{ browser: "chromium" }],
screenshotDirectory: ".vitest-screenshots",
},
globalSetup: path.resolve(__dirname, "src/runtime/websocket-test-global-setup.ts"),
},
},
],
/**
* Expo pulls in native tooling (xcode, etc.) that executes files relying on `process.send`.
* Vitest's default worker pool uses worker_threads, which intentionally stub that API and
* immediately throw `Unexpected call to process.send`. Running the suite in forked processes
* keeps `process.send` intact so the app tests can boot before hitting the intentional failures.
*/
pool: "forks",
maxWorkers: 2,
server: {
deps: {
fallbackCJS: true,
inline: [
"zustand",
"@tanstack/react-query",
"react-native-web",
"react-native-gesture-handler",
"react-native-keyboard-controller",
],
},
},
},
// Reanimated and gesture-handler pick platform files by extension
// (e.g. `GestureHandlerRootView.web.js`). Vite's optimizer does not apply `resolve.extensions`,
// so it scans the native files and dies on imports react-native-web has no answer for.
// Unbundled, the same imports go through the resolver below and land on the web files.
optimizeDeps: {
// Bundle the CJS dependencies of the excluded gesture-handler package for the browser.
include: [
"react/jsx-runtime",
"react-native-gesture-handler > hoist-non-react-statics",
"react-native-gesture-handler > invariant",
],
exclude: [
"react-native-reanimated",
"react-native-gesture-handler",
"react-native-keyboard-controller",
],
},
// The globals a React Native bundler defines, which esbuild is no longer there to supply for
// the package excluded above.
define: {
"process.env.JEST_WORKER_ID": "undefined",
__DEV__: "false",
global: "globalThis",
},
resolve: {
extensions: [
".web.mjs",
".web.js",
".web.mts",
".web.ts",
".web.jsx",
".web.tsx",
".mjs",
".js",
".mts",
".ts",
".jsx",
".tsx",
".json",
],
alias: [
{
find: /^@getpaseo\/relay\/e2ee$/,
replacement: path.resolve(__dirname, "../relay/src/e2ee.ts"),
},
{
find: /^@getpaseo\/relay$/,
replacement: path.resolve(__dirname, "../relay/src/index.ts"),
},
{ find: "@", replacement: path.resolve(__dirname, "src") },
// Keep keyboard-controller's imports in Vite so native aliases and platform extensions apply.
{
find: /^react-native-keyboard-controller$/,
replacement: path.resolve(
resolvePackageEntry("react-native-keyboard-controller"),
"lib/module/index.js",
),
},
// The CJS entry bypasses Vite's React Native alias and web-extension resolution.
{
find: /^react-native-gesture-handler$/,
replacement: path.resolve(
rootNodeModules,
"react-native-gesture-handler/lib/module/index.js",
),
},
// Must precede the `react-native` alias: a string `find` matches by prefix, so this subpath
// would otherwise resolve inside a react-native-web *file* and break the dependency scan.
// Reanimated only imports it on the native path, which no test takes.
{
find: /^react-native\/Libraries\/Renderer\/shims\/ReactFabric$/,
replacement: path.resolve(__dirname, "test-stubs/react-native-fabric-shim.ts"),
},
// Point to the ESM build so Vite can transform its imports and apply the
// react alias below (the CJS build uses require('react') which bypasses
// Vite alias resolution).
{
find: "react-native",
replacement: path.resolve(rootNodeModules, "react-native-web/dist/index.js"),
},
{ find: "react", replacement: resolvePackageEntry("react") },
{
find: "react-dom",
replacement: resolvePackageEntry("react-dom"),
},
{
find: /^@xterm\/addon-ligatures\/lib\/addon-ligatures\.mjs$/,
replacement: path.resolve(__dirname, "test-stubs/xterm-addon-ligatures.ts"),
},
{
find: /^@xterm\/addon-ligatures$/,
replacement: path.resolve(__dirname, "test-stubs/xterm-addon-ligatures.ts"),
},
{
find: /^react-native-unistyles$/,
replacement: path.resolve(__dirname, "test-stubs/react-native-unistyles.ts"),
},
{
find: /^react-native-svg$/,
replacement: path.resolve(__dirname, "test-stubs/react-native-svg.ts"),
},
// Both ship untranspiled Flow and fail to parse on import, which takes out any test that
// mounts a menu surface.
{
find: /^react-native-safe-area-context$/,
replacement: path.resolve(__dirname, "test-stubs/react-native-safe-area-context.ts"),
},
{
find: /^@gorhom\/bottom-sheet$/,
replacement: path.resolve(__dirname, "test-stubs/gorhom-bottom-sheet.ts"),
},
{
find: /^react-native-reanimated\/scripts\/validate-worklets-version$/,
replacement: path.resolve(__dirname, "test-stubs/reanimated-validate-worklets-version.ts"),
},
{
find: /^expo-linking$/,
replacement: path.resolve(__dirname, "test-stubs/expo-linking.ts"),
},
// No Node implementation: every call on the real module rejects, so a test
// touching a persisted store drowns in unhandled rejections.
{
find: /^@react-native-async-storage\/async-storage$/,
replacement: path.resolve(__dirname, "test-stubs/async-storage.ts"),
},
{
find: /^lucide-react-native$/,
replacement: path.resolve(__dirname, "test-stubs/lucide-react-native.ts"),
},
],
},
});