Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/wojtekmaj/vitest-react-native. Run React Native unit and component tests with Vitest
Something went wrong. Try again.
3.1 kB · 105 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106import { dirname, resolve } from 'node:path';import { transformSync } from '@babel/core';
import type { PluginObject } from '@babel/core';
const nativeMocksEntry = '@wojtekmaj/vitest-react-native/native-mocks';
/** * Replaces typed mock imports with paths before JavaScript can load the dependency. * Inspect import bindings so aliases work and unrelated functions stay unchanged. */export function createNativeMocksPlugin(): PluginObject { return { visitor: { CallExpression(path, state) { const callee = path.get('callee'); const namedCall = callee.isIdentifier(); const namespaceCall = callee.isMemberExpression() && !callee.node.computed && callee.get('property').isIdentifier({ name: 'mockNativeModule' });
if (!namedCall && !namespaceCall) { return; }
const identifier = callee.isMemberExpression() ? callee.get('object') : callee;
if (!identifier.isIdentifier()) { return; }
const binding = path.scope.getBinding(identifier.node.name);
if (!binding) { return; }
if (namedCall && binding.path.isImportSpecifier()) { if (!binding.path.get('imported').isIdentifier({ name: 'mockNativeModule' })) { return; } } else if (!namespaceCall || !binding.path.isImportNamespaceSpecifier()) { return; }
const declaration = binding.path.parentPath;
if ( !declaration?.isImportDeclaration() || declaration.node.source.value !== nativeMocksEntry ) { return; }
const argument = path.get('arguments')[0];
if (!argument?.isImportExpression()) { return; }
const source = argument.get('source');
if (!source.isStringLiteral()) { throw argument.buildCodeFrameError('Pass a literal import(...) to mockNativeModule'); }
// Relative imports belong to the setup file, not the application's root if (source.node.value.startsWith('.') && state.filename) { source.node.value = resolve(dirname(state.filename), source.node.value); }
argument.replaceWith(source.node); }, }, };}
/** * Handles typed mocks in application modules without changing their ES imports. * Vite performs the remaining TypeScript and JSX compilation afterwards. */export function transformNativeMocks(code: string, filename: string): string | undefined { if (!code.includes(nativeMocksEntry)) { return; }
const result = transformSync(code, { babelrc: false, configFile: false, filename, parserOpts: { createImportExpressions: true, plugins: /\.tsx?$/.test(filename) ? ['typescript', 'jsx'] : ['jsx'], }, plugins: [createNativeMocksPlugin], sourceMaps: 'inline', });
if (result?.code === undefined || result.code === null) { throw new Error(`Unable to transform native mock imports: ${filename}`); }
return result.code;}