one
Version:
One is a new React Framework that makes Vite serve both native and web.
116 lines (98 loc) • 4.07 kB
text/typescript
import { transformSync } from '@babel/core'
import { describe, expect, it } from 'vitest'
import oneRouterMetroPlugin from './one-router-metro'
const baseOptions = {
ONE_ROUTER_APP_ROOT_RELATIVE_TO_ENTRY: './app',
ONE_ROUTER_ROOT_FOLDER_NAME: 'app',
ONE_ROUTER_REQUIRE_CONTEXT_REGEX_STRING: '\\./app/.*',
}
function transform(code: string, filename: string, opts: Record<string, any> = {}) {
const result = transformSync(code, {
filename,
plugins: [[oneRouterMetroPlugin, { ...baseOptions, ...opts }]],
parserOpts: { sourceType: 'module' },
})
return result?.code ?? ''
}
describe('one-router-metro babel plugin', () => {
describe('setup file import ordering', () => {
const metroEntry = [
'import { createApp } from "one";',
'import { ctx } from "./metro-entry-ctx.js";',
'',
'createApp({ routes: {} });',
].join('\n')
it('injects setup import AFTER all existing imports in metro-entry.js', () => {
const code = transform(metroEntry, '/project/node_modules/one/metro-entry.js', {
ONE_SETUP_FILE_NATIVE: './setup-native.ts',
})
// setup import must exist
expect(code).toContain('./setup-native.ts')
// setup import must come AFTER both existing imports
const createAppPos = code.indexOf('from "one"')
const ctxPos = code.indexOf('metro-entry-ctx')
const setupPos = code.indexOf('./setup-native.ts')
expect(createAppPos).toBeGreaterThan(-1)
expect(ctxPos).toBeGreaterThan(-1)
expect(setupPos).toBeGreaterThan(-1)
expect(setupPos).toBeGreaterThan(createAppPos)
expect(setupPos).toBeGreaterThan(ctxPos)
})
it('injects setup import BEFORE non-import code', () => {
const code = transform(metroEntry, '/project/node_modules/one/metro-entry.js', {
ONE_SETUP_FILE_NATIVE: './setup-native.ts',
})
const setupPos = code.indexOf('./setup-native.ts')
const createAppCallPos = code.indexOf('createApp({')
expect(setupPos).toBeGreaterThan(-1)
expect(createAppCallPos).toBeGreaterThan(-1)
expect(setupPos).toBeLessThan(createAppCallPos)
})
it('does not inject setup import when no setup file configured', () => {
const code = transform(metroEntry, '/project/node_modules/one/metro-entry.js')
expect(code).not.toContain('setup')
})
it('does not inject setup import for non-metro-entry files', () => {
const code = transform(metroEntry, '/project/src/app.js', {
ONE_SETUP_FILE_NATIVE: './setup-native.ts',
})
expect(code).not.toContain('setup-native')
})
it('handles file with no imports by prepending setup', () => {
const noImports = 'const x = 1;\nconsole.log(x);'
const code = transform(noImports, '/project/node_modules/one/metro-entry.js', {
ONE_SETUP_FILE_NATIVE: './setup-native.ts',
})
expect(code).toContain('./setup-native.ts')
// setup should be at the top since there are no other imports
const setupPos = code.indexOf('./setup-native.ts')
const constPos = code.indexOf('const x')
expect(setupPos).toBeLessThan(constPos)
})
})
describe('env replacements', () => {
it('replaces process.env.ONE_ROUTER_ROOT_FOLDER_NAME', () => {
const code = transform(
'const x = process.env.ONE_ROUTER_ROOT_FOLDER_NAME;',
'/project/src/app.js'
)
expect(code).toContain('"app"')
expect(code).not.toContain('process.env')
})
it('replaces process.env.ONE_ROUTER_APP_ROOT_RELATIVE_TO_ENTRY', () => {
const code = transform(
'const x = process.env.ONE_ROUTER_APP_ROOT_RELATIVE_TO_ENTRY;',
'/project/src/app.js'
)
expect(code).toContain('"./app"')
})
it('replaces process.env.ONE_ROUTER_REQUIRE_CONTEXT_REGEX', () => {
const code = transform(
'const x = process.env.ONE_ROUTER_REQUIRE_CONTEXT_REGEX;',
'/project/src/app.js'
)
// should be a regex literal
expect(code).toMatch(/\/\\\.\/app\/\.\*\//)
})
})
})