18d3f3824SCedric van Puttenimport spawnAsync from '@expo/spawn-async';
28d3f3824SCedric van Puttenimport { vol } from 'memfs';
38d3f3824SCedric van Puttenimport path from 'path';
48d3f3824SCedric van Putten
58d3f3824SCedric van Puttenimport { mockSpawnPromise, mockedSpawnAsync, STUB_SPAWN_CHILD } from '../../__tests__/spawn-utils';
68d3f3824SCedric van Puttenimport { NpmPackageManager } from '../NpmPackageManager';
78d3f3824SCedric van Putten
88d3f3824SCedric van Puttenjest.mock('@expo/spawn-async');
98d3f3824SCedric van Puttenjest.mock('fs');
108d3f3824SCedric van Putten
118d3f3824SCedric van PuttenbeforeAll(() => {
128d3f3824SCedric van Putten  // Disable logging to clean up test ouput
138d3f3824SCedric van Putten  jest.spyOn(console, 'log').mockImplementation();
148d3f3824SCedric van Putten});
158d3f3824SCedric van Putten
168d3f3824SCedric van Puttendescribe('NpmPackageManager', () => {
178d3f3824SCedric van Putten  const projectRoot = '/project/with-npm';
188d3f3824SCedric van Putten
198d3f3824SCedric van Putten  it('name is set to npm', () => {
208d3f3824SCedric van Putten    const npm = new NpmPackageManager({ cwd: projectRoot });
218d3f3824SCedric van Putten    expect(npm.name).toBe('npm');
228d3f3824SCedric van Putten  });
238d3f3824SCedric van Putten
248d3f3824SCedric van Putten  describe('getDefaultEnvironment', () => {
258d3f3824SCedric van Putten    it('runs npm with ADBLOCK=1 and DISABLE_OPENCOLLECTIVE=1', async () => {
268d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
278d3f3824SCedric van Putten      await npm.installAsync();
288d3f3824SCedric van Putten
298d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
308d3f3824SCedric van Putten        expect.anything(),
318d3f3824SCedric van Putten        expect.anything(),
328d3f3824SCedric van Putten        expect.objectContaining({
338d3f3824SCedric van Putten          env: expect.objectContaining({ ADBLOCK: '1', DISABLE_OPENCOLLECTIVE: '1' }),
348d3f3824SCedric van Putten        })
358d3f3824SCedric van Putten      );
368d3f3824SCedric van Putten    });
378d3f3824SCedric van Putten
388d3f3824SCedric van Putten    it('runs with overwritten default environment', async () => {
398d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot, env: { ADBLOCK: '0' } });
408d3f3824SCedric van Putten      await npm.installAsync();
418d3f3824SCedric van Putten
428d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
438d3f3824SCedric van Putten        expect.anything(),
448d3f3824SCedric van Putten        expect.anything(),
458d3f3824SCedric van Putten        expect.objectContaining({
468d3f3824SCedric van Putten          env: { ADBLOCK: '0', DISABLE_OPENCOLLECTIVE: '1' },
478d3f3824SCedric van Putten        })
488d3f3824SCedric van Putten      );
498d3f3824SCedric van Putten    });
508d3f3824SCedric van Putten  });
518d3f3824SCedric van Putten
528d3f3824SCedric van Putten  describe('runAsync', () => {
538d3f3824SCedric van Putten    it('logs executed command', async () => {
548d3f3824SCedric van Putten      const log = jest.fn();
558d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot, log });
568d3f3824SCedric van Putten      await npm.runAsync(['install', '--some-flag']);
578d3f3824SCedric van Putten      expect(log).toHaveBeenCalledWith('> npm install --some-flag');
588d3f3824SCedric van Putten    });
598d3f3824SCedric van Putten
60*efdcf92fSCedric van Putten    it('inherits stdio output without silent', async () => {
618d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
62*efdcf92fSCedric van Putten      await npm.runAsync(['install']);
638d3f3824SCedric van Putten
64*efdcf92fSCedric van Putten      expect(spawnAsync).toBeCalledWith(
65*efdcf92fSCedric van Putten        expect.anything(),
66*efdcf92fSCedric van Putten        expect.anything(),
67*efdcf92fSCedric van Putten        expect.objectContaining({ stdio: 'inherit' })
688d3f3824SCedric van Putten      );
698d3f3824SCedric van Putten    });
708d3f3824SCedric van Putten
71*efdcf92fSCedric van Putten    it('does not inherit stdio with silent', async () => {
728d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot, silent: true });
73*efdcf92fSCedric van Putten      await npm.runAsync(['install']);
748d3f3824SCedric van Putten
75*efdcf92fSCedric van Putten      expect(spawnAsync).toBeCalledWith(
76*efdcf92fSCedric van Putten        expect.anything(),
77*efdcf92fSCedric van Putten        expect.anything(),
78*efdcf92fSCedric van Putten        expect.objectContaining({ stdio: undefined })
798d3f3824SCedric van Putten      );
808d3f3824SCedric van Putten    });
818d3f3824SCedric van Putten
828d3f3824SCedric van Putten    it('returns spawn promise with child', () => {
838d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
848d3f3824SCedric van Putten      expect(npm.runAsync(['install'])).toHaveProperty(
858d3f3824SCedric van Putten        'child',
868d3f3824SCedric van Putten        expect.objectContaining(STUB_SPAWN_CHILD)
878d3f3824SCedric van Putten      );
888d3f3824SCedric van Putten    });
898d3f3824SCedric van Putten
908d3f3824SCedric van Putten    it('adds a single package with custom parameters', async () => {
918d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
928d3f3824SCedric van Putten      await npm.runAsync(['install', '--save-peer', '@babel/core']);
938d3f3824SCedric van Putten
948d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
958d3f3824SCedric van Putten        'npm',
968d3f3824SCedric van Putten        ['install', '--save-peer', '@babel/core'],
978d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
988d3f3824SCedric van Putten      );
998d3f3824SCedric van Putten    });
1008d3f3824SCedric van Putten
1018d3f3824SCedric van Putten    it('adds multiple packages with custom parameters', async () => {
1028d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
1038d3f3824SCedric van Putten      await npm.runAsync(['install', '--save-peer', '@babel/core', '@babel/runtime']);
1048d3f3824SCedric van Putten
1058d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
1068d3f3824SCedric van Putten        'npm',
1078d3f3824SCedric van Putten        ['install', '--save-peer', '@babel/core', '@babel/runtime'],
1088d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
1098d3f3824SCedric van Putten      );
1108d3f3824SCedric van Putten    });
1118d3f3824SCedric van Putten  });
1128d3f3824SCedric van Putten
1138d3f3824SCedric van Putten  describe('versionAsync', () => {
1148d3f3824SCedric van Putten    it('returns version from npm', async () => {
1158d3f3824SCedric van Putten      mockedSpawnAsync.mockImplementation(() =>
1168d3f3824SCedric van Putten        mockSpawnPromise(Promise.resolve({ stdout: '7.0.0\n' }))
1178d3f3824SCedric van Putten      );
1188d3f3824SCedric van Putten
1198d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
1208d3f3824SCedric van Putten
1218d3f3824SCedric van Putten      expect(await npm.versionAsync()).toBe('7.0.0');
1228d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith('npm', ['--version'], expect.anything());
1238d3f3824SCedric van Putten    });
1248d3f3824SCedric van Putten  });
1258d3f3824SCedric van Putten
1268d3f3824SCedric van Putten  describe('getConfigAsync', () => {
1278d3f3824SCedric van Putten    it('returns a configuration key from npm', async () => {
1288d3f3824SCedric van Putten      mockedSpawnAsync.mockImplementation(() =>
1298d3f3824SCedric van Putten        mockSpawnPromise(Promise.resolve({ stdout: 'https://custom.registry.org/\n' }))
1308d3f3824SCedric van Putten      );
1318d3f3824SCedric van Putten
1328d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
1338d3f3824SCedric van Putten
1348d3f3824SCedric van Putten      expect(await npm.getConfigAsync('registry')).toBe('https://custom.registry.org/');
1358d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith('npm', ['config', 'get', 'registry'], expect.anything());
1368d3f3824SCedric van Putten    });
1378d3f3824SCedric van Putten  });
1388d3f3824SCedric van Putten
1398d3f3824SCedric van Putten  describe('installAsync', () => {
1408d3f3824SCedric van Putten    it('runs normal installation', async () => {
1418d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
1428d3f3824SCedric van Putten      await npm.installAsync();
1438d3f3824SCedric van Putten
1448d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
1458d3f3824SCedric van Putten        'npm',
1468d3f3824SCedric van Putten        ['install'],
1478d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
1488d3f3824SCedric van Putten      );
1498d3f3824SCedric van Putten    });
1508d3f3824SCedric van Putten
1518d3f3824SCedric van Putten    it('runs installation with flags', async () => {
1528d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
1538d3f3824SCedric van Putten      await npm.installAsync(['--ignore-scripts']);
1548d3f3824SCedric van Putten
1558d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
1568d3f3824SCedric van Putten        'npm',
1578d3f3824SCedric van Putten        ['install', '--ignore-scripts'],
1588d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
1598d3f3824SCedric van Putten      );
1608d3f3824SCedric van Putten    });
1618d3f3824SCedric van Putten  });
1628d3f3824SCedric van Putten
1638d3f3824SCedric van Putten  describe('uninstallAsync', () => {
1648d3f3824SCedric van Putten    afterEach(() => vol.reset());
1658d3f3824SCedric van Putten
1668d3f3824SCedric van Putten    it('removes node_modules folder relative to cwd', async () => {
1678d3f3824SCedric van Putten      vol.fromJSON(
1688d3f3824SCedric van Putten        {
1698d3f3824SCedric van Putten          'package.json': '{}',
1708d3f3824SCedric van Putten          'node_modules/expo/package.json': '{}',
1718d3f3824SCedric van Putten        },
1728d3f3824SCedric van Putten        projectRoot
1738d3f3824SCedric van Putten      );
1748d3f3824SCedric van Putten
1758d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
1768d3f3824SCedric van Putten      await npm.uninstallAsync();
1778d3f3824SCedric van Putten
1788d3f3824SCedric van Putten      expect(vol.existsSync(path.join(projectRoot, 'node_modules'))).toBe(false);
1798d3f3824SCedric van Putten    });
1808d3f3824SCedric van Putten
1818d3f3824SCedric van Putten    it('skips removing non-existing node_modules folder', async () => {
1828d3f3824SCedric van Putten      vol.fromJSON({ 'package.json': '{}' }, projectRoot);
1838d3f3824SCedric van Putten
1848d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
1858d3f3824SCedric van Putten      await npm.uninstallAsync();
1868d3f3824SCedric van Putten
1878d3f3824SCedric van Putten      expect(vol.existsSync(path.join(projectRoot, 'node_modules'))).toBe(false);
1888d3f3824SCedric van Putten    });
1898d3f3824SCedric van Putten
1908d3f3824SCedric van Putten    it('fails when no cwd is provided', async () => {
1918d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: undefined });
1928d3f3824SCedric van Putten      await expect(npm.uninstallAsync()).rejects.toThrow('cwd is required');
1938d3f3824SCedric van Putten    });
1948d3f3824SCedric van Putten  });
1958d3f3824SCedric van Putten
1968d3f3824SCedric van Putten  describe('addAsync', () => {
1978d3f3824SCedric van Putten    it('installs project without packages', async () => {
1988d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
1998d3f3824SCedric van Putten      await npm.addAsync();
2008d3f3824SCedric van Putten
2018d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
2028d3f3824SCedric van Putten        'npm',
2038d3f3824SCedric van Putten        ['install'],
2048d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
2058d3f3824SCedric van Putten      );
2068d3f3824SCedric van Putten    });
2078d3f3824SCedric van Putten
2088d3f3824SCedric van Putten    it('returns pending spawn promise with child', async () => {
2098d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
2108d3f3824SCedric van Putten      const pending = npm.addAsync(['expo']);
2118d3f3824SCedric van Putten
2128d3f3824SCedric van Putten      expect(pending).toHaveProperty('child', expect.any(Promise));
2138d3f3824SCedric van Putten      await expect(pending.child).resolves.toMatchObject(STUB_SPAWN_CHILD);
2148d3f3824SCedric van Putten    });
2158d3f3824SCedric van Putten
2168d3f3824SCedric van Putten    it('adds a single unversioned package to dependencies', async () => {
2178d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
2188d3f3824SCedric van Putten      await npm.addAsync(['expo']);
2198d3f3824SCedric van Putten
2208d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
2218d3f3824SCedric van Putten        'npm',
2228d3f3824SCedric van Putten        ['install', '--save', 'expo'],
2238d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
2248d3f3824SCedric van Putten      );
2258d3f3824SCedric van Putten    });
2268d3f3824SCedric van Putten
2278d3f3824SCedric van Putten    it('adds a multiple unversioned package to dependencies', async () => {
2288d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
2298d3f3824SCedric van Putten      await npm.addAsync(['expo', 'react-native']);
2308d3f3824SCedric van Putten
2318d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
2328d3f3824SCedric van Putten        'npm',
2338d3f3824SCedric van Putten        ['install', '--save', 'expo', 'react-native'],
2348d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
2358d3f3824SCedric van Putten      );
2368d3f3824SCedric van Putten    });
2378d3f3824SCedric van Putten
2388d3f3824SCedric van Putten    it('installs multiple versioned dependencies by updating package.json', async () => {
2398d3f3824SCedric van Putten      vol.fromJSON({ 'package.json': '{}' }, projectRoot);
2408d3f3824SCedric van Putten
2418d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
2428d3f3824SCedric van Putten      await npm.addAsync(['expo@^46', '[email protected]']);
2438d3f3824SCedric van Putten
2448d3f3824SCedric van Putten      const packageFile = JSON.parse(
2458d3f3824SCedric van Putten        vol.readFileSync(path.join(projectRoot, 'package.json')).toString()
2468d3f3824SCedric van Putten      );
2478d3f3824SCedric van Putten
2488d3f3824SCedric van Putten      expect(packageFile).toHaveProperty(
2498d3f3824SCedric van Putten        'dependencies',
2508d3f3824SCedric van Putten        expect.objectContaining({ expo: '^46', 'react-native': '0.69.3' })
2518d3f3824SCedric van Putten      );
2528d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
2538d3f3824SCedric van Putten        'npm',
2548d3f3824SCedric van Putten        ['install'],
2558d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
2568d3f3824SCedric van Putten      );
2578d3f3824SCedric van Putten    });
2588d3f3824SCedric van Putten
2598d3f3824SCedric van Putten    it('installs mixed dependencies with flags by updating package.json', async () => {
2608d3f3824SCedric van Putten      vol.fromJSON({ 'package.json': '{}' }, projectRoot);
2618d3f3824SCedric van Putten
2628d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
2638d3f3824SCedric van Putten      await npm.addAsync(['expo@^46', '[email protected]', 'jest', '--ignore-scripts']);
2648d3f3824SCedric van Putten
2658d3f3824SCedric van Putten      const packageFile = JSON.parse(
2668d3f3824SCedric van Putten        vol.readFileSync(path.join(projectRoot, 'package.json')).toString()
2678d3f3824SCedric van Putten      );
2688d3f3824SCedric van Putten
2698d3f3824SCedric van Putten      expect(packageFile).toHaveProperty(
2708d3f3824SCedric van Putten        'dependencies',
2718d3f3824SCedric van Putten        expect.objectContaining({ expo: '^46', 'react-native': '0.69.3' })
2728d3f3824SCedric van Putten      );
2738d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
2748d3f3824SCedric van Putten        'npm',
2758d3f3824SCedric van Putten        ['install', '--save', '--ignore-scripts', 'jest'],
2768d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
2778d3f3824SCedric van Putten      );
2788d3f3824SCedric van Putten    });
2798d3f3824SCedric van Putten
2808d3f3824SCedric van Putten    it('installs dist-tag versions with --save', async () => {
2818d3f3824SCedric van Putten      vol.fromJSON({ 'package.json': '{}' }, projectRoot);
2828d3f3824SCedric van Putten
2838d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
2848d3f3824SCedric van Putten      await npm.addAsync(['[email protected]', 'expo@next']);
2858d3f3824SCedric van Putten
2868d3f3824SCedric van Putten      const packageFile = JSON.parse(
2878d3f3824SCedric van Putten        vol.readFileSync(path.join(projectRoot, 'package.json')).toString()
2888d3f3824SCedric van Putten      );
2898d3f3824SCedric van Putten
2908d3f3824SCedric van Putten      expect(packageFile).toHaveProperty(
2918d3f3824SCedric van Putten        'dependencies',
2928d3f3824SCedric van Putten        expect.objectContaining({ 'react-native': '0.69.3' })
2938d3f3824SCedric van Putten      );
2948d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
2958d3f3824SCedric van Putten        'npm',
2968d3f3824SCedric van Putten        ['install', '--save', 'expo@next'],
2978d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
2988d3f3824SCedric van Putten      );
2998d3f3824SCedric van Putten    });
3008d3f3824SCedric van Putten  });
3018d3f3824SCedric van Putten
3028d3f3824SCedric van Putten  describe('addDevAsync', () => {
3038d3f3824SCedric van Putten    it('installs project without packages', async () => {
3048d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
3058d3f3824SCedric van Putten      await npm.addDevAsync();
3068d3f3824SCedric van Putten
3078d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
3088d3f3824SCedric van Putten        'npm',
3098d3f3824SCedric van Putten        ['install'],
3108d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
3118d3f3824SCedric van Putten      );
3128d3f3824SCedric van Putten    });
3138d3f3824SCedric van Putten
3148d3f3824SCedric van Putten    it('returns pending spawn promise with child', async () => {
3158d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
3168d3f3824SCedric van Putten      const pending = npm.addDevAsync(['expo']);
3178d3f3824SCedric van Putten
3188d3f3824SCedric van Putten      expect(pending).toHaveProperty('child', expect.any(Promise));
3198d3f3824SCedric van Putten      await expect(pending.child).resolves.toMatchObject(STUB_SPAWN_CHILD);
3208d3f3824SCedric van Putten    });
3218d3f3824SCedric van Putten
3228d3f3824SCedric van Putten    it('adds a single unversioned package to dependencies', async () => {
3238d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
3248d3f3824SCedric van Putten      await npm.addDevAsync(['expo']);
3258d3f3824SCedric van Putten
3268d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
3278d3f3824SCedric van Putten        'npm',
3288d3f3824SCedric van Putten        ['install', '--save-dev', 'expo'],
3298d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
3308d3f3824SCedric van Putten      );
3318d3f3824SCedric van Putten    });
3328d3f3824SCedric van Putten
3338d3f3824SCedric van Putten    it('adds a multiple unversioned package to dependencies', async () => {
3348d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
3358d3f3824SCedric van Putten      await npm.addDevAsync(['expo', 'react-native']);
3368d3f3824SCedric van Putten
3378d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
3388d3f3824SCedric van Putten        'npm',
3398d3f3824SCedric van Putten        ['install', '--save-dev', 'expo', 'react-native'],
3408d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
3418d3f3824SCedric van Putten      );
3428d3f3824SCedric van Putten    });
3438d3f3824SCedric van Putten
3448d3f3824SCedric van Putten    it('installs multiple versioned dependencies by updating package.json', async () => {
3458d3f3824SCedric van Putten      vol.fromJSON({ 'package.json': '{}' }, projectRoot);
3468d3f3824SCedric van Putten
3478d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
3488d3f3824SCedric van Putten      await npm.addDevAsync(['expo@^46', '[email protected]']);
3498d3f3824SCedric van Putten
3508d3f3824SCedric van Putten      const packageFile = JSON.parse(
3518d3f3824SCedric van Putten        vol.readFileSync(path.join(projectRoot, 'package.json')).toString()
3528d3f3824SCedric van Putten      );
3538d3f3824SCedric van Putten
3548d3f3824SCedric van Putten      expect(packageFile).toHaveProperty(
3558d3f3824SCedric van Putten        'devDependencies',
3568d3f3824SCedric van Putten        expect.objectContaining({ expo: '^46', 'react-native': '0.69.3' })
3578d3f3824SCedric van Putten      );
3588d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
3598d3f3824SCedric van Putten        'npm',
3608d3f3824SCedric van Putten        ['install'],
3618d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
3628d3f3824SCedric van Putten      );
3638d3f3824SCedric van Putten    });
3648d3f3824SCedric van Putten
3658d3f3824SCedric van Putten    it('installs mixed dependencies with flags by updating package.json', async () => {
3668d3f3824SCedric van Putten      vol.fromJSON({ 'package.json': '{}' }, projectRoot);
3678d3f3824SCedric van Putten
3688d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
3698d3f3824SCedric van Putten      await npm.addDevAsync(['expo@^46', '[email protected]', 'jest', '--ignore-scripts']);
3708d3f3824SCedric van Putten
3718d3f3824SCedric van Putten      const packageFile = JSON.parse(
3728d3f3824SCedric van Putten        vol.readFileSync(path.join(projectRoot, 'package.json')).toString()
3738d3f3824SCedric van Putten      );
3748d3f3824SCedric van Putten
3758d3f3824SCedric van Putten      expect(packageFile).toHaveProperty(
3768d3f3824SCedric van Putten        'devDependencies',
3778d3f3824SCedric van Putten        expect.objectContaining({ expo: '^46', 'react-native': '0.69.3' })
3788d3f3824SCedric van Putten      );
3798d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
3808d3f3824SCedric van Putten        'npm',
3818d3f3824SCedric van Putten        ['install', '--save-dev', '--ignore-scripts', 'jest'],
3828d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
3838d3f3824SCedric van Putten      );
3848d3f3824SCedric van Putten    });
3858d3f3824SCedric van Putten
3868d3f3824SCedric van Putten    it('installs dist-tag versions with --save', async () => {
3878d3f3824SCedric van Putten      vol.fromJSON({ 'package.json': '{}' }, projectRoot);
3888d3f3824SCedric van Putten
3898d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
3908d3f3824SCedric van Putten      await npm.addDevAsync(['[email protected]', 'expo@next']);
3918d3f3824SCedric van Putten
3928d3f3824SCedric van Putten      const packageFile = JSON.parse(
3938d3f3824SCedric van Putten        vol.readFileSync(path.join(projectRoot, 'package.json')).toString()
3948d3f3824SCedric van Putten      );
3958d3f3824SCedric van Putten
3968d3f3824SCedric van Putten      expect(packageFile).toHaveProperty(
3978d3f3824SCedric van Putten        'devDependencies',
3988d3f3824SCedric van Putten        expect.objectContaining({ 'react-native': '0.69.3' })
3998d3f3824SCedric van Putten      );
4008d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
4018d3f3824SCedric van Putten        'npm',
4028d3f3824SCedric van Putten        ['install', '--save-dev', 'expo@next'],
4038d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
4048d3f3824SCedric van Putten      );
4058d3f3824SCedric van Putten    });
4068d3f3824SCedric van Putten  });
4078d3f3824SCedric van Putten
4088d3f3824SCedric van Putten  describe('addGlobalAsync', () => {
4098d3f3824SCedric van Putten    it('installs project without packages', async () => {
4108d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
4118d3f3824SCedric van Putten      await npm.addGlobalAsync();
4128d3f3824SCedric van Putten
4138d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
4148d3f3824SCedric van Putten        'npm',
4158d3f3824SCedric van Putten        ['install'],
4168d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
4178d3f3824SCedric van Putten      );
4188d3f3824SCedric van Putten    });
4198d3f3824SCedric van Putten
4208d3f3824SCedric van Putten    it('adds a single package globally', async () => {
4218d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
4228d3f3824SCedric van Putten      await npm.addGlobalAsync(['expo-cli@^5']);
4238d3f3824SCedric van Putten
4248d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
4258d3f3824SCedric van Putten        'npm',
4268d3f3824SCedric van Putten        ['install', '--global', 'expo-cli@^5'],
4278d3f3824SCedric van Putten        expect.anything()
4288d3f3824SCedric van Putten      );
4298d3f3824SCedric van Putten    });
4308d3f3824SCedric van Putten
4318d3f3824SCedric van Putten    it('adds multiple packages globally', async () => {
4328d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
4338d3f3824SCedric van Putten      await npm.addGlobalAsync(['expo-cli@^5', 'eas-cli']);
4348d3f3824SCedric van Putten
4358d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
4368d3f3824SCedric van Putten        'npm',
4378d3f3824SCedric van Putten        ['install', '--global', 'expo-cli@^5', 'eas-cli'],
4388d3f3824SCedric van Putten        expect.anything()
4398d3f3824SCedric van Putten      );
4408d3f3824SCedric van Putten    });
4418d3f3824SCedric van Putten  });
4428d3f3824SCedric van Putten
4438d3f3824SCedric van Putten  describe('removeAsync', () => {
4448d3f3824SCedric van Putten    it('removes a single package', async () => {
4458d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
4468d3f3824SCedric van Putten      await npm.removeAsync(['metro']);
4478d3f3824SCedric van Putten
4488d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
4498d3f3824SCedric van Putten        'npm',
4508d3f3824SCedric van Putten        ['uninstall', 'metro'],
4518d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
4528d3f3824SCedric van Putten      );
4538d3f3824SCedric van Putten    });
4548d3f3824SCedric van Putten
4558d3f3824SCedric van Putten    it('removes multiple packages', async () => {
4568d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
4578d3f3824SCedric van Putten      await npm.removeAsync(['metro', 'jest-haste-map']);
4588d3f3824SCedric van Putten
4598d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
4608d3f3824SCedric van Putten        'npm',
4618d3f3824SCedric van Putten        ['uninstall', 'metro', 'jest-haste-map'],
4628d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
4638d3f3824SCedric van Putten      );
4648d3f3824SCedric van Putten    });
4658d3f3824SCedric van Putten  });
4668d3f3824SCedric van Putten
4678d3f3824SCedric van Putten  describe('removeDevAsync', () => {
4688d3f3824SCedric van Putten    it('removes a single package', async () => {
4698d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
4708d3f3824SCedric van Putten      await npm.removeDevAsync(['metro']);
4718d3f3824SCedric van Putten
4728d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
4738d3f3824SCedric van Putten        'npm',
4748d3f3824SCedric van Putten        ['uninstall', '--save-dev', 'metro'],
4758d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
4768d3f3824SCedric van Putten      );
4778d3f3824SCedric van Putten    });
4788d3f3824SCedric van Putten
4798d3f3824SCedric van Putten    it('removes multiple packages', async () => {
4808d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
4818d3f3824SCedric van Putten      await npm.removeDevAsync(['metro', 'jest-haste-map']);
4828d3f3824SCedric van Putten
4838d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
4848d3f3824SCedric van Putten        'npm',
4858d3f3824SCedric van Putten        ['uninstall', '--save-dev', 'metro', 'jest-haste-map'],
4868d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
4878d3f3824SCedric van Putten      );
4888d3f3824SCedric van Putten    });
4898d3f3824SCedric van Putten  });
4908d3f3824SCedric van Putten
4918d3f3824SCedric van Putten  describe('removeGlobalAsync', () => {
4928d3f3824SCedric van Putten    it('removes a single package', async () => {
4938d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
4948d3f3824SCedric van Putten      await npm.removeGlobalAsync(['expo-cli']);
4958d3f3824SCedric van Putten
4968d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
4978d3f3824SCedric van Putten        'npm',
4988d3f3824SCedric van Putten        ['uninstall', '--global', 'expo-cli'],
4998d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
5008d3f3824SCedric van Putten      );
5018d3f3824SCedric van Putten    });
5028d3f3824SCedric van Putten
5038d3f3824SCedric van Putten    it('removes multiple packages', async () => {
5048d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
5058d3f3824SCedric van Putten      await npm.removeGlobalAsync(['expo-cli', 'eas-cli']);
5068d3f3824SCedric van Putten
5078d3f3824SCedric van Putten      expect(spawnAsync).toBeCalledWith(
5088d3f3824SCedric van Putten        'npm',
5098d3f3824SCedric van Putten        ['uninstall', '--global', 'expo-cli', 'eas-cli'],
5108d3f3824SCedric van Putten        expect.objectContaining({ cwd: projectRoot })
5118d3f3824SCedric van Putten      );
5128d3f3824SCedric van Putten    });
5138d3f3824SCedric van Putten  });
5148d3f3824SCedric van Putten
5158d3f3824SCedric van Putten  describe('workspaceRoot', () => {
5168d3f3824SCedric van Putten    const workspaceRoot = '/monorepo';
5178d3f3824SCedric van Putten    const projectRoot = '/monorepo/packages/test';
5188d3f3824SCedric van Putten
5198d3f3824SCedric van Putten    it('returns null for non-monorepo project', () => {
5208d3f3824SCedric van Putten      vol.fromJSON(
5218d3f3824SCedric van Putten        {
5228d3f3824SCedric van Putten          'package.json': JSON.stringify({ name: 'project' }),
5238d3f3824SCedric van Putten        },
5248d3f3824SCedric van Putten        projectRoot
5258d3f3824SCedric van Putten      );
5268d3f3824SCedric van Putten
5278d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
5288d3f3824SCedric van Putten      expect(npm.workspaceRoot()).toBeNull();
5298d3f3824SCedric van Putten    });
5308d3f3824SCedric van Putten
5318d3f3824SCedric van Putten    it('returns new instance for monorepo project', () => {
5328d3f3824SCedric van Putten      vol.fromJSON(
5338d3f3824SCedric van Putten        {
5348d3f3824SCedric van Putten          'packages/test/package.json': JSON.stringify({ name: 'project' }),
5358d3f3824SCedric van Putten          'package.json': JSON.stringify({
5368d3f3824SCedric van Putten            name: 'monorepo',
5378d3f3824SCedric van Putten            workspaces: ['packages/*'],
5388d3f3824SCedric van Putten          }),
5398d3f3824SCedric van Putten        },
5408d3f3824SCedric van Putten        workspaceRoot
5418d3f3824SCedric van Putten      );
5428d3f3824SCedric van Putten
5438d3f3824SCedric van Putten      const npm = new NpmPackageManager({ cwd: projectRoot });
5448d3f3824SCedric van Putten      const root = npm.workspaceRoot();
5458d3f3824SCedric van Putten      expect(root).toBeInstanceOf(NpmPackageManager);
5468d3f3824SCedric van Putten      expect(root).not.toBe(npm);
5478d3f3824SCedric van Putten    });
5488d3f3824SCedric van Putten  });
5498d3f3824SCedric van Putten});
550