1// @ts-expect-error
2import freeportAsync from 'freeport-async';
3
4import { getRunningProcess } from '../getRunningProcess';
5import { choosePortAsync, ensurePortAvailabilityAsync } from '../port';
6import { confirmAsync } from '../prompts';
7
8jest.mock('../../log');
9jest.mock('freeport-async', () => jest.fn(async (port) => port));
10jest.mock('../prompts');
11jest.mock('../getRunningProcess', () => ({
12  getRunningProcess: jest.fn(() => null),
13}));
14
15describe(ensurePortAvailabilityAsync, () => {
16  it(`returns true if the port is available`, async () => {
17    jest.mocked(freeportAsync).mockResolvedValueOnce(8081);
18    expect(await ensurePortAvailabilityAsync('/', { port: 8081 })).toBe(true);
19  });
20  it(`returns false if the port is unavailable due to running the same process`, async () => {
21    jest.mocked(getRunningProcess).mockReturnValueOnce({
22      pid: 1,
23      directory: '/me',
24      command: 'npx expo',
25    });
26    jest.mocked(freeportAsync).mockResolvedValueOnce(8082);
27    expect(await ensurePortAvailabilityAsync('/me', { port: 8081 })).toBe(false);
28  });
29  it(`asserts if the port is busy because it's running a different process`, async () => {
30    jest.mocked(getRunningProcess).mockReturnValueOnce({
31      pid: 1,
32      directory: '/other',
33      command: 'npx expo',
34    });
35    jest.mocked(freeportAsync).mockResolvedValueOnce(8082);
36    await expect(ensurePortAvailabilityAsync('/me', { port: 8081 })).rejects.toThrow();
37  });
38});
39
40describe(choosePortAsync, () => {
41  it(`returns same port when given port is available`, async () => {
42    jest.mocked(freeportAsync).mockResolvedValueOnce(8081);
43    const port = await choosePortAsync('/', { defaultPort: 8081 });
44    expect(port).toBe(8081);
45    expect(confirmAsync).not.toHaveBeenCalled();
46  });
47  it(`chooses a new port if the default port is taken and isn't running the same process`, async () => {
48    jest.mocked(freeportAsync).mockResolvedValueOnce(8082);
49    jest.mocked(getRunningProcess).mockReturnValueOnce({
50      pid: 1,
51      directory: '/other/project',
52      command: 'npx expo',
53    });
54    jest.mocked(confirmAsync).mockResolvedValueOnce(true);
55    const port = await choosePortAsync('/', { defaultPort: 8081, reuseExistingPort: false });
56    expect(port).toBe(8082);
57    expect(confirmAsync).toHaveBeenCalledWith({ initial: true, message: 'Use port 8082 instead?' });
58  });
59  it(`returns null if the new suggested port is rejected`, async () => {
60    jest.mocked(freeportAsync).mockResolvedValueOnce(8082);
61    jest.mocked(getRunningProcess).mockReturnValueOnce({
62      pid: 1,
63      directory: '/other/project',
64      command: 'npx expo',
65    });
66    jest.mocked(confirmAsync).mockResolvedValueOnce(false);
67    const port = await choosePortAsync('/', { defaultPort: 8081, reuseExistingPort: false });
68    expect(port).toBe(null);
69    expect(confirmAsync).toHaveBeenCalledWith({ initial: true, message: 'Use port 8082 instead?' });
70  });
71  it(`returns null if the taken port is running the same process`, async () => {
72    jest.mocked(freeportAsync).mockResolvedValueOnce(8082);
73    jest.mocked(getRunningProcess).mockReturnValueOnce({
74      pid: 1,
75      directory: '/me',
76      command: 'npx expo',
77    });
78    jest.mocked(confirmAsync).mockResolvedValueOnce(false);
79    const port = await choosePortAsync('/me', { defaultPort: 8081, reuseExistingPort: true });
80    expect(port).toBe(null);
81    expect(confirmAsync).not.toBeCalled();
82  });
83});
84