1/* eslint-env jest */ 2import JsonFile from '@expo/json-file'; 3import execa, { ExecaError } from 'execa'; 4import fs from 'fs/promises'; 5import klawSync from 'klaw-sync'; 6import path from 'path'; 7 8import { 9 execute, 10 projectRoot, 11 getLoadedModulesAsync, 12 bin, 13 setupTestProjectAsync, 14 installAsync, 15} from './utils'; 16 17const originalForceColor = process.env.FORCE_COLOR; 18const originalCI = process.env.CI; 19beforeAll(async () => { 20 await fs.mkdir(projectRoot, { recursive: true }); 21 process.env.FORCE_COLOR = '0'; 22 process.env.CI = '1'; 23}); 24afterAll(() => { 25 process.env.FORCE_COLOR = originalForceColor; 26 process.env.CI = originalCI; 27}); 28 29it('loads expected modules by default', async () => { 30 const modules = await getLoadedModulesAsync(`require('../../build/src/install').expoInstall`); 31 expect(modules).toStrictEqual([ 32 '../node_modules/ansi-styles/index.js', 33 '../node_modules/arg/index.js', 34 '../node_modules/chalk/source/index.js', 35 '../node_modules/chalk/source/util.js', 36 '../node_modules/has-flag/index.js', 37 '../node_modules/supports-color/index.js', 38 '@expo/cli/build/src/install/index.js', 39 '@expo/cli/build/src/log.js', 40 '@expo/cli/build/src/utils/args.js', 41 ]); 42}); 43 44it('runs `npx install install --help`', async () => { 45 const results = await execute('install', '--help'); 46 expect(results.stdout).toMatchInlineSnapshot(` 47 " 48 Info 49 Install a module or other package to a project 50 51 Usage 52 $ npx expo install 53 54 Options 55 --check Check which installed packages need to be updated 56 --fix Automatically update any invalid package versions 57 --npm Use npm to install dependencies. Default when package-lock.json exists 58 --yarn Use Yarn to install dependencies. Default when yarn.lock exists 59 --pnpm Use pnpm to install dependencies. Default when pnpm-lock.yaml exists 60 -h, --help Usage info 61 62 Additional options can be passed to the underlying install command by using -- 63 $ npx expo install react -- --verbose 64 > yarn add react --verbose 65 " 66 `); 67}); 68 69it( 70 'runs `npx expo install expo-sms`', 71 async () => { 72 const projectRoot = await setupTestProjectAsync('basic-install', 'with-blank'); 73 // `npx expo install expo-sms` 74 await execa('node', [bin, 'install', 'expo-sms'], { cwd: projectRoot }); 75 76 // List output files with sizes for snapshotting. 77 // This is to make sure that any changes to the output are intentional. 78 // Posix path formatting is used to make paths the same across OSes. 79 const files = klawSync(projectRoot) 80 .map((entry) => { 81 if (entry.path.includes('node_modules') || !entry.stats.isFile()) { 82 return null; 83 } 84 return path.posix.relative(projectRoot, entry.path); 85 }) 86 .filter(Boolean); 87 88 const pkg = await JsonFile.readAsync(path.resolve(projectRoot, 'package.json')); 89 90 // Added expected package 91 const pkgDependencies = pkg.dependencies as Record<string, string>; 92 expect(pkgDependencies['expo-sms']).toBe('~11.0.0'); 93 expect(pkg.devDependencies).toEqual({ 94 '@babel/core': '^7.12.9', 95 }); 96 97 // Added new packages 98 expect(Object.keys(pkg.dependencies ?? {}).sort()).toStrictEqual([ 99 'expo', 100 'expo-sms', 101 'react', 102 'react-native', 103 ]); 104 105 expect(files).toStrictEqual(['App.js', 'app.json', 'package.json', 'yarn.lock']); 106 }, 107 // Could take 45s depending on how fast npm installs 108 60 * 1000 109); 110 111it( 112 'runs `npx expo install --check` fails', 113 async () => { 114 const projectRoot = await setupTestProjectAsync('install-check-fail', 'with-blank'); 115 await installAsync(projectRoot, ['add', '[email protected]', '[email protected]']); 116 117 let pkg = await JsonFile.readAsync(path.resolve(projectRoot, 'package.json')); 118 // Added expected package 119 let pkgDependencies = pkg.dependencies as Record<string, string>; 120 expect(pkgDependencies['expo-sms']).toBe('1.0.0'); 121 122 try { 123 await execa('node', [bin, 'install', '--check'], { cwd: projectRoot }); 124 throw new Error('SHOULD NOT HAPPEN'); 125 } catch (e) { 126 const error = e as ExecaError; 127 expect(error.stderr).toMatch(/expo-auth-session@1\.0\.0 - expected version: ~3\.\d\.\d/); 128 expect(error.stderr).toMatch(/expo-sms@1\.0\.0 - expected version: ~11\.\d\.\d/); 129 expect(error.stderr).toMatch(/npx expo install --fix/); 130 } 131 132 await expect( 133 execa('node', [bin, 'install', 'expo-sms', '--check'], { cwd: projectRoot }) 134 ).rejects.toThrowError(/expo-sms@1\.0\.0 - expected version: ~11\.\d\.\d/); 135 136 // Check doesn't fix packages 137 pkg = await JsonFile.readAsync(path.resolve(projectRoot, 'package.json')); 138 // Added expected package 139 pkgDependencies = pkg.dependencies as Record<string, string>; 140 expect(pkgDependencies['expo-sms']).toBe('1.0.0'); 141 }, 142 // Could take 45s depending on how fast npm installs 143 60 * 1000 144); 145 146it( 147 'runs `npx expo install --fix` fails', 148 async () => { 149 const projectRoot = await setupTestProjectAsync('install-fix-fail', 'with-blank'); 150 await installAsync(projectRoot, ['add', '[email protected]', '[email protected]']); 151 152 await execa('node', [bin, 'install', '--fix', 'expo-sms'], { cwd: projectRoot }); 153 154 // Ensure the versions are invalid 155 await expect( 156 execa('node', [bin, 'install', '--check'], { cwd: projectRoot }) 157 ).rejects.toThrow(); 158 159 // Check doesn't fix packages 160 let pkg = await JsonFile.readAsync(path.resolve(projectRoot, 'package.json')); 161 // Added expected package 162 let pkgDependencies = pkg.dependencies as Record<string, string>; 163 expect(pkgDependencies['expo-sms']).toBe('~11.0.0'); 164 165 // Didn't fix expo-auth-session since we didn't pass it in 166 expect(pkgDependencies['expo-auth-session']).toBe('1.0.0'); 167 168 // Fix all versions 169 await execa('node', [bin, 'install', '--fix'], { cwd: projectRoot }); 170 171 // Check that the versions are fixed 172 pkg = await JsonFile.readAsync(path.resolve(projectRoot, 'package.json')); 173 174 // Didn't fix expo-auth-session since we didn't pass it in 175 pkgDependencies = pkg.dependencies as Record<string, string>; 176 expect(pkgDependencies['expo-auth-session']).toBe('~3.8.0'); 177 }, 178 // Could take 45s depending on how fast npm installs 179 60 * 1000 180); 181