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!
Related
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?
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
How do I access the current model? I am aware of application.__container_.lookup but I understand this is a bit of a hack.
import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from 'myapp/tests/helpers/start-app';
let application;
module('Acceptance | booking/edit', {
beforeEach: function() {
application = startApp();
},
afterEach: function() {
Ember.run(application, 'destroy');
}
});
test('visiting /booking/edit', function(assert) {
visit('/booking/1');
//At this point I would like to access the model returned from the route model hook.
andThen(function() {
assert.equal(currentURL(), '/booking/1');
});
});
Sample Route excerpt.
this.route('booking', { path:'/booking' }, function() {
this.route('edit', { path:'/:booking_id' }, function() {
this.route('account', { path:'/account' });
...
});
...
});
You should be able to use moduleFor and then within the test you can use this.subject() to access the controller.
moduleFor('controller:bookingsEdit', 'Bookings Edit Controller');
If moduleFor is undefined. Then import moduleFor import {moduleFor} from 'ember-qunit';
and then within the test you can use this.subject() to access the controller
moduleFor(fullName [, description [, callbacks]])
fullName: (String) - The full name of the unit, ie
controller:application, route:index.
description: (String) optional - The description of the module
callbacks: (Object) optional - Normal QUnit callbacks (setup and
teardown), with addition to needs, which allows you specify the other
units the tests will need.
http://guides.emberjs.com/v1.10.0/testing/testing-controllers/
https://github.com/rwjblue/ember-qunit
I'm building an Ember CLI app (v0.2.3), and I have some unit tests that have been generated for me for the adapters and serializer in my app. The generated code looks like this:
// app/serializers/my-model-test.js
// Replace this with your real tests.
test('it serializes records', function (assert) {
var record = this.subject();
var serializedRecord = record.serialize();
assert.ok(serializedRecord);
});
and
// app/adapter/application-test.js
// Replace this with your real tests.
test('it exists', function (assert) {
var adapter = this.subject();
assert.ok(adapter);
});
What do I put in these tests? I've built acceptance tests and unit tests for my models and components, but not sure what needs to go in these unit tests. Haven't been able to find documentation on building these unit tests, nor can I find any example applications on GH that have built these tests out.
If you want to create unit tests for your adapters and serializers, you should look at how ember data tests those themself. Basically, you can look at the test for the RESTSerializer etc. and use their technique.
Example serializer: https://github.com/emberjs/data/tree/master/tests/integration/serializers
The code that ember data uses to achieve this: https://github.com/emberjs/data/blob/master/tests/helpers/store.js
I found it much easier to write an integration test for my custom serializer. I tried Steffans suggestion but I couldn't get it load anything other than the base JSONSerializer. The code I wrote that is working in Ember 1.13.8, Ember Data 1.13.15 is below.
import { moduleFor, test } from 'ember-qunit';
moduleFor('application', 'Integration | Serializer | application', {
integration: true
});
test('Serializer normalizes correctly for basic single object', function(assert) {
assert.expect(1);
let store = this.container.lookup('service:store');
var basicPeterJson = {
id: 1,
title: 'Mr',
firstName: 'Peter',
lastName: 'Parker'
};
var expectedHash = {
data: {
type: 'contact',
id: 1,
attributes: {
title: 'Mr',
firstName: 'Peter',
lastName: 'Parker'
},
relationships: {}
}
};
var contact = store.serializerFor('application').normalizeResponse(store, store.modelFor('contact'), basicPeterJson, 1);
assert.deepEqual(contact, expectedHash);
});
I placed this in tests/integration/serializers/my-serializer-test.js
Testing the adapter:
test('it has a url for creating a record', function (assert) {
const url = this.subject().urlForCreateRecord('person', { firstName: 'Bob' });
assert.equal(url, 'https://example.com/path/to/api');
});
Testing the serializer:
test('it serializes records', function (assert) {
const serialized = this.subject({
foo: 'bar',
}).serialize();
assert.equal(serialized.foo, 'bar');
});
For testing other serializer functions, I previously followed #Knightsy's integration test example and it worked for me. Many thanks! Then, I worked out that this can actually be simplified and unit tested (if you can call it that).
My test goes like this:
moduleForModel('person', 'Unit | Serializer | person', {
needs: ['serializer:person'],
});
test('testing', function (assert) {
const serializer = this.container.lookup('service:store').serializerFor('person');
const payload = {
id: 3,
};
const response = serializer.normalizeSingleResponse(null, null, payload, payload.id);
assert.equal(response.data.id, 3);
});
I am following a Dockyard Tutorial on using ember-cli with rails. This particular section is on basic integration testing. Unfortunately, it doesn't seem to be registering properly (at least I don't think so). The test should fail and say something along the lines of "Expected: 'Welcome to Boston Ember'"; rather, it says "should pass jshint" which it is and is therefore passing. Any idea what I am doing wrong?
tests/integration/landing-page-test.js
import Ember from 'ember';
import startApp from 'bostonember/tests/helpers/start-app';
var App;
module('Integration - Landing Page', {
setup: function() {
App = startApp();
},
teardown: function() {
Ember.run(App, 'destroy');
}
});
test('Should welcome me to Boston Ember', function() {
visit('/').then(function() {
equal(find('h2#title').text(), 'Welcome bloopde bloopasa to Boston Ember');
});
});
tests/helpers/start-app.js
/* global require */
var Application = require('bostonember/app')['default'];
var Router = require('bostonember/router')['default'];
import Ember from 'ember';
export default function startApp(attrs) {
var App;
var attributes = Ember.merge({
// useful Test defaults
rootElement: '#ember-testing',
LOG_ACTIVE_GENERATION:false,
LOG_VIEW_LOOKUPS: false
}, attrs); // but you can override;
Router.reopen({
location: 'none'
});
Ember.run(function(){
App = Application.create(attributes);
App.setupForTesting();
App.injectTestHelpers();
});
App.reset(); // this shouldn't be needed, i want to be able to "start an app at a specific URL"
return App;
}
Will provide additional info upon request. Thank you!
Must have just been a hiccup?
Solution was to recreate the file, same code, but works now.