Вычисляемое свойство модульного теста Ember.js для модели с отношением hasMany приводит к ошибке TypeError.

Используя это:

DEBUG: -------------------------------
DEBUG: Ember      : 1.5.1
DEBUG: Ember Data : 1.0.0-beta.7.f87cba88
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery     : 1.10.2
DEBUG: -------------------------------

И тестирование с помощью Ember-qunit.

Итак, я пытаюсь написать модульный тест для вычисляемого свойства моей модели. Вычисляемое свойство зависит от данных отношения hasMany.

Итак, моя модель выглядит примерно так:

App.User = DS.Model.extend({
  name: DS.attr('string'),
  roles: DS.hasMany('role'),

  isInstructor: function(){
    return this.hasRole('instructor');
  }.property('roles'),

  hasRole: function(role_name){
    var roles = this.get('roles');
    if(!Ember.isEmpty(roles)){
      return roles.any(function(role){
        return role.get('name') === role_name;
      });
    }
    return false;
  }
});

И мой тест выглядит примерно так:

moduleForModel('user', 'Course Model', {
  needs: ['model:role']
});

test('isInstructor - user is an Instructor', function() {
  var user = this.subject({
    id: 1,
    name: 'Joe'
  });

  Ember.run(function(){
    user.set('roles.content', Ember.ArrayProxy.create({content: []}));
    var role = Ember.ObjectProxy.create({name: 'instructor'});
    user.get('roles.content').pushObject(role);
  });

  var value = user.get('isInstructor');
  equal(value, true, "expected true but was " + value);
});

Когда я пытаюсь pushObject, я получаю эту ошибку:

Uncaught TypeError: undefined is not a function ember-data.prod.js?body=1:4284

Строка в ember-data, на которую он ссылается, такова:

var inverse = childType.inverseFor(this.firstRecordName);

Теперь я пробовал пару разных вещей, и до сих пор не повезло.

Для начала я попытался создать все сразу:

var user = this.subject({
  id: 1,
  name: 'Joe',
  roles: Ember.ArrayProxy.create({content: [Ember.ObjectProxy.create({name: 'instructor' })]})
});

Но это не работает, как говорится:

Uncaught Error: Cannot set read-only property "roles" on object: <App.User:ember792:1>

Поэтому позже я попытался установить роли в цикле Ember.run:

user.set('roles',
  Ember.ArrayProxy.create({
    content: [
      Ember.ObjectProxy.create({
        name: 'instructor'
      })
    ]
  })
);

И это дает ту же ошибку только для чтения.

Поэтому я попытался установить содержимое одновременно с ролями:

user.set('roles.content',
  Ember.ArrayProxy.create({
    content: [
      Ember.Object.create({
        name: 'instructor'
      })
    ]
  })
);

И я получаю

Uncaught TypeError: undefined is not a function

Итак, теперь я перешел к коду, который я определил выше:

user.set('roles.content', Ember.ArrayProxy.create({content: []}));
var role = Ember.ObjectProxy.create({name: 'instructor'});
user.get('roles.content').pushObject(role);

И получаю TypeError. Я в растерянности. Я не уверен, что я делаю неправильно или есть ошибка.

У кого-нибудь умнее меня есть предложение?

Вот jsbin http://jsbin.com/bidus/1/

Спасибо!

** ОБНОВЛЕНИЕ 1 **

Глядя на то, что говорит kingpin2k в его ответе я посмотрел на свой исходный код Ember в своем приложении. Я использую rubygem ember-source, поэтому у меня почти тот же источник, что и у «отладочная» версия, которую использовал @kingpin2k. В версии ember-source есть некоторые дополнительные функции, но все тестовые хелперы остались.

Поэтому я начал смотреть на свой код. Возникающая ошибка связана с обратными отношениями.

var inverse = childType.inverseFor(this.firstRecordName);

И глядя на свой jsbin, я не смог добавить, что образец для подражания имеет belongsTo('user')

Вот неудачный jsbin http://jsbin.com/bidus/2/, использующий тот же ember источники, которые использовал @kingpin2k. Это терпит неудачу из-за этого отношения принадлежности к модели для подражания. Я понял, что этого не должно быть, поскольку мне не нужна роль, которая должна знать пользователя. Таким образом, я удалил эту связь, и теперь все зелено.

Теперь у меня есть проходящий jsbin http://jsbin.com/bidus/3/, который является то же самое, что сделал @kingpin2k.

Но по-прежнему возникает вопрос, почему это ownTo вызывает блевотину. Насколько я могу судить, там должно быть хорошо. Может, @kingpin2k прольешь на это больше света? Мне не нужно было добавлять инверсию к ролям модели, поскольку предполагается, что ember сможет понять это самостоятельно (и я пытался добавить это для забавы и хихиканья, но код все еще блюет). Я склонен думать, что в источнике данных ember есть ошибка.


person bfcoder    schedule 22.05.2014    source источник


Ответы (1)


Честно говоря, я думаю, что основная проблема, которую я вижу, заключается в том, что вы используете производственную версию ember, и в нее не входят помощники по тестированию или метод setupForTesting.

Отладочная версия Ember

http://jsbin.com/tuvoleqo/1/edit

Более чистая версия

test('isInstructor - user is an Instructor', function() {
  var user = this.subject({
    id: 1,
    name: 'Joe'
  });

  Ember.run(function(){
    user.get('roles').pushObject(Em.Object.create({name:'instructor'}));
  });

  var value = user.get('isInstructor');
  equal(value, true, "expected true but was " + value);
});

http://jsbin.com/tuvoleqo/2/edit

person Kingpin2k    schedule 22.05.2014
comment
@ kingpin2k Извините за наивный вопрос, но я действительно не понимаю, как создание произвольного объекта Ember проверяет роли пользователей. Это единственный способ выполнить этот тест? не лучше ли вместо этого создать объект «Роль»? или это не имеет значения - person Mawaheb; 05.06.2014
comment
Он не тестирует роли пользователей, он тестирует вычисляемое свойство isInstructor. Честно говоря, нам, вероятно, следовало бы также смоделировать метод hasRoles, это модульный тест, а не интеграционный тест. Все, что нас волнует, это то, что когда hasRoles возвращает true, isInstructor возвращает true, и наоборот. В отдельном модульном тесте он мог бы протестировать hasRoles. Само по себе тестирование Ember Data не является бессмысленным, но у него есть целый набор тестов, показывающих, как работают его внутренности (не говоря уже о том, что он без проблем, в конце концов, это бета-версия, но вы не меняете его код). - person Kingpin2k; 05.06.2014
comment
О, понятно, я спросил, потому что у меня похожая ситуация. Основываясь на его примере, скажем, у этой роли есть ability и age и вычисляемое свойство limitation, которое просто объединяет ability+' '+age, а у пользователя есть roleLimit вычисляемое свойство, которое объединяет свойство limitation, для меня, Это звучит как целочисленный тест, Но потерпите меня, В случае, если я хочу проверить это, Как мне это сделать! Ваш способ не сработает, мне нужно создать объект роли, верно? Что ж, делать это из теста qunit - это кошмар! Бесконечный поиск в Интернете, безуспешно - person Mawaheb; 09.06.2014
comment
Не могли бы вы создать вопрос и поместить в него код/тест? Мне трудно следить за этим, не глядя на код, не стесняйтесь размещать ссылку здесь, и я посмотрю на нее. - person Kingpin2k; 09.06.2014
comment
Большое спасибо за то, что выслушали и проявили терпение, я создал вопрос... Заранее спасибо - person Mawaheb; 09.06.2014