Completed
Push — master ( 334bf8...741e42 )
by Felipe
38s
created

test/body.js   B

Complexity

Total Complexity 40
Complexity/F 1.05

Size

Lines of Code 676
Function Count 38

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 0
c 1
b 0
f 0
nc 1
dl 0
loc 676
rs 8.0694
wmc 40
mnd 0
bc 38
fnc 38
bpm 1
cpm 1.0526
noi 38

How to fix   Complexity   

Complexity

Complex classes like test/body.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*
2
  backgrid
3
  http://github.com/wyuenho/backgrid
4
5
  Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
6
  Licensed under the MIT license.
7
*/
8
describe("A Body", function () {
9
10
  var col;
11
  var body;
12
  beforeEach(function () {
13
14
    col = new Backbone.Collection([{
15
      id: 2
16
    }, {
17
      id: 1
18
    }, {
19
      id: 3
20
    }]);
21
22
    body = new Backgrid.Body({
23
      columns: [{
24
        name: "id",
25
        cell: "integer"
26
      }],
27
      collection: col
28
    });
29
30
    body.render();
31
  });
32
33
  it("renders table rows using the given column definitions and collection", function () {
34
    expect(body.el.tagName).toBe("TBODY");
35
    var $trs = body.$el.children();
36
    expect($trs.length).toBe(3);
37
    expect($(body.el).html().toLowerCase().replace(/\s*</g, '<'))
38
      .toBe('<tr><td class="integer-cell editable sortable renderable id">2</td></tr>' +
39
        '<tr><td class="integer-cell editable sortable renderable id">1</td></tr>' +
40
        '<tr><td class="integer-cell editable sortable renderable id">3</td></tr>');
41
  });
42
43
  it("will render a new row if a new model is added to its collection", function () {
44
    body.collection.add({
45
      id: 4
46
    });
47
    var $trs = body.$el.children();
48
    expect($trs.length).toBe(4);
49
    expect($("<div>").append($trs.eq(3).clone()).html().toLowerCase().replace(/\s*</g, '<'))
50
      .toBe('<tr><td class="integer-cell editable sortable renderable id">4</td></tr>');
51
52
    body.collection.add({
53
      id: 5
54
    }, {
55
      at: 1
56
    });
57
    $trs = body.$el.children();
58
    expect($trs.length).toBe(5);
59
    expect($("<div>").append($trs.eq(1).clone()).html().toLowerCase().replace(/\s*</g, '<'))
60
      .toBe('<tr><td class="integer-cell editable sortable renderable id">5</td></tr>');
61
  });
62
63
  it("will render a new row by calling insertRow directly with a new model", function () {
64
65
    body = new Backgrid.Body({
66
      columns: [{
67
        name: "id",
68
        cell: "integer"
69
      }],
70
      collection: new Backbone.Collection()
71
    });
72
73
    body.render();
74
75
    body.insertRow({
76
      id: 4
77
    });
78
79
    var $trs = body.$el.children();
80
    expect($trs.length).toBe(1);
81
    expect($("<div>").append($trs.eq(0).clone()).html().toLowerCase().replace(/\s*</g, '<'))
82
      .toBe('<tr><td class="integer-cell editable sortable renderable id">4</td></tr>');
83
84
    body.insertRow({
85
      id: 5
86
    }, {
87
      at: 0
88
    });
89
    $trs = body.$el.children();
90
    expect($trs.length).toBe(2);
91
    expect($("<div>").append($trs.eq(0).clone()).html().toLowerCase().replace(/\s*</g, '<'))
92
      .toBe('<tr><td class="integer-cell editable sortable renderable id">5</td></tr>');
93
  });
94
95
  it("will remove a row from the DOM if a model is removed from its collection", function () {
96
    var m1 = body.collection.at(1);
97
    body.collection.remove(m1);
98
    var $trs = body.$el.children();
99
    expect($trs.length).toBe(2);
100
    expect($(body.el).html().toLowerCase().replace(/\s+</g, '<'))
101
      .toBe('<tr><td class="integer-cell editable sortable renderable id">2</td></tr>' +
102
        '<tr><td class="integer-cell editable sortable renderable id">3</td></tr>');
103
  });
104
105
  it("will remove a row from the DOM is removeRow is called directly with a model", function () {
106
    var m1 = body.collection.at(1);
107
    body.removeRow(m1);
108
    var $trs = body.$el.children();
109
    expect($trs.length).toBe(2);
110
    expect($(body.el).html().toLowerCase().replace(/\s+</g, '<'))
111
      .toBe('<tr><td class="integer-cell editable sortable renderable id">2</td></tr>' +
112
        '<tr><td class="integer-cell editable sortable renderable id">3</td></tr>');
113
  });
114
115
  it("will refresh if its collection is reset", function () {
116
    var eventFired = false;
117
    var handler = function () {
118
      eventFired = true;
119
    };
120
    body.collection.on("backgrid:refresh", handler);
121
    body.collection.reset([{
122
      id: 6
123
    }]);
124
    body.collection.off("backgrid:refresh", handler);
125
    expect(eventFired).toBe(true);
126
    var $trs = body.$el.children();
127
    expect($trs.length).toBe(1);
128
    expect($(body.el).html().toLowerCase().replace(/\s+</g, '<'))
129
      .toBe('<tr><td class="integer-cell editable sortable renderable id">6</td></tr>');
130
  });
131
132
  it("will render rows using the Row class supplied in the constructor options", function () {
133
134
    var CustomRow = Backgrid.Row.extend({});
135
136
    spyOn(CustomRow.prototype, "render").and.callThrough();
137
138
    body = new Backgrid.Body({
139
      columns: [{
140
        name: "id",
141
        cell: "integer"
142
      }],
143
      collection: col,
144
      row: CustomRow
145
    });
146
147
    body.render();
148
149
    expect(CustomRow.prototype.render).toHaveBeenCalled();
150
  });
151
152
  describe("maintain page size at page boundary", function () {
153
154
    var col;
155
156
    beforeEach(function () {
157
      col = new Backbone.PageableCollection([{
158
        id: 1
159
      }, {
160
        id: 2
161
      }, {
162
        id: 3
163
      }], {
164
        state: {
165
          pageSize: 2
166
        },
167
        mode: "client"
168
      });
169
170
      body = new Backgrid.Body({
171
        columns: [{
172
          name: "id",
173
          cell: "integer"
174
        }],
175
        collection: col
176
      });
177
178
      body.render();
179
    });
180
181
    it("when adding to a full page", function () {
182
      col.add(new Backbone.Model({
183
        id: 4
184
      }));
185
      expect(body.$el.find("tr").length).toBe(2);
186
    });
187
188
    it("when removing from a full page", function () {
189
      col.remove(col.get(1));
190
      expect(body.$el.find("tr").length).toBe(2);
191
    });
192
193
  });
194
195
  it("will not display the empty row if collection is not empty", function () {
196
    body = new Backgrid.Body({
197
      emptyText: " ",
198
      columns: [{
199
        name: "id",
200
        cell: "integer"
201
      }],
202
      collection: col
203
    });
204
    body.render();
205
206
    expect(body.$el.find("tr.empty").length).toBe(0);
207
  });
208
209
  it("will not display the empty row if `options.emptyText` is not supplied", function () {
210
    expect(body.$el.find("tr.empty").length).toBe(0);
211
212
    col.reset();
213
    body = new Backgrid.Body({
214
      columns: [{
215
        name: "id",
216
        cell: "integer"
217
      }],
218
      collection: col
219
    });
220
    body.render();
221
222
    expect(body.$el.find("tr.empty").length).toBe(0);
223
  });
224
225
  it("will display the empty row if the collection is empty and `options.emptyText` is supplied", function () {
226
    col.reset();
227
    body = new Backgrid.Body({
228
      emptyText: " ",
229
      columns: [{
230
        name: "id",
231
        cell: "integer"
232
      }],
233
      collection: col
234
    });
235
    body.render();
236
237
    expect(body.$el.find("tr.empty").length).toBe(1);
238
    expect(body.$el.find("tr.empty > td").attr("colspan")).toBe("1");
239
  });
240
241
  it("will update the colspan of the empty row as columns are changed", function () {
242
    col.reset();
243
    body = new Backgrid.Body({
244
      emptyText: " ",
245
      columns: [{
246
        name: "id",
247
        cell: "integer"
248
      }],
249
      collection: col
250
    });
251
    body.render();
252
253
    expect(body.$el.find("tr.empty > td").attr("colspan")).toBe("1");
254
    body.columns.push({
255
      name: "age",
256
      cell: "integer"
257
    });
258
    expect(body.$el.find("tr.empty > td").attr("colspan")).toBe("2");
259
  });
260
261
  it("will clear the empty row if a new model is added to an empty collection", function () {
262
    col.reset();
263
    body = new Backgrid.Body({
264
      emptyText: " ",
265
      columns: [{
266
        name: "id",
267
        cell: "integer"
268
      }],
269
      collection: col
270
    });
271
    body.render();
272
    expect(body.$el.find("tr.empty").length).toBe(1);
273
274
    col.add({
275
      id: 4
276
    });
277
    expect(body.$el.find("tr.empty").length).toBe(0);
278
279
    col.reset();
280
    expect(body.$el.find("tr.empty").length).toBe(1);
281
282
    body.insertRow({
283
      id: 5
284
    });
285
    expect(body.$el.find("tr.empty").length).toBe(0);
286
  });
287
288
  it("will show the empty row if all rows are removed from the collection", function () {
289
    col.reset({
290
      id: 4
291
    });
292
    body = new Backgrid.Body({
293
      emptyText: " ",
294
      columns: [{
295
        name: "id",
296
        cell: "integer"
297
      }],
298
      collection: col
299
    });
300
    body.render();
301
    expect(body.$el.find("tr.empty").length).toBe(0);
302
303
    col.remove(col.at(0));
304
    expect(body.$el.find("tr.empty").length).toBe(1);
305
306
    body.insertRow({
307
      id: 5
308
    });
309
    expect(body.$el.find("tr.empty").length).toBe(0);
310
311
    body.removeRow(col.at(0));
312
    expect(body.$el.find("tr.empty").length).toBe(1);
313
  });
314
315
  it("won't call render from updateEmptyRow if there is no emptyView", function () {
316
    var pushColumn = function () {
317
      body.columns.push({
318
        name: "age",
319
        cell: "integer"
320
      });
321
    };
322
    expect(pushColumn).not.toThrow();
323
  });
324
325
  it("#sort will throw a RangeError is direction is not ascending, descending or null", function () {
326
    body = new Backgrid.Body({
327
      collection: col,
328
      columns: [{
329
        name: "id",
330
        cell: "integer"
331
      }],
332
    }).render();
333
334
    expect(function () {
335
      body.sort("id", "wat");
336
    }).toThrow();
337
  });
338
339
  it("can sort the underlying collection using the default comparator", function () {
340
    body = new Backgrid.Body({
341
      collection: col,
342
      columns: [{
343
        name: "id",
344
        cell: "integer"
345
      }],
346
    }).render();
347
348
    body.collection.trigger("backgrid:sort", body.columns.at(0), "ascending");
349
    expect(body.collection.toJSON()).toEqual([{
350
      id: 1
351
    }, {
352
      id: 2
353
    }, {
354
      id: 3
355
    }]);
356
    expect(body.columns.at(0).get("direction"), "ascending");
357
358
    body.collection.trigger("backgrid:sort", body.columns.at(0), "descending");
359
    expect(body.collection.toJSON()).toEqual([{
360
      id: 3
361
    }, {
362
      id: 2
363
    }, {
364
      id: 1
365
    }]);
366
    expect(body.columns.at(0).get("direction"), "descending");
367
368
    col.at(0).cid = "c100";
369
    col.at(1).cid = "c1";
370
    col.at(2).cid = "c10";
371
    body.collection.trigger("backgrid:sort", body.columns.at(0), null);
372
    expect(body.collection.toJSON()).toEqual([{
373
      id: 2
374
    }, {
375
      id: 1
376
    }, {
377
      id: 3
378
    }]);
379
    expect(body.columns.at(0).get("direction"), null);
380
  });
381
382
  it("can sort the underlying collection using a custom value extractor on `backgrid:sort`", function () {
383
384
    var sortValue = function (model, attr) {
385
      return 3 - model.get(attr);
386
    };
387
388
    body = new Backgrid.Body({
389
      collection: col,
390
      columns: [{
391
        name: "id",
392
        cell: "integer",
393
        sortValue: sortValue
394
      }],
395
    }).render();
396
397
    body.collection.trigger("backgrid:sort", body.columns.at(0), "ascending");
398
    expect(body.collection.toJSON()).toEqual([{
399
      id: 3
400
    }, {
401
      id: 2
402
    }, {
403
      id: 1
404
    }]);
405
    expect(body.columns.at(0).get("direction"), "ascending");
406
  });
407
408
  it("can sort on a server-mode Backbone.PageableCollection", function () {
409
410
    var oldAjax = $.ajax;
411
    $.ajax = function (settings) {
412
      settings.success([{
413
          "total_entries": 3
414
        },
415
        [{
416
          id: 2
417
        }, {
418
          id: 1
419
        }]
420
      ]);
421
    };
422
423
    var col = new(Backbone.PageableCollection.extend({
424
      url: "test-headercell"
425
    }))([{
426
      id: 1
427
    }, {
428
      id: 2
429
    }], {
430
      state: {
431
        pageSize: 3
432
      }
433
    });
434
435
    body = new Backgrid.Body({
436
      columns: [{
437
        name: "id",
438
        cell: "integer"
439
      }],
440
      collection: col
441
    });
442
443
    body.render();
444
445
    expect(body.collection.at(0).get("id")).toBe(1);
446
    expect(body.collection.at(1).get("id")).toBe(2);
447
448
    var onBackgridSortedCallArgs = [];
449
    col.on("backgrid:sorted", function () {
450
      onBackgridSortedCallArgs.push([].slice.apply(arguments));
451
    });
452
453
    body.collection.trigger("backgrid:sort", body.columns.at(0), "descending");
454
455
    expect(body.collection.at(0).get("id")).toBe(2);
456
    expect(body.collection.at(1).get("id")).toBe(1);
457
    expect(body.columns.at(0).get("direction"), "descending");
458
    expect(onBackgridSortedCallArgs.length).toBe(1);
459
    expect(onBackgridSortedCallArgs[0][0]).toBe(body.columns.at(0));
460
    expect(onBackgridSortedCallArgs[0][1]).toBe("descending");
461
462
    $.ajax = oldAjax;
463
  });
464
465
  it("can sort on a client-mode Backbone.PageableCollection", function () {
466
467
    var col = new Backbone.PageableCollection([{
468
      id: 2
469
    }, {
470
      id: 1
471
    }, {
472
      id: 3
473
    }], {
474
      state: {
475
        pageSize: 1
476
      },
477
      mode: "client"
478
    });
479
480
    body = new Backgrid.Body({
481
      columns: [{
482
        name: "id",
483
        cell: "integer",
484
        sortValue: function (model, attr) {
485
          return 3 - model.get(attr);
486
        }
487
      }],
488
      collection: col
489
    });
490
491
    body.render();
492
493
    var onBackgridSortedCallArgs = [];
494
    col.on("backgrid:sorted", function () {
495
      onBackgridSortedCallArgs.push([].slice.apply(arguments));
496
    });
497
498
    col.trigger("backgrid:sort", body.columns.at(0), "ascending");
499
    expect(body.collection.toJSON()).toEqual([{
500
      id: 3
501
    }]);
502
    expect(body.columns.at(0).get("direction"), "ascending");
503
    expect(onBackgridSortedCallArgs.length).toBe(1);
504
    expect(onBackgridSortedCallArgs[0][0]).toBe(body.columns.at(0));
505
    expect(onBackgridSortedCallArgs[0][1]).toBe("ascending");
506
    expect(onBackgridSortedCallArgs[0][2]).toBe(col);
507
508
    body.collection.getPage(2);
509
    expect(body.collection.toJSON()).toEqual([{
510
      id: 2
511
    }]);
512
513
    body.collection.getPage(3);
514
    expect(body.collection.toJSON()).toEqual([{
515
      id: 1
516
    }]);
517
518
    body.collection.getFirstPage();
519
520
    col.trigger("backgrid:sort", body.columns.at(0), "descending");
521
    expect(body.columns.at(0).get("direction"), "descending");
522
    expect(body.collection.toJSON()).toEqual([{
523
      id: 1
524
    }]);
525
    expect(onBackgridSortedCallArgs.length).toBe(2);
526
    expect(onBackgridSortedCallArgs[1][0]).toBe(body.columns.at(0));
527
    expect(onBackgridSortedCallArgs[1][1]).toBe("descending");
528
    expect(onBackgridSortedCallArgs[1][2]).toBe(col);
529
530
    col.trigger("backgrid:sort", body.columns.at(0), null);
531
    expect(body.columns.at(0).get("direction"), null);
532
    expect(body.collection.toJSON()).toEqual([{
533
      id: 2
534
    }]);
535
    expect(onBackgridSortedCallArgs.length).toBe(3);
536
    expect(onBackgridSortedCallArgs[2][0]).toBe(body.columns.at(0));
537
    expect(onBackgridSortedCallArgs[2][1]).toBe(null);
538
    expect(onBackgridSortedCallArgs[2][2]).toBe(col);
539
  });
540
541
  it("will put the next editable and renderable cell in edit mode when a save or one of the navigation commands is triggered via backgrid:edited from the collection", function () {
542
    var people = new Backbone.Collection([{
543
      name: "alice",
544
      age: 28,
545
      married: false
546
    }, {
547
      name: "bob",
548
      age: 30,
549
      married: true
550
    }]);
551
    var columns = new Backgrid.Columns([{
552
      name: "name",
553
      cell: "string"
554
    }, {
555
      name: "age",
556
      cell: "integer",
557
      editable: false
558
    }, {
559
      name: "sex",
560
      cell: "boolean",
561
      renderable: false
562
    }]);
563
    var body = new Backgrid.Body({
564
      collection: people,
565
      columns: columns
566
    });
567
    body.render();
568
569
    body.rows[0].cells[0].enterEditMode();
570
571
    // Just making sure a cell has exited edit mode before the next cell goes
572
    // into edit mode. Fixes #187.
573
    var oldExitEditMode = body.rows[0].cells[0].exitEditMode;
574
    var callOrders = [];
575
    body.rows[0].cells[0].exitEditMode = function () {
576
      callOrders.push("exit");
577
      return oldExitEditMode.apply(this, arguments);
578
    };
579
580
    var oldEnterEditMode = body.rows[1].cells[0].enterEditMode;
581
    body.rows[1].cells[0].enterEditMode = function () {
582
      callOrders.push("enter");
583
      return oldEnterEditMode.apply(this, arguments);
584
    };
585
586
    // right
587
    people.trigger("backgrid:edited", people.at(0), columns.at(0), new Backgrid.Command({
588
      keyCode: 9
589
    }));
590
    expect(body.rows[0].cells[0].$el.hasClass("editor")).toBe(false);
591
    expect(body.rows[1].cells[0].$el.hasClass("editor")).toBe(true);
592
593
    expect(callOrders[0]).toBe("exit");
594
    expect(callOrders[1]).toBe("enter");
595
    body.rows[0].cells[0].exitEditMode = oldExitEditMode;
596
    body.rows[1].cells[0].enterEditMode = oldEnterEditMode;
597
598
    // left
599
    people.trigger("backgrid:edited", people.at(1), columns.at(0), new Backgrid.Command({
600
      keyCode: 9,
601
      shiftKey: true
602
    }));
603
    expect(body.rows[0].cells[0].$el.hasClass("editor")).toBe(true);
604
    expect(body.rows[1].cells[0].$el.hasClass("editor")).toBe(false);
605
606
    // down
607
    people.trigger("backgrid:edited", people.at(0), columns.at(0), new Backgrid.Command({
608
      keyCode: 40
609
    }));
610
    expect(body.rows[0].cells[0].$el.hasClass("editor")).toBe(false);
611
    expect(body.rows[1].cells[0].$el.hasClass("editor")).toBe(true);
612
613
    // up
614
    people.trigger("backgrid:edited", people.at(1), columns.at(0), new Backgrid.Command({
615
      keyCode: 38
616
    }));
617
    expect(body.rows[0].cells[0].$el.hasClass("editor")).toBe(true);
618
    expect(body.rows[1].cells[0].$el.hasClass("editor")).toBe(false);
619
620
    // enter
621
    people.trigger("backgrid:edited", people.at(0), columns.at(0), new Backgrid.Command({
622
      keyCode: 13
623
    }));
624
    expect(body.rows[0].cells[0].$el.hasClass("editor")).toBe(false);
625
    expect(body.rows[1].cells[0].$el.hasClass("editor")).toBe(false);
626
627
    // esc
628
    body.rows[1].cells[0].enterEditMode();
629
    people.trigger("backgrid:edited", people.at(1), columns.at(0), new Backgrid.Command({
630
      keyCode: 27
631
    }));
632
    expect(body.rows[0].cells[0].$el.hasClass("editor")).toBe(false);
633
    expect(body.rows[1].cells[0].$el.hasClass("editor")).toBe(false);
634
  });
635
636
  it("will not throw an exception when backgrid:edited is fired on a shared model", function () {
637
    var people = new Backbone.Collection([{
638
      name: "alice",
639
      age: 28,
640
      married: false
641
    }, {
642
      name: "bob",
643
      age: 30,
644
      married: true
645
    }]);
646
    var columns = new Backgrid.Columns([{
647
      name: "name",
648
      cell: "string"
649
    }, {
650
      name: "age",
651
      cell: "integer",
652
      editable: false
653
    }, {
654
      name: "sex",
655
      cell: "boolean",
656
      renderable: false
657
    }]);
658
    var body = new Backgrid.Body({
659
      collection: people,
660
      columns: columns
661
    });
662
    body.render();
663
664
    var columns2 = new Backgrid.Columns([{
665
      name: "name",
666
      cell: "string"
667
    }]);
668
    var body2 = new Backgrid.Body({
669
      collection: people,
670
      columns: columns2
671
    });
672
    body2.render();
673
674
    body.rows[0].cells[0].enterEditMode();
675
    var testTrigger = function () {
676
      people.trigger("backgrid:edited", people.at(0), columns.at(0), new Backgrid.Command({
677
        keyCode: 9
678
      }));
679
    };
680
    expect(testTrigger).not.toThrow();
681
  });
682
683
});
684