Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81155 views
1
/**
2
* Copyright 2013-2014, Facebook, Inc.
3
* All rights reserved.
4
*
5
* This source code is licensed under the BSD-style license found in the
6
* LICENSE file in the root directory of this source tree. An additional grant
7
* of patent rights can be found in the PATENTS file in the same directory.
8
*
9
* @emails react-core
10
*/
11
12
"use strict";
13
14
require('mock-modules')
15
.dontMock('LegacyImmutableObject');
16
17
var LegacyImmutableObject;
18
19
/**
20
* To perform performance testing of using `LegacyImmutableObject` vs. not using
21
* `LegacyImmutableObject`, such testing must be done with __DEV__ set to false.
22
*/
23
describe('LegacyImmutableObject', function() {
24
var message;
25
beforeEach(function() {
26
require('mock-modules').dumpCache();
27
LegacyImmutableObject = require('LegacyImmutableObject');
28
this.addMatchers({
29
/**
30
* Equivalent with respect to serialization. Must stringify because
31
* constructors are different and other comparison methods will not
32
* consider them structurally equal. Probably not useful for use outside
33
* of this test module.
34
*/
35
toBeSeriallyEqualTo: function(expected) {
36
var actual = this.actual;
37
var notText = this.isNot ? " not" : "";
38
this.message = function() {
39
return "Expected " + JSON.stringify(actual) + notText +
40
" to be serially equal to " + JSON.stringify(expected);
41
};
42
43
return JSON.stringify(actual) === JSON.stringify(expected);
44
}
45
});
46
});
47
48
/**
49
* We are in __DEV__ by default.
50
*/
51
var testDev = function(message, testFunc) {
52
it(message, testFunc);
53
};
54
55
var testProd = function(message, testFunc) {
56
// Temporarily enter production mode
57
window.__DEV__ = false;
58
it(message, testFunc);
59
window.__DEV__ = true;
60
};
61
62
var testDevAndProd = function(message, testFunc) {
63
testDev(message + ':DEV', testFunc);
64
testProd(message + ':PROD', testFunc);
65
};
66
67
testDev('should be running in DEV', function() {
68
expect(window.__DEV__).toBe(true);
69
});
70
71
testDev('should not require initial map to be an object', function() {
72
// These won't throw because they're coerced
73
74
expect(function() {
75
new LegacyImmutableObject([1,2,3]);
76
}).not.toThrow();
77
78
expect(function() {
79
new LegacyImmutableObject('asdf');
80
}).not.toThrow();
81
82
expect(function() {
83
new LegacyImmutableObject({oldField: 'asdf', fieldTwo: null});
84
}).not.toThrow();
85
});
86
87
testDev('should not exceed maximum call stack size with nodes', function() {
88
var node = document.createElement('div');
89
var object = new LegacyImmutableObject({node: node});
90
expect(object.node).toBe(node);
91
});
92
93
testDevAndProd('should not throw when not mutating directly', function() {
94
var io = new LegacyImmutableObject({oldField: 'asdf'});
95
expect(function() {
96
LegacyImmutableObject.set(io, {newField: null}); // not a mutation!
97
}).not.toThrow();
98
});
99
100
testDev('should prevent shallow field addition when strict', function() {
101
expect(function() {
102
var io = new LegacyImmutableObject({oldField: 'asdf'});
103
io.newField = 'this will not work';
104
}).toThrow();
105
});
106
107
testDev('should prevent shallow field mutation when strict', function() {
108
expect(function() {
109
var io = new LegacyImmutableObject({oldField: 'asdf'});
110
io.oldField = 'this will not work!';
111
}).toThrow();
112
});
113
114
testDev('should prevent deep field addition when strict', function() {
115
expect(function() {
116
var io =
117
new LegacyImmutableObject(
118
{shallowField: {deepField: {oldField: null}}}
119
);
120
io.shallowField.deepField.oldField = 'this will not work!';
121
}).toThrow();
122
});
123
124
testDev('should prevent deep field mutation when strict', function() {
125
expect(function() {
126
var io =
127
new LegacyImmutableObject(
128
{shallowField: {deepField: {oldField: null}}}
129
);
130
io.shallowField.deepField.newField = 'this will not work!';
131
}).toThrow();
132
});
133
134
testDevAndProd(
135
'should create object with same structure when set with {}',
136
function() {
137
var beforeIO =
138
new LegacyImmutableObject(
139
{shallowField: {deepField: {oldField: null}}}
140
);
141
var afterIO = LegacyImmutableObject.set(beforeIO, {});
142
expect(afterIO).toBeSeriallyEqualTo(beforeIO);
143
expect(afterIO).not.toBe(beforeIO);
144
}
145
);
146
147
testDevAndProd(
148
'should create distinct object with shallow field insertion',
149
function() {
150
var beforeStructure = {
151
oldShallowField: {
152
deepField: {
153
oldField: null
154
}
155
}
156
};
157
158
var delta = {
159
newShallowField: 'newShallowFieldHere'
160
};
161
162
var expectedAfterStructure = {
163
oldShallowField: {
164
deepField: {
165
oldField: null
166
}
167
},
168
newShallowField: 'newShallowFieldHere'
169
};
170
171
var beforeIO = new LegacyImmutableObject(beforeStructure);
172
var afterIO = LegacyImmutableObject.set(beforeIO, delta);
173
expect(afterIO).toBeSeriallyEqualTo(expectedAfterStructure);
174
expect(afterIO).not.toBe(beforeIO);
175
}
176
);
177
178
testDevAndProd(
179
'should create distinct object with shallow field mutation',
180
function() {
181
var beforeStructure = {
182
oldShallowField: {
183
deepField: {
184
oldField: null
185
}
186
}
187
};
188
189
var delta = {
190
oldShallowField: 'this will clobber the old field'
191
};
192
193
var expectedAfterStructure = {
194
oldShallowField: 'this will clobber the old field'
195
};
196
197
var beforeIO = new LegacyImmutableObject(beforeStructure);
198
var afterIO = LegacyImmutableObject.set(beforeIO, delta);
199
expect(afterIO).toBeSeriallyEqualTo(expectedAfterStructure);
200
expect(afterIO).not.toBe(beforeIO);
201
}
202
);
203
204
message = 'should create distinct object with deep field insertion';
205
testDevAndProd(message, function() {
206
var beforeStructure = {
207
oldShallowField: {
208
deepField: {
209
oldField: null
210
}
211
}
212
};
213
214
var delta = {
215
oldShallowField: {newDeepField: 'hello'}
216
};
217
218
// LegacyImmutableObject does not yet support deep merging with
219
// LegacyImmutableObject.set().
220
var expectedAfterStructure = {
221
oldShallowField: {newDeepField: 'hello'}
222
};
223
224
var beforeIO = new LegacyImmutableObject(beforeStructure);
225
var afterIO = LegacyImmutableObject.set(beforeIO, delta);
226
expect(afterIO).toBeSeriallyEqualTo(expectedAfterStructure);
227
expect(afterIO).not.toBe(beforeIO);
228
});
229
230
message =
231
'should tolerate arrays at deeper levels and prevent mutation on them';
232
testDevAndProd(message, function() {
233
if (window.callPhantom) {
234
// PhantomJS has a bug with Object.freeze and Arrays.
235
// https://github.com/ariya/phantomjs/issues/10817
236
return;
237
}
238
var beforeStructure = {
239
shallowField: [1,'second field',3]
240
};
241
var io = new LegacyImmutableObject(beforeStructure);
242
expect(function() {
243
io.newField = 'nope!';
244
}).toThrow();
245
expect(function() {
246
io.shallowField[0] = 'nope!';
247
}).toThrow();
248
expect(io.shallowField[1]).toEqual('second field');
249
});
250
251
message = 'should provide a setField interface as sugar for set()';
252
testDevAndProd(message, function() {
253
var beforeIO = new LegacyImmutableObject({initialField: null});
254
var afterIO =
255
LegacyImmutableObject.setField(beforeIO, 'anotherField', 'anotherValue');
256
expect(afterIO).toBeSeriallyEqualTo({
257
initialField: null,
258
anotherField: 'anotherValue'
259
});
260
expect(afterIO).not.toBe(beforeIO);
261
});
262
263
message = 'should recursively create distinct objects when deep copying';
264
testDevAndProd(message, function() {
265
var beforeIO = new LegacyImmutableObject({
266
a: {b: 'b', c: {}, d: 'd', e: new LegacyImmutableObject({f: 'f'}) }
267
});
268
var afterIO = LegacyImmutableObject.setDeep(beforeIO, {
269
a: {b: {}, c: 'C', e: {f: 'F', g: 'G'}, h: 'H'}
270
});
271
expect(afterIO).toBeSeriallyEqualTo({
272
a: {b: {}, c: 'C', d: 'd', e: {f: 'F', g: 'G'}, h: 'H'}
273
});
274
expect(afterIO).not.toBe(beforeIO);
275
expect(afterIO.a).not.toBe(beforeIO.a);
276
expect(afterIO.a.e).not.toBe(beforeIO.a.e);
277
});
278
279
testDevAndProd('should deep copy member immutability', function() {
280
var beforeIO = new LegacyImmutableObject({
281
a: {b: new LegacyImmutableObject({c: 'c'}), e: {f: 'f'}}
282
});
283
var afterIO = LegacyImmutableObject.setDeep(beforeIO, {
284
a: {b: {d: 'D'}, e: new LegacyImmutableObject({g: 'G'})}
285
});
286
expect(afterIO).toBeSeriallyEqualTo({
287
a: {b: {c: 'c', d: 'D'}, e: {f: 'f', g: 'G'}}
288
});
289
expect(afterIO instanceof LegacyImmutableObject).toBe(true);
290
expect(afterIO.a.b instanceof LegacyImmutableObject).toBe(true);
291
expect(afterIO.a.e instanceof LegacyImmutableObject).toBe(true);
292
});
293
});
294
295