UNPKG

16.7 kBJavaScriptView Raw
1/*global it: false, describe: false, DeepDiffConflict: false*/
2'use strict';
3
4if (typeof require === 'function') {
5 var expect = require('expect.js'),
6 util = require('util'),
7 DeepDiff = require('..');
8}
9var deep = DeepDiff,
10 executingInBrowser = 'undefined' !== typeof window;
11
12describe('deep-diff', function() {
13 var empty = {};
14
15 describe('A target that has no properties', function() {
16
17 it('shows no differences when compared to another empty object', function() {
18 expect(deep.diff(empty, {})).to.be.an('undefined');
19 });
20
21 describe('when compared to a different type of keyless object', function() {
22 var ctor = function() {
23 this.foo = 'bar';
24 };
25 var comparandTuples = [
26 ['an array', {
27 key: []
28 }],
29 ['an object', {
30 key: {}
31 }],
32 ['a date', {
33 key: new Date()
34 }],
35 ['a null', {
36 key: null
37 }],
38 ['a regexp literal', {
39 key: /a/
40 }],
41 ['Math', {
42 key: Math
43 }]
44 ];
45
46 comparandTuples.forEach(function(lhsTuple) {
47 comparandTuples.forEach(function(rhsTuple) {
48 if (lhsTuple[0] === rhsTuple[0]) {
49 return;
50 }
51 it('shows differences when comparing ' + lhsTuple[0] + ' to ' + rhsTuple[0], function() {
52 var diff = deep.diff(lhsTuple[1], rhsTuple[1]);
53 expect(diff).to.be.ok();
54 expect(diff.length).to.be(1);
55 expect(diff[0]).to.have.property('kind');
56 expect(diff[0].kind).to.be('E');
57 });
58 });
59 });
60 });
61
62 describe('when compared with an object having other properties', function() {
63 var comparand = {
64 other: 'property',
65 another: 13.13
66 };
67 var diff = deep.diff(empty, comparand);
68
69 it('the differences are reported', function() {
70 expect(diff).to.be.ok();
71 expect(diff.length).to.be(2);
72
73 expect(diff[0]).to.have.property('kind');
74 expect(diff[0].kind).to.be('N');
75 expect(diff[0]).to.have.property('path');
76 expect(diff[0].path).to.be.an(Array);
77 expect(diff[0].path[0]).to.eql('other');
78 expect(diff[0]).to.have.property('rhs');
79 expect(diff[0].rhs).to.be('property');
80
81 expect(diff[1]).to.have.property('kind');
82 expect(diff[1].kind).to.be('N');
83 expect(diff[1]).to.have.property('path');
84 expect(diff[1].path).to.be.an(Array);
85 expect(diff[1].path[0]).to.eql('another');
86 expect(diff[1]).to.have.property('rhs');
87 expect(diff[1].rhs).to.be(13.13);
88 });
89
90 });
91
92 });
93
94 describe('A target that has one property', function() {
95 var lhs = {
96 one: 'property'
97 };
98
99 it('shows no differences when compared to itself', function() {
100 expect(deep.diff(lhs, lhs)).to.be.an('undefined');
101 });
102
103 it('shows the property as removed when compared to an empty object', function() {
104 var diff = deep.diff(lhs, empty);
105 expect(diff).to.be.ok();
106 expect(diff.length).to.be(1);
107 expect(diff[0]).to.have.property('kind');
108 expect(diff[0].kind).to.be('D');
109 });
110
111 it('shows the property as edited when compared to an object with null', function() {
112 var diff = deep.diff(lhs, {
113 one: null
114 });
115 expect(diff).to.be.ok();
116 expect(diff.length).to.be(1);
117 expect(diff[0]).to.have.property('kind');
118 expect(diff[0].kind).to.be('E');
119 });
120
121 it('shows the property as edited when compared to an array', function() {
122 var diff = deep.diff(lhs, ['one']);
123 expect(diff).to.be.ok();
124 expect(diff.length).to.be(1);
125 expect(diff[0]).to.have.property('kind');
126 expect(diff[0].kind).to.be('E');
127 });
128
129 });
130
131 describe('A target that has null value', function() {
132 var lhs = {
133 key: null
134 };
135
136 it('shows no differences when compared to itself', function() {
137 expect(deep.diff(lhs, lhs)).to.be.an('undefined');
138 });
139
140 it('shows the property as removed when compared to an empty object', function() {
141 var diff = deep.diff(lhs, empty);
142 expect(diff).to.be.ok();
143 expect(diff.length).to.be(1);
144 expect(diff[0]).to.have.property('kind');
145 expect(diff[0].kind).to.be('D');
146 });
147
148 it('shows the property is changed when compared to an object that has value', function() {
149 var diff = deep.diff(lhs, {
150 key: 'value'
151 });
152 expect(diff).to.be.ok();
153 expect(diff.length).to.be(1);
154 expect(diff[0]).to.have.property('kind');
155 expect(diff[0].kind).to.be('E');
156 });
157
158 it('shows that an object property is changed when it is set to null', function() {
159 lhs.key = {
160 nested: 'value'
161 };
162 var diff = deep.diff(lhs, {
163 key: null
164 });
165 expect(diff).to.be.ok();
166 expect(diff.length).to.be(1);
167 expect(diff[0]).to.have.property('kind');
168 expect(diff[0].kind).to.be('E');
169 });
170
171 });
172
173
174 describe('A target that has a date value', function() {
175 var lhs = {
176 key: new Date(555555555555)
177 };
178
179 it('shows the property is changed with a new date value', function() {
180 var diff = deep.diff(lhs, {
181 key: new Date(777777777777)
182 });
183 expect(diff).to.be.ok();
184 expect(diff.length).to.be(1);
185 expect(diff[0]).to.have.property('kind');
186 expect(diff[0].kind).to.be('E');
187 });
188
189 });
190
191
192 describe('A target that has a NaN', function() {
193 var lhs = {
194 key: NaN
195 };
196
197 it('shows the property is changed when compared to another number', function() {
198 var diff = deep.diff(lhs, {
199 key: 0
200 });
201 expect(diff).to.be.ok();
202 expect(diff.length).to.be(1);
203 expect(diff[0]).to.have.property('kind');
204 expect(diff[0].kind).to.be('E');
205 });
206
207 it('shows no differences when compared to another NaN', function() {
208 var diff = deep.diff(lhs, {
209 key: NaN
210 });
211 expect(diff).to.be.an('undefined');
212 });
213
214 });
215
216
217 describe('When executing in a browser (otherwise these tests are benign)', function() {
218
219 it('#isConflict reports conflict in the global namespace for `DeepDiff`', function() {
220 // the browser test harness sets up a conflict.
221 if (executingInBrowser) {
222 expect(DeepDiff.isConflict()).to.be.ok();
223 }
224 });
225
226 it('#noConflict restores prior definition for the global `DeepDiff`', function() {
227 // the browser test harness sets up a conflict.
228 if (executingInBrowser) {
229 expect(DeepDiff.isConflict()).to.be.ok();
230 var another = DeepDiff.noConflict();
231 expect(another).to.be(deep);
232 expect(DeepDiff).to.be(DeepDiffConflict);
233 }
234 });
235
236 });
237
238
239
240 describe('When filtering keys', function() {
241 var lhs = {
242 enhancement: 'Filter/Ignore Keys?',
243 numero: 11,
244 submitted_by: 'ericclemmons',
245 supported_by: ['ericclemmons'],
246 status: 'open'
247 };
248 var rhs = {
249 enhancement: 'Filter/Ignore Keys?',
250 numero: 11,
251 submitted_by: 'ericclemmons',
252 supported_by: [
253 'ericclemmons',
254 'TylerGarlick',
255 'flitbit',
256 'ergdev'
257 ],
258 status: 'closed',
259 fixed_by: 'flitbit'
260 };
261
262 describe('if the filtered property is an array', function() {
263
264 it('changes to the array do not appear as a difference', function() {
265 var prefilter = function(path, key) {
266 return key === 'supported_by';
267 };
268 var diff = deep(lhs, rhs, prefilter);
269 expect(diff).to.be.ok();
270 expect(diff.length).to.be(2);
271 expect(diff[0]).to.have.property('kind');
272 expect(diff[0].kind).to.be('E');
273 expect(diff[1]).to.have.property('kind');
274 expect(diff[1].kind).to.be('N');
275 });
276
277 });
278
279 describe('if the filtered property is not an array', function() {
280
281 it('changes do not appear as a difference', function() {
282 var prefilter = function(path, key) {
283 return key === 'fixed_by';
284 };
285 var diff = deep(lhs, rhs, prefilter);
286 expect(diff).to.be.ok();
287 expect(diff.length).to.be(4);
288 expect(diff[0]).to.have.property('kind');
289 expect(diff[0].kind).to.be('A');
290 expect(diff[1]).to.have.property('kind');
291 expect(diff[1].kind).to.be('A');
292 expect(diff[2]).to.have.property('kind');
293 expect(diff[2].kind).to.be('A');
294 expect(diff[3]).to.have.property('kind');
295 expect(diff[3].kind).to.be('E');
296 });
297
298 });
299 });
300
301 describe('A target that has nested values', function() {
302 var nestedOne = {
303 noChange: 'same',
304 levelOne: {
305 levelTwo: 'value'
306 }
307 };
308 var nestedTwo = {
309 noChange: 'same',
310 levelOne: {
311 levelTwo: 'another value'
312 }
313 };
314
315 it('shows no differences when compared to itself', function() {
316 expect(deep.diff(nestedOne, nestedOne)).to.be.an('undefined');
317 });
318
319 it('shows the property as removed when compared to an empty object', function() {
320 var diff = deep(nestedOne, empty);
321 expect(diff).to.be.ok();
322 expect(diff.length).to.be(2);
323 expect(diff[0]).to.have.property('kind');
324 expect(diff[0].kind).to.be('D');
325 expect(diff[1]).to.have.property('kind');
326 expect(diff[1].kind).to.be('D');
327 });
328
329 it('shows the property is changed when compared to an object that has value', function() {
330 var diff = deep.diff(nestedOne, nestedTwo);
331 expect(diff).to.be.ok();
332 expect(diff.length).to.be(1);
333 expect(diff[0]).to.have.property('kind');
334 expect(diff[0].kind).to.be('E');
335 });
336
337 it('shows the property as added when compared to an empty object on left', function() {
338 var diff = deep.diff(empty, nestedOne);
339 expect(diff).to.be.ok();
340 expect(diff.length).to.be(2);
341 expect(diff[0]).to.have.property('kind');
342 expect(diff[0].kind).to.be('N');
343 });
344
345 describe('when diff is applied to a different empty object', function() {
346 var diff = deep.diff(nestedOne, nestedTwo);
347 var result = {};
348
349 it('has result with nested values', function() {
350 deep.applyChange(result, nestedTwo, diff[0]);
351 expect(result.levelOne).to.be.ok();
352 expect(result.levelOne).to.be.an('object');
353 expect(result.levelOne.levelTwo).to.be.ok();
354 expect(result.levelOne.levelTwo).to.eql('another value');
355 });
356
357 });
358
359 });
360
361 describe('regression test for bug #10, ', function() {
362 var lhs = {
363 "id": "Release",
364 "phases": [{
365 "id": "Phase1",
366 "tasks": [{
367 "id": "Task1"
368 }, {
369 "id": "Task2"
370 }]
371 }, {
372 "id": "Phase2",
373 "tasks": [{
374 "id": "Task3"
375 }]
376 }]
377 };
378 var rhs = {
379 "id": "Release",
380 "phases": [{
381 // E: Phase1 -> Phase2
382 "id": "Phase2",
383 "tasks": [{
384 "id": "Task3"
385 }]
386 }, {
387 "id": "Phase1",
388 "tasks": [{
389 "id": "Task1"
390 }, {
391 "id": "Task2"
392 }]
393 }]
394 };
395
396 describe('differences in nested arrays are detected', function() {
397 var diff = deep.diff(lhs, rhs);
398
399 // there should be differences
400 expect(diff).to.be.ok();
401 expect(diff.length).to.be(6);
402
403 // It.phases[0].id changed from 'Phase1' to 'Phase2'
404 //
405 expect(diff[0].kind).to.be('E');
406 expect(diff[0].path).to.be.an('array');
407 expect(diff[0].path).to.have.length(3);
408 expect(diff[0].path[0]).to.be('phases');
409 expect(diff[0].path[1]).to.be(0);
410 expect(diff[0].path[2]).to.be('id');
411 expect(diff[0].lhs).to.be('Phase1');
412 expect(diff[0].rhs).to.be('Phase2');
413
414 // It.phases[0].tasks[0].id changed from 'Task1' to 'Task3'
415 //
416 expect(diff[1].kind).to.be('E');
417 expect(diff[1].path).to.be.an('array');
418 expect(diff[1].path).to.have.length(5);
419 expect(diff[1].path[0]).to.be('phases');
420 expect(diff[1].path[1]).to.be(0);
421 expect(diff[1].path[2]).to.be('tasks');
422 expect(diff[1].path[3]).to.be(0);
423 expect(diff[1].path[4]).to.be('id');
424 expect(diff[1].lhs).to.be('Task1');
425 expect(diff[1].rhs).to.be('Task3');
426
427 // It.phases[0].tasks[1] was deleted
428 //
429 expect(diff[2].kind).to.be('A');
430 expect(diff[2].path).to.be.an('array');
431 expect(diff[2].path).to.have.length(3);
432 expect(diff[2].path[0]).to.be('phases');
433 expect(diff[2].path[1]).to.be(0);
434 expect(diff[2].path[2]).to.be('tasks');
435 expect(diff[2].index).to.be(1);
436 expect(diff[2].item.kind).to.be('D');
437
438 // It.phases[1].id changed from 'Phase2' to 'Phase1'
439 //
440 expect(diff[3].kind).to.be('E');
441 expect(diff[3].path).to.be.an('array');
442 expect(diff[3].path).to.have.length(3);
443 expect(diff[3].path[0]).to.be('phases');
444 expect(diff[3].path[1]).to.be(1);
445 expect(diff[3].path[2]).to.be('id');
446 expect(diff[3].lhs).to.be('Phase2');
447 expect(diff[3].rhs).to.be('Phase1');
448
449 // It.phases[1].tasks[0].id changed from 'Task3' to 'Task1'
450 //
451 expect(diff[4].kind).to.be('E');
452 expect(diff[4].path).to.be.an('array');
453 expect(diff[4].path).to.have.length(5);
454 expect(diff[4].path[0]).to.be('phases');
455 expect(diff[4].path[1]).to.be(1);
456 expect(diff[4].path[2]).to.be('tasks');
457 expect(diff[4].path[3]).to.be(0);
458 expect(diff[4].path[4]).to.be('id');
459 expect(diff[4].lhs).to.be('Task3');
460 expect(diff[4].rhs).to.be('Task1');
461
462 // It.phases[1].tasks[1] is new
463 //
464 expect(diff[5].kind).to.be('A');
465 expect(diff[5].path).to.be.an('array');
466 expect(diff[5].path).to.have.length(3);
467 expect(diff[5].path[0]).to.be('phases');
468 expect(diff[5].path[1]).to.be(1);
469 expect(diff[5].path[2]).to.be('tasks');
470 expect(diff[5].index).to.be(1);
471 expect(diff[5].item.kind).to.be('N');
472
473 it('differences can be applied', function() {
474 var applied = deep.applyDiff(lhs, rhs);
475
476 it('and the result equals the rhs', function() {
477
478 });
479
480 });
481 });
482
483 });
484
485});