|
1 | 1 | import { describe, expect, it, vi } from 'vitest'; |
2 | | -import { _addTracingHeadersToFetchRequest } from '../../src/fetch'; |
| 2 | +import { _addTracingHeadersToFetchRequest, instrumentFetchRequest } from '../../src/fetch'; |
| 3 | +import type { Span } from '../../src/types-hoist/span'; |
3 | 4 |
|
4 | 5 | const { DEFAULT_SENTRY_TRACE, DEFAULT_BAGGAGE } = vi.hoisted(() => ({ |
5 | 6 | DEFAULT_SENTRY_TRACE: 'defaultTraceId-defaultSpanId-1', |
@@ -409,3 +410,94 @@ describe('_addTracingHeadersToFetchRequest', () => { |
409 | 410 | }); |
410 | 411 | }); |
411 | 412 | }); |
| 413 | + |
| 414 | +describe('instrumentFetchRequest', () => { |
| 415 | + describe('options object mutation', () => { |
| 416 | + it('does not mutate the original options object', () => { |
| 417 | + const originalOptions = { method: 'POST', body: JSON.stringify({ data: 'test' }) }; |
| 418 | + const originalOptionsSnapshot = { ...originalOptions }; |
| 419 | + |
| 420 | + const handlerData = { |
| 421 | + fetchData: { url: '/api/test', method: 'POST' }, |
| 422 | + args: ['/api/test', originalOptions] as unknown[], |
| 423 | + startTimestamp: Date.now(), |
| 424 | + }; |
| 425 | + |
| 426 | + const spans: Record<string, Span> = {}; |
| 427 | + |
| 428 | + instrumentFetchRequest( |
| 429 | + handlerData, |
| 430 | + () => true, |
| 431 | + () => true, |
| 432 | + spans, |
| 433 | + { spanOrigin: 'auto.http.browser' }, |
| 434 | + ); |
| 435 | + |
| 436 | + // original options object was not mutated |
| 437 | + expect(originalOptions).toEqual(originalOptionsSnapshot); |
| 438 | + expect(originalOptions).not.toHaveProperty('headers'); |
| 439 | + }); |
| 440 | + |
| 441 | + it('does not throw with a frozen options object', () => { |
| 442 | + const frozenOptions = Object.freeze({ method: 'POST', body: JSON.stringify({ data: 'test' }) }); |
| 443 | + |
| 444 | + const handlerData = { |
| 445 | + fetchData: { url: '/api/test', method: 'POST' }, |
| 446 | + args: ['/api/test', frozenOptions] as unknown[], |
| 447 | + startTimestamp: Date.now(), |
| 448 | + }; |
| 449 | + |
| 450 | + const spans: Record<string, Span> = {}; |
| 451 | + |
| 452 | + // This should not throw, even though the original object is frozen |
| 453 | + expect(() => { |
| 454 | + instrumentFetchRequest( |
| 455 | + handlerData, |
| 456 | + () => true, |
| 457 | + () => true, |
| 458 | + spans, |
| 459 | + { spanOrigin: 'auto.http.browser' }, |
| 460 | + ); |
| 461 | + }).not.toThrow(); |
| 462 | + |
| 463 | + // args[1] is a new object with headers (not the frozen one) |
| 464 | + const resultOptions = handlerData.args[1] as { headers?: unknown }; |
| 465 | + expect(resultOptions).toHaveProperty('headers'); |
| 466 | + expect(resultOptions).not.toBe(frozenOptions); |
| 467 | + }); |
| 468 | + |
| 469 | + it('preserves existing properties when cloning options', () => { |
| 470 | + const originalOptions = { |
| 471 | + method: 'POST', |
| 472 | + body: JSON.stringify({ data: 'test' }), |
| 473 | + credentials: 'include' as const, |
| 474 | + mode: 'cors' as const, |
| 475 | + }; |
| 476 | + |
| 477 | + const handlerData = { |
| 478 | + fetchData: { url: '/api/test', method: 'POST' }, |
| 479 | + args: ['/api/test', originalOptions] as unknown[], |
| 480 | + startTimestamp: Date.now(), |
| 481 | + }; |
| 482 | + |
| 483 | + const spans: Record<string, Span> = {}; |
| 484 | + |
| 485 | + instrumentFetchRequest( |
| 486 | + handlerData, |
| 487 | + () => true, |
| 488 | + () => true, |
| 489 | + spans, |
| 490 | + { spanOrigin: 'auto.http.browser' }, |
| 491 | + ); |
| 492 | + |
| 493 | + const resultOptions = handlerData.args[1] as Record<string, unknown>; |
| 494 | + |
| 495 | + // all original properties are preserved in the new object |
| 496 | + expect(resultOptions.method).toBe('POST'); |
| 497 | + expect(resultOptions.body).toBe(originalOptions.body); |
| 498 | + expect(resultOptions.credentials).toBe('include'); |
| 499 | + expect(resultOptions.mode).toBe('cors'); |
| 500 | + expect(resultOptions).toHaveProperty('headers'); |
| 501 | + }); |
| 502 | + }); |
| 503 | +}); |
0 commit comments