/ src / interceptor.test.ts
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  });