18d307f52SEvan Bacon/* eslint-env jest */ 28d307f52SEvan Baconimport JsonFile from '@expo/json-file'; 38d307f52SEvan Baconimport execa from 'execa'; 48d307f52SEvan Baconimport fs from 'fs/promises'; 56c8d1802SEvan Baconimport { sync as globSync } from 'glob'; 68d307f52SEvan Baconimport klawSync from 'klaw-sync'; 78d307f52SEvan Baconimport path from 'path'; 88d307f52SEvan Bacon 98d307f52SEvan Baconimport { 108d307f52SEvan Bacon bin, 118d307f52SEvan Bacon execute, 128d307f52SEvan Bacon projectRoot, 138d307f52SEvan Bacon getRoot, 148d307f52SEvan Bacon setupTestProjectAsync, 158d307f52SEvan Bacon getLoadedModulesAsync, 168d307f52SEvan Bacon} from './utils'; 178d307f52SEvan Bacon 188d307f52SEvan Baconconst originalForceColor = process.env.FORCE_COLOR; 198d307f52SEvan Baconconst originalCI = process.env.CI; 208d307f52SEvan Bacon 216c8d1802SEvan Baconconst templateFolder = path.join(__dirname, '../../../../../templates/expo-template-bare-minimum/'); 226c8d1802SEvan Bacon 236c8d1802SEvan Baconfunction getTemplatePath() { 246c8d1802SEvan Bacon const results = globSync(`*.tgz`, { 256c8d1802SEvan Bacon absolute: true, 266c8d1802SEvan Bacon cwd: templateFolder, 276c8d1802SEvan Bacon }); 286c8d1802SEvan Bacon 296c8d1802SEvan Bacon return results[0]; 306c8d1802SEvan Bacon} 316c8d1802SEvan Bacon 326c8d1802SEvan Baconasync function ensureTemplatePathAsync() { 336c8d1802SEvan Bacon let templatePath = getTemplatePath(); 346c8d1802SEvan Bacon if (templatePath) return templatePath; 356c8d1802SEvan Bacon await execa('npm', ['pack'], { cwd: templateFolder }); 366c8d1802SEvan Bacon 376c8d1802SEvan Bacon templatePath = getTemplatePath(); 386c8d1802SEvan Bacon if (templatePath) return templatePath; 396c8d1802SEvan Bacon 406c8d1802SEvan Bacon throw new Error('Could not find template tarball'); 416c8d1802SEvan Bacon} 426c8d1802SEvan Bacon 438d307f52SEvan BaconbeforeAll(async () => { 448d307f52SEvan Bacon await fs.mkdir(projectRoot, { recursive: true }); 458d307f52SEvan Bacon process.env.FORCE_COLOR = '0'; 468d307f52SEvan Bacon process.env.CI = '1'; 478d307f52SEvan Bacon}); 488d307f52SEvan Bacon 498d307f52SEvan BaconafterAll(() => { 508d307f52SEvan Bacon process.env.FORCE_COLOR = originalForceColor; 518d307f52SEvan Bacon process.env.CI = originalCI; 528d307f52SEvan Bacon}); 538d307f52SEvan Bacon 548d307f52SEvan Baconit('loads expected modules by default', async () => { 558d307f52SEvan Bacon const modules = await getLoadedModulesAsync(`require('../../build/src/prebuild').expoPrebuild`); 568d307f52SEvan Bacon expect(modules).toStrictEqual([ 574067174dSWill Schurman '../node_modules/ansi-styles/index.js', 588d307f52SEvan Bacon '../node_modules/arg/index.js', 598d307f52SEvan Bacon '../node_modules/chalk/source/index.js', 608d307f52SEvan Bacon '../node_modules/chalk/source/util.js', 618d307f52SEvan Bacon '../node_modules/has-flag/index.js', 628d307f52SEvan Bacon '../node_modules/supports-color/index.js', 638d307f52SEvan Bacon '@expo/cli/build/src/log.js', 648d307f52SEvan Bacon '@expo/cli/build/src/prebuild/index.js', 658d307f52SEvan Bacon '@expo/cli/build/src/utils/args.js', 668d307f52SEvan Bacon ]); 678d307f52SEvan Bacon}); 688d307f52SEvan Bacon 698d307f52SEvan Baconit('runs `npx expo prebuild --help`', async () => { 708d307f52SEvan Bacon const results = await execute('prebuild', '--help'); 718d307f52SEvan Bacon expect(results.stdout).toMatchInlineSnapshot(` 728d307f52SEvan Bacon " 7383d464dcSEvan Bacon Info 7483d464dcSEvan Bacon Create native iOS and Android project files for building natively 758d307f52SEvan Bacon 768d307f52SEvan Bacon Usage 778d307f52SEvan Bacon $ npx expo prebuild <dir> 788d307f52SEvan Bacon 798d307f52SEvan Bacon Options 8083d464dcSEvan Bacon <dir> Directory of the Expo project. Default: Current working directory 8183d464dcSEvan Bacon --no-install Skip installing npm packages and CocoaPods 828d307f52SEvan Bacon --clean Delete the native folders and regenerate them before applying changes 836caf5755SEvan Bacon --npm Use npm to install dependencies. Default when package-lock.json exists 846caf5755SEvan Bacon --yarn Use Yarn to install dependencies. Default when yarn.lock exists 85*9b1b5ec6SEvan Bacon --bun Use bun to install dependencies. Default when bun.lockb exists 866caf5755SEvan Bacon --pnpm Use pnpm to install dependencies. Default when pnpm-lock.yaml exists 878d307f52SEvan Bacon --template <template> Project template to clone from. File path pointing to a local tar file or a github repo 888d307f52SEvan Bacon -p, --platform <all|android|ios> Platforms to sync: ios, android, all. Default: all 898d307f52SEvan Bacon --skip-dependency-update <dependencies> Preserves versions of listed packages in package.json (comma separated list) 9083d464dcSEvan Bacon -h, --help Usage info 918d307f52SEvan Bacon " 928d307f52SEvan Bacon `); 938d307f52SEvan Bacon}); 948d307f52SEvan Bacon 958d307f52SEvan Baconit('runs `npx expo prebuild` asserts when expo is not installed', async () => { 968d307f52SEvan Bacon const projectName = 'basic-prebuild-assert-no-expo'; 978d307f52SEvan Bacon const projectRoot = getRoot(projectName); 988d307f52SEvan Bacon // Create the project root aot 998d307f52SEvan Bacon await fs.mkdir(projectRoot, { recursive: true }); 1008d307f52SEvan Bacon // Create a fake package.json -- this is a terminal file that cannot be overwritten. 1018d307f52SEvan Bacon await fs.writeFile(path.join(projectRoot, 'package.json'), '{ "version": "1.0.0" }'); 1028d307f52SEvan Bacon await fs.writeFile(path.join(projectRoot, 'app.json'), '{ "expo": { "name": "foobar" } }'); 1038d307f52SEvan Bacon 1048d307f52SEvan Bacon await expect(execute('prebuild', projectName, '--no-install')).rejects.toThrowError( 1058d307f52SEvan Bacon /Cannot determine which native SDK version your project uses because the module `expo` is not installed\. Please install it with `yarn add expo` and try again./ 1068d307f52SEvan Bacon ); 1078d307f52SEvan Bacon}); 1088d307f52SEvan Bacon 1098d307f52SEvan Baconit( 1108d307f52SEvan Bacon 'runs `npx expo prebuild`', 1118d307f52SEvan Bacon async () => { 1128d307f52SEvan Bacon const projectRoot = await setupTestProjectAsync('basic-prebuild', 'with-blank'); 1138d307f52SEvan Bacon // `npx expo prebuild --no-install` 1146c8d1802SEvan Bacon 1156c8d1802SEvan Bacon const templateFolder = await ensureTemplatePathAsync(); 1166c8d1802SEvan Bacon console.log('Using local template:', templateFolder); 1176c8d1802SEvan Bacon 1186c8d1802SEvan Bacon await execa('node', [bin, 'prebuild', '--no-install', '--template', templateFolder], { 1196c8d1802SEvan Bacon cwd: projectRoot, 1206c8d1802SEvan Bacon }); 1218d307f52SEvan Bacon 1228d307f52SEvan Bacon // List output files with sizes for snapshotting. 1238d307f52SEvan Bacon // This is to make sure that any changes to the output are intentional. 1248d307f52SEvan Bacon // Posix path formatting is used to make paths the same across OSes. 1258d307f52SEvan Bacon const files = klawSync(projectRoot) 1268d307f52SEvan Bacon .map((entry) => { 1278d307f52SEvan Bacon if (entry.path.includes('node_modules') || !entry.stats.isFile()) { 1288d307f52SEvan Bacon return null; 1298d307f52SEvan Bacon } 1308d307f52SEvan Bacon return path.posix.relative(projectRoot, entry.path); 1318d307f52SEvan Bacon }) 1328d307f52SEvan Bacon .filter(Boolean); 1338d307f52SEvan Bacon 1348d307f52SEvan Bacon const pkg = await JsonFile.readAsync(path.resolve(projectRoot, 'package.json')); 1358d307f52SEvan Bacon 1368d307f52SEvan Bacon // Added new packages 137e1bb5bdfSKudo Chien expect(Object.keys(pkg.dependencies ?? {}).sort()).toStrictEqual([ 1388d307f52SEvan Bacon 'expo', 1398d307f52SEvan Bacon 'expo-splash-screen', 1408d307f52SEvan Bacon 'expo-status-bar', 1418d307f52SEvan Bacon 'react', 1428d307f52SEvan Bacon 'react-native', 1438d307f52SEvan Bacon ]); 1448d307f52SEvan Bacon 1458d307f52SEvan Bacon // Updated scripts 1468d307f52SEvan Bacon expect(pkg.scripts).toStrictEqual({ 1478d307f52SEvan Bacon android: 'expo run:android', 1488d307f52SEvan Bacon ios: 'expo run:ios', 1498d307f52SEvan Bacon }); 1508d307f52SEvan Bacon 1518d307f52SEvan Bacon // If this changes then everything else probably changed as well. 1528d307f52SEvan Bacon expect(files).toMatchInlineSnapshot(` 153e1bb5bdfSKudo Chien [ 1548d307f52SEvan Bacon "App.js", 155fa5d5955SEvan Bacon "android/.gitignore", 1568d307f52SEvan Bacon "android/app/build.gradle", 1578d307f52SEvan Bacon "android/app/debug.keystore", 1588d307f52SEvan Bacon "android/app/proguard-rules.pro", 1598d307f52SEvan Bacon "android/app/src/debug/AndroidManifest.xml", 1608d307f52SEvan Bacon "android/app/src/debug/java/com/example/minimal/ReactNativeFlipper.java", 1618d307f52SEvan Bacon "android/app/src/main/AndroidManifest.xml", 1628d307f52SEvan Bacon "android/app/src/main/java/com/example/minimal/MainActivity.java", 1638d307f52SEvan Bacon "android/app/src/main/java/com/example/minimal/MainApplication.java", 164fa5d5955SEvan Bacon "android/app/src/main/res/drawable/rn_edit_text_material.xml", 1658d307f52SEvan Bacon "android/app/src/main/res/drawable/splashscreen.xml", 1668d307f52SEvan Bacon "android/app/src/main/res/mipmap-hdpi/ic_launcher.png", 1678d307f52SEvan Bacon "android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png", 1688d307f52SEvan Bacon "android/app/src/main/res/mipmap-mdpi/ic_launcher.png", 1698d307f52SEvan Bacon "android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png", 1708d307f52SEvan Bacon "android/app/src/main/res/mipmap-xhdpi/ic_launcher.png", 1718d307f52SEvan Bacon "android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png", 1728d307f52SEvan Bacon "android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png", 1738d307f52SEvan Bacon "android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png", 1748d307f52SEvan Bacon "android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png", 1758d307f52SEvan Bacon "android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png", 1768d307f52SEvan Bacon "android/app/src/main/res/values/colors.xml", 1778d307f52SEvan Bacon "android/app/src/main/res/values/strings.xml", 1788d307f52SEvan Bacon "android/app/src/main/res/values/styles.xml", 1798d307f52SEvan Bacon "android/app/src/main/res/values-night/colors.xml", 180e1bb5bdfSKudo Chien "android/app/src/release/java/com/example/minimal/ReactNativeFlipper.java", 1818d307f52SEvan Bacon "android/build.gradle", 1828d307f52SEvan Bacon "android/gradle/wrapper/gradle-wrapper.jar", 1838d307f52SEvan Bacon "android/gradle/wrapper/gradle-wrapper.properties", 1848d307f52SEvan Bacon "android/gradle.properties", 1858d307f52SEvan Bacon "android/gradlew", 1868d307f52SEvan Bacon "android/gradlew.bat", 1878d307f52SEvan Bacon "android/settings.gradle", 1888d307f52SEvan Bacon "app.json", 189fa5d5955SEvan Bacon "ios/.gitignore", 1906c8d1802SEvan Bacon "ios/.xcode.env", 1918d307f52SEvan Bacon "ios/Podfile", 1928d307f52SEvan Bacon "ios/Podfile.properties.json", 1938d307f52SEvan Bacon "ios/basicprebuild/AppDelegate.h", 194fa5d5955SEvan Bacon "ios/basicprebuild/AppDelegate.mm", 1958d307f52SEvan Bacon "ios/basicprebuild/Images.xcassets/AppIcon.appiconset/Contents.json", 1968d307f52SEvan Bacon "ios/basicprebuild/Images.xcassets/Contents.json", 1978d307f52SEvan Bacon "ios/basicprebuild/Images.xcassets/SplashScreenBackground.imageset/Contents.json", 1988d307f52SEvan Bacon "ios/basicprebuild/Images.xcassets/SplashScreenBackground.imageset/image.png", 1998d307f52SEvan Bacon "ios/basicprebuild/Info.plist", 2008d307f52SEvan Bacon "ios/basicprebuild/SplashScreen.storyboard", 2018d307f52SEvan Bacon "ios/basicprebuild/Supporting/Expo.plist", 202b6b91c50SEvan Bacon "ios/basicprebuild/basicprebuild-Bridging-Header.h", 2038d307f52SEvan Bacon "ios/basicprebuild/basicprebuild.entitlements", 2048d307f52SEvan Bacon "ios/basicprebuild/main.m", 2058d307f52SEvan Bacon "ios/basicprebuild/noop-file.swift", 2068d307f52SEvan Bacon "ios/basicprebuild.xcodeproj/project.pbxproj", 2078d307f52SEvan Bacon "ios/basicprebuild.xcodeproj/project.xcworkspace/contents.xcworkspacedata", 2088d307f52SEvan Bacon "ios/basicprebuild.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist", 2098d307f52SEvan Bacon "ios/basicprebuild.xcodeproj/xcshareddata/xcschemes/basicprebuild.xcscheme", 2108d307f52SEvan Bacon "package.json", 2118d307f52SEvan Bacon "yarn.lock", 2128d307f52SEvan Bacon ] 2138d307f52SEvan Bacon `); 2148d307f52SEvan Bacon }, 2158d307f52SEvan Bacon // Could take 45s depending on how fast npm installs 2168d307f52SEvan Bacon 60 * 1000 2178d307f52SEvan Bacon); 218