fork of hey-api/openapi-ts because I need some additional things

test(client-ky): add comprehensive test coverage

Add test suite for ky client plugin with comprehensive coverage:
- buildUrl functionality with various path/query scenarios
- zero-length body handling for all content types
- unserialized and serialized request body handling
- request, response, and error interceptors
- error handling with throwOnError option
- retry configuration
- responseStyle configuration

Tests follow patterns from client-fetch and cover all core functionality.

+921
+652
packages/openapi-ts/src/plugins/@hey-api/client-ky/__tests__/client.test.ts
··· 1 + import { HTTPError } from 'ky'; 2 + import { describe, expect, it, vi } from 'vitest'; 3 + 4 + import type { ResolvedRequestOptions } from '../bundle'; 5 + import { createClient } from '../bundle/client'; 6 + 7 + type MockKy = ((...args: any[]) => any) & { 8 + preconnect?: any; 9 + }; 10 + 11 + describe('buildUrl', () => { 12 + const client = createClient(); 13 + 14 + const scenarios: { 15 + options: Parameters<typeof client.buildUrl>[0]; 16 + url: string; 17 + }[] = [ 18 + { 19 + options: { 20 + url: '', 21 + }, 22 + url: '/', 23 + }, 24 + { 25 + options: { 26 + url: '/foo', 27 + }, 28 + url: '/foo', 29 + }, 30 + { 31 + options: { 32 + path: { 33 + fooId: 1, 34 + }, 35 + url: '/foo/{fooId}', 36 + }, 37 + url: '/foo/1', 38 + }, 39 + { 40 + options: { 41 + path: { 42 + fooId: 1, 43 + }, 44 + query: { 45 + bar: 'baz', 46 + }, 47 + url: '/foo/{fooId}', 48 + }, 49 + url: '/foo/1?bar=baz', 50 + }, 51 + { 52 + options: { 53 + query: { 54 + bar: [], 55 + foo: [], 56 + }, 57 + url: '/', 58 + }, 59 + url: '/', 60 + }, 61 + { 62 + options: { 63 + query: { 64 + bar: [], 65 + foo: ['abc', 'def'], 66 + }, 67 + url: '/', 68 + }, 69 + url: '/?foo=abc&foo=def', 70 + }, 71 + ]; 72 + 73 + it.each(scenarios)('returns $url', ({ options, url }) => { 74 + expect(client.buildUrl(options)).toBe(url); 75 + }); 76 + }); 77 + 78 + describe('zero-length body handling', () => { 79 + const client = createClient({ baseUrl: 'https://example.com' }); 80 + 81 + it('returns empty Blob for zero-length application/octet-stream response', async () => { 82 + const mockResponse = new Response(null, { 83 + headers: { 84 + 'Content-Length': '0', 85 + 'Content-Type': 'application/octet-stream', 86 + }, 87 + status: 200, 88 + }); 89 + 90 + const mockKy: MockKy = vi.fn().mockResolvedValue(mockResponse); 91 + 92 + const result = await client.request({ 93 + ky: mockKy, 94 + method: 'GET', 95 + url: '/test', 96 + }); 97 + 98 + expect(result.data).toBeInstanceOf(Blob); 99 + expect((result.data as Blob).size).toBe(0); 100 + }); 101 + 102 + it('returns empty ArrayBuffer for zero-length response with arrayBuffer parseAs', async () => { 103 + const mockResponse = new Response(null, { 104 + headers: { 105 + 'Content-Length': '0', 106 + }, 107 + status: 200, 108 + }); 109 + 110 + const mockKy: MockKy = vi.fn().mockResolvedValue(mockResponse); 111 + 112 + const result = await client.request({ 113 + ky: mockKy, 114 + method: 'GET', 115 + parseAs: 'arrayBuffer', 116 + url: '/test', 117 + }); 118 + 119 + expect(result.data).toBeInstanceOf(ArrayBuffer); 120 + expect((result.data as ArrayBuffer).byteLength).toBe(0); 121 + }); 122 + 123 + it('returns empty string for zero-length text response', async () => { 124 + const mockResponse = new Response(null, { 125 + headers: { 126 + 'Content-Length': '0', 127 + 'Content-Type': 'text/plain', 128 + }, 129 + status: 200, 130 + }); 131 + 132 + const mockKy: MockKy = vi.fn().mockResolvedValue(mockResponse); 133 + 134 + const result = await client.request({ 135 + ky: mockKy, 136 + method: 'GET', 137 + url: '/test', 138 + }); 139 + 140 + expect(result.data).toBe(''); 141 + }); 142 + 143 + it('returns empty object for zero-length JSON response', async () => { 144 + const mockResponse = new Response(null, { 145 + headers: { 146 + 'Content-Length': '0', 147 + 'Content-Type': 'application/json', 148 + }, 149 + status: 200, 150 + }); 151 + 152 + const mockKy: MockKy = vi.fn().mockResolvedValue(mockResponse); 153 + 154 + const result = await client.request({ 155 + ky: mockKy, 156 + method: 'GET', 157 + url: '/test', 158 + }); 159 + 160 + expect(result.data).toEqual({}); 161 + }); 162 + 163 + it('returns empty FormData for zero-length multipart/form-data response', async () => { 164 + const mockResponse = new Response(null, { 165 + headers: { 166 + 'Content-Length': '0', 167 + 'Content-Type': 'multipart/form-data', 168 + }, 169 + status: 200, 170 + }); 171 + 172 + const mockKy: MockKy = vi.fn().mockResolvedValue(mockResponse); 173 + 174 + const result = await client.request({ 175 + ky: mockKy, 176 + method: 'GET', 177 + url: '/test', 178 + }); 179 + 180 + expect(result.data).toBeInstanceOf(FormData); 181 + expect([...(result.data as FormData).entries()]).toHaveLength(0); 182 + }); 183 + 184 + it('returns stream body for zero-length stream response', async () => { 185 + const mockBody = new ReadableStream(); 186 + const mockResponse = new Response(mockBody, { 187 + headers: { 188 + 'Content-Length': '0', 189 + }, 190 + status: 200, 191 + }); 192 + 193 + const mockKy: MockKy = vi.fn().mockResolvedValue(mockResponse); 194 + 195 + const result = await client.request({ 196 + ky: mockKy, 197 + method: 'GET', 198 + parseAs: 'stream', 199 + url: '/test', 200 + }); 201 + 202 + expect(result.data).toBe(mockBody); 203 + }); 204 + 205 + it('handles non-zero content correctly for comparison', async () => { 206 + const blobContent = new Blob(['test data']); 207 + const mockResponse = new Response(blobContent, { 208 + headers: { 209 + 'Content-Type': 'application/octet-stream', 210 + }, 211 + status: 200, 212 + }); 213 + 214 + const mockKy: MockKy = vi.fn().mockResolvedValue(mockResponse); 215 + 216 + const result = await client.request({ 217 + ky: mockKy, 218 + method: 'GET', 219 + url: '/test', 220 + }); 221 + 222 + expect(result.data).toBeInstanceOf(Blob); 223 + expect((result.data as Blob).size).toBeGreaterThan(0); 224 + }); 225 + }); 226 + 227 + describe('unserialized request body handling', () => { 228 + const client = createClient({ baseUrl: 'https://example.com' }); 229 + 230 + const scenarios = [ 231 + { body: 0, textValue: '0' }, 232 + { body: false, textValue: 'false' }, 233 + { body: 'test string', textValue: 'test string' }, 234 + { body: '', textValue: '' }, 235 + ]; 236 + 237 + it.each(scenarios)( 238 + 'handles plain text body with $body value', 239 + async ({ body, textValue }) => { 240 + const mockResponse = new Response(JSON.stringify({ success: true }), { 241 + headers: { 242 + 'Content-Type': 'application/json', 243 + }, 244 + status: 200, 245 + }); 246 + 247 + const mockKy: MockKy = vi.fn().mockResolvedValueOnce(mockResponse); 248 + 249 + const result = await client.post({ 250 + body, 251 + bodySerializer: null, 252 + headers: { 253 + 'Content-Type': 'text/plain', 254 + }, 255 + ky: mockKy, 256 + url: '/test', 257 + }); 258 + 259 + expect(mockKy).toHaveBeenCalledWith( 260 + expect.objectContaining({ 261 + body: expect.any(ReadableStream), 262 + }), 263 + expect.any(Object), 264 + ); 265 + 266 + await expect(result.request.text()).resolves.toEqual(textValue); 267 + expect(result.request.headers.get('Content-Type')).toEqual('text/plain'); 268 + }, 269 + ); 270 + }); 271 + 272 + describe('serialized request body handling', () => { 273 + const client = createClient({ baseUrl: 'https://example.com' }); 274 + 275 + const scenarios = [ 276 + { 277 + body: '', 278 + expectBodyValue: false, 279 + expectContentHeader: false, 280 + serializedBody: '', 281 + textValue: '', 282 + }, 283 + { 284 + body: 0, 285 + expectBodyValue: true, 286 + expectContentHeader: true, 287 + serializedBody: 0, 288 + textValue: '0', 289 + }, 290 + { 291 + body: false, 292 + expectBodyValue: true, 293 + expectContentHeader: true, 294 + serializedBody: false, 295 + textValue: 'false', 296 + }, 297 + { 298 + body: {}, 299 + expectBodyValue: true, 300 + expectContentHeader: true, 301 + serializedBody: '{"key":"value"}', 302 + textValue: '{"key":"value"}', 303 + }, 304 + ]; 305 + 306 + it.each(scenarios)( 307 + 'handles $serializedBody serializedBody value', 308 + async ({ 309 + body, 310 + expectBodyValue, 311 + expectContentHeader, 312 + serializedBody, 313 + textValue, 314 + }) => { 315 + const mockResponse = new Response(JSON.stringify({ success: true }), { 316 + headers: { 317 + 'Content-Type': 'application/json', 318 + }, 319 + status: 200, 320 + }); 321 + 322 + const mockKy: MockKy = vi.fn().mockResolvedValueOnce(mockResponse); 323 + 324 + const result = await client.post({ 325 + body, 326 + bodySerializer: () => serializedBody, 327 + headers: { 328 + 'Content-Type': 'application/json', 329 + }, 330 + ky: mockKy, 331 + url: '/test', 332 + }); 333 + 334 + expect(mockKy).toHaveBeenCalledWith( 335 + expect.objectContaining({ 336 + body: expectBodyValue ? expect.any(ReadableStream) : null, 337 + }), 338 + expect.any(Object), 339 + ); 340 + 341 + await expect(result.request.text()).resolves.toEqual(textValue); 342 + expect(result.request.headers.get('Content-Type')).toEqual( 343 + expectContentHeader ? 'application/json' : null, 344 + ); 345 + }, 346 + ); 347 + }); 348 + 349 + describe('request interceptor', () => { 350 + const client = createClient({ baseUrl: 'https://example.com' }); 351 + 352 + const scenarios = [ 353 + { 354 + body: 'test string', 355 + bodySerializer: null, 356 + contentType: 'text/plain', 357 + expectedSerializedValue: undefined, 358 + expectedValue: async (request: Request) => await request.text(), 359 + }, 360 + { 361 + body: { key: 'value' }, 362 + bodySerializer: (body: object) => JSON.stringify(body), 363 + contentType: 'application/json', 364 + expectedSerializedValue: '{"key":"value"}', 365 + expectedValue: async (request: Request) => await request.json(), 366 + }, 367 + ]; 368 + 369 + it.each(scenarios)( 370 + 'exposes $contentType serialized and raw body values', 371 + async ({ body, bodySerializer, contentType, expectedSerializedValue }) => { 372 + const mockResponse = new Response(JSON.stringify({ success: true }), { 373 + headers: { 374 + 'Content-Type': 'application/json', 375 + }, 376 + status: 200, 377 + }); 378 + 379 + const mockKy: MockKy = vi.fn().mockResolvedValueOnce(mockResponse); 380 + 381 + const mockRequestInterceptor = vi 382 + .fn() 383 + .mockImplementation( 384 + (request: Request, options: ResolvedRequestOptions) => { 385 + expect(options.serializedBody).toBe(expectedSerializedValue); 386 + expect(options.body).toBe(body); 387 + 388 + return request; 389 + }, 390 + ); 391 + 392 + const interceptorId = client.interceptors.request.use( 393 + mockRequestInterceptor, 394 + ); 395 + 396 + await client.post({ 397 + body, 398 + bodySerializer, 399 + headers: { 400 + 'Content-Type': contentType, 401 + }, 402 + ky: mockKy, 403 + url: '/test', 404 + }); 405 + 406 + expect(mockRequestInterceptor).toHaveBeenCalledOnce(); 407 + 408 + client.interceptors.request.eject(interceptorId); 409 + }, 410 + ); 411 + }); 412 + 413 + describe('response interceptor', () => { 414 + const client = createClient({ baseUrl: 'https://example.com' }); 415 + 416 + it('allows response transformation', async () => { 417 + const mockResponse = new Response(JSON.stringify({ success: true }), { 418 + headers: { 419 + 'Content-Type': 'application/json', 420 + }, 421 + status: 200, 422 + }); 423 + 424 + const mockKy: MockKy = vi.fn().mockResolvedValue(mockResponse); 425 + 426 + const mockResponseInterceptor = vi 427 + .fn() 428 + .mockImplementation((response: Response) => { 429 + expect(response).toBe(mockResponse); 430 + return response; 431 + }); 432 + 433 + const interceptorId = client.interceptors.response.use( 434 + mockResponseInterceptor, 435 + ); 436 + 437 + await client.get({ 438 + ky: mockKy, 439 + url: '/test', 440 + }); 441 + 442 + expect(mockResponseInterceptor).toHaveBeenCalledOnce(); 443 + 444 + client.interceptors.response.eject(interceptorId); 445 + }); 446 + }); 447 + 448 + describe('error handling', () => { 449 + const client = createClient({ baseUrl: 'https://example.com' }); 450 + 451 + it('handles HTTP errors with throwOnError: false', async () => { 452 + const errorResponse = new Response( 453 + JSON.stringify({ message: 'Not found' }), 454 + { 455 + headers: { 456 + 'Content-Type': 'application/json', 457 + }, 458 + status: 404, 459 + }, 460 + ); 461 + 462 + const mockKy: MockKy = vi.fn().mockRejectedValue( 463 + new HTTPError(errorResponse, new Request('https://example.com/test'), { 464 + method: 'GET', 465 + } as any), 466 + ); 467 + 468 + const result = await client.get({ 469 + ky: mockKy, 470 + throwOnError: false, 471 + url: '/test', 472 + }); 473 + 474 + expect(result.error).toEqual({ message: 'Not found' }); 475 + expect(result.response.status).toBe(404); 476 + }); 477 + 478 + it('throws HTTP errors with throwOnError: true', async () => { 479 + const errorResponse = new Response( 480 + JSON.stringify({ message: 'Not found' }), 481 + { 482 + headers: { 483 + 'Content-Type': 'application/json', 484 + }, 485 + status: 404, 486 + }, 487 + ); 488 + 489 + const mockKy: MockKy = vi.fn().mockRejectedValue( 490 + new HTTPError(errorResponse, new Request('https://example.com/test'), { 491 + method: 'GET', 492 + } as any), 493 + ); 494 + 495 + await expect( 496 + client.get({ 497 + ky: mockKy, 498 + throwOnError: true, 499 + url: '/test', 500 + }), 501 + ).rejects.toEqual({ message: 'Not found' }); 502 + }); 503 + 504 + it('handles text error responses', async () => { 505 + const errorResponse = new Response('Internal Server Error', { 506 + status: 500, 507 + }); 508 + 509 + const mockKy: MockKy = vi.fn().mockRejectedValue( 510 + new HTTPError(errorResponse, new Request('https://example.com/test'), { 511 + method: 'GET', 512 + } as any), 513 + ); 514 + 515 + const result = await client.get({ 516 + ky: mockKy, 517 + throwOnError: false, 518 + url: '/test', 519 + }); 520 + 521 + expect(result.error).toBe('Internal Server Error'); 522 + expect(result.response.status).toBe(500); 523 + }); 524 + }); 525 + 526 + describe('error interceptor', () => { 527 + const client = createClient({ baseUrl: 'https://example.com' }); 528 + 529 + it('allows error transformation', async () => { 530 + const errorResponse = new Response( 531 + JSON.stringify({ message: 'Not found' }), 532 + { 533 + headers: { 534 + 'Content-Type': 'application/json', 535 + }, 536 + status: 404, 537 + }, 538 + ); 539 + 540 + const mockKy: MockKy = vi.fn().mockRejectedValue( 541 + new HTTPError(errorResponse, new Request('https://example.com/test'), { 542 + method: 'GET', 543 + } as any), 544 + ); 545 + 546 + const mockErrorInterceptor = vi 547 + .fn() 548 + .mockImplementation((error: any) => ({ transformed: true, ...error })); 549 + 550 + const interceptorId = client.interceptors.error.use(mockErrorInterceptor); 551 + 552 + const result = await client.get({ 553 + ky: mockKy, 554 + throwOnError: false, 555 + url: '/test', 556 + }); 557 + 558 + expect(mockErrorInterceptor).toHaveBeenCalledOnce(); 559 + expect(result.error).toEqual({ message: 'Not found', transformed: true }); 560 + 561 + client.interceptors.error.eject(interceptorId); 562 + }); 563 + }); 564 + 565 + describe('retry configuration', () => { 566 + const client = createClient({ baseUrl: 'https://example.com' }); 567 + 568 + it('passes retry configuration to ky', async () => { 569 + const mockResponse = new Response(JSON.stringify({ success: true }), { 570 + headers: { 571 + 'Content-Type': 'application/json', 572 + }, 573 + status: 200, 574 + }); 575 + 576 + const mockKy: MockKy = vi.fn().mockResolvedValue(mockResponse); 577 + 578 + await client.get({ 579 + ky: mockKy, 580 + retry: { 581 + limit: 3, 582 + methods: ['get', 'post'], 583 + statusCodes: [408, 429, 500], 584 + }, 585 + url: '/test', 586 + }); 587 + 588 + expect(mockKy).toHaveBeenCalledWith( 589 + expect.any(Request), 590 + expect.objectContaining({ 591 + retry: { 592 + limit: 3, 593 + methods: ['get', 'post'], 594 + statusCodes: [408, 429, 500], 595 + }, 596 + }), 597 + ); 598 + }); 599 + }); 600 + 601 + describe('responseStyle configuration', () => { 602 + const client = createClient({ 603 + baseUrl: 'https://example.com', 604 + responseStyle: 'data', 605 + }); 606 + 607 + it('returns only data when responseStyle is "data"', async () => { 608 + const mockResponse = new Response(JSON.stringify({ result: 'success' }), { 609 + headers: { 610 + 'Content-Type': 'application/json', 611 + }, 612 + status: 200, 613 + }); 614 + 615 + const mockKy: MockKy = vi.fn().mockResolvedValue(mockResponse); 616 + 617 + const result = await client.get({ 618 + ky: mockKy, 619 + url: '/test', 620 + }); 621 + 622 + expect(result).toEqual({ result: 'success' }); 623 + expect(result).not.toHaveProperty('response'); 624 + expect(result).not.toHaveProperty('request'); 625 + }); 626 + 627 + it('returns undefined for errors when responseStyle is "data"', async () => { 628 + const errorResponse = new Response( 629 + JSON.stringify({ message: 'Not found' }), 630 + { 631 + headers: { 632 + 'Content-Type': 'application/json', 633 + }, 634 + status: 404, 635 + }, 636 + ); 637 + 638 + const mockKy: MockKy = vi.fn().mockRejectedValue( 639 + new HTTPError(errorResponse, new Request('https://example.com/test'), { 640 + method: 'GET', 641 + } as any), 642 + ); 643 + 644 + const result = await client.get({ 645 + ky: mockKy, 646 + throwOnError: false, 647 + url: '/test', 648 + }); 649 + 650 + expect(result).toBeUndefined(); 651 + }); 652 + });
+269
packages/openapi-ts/src/plugins/@hey-api/client-ky/__tests__/utils.test.ts
··· 1 + import { describe, expect, it, vi } from 'vitest'; 2 + 3 + import type { Auth } from '../../client-core/bundle/auth'; 4 + import type { Client } from '../bundle/types'; 5 + import { buildUrl, getParseAs, setAuthParams } from '../bundle/utils'; 6 + 7 + describe('buildUrl', () => { 8 + const scenarios: Array<{ 9 + options: Parameters<Client['buildUrl']>[0]; 10 + url: string; 11 + }> = [ 12 + { 13 + options: { 14 + path: { 15 + id: new Date('2025-01-01T00:00:00.000Z'), 16 + }, 17 + url: '/foo/{id}', 18 + }, 19 + url: '/foo/2025-01-01T00:00:00.000Z', 20 + }, 21 + ]; 22 + 23 + it.each(scenarios)('builds $url', async ({ options, url }) => { 24 + expect(buildUrl(options)).toEqual(url); 25 + }); 26 + }); 27 + 28 + describe('getParseAs', () => { 29 + const scenarios: Array<{ 30 + content: Parameters<typeof getParseAs>[0]; 31 + parseAs: ReturnType<typeof getParseAs>; 32 + }> = [ 33 + { 34 + content: null, 35 + parseAs: 'stream', 36 + }, 37 + { 38 + content: 'application/json', 39 + parseAs: 'json', 40 + }, 41 + { 42 + content: 'application/ld+json', 43 + parseAs: 'json', 44 + }, 45 + { 46 + content: 'application/ld+json;charset=utf-8', 47 + parseAs: 'json', 48 + }, 49 + { 50 + content: 'application/ld+json; charset=utf-8', 51 + parseAs: 'json', 52 + }, 53 + { 54 + content: 'multipart/form-data', 55 + parseAs: 'formData', 56 + }, 57 + { 58 + content: 'application/*', 59 + parseAs: 'blob', 60 + }, 61 + { 62 + content: 'audio/*', 63 + parseAs: 'blob', 64 + }, 65 + { 66 + content: 'image/*', 67 + parseAs: 'blob', 68 + }, 69 + { 70 + content: 'video/*', 71 + parseAs: 'blob', 72 + }, 73 + { 74 + content: 'text/*', 75 + parseAs: 'text', 76 + }, 77 + { 78 + content: 'unsupported', 79 + parseAs: undefined, 80 + }, 81 + ]; 82 + 83 + it.each(scenarios)( 84 + 'detects $content as $parseAs', 85 + async ({ content, parseAs }) => { 86 + expect(getParseAs(content)).toEqual(parseAs); 87 + }, 88 + ); 89 + }); 90 + 91 + describe('setAuthParams', () => { 92 + it('sets bearer token in headers', async () => { 93 + const auth = vi.fn().mockReturnValue('foo'); 94 + const headers = new Headers(); 95 + const query: Record<any, unknown> = {}; 96 + await setAuthParams({ 97 + auth, 98 + headers, 99 + query, 100 + security: [ 101 + { 102 + name: 'baz', 103 + scheme: 'bearer', 104 + type: 'http', 105 + }, 106 + ], 107 + }); 108 + expect(auth).toHaveBeenCalled(); 109 + expect(headers.get('baz')).toBe('Bearer foo'); 110 + expect(Object.keys(query).length).toBe(0); 111 + }); 112 + 113 + it('sets access token in query', async () => { 114 + const auth = vi.fn().mockReturnValue('foo'); 115 + const headers = new Headers(); 116 + const query: Record<any, unknown> = {}; 117 + await setAuthParams({ 118 + auth, 119 + headers, 120 + query, 121 + security: [ 122 + { 123 + in: 'query', 124 + name: 'baz', 125 + scheme: 'bearer', 126 + type: 'http', 127 + }, 128 + ], 129 + }); 130 + expect(auth).toHaveBeenCalled(); 131 + expect(headers.get('baz')).toBeNull(); 132 + expect(query.baz).toBe('Bearer foo'); 133 + }); 134 + 135 + it('sets Authorization header when `in` and `name` are undefined', async () => { 136 + const auth = vi.fn().mockReturnValue('foo'); 137 + const headers = new Headers(); 138 + const query: Record<any, unknown> = {}; 139 + await setAuthParams({ 140 + auth, 141 + headers, 142 + query, 143 + security: [ 144 + { 145 + type: 'http', 146 + }, 147 + ], 148 + }); 149 + expect(auth).toHaveBeenCalled(); 150 + expect(headers.get('Authorization')).toBe('foo'); 151 + expect(query).toEqual({}); 152 + }); 153 + 154 + it('sets first scheme only', async () => { 155 + const auth = vi.fn().mockReturnValue('foo'); 156 + const headers = new Headers(); 157 + const query: Record<any, unknown> = {}; 158 + await setAuthParams({ 159 + auth, 160 + headers, 161 + query, 162 + security: [ 163 + { 164 + name: 'baz', 165 + scheme: 'bearer', 166 + type: 'http', 167 + }, 168 + { 169 + in: 'query', 170 + name: 'baz', 171 + scheme: 'bearer', 172 + type: 'http', 173 + }, 174 + ], 175 + }); 176 + expect(auth).toHaveBeenCalled(); 177 + expect(headers.get('baz')).toBe('Bearer foo'); 178 + expect(Object.keys(query).length).toBe(0); 179 + }); 180 + 181 + it('sets first scheme with token', async () => { 182 + const auth = vi.fn().mockImplementation((auth: Auth) => { 183 + if (auth.type === 'apiKey') { 184 + return; 185 + } 186 + return 'foo'; 187 + }); 188 + const headers = new Headers(); 189 + const query: Record<any, unknown> = {}; 190 + await setAuthParams({ 191 + auth, 192 + headers, 193 + query, 194 + security: [ 195 + { 196 + name: 'baz', 197 + type: 'apiKey', 198 + }, 199 + { 200 + in: 'query', 201 + name: 'baz', 202 + scheme: 'bearer', 203 + type: 'http', 204 + }, 205 + ], 206 + }); 207 + expect(auth).toHaveBeenCalled(); 208 + expect(headers.get('baz')).toBeNull(); 209 + expect(query.baz).toBe('Bearer foo'); 210 + }); 211 + 212 + it('sets an API key in a cookie', async () => { 213 + const auth = vi.fn().mockReturnValue('foo'); 214 + const headers = new Headers(); 215 + const query: Record<any, unknown> = {}; 216 + await setAuthParams({ 217 + auth, 218 + headers, 219 + query, 220 + security: [ 221 + { 222 + in: 'cookie', 223 + name: 'baz', 224 + type: 'apiKey', 225 + }, 226 + ], 227 + }); 228 + expect(auth).toHaveBeenCalled(); 229 + expect(headers.get('Cookie')).toBe('baz=foo'); 230 + expect(query).toEqual({}); 231 + }); 232 + 233 + it('sets only one specific header', async () => { 234 + const auth = vi.fn(({ name }: Auth) => { 235 + if (name === 'baz') { 236 + return 'foo'; 237 + } 238 + return 'buz'; 239 + }); 240 + const headers = new Headers(); 241 + const query: Record<any, unknown> = {}; 242 + await setAuthParams({ 243 + auth, 244 + headers, 245 + query, 246 + security: [ 247 + { 248 + name: 'baz', 249 + scheme: 'bearer', 250 + type: 'http', 251 + }, 252 + { 253 + name: 'fiz', 254 + type: 'http', 255 + }, 256 + { 257 + in: 'query', 258 + name: 'baz', 259 + scheme: 'bearer', 260 + type: 'http', 261 + }, 262 + ], 263 + }); 264 + expect(auth).toHaveBeenCalled(); 265 + expect(headers.get('baz')).toBe('Bearer foo'); 266 + expect(headers.get('fiz')).toBe('buz'); 267 + expect(Object.keys(query).length).toBe(0); 268 + }); 269 + });