55 parsePartialJsonObjectSingle ,
66} from '../partial-json-delta'
77
8- describe ( 'parsePartialJsonObject ' , ( ) => {
9- describe ( 'valid JSON' , ( ) => {
8+ describe ( 'parsePartialJsonObjectSingle ' , ( ) => {
9+ describe ( 'complete valid JSON' , ( ) => {
1010 it ( 'should parse complete valid JSON' , ( ) => {
1111 const input = '{"name": "test", "value": 42}'
1212 const result = parsePartialJsonObjectSingle ( input )
@@ -196,37 +196,59 @@ describe('parsePartialJsonObject', () => {
196196} )
197197
198198describe ( 'getPartialJsonDelta' , ( ) => {
199- describe ( 'basic delta detection' , ( ) => {
200- it ( 'should detect new properties' , ( ) => {
199+ describe ( 'input validation' , ( ) => {
200+ it ( 'should throw error when content does not start with previous' , ( ) => {
201+ const content = '{"name": "test"}'
202+ const previous = '{"other": "value"}'
203+
204+ expect ( ( ) => getPartialJsonDelta ( content , previous ) ) . toThrow (
205+ 'Content must be previous content plus new content'
206+ )
207+ } )
208+
209+ it ( 'should work when content starts with previous' , ( ) => {
201210 const content = '{"name": "test", "value": 42}'
202- const previous = { }
211+ const previous = '{"name": "test"'
212+
213+ expect ( ( ) => getPartialJsonDelta ( content , previous ) ) . not . toThrow ( )
214+ } )
215+ } )
216+
217+ describe ( 'basic delta detection from streaming JSON' , ( ) => {
218+ it ( 'should detect new properties added to empty object' , ( ) => {
219+ const content = '{"name": "test", "value": 42}'
220+ const previous = '{'
203221 const result = getPartialJsonDelta ( content , previous )
204222
205223 expect ( result . delta ) . toEqual ( { name : 'test' , value : 42 } )
206224 expect ( result . result ) . toEqual ( { name : 'test' , value : 42 } )
225+ expect ( result . lastParam . key ) . toBe ( 'value' )
226+ expect ( result . lastParam . complete ) . toBe ( false )
207227 } )
208228
209- it ( 'should detect changed properties ' , ( ) => {
210- const content = '{"value":100," name":"updated"}'
211- const previous = { value : 100 , name : ' upda' }
229+ it ( 'should detect completion of partial string value ' , ( ) => {
230+ const content = '{"name": "updated"}'
231+ const previous = '{" name": " upda'
212232 const result = getPartialJsonDelta ( content , previous )
213233
214234 expect ( result . delta ) . toEqual ( { name : 'ted' } )
215- expect ( result . result ) . toEqual ( { value : 100 , name : 'updated' } )
235+ expect ( result . result ) . toEqual ( { name : 'updated' } )
236+ expect ( result . lastParam . key ) . toBe ( 'name' )
237+ expect ( result . lastParam . complete ) . toBe ( true )
216238 } )
217239
218- it ( 'should return empty delta for unchanged properties ' , ( ) => {
240+ it ( 'should return empty delta when no changes detected ' , ( ) => {
219241 const content = '{"name": "test", "value": 42}'
220- const previous = { name : ' test' , value : 42 }
242+ const previous = '{" name": " test", " value" : 42'
221243 const result = getPartialJsonDelta ( content , previous )
222244
223245 expect ( result . delta ) . toEqual ( { } )
224246 expect ( result . result ) . toEqual ( { name : 'test' , value : 42 } )
225247 } )
226248
227- it ( 'should detect partial changes ' , ( ) => {
249+ it ( 'should detect new property being added ' , ( ) => {
228250 const content = '{"name": "test", "value": 100}'
229- const previous = { name : ' test' , value : 42 }
251+ const previous = '{" name": " test", " value": '
230252 const result = getPartialJsonDelta ( content , previous )
231253
232254 expect ( result . delta ) . toEqual ( { value : 100 } )
@@ -235,139 +257,213 @@ describe('getPartialJsonDelta', () => {
235257 } )
236258
237259 describe ( 'string delta handling' , ( ) => {
238- it ( 'should handle string changes ' , ( ) => {
260+ it ( 'should return string slice for partial string updates ' , ( ) => {
239261 const content = '{"message": "Hello World"}'
240- const previous = { message : ' Hello' }
262+ const previous = '{" message": " Hello'
241263 const result = getPartialJsonDelta ( content , previous )
242264
243- // Note: Current implementation has a bug - it doesn't return the sliced string
244- // This test documents the current behavior
245265 expect ( result . delta ) . toEqual ( { message : ' World' } )
246266 expect ( result . result ) . toEqual ( { message : 'Hello World' } )
247267 } )
248268
249269 it ( 'should handle empty string to non-empty string' , ( ) => {
250270 const content = '{"message": "Hello"}'
251- const previous = { message : '' }
271+ const previous = '{" message": "'
252272 const result = getPartialJsonDelta ( content , previous )
253273
254274 expect ( result . delta ) . toEqual ( { message : 'Hello' } )
255275 expect ( result . result ) . toEqual ( { message : 'Hello' } )
256276 } )
257277
258- it ( 'should handle undefined to string' , ( ) => {
278+ it ( 'should handle new string property ' , ( ) => {
259279 const content = '{"message": "Hello"}'
260- const previous = { }
280+ const previous = '{'
261281 const result = getPartialJsonDelta ( content , previous )
262282
263283 expect ( result . delta ) . toEqual ( { message : 'Hello' } )
264284 expect ( result . result ) . toEqual ( { message : 'Hello' } )
265285 } )
286+
287+ it ( 'should handle multi-line string streaming' , ( ) => {
288+ const content = '{"text": "Line 1\\nLine 2\\nLine 3"}'
289+ const previous = '{"text": "Line 1\\nLine'
290+ const result = getPartialJsonDelta ( content , previous )
291+
292+ expect ( result . delta ) . toEqual ( { text : ' 2\nLine 3' } )
293+ expect ( result . result ) . toEqual ( { text : 'Line 1\nLine 2\nLine 3' } )
294+ } )
266295 } )
267296
268- describe ( 'complex object changes' , ( ) => {
269- it ( 'should handle nested object changes' , ( ) => {
270- const content = '{"user": {"name": "John", "age": 31}}'
271- const previous = { user : { name : 'John' , age : 30 } }
297+ describe ( 'non-string value changes' , ( ) => {
298+ it ( 'should return full value for non-string changes' , ( ) => {
299+ const content = '{"count": 42}'
300+ const previous = '{"count": '
301+ const result = getPartialJsonDelta ( content , previous )
302+
303+ expect ( result . delta ) . toEqual ( { count : 42 } )
304+ expect ( result . result ) . toEqual ( { count : 42 } )
305+ } )
306+
307+ it ( 'should handle boolean values' , ( ) => {
308+ const content = '{"active": true}'
309+ const previous = '{"active": '
310+ const result = getPartialJsonDelta ( content , previous )
311+
312+ expect ( result . delta ) . toEqual ( { active : true } )
313+ expect ( result . result ) . toEqual ( { active : true } )
314+ } )
315+
316+ it ( 'should handle null values' , ( ) => {
317+ const content = '{"data": null}'
318+ const previous = '{"data": '
272319 const result = getPartialJsonDelta ( content , previous )
273320
274- expect ( result . delta ) . toEqual ( { user : { name : 'John' , age : 31 } } )
275- expect ( result . result ) . toEqual ( { user : { name : 'John' , age : 31 } } )
321+ expect ( result . delta ) . toEqual ( { data : null } )
322+ expect ( result . result ) . toEqual ( { data : null } )
276323 } )
277324
278- it ( 'should handle array changes ' , ( ) => {
279- const content = '{"items": [1, 2, 3, 4 ]}'
280- const previous = { items : [ 1 , 2 , 3 ] }
325+ it ( 'should handle array values ' , ( ) => {
326+ const content = '{"items": [1, 2, 3]}'
327+ const previous = '{" items": '
281328 const result = getPartialJsonDelta ( content , previous )
282329
283- expect ( result . delta ) . toEqual ( { items : [ 1 , 2 , 3 , 4 ] } )
284- expect ( result . result ) . toEqual ( { items : [ 1 , 2 , 3 , 4 ] } )
330+ expect ( result . delta ) . toEqual ( { items : [ 1 , 2 , 3 ] } )
331+ expect ( result . result ) . toEqual ( { items : [ 1 , 2 , 3 ] } )
285332 } )
286333
287- it ( 'should handle mixed type changes ' , ( ) => {
288- const content = '{"value ": "string" }'
289- const previous = { value : 42 }
334+ it ( 'should handle nested object values ' , ( ) => {
335+ const content = '{"user ": {"name": "John", "age": 30} }'
336+ const previous = '{"user": '
290337 const result = getPartialJsonDelta ( content , previous )
291338
292- expect ( result . delta ) . toEqual ( { value : 'string' } )
293- expect ( result . result ) . toEqual ( { value : 'string' } )
339+ expect ( result . delta ) . toEqual ( { user : { name : 'John' , age : 30 } } )
340+ expect ( result . result ) . toEqual ( { user : { name : 'John' , age : 30 } } )
294341 } )
295342 } )
296343
297- describe ( 'streaming scenarios' , ( ) => {
344+ describe ( 'realistic streaming scenarios' , ( ) => {
298345 it ( 'should handle progressive JSON building' , ( ) => {
299- let previous = { }
300-
301- // First chunk
346+ // Simulate streaming JSON construction
347+ let previous = '{'
302348 let content = '{"status": "processing"'
303349 let result = getPartialJsonDelta ( content , previous )
350+
304351 expect ( result . delta ) . toEqual ( { status : 'processing' } )
305- previous = result . result
352+ expect ( result . result ) . toEqual ( { status : 'processing' } )
306353
307- // Second chunk
308- content += ', "progress": 1.0'
354+ // Add more content
355+ previous = content
356+ content = '{"status": "processing", "progress": 0.5'
309357 result = getPartialJsonDelta ( content , previous )
310- expect ( result . delta ) . toEqual ( { progress : 1.0 } )
311- previous = result . result
312358
313- // Final chunk
314- content += ', "result": "success"}'
359+ expect ( result . delta ) . toEqual ( { progress : 0.5 } )
360+ expect ( result . result ) . toEqual ( { status : 'processing' , progress : 0.5 } )
361+
362+ // Complete the JSON
363+ previous = content
364+ content =
365+ '{"status": "processing", "progress": 0.5, "message": "Almost done"}'
315366 result = getPartialJsonDelta ( content , previous )
316- expect ( result . delta ) . toEqual ( {
317- result : 'success' ,
367+
368+ expect ( result . delta ) . toEqual ( { message : 'Almost done' } )
369+ expect ( result . result ) . toEqual ( {
370+ status : 'processing' ,
371+ progress : 0.5 ,
372+ message : 'Almost done' ,
318373 } )
319374 } )
320375
321- it ( 'should handle incomplete JSON in streaming' , ( ) => {
376+ it ( 'should handle streaming text completion' , ( ) => {
377+ const previous = '{"response": "The quick brown'
322378 const content =
323- '{"message": "This is a long message that is being streamed'
324- const previous = { message : 'This is a long' }
379+ '{"response": "The quick brown fox jumps over the lazy dog"}'
325380 const result = getPartialJsonDelta ( content , previous )
326381
327- expect ( result . delta ) . toEqual ( {
328- message : ' message that is being streamed' ,
382+ expect ( result . delta ) . toEqual ( { response : ' fox jumps over the lazy dog' } )
383+ expect ( result . result ) . toEqual ( {
384+ response : 'The quick brown fox jumps over the lazy dog' ,
329385 } )
386+ } )
387+
388+ it ( 'should handle incomplete JSON with trailing comma' , ( ) => {
389+ const previous = '{"name": "test", "value": 42,'
390+ const content = '{"name": "test", "value": 42, "status": "complete"}'
391+ const result = getPartialJsonDelta ( content , previous )
392+
393+ expect ( result . delta ) . toEqual ( { status : 'complete' } )
330394 expect ( result . result ) . toEqual ( {
331- message : 'This is a long message that is being streamed' ,
395+ name : 'test' ,
396+ value : 42 ,
397+ status : 'complete' ,
332398 } )
333399 } )
334400 } )
335401
336- describe ( 'edge cases ' , ( ) => {
337- it ( 'should handle empty content ' , ( ) => {
338- const content = ''
339- const previous = { name : 'test' }
402+ describe ( 'lastParam tracking ' , ( ) => {
403+ it ( 'should track last parameter key and completion status ' , ( ) => {
404+ const content = '{"name": "test", "value": 42} '
405+ const previous = '{'
340406 const result = getPartialJsonDelta ( content , previous )
341407
342- expect ( result . delta ) . toEqual ( { } )
343- expect ( result . result ) . toEqual ( { } )
408+ expect ( result . lastParam . key ) . toBe ( 'value' )
409+ expect ( result . lastParam . complete ) . toBe ( false )
410+ } )
411+
412+ it ( 'should indicate incomplete last parameter' , ( ) => {
413+ const content = '{"name": "test", "message": "partial'
414+ const previous = '{'
415+ const result = getPartialJsonDelta ( content , previous )
416+
417+ expect ( result . lastParam . key ) . toBe ( 'message' )
418+ expect ( result . lastParam . complete ) . toBe ( false )
344419 } )
345420
346- it ( 'should handle invalid JSON content' , ( ) => {
347- const content = 'not json'
348- const previous = { name : 'test' }
421+ it ( 'should handle undefined key for empty object' , ( ) => {
422+ const content = '{}'
423+ const previous = '{'
424+ const result = getPartialJsonDelta ( content , previous )
425+
426+ expect ( result . lastParam . key ) . toBeUndefined ( )
427+ expect ( result . lastParam . complete ) . toBe ( false )
428+ } )
429+ } )
430+
431+ describe ( 'edge cases' , ( ) => {
432+ it ( 'should handle empty previous string' , ( ) => {
433+ const content = '{"name": "test"}'
434+ const previous = ''
435+
436+ expect ( ( ) => getPartialJsonDelta ( content , previous ) ) . not . toThrow ( )
437+ const result = getPartialJsonDelta ( content , previous )
438+ expect ( result . delta ) . toEqual ( { name : 'test' } )
439+ } )
440+
441+ it ( 'should handle identical content and previous' , ( ) => {
442+ const content = '{"name": "test"}'
443+ const previous = '{"name": "test"}'
349444 const result = getPartialJsonDelta ( content , previous )
350445
351446 expect ( result . delta ) . toEqual ( { } )
352- expect ( result . result ) . toEqual ( { } )
447+ expect ( result . result ) . toEqual ( { name : 'test' } )
353448 } )
354449
355- it ( 'should handle null and undefined values ' , ( ) => {
356- const content = '{"value ": null}'
357- const previous = { value : undefined }
450+ it ( 'should handle malformed JSON gracefully ' , ( ) => {
451+ const content = '{"name ": test}' // Invalid JSON
452+ const previous = '{'
358453 const result = getPartialJsonDelta ( content , previous )
359454
360- expect ( result . delta ) . toEqual ( { value : null } )
361- expect ( result . result ) . toEqual ( { value : null } )
455+ // Should return empty objects when JSON parsing fails
456+ expect ( result . delta ) . toEqual ( { } )
457+ expect ( result . result ) . toEqual ( { } )
362458 } )
363459
364- it ( 'should handle boolean changes ' , ( ) => {
365- const content = '{"active ": false }'
366- const previous = { active : true }
460+ it ( 'should handle escaped quotes in strings ' , ( ) => {
461+ const content = '{"message ": "He said \\"Hello\\" to me" }'
462+ const previous = '{"message": "He said \\"Hello'
367463 const result = getPartialJsonDelta ( content , previous )
368464
369- expect ( result . delta ) . toEqual ( { active : false } )
370- expect ( result . result ) . toEqual ( { active : false } )
465+ expect ( result . delta ) . toEqual ( { message : '" to me' } )
466+ expect ( result . result ) . toEqual ( { message : 'He said "Hello" to me' } )
371467 } )
372468 } )
373469} )
0 commit comments