1+ import { composeFullRepetitionEvent } from '../../src/utils/merge' ;
2+ import { GroupedEventDBScheme , RepetitionDBScheme } from '@hawk.so/types' ;
3+
4+ import { diff } from '@n1ru4l/json-patch-plus' ;
5+
6+ describe ( 'composeFullRepetitionEvent' , ( ) => {
7+ const mockOriginalEvent : GroupedEventDBScheme = {
8+ groupHash : 'original-event-1' ,
9+ totalCount : 1 ,
10+ catcherType : 'javascript' ,
11+ payload : {
12+ title : 'Original message' ,
13+ type : 'error' ,
14+ addons : JSON . stringify ( { userId : 123 } ) ,
15+ context : JSON . stringify ( { sessionId : 'abc' } ) ,
16+ } ,
17+ usersAffected : 1 ,
18+ visitedBy : [ ] ,
19+ timestamp : 1640995200 , // 2023-01-01T00:00:00Z
20+ } ;
21+
22+ beforeEach ( ( ) => {
23+ jest . clearAllMocks ( ) ;
24+ } ) ;
25+
26+ describe ( 'when repetition is undefined' , ( ) => {
27+ it ( 'should return a deep copy of the original event' , ( ) => {
28+ /**
29+ * Arrange
30+ */
31+ const repetition = undefined ;
32+
33+ /**
34+ * Act
35+ */
36+ const result = composeFullRepetitionEvent ( mockOriginalEvent , repetition ) ;
37+
38+ /**
39+ * Assert
40+ */
41+ expect ( result ) . toEqual ( mockOriginalEvent ) ;
42+ expect ( result ) . toMatchObject ( mockOriginalEvent ) ;
43+ expect ( result . payload ) . toMatchObject ( mockOriginalEvent . payload ) ;
44+ } ) ;
45+ } ) ;
46+
47+ describe ( 'when repetition.delta is provided (new delta format)' , ( ) => {
48+ it ( 'should parse addons and context, apply patch, and stringify fields back' , ( ) => {
49+ /**
50+ * Arrange
51+ */
52+ const delta = diff ( {
53+ left : mockOriginalEvent . payload ,
54+ right : {
55+ ...mockOriginalEvent . payload ,
56+ title : 'Updated message' ,
57+ type : 'warning' ,
58+ } ,
59+ } ) ;
60+
61+ const repetition : RepetitionDBScheme = {
62+ groupHash : 'original-event-1' ,
63+ timestamp : 1640995200 ,
64+ delta : JSON . stringify ( delta ) ,
65+ } ;
66+
67+ /**
68+ * Act
69+ */
70+ const result = composeFullRepetitionEvent ( mockOriginalEvent , repetition ) ;
71+
72+ /**
73+ * Assert
74+ */
75+ expect ( result . payload ) . toEqual ( {
76+ title : 'Updated message' ,
77+ type : 'warning' ,
78+ addons : JSON . stringify ( { userId : 123 } ) ,
79+ context : JSON . stringify ( { sessionId : 'abc' } ) ,
80+ } ) ;
81+ } ) ;
82+
83+ it ( 'should handle delta with new fields' , ( ) => {
84+ /**
85+ * Arrange
86+ */
87+ const delta = diff ( {
88+ left : mockOriginalEvent . payload ,
89+ right : {
90+ ...mockOriginalEvent . payload ,
91+ release : 'v1.0.0' ,
92+ catcherVersion : '2.0.0' ,
93+ } ,
94+ } ) ;
95+
96+ const repetition : RepetitionDBScheme = {
97+ groupHash : 'original-event-1' ,
98+ timestamp : 1640995200 ,
99+ delta : JSON . stringify ( delta ) ,
100+ } ;
101+
102+ /**
103+ * Act
104+ */
105+ const result = composeFullRepetitionEvent ( mockOriginalEvent , repetition ) ;
106+
107+ /**
108+ * Assert
109+ */
110+ expect ( result . payload ) . toEqual ( {
111+ title : 'Original message' ,
112+ type : 'error' ,
113+ release : 'v1.0.0' ,
114+ catcherVersion : '2.0.0' ,
115+ addons : JSON . stringify ( { userId : 123 } ) ,
116+ context : JSON . stringify ( { sessionId : 'abc' } ) ,
117+ } ) ;
118+ } ) ;
119+ } ) ;
120+
121+ describe ( 'when repetition.delta is undefined and repetition.payload is undefined' , ( ) => {
122+ it ( 'should return the original event unchanged' , ( ) => {
123+ /**
124+ * Arrange
125+ */
126+ const repetition : RepetitionDBScheme = {
127+ groupHash : 'original-event-1' ,
128+ timestamp : 1640995200 ,
129+ delta : undefined ,
130+ payload : undefined ,
131+ } ;
132+
133+ /**
134+ * Act
135+ */
136+ const result = composeFullRepetitionEvent ( mockOriginalEvent , repetition ) ;
137+
138+ /**
139+ * Assert
140+ */
141+ expect ( result ) . toEqual ( mockOriginalEvent ) ;
142+ expect ( result ) . not . toBe ( mockOriginalEvent ) ; // Должна быть глубокая копия
143+ } ) ;
144+ } ) ;
145+
146+ describe ( 'when repetition.delta is undefined and repetition.payload is provided (old delta format)' , ( ) => {
147+ it ( 'should use repetitionAssembler to merge payloads' , ( ) => {
148+ /**
149+ * Arrange
150+ */
151+ const repetition : RepetitionDBScheme = {
152+ groupHash : 'original-event-1' ,
153+ timestamp : 1640995200 ,
154+ delta : undefined ,
155+ payload : {
156+ title : 'Updated message' ,
157+ type : 'warning' ,
158+ release : 'v1.0.0' ,
159+ } ,
160+ } ;
161+
162+ /**
163+ * Act
164+ */
165+ const result = composeFullRepetitionEvent ( mockOriginalEvent , repetition ) ;
166+
167+ /**
168+ * Assert
169+ */
170+ expect ( result . payload ) . toEqual ( {
171+ title : 'Updated message' ,
172+ type : 'warning' ,
173+ release : 'v1.0.0' ,
174+ // Addons and context should be, because old format doesn't remove fields
175+ addons : JSON . stringify ( { userId : 123 } ) ,
176+ context : JSON . stringify ( { sessionId : 'abc' } ) ,
177+ } ) ;
178+ } ) ;
179+
180+ it ( 'should handle null values in repetition payload' , ( ) => {
181+ /**
182+ * Arrange
183+ */
184+ const repetition : RepetitionDBScheme = {
185+ groupHash : 'original-event-1' ,
186+ timestamp : 1640995200 ,
187+ delta : undefined ,
188+ payload : {
189+ title : 'Updated title' ,
190+ type : 'info' ,
191+ } ,
192+ } ;
193+
194+ /**
195+ * Act
196+ */
197+ const result = composeFullRepetitionEvent ( mockOriginalEvent , repetition ) ;
198+
199+ /**
200+ * Assert
201+ */
202+ expect ( result . payload ) . toEqual ( {
203+ title : 'Updated title' , // repetition value replaces original
204+ type : 'info' ,
205+ // Addons and context should be, because old format doesn't remove fields
206+ addons : JSON . stringify ( { userId : 123 } ) ,
207+ context : JSON . stringify ( { sessionId : 'abc' } ) ,
208+ } ) ;
209+ } ) ;
210+
211+ it ( 'should preserve original value when repetition payload has null' , ( ) => {
212+ /**
213+ * Arrange
214+ */
215+ const repetition : RepetitionDBScheme = {
216+ groupHash : 'original-event-1' ,
217+ timestamp : 1640995200 ,
218+ delta : undefined ,
219+ payload : {
220+ title : null as any ,
221+ type : 'info' ,
222+ } ,
223+ } ;
224+
225+ /**
226+ * Act
227+ */
228+ const result = composeFullRepetitionEvent ( mockOriginalEvent , repetition ) ;
229+
230+ /**
231+ * Assert
232+ */
233+ expect ( result . payload ) . toEqual ( {
234+ title : 'Original message' , // null в repetition должно сохранить оригинальное значение
235+ type : 'info' ,
236+ addons : JSON . stringify ( { userId : 123 } ) ,
237+ context : JSON . stringify ( { sessionId : 'abc' } ) ,
238+ } ) ;
239+ } ) ;
240+ } ) ;
241+
242+ describe ( 'edge cases' , ( ) => {
243+ it ( 'should handle empty payload in original event' , ( ) => {
244+ /**
245+ * Arrange
246+ */
247+ const eventWithEmptyPayload : GroupedEventDBScheme = {
248+ groupHash : 'event-4' ,
249+ totalCount : 1 ,
250+ catcherType : 'javascript' ,
251+ payload : {
252+ title : 'Empty event' ,
253+ } ,
254+ usersAffected : 1 ,
255+ visitedBy : [ ] ,
256+ timestamp : 1640995200 ,
257+ } ;
258+
259+ const delta = diff ( {
260+ left : eventWithEmptyPayload . payload ,
261+ right : {
262+ ...eventWithEmptyPayload . payload ,
263+ title : 'New message' ,
264+ } ,
265+ } ) ;
266+
267+ const repetition : RepetitionDBScheme = {
268+ groupHash : 'event-4' ,
269+ timestamp : 1640995200 ,
270+ delta : JSON . stringify ( delta ) ,
271+ } ;
272+
273+ /**
274+ * Act
275+ */
276+ const result = composeFullRepetitionEvent ( eventWithEmptyPayload , repetition ) ;
277+
278+ /**
279+ * Assert
280+ */
281+ expect ( result . payload ) . toEqual ( {
282+ title : 'New message' ,
283+ } ) ;
284+ } ) ;
285+
286+ it ( 'should handle null payload in original event' , ( ) => {
287+ /**
288+ * Arrange
289+ */
290+ const eventWithNullPayload : GroupedEventDBScheme = {
291+ groupHash : 'event-5' ,
292+ totalCount : 1 ,
293+ catcherType : 'javascript' ,
294+ payload : null as any ,
295+ usersAffected : 1 ,
296+ visitedBy : [ ] ,
297+ timestamp : 1640995200 ,
298+ } ;
299+
300+ const delta = diff ( {
301+ left : eventWithNullPayload . payload ,
302+ right : {
303+ title : 'New message' ,
304+ } ,
305+ } ) ;
306+
307+ const repetition : RepetitionDBScheme = {
308+ groupHash : 'event-5' ,
309+ timestamp : 1640995200 ,
310+ delta : JSON . stringify ( delta ) ,
311+ } ;
312+
313+ /**
314+ * Act
315+ */
316+ const result = composeFullRepetitionEvent ( eventWithNullPayload , repetition ) ;
317+
318+ /**
319+ * Assert
320+ */
321+ expect ( result . payload ) . toEqual ( {
322+ title : 'New message' ,
323+ } ) ;
324+ } ) ;
325+
326+ it ( 'should handle invalid JSON in addons or context' , ( ) => {
327+ /**
328+ * Arrange
329+ */
330+ const eventWithInvalidJSON : GroupedEventDBScheme = {
331+ groupHash : 'event-6' ,
332+ totalCount : 1 ,
333+ catcherType : 'javascript' ,
334+ payload : {
335+ title : 'Test' ,
336+ addons : 'invalid json' ,
337+ context : 'also invalid' ,
338+ } ,
339+ usersAffected : 1 ,
340+ visitedBy : [ ] ,
341+ timestamp : 1640995200 ,
342+ } ;
343+
344+ const delta = diff ( {
345+ left : eventWithInvalidJSON . payload ,
346+ right : {
347+ ...eventWithInvalidJSON . payload ,
348+ title : 'Updated' ,
349+ } ,
350+ } ) ;
351+
352+ const repetition : RepetitionDBScheme = {
353+ groupHash : 'event-6' ,
354+ timestamp : 1640995200 ,
355+ delta : JSON . stringify ( delta ) ,
356+ } ;
357+
358+ /**
359+ * Act & Assert
360+ */
361+ expect ( ( ) => {
362+ composeFullRepetitionEvent ( eventWithInvalidJSON , repetition ) ;
363+ } ) . toThrow ( ) ; // Должно выбросить ошибку при парсинге невалидного JSON
364+ } ) ;
365+ } ) ;
366+ } ) ;
0 commit comments