@@ -6,7 +6,6 @@ const MATRIX = [
66 { name : 'string' , object : 'test' , serialized : '"test"' } ,
77 { name : 'array' , object : [ 1 , 'test' ] , serialized : '[1,"test"]' } ,
88 { name : 'object' , object : { a : 'test' } , serialized : '{"a":"test"}' } ,
9- // TODO: Add tests for cyclic and deep objects
109] ;
1110
1211describe ( 'clone()' , ( ) => {
@@ -18,11 +17,207 @@ describe('clone()', () => {
1817} ) ;
1918
2019describe ( 'serialize()' , ( ) => {
20+ function jsonify ( obj : object ) : string {
21+ return JSON . stringify ( obj ) ;
22+ }
23+
2124 for ( const entry of MATRIX ) {
2225 test ( `serializes a ${ entry . name } ` , ( ) => {
2326 expect ( serialize ( entry . object ) ) . toEqual ( entry . serialized ) ;
2427 } ) ;
2528 }
29+
30+ describe ( 'cyclical structures' , ( ) => {
31+ it ( 'must stringify circular objects' , ( ) => {
32+ const obj = { name : 'Alice' } ;
33+ // @ts -ignore
34+ obj . self = obj ;
35+
36+ const json = serialize ( obj ) ;
37+ expect ( json ) . toEqual ( jsonify ( { name : 'Alice' , self : '[Circular ~]' } ) ) ;
38+ } ) ;
39+
40+ it ( 'must stringify circular objects with intermediaries' , ( ) => {
41+ const obj = { name : 'Alice' } ;
42+ // @ts -ignore
43+ obj . identity = { self : obj } ;
44+ const json = serialize ( obj ) ;
45+ expect ( json ) . toEqual (
46+ jsonify ( { name : 'Alice' , identity : { self : '[Circular ~]' } } ) ,
47+ ) ;
48+ } ) ;
49+
50+ it ( 'must stringify circular objects deeper' , ( ) => {
51+ const obj = { name : 'Alice' , child : { name : 'Bob' } } ;
52+ // @ts -ignore
53+ obj . child . self = obj . child ;
54+
55+ expect ( serialize ( obj ) ) . toEqual (
56+ jsonify ( {
57+ name : 'Alice' ,
58+ child : { name : 'Bob' , self : '[Circular ~.child]' } ,
59+ } ) ,
60+ ) ;
61+ } ) ;
62+
63+ it ( 'must stringify circular objects deeper with intermediaries' , ( ) => {
64+ const obj = { name : 'Alice' , child : { name : 'Bob' } } ;
65+ // @ts -ignore
66+ obj . child . identity = { self : obj . child } ;
67+
68+ expect ( serialize ( obj ) ) . toEqual (
69+ jsonify ( {
70+ name : 'Alice' ,
71+ child : { name : 'Bob' , identity : { self : '[Circular ~.child]' } } ,
72+ } ) ,
73+ ) ;
74+ } ) ;
75+
76+ it ( 'must stringify circular objects in an array' , ( ) => {
77+ const obj = { name : 'Alice' } ;
78+ // @ts -ignore
79+ obj . self = [ obj , obj ] ;
80+
81+ expect ( serialize ( obj ) ) . toEqual (
82+ jsonify ( {
83+ name : 'Alice' ,
84+ self : [ '[Circular ~]' , '[Circular ~]' ] ,
85+ } ) ,
86+ ) ;
87+ } ) ;
88+
89+ it ( 'must stringify circular objects deeper in an array' , ( ) => {
90+ const obj = {
91+ name : 'Alice' ,
92+ children : [ { name : 'Bob' } , { name : 'Eve' } ] ,
93+ } ;
94+ // @ts -ignore
95+ obj . children [ 0 ] . self = obj . children [ 0 ] ;
96+ // @ts -ignore
97+ obj . children [ 1 ] . self = obj . children [ 1 ] ;
98+
99+ expect ( serialize ( obj ) ) . toEqual (
100+ jsonify ( {
101+ name : 'Alice' ,
102+ children : [
103+ { name : 'Bob' , self : '[Circular ~.children.0]' } ,
104+ { name : 'Eve' , self : '[Circular ~.children.1]' } ,
105+ ] ,
106+ } ) ,
107+ ) ;
108+ } ) ;
109+
110+ it ( 'must stringify circular arrays' , ( ) => {
111+ const obj : object [ ] = [ ] ;
112+ obj . push ( obj ) ;
113+ obj . push ( obj ) ;
114+ const json = serialize ( obj ) ;
115+ expect ( json ) . toEqual ( jsonify ( [ '[Circular ~]' , '[Circular ~]' ] ) ) ;
116+ } ) ;
117+
118+ it ( 'must stringify circular arrays with intermediaries' , ( ) => {
119+ const obj : object [ ] = [ ] ;
120+ obj . push ( { name : 'Alice' , self : obj } ) ;
121+ obj . push ( { name : 'Bob' , self : obj } ) ;
122+
123+ expect ( serialize ( obj ) ) . toEqual (
124+ jsonify ( [
125+ { name : 'Alice' , self : '[Circular ~]' } ,
126+ { name : 'Bob' , self : '[Circular ~]' } ,
127+ ] ) ,
128+ ) ;
129+ } ) ;
130+
131+ it ( 'must stringify repeated objects in objects' , ( ) => {
132+ const obj = { } ;
133+ const alice = { name : 'Alice' } ;
134+ // @ts -ignore
135+ obj . alice1 = alice ;
136+ // @ts -ignore
137+ obj . alice2 = alice ;
138+
139+ expect ( serialize ( obj ) ) . toEqual (
140+ jsonify ( {
141+ alice1 : { name : 'Alice' } ,
142+ alice2 : { name : 'Alice' } ,
143+ } ) ,
144+ ) ;
145+ } ) ;
146+
147+ it ( 'must stringify repeated objects in arrays' , ( ) => {
148+ const alice = { name : 'Alice' } ;
149+ const obj = [ alice , alice ] ;
150+ const json = serialize ( obj ) ;
151+ expect ( json ) . toEqual ( jsonify ( [ { name : 'Alice' } , { name : 'Alice' } ] ) ) ;
152+ } ) ;
153+
154+ it ( 'must stringify error objects, including extra properties' , ( ) => {
155+ const obj = new Error ( 'Wubba Lubba Dub Dub' ) ;
156+ // @ts -ignore
157+ obj . reason = new TypeError ( "I'm pickle Riiick!" ) ;
158+ // @ts -ignore
159+ obj . extra = 'some extra prop' ;
160+
161+ // Stack is inconsistent across browsers, so override it and just make sure its stringified
162+ obj . stack = 'x' ;
163+ // @ts -ignore
164+ obj . reason . stack = 'x' ;
165+
166+ // IE 10/11
167+ // @ts -ignore
168+ delete obj . description ;
169+ // @ts -ignore
170+ delete obj . reason . description ;
171+
172+ // Safari doesn't allow deleting those properties from error object, yet only it provides them
173+ const result = serialize ( obj )
174+ . replace ( / + " ( l i n e | c o l u m n | s o u r c e U R L ) " : .+ , ? \n / g, '' )
175+ . replace ( / , \n ( + ) } / g, '\n$1}' ) ; // make sure to strip trailing commas as well
176+
177+ expect ( result ) . toEqual (
178+ jsonify ( {
179+ message : 'Wubba Lubba Dub Dub' ,
180+ name : 'Error' ,
181+ stack : 'x' ,
182+ reason : {
183+ message : "I'm pickle Riiick!" ,
184+ name : 'TypeError' ,
185+ stack : 'x' ,
186+ } ,
187+ extra : 'some extra prop' ,
188+ } ) ,
189+ ) ;
190+ } ) ;
191+ } ) ;
192+
193+ it ( 'must stringify error objects with circular references' , ( ) => {
194+ const obj = new Error ( 'Wubba Lubba Dub Dub' ) ;
195+ // @ts -ignore
196+ obj . reason = obj ;
197+
198+ // Stack is inconsistent across browsers, so override it and just make sure its stringified
199+ obj . stack = 'x' ;
200+ // @ts -ignore
201+ obj . reason . stack = 'x' ;
202+
203+ // IE 10/11
204+ // @ts -ignore
205+ delete obj . description ;
206+
207+ // Safari doesn't allow deleting those properties from error object, yet only it provides them
208+ const result = serialize ( obj )
209+ . replace ( / + " ( l i n e | c o l u m n | s o u r c e U R L ) " : .+ , ? \n / g, '' )
210+ . replace ( / , \n ( + ) } / g, '\n$1}' ) ; // make sure to strip trailing commas as well
211+
212+ expect ( result ) . toEqual (
213+ jsonify ( {
214+ message : 'Wubba Lubba Dub Dub' ,
215+ name : 'Error' ,
216+ stack : 'x' ,
217+ reason : '[Circular ~]' ,
218+ } ) ,
219+ ) ;
220+ } ) ;
26221} ) ;
27222
28223describe ( 'deserialize()' , ( ) => {
0 commit comments