one
Version:
One is a React framework for web, iOS, and Android apps.
115 lines (105 loc) • 3.5 kB
text/typescript
import { spawnSync } from 'node:child_process'
import {
chmodSync,
copyFileSync,
existsSync,
mkdirSync,
mkdtempSync,
readFileSync,
rmSync,
writeFileSync,
} from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, beforeEach, expect, test } from 'vitest'
const fixture = join(import.meta.dirname, '../../../tests/native-features')
let root: string
beforeEach(() => {
root = mkdtempSync(join(tmpdir(), 'one-fixture-prebuild-'))
mkdirSync(join(root, 'scripts'))
mkdirSync(join(root, 'bin'))
copyFileSync(join(fixture, 'package.json'), join(root, 'package.json'))
copyFileSync(
join(fixture, 'scripts/prebuild-native.ts'),
join(root, 'scripts/prebuild-native.ts')
)
for (const hook of ['audio-interruption', 'background-tasks']) {
writeFileSync(
join(root, 'scripts', `prepare-ios-${hook}.ts`),
`
import { appendFileSync } from 'node:fs'
appendFileSync(process.env.HOOK_FILE!, JSON.stringify('${hook}') + '\\n')
`
)
}
writeFileSync(
join(root, 'scripts', 'prepare-android-background-tasks.ts'),
`
import { appendFileSync } from 'node:fs'
appendFileSync(process.env.HOOK_FILE!, JSON.stringify('android-background-tasks') + '\\n')
`
)
const one = join(root, 'bin', 'one')
writeFileSync(
one,
`#!/usr/bin/env node
import { writeFileSync } from 'node:fs'
writeFileSync(process.env.RECORD_FILE, JSON.stringify(process.argv.slice(2)))
process.exit(Number(process.env.PREBUILD_EXIT_CODE ?? 0))
`
)
chmodSync(one, 0o755)
})
afterEach(() => rmSync(root, { recursive: true, force: true }))
function run(args: string[], exitCode = 0) {
return spawnSync('bun', ['run', 'prebuild:native', ...args], {
cwd: root,
encoding: 'utf8',
env: {
...process.env,
PATH: `${join(root, 'bin')}:${process.env.PATH}`,
RECORD_FILE: join(root, 'args.json'),
HOOK_FILE: join(root, 'hooks.jsonl'),
PREBUILD_EXIT_CODE: String(exitCode),
},
})
}
function hooks() {
return readFileSync(join(root, 'hooks.jsonl'), 'utf8')
.trim()
.split('\n')
.map((line) => JSON.parse(line))
}
test('Android prebuild forwards CLI options and succeeds without an iOS project', () => {
const result = run(['--platform', 'android', '--no-install'])
expect(result.status, result.stderr).toBe(0)
expect(JSON.parse(readFileSync(join(root, 'args.json'), 'utf8'))).toEqual([
'prebuild',
'--platform',
'android',
'--no-install',
])
expect(existsSync(join(root, 'ios'))).toBe(false)
expect(hooks()).toEqual(['android-background-tasks'])
})
test('iOS prebuild forwards CLI options and installs both simulator hooks', () => {
const result = run(['--platform', 'ios', '--no-install'])
expect(result.status, result.stderr).toBe(0)
expect(JSON.parse(readFileSync(join(root, 'args.json'), 'utf8'))).toEqual([
'prebuild',
'--platform',
'ios',
'--no-install',
])
expect(hooks()).toEqual(['audio-interruption', 'background-tasks'])
})
test('a failed prebuild preserves its exit status and leaves simulator hooks untouched', () => {
const result = run(['--platform', 'ios'], 42)
expect(result.status, result.stderr).toBe(42)
expect(existsSync(join(root, 'hooks.jsonl'))).toBe(false)
})
test('prebuilding both platforms still installs the iOS simulator hooks', () => {
const result = run([])
expect(result.status, result.stderr).toBe(0)
expect(hooks()).toEqual(['audio-interruption', 'background-tasks'])
})