Skip to content

Commit 61889ce

Browse files
authored
Add more test cases (#696)
1 parent cf66827 commit 61889ce

File tree

4 files changed

+207
-7
lines changed

4 files changed

+207
-7
lines changed

.changeset/curly-camels-doubt.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'fets': patch
3+
---
4+
5+
More strict on request parameters typing

packages/fets/src/types.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import type {
1111
ServerAdapterPlugin,
1212
ServerAdapterRequestHandler,
1313
} from '@whatwg-node/server';
14-
import { ClientTypedResponsePromise } from './client/clientResponse.js';
15-
import { ClientRequestInit } from './client/types.js';
14+
import type { ClientTypedResponsePromise } from './client/clientResponse.js';
15+
import type { ClientRequestInit } from './client/types.js';
1616
import type { SwaggerUIOpts } from './plugins/openapi.js';
1717
import type {
1818
HTTPMethod,
@@ -359,13 +359,27 @@ export type RouterPlugin<
359359
onRouteHandle?: OnRouteHandleHook<TServerContext, TComponents>;
360360
};
361361

362+
type ObjectSchemaWithPrimitiveProperties = JSONSchema & {
363+
type: 'object';
364+
properties: Record<
365+
string,
366+
{
367+
type: 'string' | 'number' | 'integer' | 'boolean' | 'null';
368+
}
369+
>;
370+
};
371+
372+
type ObjectSchema = JSONSchema & {
373+
type: 'object';
374+
};
375+
362376
export type RouteSchemas = {
363377
request?: {
364-
headers?: JSONSchema;
365-
params?: JSONSchema;
366-
query?: JSONSchema;
378+
headers?: ObjectSchemaWithPrimitiveProperties;
379+
params?: ObjectSchemaWithPrimitiveProperties;
380+
query?: ObjectSchema;
367381
json?: JSONSchema;
368-
formData?: JSONSchema;
382+
formData?: ObjectSchema;
369383
};
370384
responses?: StatusCodeMap<JSONSchema>;
371385
};

packages/fets/tests/typebox-test.ts

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,184 @@ if (res.ok) {
6464
// @ts-expect-error id is not a valid property
6565
console.log(errorBody.id);
6666
}
67+
68+
// More test cases
69+
70+
{
71+
const router = createRouter().route({
72+
path: '/user/:id',
73+
method: 'POST',
74+
schemas: {
75+
request: {
76+
params: Type.Object({
77+
id: Type.String(),
78+
}),
79+
json: Type.Object({
80+
name: Type.String(),
81+
}),
82+
},
83+
responses: {
84+
200: Type.Object({
85+
id: Type.String(),
86+
name: Type.String(),
87+
}),
88+
404: Type.Object({
89+
message: Type.String(),
90+
}),
91+
},
92+
},
93+
async handler(req) {
94+
if (req.params.id !== '1') {
95+
return Response.json(
96+
{
97+
message: 'not found',
98+
},
99+
{
100+
status: 404,
101+
},
102+
);
103+
}
104+
return Response.json({
105+
id: '1',
106+
name: 'John',
107+
});
108+
},
109+
});
110+
111+
const client = createClient<typeof router>({});
112+
113+
const res = await client['/user/:id'].post({
114+
params: {
115+
id: '1',
116+
// @ts-expect-error a is not a valid param
117+
a: 2,
118+
},
119+
json: {
120+
// @ts-expect-error name is a string
121+
name: 2,
122+
},
123+
});
124+
125+
if (res.ok) {
126+
const successBody = await res.json();
127+
// @ts-expect-error message is not a valid property
128+
console.log(successBody.message);
129+
} else {
130+
const errorBody = await res.json();
131+
// @ts-expect-error id is not a valid property
132+
console.log(errorBody.id);
133+
}
134+
}
135+
136+
// only accept TypeObject with string keys and values for request header schema
137+
// eslint-disable-next-line no-lone-blocks
138+
{
139+
// @ts-expect-error this should only accept objects
140+
createRouter().route({
141+
path: '/foo',
142+
method: 'POST',
143+
schemas: {
144+
request: {
145+
headers: Type.String(),
146+
},
147+
},
148+
async handler() {
149+
return Response.json({});
150+
},
151+
});
152+
}
153+
154+
// only accept TypeObject with string keys and values for request header schema
155+
// eslint-disable-next-line no-lone-blocks
156+
{
157+
// @ts-expect-error this should only accept objects with string values
158+
createRouter().route({
159+
path: '/foo',
160+
method: 'POST',
161+
schemas: {
162+
request: {
163+
headers: Type.Object({
164+
authorization: Type.Object({}),
165+
}),
166+
},
167+
},
168+
async handler() {
169+
return Response.json({});
170+
},
171+
});
172+
}
173+
174+
// only accept TypeObject with string keys and values for request params schema
175+
// eslint-disable-next-line no-lone-blocks
176+
{
177+
// @ts-expect-error this should only accept objects
178+
createRouter().route({
179+
path: '/foo',
180+
method: 'POST',
181+
schemas: {
182+
request: {
183+
params: Type.String(),
184+
},
185+
},
186+
async handler() {
187+
return Response.json({});
188+
},
189+
});
190+
}
191+
192+
// only accept TypeObject with string keys and values for request params schema
193+
// eslint-disable-next-line no-lone-blocks
194+
{
195+
// @ts-expect-error this should only accept objects with string values
196+
createRouter().route({
197+
path: '/foo',
198+
method: 'POST',
199+
schemas: {
200+
request: {
201+
params: Type.Object({
202+
authorization: Type.Object({}),
203+
}),
204+
},
205+
},
206+
async handler() {
207+
return Response.json({});
208+
},
209+
});
210+
}
211+
212+
// only accept TypeObject with string keys and values for request query schema
213+
// eslint-disable-next-line no-lone-blocks
214+
{
215+
// @ts-expect-error this should only accept objects
216+
createRouter().route({
217+
path: '/foo',
218+
method: 'POST',
219+
schemas: {
220+
request: {
221+
query: Type.String(),
222+
},
223+
},
224+
async handler() {
225+
return Response.json({});
226+
},
227+
});
228+
}
229+
230+
// handler should match responses
231+
// eslint-disable-next-line no-lone-blocks
232+
{
233+
createRouter().route({
234+
path: '/foo',
235+
method: 'POST',
236+
schemas: {
237+
responses: {
238+
200: Type.Object({
239+
id: Type.String(),
240+
name: Type.String(),
241+
}),
242+
},
243+
},
244+
// @ts-expect-error nothing is returned from handler that matches the responses
245+
async handler() {},
246+
});
247+
}

website/src/components/index-page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export function IndexPage(): ReactElement {
115115
</div>
116116
))}
117117
</div>
118-
<Diagram className="mx-auto max-w-[980px] [&_[fill=\\\\\\\\\\\\\\\\#70788A]]:dark:fill-gray-100 [&_[fill=\\\\\\\\\\\\\\\\#F3F4F6]]:dark:fill-gray-500" />
118+
<Diagram className="mx-auto max-w-[980px] [&_[fill=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\#70788A]]:dark:fill-gray-100 [&_[fill=\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\#F3F4F6]]:dark:fill-gray-500" />
119119
</div>
120120
</section>
121121

0 commit comments

Comments
 (0)