Stubbing out a service when testing ember component integration tests - ember.js

I'm looking at the ember testing guides and it says to do the following when you want to stub out a service
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import Ember from 'ember';
//Stub location service
const locationStub = Ember.Service.extend({
city: 'New York',
country: 'USA',
currentLocation: {
x: 1234,
y: 5678
},
getCurrentCity() {
return this.get('city');
},
getCurrentCountry() {
return this.get('country');
}
});
moduleForComponent('location-indicator', 'Integration | Component | location indicator', {
integration: true,
beforeEach: function () {
this.register('service:location-service', locationStub);
this.inject.service('location-service', { as: 'location' });
}
});
The issue is that I get a Uncaught TypeError: this.register is not a function when I use this code. So I am assuming the in the before each this.register('service:location-service', locationStub); is causing the problem.
Any one has any idea how I can work around this or what's the more proper way of stubbing out a service? This code is currently in Ember's docs.

Looks like this.register is only present on later versions of ember-qunit, you need to make sure you are running ember-qunit >= 0.4.13.
this.register is only present on ember-qunit >= 0.4.13.
http://discuss.emberjs.com/t/service-injection-in-component-integration-tests/8956/3

Related

Ember.js + Mirage: pulling a mocked relationship in integration test

I have a component that makes use of this.get('model.property'), and it works as intended.
For my integration tests I'm using Mirage, which has worked for all my other tests (integration tests included), however when I test this specific component I get:
TypeError: Cannot read property 'then' of undefined
This is what my test looks like:
import { moduleForComponent, test } from 'ember-qunit'
import hbs from 'htmlbars-inline-precompile'
import { startMirage } from 'app/initializers/ember-cli-mirage'
import Ember from 'ember'
moduleForComponent('summary-card', 'Integration | Component | summary card', {
integration: true,
beforeEach() {
this.server = startMirage()
},
afterEach() {
this.server.shutdown()
}
})
test('it renders', function(assert) {
const customer = this.server.create('customer')
const location = this.server.create('location', { customer })
const manufacturer = this.server.create('manufacturer')
const model = this.server.create('device-model', { manufacturer })
this.server.createList('device', 5, { model, customer, location })
const loc = Ember.Object.create(location)
this.set('model', loc)
this.render(hbs`{{summary-card model=model model-name=model.name tag='location' belongs-to='customer' has-many='device'}}`);
assert.equal(this.$('h1').text().trim(), 'Location 0', 'should be titled Location 0')
});
And basically, my summary-card.js has something like this:
this.get('model.' + belongs).then(relationship => {...})
where belongs is simply the value of whatever belongs-to is set to when the component is invoked.
I'm a bit puzzled, as it seems like the mock model I'm passing to my test isn't really representing the model in the same way it does when running ember s (I'm using Mirage for development purposes as well). Is there anywhere where I can find out more about what's exactly going on there?
Thank you!
P.S. I've also tried to use the location object as is provided by server.create(), and I get a slightly different error:
TypeError: _this.get(...).then is not a function
Well, by reading this answer, I managed to find my own solution, which works really well:
import { moduleForComponent, test } from 'ember-qunit'
import hbs from 'htmlbars-inline-precompile'
import Ember from 'ember'
moduleForComponent('summary-card', 'Integration | Component | summary card', {
integration: true
})
test('it renders', function(assert) {
this.inject.service('store', {as: 'store'})
let location
Ember.run(() => {
location = this.store.createRecord('location', {
id: 0,
name: 'Location 0',
customer: this.store.createRecord('customer', {
id: 1,
name: 'Customer 0'
}),
devices: [this.store.createRecord('device', {id: 1})]
})
})
this.set('model', location)
this.render(hbs`
{{#summary-card model=model model-name=model.name tag='location' belongs-to='customer' has-many='device'}}
<div class='test-content'>Test Content</div>
{{/summary-card}}
`)
Basically, I have opted for using the store directly, rather than using Mirage, and it works!

Switching from .findall() to .query() breaks integration testing

I have a component that calls something like:
this.get('store')
.findAll('calendar-event')
.then((data) => {
// do stuff
});
However, when I replace findAll() with query() it breaks my integration testing.
this.get('store')
.query('calendar-event', { some_stuff: [596] })
.then((data) => {
// do stuff
});
The application in the web browser via ember server continues to function correctly. However: no luck with integration testing. Error I get is: TypeError: Cannot read property 'setObjects' of null
Integration test looks like:
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import moment from 'moment';
import startMirage from '../../helpers/setup-mirage-for-integration';
moduleForComponent('main-calendar', 'Integration | Component | main calendar', {
integration: true,
beforeEach() {
startMirage(this.container);
},
afterEach() {
window.server.shutdown();
}
});
test('it renders', function (assert) {
this.render(hbs`{{main-calendar}}`);
assert.equal(this.$('.col-sm.text-center').text().trim(), moment().format('MMMM YYYY'));
});
Any ideas why it would render with the server but not on the integration testing side of things.

how to write a unit test for controller action with promises in emberjs

I have a ember js controller with the following action that takes a model.
How do I write a unit test to test the action which returns a promise?
deleteUser(model)
{
model.destroyRecord().then(() => this.transitionToRoute('posts'));
}
The wait() function sounds like what you want here. Not sure it works with promises, as it does not mention promises in this part of the documentation. Might want to give it a shot anyway.
From the Ember docs (https://guides.emberjs.com/v2.12.0/testing/testing-components/):
import { moduleForComponent, test } from 'ember-qunit';
import wait from 'ember-test-helpers/wait';
import hbs from 'htmlbars-inline-precompile';
moduleForComponent('delayed-typeahead', 'Integration | Component | delayed typeahead', {
integration: true
});
const stubResults = [
{ name: 'result 1' },
{ name: 'result 2' }
];
test('should render results after typing a term', function(assert) {
assert.expect(2);
this.set('results', []);
this.set('fetchResults', (value) => {
assert.equal(value, 'test', 'fetch closure action called with search value');
this.set('results', stubResults);
});
this.render(hbs`{{delayed-typeahead fetchResults=fetchResults results=results}}`);
this.$('input').val('test');
this.$('input').trigger('keyup');
return wait().then(() => {
assert.equal(this.$('.result').length, 2, 'two results rendered');
});
});
EDIT: The example above is from integration tests... not sure this is what you have in mind. Note, there is also the andThen helper which you may want to look into. Perhaps give us some more information regarding what you have in mind?

Ember mirage server is not defined in tests

I am trying to integrate ember-cli-mirage fixtures into some tests. I followed the documentation here: ember fixtures
Problem: The server is not defined. error message:
ReferenceError: server is not defined
model-test.js:
import { moduleForModel, test } from 'ember-qunit';
moduleForModel('network', 'Unit | Model | network', {
needs: []
});
test('it exists', function(assert) {
server.loadFixtures('networks'); //no defined
andThen(function() {
let net1 = networks.first();
});
assert.ok(true);
});
I have also verified that the config is set to true.
ENV['ember-cli-mirage'] = {
enabled: true
}
Mirage starts up in an initializer. Since initializers only run when a full Ember app boots up, by default the Mirage server is only available in an acceptance test.
To use Mirage in an integration or unit test, follow the docs on manually starting your Mirage server. Currently the docs say this:
To run your Mirage server during a unit or integration test, first create a helper:
// tests/helpers/start-mirage.js
import mirageInitializer from '../../initializers/ember-cli-mirage';
export default function startMirage(container) {
mirageInitializer.initialize(container);
}
Then, add the following to any test where you want Mirage to initialize:
// tests/integration/components/your-test.js
import startMirage from '../../../helpers/start-mirage';
moduleForComponent('your-component', 'Integration | Component | your component', {
integration: true,
setup: function() {
startMirage(this.container);
}
});

Could not find the "presence" validator with Ember Validations addon

I'm trying to use the Ember Validations addon and I can't get it working. In the Chrome console, I see: WARNING: Could not find the "presence" validator.
Here is my model:
import Ember from 'ember';
import DS from 'ember-data';
import EmberValidations from 'ember-validations';
export default DS.Model.extend(EmberValidations.Mixin, {
name: DS.attr('string'),
validations: {
name: {
presence: true
}
}
});
And here is the my test:
import Ember from 'ember';
import EmberValidations from 'ember-validations';
import { moduleForModel, test } from 'ember-qunit';
moduleForModel('person', 'Unit | Model | person', {
// Specify the other units that are required for this test.
needs: ['ember-validations#validator:local/presence'],
afterEach: function() {
window.sessionStorage.clear();
}
});
test('isValid should be false if name is not set', function(assert) {
stop();
var model = this.subject();
console.log(model);
Ember.run(function() {
sinon.spy(model, 'save');
model.validate().then(function() {
start();
assert.equal(model.get('isValid'), false);
});
});
});
The result of this test is:
Died on test #1 at Object.test (http://localhost:4200/assets/test-support.js:1644:11)
at http://localhost:4200/assets/myproj.js:14450:15
at mod.state (http://localhost:4200/assets/vendor.js:150:29)
at tryFinally (http://localhost:4200/assets/vendor.js:30:14)
at requireModule (http://localhost:4200/assets/vendor.js:148:5)
at Object.TestLoader.require (http://localhost:4200/assets/test-loader.js:29:9)
at Object.TestLoader.loadModules (http://localhost:4200/assets/test-loader.js:21:18): <(unknown mixin):ember848>
You need to add dependencies to test suite as defined in ember-validations docs in testing part. However, take notice that these docs are a little bit outdated. The proper needs should include only the validators you use (presence) and look like this:
needs: ['ember-validations#validator:local/presence']
Do not indclude service:validations.
I posted an issue quite a while ago but it's not discussed yet.