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.
Related
I'm trying to write an acceptance test to see if a certain property in the model for the route I visit equals what I am asserting.
I am not outputting information to the page with this route, instead I will be saving some portion of it to localstorage using an ember addon. So normally I realize I could use a find() to find an element on the page and check it's content to determine if the model is being resolved but that won't work for this case.
In the acceptance test I have this setup (using mirage btw)
test('Returns a user', function(assert) {
// Generate a user
var user = server.create('user',{first_name: 'Jordan'});
// Visit the index page with the users short_url
visit('/' + user.short_url);
var route = this.application.__container__.lookup('route:index');
// Assert that the model the user we created by checking the first name we passed in
assert.equal(route.model.first_name,'Jordan','Model returns user with first name Jordan');
});
But when I run the test it shows the result as being undefined
UPDATE:
After trying Daniel Kmak's answer I still cannot get it to pass. This is the route code I am working with
import Ember from 'ember';
import LocalUser from 'bidr/models/user-local';
export default Ember.Route.extend({
localUser: LocalUser.create(),
navigationService: Ember.inject.service('navigation'),
activate() {
this.get('navigationService').set('navigationMenuItems', []);
},
beforeModel() {
this.localUser.clear();
},
model(params) {
var self = this;
return this.store.queryRecord('user',{short_url: params.short_url}).then(function(result){
if(result){
self.set('localUser.user', {
"id": result.get('id'),
"first_name": result.get('first_name'),
"active_auction": result.get('active_auction'),
"phone": result.get('phone')
});
// transition to event page
self.transitionTo('items');
} else {
self.transitionTo('home');
}
});
}
});
And the test looks like this
import Ember from 'ember';
import { module, test } from 'qunit';
import startApp from 'bidr/tests/helpers/start-app';
module('Acceptance | index route', {
beforeEach: function() {
this.application = startApp();
},
afterEach: function() {
Ember.run(this.application, 'destroy');
}
});
test('Returns a user', function(assert) {
var user = server.create('user',{first_name: 'Jordan'});
visit('/' + user.short_url);
var route = this.application.__container__.lookup('route:index');
andThen(function() {
assert.equal(route.get('currentModel.first_name'),'Jordan','Model returns user with first name Jordan');
});
});
All the code works as it should in development.
Ok, so I've experimented with testing in Ember and it seems you should be good with getting model in andThen hook:
test('returns a user', function(assert) {
visit('/'); // visit your route
var route = this.application.__container__.lookup('route:index'); // find your route where you have model function defined
andThen(function() {
console.log(route.get('currentModel')); // your model value is correct here
assert.equal(currentURL(), '/'); // make sure you've transitioned to correct route
});
});
Taking your code it should run just fine:
test('Returns a user', function(assert) {
var user = server.create('user',{first_name: 'Jordan'});
visit('/' + user.short_url);
var route = this.application.__container__.lookup('route:index');
andThen(function() {
assert.equal(route.get('currentModel.first_name'),'Jordan','Model returns user with first name Jordan');
});
});
Another thing to note is that you can access model via route.currentModel property.
For my model:
export default Ember.Route.extend({
model() {
return Ember.RSVP.hash({
simple: 'simpleValue',
promise: Ember.RSVP.resolve(5)
});
}
});
In andThen with console.log(route.get('currentModel')); I got:
Object {simple: "simpleValue", promise: 5}
Logged.
I have not been able to test React Router with context successfully. I am using
react 0.13.3
react-router 0.13.3
jest 0.3.0
node 0.10.33
and have tried these approaches:
https://labs.chie.do/jest-testing-with-react-router/
https://gist.github.com/alanrubin/da3f740308eb26b20e70
Is there a definitive example?
All links to the "super-secret guide" mentioned in this question (which does not use Jest) are now broken. When I was able to view that guide, it didn't provide any more information than the first link listed above.
Not sure if this is what you're looking for exactly, but I got around this by making a helper function that I use when writing jest tests for components that depend on router state.
//router-test-helper
var Router = require('react-router'),
Route = Router.Route,
TestLocation = require('react-router/lib/locations/TestLocation');
module.exports = function(React){
TestUtils = React.addons.TestUtils;
return {
getRouterComponent: function(targetComponent, mockProps) {
var component,
div = document.createElement('div'),
routes = [
React.createFactory(Route)({
name: '/',
handler: targetComponent
})
];
location = new TestLocation('/');
Router.run(routes, location, function (Handler) {
var mainComponent = React.render(React.createFactory(Handler)(mockProps), div);
component = TestUtils.findRenderedComponentWithType(mainComponent, targetComponent);
});
return component;
}
};
};
I didn't write all of this on my own, most of it I think I pulled from that now defunct guide you linked to. If I remember right... it's been a while.
After you have that you can use this in your tests kinda like this.
//test-example
jest.dontMock('../src/js/someComponent');
var React = require('react/addons');
var TestUtils = React.addons.TestUtils;
var routerHelper = require('../router-test-helper')(React);
var SomeComponent = require('../srcs/js/someComponent');
describe('Some Component', function(){
it('should be testable', function(){
var mockProps = {};
var renderedComponent = routerHelper.getRouterComponent(SomeComponent, mockProps);
// Test your component as usual from here.....
///////////////////////////////////////////////
var inputs = TestUtils.scryRenderedDOMComponentsWithTag(renderedComponent, 'input');
//blah blah blah
});
});
This assumes you have React and the helper in your unmocked module paths
If you're actually trying to test things specific to certain routes, or transitioning between routes... I'm not sure if this is a good approach. May be better to use something more intergration test-y, like selenium or something.. Also... this probably won't work once the 1.0 of react router comes out. But it may be even easier to test things thing 'The React Way'(tm) because all the routing stuff will be handled through props. At least that's the impression I get from the the little bit I've read into it.
To anyone who happens to stuck with this problem.
Here's the setup that I've ended up with for my context dependent components (stripped down for simplicity, of course):
// dontmock.config.js contains jest.dontMock('components/Breadcrumbs')
// to avoid issue with hoisting of import operators, which causes
// jest.dontMock() to be ignored
import dontmock from 'dontmock.config.js';
import React from "react";
import { Router, createMemoryHistory } from "react-router";
import TestUtils from "react-addons-test-utils";
import Breadcrumbs from "components/Breadcrumbs";
// Create history object to operate with in non-browser environment
const history = createMemoryHistory("/products/product/12");
// Setup routes configuration.
// JSX would also work, but this way it's more convenient to specify custom
// route properties (excludes, localized labels, etc..).
const routes = [{
path: "/",
component: React.createClass({
render() { return <div>{this.props.children}</div>; }
}),
childRoutes: [{
path: "products",
component: React.createClass({
render() { return <div>{this.props.children}</div>; }
}),
childRoutes: [{
path: "product/:id",
component: React.createClass({
// Render your component with contextual route props or anything else you need
// If you need to test different combinations of properties, then setup a separate route configuration.
render() { return <Breadcrumbs routes={this.props.routes} />; }
}),
childRoutes: []
}]
}]
}];
describe("Breadcrumbs component test suite:", () => {
beforeEach(function() {
// Render the entire route configuration with Breadcrumbs available on a specified route
this.component = TestUtils.renderIntoDocument(<Router routes={routes} history={history} />);
this.componentNode = ReactDOM.findDOMNode(this.component);
this.breadcrumbNode = ReactDOM.findDOMNode(this.component).querySelector(".breadcrumbs");
});
it("should be defined", function() {
expect(this.breadcrumbNode).toBeDefined();
});
/**
* Now test whatever you need to
*/
First, I made a small Ember app without Ember CLI.
I had this piece of code.
window.MyApp = Ember.Application.create({
ready: function() {
this.register('session:current', MyApp.SessionController, { singleton: true });
this.inject('controller', 'session', 'session:current');
}
});
This worked.
Then I decided to rewrite everything from scratch with Ember CLI.
I edited the file app/app.js and added the ready hook just like in my previous version.
var App = Ember.Application.extend({
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix,
Resolver: Resolver,
ready: function() {
this.register('session:current', App.SessionController, { singleton: true });
this.inject('controller', 'session', 'session:current');
}
});
This doesn't work.
The session controller does exist. That's the content of the file app/controllers/session.js
export default Ember.Controller.extend({
isLoggedIn: false,
});
The error message I get is
TypeError: Attempting to register an unknown factory: `session:current`
It appears in the browser.
I googled that message, but I found nothing about dependency injection in Ember CLI.
Any idea?
In ember-cli you can use ember generate service <name of service> and ember generate initializer <name of initializer> to build the stubs to achieve this, which is far better than fiddling about with app.js.
You create a service basically like this:
// app/services/notifications.js
import Ember from 'ember';
export default Ember.Object.extend({
initNotifications: function() {
// setup comes here
}.on('init'),
// Implementation snipped, not relevant to the answer.
});
And the initializer, which injects the service into the component(s) of your application which need it:
// app/initializers/notifications-service.js
import Notifications from '../services/notifications';
export default {
name: 'notification-service',
after: 'auth-service',
initialize: function( container, app ) {
app.register( 'notifications:main', Notifications, { singleton: true } );
app.inject( 'component:system-notifications', 'notificationService', 'service:notifications' );
app.inject( 'service:auth', 'notificationService', 'service:notifications' );
}
};
With that, it becomes available as notificationService on the components specified.
Documentation on the subject of dependency injection in Ember can be found at http://emberjs.com/guides/understanding-ember/dependency-injection-and-service-lookup/
I have these models in an ember-cli app:
var PuzzleRound = DS.Model.extend({
year: DS.attr('number')
});
var Puzzle = DS.Model.extend({
puzzleRounds: DS.hasMany('puzzleRound', {async: true})
});
And here's my test from tests/unit/models/puzzle-test.js:
import {
moduleForModel,
test
} from 'ember-qunit';
import PuzzleRound from 'weather-roulette/models/puzzle-round';
moduleForModel('puzzle', 'Puzzle', {
// Specify the other units that are required for this test.
needs: ['model:puzzleRound']
});
test('it exists', function() {
var model = this.subject();
// var store = this.store();
ok(!!model);
});
I get this error when running ember test:
Attempting to register an unknown factory: `model:puzzleRound`
I'm using ember-cli 0.1.1, Ember.js 1.7.0, Ember Data 1.0.0-beta.11. Does anyone have anything I can try to fix this?
I just tried out this code with ember-cli 0.0.44 and I got the same error that you did.
I renamed both references to the puzzleRound model path to puzzle-round and then your test passed for me. So:
DS.Model.extend({
puzzleRounds: DS.hasMany('puzzle-round', {async: true})
});
and
moduleForModel('puzzle', 'Puzzle', {
needs: ['model:puzzle-round']
});
I knew that the hyphenated style was preferred over the camelCase style, but I'm not sure when this became mandatory. This requirement may be specific to ember-cli or ember-qunit.
I was looking for a solution similar to this one for awhile, and did not see any mention of my solution so I thought I would post here anyways. It's quite simple really: make sure that the controller you're referencing is actually there.
// my-ember-application/tests/unit/controllers/index/bar-test.js
moduleFor('controller:index/bar', 'My Bar Test', {
beforeEach() { .. }
});
test('it exists', function (assert) {
assert.ok(true);
});
This code would reference a controller at this location:
my-ember-application/app/controllers/index/bar.js
I'm simply trying to write some tests to make sure logging in and out works, including everything that goes with it. Here's what I'm doing so far:
tests/integration/sessions-test.js
import Ember from "ember";
import { test } from 'ember-qunit';
import startApp from '../helpers/start-app';
var App;
module('Integrations: Sessions', {
setup: function() {
App = startApp();
},
teardown: function() {
Ember.run(App, App.destroy);
}
});
test('Unsuccessful Sign In', function() {
expect(3);
visit('/sign-in');
andThen(function() {
fillIn('input#email', 'test#user.com');
fillIn('input#password', 'bad_password');
click('input#submit');
andThen(function() {
equal(currentRouteName(), 'sign-in', 'Unsuccessfull sign in stays on the sign in page.');
ok($('input#email, input#password').hasClass('error'), 'Inputs have a class of "error."');
equal($('input#submit').prop('disabled'), false, 'Submit button is not disabled.');
});
});
});
test('Successful Sign In', function() {
expect(2);
visit('/sign-in');
andThen(function() {
fillIn('input#email', 'test#user.com');
fillIn('input#password', 'password');
click('input#submit');
andThen(function() {
equal(currentRouteName(), 'welcome', 'Successfull sign in redirects to welcome route.');
ok(find('.message').length, "Page contains a list of messages.");
});
});
});
And, here's a trimmed down version of the sign in logic behind the scenes:
app/controllers/sign-in.js
import Ember from 'ember';
export default Ember.Controller.extend({
needs: ['application'],
actions: {
signIn: function() {
var self = this;
var data = this.getProperties('email', 'password');
// Attempt to sign in and handle the response.
var promise = Ember.$.post('/v3/sessions', data);
promise.done(function(response) {
Ember.run(function() {
self.get('controllers.application').set('token', response.access_token);
self.transitionToRoute('welcome');
});
});
...
}
}
});
The "Unsuccessful Sign In" test works just fine. The "Successful Sign In" starts to work, then quits halfway through. It signs in, then redirects correctly. On the welcome page, when it makes a call to get the messages, the node server is responding with Error: Not enough or too many segments and a 500 status. What in the world does that mean and how can I fix it, assuming I don't have any control over the API?
Also, the API is written primarily using Koa and Passport, as far as I know.
Figured it out. Apparently, it was an authentication error, not that you'd ever be able to guess that by the error message.
In the sign in controller, there's a line where I was setting the token property of the application controller. The application controller had an observer to watch that property for changes, then setup the AJAX headers when it changed. Problem is, observes use Ember's run loop, which is disabled while testing.
To fix the issue, I set the AJAX headers there in the sign in controller, just before transitioning to the welcome route.