Skip to content

Commit ba2f4af

Browse files
frontend: Add test for '@apidevtools/swagger-parser'
Signed-off-by: adwait-godbole <adwaitngodbole@gmail.com>
1 parent f979bf5 commit ba2f4af

File tree

3 files changed

+135
-10
lines changed

3 files changed

+135
-10
lines changed

frontend/src/components/common/Resource/DocsViewer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { TreeView } from '@mui/x-tree-view/TreeView';
66
// import * as buffer from 'buffer';
77
import React from 'react';
88
import { useTranslation } from 'react-i18next';
9-
import getDocDefinitions from '../../../lib/docs';
9+
import { getDocDefinitions } from '../../../lib/docs';
1010
import Empty from '../EmptyContent';
1111
import Loader from '../Loader';
1212

frontend/src/lib/docs.test.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import Swagger from '@apidevtools/swagger-parser';
2+
import { Mock, vi } from 'vitest';
3+
import { getDocDefinitions, getDocs } from './docs';
4+
import { request } from './k8s/apiProxy';
5+
6+
vi.mock('@apidevtools/swagger-parser', () => ({
7+
default: { dereference: vi.fn() },
8+
}));
9+
10+
vi.mock('./k8s/apiProxy', () => ({
11+
request: vi.fn(),
12+
}));
13+
14+
describe('getDocs', () => {
15+
beforeEach(() => {
16+
vi.resetAllMocks();
17+
});
18+
19+
it('should fetch and dereference the OpenAPI docs', async () => {
20+
const mockDocs = { definitions: {} };
21+
(request as Mock).mockResolvedValue(mockDocs);
22+
(Swagger.dereference as Mock).mockResolvedValue(mockDocs);
23+
24+
const result = await getDocs();
25+
26+
expect(request).toHaveBeenCalledWith('/openapi/v2');
27+
expect(Swagger.dereference).toHaveBeenCalledWith(mockDocs);
28+
expect(result).toEqual(mockDocs);
29+
});
30+
31+
it('should handle API request errors', async () => {
32+
(request as Mock).mockRejectedValue(new Error('API request failed'));
33+
34+
await expect(getDocs()).rejects.toThrow('API request failed');
35+
});
36+
37+
it('should handle Swagger parser errors', async () => {
38+
const mockDocs = { definitions: {} };
39+
(request as Mock).mockResolvedValue(mockDocs);
40+
(Swagger.dereference as Mock).mockRejectedValue(new Error('Swagger parsing failed'));
41+
42+
await expect(getDocs()).rejects.toThrow('Swagger parsing failed');
43+
});
44+
});
45+
46+
describe('getDocDefinitions', () => {
47+
beforeEach(() => {
48+
vi.resetAllMocks();
49+
});
50+
51+
it('should return the correct definition for given API version and kind', async () => {
52+
const mockDocs = {
53+
definitions: {
54+
PlaceholderKey: {
55+
'x-kubernetes-group-version-kind': [
56+
{ group: 'apps', version: 'v1', kind: 'ExampleKind' },
57+
],
58+
},
59+
},
60+
};
61+
(request as Mock).mockResolvedValue(mockDocs);
62+
(Swagger.dereference as Mock).mockResolvedValue(mockDocs);
63+
64+
const result = await getDocDefinitions('apps/v1', 'ExampleKind');
65+
66+
expect(result).toBeDefined();
67+
expect(result).toEqual(mockDocs.definitions.PlaceholderKey);
68+
});
69+
70+
it('should correctly parse API version when group is missing', async () => {
71+
const mockDocs = {
72+
definitions: {
73+
PlaceholderKey: {
74+
'x-kubernetes-group-version-kind': [{ group: '', version: 'v1', kind: 'ExampleKind' }],
75+
},
76+
},
77+
};
78+
(request as Mock).mockResolvedValue(mockDocs);
79+
(Swagger.dereference as Mock).mockResolvedValue(mockDocs);
80+
81+
const result = await getDocDefinitions('v1', 'ExampleKind');
82+
83+
expect(result).toBeDefined();
84+
expect(result).toEqual(mockDocs.definitions.PlaceholderKey);
85+
});
86+
87+
it('should return undefined when no matching definition is found', async () => {
88+
const mockDocs = {
89+
definitions: {
90+
PlaceholderKey: {
91+
'x-kubernetes-group-version-kind': [
92+
{ group: 'apps', version: 'v1', kind: 'ExampleKind' },
93+
],
94+
},
95+
},
96+
};
97+
(request as Mock).mockResolvedValue(mockDocs);
98+
(Swagger.dereference as Mock).mockResolvedValue(mockDocs);
99+
100+
const result = await getDocDefinitions('apps/v1', 'NonExistentKind');
101+
102+
expect(result).toBeUndefined();
103+
});
104+
105+
it('should handle cases where definitions are missing', async () => {
106+
const mockDocs = { definitions: {} };
107+
(request as Mock).mockResolvedValue(mockDocs);
108+
(Swagger.dereference as Mock).mockResolvedValue(mockDocs);
109+
110+
const result = await getDocDefinitions('apps/v1', 'ExampleKind');
111+
112+
expect(result).toBeUndefined();
113+
});
114+
115+
it("should handle missing key 'x-kubernetes-group-version-kind'", async () => {
116+
const mockDocs = {
117+
definitions: {
118+
PlaceholderKey: {
119+
someOtherProperty: 'value',
120+
},
121+
},
122+
};
123+
(request as Mock).mockResolvedValue(mockDocs);
124+
(Swagger.dereference as Mock).mockResolvedValue(mockDocs);
125+
126+
const result = await getDocDefinitions('apps/v1', 'ExampleKind');
127+
128+
expect(result).toBeUndefined();
129+
});
130+
});

frontend/src/lib/docs.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,14 @@ import Swagger from '@apidevtools/swagger-parser';
66
import { OpenAPIV2 } from 'openapi-types';
77
import { request } from './k8s/apiProxy';
88

9-
let docsPromise: ReturnType<typeof getDocs>;
10-
11-
async function getDocs() {
9+
export async function getDocs() {
1210
const docs = await request('/openapi/v2');
1311
return Swagger.dereference(docs);
1412
}
1513

16-
export default async function getDocDefinitions(apiVersion: string, kind: string) {
17-
if (!docsPromise) {
18-
docsPromise = getDocs(); // Don't wait here. Just kick off the request
19-
}
20-
21-
const { definitions = {} } = (await docsPromise) as OpenAPIV2.Document;
14+
export async function getDocDefinitions(apiVersion: string, kind: string) {
15+
// We want a fresh call to getDocs() each time to ensure we get the latest mock data during testing
16+
const { definitions = {} } = (await getDocs()) as OpenAPIV2.Document;
2217

2318
let [group, version] = apiVersion.split('/');
2419
if (!version) {

0 commit comments

Comments
 (0)