1import spawnAsync from '@expo/spawn-async'; 2import chalk from 'chalk'; 3 4import { filterAsync } from '../Utils'; 5import * as Directories from '../Directories'; 6import * as Packages from '../Packages'; 7 8const ANDROID_DIR = Directories.getAndroidDir(); 9 10const excludedInTests = [ 11 'expo-module-template', 12 'expo-notifications', 13 'expo-in-app-purchases', 14 'expo-splash-screen', 15 'unimodules-test-core', 16]; 17 18type TestType = 'local' | 'instrumented'; 19 20export async function androidNativeUnitTests({ type }: { type: TestType }) { 21 if (!type) { 22 throw new Error( 23 'Must specify which type of unit test to run with `--type local` or `--type instrumented`.' 24 ); 25 } 26 if (type !== 'local' && type !== 'instrumented') { 27 throw new Error('Invalid type specified. Must use `--type local` or `--type instrumented`.'); 28 } 29 30 const packages = await Packages.getListOfPackagesAsync(); 31 32 function consoleErrorOutput( 33 output: string, 34 label: string, 35 colorifyLine: (string) => string 36 ): void { 37 const lines = output.trim().split(/\r\n?|\n/g); 38 console.error(lines.map((line) => `${chalk.gray(label)} ${colorifyLine(line)}`).join('\n')); 39 } 40 41 const androidPackages = await filterAsync(packages, async (pkg) => { 42 const pkgSlug = pkg.packageSlug; 43 44 if (type === 'instrumented') { 45 return ( 46 pkg.isSupportedOnPlatform('android') && 47 (await pkg.hasNativeInstrumentationTestsAsync('android')) && 48 !excludedInTests.includes(pkgSlug) 49 ); 50 } else { 51 return ( 52 pkg.isSupportedOnPlatform('android') && 53 (await pkg.hasNativeTestsAsync('android')) && 54 !excludedInTests.includes(pkgSlug) 55 ); 56 } 57 }); 58 59 console.log(chalk.green('Packages to test: ')); 60 androidPackages.forEach((pkg) => { 61 console.log(chalk.yellow(pkg.packageSlug)); 62 }); 63 64 const testCommand = type === 'instrumented' ? 'connectedAndroidTest' : 'test'; 65 try { 66 await spawnAsync( 67 './gradlew', 68 androidPackages.map((pkg) => `:${pkg.packageSlug}:${testCommand}`), 69 { 70 cwd: ANDROID_DIR, 71 stdio: 'inherit', 72 env: { ...process.env }, 73 } 74 ); 75 } catch (error) { 76 console.error('Failed while executing android unit tests'); 77 consoleErrorOutput(error.stdout, 'stdout >', chalk.reset); 78 consoleErrorOutput(error.stderr, 'stderr >', chalk.red); 79 throw error; 80 } 81 console.log(chalk.green('Finished android unit tests successfully.')); 82 return; 83} 84 85export default (program: any) => { 86 program 87 .command('android-native-unit-tests') 88 .option('-t, --type <string>', 'Type of unit test to run: local or instrumented') 89 .description('Runs Android native unit tests for each package that provides them.') 90 .asyncAction(androidNativeUnitTests); 91}; 92