/ clis / grok / image.test.ts
image.test.ts
  1  import { describe, expect, it } from 'vitest';
  2  import type { IPage } from '@jackwener/opencli/types';
  3  import { __test__ } from './image.js';
  4  
  5  describe('grok image helpers', () => {
  6    describe('isOnGrok', () => {
  7      const fakePage = (url: string | Error): IPage =>
  8        ({ evaluate: () => url instanceof Error ? Promise.reject(url) : Promise.resolve(url) }) as unknown as IPage;
  9  
 10      it('returns true for grok.com URLs', async () => {
 11        expect(await __test__.isOnGrok(fakePage('https://grok.com/'))).toBe(true);
 12        expect(await __test__.isOnGrok(fakePage('https://grok.com/chat/abc123'))).toBe(true);
 13      });
 14  
 15      it('returns true for grok.com subdomains', async () => {
 16        expect(await __test__.isOnGrok(fakePage('https://assets.grok.com/foo'))).toBe(true);
 17      });
 18  
 19      it('returns false for non-grok domains', async () => {
 20        expect(await __test__.isOnGrok(fakePage('https://fakegrok.com/'))).toBe(false);
 21        expect(await __test__.isOnGrok(fakePage('about:blank'))).toBe(false);
 22      });
 23  
 24      it('returns false when evaluate throws (detached tab)', async () => {
 25        expect(await __test__.isOnGrok(fakePage(new Error('detached')))).toBe(false);
 26      });
 27    });
 28  
 29    it('normalizes boolean flags', () => {
 30      expect(__test__.normalizeBooleanFlag(true)).toBe(true);
 31      expect(__test__.normalizeBooleanFlag('true')).toBe(true);
 32      expect(__test__.normalizeBooleanFlag('1')).toBe(true);
 33      expect(__test__.normalizeBooleanFlag('yes')).toBe(true);
 34      expect(__test__.normalizeBooleanFlag('on')).toBe(true);
 35  
 36      expect(__test__.normalizeBooleanFlag(false)).toBe(false);
 37      expect(__test__.normalizeBooleanFlag('false')).toBe(false);
 38      expect(__test__.normalizeBooleanFlag(undefined)).toBe(false);
 39    });
 40  
 41    it('dedupes images by src', () => {
 42      const deduped = __test__.dedupeBySrc([
 43        { src: 'https://a.example/1.jpg', w: 500, h: 500 },
 44        { src: 'https://a.example/1.jpg', w: 500, h: 500 },
 45        { src: 'https://a.example/2.jpg', w: 500, h: 500 },
 46        { src: '', w: 500, h: 500 },
 47      ]);
 48      expect(deduped.map(i => i.src)).toEqual([
 49        'https://a.example/1.jpg',
 50        'https://a.example/2.jpg',
 51      ]);
 52    });
 53  
 54    it('builds a deterministic-ish signature order-independent by src', () => {
 55      const sigA = __test__.imagesSignature([
 56        { src: 'https://a.example/1.jpg', w: 1, h: 1 },
 57        { src: 'https://a.example/2.jpg', w: 1, h: 1 },
 58      ]);
 59      const sigB = __test__.imagesSignature([
 60        { src: 'https://a.example/2.jpg', w: 1, h: 1 },
 61        { src: 'https://a.example/1.jpg', w: 1, h: 1 },
 62      ]);
 63      expect(sigA).toBe(sigB);
 64    });
 65  
 66    it('maps content-type to sensible image extensions', () => {
 67      expect(__test__.extFromContentType('image/png')).toBe('png');
 68      expect(__test__.extFromContentType('image/webp')).toBe('webp');
 69      expect(__test__.extFromContentType('image/gif')).toBe('gif');
 70      expect(__test__.extFromContentType('image/jpeg')).toBe('jpg');
 71      expect(__test__.extFromContentType(undefined)).toBe('jpg');
 72      expect(__test__.extFromContentType('')).toBe('jpg');
 73    });
 74  
 75    it('builds filenames with a stable sha1 slice tied to the src', () => {
 76      const a1 = __test__.buildFilename('https://a.example/1.jpg', 'image/jpeg');
 77      const a2 = __test__.buildFilename('https://a.example/1.jpg', 'image/jpeg');
 78      const b1 = __test__.buildFilename('https://a.example/2.jpg', 'image/png');
 79      // Same URL → same 12-char hash slice (timestamps may differ).
 80      expect(a1.split('-')[2].split('.')[0]).toBe(a2.split('-')[2].split('.')[0]);
 81      expect(a1.split('-')[2].split('.')[0]).not.toBe(b1.split('-')[2].split('.')[0]);
 82      expect(a1.endsWith('.jpg')).toBe(true);
 83      expect(b1.endsWith('.png')).toBe(true);
 84    });
 85  
 86    it('only accepts image bubbles that appeared after the baseline', () => {
 87      const candidate = __test__.pickLatestImageCandidate([
 88        [{ src: 'https://a.example/stale.jpg', w: 512, h: 512 }],
 89        [],
 90        [{ src: 'https://a.example/fresh.jpg', w: 1024, h: 1024 }],
 91      ], 1);
 92  
 93      expect(candidate).toEqual([
 94        { src: 'https://a.example/fresh.jpg', w: 1024, h: 1024 },
 95      ]);
 96    });
 97  
 98    it('does not reuse stale images when no new image bubble appears after baseline', () => {
 99      const candidate = __test__.pickLatestImageCandidate([
100        [{ src: 'https://a.example/stale.jpg', w: 512, h: 512 }],
101        [],
102        [],
103      ], 1);
104  
105      expect(candidate).toEqual([]);
106    });
107  });