1import chalk from 'chalk';
2
3import * as Log from '../../log';
4import { isModuleSymlinked } from '../../utils/isModuleSymlinked';
5import { hashForDependencyMap, updatePkgDependencies } from '../updatePackageJson';
6
7jest.mock('../../utils/isModuleSymlinked');
8jest.mock('../../log');
9
10describe(hashForDependencyMap, () => {
11  it(`dependencies in any order hash to the same value`, () => {
12    expect(hashForDependencyMap({ a: '1.0.0', b: 2, c: '~3.0' })).toBe(
13      hashForDependencyMap({ c: '~3.0', b: 2, a: '1.0.0' })
14    );
15  });
16});
17
18describe(updatePkgDependencies, () => {
19  beforeAll(() => {
20    (isModuleSymlinked as any).mockImplementation(() => false);
21  });
22  const requiredPackages = {
23    react: 'version-from-template-required-1',
24    'react-native': 'version-from-template-required-1',
25    'react-native-unimodules': 'version-from-template-required-1',
26    'expo-updates': 'version-from-template-required-1',
27  };
28
29  test('default bahaviour', () => {
30    const pkg = {
31      dependencies: {
32        'react-native': 'version-from-project',
33        'optional-package': 'version-from-project-1',
34        'optional-package-3': 'version-from-project-3',
35      },
36      devDependencies: {},
37    };
38    updatePkgDependencies('fake path', {
39      templatePkg: {
40        dependencies: {
41          ...requiredPackages,
42          'optional-package': 'version-from-template-1',
43          'optional-package-2': 'version-from-template-2',
44        },
45        devDependencies: {},
46      },
47      pkg,
48    });
49    expect(pkg.dependencies).toStrictEqual({
50      ...requiredPackages,
51      'react-native': 'version-from-project', // add-only package, do not overwrite
52      'optional-package': 'version-from-project-1',
53      'optional-package-2': 'version-from-template-2',
54      'optional-package-3': 'version-from-project-3',
55    });
56  });
57  test('with skipDependencyUpdate', () => {
58    const pkg = {
59      dependencies: {
60        'react-native': 'version-from-project',
61        'optional-package': 'version-from-project-1',
62        'optional-package-3': 'version-from-project-3',
63      },
64      devDependencies: {},
65    };
66    updatePkgDependencies('fake path', {
67      pkg,
68      templatePkg: {
69        dependencies: {
70          ...requiredPackages,
71          'react-native': 'version-from-project',
72          'optional-package': 'version-from-template-1',
73          'optional-package-2': 'version-from-template-2',
74        },
75        devDependencies: {},
76      },
77      skipDependencyUpdate: ['react-native'],
78    });
79    expect(pkg.dependencies).toStrictEqual({
80      ...requiredPackages,
81      'react-native': 'version-from-project',
82      'optional-package': 'version-from-project-1',
83      'optional-package-2': 'version-from-template-2',
84      'optional-package-3': 'version-from-project-3',
85    });
86  });
87  test('test expo-updates not required by default in sdk 44', () => {
88    const sdk44RequiredPackages = {
89      react: 'version-from-template-required-1',
90      'react-native': 'version-from-template-required-1',
91    };
92    const pkg = {
93      dependencies: {
94        'react-native': 'version-from-project',
95        'optional-package': 'version-from-project-1',
96        'optional-package-3': 'version-from-project-3',
97      },
98      devDependencies: {},
99    };
100    updatePkgDependencies('fake path', {
101      templatePkg: {
102        dependencies: {
103          ...sdk44RequiredPackages,
104          'optional-package': 'version-from-template-1',
105          'optional-package-2': 'version-from-template-2',
106        },
107        devDependencies: {},
108      },
109      pkg,
110    });
111    expect(pkg.dependencies).toStrictEqual({
112      ...sdk44RequiredPackages,
113      'react-native': 'version-from-project', // add-only package, do not overwrite
114      'optional-package': 'version-from-project-1',
115      'optional-package-2': 'version-from-template-2',
116      'optional-package-3': 'version-from-project-3',
117    });
118  });
119  test('does not overwrite add-only packages when defined', () => {
120    const pkg = {
121      dependencies: {
122        expo: 'version-from-project',
123        'react-native': 'version-from-project',
124      },
125      devDependencies: {},
126    };
127    updatePkgDependencies('fake path', {
128      templatePkg: {
129        dependencies: {
130          ...requiredPackages,
131          expo: 'version-from-template',
132        },
133        devDependencies: {},
134      },
135      pkg,
136    });
137    expect(pkg.dependencies).toStrictEqual({
138      ...requiredPackages,
139      'react-native': 'version-from-project', // add-only package, do not overwrite
140      expo: 'version-from-project',
141    });
142    expect(Log.warn).toBeCalledWith(
143      expect.stringContaining(
144        `instead of recommended ${[
145          `expo@version-from-template`,
146          `react-native@version-from-template-required-1`,
147        ]
148          .map((dep) => chalk.bold(dep))
149          .join(', ')}`
150      )
151    );
152  });
153});
154