network-key.test.ts
1 import { describe, expect, it } from 'vitest'; 2 import { assignKeys, deriveKey } from './network-key.js'; 3 4 describe('deriveKey', () => { 5 it('extracts operationName from Twitter-style graphql URLs', () => { 6 expect(deriveKey({ 7 method: 'GET', 8 url: 'https://x.com/i/api/graphql/6fWQaBPK51aGyC_VC7t9GQ/UserTweets?variables=...', 9 })).toBe('UserTweets'); 10 }); 11 12 it('handles graphql URLs without a query id', () => { 13 expect(deriveKey({ 14 method: 'POST', 15 url: 'https://example.com/graphql/MyOp?vars=1', 16 })).toBe('MyOp'); 17 }); 18 19 it('uses METHOD host+pathname for REST calls', () => { 20 expect(deriveKey({ 21 method: 'get', 22 url: 'https://api.example.com/v1/users?page=1', 23 })).toBe('GET api.example.com/v1/users'); 24 }); 25 26 it('falls back to truncated raw url when URL parsing fails', () => { 27 const key = deriveKey({ method: 'GET', url: 'not-a-valid-url' }); 28 expect(key.startsWith('GET ')).toBe(true); 29 expect(key).toContain('not-a-valid-url'); 30 }); 31 }); 32 33 describe('assignKeys', () => { 34 it('disambiguates collisions with #N suffixes', () => { 35 const out = assignKeys([ 36 { url: 'https://x.com/i/api/graphql/a/UserTweets', method: 'GET' }, 37 { url: 'https://x.com/i/api/graphql/b/UserTweets', method: 'GET' }, 38 { url: 'https://api.example.com/v1/u', method: 'GET' }, 39 { url: 'https://api.example.com/v1/u', method: 'GET' }, 40 { url: 'https://api.example.com/v1/u', method: 'GET' }, 41 ]); 42 expect(out.map(o => o.key)).toEqual([ 43 'UserTweets', 44 'UserTweets#2', 45 'GET api.example.com/v1/u', 46 'GET api.example.com/v1/u#2', 47 'GET api.example.com/v1/u#3', 48 ]); 49 }); 50 51 it('preserves extra fields on each request', () => { 52 const out = assignKeys([{ url: 'https://a.com/x', method: 'GET', status: 200 }]); 53 expect(out[0]).toMatchObject({ status: 200, key: 'GET a.com/x' }); 54 }); 55 });