1/* eslint-env jest */
2import JsonFile from '@expo/json-file';
3import fs from 'fs/promises';
4import klawSync from 'klaw-sync';
5import path from 'path';
6import execa from 'execa';
7
8import {
9  execute,
10  projectRoot,
11  getRoot,
12  getLoadedModulesAsync,
13  bin,
14  setupTestProjectAsync,
15} from './utils';
16
17const originalForceColor = process.env.FORCE_COLOR;
18beforeAll(async () => {
19  await fs.mkdir(projectRoot, { recursive: true });
20  process.env.FORCE_COLOR = '0';
21});
22afterAll(() => {
23  process.env.FORCE_COLOR = originalForceColor;
24});
25
26it('loads expected modules by default', async () => {
27  const modules = await getLoadedModulesAsync(`require('../../build/src/install').expoInstall`);
28  expect(modules).toStrictEqual([
29    '../node_modules/ansi-styles/index.js',
30    '../node_modules/arg/index.js',
31    '../node_modules/chalk/source/index.js',
32    '../node_modules/chalk/source/util.js',
33    '../node_modules/has-flag/index.js',
34    '../node_modules/supports-color/index.js',
35    '@expo/cli/build/src/install/index.js',
36    '@expo/cli/build/src/log.js',
37    '@expo/cli/build/src/utils/args.js',
38  ]);
39});
40
41it('runs `npx install install --help`', async () => {
42  const results = await execute('install', '--help');
43  expect(results.stdout).toMatchInlineSnapshot(`
44    "
45      Description
46        Install a module or other package to a project
47
48      Usage
49        $ npx expo install [packages...] [options]
50
51      Options
52        --npm       Use npm to install dependencies. Default when package-lock.json exists
53        --yarn      Use Yarn to install dependencies. Default when yarn.lock exists
54        -h, --help  Output usage information
55
56      Additional options can be passed to the underlying install command by using --
57        $ expo install react -- --verbose
58        > yarn add react --verbose
59        "
60  `);
61});
62
63it(
64  'runs `npx expo install expo-sms`',
65  async () => {
66    const projectRoot = await setupTestProjectAsync('basic-install', 'with-blank');
67    // `npx expo install expo-sms`
68    await execa('node', [bin, 'install', 'expo-sms'], { cwd: projectRoot });
69
70    // List output files with sizes for snapshotting.
71    // This is to make sure that any changes to the output are intentional.
72    // Posix path formatting is used to make paths the same across OSes.
73    const files = klawSync(projectRoot)
74      .map((entry) => {
75        if (entry.path.includes('node_modules') || !entry.stats.isFile()) {
76          return null;
77        }
78        return path.posix.relative(projectRoot, entry.path);
79      })
80      .filter(Boolean);
81
82    const pkg = await JsonFile.readAsync(path.resolve(projectRoot, 'package.json'));
83
84    // Added expected package
85    expect(pkg.dependencies['expo-sms']).toBe('~10.1.0');
86    expect(pkg.devDependencies).toEqual({
87      '@babel/core': '^7.12.9',
88    });
89
90    // Added new packages
91    expect(Object.keys(pkg.dependencies).sort()).toStrictEqual([
92      'expo',
93      'expo-sms',
94      'react',
95      'react-native',
96    ]);
97
98    expect(files).toStrictEqual(['App.js', 'app.json', 'package.json', 'yarn.lock']);
99  },
100  // Could take 45s depending on how fast npm installs
101  60 * 1000
102);
103