import { describe, expect, it } from 'vitest'; import { ObjectId } from 'mongodb'; import { compareShadow, notifKey } from '../src/matcher/compare.js'; import type { NotificationDoc } from '../src/types.js'; function n(userId: string, lon: number, lat: number, content = 'c'): NotificationDoc { return { _id: new ObjectId(), userId, content, geo: { type: 'Point', coordinates: [lon, lat] }, type: 'mobile', when: new Date('2026-07-13T12:00:00Z'), sealed: 's', }; } describe('compareShadow', () => { it('matches identical sets', () => { const a = [n('u1', -3.7, 40.4), n('u2', -4, 41)]; const b = [n('u1', -3.7, 40.4), n('u2', -4, 41)]; const diff = compareShadow(a, b); expect(diff.matched).toBe(2); expect(diff.shadowOnly).toHaveLength(0); expect(diff.realOnly).toHaveLength(0); }); it('flags shadowOnly (spam risk) when we generate an extra notification', () => { const shadow = [n('u1', -3.7, 40.4), n('u3', -5, 42)]; const real = [n('u1', -3.7, 40.4)]; const diff = compareShadow(shadow, real); expect(diff.shadowOnly).toEqual([notifKey(n('u3', -5, 42))]); expect(diff.realOnly).toHaveLength(0); }); it('flags realOnly (missing) when node-red had one we do not', () => { const shadow = [n('u1', -3.7, 40.4)]; const real = [n('u1', -3.7, 40.4), n('u2', -4, 41)]; const diff = compareShadow(shadow, real); expect(diff.realOnly).toEqual([notifKey(n('u2', -4, 41))]); expect(diff.shadowOnly).toHaveLength(0); }); it('reports content mismatches on matched keys', () => { const shadow = [n('u1', -3.7, 40.4, 'nuevo texto')]; const real = [n('u1', -3.7, 40.4, 'viejo texto')]; const diff = compareShadow(shadow, real); expect(diff.matched).toBe(1); expect(diff.contentMismatches).toHaveLength(1); expect(diff.contentMismatches[0]).toMatchObject({ shadow: 'nuevo texto', real: 'viejo texto' }); }); });