Unit testing Ember services that retrieve data

I have an ember service whose main task is to get data for a specific model and descendants of the model. The reason I use this in the service is because the route for this particular type uses a pool that is not a primary key, so store.find needs store.query instead of store.query . When we get this model, I have some logic that looks into the ember repository to see if we can load it from there before proceeding to the api request. This provider also monitors bullet changes and updates the current model based on this.

The problem I am facing is that it seems to have very little documentation when it comes to how to test such a thing. Actually, I don’t see the section on testing services anywhere in guides here http://guides.emberjs.com/v2.1.0/

This is a fragment of this service.

 import Ember from 'ember'; export default Ember.Service.extend({ _vendorSlug: null, vendor: null, vendorSlug: function (key, value) { if (arguments.length > 1) { if (this._vendorSlug) { return this._vendorSlug; } this._vendorSlug = value; } return this._vendorSlug; }.property(), ensureVendorLoaded: function (slug) { var service = this, vendorSlug = slug || service.get('vendorSlug'), currentVendor = service.get('vendor'), storedVendor; if (!Ember.isNone(currentVendor) && (vendorSlug === currentVendor.get('slug'))) { return new Ember.RSVP.Promise((resolve) => { resolve(currentVendor); }); } else { var storedVendors = service.store.peekAll('vendor').filter((vendor) => { return vendor.get('slug') === vendorSlug; }); if (storedVendors.length) { storedVendor = storedVendors[0]; } } if (!Ember.isNone(storedVendor)) { service.set('vendorSlug', storedVendor.get('slug')); return new Ember.RSVP.Promise((resolve) => { resolve(storedVendor); }); } return service.store.queryRecord('vendor', {slug: vendorSlug}).then((vendor) => { service.set('vendor', vendor); service.set('vendorSlug', vendor.get('slug')); return vendor; }); }, _vendorSlugChanged: function () { if (this.get("vendorSlug") === this.get("vendor.slug")) { return; } this.ensureVendorLoaded(); }.observes('vendorSlug') }); 

I would like to be able to approve several scenarios here with interaction with the store. The provider is already installed, the provider is loaded from the pry filter, and the provider is loaded from the request.

+5
source share
2 answers

I think I finally came to a reasonable conclusion. Let me share with you what, in my opinion, might be the best way to approach unit testing services that rely on the store.

The answer really lies in the assumption that we must make when writing unit tests . That is, everything that is outside of our logical unit should be considered correct, and our units must be completely independent.

Thus, when servicing a store, it is best to create a stub or mock (see this question to understand the difference between a layout and a stub) for a store. The stop for the store itself is quite simple. Something like this will do:

  store: { find: function() { var mockedModel = Ember.Object.create({/*empty*/}); return mockedModel; }, query: ... } 

If you prefer to use the layout instead, you can do something like the following (I did it very quickly so that it does not work completely, but it is enough to convey the idea):

 import Ember from 'ember'; class MockStore { constructor() { this.models = Ember.A([]); } createRecord(modelName, record) { // add a save method to the record record.save = () => { return new Ember.RSVP.Promise((resolve) => { resolve(true); }); }; if (!this.models[modelName]) { this.models[modelName] = Ember.A([]); } this.models[modelName].pushObject(record); return record; } query(modelName, query) { let self = this; return new Ember.RSVP.Promise((resolve) => { let model = self.models[modelName]; // find the models that match the query let results = model.filter((item) => { let result = true; for (let prop in query) { if (query.hasOwnProperty(prop)) { if (!item[prop]) { result = false; } else if (query[prop] !== item[prop]) { result = false; } } } return result; }); resolve(results); }); } } export default MockStore; 

Further, all you need to do is set the repository property (or any other access to it) to your service in a new instance of the mock store when you run the test. I did it like this:

 import Ember from 'ember'; import { moduleFor, test } from 'ember-qunit'; import MockStore from '../../helpers/mock-store'; let session; let store; const username = ''; const password = ''; moduleFor('service:authentication', 'Unit | Service | authentication', { beforeEach() { session = Ember.Object.create({}); store = new MockStore(); } }); test('it should authenticate the user', function (assert) { // this sets the store property of the service to the mock store let authService = this.subject({session: session, store: store}); authService.authenticate(username, password).then(() => { assert.ok(session.get('username')); }); }); 

The documentation for testing these situations is definitely unsatisfactory, so there may be a better method, but I'll work on that now. Also, if you look at the Discourse project that uses ember, they follow the same pattern described here, but in a slightly more advanced way.

+6
source

I'm not sure if this is the answer you want, but I will still give him a chance. The Ember Service is actually not much larger than the Ember object, and if you are "unit testing" this Service, it should be isolated from its dependencies (otherwise it will not be a unit test ).

From my understanding (and this may be wrong). If you want to test this service, you need to replace the repository with a mock version.

 //tests/unit/services/my-service.js test('some scenario', function(assert) { let service = this.subject({ store: Ember.Object.create({ peekAll(modelName){ //Return array for this scenario }, query(model, params){ //Return array for this scenario } }); }); assert.ok(service); }); 

I also think that is why there are small documentation testing services. One resource I recommend about services is talking from the Chicago Ember Meetup

+1
source

Source: https://habr.com/ru/post/1234803/


All Articles