PageRenderTime 12ms CodeModel.GetById 2ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/test/views.js

https://github.com/d1b1/backbone.layoutmanager
JavaScript | 1169 lines | 848 code | 286 blank | 35 comment | 3 complexity | f0d1a1bccd3643be6de15a7328be8bd1 MD5 | raw file
   1function isNode(obj) {
   2  if (obj && obj.nodeType != null) {
   3    return true;
   4  }
   5}
   6
   7module("views", {
   8  setup: function() {
   9    var setup = this;
  10
  11    // Custom View
  12    this.View = Backbone.LayoutView.extend({
  13      template: "#test",
  14
  15      serialize: function() {
  16        return { text: this.msg };
  17      },
  18
  19      initialize: function(opts) {
  20        this.msg = opts.msg;
  21      }
  22    });
  23
  24    // Initialize View
  25    this.InitView = Backbone.LayoutView.extend({
  26      template: "#test",
  27
  28      serialize: function() {
  29        return { text: this.msg };
  30      },
  31
  32      initialize: function(opts) {
  33        this.msg = opts.msg;
  34
  35        this.setViews({
  36          ".inner-right": new setup.SubView()
  37        });
  38      }
  39    });
  40
  41    this.SubView = Backbone.LayoutView.extend({
  42      template: "#test-sub",
  43
  44      serialize: function() {
  45        return { text: "Right" };
  46      }
  47    });
  48
  49    this.EventedListView = Backbone.LayoutView.extend({
  50      template: "#list",
  51
  52      initialize: function() {
  53        this.collection.on("reset", this.render, this);
  54      },
  55
  56      cleanup: function() {
  57        this.collection.off(null, null, this);
  58      },
  59
  60      beforeRender: function() {
  61        this.collection.each(function(model) {
  62          this.insertView("ul", new setup.ItemView({ model: model.toJSON() }));
  63        }, this);
  64      }
  65    });
  66
  67    this.ListView = Backbone.LayoutView.extend({
  68      template: "#list",
  69
  70      beforeRender: function() {
  71        // Iterate over the passed collection and insert into the view
  72        _.each(this.collection, function(model) {
  73          this.insertView("ul", new setup.ItemView({ model: model }));
  74        }, this);
  75      }
  76    });
  77
  78    this.ItemView = Backbone.LayoutView.extend({
  79      template: "#test-sub",
  80      tagName: "li",
  81
  82      serialize: function() {
  83        return this.model;
  84      }
  85    });
  86  }
  87});
  88
  89asyncTest("render outside defined partial", 2, function() {
  90  var main = new Backbone.Layout({
  91    template: "#main"
  92  });
  93
  94  var a = main.setView(".right", new this.View({ msg: "Right" }));
  95
  96  main.render().then(function() {
  97    var trimmed = $.trim( $(this.el).find(".inner-left").html() );
  98
  99    ok(isNode(this.el), "Contents is a DOM Node");
 100    equal(trimmed, "Right", "Correct render");
 101
 102    start();
 103  });
 104});
 105
 106asyncTest("render inside defined partial", function() {
 107  expect(2);
 108
 109  var main = new Backbone.Layout({
 110    template: "#main",
 111
 112    views: {
 113      ".right": new this.View({ msg: "Right" })
 114    }
 115  });
 116
 117  main.render(function(el) {
 118    var trimmed = $.trim( $(el).find(".inner-left").html() );
 119
 120    ok(isNode(el), "Contents is a DOM Node");
 121    equal(trimmed, "Right", "Correct render");
 122
 123    start();
 124  });
 125});
 126
 127asyncTest("re-render a view defined after initialization", function(){
 128  expect(2);
 129
 130  var trimmed;
 131  var setup = this;
 132
 133  var main = new Backbone.Layout({
 134    template: "#main"
 135  });
 136
 137  main.setView(".right", new this.View({ msg: "Right" }));
 138
 139  main.render(function(el) {
 140    $('#container').html(el);
 141
 142    trimmed = $.trim( $("#container .inner-left").html() );
 143    equal(trimmed, "Right", "Correct re-render");
 144
 145    main.setView(".right", new setup.View({
 146      msg: "Right Again"
 147    })).render().then(function() {
 148      trimmed = $.trim( $("#container .inner-left").html() );
 149      equal(trimmed, "Right Again", "Correct re-render");
 150
 151      start();
 152    });
 153  });
 154});
 155
 156asyncTest("nested views", function() {
 157  expect(2);
 158
 159  var main = new Backbone.Layout({
 160    template: "#main",
 161
 162    views: {
 163      ".right": new this.View({
 164        msg: "Left",
 165
 166        views: {
 167          ".inner-right": new this.SubView({ lol: "hi" })
 168        }
 169      })
 170    }
 171  });
 172
 173  main.render().then(function() {
 174    var view = this;
 175    var trimmed = $.trim(this.$(".inner-right div").html());
 176
 177    ok(isNode(this.el), "Contents is a DOM Node");
 178    equal(trimmed, "Right", "Correct render");
 179
 180    start();
 181  });
 182});
 183
 184asyncTest("serialize on Layout is a function", function() {
 185  expect(1);
 186
 187  var testText = "test text";
 188
 189  var main = new Backbone.Layout({
 190    template: "#test-sub",
 191    serialize: { text: "test text" }
 192  });
 193
 194  main.render(function(el) {
 195    equal($.trim( $(el).text() ), testText, "correct serialize");
 196
 197    start();
 198  });
 199});
 200
 201asyncTest("serialize on Layout is an object", function() {
 202  expect(1);
 203
 204  var testText = "test text";
 205
 206  var main = new Backbone.Layout({
 207    template: "#test-sub",
 208    serialize: { text: "test text" }
 209  });
 210
 211  main.render(function(el) {
 212    equal($.trim( $(el).text() ), testText, "correct serialize");
 213
 214    start();
 215  });
 216});
 217
 218// TODO THIS TEST
 219asyncTest("rendered event", function() {
 220  expect(4);
 221
 222  var main = new Backbone.Layout({
 223    template: "#main",
 224
 225    views: {
 226      ".right": new this.ListView({
 227        collection: [{ text: "one" }, { text: "two" }]
 228      })
 229    }
 230  });
 231
 232  main.render(function(el) {
 233    ok(isNode(el), "Contents is a DOM Node");
 234
 235    equal($(el).find("ul li").length, 2, "Correct number of nested li's");
 236    equal($.trim( $(el).find("ul li:eq(0)").html() ), "one",
 237      "Correct first li content");
 238
 239    equal($.trim( $(el).find("ul li:eq(1)").html() ), "two",
 240      "Correct second li content");
 241
 242    start();
 243  });
 244});
 245
 246asyncTest("insert views", function() {
 247  expect(4);
 248
 249  var main = new Backbone.Layout({
 250    template: "#main",
 251
 252    views: {
 253      ".right": new this.ListView({
 254        collection: [{ text: "one" }, { text: "two" }]
 255      })
 256    }
 257  });
 258
 259  main.render(function(el) {
 260    ok(isNode(el), "Contents is a DOM Node");
 261
 262    equal($(el).find("ul li").length, 2, "Correct number of nested li's");
 263
 264    equal($.trim( $(el).find("ul li:eq(0)").html() ), "one",
 265      "Correct first li content");
 266
 267    equal($.trim( $(el).find("ul li:eq(1)").html() ), "two",
 268      "Correct second li content");
 269
 270    start();
 271  });
 272});
 273
 274asyncTest("using setViews", function() {
 275  expect(2);
 276
 277  var main = new Backbone.Layout({
 278    template: "#main"
 279  });
 280
 281  main.setViews({
 282    ".right": new this.View({
 283      msg: "Left",
 284
 285      views: {
 286        ".inner-right": new this.SubView()
 287      }
 288    })
 289  });
 290
 291  main.render().then(function() {
 292    var trimmed = $.trim(this.$(".inner-right div").html());
 293
 294    ok(isNode(this.el), "Contents is a DOM Node");
 295    equal(trimmed, "Right", "Correct render");
 296
 297    start();
 298  });
 299});
 300
 301asyncTest("using setViews inside initialize", function() {
 302  expect(2);
 303
 304  var main = new Backbone.Layout({
 305    template: "#main"
 306  });
 307
 308  main.setViews({
 309    ".right": new this.InitView({
 310      msg: "Left"
 311    })
 312  });
 313
 314  main.render(function(el) {
 315    var trimmed = $.trim( $(el).find(".inner-right div").html() );
 316
 317    ok(isNode(el), "Contents is a DOM Node");
 318    equal(trimmed, "Right", "Correct render");
 319
 320    start();
 321  });
 322});
 323
 324asyncTest("extend layoutmanager", 1, function() {
 325  var testText = "test text";
 326
 327  var BaseLayout = Backbone.Layout.extend({
 328    template: "#test-sub",
 329    serialize: { text: "test text" }
 330  });
 331
 332  var main = new BaseLayout();
 333
 334  main.render(function(el) {
 335    equal($.trim( $(el).text() ), testText, "correct serialize");
 336
 337    start();
 338  });
 339});
 340
 341asyncTest("appending views with array literal", 3, function() {
 342  var main = new Backbone.Layout({
 343    template: "#main"
 344  });
 345
 346  main.setViews({
 347    ".right": [
 348      new this.View({
 349        msg: "One",
 350        keep: true
 351      }),
 352
 353      new this.View({
 354        msg: "Two",
 355        keep: true
 356      })
 357    ]
 358  });
 359
 360  main.render(function(el) {
 361    main.render().then(function(el) {
 362      equal($(el).find(".right").children().length, 2, "correct children length");
 363
 364      equal($.trim( $(el).find(".right").children().eq(0).text() ), "One",
 365        "correct value set for the first child");
 366
 367      equal($.trim( $(el).find(".right").children().eq(1).text() ), "Two",
 368        "correct value set for the second child");
 369
 370      start();
 371    });
 372  });
 373});
 374
 375asyncTest("use layout without a template property", function() {
 376  expect(1);
 377
 378  var main = new Backbone.Layout({
 379    el: "#prefilled"
 380  });
 381
 382  main.setViews({
 383    ".test": new this.SubView()
 384  });
 385
 386  main.render(function(el) {
 387    equal($.trim( $(el).find(".test").text() ), "Right",
 388      "Able to use an existing DOM element");
 389     
 390    start();
 391  });
 392});
 393
 394asyncTest("single render per view", function() {
 395  expect(1);
 396
 397  var count = 0;
 398
 399  var main = new Backbone.Layout({
 400    template: "#main"
 401  });
 402
 403  var right = main.setView(".right", new this.View({
 404    msg: "1"
 405  }));
 406  
 407  // Level 1
 408  right.render(function() {
 409    count++;
 410  });
 411
 412  // Level 2
 413  right.setView(".inner-right", new this.View({ msg: "2" })).render(function() {
 414    count++;
 415  });
 416
 417  // Level 3
 418  var innerRight = right.views[".inner-right"];
 419
 420  innerRight.setViews({
 421    ".inner-right": [ new this.SubView(), new this.SubView() ]
 422  });
 423  
 424  innerRight.views[".inner-right"][0].render(function() {
 425    count++;
 426  });
 427
 428  innerRight.views[".inner-right"][1].render(function() {
 429    count++;
 430  });
 431
 432  main.render(function(el) {
 433    equal(count, 4, "Render is only called once for each view");
 434     
 435    start();
 436  });
 437});
 438
 439asyncTest("render callback and deferred context is view", function() {
 440  expect(6);
 441
 442  var main = new Backbone.Layout({
 443    template: "#main",
 444
 445    views: {
 446      ".right": new this.View({ msg: "Right" }),
 447      ".left": [
 448        new this.View({ keep: true, msg: "Left 1" }),
 449        new this.View({
 450            msg: "Left 2",
 451            keep: true,
 452            views: {
 453              ".inner-left": new this.SubView({ lol: "hi" })
 454            }
 455        })
 456      ]
 457    }
 458  });
 459
 460  main.render(function(el) {
 461    equal(this, main, "Layout render callback context is Layout");
 462    start();
 463  }).then(function(el) {
 464    equal(this, main, "Layout render deferred context is Layout");
 465    start();
 466  });
 467
 468  main.views[".right"].render(function(el) {
 469    equal(this, main.views[".right"], "View render callback context is View");
 470    start();
 471  }).then(function(el) {
 472    equal(this, main.views[".right"], "View render deferred context is View");
 473    start();
 474  });
 475
 476  main.views[".left"][1].views[".inner-left"].render(function(el) {
 477    equal(this, main.views[".left"][1].views[".inner-left"],
 478      "Nested View render callback context is View");
 479    start();
 480  }).then(function() {
 481    equal(this, main.views[".left"][1].views[".inner-left"],
 482      "Nested View render deferred context is View");
 483    start();
 484  });
 485});
 486
 487asyncTest("list items don't duplicate", 2, function() {
 488  var element;
 489
 490  var main = new Backbone.Layout({
 491    template: "#main"
 492  });
 493
 494  var view = main.setView(".right", new this.EventedListView({
 495    collection: new Backbone.Collection()
 496  }));
 497
 498  view.collection.reset([ { text: 5 } ]);
 499
 500  main.render().then(function() {
 501    view.collection.reset([ { text: 5 } ]);
 502  });
 503
 504  view.collection.reset([ { text: 5 } ]);
 505
 506  window.setTimeout(function() {
 507    view.collection.reset([
 508      { text: 1 },
 509      { text: 2 },
 510      { text: 3 },
 511      { text: 4 }
 512    ]);
 513
 514    view.render().then(function() {
 515      equal(view.$("ul").children().length, 4, "Only four elements");
 516      equal(view.views.ul.length, 4, "Only four Views");
 517
 518      start();
 519    });
 520  }, 5);
 521});
 522
 523test("afterRender triggers for subViews", 1, function() {
 524  var triggered = false;
 525  var main = new Backbone.Layout({
 526    el: "#prefilled"
 527  });
 528
 529  main.setViews({
 530    ".test": new this.SubView({
 531      serialize: { text: "Here" },
 532
 533      afterRender: function() {
 534        triggered = true;
 535      }
 536    })
 537  });
 538
 539  main.render().then(function() {
 540    ok(triggered === true, "afterRender is called");
 541     
 542    start();
 543  });
 544});
 545
 546// Do this one without a custom render function as well.
 547test("view render can be attached inside initalize", 1, function() {
 548  var main = new Backbone.Layout({
 549    template: "#main"
 550  });
 551
 552  var TestRender = Backbone.View.extend({
 553    manage: true,
 554
 555    initialize: function() {
 556      this.model.on("change", this.render, this);
 557    },
 558
 559    beforeRender: function() {
 560      this.$el.html("This works now!");
 561    }
 562  });
 563
 564  var testModel = new Backbone.Model();
 565
 566  main.setView(".right", new TestRender({
 567    model: testModel
 568  }));
 569
 570  testModel.trigger("change");
 571
 572  main.render().then(function(el) {
 573    equal(this.$(".right").children().html(), "This works now!",
 574      "Content correctly set");
 575
 576    start();
 577  });
 578});
 579
 580test("Allow normal Views to co-exist with LM", 1, function() {
 581  var called = false;
 582  var View = Backbone.View.extend({
 583    render: function() {
 584      called = true;
 585    }
 586  });
 587
 588  var view = new View();
 589
 590  view.render();
 591
 592  ok(called, "Render methods work without being in LM");
 593});
 594
 595test("setView works going from append mode to normal", 1, function() {
 596  var main = new Backbone.Layout({
 597    template: "#main",
 598
 599    views: {
 600      ".left": [
 601        new this.View({ keep: true, msg: "Left 1" }),
 602        new this.View({
 603            msg: "Left 2",
 604            keep: true,
 605            views: {
 606              ".inner-left": new this.SubView({ lol: "hi" })
 607            }
 608        })
 609      ]
 610    }
 611  });
 612
 613  main.setView(".left", new this.View({ msg: "Right" }));
 614
 615  ok(true, "setView does not crash");
 616});
 617
 618test("setView and insertView not working after model change", function() {
 619  var setup = this;
 620
 621  var m = new Backbone.Model();
 622
 623  var View = Backbone.View.extend({
 624    manage: true,
 625
 626    initialize: function() {
 627      this.model.on("change", function() {
 628        this.render();
 629      }, this);
 630    },
 631
 632    beforeRender: function() {
 633      this.insertView(new setup.View({
 634        msg: "insert",
 635
 636        // Need keep true.
 637        keep: true
 638      }));
 639    }
 640  });
 641
 642  var view = new View({ model: m });
 643
 644  var layout = new Backbone.Layout({
 645    template: "#main",
 646
 647    views: {
 648      ".left": view
 649    }
 650  });
 651
 652  m.set("some", "change");
 653
 654  layout.render().then(function(el) {
 655    equal(this.$(".inner-left").length, 2, "rendered twice");
 656  });
 657});
 658
 659asyncTest("Ensure afterRender can access element's parent.", 1, function() {
 660  var view = new Backbone.LayoutView({
 661    template: "#main",
 662
 663    views: {
 664      ".left": new Backbone.LayoutView({
 665        afterRender: function() {
 666        
 667          var subView = this;
 668
 669          ok($.contains(view.el, subView.el),
 670            "Parent can be found in afterRender");
 671
 672          start();
 673        }
 674      })
 675    }
 676  });
 677
 678  view.render();
 679});
 680
 681// https://github.com/tbranyen/backbone.layoutmanager/issues/108
 682test("render callback vs deferred resolve when called twice", 1, function() {
 683  // Create a new View.
 684  var view = new Backbone.View();
 685
 686  // Set it up to work with LayoutManager.
 687  Backbone.LayoutManager.setupView(view);
 688
 689  // Two renders using callback style.
 690  view.render(function() {
 691    view.render(function() {
 692      ok(true, "Two render's using callback style work.");
 693    });
 694  });
 695});
 696
 697// https://github.com/tbranyen/backbone.layoutmanager/issues/115
 698test("Uncaught RangeError: Maximum call stack size exceeded", 1, function() {
 699  var View = Backbone.View.extend({
 700    manage: true
 701  });
 702
 703  new View({
 704    model: new Backbone.Model()
 705  }).render();
 706
 707  ok(true, "No call stack exceeded error");
 708});
 709
 710// https://github.com/tbranyen/backbone.layoutmanager/issues/117
 711asyncTest("Views getting appended in the wrong order", 3, function() {
 712  var View = Backbone.View.extend({
 713    manage: true,
 714
 715    template: "testing",
 716
 717    fetch: function(name) {
 718      var done = this.async();
 719
 720      setTimeout(function() {
 721        done( _.template(name));
 722      }, Math.random()*100);
 723    }
 724  });
 725
 726  var view = new View({
 727    views: {
 728      "": [ new View({ order: 1 }), new View({ order: 2 }) ]
 729    }
 730  });
 731
 732  view.render().then(function() {
 733    equal(this.views[""].length, 2, "There should be two views");
 734    equal(this.views[""][0].options.order, 1, "The first order should be 1");
 735    equal(this.views[""][1].options.order, 2, "The second order should be 2");
 736
 737    start();
 738  });
 739
 740});
 741
 742// https://github.com/tbranyen/backbone.layoutmanager/issues/116
 743test("Re-rendering of inserted views causes append at the end of the list", 1, function() {
 744  var ItemView = Backbone.LayoutView.extend({
 745    tagName: "tr",
 746
 747    template: "<%= msg %>",
 748
 749    fetch: function(name) {
 750      return _.template(name);
 751    },
 752
 753    serialize: function() {
 754      return { msg: this.options.msg };
 755    }
 756  });
 757
 758  var item1 = new ItemView({ msg: "hello" });
 759  var item2 = new ItemView({ msg: "goodbye" });
 760
 761  var list = new Backbone.LayoutView({
 762    template: "<tbody></tbody>",
 763
 764    fetch: function(name) {
 765      return _.template(name);
 766    },
 767    
 768    beforeRender: function() {
 769      this.insertView("tbody", item1);
 770      this.insertView("tbody", item2);
 771    }
 772  });
 773
 774  var main = new Backbone.Layout({
 775    tagName: "table"
 776  });
 777
 778  main.insertView(list);
 779
 780  main.render().then(function() {
 781    var parent = this;
 782    
 783    list.views.tbody[0].render().then(function() {
 784      equal(parent.$("tbody:first tr").html(), "hello", "Correct tbody order.");
 785    });
 786  });
 787});
 788
 789// https://github.com/tbranyen/backbone.layoutmanager/issues/118
 790test("events not correctly bound", 1, function() {
 791  var hit = false;
 792
 793  var m = new Backbone.Model();
 794
 795  var EventView = Backbone.LayoutView.extend({
 796    events: {
 797      click: "myFunc"
 798    },
 799
 800    myFunc: function() {
 801      hit = true;
 802    },
 803
 804    cleanup: function() {
 805      this.model.off(null, null, this);
 806    },
 807
 808    initialize: function() {
 809      this.model.on("change", this.render, this);
 810    }
 811  });
 812
 813  var Layout = Backbone.LayoutView.extend({
 814    template: "<p></p>",
 815
 816    fetch: function(name) {
 817      return _.template(name);
 818    },
 819
 820    beforeRender: function() {
 821      var eventView = this.insertView("p", new EventView({
 822        model: m
 823      }));
 824    }
 825  });
 826
 827  var view = new Layout();
 828
 829  view.$el.appendTo("#container");
 830
 831  view.render().then(function() {
 832    view.views.p[0].$el.click();
 833
 834    ok(hit, "Event was fired");
 835  });
 836
 837});
 838
 839// https://github.com/tbranyen/backbone.layoutmanager/issues/122
 840test("afterRender() not called on item added with insertView()", 2, function() {
 841  var hitAfter = 0;
 842  var hitBefore = 0;
 843
 844  var m = new Backbone.Model();
 845
 846  var Item = Backbone.LayoutView.extend({
 847    template: "",
 848
 849    fetch: function(path) {
 850      return _.template(path);
 851    },
 852
 853    tagName: "tr",
 854
 855    beforeRender: function() {
 856      hitBefore = hitBefore + 1;
 857    },
 858
 859    afterRender: function() {
 860      hitAfter = hitAfter + 1;
 861    },
 862    
 863    cleanup: function() {
 864      this.model.off(null, null, this);
 865    },
 866
 867    initialize: function() {
 868      this.model.on("change", this.render, this);
 869    }
 870  });
 871
 872  var List = Backbone.LayoutView.extend({
 873    template: "<tbody></tbody>",
 874
 875    fetch: function(path) {
 876      return _.template(path);
 877    },
 878
 879    beforeRender: function() {
 880      // Pass the model through.
 881      this.insertView("tbody", new Item({ model: m }));
 882    }
 883  });
 884
 885  var list = new List({ model: m });
 886
 887  list.render().then(function() {
 888    m.set("something", "changed");
 889    equal(hitBefore, 2, "beforeRender hit twice");
 890    equal(hitAfter, 2, "afterRender hit twice");
 891  });
 892});
 893
 894// https://github.com/tbranyen/backbone.layoutmanager/issues/126
 895test("render works when called late", 1, function() {
 896  var hit = false;
 897  var A = Backbone.Model.extend({});
 898  var ACollection = Backbone.Collection.extend({ model: A });
 899  var View = Backbone.LayoutView.extend({
 900    template: "<div>Click Here</div>",
 901    className: "hitMe",
 902
 903    fetch: function(path) {
 904      return _.template(path);
 905    },
 906
 907    events: {
 908      click: "onClick"
 909    },
 910      
 911    initialize: function() {
 912      this.collection.on("reset", function() {
 913        this.render();
 914      }, this);
 915    },
 916    
 917    onClick: function() {
 918      hit = true;
 919    }
 920  });
 921          
 922  var collection = new ACollection([]);
 923  var layout = new Backbone.Layout({
 924      template: "<div class='button'></div>",
 925
 926      fetch: function(path) {
 927        return _.template(path);
 928      },
 929      
 930      views: {
 931        ".button": new View({ collection: collection })
 932      }
 933
 934  });
 935
 936  layout.render();
 937  collection.reset([]);
 938
 939  // Simulate click.
 940  layout.$(".hitMe").click();
 941
 942  ok(hit, "render works as expected when called late");
 943});
 944
 945// https://github.com/tbranyen/backbone.layoutmanager/issues/126
 946test("render works when assigned early", 1, function() {
 947  var hit = false;
 948  var A = Backbone.Model.extend({});
 949  var ACollection = Backbone.Collection.extend({ model: A });
 950  var View = Backbone.LayoutView.extend({
 951    template: "<div>Click Here</div>",
 952    className: "hitMe",
 953
 954    fetch: function(path) {
 955      return _.template(path);
 956    },
 957
 958    events: {
 959      click: "onClick"
 960    },
 961      
 962    initialize: function() {
 963      this.collection.on("reset", this.render, this);
 964    },
 965    
 966    onClick: function() {
 967      hit = true;
 968    }
 969  });
 970          
 971  var collection = new ACollection([]);
 972  var layout = new Backbone.Layout({
 973      template: "<div class='button'></div>",
 974
 975      fetch: function(path) {
 976        return _.template(path);
 977      },
 978      
 979      views: {
 980        ".button": new View({ collection: collection })
 981      }
 982
 983  });
 984
 985  layout.render();
 986
 987  collection.reset([]);
 988
 989  // Simulate click.
 990  layout.$(".hitMe").click();
 991
 992  ok(hit, "render works as expected when assigned early");
 993});
 994
 995test("Render doesn't work inside insertView", 1, function() {
 996  var V = Backbone.LayoutView.extend({
 997    template: "<p class='inner'><%= lol %></p>",
 998    fetch: function(path) { return _.template(path); }
 999  });
1000
1001  var n = new Backbone.LayoutView({
1002    template: "<p></p>",
1003    fetch: function(path) { return _.template(path); }
1004  });
1005
1006  n.render();
1007  n.insertView("p", new V({ serialize: { lol: "hi" } })).render();
1008
1009  equal(n.$("p.inner").html(), "hi", "Render works with insertView");
1010});
1011
1012// https://github.com/tbranyen/backbone.layoutmanager/issues/134
1013test("Ensure events are copied over properly", 1, function() {
1014  var hit = false;
1015  var layout = new Backbone.Layout({
1016    template: "<p></p>",
1017    fetch: function(path) { return _.template(path); },
1018
1019    events: {
1020      "click p": "test"
1021    },
1022
1023    test: function(ev) {
1024      hit = true;
1025    }
1026  });
1027
1028  layout.render();
1029
1030  layout.$("p").click();
1031
1032  ok(hit, "Events were bound and triggered correctly");
1033});
1034
1035// https://github.com/tbranyen/backbone.layoutmanager/issues/131
1036test("Ensure global paths are adhered to", 1, function() {
1037    Backbone.LayoutManager.configure({
1038      paths: {
1039        template: "test/"
1040      }
1041    });
1042
1043    var t = new Backbone.LayoutView({
1044      template: "here"
1045    });
1046
1047    equal(t.__manager__.prefix, "test/", "Prefix properly hooked up");
1048
1049    Backbone.LayoutManager.configure({
1050      paths: {}
1051    });
1052});
1053
1054// https://github.com/tbranyen/backbone.layoutmanager/issues/137
1055test("afterRender not firing", 1, function() {
1056  var hit = false;
1057  var l = new Backbone.Layout({
1058    template: "<p></p>",
1059    fetch: function(path) { return _.template(path); }
1060  });
1061
1062  l.render();
1063
1064  var V = Backbone.LayoutView.extend({
1065    template: "<span>hey</span>",
1066    fetch: function(path) { return _.template(path); },
1067
1068    afterRender: function() {
1069      hit = true;
1070    }
1071  });
1072
1073  l.setView("p", new V()).render();
1074
1075  ok(hit, "afterRender was hit successfully");
1076});
1077
1078// https://github.com/tbranyen/backbone.layoutmanager/issues/134
1079// https://github.com/tbranyen/backbone.layoutmanager/issues/139
1080asyncTest("events are bound correctly", 1, function() {
1081  var hit = 0;
1082
1083  var l = new Backbone.Layout({
1084    template: "<p></p>",
1085    fetch: function(path) { return _.template(path); }
1086  });
1087
1088  l.render();
1089
1090  var V = Backbone.LayoutView.extend({
1091    keep: true,
1092    template: "<span>hey</span>",
1093    fetch: function(path) { return _.template(path); },
1094
1095    events: {
1096      click: "hit"
1097    },
1098
1099    hit: function(ev) {
1100      hit++;
1101    }
1102  });
1103
1104  // Insert two views.
1105  l.insertView("p", new V());
1106  l.insertView("p", new V());
1107
1108  // Render twice.
1109  l.render();
1110  l.render().then(function() {
1111    l.$("p div").trigger("click");
1112
1113    equal(hit, 2, "Event handler is bound and fired correctly");
1114    start();
1115  });
1116});
1117
1118asyncTest("more events issues", 1, function() {
1119  var hit = 0;
1120
1121  var V = Backbone.LayoutView.extend({
1122    template: "<span>hey</span>",
1123    fetch: function(path) { return _.template(path); },
1124
1125    events: {
1126      click: "hit"
1127    },
1128
1129    hit: function(ev) {
1130      hit++;
1131    }
1132  });
1133
1134  var S = Backbone.LayoutView.extend({
1135    template: "<p></p>",
1136    fetch: function(path) { return _.template(path); },
1137
1138    beforeRender: function() {
1139      // Insert two views.
1140      this.insertView("p", new V());
1141      this.insertView("p", new V());
1142    },
1143
1144    reset: function() {
1145      this.render();
1146    }
1147  });
1148
1149  // Create a sub-layout.
1150  var s = new S();
1151
1152  // Create a main layout.
1153  var l = new Backbone.Layout({
1154    views: {
1155      "": s
1156    }
1157  });
1158
1159  // Render the layout.
1160  l.render();
1161
1162  // Re-render.
1163  s.reset();
1164
1165  l.$("p div").trigger("click");
1166
1167  equal(hit, 2, "Event handler is bound and fired correctly");
1168  start();
1169});