I have a tasks-table component that uses 'current-user' service. I inject the service into the component as displayed below
import { inject as service } from '#ember/service';
export default Component.extend({
currentUser: service(),
showBatchAction: computed('currentUser.user.directRoles.#each.title', function() {
return this.get('currentUser.user.directRoles').toArray().some((role) => {
return (role.id == 13) || (role.id == 15)
});
}),
});
The code works fine however, the integration test fails.
Test:
module('Integration | Component | tasks-table export csv button', function(hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function() {
run(() => {
this.owner.unregister('service:current-user');
});
this.owner.register('serivce:current-user', Service.extend({
user: EmberObject.create({
first_name: 'Bob',
last_name: 'Newby',
role: 'client',
directRoles: {title: 'employee', id: 1}
})
}));
});
test('it renders', async function(assert) {
var component = this.subject({
authManager: stubMyService.create()
});
await render(hbs `{{tasks-table}}`);
assert.equal(this.$('.export-csv').text().trim(), 'Export as CSV');
});
});
The error I'm getting is: TypeError: undefined is not an object (evaluating 'this.get('currentUser.user.directRoles').toArray')
directRoles is not an array? How come you loop through (some method) over an object. By saying object.toArray() does not work.
Related
I'm writing my first question here sorry for any ambiguity.
I write an integration test for update-pw component which simple render update-pw and then fill input field with fillIn and then click save button which trigger the action savePW in update-pw.js. I only pass email(for whom we want to change password) and new password.
savePW() function further has a function call self.store.updateSingleUserPw(email, newPw) which is written in service store.js.
updateSingleUserPw(email, newPw) returns a promise after server process on API call. On basis of fulfillment or rejection of promise I show a modal.
I just want to make that promise fulfill or rejected in my test instead of server response for promise.
// integration/component/update-pw-test.js
import { module, test } from 'qunit';
import EmberObject from '#ember/object';
import { setupRenderingTest } from 'ember-qunit';
import { render, fillIn, click } from '#ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import Service from '#ember/service';
module('Integration | Component | update-pw', function(hooks) {
setupRenderingTest(hooks);
const store = Service.extend({
savePW() {
self.store.updateSingleUserPw(email, newPw, function() {
console.log('this is function overriding', email, newPw);
return true;
})
.then(function() {
// Reset controller fields
self.set('password', '');
self.set('updateModal', false);
swal({
title: 'Das hat geklappt',
type: 'success'
});
}, function() {
self.set('updateModal', false);
swal({
title: 'problems with setting new pw.',
type: 'error'
});
})
.finally(function() {
self.set('changingPassword', false);
});
}
});
test('it renders', async function(assert) {
this.application.register('service:store', store);
this.application.inject.service('store', { as: 'store' });
assert.expect(2);
this.set('updateModal', true);
this.set('testing', true);
let currentUpdateAdmin = EmberObject.create({
username: 'steinauer',
email: 'lala#test.at'
});
this.set('currentUpdateAdmin', currentUpdateAdmin);
await render(hbs`{{update-pw updateModal=updateModal currentUpdateAdmin=currentUpdateAdmin testing=testing store=store}}`);
assert.equal(this.element.querySelector('h4').textContent.trim(), 'set new PW for steinauer');
await fillIn('#password', 'test123456');
await click('.save-button');
// Template block usage:
await render(hbs`
{{#update-pw}}
template block text
{{/update-pw}}
`);
// assert.equal(this.element.textContent.trim(), 'what is this');
});
});
// components/update-pw.js
import Component from '#ember/component';
export default Component.extend({
changingPassword: false,
actions: {
savePW() {
let self = this;
if (!self.get('currentUpdateAdmin.email'))
return;
let newPw = self.get('password');
let email = self.get('currentUpdateAdmin.email');
self.set('changingPassword', true);
if (!email)
return;
self.store.updateSingleUserPw(email, newPw)
.then(function() {
// Reset controller fields
self.set('password', '');
self.set('updateModal', false);
swal({
title: 'Das hat geklappt',
type: 'success'
});
}, function() {
self.set('updateModal', false);
swal({
title: 'problems with setting new pw',
type: 'error'
});
})
.finally(function() {
self.set('changingPassword', false);
});
}
}
});
function in Service/store.js :
updateSingleUserPw(email, newPw) {
let headers = this.get('headers');
return new Promise(function(resolve, reject) {
$.ajax({
type: 'POST',
url: ENV.api + '/accounts/updateSingleUserPw',
data: {
email: email,
pwNew: newPw
},
headers,
dataType: 'json'
}).then(function(success) {
if (success) {
resolve(newPw);
} else {
reject('password change failed');
}
}, function(xhr, status, error) {
reject(error);
});
});
}
Before trying to override function I got only rejected promise modal but after the try of overriding the function i'm getting:
Promise rejected during "it renders": Cannot read property register of undefined.
thanks for your question 🎉
Firstly can I thank you for providing your code samples, I would not have been able to solve your question had you not provided so much! I have actually simplified some of the things that you are trying to do and I think by simplifying things I have come to the solution.
Firstly I have renamed the Service that you keep using to be called password-store. Usually when an Ember developer sees a Service named store they tend to think of an ember-data store which I'm assuming you're not actually using here by the functionality that you are expecting.
I generated a very simple mock store that just had one function in it:
// app/services/password-store.js
import Service from '#ember/service';
export default Service.extend({
updateSingleUserPw(email, password) {
// TODO: do something with email & password
return Promise.resolve();
}
});
This just returns a promise so that it won't break any of the other code samples. I then updated your update-pw component to use the new password store:
// app/components/update-pw.js
import Component from '#ember/component';
import { inject as service } from '#ember/service';
function swal() {
// noop - not sure where this comes from
}
export default Component.extend({
passwordStore: service(),
changingPassword: false,
actions: {
savePW() {
if (!this.get('currentUpdateAdmin.email'))
return;
let newPw = this.get('password');
let email = this.get('currentUpdateAdmin.email');
this.set('changingPassword', true);
if (!email)
return;
this.passwordStore.updateSingleUserPw(email, newPw)
.then(() => {
// Reset controller fields
this.set('password', '');
this.set('updateModal', false);
swal({
title: 'Das hat geklappt',
type: 'success'
});
}, () => {
this.set('updateModal', false);
swal({
title: 'problems with setting new pw',
type: 'error'
});
})
.finally(() => {
this.set('changingPassword', false);
});
}
}
});
I also added a swal() function because I didn't quite know where that came from in your example. It seemed to be missing so I just ignored it.
Now lastly I have setup a template so that the test will actually pass:
// app/templates/components/update-pw.hbs
<h4>set new PW for steinauer</h4>
{{input id="password" value=password}}
<button type="button" name="button" class="save-button" {{action 'savePW'}}></button>
Now with the application fully setup here is the full example of a test that will do exactly what you were hoping to do:
// tests/integration/components/update-pw-test.js
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, fillIn, click } from '#ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
import StoreService from 'your-app-name/services/password-store';
module('Integration | Component | update-pw', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
const passwordStore = StoreService.extend({
updateSingleUserPw(email, newPw) {
console.log('updateSingleUserPw override!!');
assert.equal(newPw, 'test123456');
return Promise.resolve();
}
});
this.owner.register('service:password-store', passwordStore);
assert.expect(2);
this.set('updateModal', true);
this.set('testing', true);
let currentUpdateAdmin = {
username: 'steinauer',
email: 'lala#test.at'
};
this.set('currentUpdateAdmin', currentUpdateAdmin);
await render(hbs`{{update-pw updateModal=updateModal currentUpdateAdmin=currentUpdateAdmin testing=testing store=store}}`);
assert.equal(this.element.querySelector('h4').textContent.trim(), 'set new PW for steinauer');
await fillIn('#password', 'test123456');
await click('.save-button');
// Template block usage:
await render(hbs`
{{#update-pw}}
template block text
{{/update-pw}}
`);
});
});
The first thing that you might notice is that we are not using this.application.register or this.application.inject. I can't remember exactly if this is how it used to be done a long time ago but this is not available for a few years in Ember.
What we end up doing is we import the StoreService from your-app-name/services/password-store (replacing your-app-name with whatever your modulePrefix is) and then we extend it while overriding the updateSingleUserPw() function. In your example it looked like you were trying to override a function called savePW() but that is actually the action name from the component and it might have been slightly confusing you.
I hope that helps, I have tested the example locally and it works perfectly well! You may also notice I added an assertion inside the service, this is quite a useful pattern to make sure that the service receives the right arguments from the component 👍
Ember serializer test below is failing with “Cannot read property ‘push’ of null”.
I am using Pretender mock server library. The test is failing when I'm calling a store.findRecord()
Note how there are no relationships in the assignment model/serializer, which is why it's confusing that it's throwing the following error:
Click here to see the error that's getting returned
assignment serializer:
import DS from 'ember-data';
const { JSONAPISerializer } = DS;
export default JSONAPISerializer.extend({
attrs: {
autoPassReviewerNote: 'autoPassReviewerNote',
dateOfCreation: 'date_of_creation',
displayType: 'displayType',
lastUpdate: 'last_update',
moduleItem: 'moduleItem',
submissionType: 'submissionType'
}
});
assignment model:
import DS from 'ember-data';
const {
Model,
attr
} = DS;
export default Model.extend({
title: attr('string'),
submissionType: attr('string'),
description: attr('string'),
completed: attr('boolean'),
displayType: attr('string'),
dateOfCreation: attr('string'),
lastUpdate: attr('string'),
autopass: attr('boolean'),
moduleItem: attr('object')
});
serializer test (which is failing):
import { moduleForModel, test } from 'ember-qunit';
import Pretender from 'pretender';
import Ember from 'ember';
const {
run
} = Ember;
var server;
moduleForModel('assignment', 'Unit | Serializer | assignment', {
needs: [
'serializer:assignment'
],
beforeEach: function() {
server = new Pretender(function() {
// eslint-disable-next-line ember/use-ember-get-and-set
this.get('/assignments/:id', function() {
data: {
type: 'assignment',
id: 98,
attributes: {
title: 'dfgdfg',
submissionType: 'dfgdf',
displayType: 'dfgdfg',
date_of_creation: 'sdfgsdfg',
last_update: 'fgdgd'
}
}
};
return [ 200, { 'Content-Type': 'application/json' }, JSON.stringify(response) ];
});
});
},
afterEach: function() {
server.shutdown();
}
});
test('testing assignment serializer', function(assert) {
var checkAttrSerialization = (assignment) => {
assert.equal(assignment, true);
}
let store = this.store();
run(() => {
return store.findRecord('assignment', 98).then((assignment) => checkAttrSerialization(assignment));
});
});
I've went over a lot of examples both here on SO and in some guides/blogs. Nothing seems to work.
I have a customer that hasMany loads
currently the code is:
route
export default Ember.Route.extend({
setupController: function(controller, model) {
controller.setProperties(model);
},
model: function() {
return Ember.RSVP.hash({
content: this.store.createRecord('truck-load'),
customerList: this.store.findAll('customer'),
equipmentList: this.store.findAll('equipment-list')
});
},
resetController(controller, isExisting) {
if (isExisting) {
var model = controller.get('model');
if (model.get('isNew')) {
model.destroyRecord();
}
}
}
});
select box in the template - materialize add on for ember-cli
{{md-select content=customerList
value=model.customer
label="Customer"
prompt="Please Choose a Customer..."
optionLabelPath='content.name'
optionValuePath='content.id'}}
Current controller - I've tried this many ways
export default Ember.Controller.extend({
actions: {
save() {
var truckload = this.get('model');
this.get('model.customer').then((customer) => {
truckload.set('customer', customer);
truckload.save().then((load) => {
this.get('notify').success('Truck Load Created');
this.transitionToRoute('truck-loads.show', load.id);
});
});
JSON for my JSON-API server running Elixir/Phoenix
Parameters: %{"data" => %{"attributes" => %{"pro_number" => "423432", "special" => nil, "status" => nil},
"relationships" => %{"customer" => %{"data" => nil},
"equipment_list" => %{"data" => nil}}} }
customer (and equipment-list) are both coming over nil.
This fixed it.
1) Settings the drop down result as a controller property
2) Accessing this to lookup the model and set it.
selectedCustomer: null,
selectedEquipment: null,
actions: {
save() {
var truckload = this.get('model');
var customer_id = this.get('selectedCustomer');
var equipment_id = this.get('selectedEquipment')
this.store.findRecord('customer', customer_id).then((customer) => {
truckload.set('customer', customer);
this.store.findRecord('equipmentList',equipment_id).then((equipment) => {
truckload.set('equipmentList', equipment);
truckload.save().then((load) => {
this.get('notify').success('Truck Load Created');
this.transitionToRoute('truck-loads.show', load.id);
});
});
});
return false;
},
I doubt this is the best way to do it - but - it DOES work.
I use JSONAPI as the adapter.
Model:
App.Report = DS.Model.extend({
'name': DS.attr('string'),
'description': DS.attr(),
'placemark': DS.belongsTo('placemark', {
'async': true
})
});
App.Placemark = DS.Model.extend({
'geometry': DS.attr(),
'description': DS.attr(),
'reports': DS.hasMany('report', {
'async': true
})
});
Route:
App.ReportRoute = Ember.Route.extend({
'model': function (params) {
return this.store.find('report', params.report_id);
},
'renderTemplate': function () {
this.render('report', {
'into': 'application'
});
}
});
App.PlacemarkRoute = Ember.Route.extend({
'model': function (params) {
return this.store.find('placemark', params.element_id);
},
'renderTemplate': function () {
this.render('placemark', {
'into': 'application'
});
}
});
i use a component for embeddeding a map canvas where the data (placemark) are come from the Report:
{{map-canvas placemark=model.placemark}}
App.MapCanvasComponent = Ember.Component.extend({
'availablePlacemark': Ember.computed('placemark', function() {
return this.get('placemark.geometry');
});
I found placemark is unable to retrieve and 'undefined' returned.
I tries using:
return this.get('placemark').then(function(placemark) {
return placemark.get('geometry');
});
it did not work.
now, I am thinking if it is a JSONAPI adapter issue or async problem from view to a components.
i am using ember 1.13
Hope someone could help
thanks
In ember controller
action:function(){
a:function(){
....
this.set('b',true);
}
}
I just want to write a test case for this
test('a - function test case', function(assert) {
var controller= this.subject();
controller._action().a();
assert(controller.get(b),true);
});
but this not working I'm getting undefined error.
any other way to pass this test case?
Looking to your code, I believe you're trying to use ember actions, if so you have to use actions: { ... } instead of action: function() { ... }.
And to trigger an action you use the send method.
This is an example on how to test an action in ember-cli:
app/controllers/index
import Ember from 'ember';
export default Ember.Controller.extend({
value: null,
actions: {
changeValue: function() {
this.set('value', true);
}
}
});
tests/unit/controllers/index-test.js
import {
moduleFor,
test
} from 'ember-qunit';
moduleFor('controller:index', {});
test('it exists', function(assert) {
var controller = this.subject();
assert.ok(!controller.get('value'));
controller.send('changeValue');
assert.ok(controller.get('value'));
});
This was working for me
test('it exists', function(assert) {
var controller = this.subject();
assert.ok(!controller.get('value'));
Ember.run(function(){
controller.send('changeValue');
assert.ok(controller.get('value'));
});
});