interceptor.test.ts
1 /** 2 * Tests for interceptor.ts: JavaScript code generators for XHR/Fetch interception. 3 */ 4 5 import { describe, it, expect } from 'vitest'; 6 import { generateInterceptorJs, generateReadInterceptedJs, generateTapInterceptorJs } from './interceptor.js'; 7 8 describe('generateInterceptorJs', () => { 9 it('generates valid JavaScript function source', () => { 10 const js = generateInterceptorJs('"api/search"'); 11 expect(js).toContain('window.fetch'); 12 expect(js).toContain('XMLHttpRequest'); 13 expect(js).toContain('"api/search"'); 14 // Should be a function expression wrapping 15 expect(js.trim()).toMatch(/^\(\)\s*=>/); 16 }); 17 18 it('uses default array name and patch guard', () => { 19 const js = generateInterceptorJs('"test"'); 20 expect(js).toContain('__opencli_intercepted'); 21 expect(js).toContain('__opencli_interceptor_patched'); 22 }); 23 24 it('uses custom array name and patch guard', () => { 25 const js = generateInterceptorJs('"test"', { 26 arrayName: '__my_data', 27 patchGuard: '__my_guard', 28 }); 29 expect(js).toContain('__my_data'); 30 expect(js).toContain('__my_guard'); 31 expect(js).not.toContain('__opencli_intercepted'); 32 }); 33 34 it('includes fetch clone and json parsing', () => { 35 const js = generateInterceptorJs('"api"'); 36 expect(js).toContain('response.clone()'); 37 expect(js).toContain('clone.json()'); 38 }); 39 40 it('includes XHR open and send patching', () => { 41 const js = generateInterceptorJs('"api"'); 42 expect(js).toContain('XMLHttpRequest.prototype'); 43 expect(js).toContain('__origOpen'); 44 expect(js).toContain('__origSend'); 45 }); 46 }); 47 48 describe('generateReadInterceptedJs', () => { 49 it('generates valid JavaScript to read and clear data', () => { 50 const js = generateReadInterceptedJs(); 51 expect(js).toContain('__opencli_intercepted'); 52 // Should clear the array after reading 53 expect(js).toContain('= []'); 54 }); 55 56 it('uses custom array name', () => { 57 const js = generateReadInterceptedJs('__custom_arr'); 58 expect(js).toContain('__custom_arr'); 59 expect(js).not.toContain('__opencli_intercepted'); 60 }); 61 }); 62 63 describe('generateTapInterceptorJs', () => { 64 it('returns all required fields', () => { 65 const tap = generateTapInterceptorJs('"api/data"'); 66 67 expect(tap.setupVar).toBeDefined(); 68 expect(tap.capturedVar).toBe('captured'); 69 expect(tap.promiseVar).toBe('capturePromise'); 70 expect(tap.resolveVar).toBe('captureResolve'); 71 expect(tap.fetchPatch).toBeDefined(); 72 expect(tap.xhrPatch).toBeDefined(); 73 expect(tap.restorePatch).toBeDefined(); 74 }); 75 76 it('contains the capture pattern in setup', () => { 77 const tap = generateTapInterceptorJs('"my-pattern"'); 78 expect(tap.setupVar).toContain('"my-pattern"'); 79 }); 80 81 it('restores original fetch and XHR in restorePatch', () => { 82 const tap = generateTapInterceptorJs('"test"'); 83 expect(tap.restorePatch).toContain('origFetch'); 84 expect(tap.restorePatch).toContain('origXhrOpen'); 85 expect(tap.restorePatch).toContain('origXhrSend'); 86 }); 87 88 it('uses first-match capture (only first response)', () => { 89 const tap = generateTapInterceptorJs('"test"'); 90 // Both fetch and xhr patches should check !captured before storing 91 expect(tap.fetchPatch).toContain('!captured'); 92 expect(tap.xhrPatch).toContain('!captured'); 93 }); 94 });