549 行
20 KiB
JavaScript
549 行
20 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { execFileSync } from 'node:child_process'
|
|
import { createHash } from 'node:crypto'
|
|
import {
|
|
chmodSync,
|
|
copyFileSync,
|
|
existsSync,
|
|
mkdirSync,
|
|
mkdtempSync,
|
|
readFileSync,
|
|
rmSync,
|
|
writeFileSync,
|
|
} from 'node:fs'
|
|
import { createRequire } from 'node:module'
|
|
import { tmpdir } from 'node:os'
|
|
import path from 'node:path'
|
|
import test from 'node:test'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { strFromU8, unzipSync } from 'fflate'
|
|
|
|
const cli = fileURLToPath(new URL('./xuqm-rn.mjs', import.meta.url))
|
|
const workspaceRequire = createRequire(import.meta.url)
|
|
|
|
test('Gradle models and forwards the exact embedded release identity', () => {
|
|
const gradle = readFileSync(
|
|
fileURLToPath(new URL('../android/xuqm-bundles.gradle', import.meta.url)),
|
|
'utf8',
|
|
)
|
|
assert.match(gradle, /@Input\s+abstract Property<String> getBuildId\(\)/)
|
|
assert.match(gradle, /@Input\s+abstract Property<String> getBugCollectMode\(\)/)
|
|
assert.match(gradle, /environment\("XUQM_BUILD_ID", buildId\.get\(\)\)/)
|
|
assert.match(gradle, /environment\("XUQM_BUGCOLLECT_MODE", bugCollectMode\.get\(\)\)/)
|
|
})
|
|
|
|
test('embed creates a complete versioned manifest from a host fixture', () => {
|
|
const root = mkdtempSync(path.join(tmpdir(), 'xuqm-cli-'))
|
|
const output = path.join(root, 'generated', 'rn-bundles')
|
|
try {
|
|
writeFileSync(
|
|
path.join(root, 'package.json'),
|
|
JSON.stringify({
|
|
name: 'fixture',
|
|
version: '7.2.14',
|
|
dependencies: { '@xuqm/rn-update': '0.5.0-alpha.5' },
|
|
}),
|
|
)
|
|
writeFileSync(path.join(root, 'common.ts'), '')
|
|
writeFileSync(path.join(root, 'app.ts'), '')
|
|
writeFileSync(path.join(root, 'metro.config.js'), 'module.exports = {}\n')
|
|
writeFileSync(
|
|
path.join(root, 'xuqm.modules.json'),
|
|
JSON.stringify({
|
|
schemaVersion: 3,
|
|
appId: 'fixture.app',
|
|
packageName: 'com.example.fixture',
|
|
iosBundleId: 'com.example.fixture.ios',
|
|
mainModuleName: 'Fixture',
|
|
pluginVersion: '1.0.0',
|
|
appVersionRange: '>=7.2.14 <8.0.0',
|
|
outputDir: './bundle',
|
|
metroConfig: './metro.config.js',
|
|
embeddedOutput: { android: './unused' },
|
|
modules: [
|
|
{ id: 'common', type: 'common', entry: './common.ts' },
|
|
{ id: 'app', type: 'app', entry: './app.ts' },
|
|
],
|
|
}),
|
|
)
|
|
for (const moduleId of ['common', 'app']) {
|
|
const directory = path.join(root, 'bundle', 'android', moduleId)
|
|
mkdirSync(directory, { recursive: true })
|
|
writeFileSync(path.join(directory, `${moduleId}.android.bundle`), moduleId)
|
|
if (moduleId === 'app') {
|
|
mkdirSync(path.join(directory, 'drawable-mdpi'), { recursive: true })
|
|
writeFileSync(path.join(directory, 'drawable-mdpi', 'fixture_icon.png'), 'png')
|
|
}
|
|
}
|
|
|
|
execFileSync(process.execPath, [cli, 'embed', 'android', '--skip-build', '--output', output], {
|
|
cwd: root,
|
|
stdio: 'pipe',
|
|
})
|
|
|
|
const manifest = JSON.parse(readFileSync(path.join(output, 'manifest.json'), 'utf8'))
|
|
assert.equal(manifest.appVersion, '7.2.14')
|
|
assert.equal(manifest.bundleFormat, 'javascript')
|
|
assert.equal(manifest.modules.common.moduleVersion, '1.0.0')
|
|
assert.equal(manifest.modules.app.moduleVersion, '1.0.0')
|
|
assert.equal(manifest.modules.app.commonVersionRange, '>=1.0.0 <2.0.0')
|
|
assert.equal(manifest.modules.app.minNativeApiLevel, 2)
|
|
assert.equal(manifest.modules.app.appVersionRange, '>=7.2.14 <8.0.0')
|
|
assert.equal(manifest.modules.app.sha256, createHash('sha256').update('app').digest('hex'))
|
|
assert.equal(manifest.modules.app.byteLength, 3)
|
|
assert.deepEqual(manifest.modules.app.assetFiles, ['drawable-mdpi/fixture_icon.png'])
|
|
assert.equal(readFileSync(path.join(output, 'app.android.bundle'), 'utf8'), 'app')
|
|
assert.equal(
|
|
readFileSync(path.join(output, 'drawable-mdpi', 'fixture_icon.png'), 'utf8'),
|
|
'png',
|
|
)
|
|
} finally {
|
|
rmSync(root, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('Android Hermes hosts compile plugin bundles to bytecode', () => {
|
|
const root = mkdtempSync(path.join(tmpdir(), 'xuqm-cli-hermes-'))
|
|
try {
|
|
writeFileSync(
|
|
path.join(root, 'package.json'),
|
|
JSON.stringify({
|
|
name: 'fixture',
|
|
version: '1.0.0',
|
|
dependencies: { '@xuqm/rn-update': '0.5.0-alpha.10' },
|
|
}),
|
|
)
|
|
writeFileSync(path.join(root, 'common.ts'), '')
|
|
mkdirSync(path.join(root, 'android'), { recursive: true })
|
|
writeFileSync(path.join(root, 'android', 'gradle.properties'), 'hermesEnabled=true\n')
|
|
writeFileSync(
|
|
path.join(root, 'xuqm.modules.json'),
|
|
JSON.stringify({
|
|
schemaVersion: 3,
|
|
appId: 'fixture.app',
|
|
packageName: 'com.example.fixture',
|
|
mainModuleName: 'Fixture',
|
|
pluginVersion: '1.0.0',
|
|
appVersionRange: '>=1.0.0 <2.0.0',
|
|
outputDir: './bundle',
|
|
embeddedOutput: { android: './generated' },
|
|
modules: [{ id: 'common', type: 'common', entry: './common.ts' }],
|
|
}),
|
|
)
|
|
|
|
const reactNativeDirectory = path.join(root, 'node_modules', 'react-native')
|
|
const compilerDirectory = path.join(root, 'node_modules', 'hermes-compiler')
|
|
mkdirSync(path.join(reactNativeDirectory, 'scripts'), { recursive: true })
|
|
mkdirSync(
|
|
path.join(
|
|
compilerDirectory,
|
|
'hermesc',
|
|
process.platform === 'win32'
|
|
? 'win64-bin'
|
|
: process.platform === 'darwin'
|
|
? 'osx-bin'
|
|
: 'linux64-bin',
|
|
),
|
|
{ recursive: true },
|
|
)
|
|
writeFileSync(
|
|
path.join(reactNativeDirectory, 'package.json'),
|
|
JSON.stringify({
|
|
name: 'react-native',
|
|
version: '0.86.0',
|
|
dependencies: { 'hermes-compiler': '1.0.0' },
|
|
}),
|
|
)
|
|
writeFileSync(
|
|
path.join(reactNativeDirectory, 'cli.js'),
|
|
`
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const args = process.argv.slice(2);
|
|
const output = args[args.indexOf('--bundle-output') + 1];
|
|
const sourceMap = args[args.indexOf('--sourcemap-output') + 1];
|
|
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
fs.writeFileSync(output, 'javascript');
|
|
fs.writeFileSync(sourceMap, JSON.stringify({
|
|
version: 3,
|
|
sources: ['/fixture/common.ts'],
|
|
names: [],
|
|
mappings: '',
|
|
}));
|
|
`,
|
|
)
|
|
writeFileSync(
|
|
path.join(reactNativeDirectory, 'scripts', 'compose-source-maps.js'),
|
|
`
|
|
const fs = require('node:fs');
|
|
const args = process.argv.slice(2);
|
|
const output = args[args.indexOf('-o') + 1];
|
|
fs.copyFileSync(args[0], output);
|
|
`,
|
|
)
|
|
writeFileSync(
|
|
path.join(compilerDirectory, 'package.json'),
|
|
JSON.stringify({ name: 'hermes-compiler', version: '1.0.0' }),
|
|
)
|
|
const compiler = path.join(
|
|
compilerDirectory,
|
|
'hermesc',
|
|
process.platform === 'win32'
|
|
? 'win64-bin'
|
|
: process.platform === 'darwin'
|
|
? 'osx-bin'
|
|
: 'linux64-bin',
|
|
process.platform === 'win32' ? 'hermesc.exe' : 'hermesc',
|
|
)
|
|
// 使用当前 React Native 实际依赖的 Hermes 编译器。文本脚本即使命名为
|
|
// hermesc.exe 也不是 Windows 可执行文件,会让 CI 只验证到测试替身而非真实链路。
|
|
const workspaceReactNativeManifest = workspaceRequire.resolve('react-native/package.json')
|
|
const workspaceReactNativeRequire = createRequire(workspaceReactNativeManifest)
|
|
const workspaceCompilerManifest = workspaceReactNativeRequire.resolve(
|
|
'hermes-compiler/package.json',
|
|
)
|
|
const workspaceCompiler = path.join(
|
|
path.dirname(workspaceCompilerManifest),
|
|
'hermesc',
|
|
process.platform === 'win32'
|
|
? 'win64-bin'
|
|
: process.platform === 'darwin'
|
|
? 'osx-bin'
|
|
: 'linux64-bin',
|
|
process.platform === 'win32' ? 'hermesc.exe' : 'hermesc',
|
|
)
|
|
copyFileSync(workspaceCompiler, compiler)
|
|
if (process.platform !== 'win32') chmodSync(compiler, 0o755)
|
|
|
|
execFileSync(process.execPath, [cli, 'embed', 'android'], {
|
|
cwd: root,
|
|
stdio: 'pipe',
|
|
env: {
|
|
...process.env,
|
|
XUQM_BUILD_ID: 'release-fixture-1',
|
|
XUQM_BUGCOLLECT_MODE: 'disabled',
|
|
},
|
|
})
|
|
|
|
const bytecode = readFileSync(path.join(root, 'generated', 'common.android.bundle'))
|
|
assert.ok(bytecode.length > Buffer.byteLength('javascript'))
|
|
assert.notEqual(bytecode.toString('utf8'), 'javascript')
|
|
const manifest = JSON.parse(readFileSync(path.join(root, 'generated', 'manifest.json'), 'utf8'))
|
|
assert.equal(manifest.bundleFormat, 'hermes-bytecode')
|
|
assert.equal(manifest.buildId, 'release-fixture-1')
|
|
assert.equal(manifest.bugCollectMode, 'disabled')
|
|
const packaged = unzipSync(
|
|
new Uint8Array(
|
|
readFileSync(path.join(root, 'bundle/android/common/common.android.xuqm.zip')),
|
|
),
|
|
)
|
|
const packagedManifest = JSON.parse(strFromU8(packaged['rn-manifest.json']))
|
|
assert.equal(packagedManifest.buildId, manifest.buildId)
|
|
assert.equal(packagedManifest.bugCollectMode, manifest.bugCollectMode)
|
|
} finally {
|
|
rmSync(root, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('embed rejects assets owned by more than one module', () => {
|
|
const root = mkdtempSync(path.join(tmpdir(), 'xuqm-cli-asset-ownership-'))
|
|
try {
|
|
writeFileSync(
|
|
path.join(root, 'package.json'),
|
|
JSON.stringify({
|
|
name: 'fixture',
|
|
version: '1.0.0',
|
|
dependencies: { '@xuqm/rn-update': '0.5.0-alpha.10' },
|
|
}),
|
|
)
|
|
for (const moduleId of ['common', 'app']) {
|
|
writeFileSync(path.join(root, `${moduleId}.ts`), '')
|
|
const directory = path.join(root, 'bundle', 'android', moduleId, 'drawable-mdpi')
|
|
mkdirSync(directory, { recursive: true })
|
|
writeFileSync(
|
|
path.join(root, 'bundle', 'android', moduleId, `${moduleId}.android.bundle`),
|
|
moduleId,
|
|
)
|
|
writeFileSync(path.join(directory, 'shared.png'), 'png')
|
|
}
|
|
writeFileSync(path.join(root, 'metro.config.js'), 'module.exports = {}\n')
|
|
writeFileSync(
|
|
path.join(root, 'xuqm.modules.json'),
|
|
JSON.stringify({
|
|
schemaVersion: 3,
|
|
appId: 'fixture.app',
|
|
packageName: 'com.example.fixture',
|
|
mainModuleName: 'Fixture',
|
|
pluginVersion: '1.0.0',
|
|
appVersionRange: '>=1.0.0 <2.0.0',
|
|
outputDir: './bundle',
|
|
metroConfig: './metro.config.js',
|
|
embeddedOutput: { android: './generated' },
|
|
modules: [
|
|
{ id: 'common', type: 'common', entry: './common.ts' },
|
|
{ id: 'app', type: 'app', entry: './app.ts' },
|
|
],
|
|
}),
|
|
)
|
|
|
|
assert.throws(
|
|
() =>
|
|
execFileSync(process.execPath, [cli, 'embed', 'android', '--skip-build'], {
|
|
cwd: root,
|
|
stdio: 'pipe',
|
|
}),
|
|
/Command failed/,
|
|
)
|
|
} finally {
|
|
rmSync(root, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('build invokes the host-local React Native CLI with a consistent color environment', () => {
|
|
const root = mkdtempSync(path.join(tmpdir(), 'xuqm-cli-local-rn-'))
|
|
try {
|
|
writeFileSync(
|
|
path.join(root, 'package.json'),
|
|
JSON.stringify({
|
|
name: 'fixture',
|
|
version: '1.0.0',
|
|
dependencies: { '@xuqm/rn-update': '0.5.0-alpha.8' },
|
|
}),
|
|
)
|
|
writeFileSync(path.join(root, 'common.ts'), '')
|
|
writeFileSync(
|
|
path.join(root, 'xuqm.modules.json'),
|
|
JSON.stringify({
|
|
schemaVersion: 3,
|
|
appId: 'fixture.app',
|
|
packageName: 'com.example.fixture',
|
|
iosBundleId: 'com.example.fixture.ios',
|
|
mainModuleName: 'Fixture',
|
|
pluginVersion: '1.0.0',
|
|
appVersionRange: '>=1.0.0 <2.0.0',
|
|
outputDir: './bundle',
|
|
embeddedOutput: { android: './generated' },
|
|
modules: [{ id: 'common', type: 'common', entry: './common.ts' }],
|
|
}),
|
|
)
|
|
const reactNativeDirectory = path.join(root, 'node_modules', 'react-native')
|
|
mkdirSync(reactNativeDirectory, { recursive: true })
|
|
writeFileSync(
|
|
path.join(reactNativeDirectory, 'cli.js'),
|
|
`
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const args = process.argv.slice(2);
|
|
const output = args[args.indexOf('--bundle-output') + 1];
|
|
const sourceMap = args[args.indexOf('--sourcemap-output') + 1];
|
|
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
fs.writeFileSync(output, 'bundle');
|
|
fs.writeFileSync(sourceMap, JSON.stringify({
|
|
version: 3,
|
|
sources: ['/fixture/common.ts'],
|
|
names: [],
|
|
mappings: '',
|
|
}));
|
|
fs.writeFileSync(path.join(process.cwd(), 'child.json'), JSON.stringify({
|
|
args,
|
|
forceColor: process.env.FORCE_COLOR ?? null,
|
|
noColor: process.env.NO_COLOR ?? null,
|
|
}));
|
|
`,
|
|
)
|
|
|
|
execFileSync(process.execPath, [cli, 'build', 'android'], {
|
|
cwd: root,
|
|
env: { ...process.env, FORCE_COLOR: '1', NO_COLOR: '1' },
|
|
stdio: 'pipe',
|
|
})
|
|
|
|
const child = JSON.parse(readFileSync(path.join(root, 'child.json'), 'utf8'))
|
|
assert.equal(child.args[0], 'bundle')
|
|
assert.equal(child.forceColor, '0')
|
|
assert.equal(child.noColor, null)
|
|
|
|
const androidPackage = unzipSync(
|
|
new Uint8Array(
|
|
readFileSync(path.join(root, 'bundle/android/common/common.android.xuqm.zip')),
|
|
),
|
|
)
|
|
const androidManifest = JSON.parse(strFromU8(androidPackage['rn-manifest.json']))
|
|
assert.equal(androidManifest.packageName, 'com.example.fixture')
|
|
|
|
execFileSync(process.execPath, [cli, 'build', 'ios'], {
|
|
cwd: root,
|
|
stdio: 'pipe',
|
|
})
|
|
const iosPackage = unzipSync(
|
|
new Uint8Array(readFileSync(path.join(root, 'bundle/ios/common/common.ios.xuqm.zip'))),
|
|
)
|
|
const iosManifest = JSON.parse(strFromU8(iosPackage['rn-manifest.json']))
|
|
assert.equal(iosManifest.platform, 'ios')
|
|
assert.equal(iosManifest.packageName, 'com.example.fixture.ios')
|
|
} finally {
|
|
rmSync(root, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('building one buz first rebuilds startup and common module maps', () => {
|
|
const root = mkdtempSync(path.join(tmpdir(), 'xuqm-cli-buz-dependencies-'))
|
|
try {
|
|
writeFileSync(
|
|
path.join(root, 'package.json'),
|
|
JSON.stringify({
|
|
name: 'fixture',
|
|
version: '1.0.0',
|
|
dependencies: { '@xuqm/rn-update': '0.5.0-alpha.10' },
|
|
}),
|
|
)
|
|
for (const entry of ['startup.ts', 'common.ts', 'app.ts', 'orders.ts']) {
|
|
writeFileSync(path.join(root, entry), '')
|
|
}
|
|
mkdirSync(path.join(root, 'shared'), { recursive: true })
|
|
writeFileSync(path.join(root, 'shared', 'shared.ts'), 'export const shared = true\n')
|
|
writeFileSync(path.join(root, 'shared', 'ignored.test.ts'), 'throw new Error()\n')
|
|
writeFileSync(path.join(root, 'metro.config.js'), 'module.exports = {}\n')
|
|
writeFileSync(
|
|
path.join(root, 'xuqm.modules.json'),
|
|
JSON.stringify({
|
|
schemaVersion: 3,
|
|
appId: 'fixture.app',
|
|
packageName: 'com.example.fixture',
|
|
mainModuleName: 'Fixture',
|
|
pluginVersion: '1.0.0',
|
|
appVersionRange: '>=1.0.0 <2.0.0',
|
|
outputDir: './bundle',
|
|
metroConfig: './metro.config.js',
|
|
embeddedOutput: { android: './generated' },
|
|
// 配置顺序不作为执行顺序;CLI 必须按依赖拓扑重排。
|
|
modules: [
|
|
{ id: 'orders', type: 'buz', entry: './orders.ts' },
|
|
{ id: 'app', type: 'app', entry: './app.ts' },
|
|
{
|
|
id: 'common',
|
|
type: 'common',
|
|
entry: './common.ts',
|
|
ownershipRoots: ['./shared'],
|
|
},
|
|
{ id: 'startup', type: 'startup', entry: './startup.ts' },
|
|
],
|
|
}),
|
|
)
|
|
const reactNativeDirectory = path.join(root, 'node_modules', 'react-native')
|
|
mkdirSync(reactNativeDirectory, { recursive: true })
|
|
writeFileSync(
|
|
path.join(reactNativeDirectory, 'cli.js'),
|
|
`
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const callsFile = path.join(process.cwd(), 'module-calls.json');
|
|
const calls = fs.existsSync(callsFile) ? JSON.parse(fs.readFileSync(callsFile, 'utf8')) : [];
|
|
const args = process.argv.slice(2);
|
|
calls.push({
|
|
entry: args[args.indexOf('--entry-file') + 1],
|
|
id: process.env.XUQM_MODULE_ID,
|
|
index: process.env.XUQM_MODULE_INDEX,
|
|
reset: process.env.XUQM_RESET_MODULE_CACHE,
|
|
type: process.env.XUQM_MODULE_TYPE,
|
|
});
|
|
fs.writeFileSync(callsFile, JSON.stringify(calls));
|
|
const output = args[args.indexOf('--bundle-output') + 1];
|
|
const sourceMap = args[args.indexOf('--sourcemap-output') + 1];
|
|
fs.mkdirSync(path.dirname(output), { recursive: true });
|
|
fs.writeFileSync(output, 'bundle');
|
|
fs.writeFileSync(sourceMap, JSON.stringify({
|
|
version: 3,
|
|
sources: ['/fixture/' + process.env.XUQM_MODULE_ID + '.ts'],
|
|
names: [],
|
|
mappings: '',
|
|
}));
|
|
`,
|
|
)
|
|
|
|
execFileSync(process.execPath, [cli, 'build', 'android', '--module', 'orders'], {
|
|
cwd: root,
|
|
stdio: 'pipe',
|
|
})
|
|
|
|
const calls = JSON.parse(readFileSync(path.join(root, 'module-calls.json'), 'utf8'))
|
|
assert.equal(calls[0].entry, './startup.ts')
|
|
assert.match(calls[1].entry, /\.xuqm-cache\/ownership\/common\.android\.js$/)
|
|
assert.equal(calls[2].entry, './orders.ts')
|
|
assert.deepEqual(
|
|
calls.map(({ entry: _entry, ...call }) => call),
|
|
[
|
|
{ id: 'startup', index: '3', reset: 'true', type: 'startup' },
|
|
{ id: 'common', index: '2', reset: 'false', type: 'common' },
|
|
{ id: 'orders', index: '0', reset: 'false', type: 'buz' },
|
|
],
|
|
)
|
|
const ownershipEntry = readFileSync(calls[1].entry, 'utf8')
|
|
assert.match(ownershipEntry, /shared\/shared\.ts/)
|
|
assert.doesNotMatch(ownershipEntry, /ignored\.test\.ts/)
|
|
assert.equal(
|
|
existsSync(path.join(root, 'bundle/android/startup/startup.android.xuqm.zip')),
|
|
false,
|
|
)
|
|
|
|
const commonPackage = unzipSync(
|
|
new Uint8Array(
|
|
readFileSync(path.join(root, 'bundle/android/common/common.android.xuqm.zip')),
|
|
),
|
|
)
|
|
const packageManifest = JSON.parse(strFromU8(commonPackage['rn-manifest.json']))
|
|
assert.equal(packageManifest.schemaVersion, 1)
|
|
assert.equal(packageManifest.packageName, 'com.example.fixture')
|
|
assert.equal(packageManifest.moduleId, 'common')
|
|
assert.equal(packageManifest.bundleFormat, 'javascript')
|
|
assert.deepEqual(packageManifest.assets, [])
|
|
assert.equal(strFromU8(commonPackage['common.android.bundle']), 'bundle')
|
|
} finally {
|
|
rmSync(root, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
test('start and run forward arguments through the host-local React Native CLI', () => {
|
|
const root = mkdtempSync(path.join(tmpdir(), 'xuqm-cli-run-rn-'))
|
|
try {
|
|
const reactNativeDirectory = path.join(root, 'node_modules', 'react-native')
|
|
mkdirSync(reactNativeDirectory, { recursive: true })
|
|
writeFileSync(
|
|
path.join(reactNativeDirectory, 'cli.js'),
|
|
`
|
|
const fs = require('node:fs');
|
|
const callsFile = require('node:path').join(process.cwd(), 'calls.json');
|
|
const calls = fs.existsSync(callsFile) ? JSON.parse(fs.readFileSync(callsFile, 'utf8')) : [];
|
|
calls.push({
|
|
args: process.argv.slice(2),
|
|
forceColor: process.env.FORCE_COLOR ?? null,
|
|
noColor: process.env.NO_COLOR ?? null,
|
|
});
|
|
fs.writeFileSync(callsFile, JSON.stringify(calls));
|
|
`,
|
|
)
|
|
|
|
const environment = { ...process.env, FORCE_COLOR: '1', NO_COLOR: '1' }
|
|
execFileSync(process.execPath, [cli, 'start', '--reset-cache'], {
|
|
cwd: root,
|
|
env: environment,
|
|
stdio: 'pipe',
|
|
})
|
|
execFileSync(process.execPath, [cli, 'run', 'android', '--device', 'emulator-5554'], {
|
|
cwd: root,
|
|
env: environment,
|
|
stdio: 'pipe',
|
|
})
|
|
|
|
const calls = JSON.parse(readFileSync(path.join(root, 'calls.json'), 'utf8'))
|
|
assert.deepEqual(calls[0].args, ['start', '--reset-cache'])
|
|
assert.deepEqual(calls[1].args, ['run-android', '--device', 'emulator-5554'])
|
|
assert.equal(calls[0].forceColor, '0')
|
|
assert.equal(calls[1].forceColor, '0')
|
|
assert.equal(calls[0].noColor, null)
|
|
assert.equal(calls[1].noColor, null)
|
|
} finally {
|
|
rmSync(root, { recursive: true, force: true })
|
|
}
|
|
})
|