1import { Log } from '../../log';
2import {
3  getVersionedDependenciesAsync,
4  logIncorrectDependencies,
5} from '../../start/doctor/dependencies/validateDependenciesVersions';
6import { confirmAsync } from '../../utils/prompts';
7import { checkPackagesAsync } from '../checkPackages';
8import { installPackagesAsync } from '../installAsync';
9
10const asMock = <T extends (...args: any[]) => any>(fn: T): jest.MockedFunction<T> =>
11  fn as jest.MockedFunction<T>;
12
13jest.mock('../../log');
14
15jest.mock('../../utils/prompts');
16
17jest.mock('../installAsync', () => ({
18  installPackagesAsync: jest.fn(),
19}));
20
21jest.mock('../../start/doctor/dependencies/validateDependenciesVersions', () => ({
22  getVersionedDependenciesAsync: jest.fn(),
23  logIncorrectDependencies: jest.fn(),
24}));
25
26jest.mock('@expo/config', () => ({
27  getProjectConfigDescriptionWithPaths: jest.fn(),
28  getConfig: jest.fn(() => ({
29    pkg: {},
30    exp: {
31      sdkVersion: '45.0.0',
32      name: 'my-app',
33      slug: 'my-app',
34    },
35  })),
36}));
37
38describe(checkPackagesAsync, () => {
39  it(`checks packages and exits when packages are invalid`, async () => {
40    asMock(confirmAsync).mockResolvedValueOnce(false);
41    asMock(getVersionedDependenciesAsync).mockResolvedValueOnce([
42      {
43        packageName: 'react-native',
44        expectedVersionOrRange: '^1.0.0',
45        actualVersion: '0.69.0',
46      },
47    ]);
48    await expect(
49      checkPackagesAsync('/', {
50        packages: ['react-native'],
51        options: { fix: false },
52        // @ts-expect-error
53        packageManager: {},
54        packageManagerArguments: [],
55      })
56    ).rejects.toThrowError(/EXIT/);
57
58    expect(logIncorrectDependencies).toBeCalledTimes(1);
59
60    expect(Log.exit).toBeCalledWith(
61      // Because of ansi
62      expect.stringContaining('Found outdated dependencies'),
63      1
64    );
65  });
66
67  it(`checks packages and exits with zero if all are valid`, async () => {
68    asMock(confirmAsync).mockResolvedValueOnce(false);
69    asMock(getVersionedDependenciesAsync).mockResolvedValueOnce([]);
70    await expect(
71      checkPackagesAsync('/', {
72        packages: ['react-native'],
73        options: { fix: false },
74        // @ts-expect-error
75        packageManager: {},
76        packageManagerArguments: [],
77      })
78    ).rejects.toThrowError(/EXIT/);
79
80    expect(logIncorrectDependencies).toBeCalledTimes(0);
81
82    expect(Log.exit).toBeCalledWith(
83      // Because of ansi
84      expect.stringContaining('Dependencies are up to date'),
85      0
86    );
87  });
88
89  it(`fixes invalid packages`, async () => {
90    asMock(getVersionedDependenciesAsync).mockResolvedValueOnce([
91      {
92        packageName: 'react-native',
93        expectedVersionOrRange: '^1.0.0',
94        actualVersion: '0.69.0',
95      },
96      {
97        packageName: 'expo',
98        expectedVersionOrRange: '^1.0.0',
99        actualVersion: '0.69.0',
100      },
101    ]);
102
103    await checkPackagesAsync('/', {
104      packages: ['react-native', 'expo'],
105      options: { fix: true },
106      // @ts-expect-error
107      packageManager: {},
108      packageManagerArguments: [],
109    });
110
111    expect(installPackagesAsync).toBeCalledWith('/', {
112      packageManager: {},
113      packageManagerArguments: [],
114      packages: ['react-native', 'expo'],
115      sdkVersion: '45.0.0',
116    });
117    expect(logIncorrectDependencies).toBeCalledTimes(1);
118  });
119});
120