1import { getConfig } from '@expo/config';
2
3import { asMock } from '../../__tests__/asMock';
4import { Log } from '../../log';
5import {
6  getVersionedDependenciesAsync,
7  logIncorrectDependencies,
8} from '../../start/doctor/dependencies/validateDependenciesVersions';
9import { confirmAsync } from '../../utils/prompts';
10import { checkPackagesAsync } from '../checkPackages';
11import { fixPackagesAsync } from '../installAsync';
12
13jest.mock('../../log');
14
15jest.mock('../../utils/prompts');
16
17jest.mock('../installAsync', () => ({
18  fixPackagesAsync: 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        packageType: 'dependencies',
45        expectedVersionOrRange: '^1.0.0',
46        actualVersion: '0.69.0',
47      },
48    ]);
49    await expect(
50      checkPackagesAsync('/', {
51        packages: ['react-native'],
52        options: { fix: false },
53        // @ts-expect-error
54        packageManager: {},
55        packageManagerArguments: [],
56      })
57    ).rejects.toThrowError(/EXIT/);
58
59    expect(logIncorrectDependencies).toBeCalledTimes(1);
60
61    expect(Log.exit).toBeCalledWith(
62      // Because of ansi
63      expect.stringContaining('Found outdated dependencies'),
64      1
65    );
66  });
67
68  it(`notifies when dependencies are on exclude list`, async () => {
69    asMock(confirmAsync).mockResolvedValueOnce(false);
70    // @ts-expect-error
71    asMock(getConfig).mockReturnValueOnce({
72      pkg: {
73        expo: {
74          install: {
75            exclude: ['expo-av', 'expo-blur'],
76          },
77        },
78      },
79      exp: {
80        sdkVersion: '45.0.0',
81        name: 'my-app',
82        slug: 'my-app',
83      },
84    });
85    asMock(getVersionedDependenciesAsync).mockResolvedValueOnce([
86      {
87        packageName: 'expo-av',
88        packageType: 'dependencies',
89        expectedVersionOrRange: '^2.0.0',
90        actualVersion: '1.0.0',
91      },
92    ]);
93    await checkPackagesAsync('/', {
94      packages: ['expo-av'],
95      options: { fix: true },
96      // @ts-expect-error
97      packageManager: {},
98      packageManagerArguments: [],
99    });
100
101    expect(Log.log).toBeCalledWith(
102      expect.stringContaining('Skipped fixing dependencies: expo-av and expo-blur')
103    );
104  });
105
106  it(`checks packages and exits with zero if all are valid`, async () => {
107    asMock(confirmAsync).mockResolvedValueOnce(false);
108    asMock(getVersionedDependenciesAsync).mockResolvedValueOnce([]);
109    await expect(
110      checkPackagesAsync('/', {
111        packages: ['react-native'],
112        options: { fix: false },
113        // @ts-expect-error
114        packageManager: {},
115        packageManagerArguments: [],
116      })
117    ).rejects.toThrowError(/EXIT/);
118
119    expect(logIncorrectDependencies).toBeCalledTimes(0);
120
121    expect(Log.exit).toBeCalledWith(
122      // Because of ansi
123      expect.stringContaining('Dependencies are up to date'),
124      0
125    );
126  });
127
128  it(`fixes invalid packages`, async () => {
129    const issues: Awaited<ReturnType<typeof getVersionedDependenciesAsync>> = [
130      {
131        packageName: 'react-native',
132        packageType: 'dependencies',
133        expectedVersionOrRange: '^1.0.0',
134        actualVersion: '0.69.0',
135      },
136      {
137        packageName: 'expo',
138        packageType: 'dependencies',
139        expectedVersionOrRange: '^1.0.0',
140        actualVersion: '0.69.0',
141      },
142    ];
143
144    asMock(getVersionedDependenciesAsync).mockResolvedValueOnce(issues);
145
146    await checkPackagesAsync('/', {
147      packages: ['react-native', 'expo'],
148      options: { fix: true },
149      // @ts-expect-error
150      packageManager: {},
151      packageManagerArguments: [],
152    });
153
154    expect(fixPackagesAsync).toBeCalledWith('/', {
155      packageManager: {},
156      packageManagerArguments: [],
157      packages: issues,
158      sdkVersion: '45.0.0',
159    });
160    expect(logIncorrectDependencies).toBeCalledTimes(1);
161  });
162});
163