Инициализатор экземпляра unit test выходит из строя с "store is undefined"

После создания примера приложения:

ember new preloadtest
cd preloadtest/
ember g instance-initializer preload
ember g model test-data
ember g route index
ember g adapter application

Со следующими файлами:

Модели/тест-data.js

import DS from 'ember-data';

export default DS.Model.extend({
  name: DS.attr('string'),
  value: DS.attr( 'number' )
});

маршруты /index.js

import Ember from 'ember';

export default Ember.Route.extend({
  model(){
    return this.store.peekAll( 'test-data' );
  }
});

экземпляр-инициализаторы/preload.js

export function initialize( appInstance ) {
  let store = appInstance.lookup( 'service:store' );
  store.pushPayload( { "testDatas": [
    { "id": 1, "name": "aaa", "value": 1},
    { "id": 2, "name": "bbb", "value": 2},
    { "id": 3, "name": "ccc", "value": 3}
  ] } );
}

export default {
  name: 'preload',
  initialize
};

Шаблоны /index.hbs

<ul>
{{#each model as |td|}}
  <li>{{td.name}}: {{td.value}}</li>
{{/each}}
</ul>

адаптеры /application.js

import RESTAdapter from 'ember-data/adapters/rest';

export default RESTAdapter.extend({});

ember serve запускает приложение и отображает данные предварительной загрузки, но переходит на /tests по умолчанию unit test для инициализатора экземпляра preload не работает с ошибкой store is undefined.

Полное сообщение об ошибке:

Died on test #1 @http://localhost:4200/assets/tests.js:212:1
[email protected]://localhost:4200/assets/vendor.js:94:20
[email protected]://localhost:4200/assets/vendor.js:142:5
[email protected]://localhost:4200/assets/vendor.js:193:5
[email protected]://localhost:4200/assets/vendor.js:181:12
[email protected]://localhost:4200/assets/test-loader.js:67:9
[email protected]://localhost:4200/assets/test-loader.js:58:13
[email protected]://localhost:4200/assets/test-loader.js:89:7
@http://localhost:4200/assets/test-support.js:6397:5
: store is [email protected] 114 ms
Source:     

[email protected]://localhost:4200/assets/preloadtest.js:213:5
@http://localhost:4200/assets/tests.js:213:1
[email protected]://localhost:4200/assets/test-support.js:2716:14
[email protected]://localhost:4200/assets/test-support.js:2701:4
run/<@http://localhost:4200/assets/test-support.js:2843:6
[email protected]://localhost:4200/assets/test-support.js:2502:4
[email protected]://localhost:4200/assets/test-support.js:2484:2
resumeProcessing/<@http://localhost:4200/assets/test-support.js:2544:4

Как инициализировать хранилище приложений, чтобы его можно было использовать в unit test?

Изменить - тесты /unit/instance -initializers/preload-test.js

import Ember from 'ember';
import { initialize } from 'preloadtest/instance-initializers/preload';
import { module, test } from 'qunit';
import destroyApp from '../../helpers/destroy-app';
//import DS from 'ember-data';

module('Unit | Instance Initializer | preload', {
  //needs: [ 'service:store' ],
  beforeEach: function() {
    Ember.run(() => {
      this.application = Ember.Application.create();
      this.appInstance = this.application.buildInstance();
    });
  },
  afterEach: function() {
    Ember.run(this.appInstance, 'destroy');
    destroyApp(this.application);
  }
});

// Replace this with your real tests.
test('it works', function(assert) {
  initialize(this.appInstance);

  // you would normally confirm the results of the initializer here
  assert.ok(true);
});

Пробовал это с помощью needs: [ 'service:store' ] и без (хотя предлагалось, что вы не должны делать этого, если Ember-Data находится на странице - что я также попытался импортировать как в unit test, так и в инициализатор экземпляра).

Версии

Ember      : 2.4.5
Ember Data : 2.5.2

Ответ 1

В Unit test инициализатора экземпляра вам не нужно получать реальный сервис store. В таких случаях предпочитайте использовать макетные услуги. Поведение вашего инициализатора экземпляра состоит в том, чтобы поместить некоторые данные в хранилище, которое предоставляется приложением. Вы можете легко имитировать этот магазин.

Пример тестового кода с макетным сервисом:

import Ember from 'ember';
import { initialize } from 'preloadtest/instance-initializers/preload';
import { module, test } from 'qunit';
import destroyApp from '../../helpers/destroy-app';

//this is the mock store service:
const storeStubFactory  = Ember.Service.extend({
  data: null,
  init(){
    this.data = [];
  },
  pushPayload(payload){
      this.get('data').pushObject(payload); 
  },
  getAllPayloads(){
      return this.get('data');
  }
});

module('Unit | Instance Initializer | preload', {
  beforeEach: function() {
    Ember.run(() => {
      this.application = Ember.Application.create();
      this.appInstance = this.application.buildInstance();
      //Register your mock service (do not  create instance, use factory)
      this.appInstance.register('service:store', storeStubFactory);
    });
  },
  afterEach: function() {
    Ember.run(this.appInstance, 'destroy');
    destroyApp(this.application);
  }
});

// This is your real test:
test('it works', function(assert) {
  initialize(this.appInstance);

  // confirm that mock service has the correct payload:      
  assert.ok(this.appInstance.lookup('service:store').getAllPayloads());
});

Второй вариант

Конечно, вы также можете макет appInstance paramater функции initialize, как показано ниже:

import Ember from 'ember';
import { initialize } from 'preloadtest/instance-initializers/preload';
import { module, test } from 'qunit';
import destroyApp from '../../helpers/destroy-app';

const storeStubFactory  = Ember.Service.extend({
  data: null,
  init(){
    this.data = [];
  },
  pushPayload(payload){
      this.get('data').pushObject(payload); 
  },
  getAllPayloads(){
      return this.get('data');
  }
});

module('Unit | Instance Initializer | preload');

// This is your real test:
test('it works', function(assert) {
  let instance = storeStubFactory.create();

  initialize({lookup:function(serviceName){return serviceName==='service:store' ? instance : null;}}); 

  // confirm that mock service has the correct payload:   
  assert.ok(instance.getAllPayloads());
});

Но я предпочитаю использовать первый. Мы заявили, что поведение ваших инициализаторов экземпляров помещает некоторые данные в хранилище, которые предоставляются приложением. Но во втором случае кажется, что мы также проверяем, что ваш инициализатор экземпляра вызывает функцию поиска appInstance. Этот тест более тесно связан с вашей реализацией.