1/* eslint-env jest */ 2import JsonFile from '@expo/json-file'; 3import execa from 'execa'; 4import fs from 'fs/promises'; 5import klawSync from 'klaw-sync'; 6import path from 'path'; 7 8import { 9 bin, 10 execute, 11 projectRoot, 12 getRoot, 13 setupTestProjectAsync, 14 getLoadedModulesAsync, 15} from './utils'; 16 17const originalForceColor = process.env.FORCE_COLOR; 18const originalCI = process.env.CI; 19 20beforeAll(async () => { 21 await fs.mkdir(projectRoot, { recursive: true }); 22 process.env.FORCE_COLOR = '0'; 23 process.env.CI = '1'; 24}); 25 26afterAll(() => { 27 process.env.FORCE_COLOR = originalForceColor; 28 process.env.CI = originalCI; 29}); 30 31it('loads expected modules by default', async () => { 32 const modules = await getLoadedModulesAsync(`require('../../build/src/prebuild').expoPrebuild`); 33 expect(modules).toStrictEqual([ 34 '../node_modules/ansi-styles/index.js', 35 '../node_modules/arg/index.js', 36 '../node_modules/chalk/source/index.js', 37 '../node_modules/chalk/source/util.js', 38 '../node_modules/has-flag/index.js', 39 '../node_modules/supports-color/index.js', 40 '@expo/cli/build/src/log.js', 41 '@expo/cli/build/src/prebuild/index.js', 42 '@expo/cli/build/src/utils/args.js', 43 ]); 44}); 45 46it('runs `npx expo prebuild --help`', async () => { 47 const results = await execute('prebuild', '--help'); 48 expect(results.stdout).toMatchInlineSnapshot(` 49 " 50 Description 51 Create native iOS and Android project files before building natively. 52 53 Usage 54 $ npx expo prebuild <dir> 55 56 <dir> is the directory of the Expo project. 57 Defaults to the current working directory. 58 59 Options 60 --no-install Skip installing npm packages and CocoaPods. 61 --clean Delete the native folders and regenerate them before applying changes 62 --npm Use npm to install dependencies. (default when Yarn is not installed) 63 --template <template> Project template to clone from. File path pointing to a local tar file or a github repo 64 -p, --platform <all|android|ios> Platforms to sync: ios, android, all. Default: all 65 --skip-dependency-update <dependencies> Preserves versions of listed packages in package.json (comma separated list) 66 -h, --help Output usage information 67 68 " 69 `); 70}); 71 72it('runs `npx expo prebuild` asserts when expo is not installed', async () => { 73 const projectName = 'basic-prebuild-assert-no-expo'; 74 const projectRoot = getRoot(projectName); 75 // Create the project root aot 76 await fs.mkdir(projectRoot, { recursive: true }); 77 // Create a fake package.json -- this is a terminal file that cannot be overwritten. 78 await fs.writeFile(path.join(projectRoot, 'package.json'), '{ "version": "1.0.0" }'); 79 await fs.writeFile(path.join(projectRoot, 'app.json'), '{ "expo": { "name": "foobar" } }'); 80 81 await expect(execute('prebuild', projectName, '--no-install')).rejects.toThrowError( 82 /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./ 83 ); 84}); 85 86it( 87 'runs `npx expo prebuild`', 88 async () => { 89 const projectRoot = await setupTestProjectAsync('basic-prebuild', 'with-blank'); 90 // `npx expo prebuild --no-install` 91 await execa('node', [bin, 'prebuild', '--no-install'], { cwd: projectRoot }); 92 93 // List output files with sizes for snapshotting. 94 // This is to make sure that any changes to the output are intentional. 95 // Posix path formatting is used to make paths the same across OSes. 96 const files = klawSync(projectRoot) 97 .map((entry) => { 98 if (entry.path.includes('node_modules') || !entry.stats.isFile()) { 99 return null; 100 } 101 return path.posix.relative(projectRoot, entry.path); 102 }) 103 .filter(Boolean); 104 105 const pkg = await JsonFile.readAsync(path.resolve(projectRoot, 'package.json')); 106 107 // Deleted 108 expect(pkg.main).not.toBeDefined(); 109 110 // Added new packages 111 expect(Object.keys(pkg.dependencies).sort()).toStrictEqual([ 112 'expo', 113 'expo-splash-screen', 114 'expo-status-bar', 115 'react', 116 'react-dom', 117 'react-native', 118 'react-native-web', 119 ]); 120 121 // Updated scripts 122 expect(pkg.scripts).toStrictEqual({ 123 android: 'expo run:android', 124 ios: 'expo run:ios', 125 start: 'expo start --dev-client', 126 }); 127 128 // If this changes then everything else probably changed as well. 129 expect(files).toMatchInlineSnapshot(` 130 Array [ 131 "App.js", 132 "android/app/BUCK", 133 "android/app/build.gradle", 134 "android/app/build_defs.bzl", 135 "android/app/debug.keystore", 136 "android/app/proguard-rules.pro", 137 "android/app/src/debug/AndroidManifest.xml", 138 "android/app/src/debug/java/com/example/minimal/ReactNativeFlipper.java", 139 "android/app/src/main/AndroidManifest.xml", 140 "android/app/src/main/java/com/example/minimal/MainActivity.java", 141 "android/app/src/main/java/com/example/minimal/MainApplication.java", 142 "android/app/src/main/res/drawable/splashscreen.xml", 143 "android/app/src/main/res/mipmap-hdpi/ic_launcher.png", 144 "android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png", 145 "android/app/src/main/res/mipmap-mdpi/ic_launcher.png", 146 "android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png", 147 "android/app/src/main/res/mipmap-xhdpi/ic_launcher.png", 148 "android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png", 149 "android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png", 150 "android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png", 151 "android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png", 152 "android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png", 153 "android/app/src/main/res/values/colors.xml", 154 "android/app/src/main/res/values/strings.xml", 155 "android/app/src/main/res/values/styles.xml", 156 "android/app/src/main/res/values-night/colors.xml", 157 "android/build.gradle", 158 "android/gradle/wrapper/gradle-wrapper.jar", 159 "android/gradle/wrapper/gradle-wrapper.properties", 160 "android/gradle.properties", 161 "android/gradlew", 162 "android/gradlew.bat", 163 "android/settings.gradle", 164 "app.json", 165 "index.js", 166 "ios/Podfile", 167 "ios/Podfile.properties.json", 168 "ios/basicprebuild/AppDelegate.h", 169 "ios/basicprebuild/AppDelegate.m", 170 "ios/basicprebuild/Images.xcassets/AppIcon.appiconset/Contents.json", 171 "ios/basicprebuild/Images.xcassets/Contents.json", 172 "ios/basicprebuild/Images.xcassets/SplashScreenBackground.imageset/Contents.json", 173 "ios/basicprebuild/Images.xcassets/SplashScreenBackground.imageset/image.png", 174 "ios/basicprebuild/Info.plist", 175 "ios/basicprebuild/SplashScreen.storyboard", 176 "ios/basicprebuild/Supporting/Expo.plist", 177 "ios/basicprebuild/basicprebuild-Bridging-Header.h", 178 "ios/basicprebuild/basicprebuild.entitlements", 179 "ios/basicprebuild/main.m", 180 "ios/basicprebuild/noop-file.swift", 181 "ios/basicprebuild.xcodeproj/project.pbxproj", 182 "ios/basicprebuild.xcodeproj/project.xcworkspace/contents.xcworkspacedata", 183 "ios/basicprebuild.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist", 184 "ios/basicprebuild.xcodeproj/project.xcworkspace/xcuserdata/brentvatne.xcuserdatad/UserInterfaceState.xcuserstate", 185 "ios/basicprebuild.xcodeproj/xcshareddata/xcschemes/basicprebuild.xcscheme", 186 "metro.config.js", 187 "package.json", 188 "yarn.lock", 189 ] 190 `); 191 }, 192 // Could take 45s depending on how fast npm installs 193 60 * 1000 194); 195