Ember Js testing a service with promises - ember.js

How to test a method inside a service that returns a store in Ember Unit Test using qunit
export default Ember.Service.extend({
store: Ember.inject.service(),
setSomeProps() {
this.get('store').find('somemodel', id)
.then((someData) => {
this.set('someProp', someDate.get('name'));
});
}
});
The setSomeProps is a method inside my service, I am fairly new to ember and cannot get my head around ember unit test. Whats the best way to write a unit test for this function

You can mock the store service in your unit test of store-caller-service.
You should use wait function for asynchronous test behaviour which is described here.
Take a look at this twiddle example

Related

Ember Test for parent route with method calls

I was brought in on the "back-end" of a project and asked to help write tests for an app. I am very new to Ember and need just a little help getting started. We are trying to provide unit test for the routes, so we can have a bit more molecular scope over the app, instead of acceptance test. I have looked at some tutorials and went through every possible scenario that I could think of. I just need a bit of jumpstart.
Here is the part of the route.js for this route.
down stream of this parent route, we have another nested route that shows a list of contacts and when a user clicks on a show button it calls "model" and returns that variable "rec" for the template and the url
export default Route.extend(ScrollTo, {
flashMessages: service(),
model: function(params) {
let rec= this.store.peekRecord('contact', params.contact_id);
return rec;
},
actions: {
saveContact: function() {
let model = this.currentRouteModel();
model
.save()
.then(() => {
//this.refresh();
//this.setModelHash();
this.flashMessages
.success(`Saved Contact: ${model.get('title')}`);
//this.transitionTo('contacts');
});
}
Here is pre-generated code for the test. I really haven't made any modifications, because I really didn't know where to start.
This app doesn't have a back-end, it's design is to take in information and provide a iso file based on whatever standard the user wants.
I am sure I need to provide some mock data for the test and send that to the method, but again I am not sure what Qunit parts I use.
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Route | contact/show', function(hooks) {
setupTest(hooks)
test('it exists', function(assert) {
var route = this.owner.lookup('route:contact/show');
assert.ok(route, 'contact.show route works');
});
});
I struggled with this as well when I first moved to frontend testing. With a few years experience I'm confident in saying you shouldn't unit test the route objects in this way. Instead the testing of an ember app should focus on two types of tests.
What ember calls integration tests (but are actually closer to UI unit tests)
Acceptance tests
Integration tests on components allow you to get into the smaller details and edge cases and they can be super valuable.
What I think you want in this case is actually an acceptance test.
If your testing experience is at all like mine it will feel like you're testing too many things at first, but these types of tests where the browser actually loads the entire application have the most value in hunting down bugs and are the most maintainable over time.

Possible to make a route transition inside of a service in Ember?

I'm using ember-cli 1.13.8 and I have a service that handles most of my logic. Right now I have a function that listens to whether certain things are true or false and then can make a route change based upon that. I'd rather not have to call that function from inside every route since I want it to happen on every route. Its goal is to determine whether the player won and every interaction in the game drives this.
Inside of my game service:
init() {
...
if(true) {
console.log("you've won!");
this.transitionTo("congratulations");
}
},
Of course, this fails because this isn't a route like Ember expects. I know I can call this method from inside of every route instead but I'm wondering if there is a better way to do this.
Thanks
Edit
So far I've tried importing in the App and then trying to extend the Router. This seems like a bad idea though.
You can use the routing service (which is a private API):
routing: Ember.inject.service('-routing'),
init() {
...
if(true) {
console.log("you've won!");
this.get("routing").transitionTo("congratulations");
}
},
As of Ember 2.15, there is a public router service for exactly this use case. Just add router: Ember.inject.service(), to your Ember class and call this.get('router').transitionTo(...);, easy!
Generally this is a bad idea, but in some cases it's easier than passing through route actions in 100 places (personal experience).
The better way to do this from anywhere is to look the router up on the container:
Ember.getOwner(this).lookup('router:main').transitionTo(...);
this has to be some container allocated Ember object, which includes components, services, and Ember Data models.
Note also that if this will be called a lot, you will want to store the router as a property. You can do this in the init hook:
init() {
this._super(...arguments);
this.set('router', Ember.getOwner(this).lookup('router:main'));
}
...
this.get('router').transitionTo(...);
Ember.getOwner(this) works in Ember 2.3+, prior to that you can use this.get('container') instead.
Ember 1.13:
Create another service called routing:
import Ember from 'ember';
export default Ember.Service.extend({
_router: null,
init() {
this._super();
this.set('_router', this.get('container').lookup('router:main'));
},
transitionTo() {
this.get('_router').transitionTo(...arguments);
}
});
Then you can:
routing: Ember.inject.service(),
goSomewhere() {
this.get('routing').transitionTo('index');
}

How do enable the format.js helpers in Ember Unit tests

I am using Ember with formatjs to internationalize my application, and ember-cli to build it all.
When I generate a component with
ember g component some-component
Ember also creates a test that checks that the component renders. However, if I use the intl-get helper from formatjs in the component template, the unit test fails.
So how can I register the custom helpers that formatjs creates for a unit test?
I first tried to add the intl-get helper:
moduleForComponent('some-component', {
needs: ['helper:intl-get']
});
However, this just fails inside intl-get when it tries to access "intl:main". I would like for the intl initializer to run, but I am not sure if there is even application setup. Or is it some way to just mock those methods using sinon?
My current workaround is to just delete the 'it renders' tests. But I would like for these tests to pass as well, so I can further test rendering later if I want.
Try:
moduleForComponent('some-component', {
integration: true
});

EmberJS: Unit testing a Component says common helpers like 'click' and 'andThen' are undefined

TLDR
I'm trying to unit test a very simple component. However, it appears some very common test helpers aren't being defined. This is something specific about unit-testing a component, as I'm using these in integration tests without issue.
Now just jump straight to the Questions at the end.
Details
The errors are generic:
click is not defined
andThen is not defined
Stack trace for context:
Died on test #4 at Object.test (http://localhost:7357/assets/test-support.js:110:11)
at http://localhost:7357/assets/skylab.js:14977:15
at mod.state (http://localhost:7357/assets/vendor.js:150:29)
at tryFinally (http://localhost:7357/assets/vendor.js:30:14)
at requireModule (http://localhost:7357/assets/vendor.js:148:5)
at Object.TestLoader.require (http://localhost:7357/assets/test-loader.js:29:9)
at Object.TestLoader.loadModules (http://localhost:7357/assets/test-loader.js:21:18): click is not defined
The component and the tests are very basic. The component:
import Ember from 'ember';
export default Ember.TextField.extend({
classNames: ['input-span']
});
The Test:
import Ember from 'ember';
import {
moduleForComponent,
test
} from 'ember-qunit';
moduleForComponent('custom-input');
test('focus on click', function(assert) {
assert.expect(1);
var component = this.subject();
this.render();
click('input')
assert.ok(component.$('input').is(':focus'));
});
Best Guess
My best guess is that these helpers work in the acceptance tests because the startApp helper creates the click and andThen helper functions. I don't have setup & teardown code in my moduleForComponent call, but it doesn't look like I should need it. And I don't want to test the whole app here -- just an isolated component.
Questions
Is there another way to inject these test helpers that I'm unaware of?
Am I writing these tests wrong? Should I never use click in a component test? Is the documentation simply outdated?
Should this be supported as-written, and is this a framework bug I should report?
acceptance level helpers currently depend on an app being spun up, as such they are not available for unit level tests. As those do not have an app.

Global teardown function in Jasmine.js

I´m testing a Rails 4 / ember.js application with Jasmine.
How do I reset Ember after each spec without writing the teardown into every spec file?
# Spec/javascript/support/spec_helper.js.coffee
App.ApplicationAdapter = DS.FixtureAdapter
App.setupForTesting()
App.injectTestHelpers()
# Reset Ember after each spec
# How do I tell jasmine to run a function after each spec?
# Metacode:
jasmine.afterEach ->
App.reset()
beforeEach/afterEach can be declared globally as well, just use
beforeEach(function() {
console.log('before');
});
or
afterEach(function() {
console.log('after');
});
Here's an example of global implementation (not Ember).
http://jsbin.com/pavokiru/1/edit
Personally I would use qunit with Ember, they've built so many helpers for use with qunit, it'd be a lot of work to make it work with jasmine, especially when it comes to asynchronous processes (which are many in Ember).