import { describe, expect, it } from 'vitest';
import { applyPatchObject, patchPath, patchedProperties } from '../jmap/patch-object';
describe('patch-object', () => {
it('escapes path segments as JSON Pointer does', () => {
expect(patchPath('relatedTo', '')).toBe('relatedTo/');
});
it('applies plain keys and member paths without touching the target', () => {
const target = { title: 'T', alerts: { a: { acknowledged: null, action: 'display' }, b: { acknowledged: null } } };
const after = applyPatchObject(target, { title: 'U', 'alerts/a/acknowledged': '2026-05-04T07:00:00Z', 'alerts/b': null, 'links/x~1y': { href: 'h' } });
expect(after).toEqual({
title: 'U',
alerts: { a: { acknowledged: '2026-05-04T07:00:00Z', action: 'display' } },
links: { 'x/y': { href: 'h' } },
});
expect(target.alerts.b).toEqual({ acknowledged: null });
});
it('keeps __proto__ as a plain key', () => {
const after = applyPatchObject({ alerts: {} }, { 'alerts/__proto__': { polluted: true } }) as { alerts: object };
expect(Object.getPrototypeOf(after.alerts)).toBe(Object.prototype);
expect(Object.keys(after.alerts)).toEqual(['__proto__']);
expect(({} as Record).polluted).toBeUndefined();
});
it('shows a path patch as whole properties', () => {
expect(patchedProperties({ alerts: { a: { x: 1 }, b: { x: 2 } } }, { 'alerts/a/x': 3 })).toEqual({ alerts: { a: { x: 3 }, b: { x: 2 } } });
});
});