@mintlify/cli 4.0.603 → 4.0.605
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +4 -0
- package/__test__/brokenLinks.test.ts +106 -0
- package/__test__/{cli.test.ts → checkPort.test.ts} +31 -15
- package/__test__/minVersion.test.ts +24 -10
- package/__test__/openApiCheck.test.ts +127 -0
- package/__test__/update.test.ts +148 -47
- package/__test__/utils.ts +9 -0
- package/bin/cli.js +154 -148
- package/bin/helpers.js +29 -21
- package/bin/tsconfig.build.tsbuildinfo +1 -1
- package/bin/update.js +22 -22
- package/package.json +11 -10
- package/src/cli.tsx +255 -0
- package/src/{helpers.ts → helpers.tsx} +44 -23
- package/src/update.tsx +79 -0
- package/tsconfig.json +3 -2
- package/src/cli.ts +0 -222
- package/src/update.ts +0 -71
package/CONTRIBUTING.md
CHANGED
|
@@ -43,3 +43,7 @@ If for some reason the release workflow is broken or we can't access AWS program
|
|
|
43
43
|
## Manually overriding the client version used locally
|
|
44
44
|
|
|
45
45
|
Run `mintlify dev --client-version x.x.xxxx` with the client version you would like to use and that version will be downloaded instead of the latest client version.
|
|
46
|
+
|
|
47
|
+
## Breaking changes
|
|
48
|
+
|
|
49
|
+
If cli or client contain breaking changes that require they are both updated together, change the MINIMUM_CLI_VERSION to make sure `mint dev` will silently update to a minimum viable CLI version.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { getBrokenInternalLinks } from '@mintlify/link-rot';
|
|
2
|
+
import { MdxPath } from '@mintlify/link-rot/dist/graph.js';
|
|
3
|
+
import * as previewing from '@mintlify/previewing';
|
|
4
|
+
import { mockProcessExit } from 'vitest-mock-process';
|
|
5
|
+
|
|
6
|
+
import { checkForMintJson } from '../src/helpers.js';
|
|
7
|
+
import { runCommand } from './utils.js';
|
|
8
|
+
|
|
9
|
+
vi.mock('../src/helpers.js', async () => {
|
|
10
|
+
const actual = await import('../src/helpers.js');
|
|
11
|
+
return {
|
|
12
|
+
...actual,
|
|
13
|
+
checkForMintJson: vi.fn(),
|
|
14
|
+
};
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
vi.mock('@mintlify/link-rot', async () => {
|
|
18
|
+
const actual = await import('@mintlify/link-rot');
|
|
19
|
+
return {
|
|
20
|
+
...actual,
|
|
21
|
+
getBrokenInternalLinks: vi.fn(),
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const addLogSpy = vi.spyOn(previewing, 'addLog');
|
|
26
|
+
const clearLogsSpy = vi.spyOn(previewing, 'clearLogs');
|
|
27
|
+
const processExitMock = mockProcessExit();
|
|
28
|
+
|
|
29
|
+
describe('brokenLinks', () => {
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
vi.clearAllMocks();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
vi.clearAllMocks();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('success with no broken links', async () => {
|
|
39
|
+
vi.mocked(checkForMintJson).mockResolvedValueOnce(true);
|
|
40
|
+
vi.mocked(getBrokenInternalLinks).mockResolvedValueOnce([]);
|
|
41
|
+
|
|
42
|
+
await runCommand('broken-links');
|
|
43
|
+
|
|
44
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
45
|
+
expect.objectContaining({
|
|
46
|
+
props: { message: 'checking for broken links...' },
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
50
|
+
expect.objectContaining({
|
|
51
|
+
props: { message: 'no broken links found' },
|
|
52
|
+
})
|
|
53
|
+
);
|
|
54
|
+
expect(processExitMock).toHaveBeenCalledWith(0);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('success with broken links', async () => {
|
|
58
|
+
vi.mocked(checkForMintJson).mockResolvedValueOnce(true);
|
|
59
|
+
vi.mocked(getBrokenInternalLinks).mockResolvedValueOnce([
|
|
60
|
+
{
|
|
61
|
+
relativeDir: '.',
|
|
62
|
+
filename: 'introduction.mdx',
|
|
63
|
+
originalPath: '/api/invalid-path',
|
|
64
|
+
pathType: 'internal',
|
|
65
|
+
} as MdxPath,
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
await runCommand('broken-links');
|
|
69
|
+
|
|
70
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
71
|
+
expect.objectContaining({
|
|
72
|
+
props: { message: 'checking for broken links...' },
|
|
73
|
+
})
|
|
74
|
+
);
|
|
75
|
+
expect(clearLogsSpy).toHaveBeenCalled();
|
|
76
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
77
|
+
expect.objectContaining({
|
|
78
|
+
props: {
|
|
79
|
+
brokenLinksByFile: {
|
|
80
|
+
'introduction.mdx': ['/api/invalid-path'],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
);
|
|
85
|
+
expect(processExitMock).toHaveBeenCalledWith(0);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('error with broken links', async () => {
|
|
89
|
+
vi.mocked(checkForMintJson).mockResolvedValueOnce(true);
|
|
90
|
+
vi.mocked(getBrokenInternalLinks).mockRejectedValueOnce(new Error('some error'));
|
|
91
|
+
|
|
92
|
+
await runCommand('broken-links');
|
|
93
|
+
|
|
94
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
95
|
+
expect.objectContaining({
|
|
96
|
+
props: { message: 'checking for broken links...' },
|
|
97
|
+
})
|
|
98
|
+
);
|
|
99
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
100
|
+
expect.objectContaining({
|
|
101
|
+
props: { message: 'some error' },
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as previewing from '@mintlify/previewing';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
|
+
import { mockProcessExit } from 'vitest-mock-process';
|
|
3
4
|
|
|
4
5
|
import { runCommand } from './utils.js';
|
|
5
6
|
|
|
6
|
-
vi.mock('@mintlify/previewing', () =>
|
|
7
|
+
vi.mock('@mintlify/previewing', async () => {
|
|
8
|
+
const originalModule =
|
|
9
|
+
await vi.importActual<typeof import('@mintlify/previewing')>('@mintlify/previewing');
|
|
10
|
+
return {
|
|
11
|
+
...originalModule,
|
|
12
|
+
dev: vi.fn(),
|
|
13
|
+
};
|
|
14
|
+
});
|
|
7
15
|
|
|
8
16
|
vi.mock('readline/promises', () => {
|
|
9
17
|
return {
|
|
@@ -25,7 +33,11 @@ vi.mock('detect-port', () => ({
|
|
|
25
33
|
default: (port: number) => (allowedPorts.includes(port) ? port : port + 1),
|
|
26
34
|
}));
|
|
27
35
|
|
|
28
|
-
|
|
36
|
+
const devSpy = vi.spyOn(previewing, 'dev');
|
|
37
|
+
const addLogSpy = vi.spyOn(previewing, 'addLog');
|
|
38
|
+
const processExitMock = mockProcessExit();
|
|
39
|
+
|
|
40
|
+
describe('checkPort', () => {
|
|
29
41
|
let originalArgv: string[];
|
|
30
42
|
|
|
31
43
|
beforeEach(() => {
|
|
@@ -49,28 +61,32 @@ describe('cli', () => {
|
|
|
49
61
|
it('should run dev command', async () => {
|
|
50
62
|
await runCommand('dev');
|
|
51
63
|
|
|
52
|
-
expect(
|
|
64
|
+
expect(devSpy).toHaveBeenCalledWith(expect.objectContaining({ port: 3000 }));
|
|
53
65
|
});
|
|
54
66
|
|
|
55
67
|
it('port 5000 and 5001 should be taken and 5002 should be accepted by the user and available.', async () => {
|
|
56
|
-
const consoleSpy = vi.spyOn(console, 'log');
|
|
57
|
-
|
|
58
68
|
await runCommand('dev', '--port=5000');
|
|
59
69
|
|
|
60
|
-
expect(
|
|
61
|
-
expect(
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
expect(addLogSpy).toHaveBeenCalledTimes(2);
|
|
71
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
72
|
+
expect.objectContaining({
|
|
73
|
+
props: { message: 'port 5000 is already in use. trying 5001 instead' },
|
|
74
|
+
})
|
|
75
|
+
);
|
|
76
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
77
|
+
expect.objectContaining({
|
|
78
|
+
props: { message: 'port 5001 is already in use. trying 5002 instead' },
|
|
79
|
+
})
|
|
80
|
+
);
|
|
64
81
|
});
|
|
65
82
|
|
|
66
83
|
it('fails after the 10th used port', async () => {
|
|
67
|
-
const consoleSpy = vi.spyOn(console, 'log');
|
|
68
|
-
|
|
69
84
|
await runCommand('dev', '--port=8000');
|
|
70
85
|
|
|
71
|
-
expect(
|
|
72
|
-
expect(
|
|
73
|
-
|
|
86
|
+
expect(addLogSpy).toHaveBeenCalledTimes(10);
|
|
87
|
+
expect(addLogSpy).toHaveBeenLastCalledWith(
|
|
88
|
+
expect.objectContaining({ props: { message: 'no available port found' } })
|
|
74
89
|
);
|
|
90
|
+
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
75
91
|
});
|
|
76
92
|
});
|
|
@@ -1,25 +1,36 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as previewing from '@mintlify/previewing';
|
|
2
2
|
|
|
3
3
|
import { LOCAL_LINKED_VERSION } from '../src/constants.js';
|
|
4
4
|
import { getCliVersion } from '../src/helpers.js';
|
|
5
5
|
import * as updateModule from '../src/update.js';
|
|
6
6
|
import { runCommand } from './utils.js';
|
|
7
7
|
|
|
8
|
-
vi.mock('
|
|
9
|
-
const
|
|
8
|
+
vi.mock('@mintlify/previewing', async () => {
|
|
9
|
+
const originalModule =
|
|
10
|
+
await vi.importActual<typeof import('@mintlify/previewing')>('@mintlify/previewing');
|
|
10
11
|
return {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
...originalModule,
|
|
13
|
+
dev: vi.fn().mockResolvedValue(undefined),
|
|
14
|
+
addLog: vi.fn().mockResolvedValue(undefined),
|
|
14
15
|
};
|
|
15
16
|
});
|
|
16
17
|
|
|
17
|
-
vi.mock('
|
|
18
|
+
vi.mock('../src/helpers.js', async () => {
|
|
19
|
+
const originalModule =
|
|
20
|
+
await vi.importActual<typeof import('../src/helpers.js')>('../src/helpers.js');
|
|
21
|
+
return {
|
|
22
|
+
...originalModule,
|
|
23
|
+
getCliVersion: vi.fn(),
|
|
24
|
+
};
|
|
25
|
+
});
|
|
18
26
|
|
|
19
27
|
vi.mock('../src/update.js', () => ({
|
|
20
28
|
update: vi.fn().mockResolvedValue(undefined),
|
|
21
29
|
}));
|
|
22
30
|
|
|
31
|
+
const devSpy = vi.spyOn(previewing, 'dev');
|
|
32
|
+
const addLogSpy = vi.spyOn(previewing, 'addLog');
|
|
33
|
+
|
|
23
34
|
describe('minimum version', () => {
|
|
24
35
|
beforeEach(() => {
|
|
25
36
|
vi.clearAllMocks();
|
|
@@ -36,7 +47,8 @@ describe('minimum version', () => {
|
|
|
36
47
|
await runCommand('dev');
|
|
37
48
|
|
|
38
49
|
expect(updateSpy).toHaveBeenCalled();
|
|
39
|
-
expect(
|
|
50
|
+
expect(devSpy).toHaveBeenCalled();
|
|
51
|
+
expect(addLogSpy).not.toHaveBeenCalled();
|
|
40
52
|
});
|
|
41
53
|
it('should not update the cli if the version is above the minimum', async () => {
|
|
42
54
|
vi.mocked(getCliVersion).mockReturnValueOnce('4.2.1');
|
|
@@ -45,7 +57,8 @@ describe('minimum version', () => {
|
|
|
45
57
|
await runCommand('dev');
|
|
46
58
|
|
|
47
59
|
expect(updateSpy).not.toHaveBeenCalled();
|
|
48
|
-
expect(
|
|
60
|
+
expect(devSpy).toHaveBeenCalled();
|
|
61
|
+
expect(addLogSpy).not.toHaveBeenCalled();
|
|
49
62
|
});
|
|
50
63
|
it('should not update the cli if the version is linked to local package', async () => {
|
|
51
64
|
vi.mocked(getCliVersion).mockReturnValueOnce(LOCAL_LINKED_VERSION);
|
|
@@ -54,6 +67,7 @@ describe('minimum version', () => {
|
|
|
54
67
|
await runCommand('dev');
|
|
55
68
|
|
|
56
69
|
expect(updateSpy).not.toHaveBeenCalled();
|
|
57
|
-
expect(
|
|
70
|
+
expect(devSpy).toHaveBeenCalled();
|
|
71
|
+
expect(addLogSpy).not.toHaveBeenCalled();
|
|
58
72
|
});
|
|
59
73
|
});
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { getOpenApiDocumentFromUrl, isAllowedLocalSchemaUrl, validate } from '@mintlify/common';
|
|
2
|
+
import * as previewing from '@mintlify/previewing';
|
|
3
|
+
import { mockProcessExit } from 'vitest-mock-process';
|
|
4
|
+
|
|
5
|
+
import { readLocalOpenApiFile } from '../src/helpers.js';
|
|
6
|
+
import { mockValidOpenApiDocument, runCommand } from './utils.js';
|
|
7
|
+
|
|
8
|
+
vi.mock('@mintlify/common', () => ({
|
|
9
|
+
getOpenApiDocumentFromUrl: vi.fn(),
|
|
10
|
+
isAllowedLocalSchemaUrl: vi.fn(),
|
|
11
|
+
validate: vi.fn(),
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
vi.mock('../src/helpers.js', async () => {
|
|
15
|
+
const originalModule = await import('../src/helpers.js');
|
|
16
|
+
return {
|
|
17
|
+
...originalModule,
|
|
18
|
+
readLocalOpenApiFile: vi.fn(),
|
|
19
|
+
};
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const addLogSpy = vi.spyOn(previewing, 'addLog');
|
|
23
|
+
const processExitMock = mockProcessExit();
|
|
24
|
+
|
|
25
|
+
describe('openApiCheck', () => {
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
vi.clearAllMocks();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
vi.clearAllMocks();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('valid openApi file from url', async () => {
|
|
35
|
+
vi.mocked(isAllowedLocalSchemaUrl).mockReturnValueOnce(true);
|
|
36
|
+
vi.mocked(getOpenApiDocumentFromUrl).mockResolvedValueOnce(mockValidOpenApiDocument);
|
|
37
|
+
|
|
38
|
+
await runCommand('openapi-check', 'https://petstore3.swagger.io/api/v3/openapi.json');
|
|
39
|
+
|
|
40
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
41
|
+
expect.objectContaining({
|
|
42
|
+
props: { message: 'OpenAPI definition is valid.' },
|
|
43
|
+
})
|
|
44
|
+
);
|
|
45
|
+
expect(processExitMock).toHaveBeenCalledWith(0);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('invalid openApi file from url', async () => {
|
|
49
|
+
vi.mocked(isAllowedLocalSchemaUrl).mockReturnValueOnce(true);
|
|
50
|
+
vi.mocked(getOpenApiDocumentFromUrl).mockRejectedValueOnce(
|
|
51
|
+
new Error('Could not parse OpenAPI document.')
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
await runCommand('openapi-check', 'https://petstore3.swagger.io/api/v3/openapi.json');
|
|
55
|
+
|
|
56
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
57
|
+
expect.objectContaining({
|
|
58
|
+
props: { message: 'Could not parse OpenAPI document.' },
|
|
59
|
+
})
|
|
60
|
+
);
|
|
61
|
+
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('valid openApi file from localhost', async () => {
|
|
65
|
+
vi.mocked(isAllowedLocalSchemaUrl).mockReturnValueOnce(true);
|
|
66
|
+
vi.mocked(getOpenApiDocumentFromUrl).mockResolvedValueOnce(mockValidOpenApiDocument);
|
|
67
|
+
|
|
68
|
+
await runCommand('openapi-check', 'http://localhost:3000/openapi.json');
|
|
69
|
+
|
|
70
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
71
|
+
expect.objectContaining({
|
|
72
|
+
props: { message: 'OpenAPI definition is valid.' },
|
|
73
|
+
})
|
|
74
|
+
);
|
|
75
|
+
expect(processExitMock).toHaveBeenCalledWith(0);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('invalid openApi file from localhost', async () => {
|
|
79
|
+
vi.mocked(isAllowedLocalSchemaUrl).mockReturnValueOnce(false);
|
|
80
|
+
vi.mocked(readLocalOpenApiFile).mockResolvedValueOnce(undefined);
|
|
81
|
+
|
|
82
|
+
await runCommand('openapi-check', 'http://localhost:3000/openapi.json');
|
|
83
|
+
|
|
84
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
85
|
+
expect.objectContaining({
|
|
86
|
+
props: {
|
|
87
|
+
message:
|
|
88
|
+
'failed to parse OpenAPI spec: could not parse file correctly, please check for any syntax errors.',
|
|
89
|
+
},
|
|
90
|
+
})
|
|
91
|
+
);
|
|
92
|
+
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('valid openApi file from local file', async () => {
|
|
96
|
+
vi.mocked(isAllowedLocalSchemaUrl).mockReturnValueOnce(false);
|
|
97
|
+
vi.mocked(readLocalOpenApiFile).mockResolvedValueOnce(mockValidOpenApiDocument);
|
|
98
|
+
vi.mocked(validate).mockResolvedValueOnce({
|
|
99
|
+
valid: true,
|
|
100
|
+
errors: [],
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await runCommand('openapi-check', 'test/openapi.yaml');
|
|
104
|
+
|
|
105
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
106
|
+
expect.objectContaining({
|
|
107
|
+
props: { message: 'OpenAPI definition is valid.' },
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
expect(processExitMock).toHaveBeenCalledWith(0);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('invalid openApi file from local file', async () => {
|
|
114
|
+
vi.mocked(isAllowedLocalSchemaUrl).mockReturnValueOnce(false);
|
|
115
|
+
vi.mocked(readLocalOpenApiFile).mockResolvedValueOnce(mockValidOpenApiDocument);
|
|
116
|
+
vi.mocked(validate).mockRejectedValueOnce(new Error('some schema parsing error'));
|
|
117
|
+
|
|
118
|
+
await runCommand('openapi-check', 'test/openapi.yaml');
|
|
119
|
+
|
|
120
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
121
|
+
expect.objectContaining({
|
|
122
|
+
props: { message: 'some schema parsing error' },
|
|
123
|
+
})
|
|
124
|
+
);
|
|
125
|
+
expect(processExitMock).toHaveBeenCalledWith(1);
|
|
126
|
+
});
|
|
127
|
+
});
|
package/__test__/update.test.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { execSync } from 'node:child_process';
|
|
3
|
-
import { mockProcessExit } from 'vitest-mock-process';
|
|
1
|
+
import * as previewing from '@mintlify/previewing';
|
|
4
2
|
|
|
5
|
-
import { getLatestCliVersion, getVersions } from '../src/helpers.js';
|
|
3
|
+
import { getLatestCliVersion, getVersions, execAsync } from '../src/helpers.js';
|
|
6
4
|
import { update } from '../src/update.js';
|
|
7
5
|
|
|
8
|
-
vi.mock('
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
6
|
+
vi.mock('@mintlify/previewing', async () => {
|
|
7
|
+
const originalModule =
|
|
8
|
+
await vi.importActual<typeof import('@mintlify/previewing')>('@mintlify/previewing');
|
|
9
|
+
return {
|
|
10
|
+
...originalModule,
|
|
11
|
+
getClientVersion: vi.fn(),
|
|
12
|
+
getTargetMintVersion: vi.fn(),
|
|
13
|
+
downloadTargetMint: vi.fn(),
|
|
14
|
+
};
|
|
15
|
+
});
|
|
17
16
|
|
|
18
|
-
vi.mock('../src/helpers.js', async (
|
|
19
|
-
const
|
|
17
|
+
vi.mock('../src/helpers.js', async () => {
|
|
18
|
+
const originalModule =
|
|
19
|
+
await vi.importActual<typeof import('../src/helpers.js')>('../src/helpers.js');
|
|
20
20
|
return {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
...originalModule,
|
|
22
|
+
execAsync: vi.fn(),
|
|
23
23
|
getLatestCliVersion: vi.fn(),
|
|
24
24
|
getVersions: vi.fn().mockReturnValue({
|
|
25
25
|
cli: '1.0.0',
|
|
@@ -28,7 +28,7 @@ vi.mock('../src/helpers.js', async (importOriginal) => {
|
|
|
28
28
|
};
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
const
|
|
31
|
+
const addLogSpy = vi.spyOn(previewing, 'addLog');
|
|
32
32
|
|
|
33
33
|
describe('update', () => {
|
|
34
34
|
beforeEach(() => {
|
|
@@ -44,16 +44,50 @@ describe('update', () => {
|
|
|
44
44
|
cli: '1.0.0',
|
|
45
45
|
client: '1.0.0',
|
|
46
46
|
});
|
|
47
|
-
vi.mocked(getTargetMintVersion).mockResolvedValue('2.0.0');
|
|
47
|
+
vi.mocked(previewing.getTargetMintVersion).mockResolvedValue('2.0.0');
|
|
48
48
|
vi.mocked(getLatestCliVersion).mockReturnValue('2.0.0');
|
|
49
|
-
vi.mocked(
|
|
50
|
-
vi.mocked(downloadTargetMint).mockResolvedValue();
|
|
49
|
+
vi.mocked(execAsync).mockResolvedValue({ stdout: '', stderr: '' });
|
|
50
|
+
vi.mocked(previewing.downloadTargetMint).mockResolvedValue();
|
|
51
51
|
|
|
52
52
|
await update({ packageName: 'mintlify' });
|
|
53
53
|
|
|
54
|
-
expect(
|
|
55
|
-
expect(
|
|
56
|
-
|
|
54
|
+
expect(addLogSpy).toHaveBeenCalledTimes(4);
|
|
55
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
56
|
+
expect.objectContaining({ props: { message: 'updating...' } })
|
|
57
|
+
);
|
|
58
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
59
|
+
expect.objectContaining({ props: { message: 'updating mintlify package...' } })
|
|
60
|
+
);
|
|
61
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
62
|
+
expect.objectContaining({ props: { message: 'updating mintlify client to 2.0.0...' } })
|
|
63
|
+
);
|
|
64
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
65
|
+
expect.objectContaining({
|
|
66
|
+
props: { message: 'updated mintlify to the latest version: 2.0.0' },
|
|
67
|
+
})
|
|
68
|
+
);
|
|
69
|
+
expect(execAsync).toHaveBeenCalledWith('npm install -g mintlify@latest --silent');
|
|
70
|
+
expect(previewing.downloadTargetMint).toHaveBeenCalledWith({
|
|
71
|
+
targetVersion: '2.0.0',
|
|
72
|
+
existingVersion: '1.0.0',
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should update the cli and client successfully - silently', async () => {
|
|
77
|
+
vi.mocked(getVersions).mockReturnValue({
|
|
78
|
+
cli: '1.0.0',
|
|
79
|
+
client: '1.0.0',
|
|
80
|
+
});
|
|
81
|
+
vi.mocked(previewing.getTargetMintVersion).mockResolvedValue('2.0.0');
|
|
82
|
+
vi.mocked(getLatestCliVersion).mockReturnValue('2.0.0');
|
|
83
|
+
vi.mocked(execAsync).mockResolvedValue({ stdout: '', stderr: '' });
|
|
84
|
+
vi.mocked(previewing.downloadTargetMint).mockResolvedValue();
|
|
85
|
+
|
|
86
|
+
await update({ packageName: 'mintlify', silent: true });
|
|
87
|
+
|
|
88
|
+
expect(addLogSpy).not.toHaveBeenCalled();
|
|
89
|
+
expect(execAsync).toHaveBeenCalledWith('npm install -g mintlify@latest --silent');
|
|
90
|
+
expect(previewing.downloadTargetMint).toHaveBeenCalledWith({
|
|
57
91
|
targetVersion: '2.0.0',
|
|
58
92
|
existingVersion: '1.0.0',
|
|
59
93
|
});
|
|
@@ -65,14 +99,38 @@ describe('update', () => {
|
|
|
65
99
|
client: '1.0.0',
|
|
66
100
|
});
|
|
67
101
|
vi.mocked(getLatestCliVersion).mockReturnValue('1.0.0');
|
|
68
|
-
vi.mocked(getTargetMintVersion).mockResolvedValue('1.0.0');
|
|
69
|
-
vi.mocked(
|
|
70
|
-
vi.mocked(downloadTargetMint).mockResolvedValue();
|
|
102
|
+
vi.mocked(previewing.getTargetMintVersion).mockResolvedValue('1.0.0');
|
|
103
|
+
vi.mocked(execAsync).mockResolvedValue({ stdout: '', stderr: '' });
|
|
104
|
+
vi.mocked(previewing.downloadTargetMint).mockResolvedValue();
|
|
71
105
|
|
|
72
106
|
await update({ packageName: 'mintlify' });
|
|
73
107
|
|
|
74
|
-
expect(
|
|
75
|
-
expect(
|
|
108
|
+
expect(addLogSpy).toHaveBeenCalledTimes(2);
|
|
109
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
110
|
+
expect.objectContaining({ props: { message: 'updating...' } })
|
|
111
|
+
);
|
|
112
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
113
|
+
expect.objectContaining({ props: { message: 'already up to date' } })
|
|
114
|
+
);
|
|
115
|
+
expect(execAsync).not.toHaveBeenCalled();
|
|
116
|
+
expect(previewing.downloadTargetMint).not.toHaveBeenCalled();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should return when already up to date - silently', async () => {
|
|
120
|
+
vi.mocked(getVersions).mockReturnValue({
|
|
121
|
+
cli: '1.0.0',
|
|
122
|
+
client: '1.0.0',
|
|
123
|
+
});
|
|
124
|
+
vi.mocked(getLatestCliVersion).mockReturnValue('1.0.0');
|
|
125
|
+
vi.mocked(previewing.getTargetMintVersion).mockResolvedValue('1.0.0');
|
|
126
|
+
vi.mocked(execAsync).mockResolvedValue({ stdout: '', stderr: '' });
|
|
127
|
+
vi.mocked(previewing.downloadTargetMint).mockResolvedValue();
|
|
128
|
+
|
|
129
|
+
await update({ packageName: 'mintlify', silent: true });
|
|
130
|
+
|
|
131
|
+
expect(addLogSpy).not.toHaveBeenCalled();
|
|
132
|
+
expect(execAsync).not.toHaveBeenCalled();
|
|
133
|
+
expect(previewing.downloadTargetMint).not.toHaveBeenCalled();
|
|
76
134
|
});
|
|
77
135
|
|
|
78
136
|
it('should only update cli if client version is up to date', async () => {
|
|
@@ -81,13 +139,26 @@ describe('update', () => {
|
|
|
81
139
|
client: '2.0.0',
|
|
82
140
|
});
|
|
83
141
|
vi.mocked(getLatestCliVersion).mockReturnValue('2.0.0');
|
|
84
|
-
vi.mocked(getTargetMintVersion).mockResolvedValue('2.0.0');
|
|
85
|
-
vi.mocked(
|
|
142
|
+
vi.mocked(previewing.getTargetMintVersion).mockResolvedValue('2.0.0');
|
|
143
|
+
vi.mocked(execAsync).mockResolvedValue({ stdout: '', stderr: '' });
|
|
86
144
|
|
|
87
145
|
await update({ packageName: 'mintlify' });
|
|
88
146
|
|
|
89
|
-
expect(
|
|
90
|
-
expect(
|
|
147
|
+
expect(addLogSpy).toHaveBeenCalledTimes(3);
|
|
148
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
149
|
+
expect.objectContaining({ props: { message: 'updating...' } })
|
|
150
|
+
);
|
|
151
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
152
|
+
expect.objectContaining({ props: { message: 'updating mintlify package...' } })
|
|
153
|
+
);
|
|
154
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
155
|
+
expect.objectContaining({
|
|
156
|
+
props: { message: 'updated mintlify to the latest version: 2.0.0' },
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
expect(execAsync).toHaveBeenCalledWith('npm install -g mintlify@latest --silent');
|
|
161
|
+
expect(previewing.downloadTargetMint).not.toHaveBeenCalled();
|
|
91
162
|
});
|
|
92
163
|
|
|
93
164
|
it('should only update client if cli version is up to date', async () => {
|
|
@@ -96,14 +167,26 @@ describe('update', () => {
|
|
|
96
167
|
client: '1.0.0',
|
|
97
168
|
});
|
|
98
169
|
vi.mocked(getLatestCliVersion).mockReturnValue('2.0.0');
|
|
99
|
-
vi.mocked(getTargetMintVersion).mockResolvedValue('2.0.0');
|
|
100
|
-
vi.mocked(
|
|
170
|
+
vi.mocked(previewing.getTargetMintVersion).mockResolvedValue('2.0.0');
|
|
171
|
+
vi.mocked(execAsync).mockResolvedValue({ stdout: '', stderr: '' });
|
|
101
172
|
|
|
102
173
|
await update({ packageName: 'mintlify' });
|
|
103
174
|
|
|
104
|
-
expect(
|
|
105
|
-
expect(
|
|
106
|
-
|
|
175
|
+
expect(addLogSpy).toHaveBeenCalledTimes(3);
|
|
176
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
177
|
+
expect.objectContaining({ props: { message: 'updating...' } })
|
|
178
|
+
);
|
|
179
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
180
|
+
expect.objectContaining({ props: { message: 'updating mintlify client to 2.0.0...' } })
|
|
181
|
+
);
|
|
182
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
183
|
+
expect.objectContaining({
|
|
184
|
+
props: { message: 'updated mintlify to the latest version: 2.0.0' },
|
|
185
|
+
})
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
expect(execAsync).not.toHaveBeenCalled();
|
|
189
|
+
expect(previewing.downloadTargetMint).toHaveBeenCalledWith({
|
|
107
190
|
targetVersion: '2.0.0',
|
|
108
191
|
existingVersion: '1.0.0',
|
|
109
192
|
});
|
|
@@ -115,13 +198,21 @@ describe('update', () => {
|
|
|
115
198
|
client: '1.0.0',
|
|
116
199
|
});
|
|
117
200
|
vi.mocked(getLatestCliVersion).mockReturnValue('2.0.0');
|
|
118
|
-
vi.mocked(getTargetMintVersion).mockResolvedValue('2.0.0');
|
|
119
|
-
vi.mocked(
|
|
120
|
-
throw new Error('Update failed');
|
|
121
|
-
});
|
|
201
|
+
vi.mocked(previewing.getTargetMintVersion).mockResolvedValue('2.0.0');
|
|
202
|
+
vi.mocked(execAsync).mockRejectedValue(new Error('Update failed'));
|
|
122
203
|
|
|
123
204
|
await update({ packageName: 'mintlify' });
|
|
124
|
-
|
|
205
|
+
|
|
206
|
+
expect(addLogSpy).toHaveBeenCalledTimes(3);
|
|
207
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
208
|
+
expect.objectContaining({ props: { message: 'updating...' } })
|
|
209
|
+
);
|
|
210
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
211
|
+
expect.objectContaining({ props: { message: 'updating mintlify package...' } })
|
|
212
|
+
);
|
|
213
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
214
|
+
expect.objectContaining({ props: { message: 'failed to update mintlify@latest' } })
|
|
215
|
+
);
|
|
125
216
|
});
|
|
126
217
|
|
|
127
218
|
it('should handle client update failure', async () => {
|
|
@@ -130,11 +221,21 @@ describe('update', () => {
|
|
|
130
221
|
client: '1.0.0',
|
|
131
222
|
});
|
|
132
223
|
vi.mocked(getLatestCliVersion).mockReturnValue('2.0.0');
|
|
133
|
-
vi.mocked(getTargetMintVersion).mockResolvedValue('2.0.0');
|
|
134
|
-
vi.mocked(
|
|
135
|
-
vi.mocked(downloadTargetMint).mockRejectedValue(new Error('Download failed'));
|
|
224
|
+
vi.mocked(previewing.getTargetMintVersion).mockResolvedValue('2.0.0');
|
|
225
|
+
vi.mocked(execAsync).mockResolvedValue({ stdout: '', stderr: '' });
|
|
226
|
+
vi.mocked(previewing.downloadTargetMint).mockRejectedValue(new Error('Download failed'));
|
|
136
227
|
|
|
137
228
|
await update({ packageName: 'mintlify' });
|
|
138
|
-
|
|
229
|
+
|
|
230
|
+
expect(addLogSpy).toHaveBeenCalledTimes(4);
|
|
231
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
232
|
+
expect.objectContaining({ props: { message: 'updating...' } })
|
|
233
|
+
);
|
|
234
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
235
|
+
expect.objectContaining({ props: { message: 'updating mintlify client to 2.0.0...' } })
|
|
236
|
+
);
|
|
237
|
+
expect(addLogSpy).toHaveBeenCalledWith(
|
|
238
|
+
expect.objectContaining({ props: { message: 'failed to update mintlify client to 2.0.0' } })
|
|
239
|
+
);
|
|
139
240
|
});
|
|
140
241
|
});
|
package/__test__/utils.ts
CHANGED
|
@@ -9,3 +9,12 @@ export async function runCommand(...args: string[]) {
|
|
|
9
9
|
process.argv = ['node', 'cli.js', ...args];
|
|
10
10
|
return cli();
|
|
11
11
|
}
|
|
12
|
+
|
|
13
|
+
export const mockValidOpenApiDocument = {
|
|
14
|
+
openapi: '3.0.0',
|
|
15
|
+
info: {
|
|
16
|
+
title: 'Test API',
|
|
17
|
+
version: '1.0.0',
|
|
18
|
+
},
|
|
19
|
+
components: {},
|
|
20
|
+
};
|