I'm trying to setup a mock server in for my Ember CLI (1.13.1) acceptance test with Ember CLI Mirage. I'm stuck on how to debug the setup and actually test the model data available in the view.
I tried adding a console log statement inside my mirage route:
this.get('/users', function(db){
console.log(db.users);
return db.users;
});
Which tells me that the mirage route is called and there should be three users present. But my test is still failing. How do I check what is in the store in my acceptance test or in my template?
tests/acceptance/users/index-test.js
/* jshint expr:true */
import {
describe,
it,
beforeEach,
afterEach
} from 'mocha';
import { expect } from 'chai';
import Ember from 'ember';
import startApp from 'tagged/tests/helpers/start-app';
describe('Acceptance: UsersIndex', function() {
var application;
var users;
beforeEach(function() {
application = startApp();
users = server.createList('user', 3);
});
afterEach(function() {
Ember.run(application, 'destroy');
});
it('can visit /users/index', function() {
visit('/users');
andThen(function() {
expect(currentPath()).to.equal('users.index');
});
});
it('lists the users', function(){
visit('/users');
andThen(function() {
users = server.createList('user', 3);
expect(find('.user').length).to.equal(3); // fails
});
});
});
AssertionError: expected 0 to equal 3
app/mirage/config.js
export default function() {
/*
Config (with defaults).
Note: these only affect routes defined *after* them!
*/
this.namespace = '/api/v1'; // make this `api`, for example, if your API is namespaced
// this.timing = 400; // delay for each request, automatically set to 0 during testing
this.get('/users');
}
// You can optionally export a config that is only loaded during tests
export function testConfig() {
this.timing = 1;
}
app/mirage/factories/user.js
import Mirage, {faker} from 'ember-cli-mirage';
export default Mirage.Factory.extend({
email: function(){ return faker.internet.email(); }
});
app/routes/users/index.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(){
return this.store.findAll('user');
}
});
app/templates/users/index.hbs
<h2>Users</h2>
<table>
<thead>
<tr>
<th>Actions</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{{#each model as |user|}}
<tr class="user">
<td class="actions">Show</td>
<td class="email">{{ user.email }}</td>
</tr>
{{/each}}
</tbody>
</table>
I usually start by looking in the Data tab of the Ember Inspector to see if any models were added to the store.
If you're on 1.13 you're probably using the JSON API adapter and will need to do just a bit more work in your mirage route handler, like returning the object under a data key with a type.
For example, it might look like this:
this.get('/users', function(db){
return {
data: db.users.map(u => ({
id: u.id,
type: u.type,
attributes: _.omit(u, ['id', 'type'])
}))
};
});
Note that your factories are only for seeding Mirage's db. So with the route above, you'd now be able to use a factory like the one you have defined in your question
// mirage/scenarios/default.js
export default function(server) {
server.createList('user', 10);
});
and then when you booted your app and it made a GET request to /users, the data should be returned and properly deserialized by Ember Data.
Related
I'm trying to create a helper for my test in order to simulate a model.
I'm receiving the follow error, though:
: makeInventoryObjects is not defined
My test helper:
// ../tests/helpers/make-inventory-objects.js
import Ember from 'ember';
export default Ember.Test.registerAsyncHelper('makeInventoryObjects', function() {
const inventoryObjects = [{'id': 1, 'name': 'test'}];
return inventoryObjects;
});
My start-app in helpers contains application.injectTestHelpers();
The test which is failing:
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
// I tried to import manually too and it did not work
// import makeInventoryObjects from '../../helpers/make-inventory-objects';
moduleForComponent('model-table', 'Integration | Component | model table', {
integration: true
});
test('it renders', function(assert) {
this.set('inventoryResult', makeInventoryObjects());
this.render(hbs`{{model-table inventoryResult}}`);
assert.equal(this.$().text().trim(), '');
});
Whenever I add the comment of the import, I get this error:
: _frontendTestsHelpersMakeInventoryObjects["default"] is not a function
The main reason what I've done was failing is because I was trying to initialize the helper within the startApp and that is done only for acceptance test, not integration test.
I had to rewrite my helper to:
// ../tests/helpers/make-inventory-objects.js
export default function makeInventoryObjects() {
const inventoryObjects = [{'id': 1, 'name': 'test'}];
return inventoryObjects;
});
and then import in my test with the commented line.
Also, as a side note I missed to add in my .jshintrc my test helper if I were doing acceptance test. So, it was wrong for acceptance test as well.
I'm new to ember js. I was trying to use dynamic segments in my ember project and it give me an error.I tried localhost/4200/profile/john in my browser to get the info of "john".I think it is complaining about api end point in server.js.. Please help me to find what i have done wrong.
error display in console:
GET localhost:4500/api/users/john 404 (Not Found)
These are my files;
router.js
Router.map(function() {
this.resource('profile', { path: '/profile/:username' });
});
model/user.js
import DS from 'ember-data';
export default DS.Model.extend({
docType:DS.attr('string'),
firstName:DS.attr('string'),
userName:DS.attr('string'),
password:DS.attr('string'),
lastName:DS.attr('string'),
mobileNo:DS.attr('string'),
landNo:DS.attr('string'),
address:DS.attr(
{
no:'string',
street:'string',
city:'string'
}
),
nicNo:DS.attr('string'),
created_at:DS.attr('date'),
updated_at:DS.attr('date')
});
route/profile.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params, transition) {
return this.get('store').find('user', params.username);
}
});
server.js
app.get('/api/users', function(req,res) {
UserModel.find({},function(err,docs) {
if(err) {
res.send({error:err});
}
else {
res.send({user:docs});
}
});
});
template/profile.hbs
<h2>Welcome user</h2>
{{#each item in model}}
{{item.userName}}
{{/each}}
You need to add an adapter to your application and tell it where your API is.
//app/adapters/application.js
import DS from 'ember-data';
export default DS.JSONAPIAdapter.extend({
namespace: 'api' //All requests will be made to api/*
});
Beware that the example I gave you is using the JSONAPI Adapter (Ember 2.0) but there's also a RESTAdapter, you have to choose the right one for you.
I'm using Ember Simple Auth and a service that gets injected into application controller to keep track of currently logged in user. I can use {{accountName}} for the currently logged in user in my application template by doing the following:
//controllers/applications.js
import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service(),
userFromSession: Ember.inject.service('session-user'),
accountName: Ember.computed('session.data.authenticated.userId', function(){
this.get('userFromSession.user').then((user)=>{
if (Ember.isEmpty(user.get('company'))) {
this.set('accountName', user.get('firstName') + ' ' + user.get('firstName'));
} else {
this.set('accountName', user.get('company.name'));
}
});
})
});
My session-user service looks like the following:
//services/session-user.js
import Ember from 'ember';
import DS from 'ember-data';
const { service } = Ember.inject;
export default Ember.Service.extend({
session: service('session'),
store: service(),
user: Ember.computed('session.data.authenticated.userId', function() {
const userId = this.get('session.data.authenticated.userId');
if (!Ember.isEmpty(userId)) {
return DS.PromiseObject.create({
promise: this.get('store').find('user', userId)
});
}
})
});
Now, a user has a company, and a company has opportunities. I would like to retrieve the company opportunities, based on the currently logged in user. How do I do this? In my opportunities route I have tried the following:
//routes/opportunities/index.js
import Ember from 'ember';
export default Ember.Route.extend({
sessionUser: Ember.inject.service('session-user'),
model: function(){
this.get('sessionUser.user').then((user)=>{
let companySlug = user.get('company.slug');
console.log(companySlug);
return this.store.findRecord('company', companySlug);
});
}
});
When using {{model.opportunities}} in my template, it just stays blank and looks like the promise never resolves. However, I can see the data populating in the Ember Inspector, as well as the expected output of my console logs. Further, when I do the following, it works fine:
//routes/opportunities/index.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(){
let companySlug = 'known-company-slug';
return this.store.findRecord('company', companySlug);
}
});
Which means that the problem lies with model not resolving/updating for some reason. What am I doing wrong here?
Okay so I was trying to get the company model when I already had access to it through the sessionUser service.
//routes/opportunities/index.js
import Ember from 'ember';
export default Ember.Route.extend({
sessionUser: Ember.inject.service('session-user'),
model: function(){
return this.get('sessionUser.user').then(user => user.get('company'));
}
});
So I have been setting up a auth manager through my ember for the past week a and finally got it working. However, I'm still getting a error when invalidating the user.
Nothing handled the action 'sessionInvalidationSucceeded'
Can't figure out what the best way to handle the error?
import Ember from 'ember';
import DS from 'ember-data';
export default Ember.Object.extend({
authenticate: function(controller, user) {
var app = this.container.lookup('controller:application');
var session = app.get('session').authenticate('simple-auth-authenticator:oauth2-password-grant', user);
session.then(function() {
console.log('Session Started');
controller.transitionToRoute('brands');
});
},
endSession: function() {
var app = this.container.lookup('controller:application');
var session = app.get('session').invalidate();
session.then(function() {
app.store = DS.Store.create();
console.log('Session Ended');
app.transitionToRoute('index');
app.store.destroy();
});
}
});
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
sessionEnded: function() {
this.authManagerService.endSession();
}
},
currentUser: function() {
return this.store.find('user', this.session.get('user_id');
}.property('#each.user')
});
You need to include the Simple Auth Route mixin on the route you are authenticating
import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin';
or handle the action in your initializer
Ember.Application.initializer({
name: 'authentication',
after: 'simple-auth',
initialize: function(container, application) {
var applicationRoute = container.lookup('route:application');
var session = container.lookup('simple-auth-session:main');
// handle the session events
session.on('sessionInvalidationSucceeded', function() {
applicationRoute.transitionTo('index');
});
}
});
Take a look at the api, it's really helpful
http://ember-simple-auth.com/ember-simple-auth-api-docs.html#SimpleAuth-ApplicationRouteMixin-sessionInvalidationSucceeded
i am using Ember CLI + Ember Data + Simple Auth. The authenticator is working fine. But when im am doing a Rest Call with Ember Data Rest Adapter this.store.findAll("user"); the authorize function in my custom authorizer don't gets called.
The Rest API Endpoint is on an other domain, so i added the url to the crossOriginWhitelist in my environment.js.
environment.js:
module.exports = function(environment) {
var ENV = {
// some configuration
};
ENV['simple-auth'] = {
crossOriginWhitelist: ['http://api.xxxx.com'],
authorizer: 'authorizer:xxxx',
routeAfterAuthentication: 'dashboard',
};
return ENV;
};
authorizer
import Ember from 'ember';
import Base from 'simple-auth/authorizers/base';
var XXXXAuthorizer = Base.extend({
authorize: function(jqXHR, requestOptions) {
// Some Code, gets not called, damn it :(
}
});
export default {
name: 'authorization',
before: 'simple-auth',
initialize: function(container) {
container.register('authorizer:xxxx', XXXXAuthorizer);
}
};
index.html
....
<script>
window.XXXXWebclientENV = {{ENV}};
window.ENV = window.MyAppENV;
window.EmberENV = window.XXXXWebclientENV.EmberENV;
</script>
<script>
window.XXXXWebclient = require('xxxx-webclient/app')['default'].create(XXXXWebclientENV.APP);
</script>
....
Thanks for help :)
I had a similar problem. For me it was the crossOriginWhitelist config.
I set it like this:
// config/environment.js
ENV['simple-auth'] = {
crossOriginWhitelist: ['*'] // <-- Make sure it's an array, not a string
};
to see if I could get it working (I could), then I could narrow it down to figure out exactly what URL I should use to enforce the restriction (port number and hostname etc).
Don't leave it like that though!
You should actually figure out what URL works for the whitelist, and use that.
I am facing the same issue. I have same setup but the authorize function is not being called. May be you can try by adding the port number in your crossOriginWhiteList url.
I am adding window.ENV = window.MyAppENV line in new initializer which runs before simple-auth. You have added that in index file and may be that is the reason why simple-auth is not able to read your configuration.
Does the other configuration routeAfterAuthentication: 'dashboard', works properly? If not then this might be the reason. Try adding new initializer like
export default {
name: 'simple-auth-config',
before: 'simple-auth',
initialize: function() {
window.ENV = window.MyAppNameENV;
}
};