Skip to content

Commit 6c6ada0

Browse files
committed
feat: add tests for applyRootSecurityToServices function and improve response handling
1 parent c903e89 commit 6c6ada0

3 files changed

Lines changed: 135 additions & 1 deletion

File tree

packages/openapi-plugin/src/lib/open-api/OpenAPISchemaType.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export type OpenAPISchemaType = {
2424
required?: boolean;
2525
};
2626
responses: {
27-
[statusCode in number | 'default']: {
27+
[statusCode in number | 'default']?: {
2828
$ref?: string;
2929
description?: string;
3030
content?: {

packages/openapi-plugin/src/lib/open-api/getServices.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ export const getServices = (
6666
>
6767
>(
6868
(acc, [statusCode, response]) => {
69+
if (!response) return acc;
6970
if (response.$ref) {
7071
response = resolveDocumentLocalRef(
7172
response.$ref,
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import type { OpenAPISchemaType } from '@openapi-qraft/plugin/lib/open-api/OpenAPISchemaType';
2+
import type { OpenAPIService } from '@openapi-qraft/plugin/lib/open-api/OpenAPIService';
3+
import { describe, expect, test } from 'vitest';
4+
import { applyRootSecurityToServices } from './applyRootSecurityToServices.js';
5+
6+
function createSchema(
7+
overrides: Partial<OpenAPISchemaType> = {}
8+
): OpenAPISchemaType {
9+
return {
10+
openapi: '3.0.0',
11+
info: { title: 'API', version: '1' },
12+
paths: {},
13+
components: { parameters: undefined },
14+
...overrides,
15+
};
16+
}
17+
18+
function createOperation(
19+
path: string,
20+
method: OpenAPIService['operations'][number]['method'] = 'get'
21+
): OpenAPIService['operations'][number] {
22+
return {
23+
method,
24+
path,
25+
name: 'op',
26+
description: undefined,
27+
summary: undefined,
28+
deprecated: undefined,
29+
errors: {},
30+
success: {},
31+
parameters: undefined,
32+
requestBody: undefined,
33+
security: undefined,
34+
};
35+
}
36+
37+
function createService(
38+
operations: OpenAPIService['operations']
39+
): OpenAPIService {
40+
return {
41+
name: 'svc',
42+
variableName: 'svc',
43+
typeName: 'Svc',
44+
fileBaseName: 'svc',
45+
operations,
46+
};
47+
}
48+
49+
describe('applyRootSecurityToServices', () => {
50+
test('sets operation security from root schema when operation omits security', () => {
51+
const rootSecurity = [{ bearerAuth: [] as string[] | undefined }];
52+
const schema = createSchema({
53+
security: rootSecurity,
54+
paths: {
55+
'/items': {
56+
get: {
57+
responses: { 200: { description: 'ok' } },
58+
},
59+
},
60+
},
61+
});
62+
const services = [createService([createOperation('/items', 'get')])];
63+
64+
const result = applyRootSecurityToServices({ services, schema });
65+
66+
expect(result[0].operations[0].security).toEqual(rootSecurity);
67+
});
68+
69+
test('keeps operation-level security and does not fall back to root', () => {
70+
const rootSecurity = [{ bearerAuth: [] as string[] | undefined }];
71+
const opSecurity = [{ apiKey: ['write'] }];
72+
const schema = createSchema({
73+
security: rootSecurity,
74+
paths: {
75+
'/items': {
76+
get: {
77+
security: opSecurity,
78+
responses: { 200: { description: 'ok' } },
79+
},
80+
},
81+
},
82+
});
83+
const services = [createService([createOperation('/items', 'get')])];
84+
85+
const result = applyRootSecurityToServices({ services, schema });
86+
87+
expect(result[0].operations[0].security).toEqual(opSecurity);
88+
});
89+
90+
test('uses explicit empty security on operation instead of root', () => {
91+
const rootSecurity = [{ bearerAuth: [] as string[] | undefined }];
92+
const schema = createSchema({
93+
security: rootSecurity,
94+
paths: {
95+
'/public': {
96+
get: {
97+
security: [],
98+
responses: { 200: { description: 'ok' } },
99+
},
100+
},
101+
},
102+
});
103+
const services = [createService([createOperation('/public', 'get')])];
104+
105+
const result = applyRootSecurityToServices({ services, schema });
106+
107+
expect(result[0].operations[0].security).toEqual([]);
108+
});
109+
110+
test('returns undefined security when path or method is missing in schema', () => {
111+
const schema = createSchema({
112+
security: [{ bearerAuth: [] as string[] | undefined }],
113+
paths: {
114+
'/other': {
115+
get: {
116+
responses: { 200: { description: 'ok' } },
117+
},
118+
},
119+
},
120+
});
121+
const services = [
122+
createService([
123+
createOperation('/unknown', 'get'),
124+
createOperation('/other', 'post'),
125+
]),
126+
];
127+
128+
const result = applyRootSecurityToServices({ services, schema });
129+
130+
expect(result[0].operations[0].security).toBeUndefined();
131+
expect(result[0].operations[1].security).toBeUndefined();
132+
});
133+
});

0 commit comments

Comments
 (0)