【问题标题】:TypeError testing Backbone.js in CoffeeScript with Jasmine使用 Jasmine 在 CoffeeScript 中测试 Backbone.js 的 TypeError
【发布时间】:2011-11-22 12:53:33
【问题描述】:

我目前正在处理 PeepCode video on Backbone.js,但尝试用 CoffeeScript 而不是纯 JavaScript 编写它。

到目前为止一切顺利,除非我尝试对遇到一些 TypeErrors 的代码运行 Jasmine 测试:

TypeError: Cannot call method 'isFirstTrack' of undefined
TypeError: Cannot call method 'get' of undefined

我的 CoffeeScript/Backbone 文件如下所示:

jQuery ->
  class window.Album extends Backbone.Model
    isFirstTrack: (index) ->
    index is 0

  class window.AlbumView extends Backbone.View
    tagName:    'li'
    className:  'album'

    initialize: ->
      @model.bind('change', @render)
      @template = _.template $('#album-template').html()     
    render: =>
      renderedContent = @template @model.toJSON()
      $(@el).html(renderedContent)
      return this

还有这样的 Jasmine 测试规范:

var albumData = [{
  "title":  "Album A",
  "artist": "Artist A",
  "tracks": [
    {
        "title": "Track A",
        "url": "/music/Album A Track A.mp3"
    },
    {
        "title": "Track B",
        "url": "/music/Album A Track B.mp3"
    }]
}, {
  "title": "Album B",
  "artist": "Artist B",
  "tracks": [
    {
        "title": "Track A",
        "url": "/music/Album B Track A.mp3"
    },
    {
        "title": "Track B",
        "url": "/music/Album B Track B.mp3"
  }]
}];

describe("Album", function () {

  beforeEach(function () {
    album = new Album(albumData[0]);
  });

  it("creates from data", function () {
    expect(this.album.get('tracks').length).toEqual(2);
  });

  describe("first track", function() {
    it("identifies correct first track", function() {
      expect(this.album.isFirstTrack(0)).toBeTruthy();
    })
  });

});

我猜这个问题与 CoffeeScript 将所有内容包装在一个函数中有关。当我从等式中删除 jQuery 时,它工作正常。 奇怪的是,即使 Jasmine 告诉我TypeError: Cannot call method 'isFirstTrack' of undefined,如果我在页面上的控制台中运行album.isFirstTrack(0),它也会返回true,所以窗口确实可以访问变量和方法。

【问题讨论】:

  • 在挖掘了更多之后 - 我已经设法修复它。从 Jasmine 测试规范中的两个 expect 语句中删除 this 关键字似乎有效。仍然有兴趣了解为什么 - 这是范围问题吗?
  • 问题不在于 CoffeeScript 的函数包装器。通过将它们定义为 window.Albumwindow.AlbumView,您已经正确导出了两个类。

标签: javascript backbone.js coffeescript jasmine


【解决方案1】:

原因是范围,是的。

当您声明没有var 关键字的album 变量并且没有将其附加到另一个对象时,您将在全局范围内创建一个变量。

这是个坏主意。你真的想限制你创建的全局对象的数量,因为另一块 javascript 很容易覆盖你的数据,或者导致冲突等。

从这个角度来看,您在测试中调用this.model 的想法是正确的。问题是您需要将model 附加到this 才能做到这一点。很简单:

  beforeEach(function () {
    this.album = new Album(albumData[0]);
  });

您只需说this.album = ...,就完成了。现在您的测试将能够找到 this.album 并且一切正常。

【讨论】:

  • 对,album =this.album = 是不等价的(除非 thiswindow,当 Jasmine 调用 beforeEach 回调时情况并非如此)。
【解决方案2】:

注意:我相信 Derick 的回答是正确的——它解释了TypeError: Cannot call method 'isFirstTrack' of undefined 消息——但这个回答也可能是相关的。)

你说

当我从等式中删除 jQuery 时,它工作正常。

意思是如果你剪掉jQuery ->,那么你的测试就通过了?如果是这样,那不是范围问题;这是一个代码顺序问题。当您将一个函数传递给 jQuery 时,该函数在文档准备好之前不会执行。同时,您的测试会立即运行——在定义 AlbumAlbumView 类之前。

没有理由使用jQuery -> 包装器,因为您的类定义不依赖于任何现有的 DOM 元素。

【讨论】:

  • 很好的答案和很好的建议。除非在 jQuery 准备就绪时需要运行某些东西 jQuery -> 根本没有必要。
猜你喜欢
  • 2012-06-14
  • 2011-12-20
  • 1970-01-01
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 2020-11-20
相关资源
最近更新 更多