I am using angular with ngMaterial. I am using md-toast that comes with it. The problem is that the toasts are using timeout instead of interval and Protractor doesn't like them.
I just want to remove the md-toast calls from my tests. All my md-toast calls are on this class:
# Coffeescript
class MyAppController extends MyAppBase
showToast: (msg, type) ->
#rootScope.customToastMessage =
toast_type: type
messageString: msg
#rootScope.appctrl.openCustomToastMessage()
It is possible to change the showToast method in Protractor tests?
You should look into Protractor's addMockModule()
http://angular.github.io/protractor/#/api?view=Protractor.prototype.addMockModule
(some more info: http://eitanp461.blogspot.be/2014/01/advanced-protractor-features.html)
Example mock:
var MdToastMock = function () {
this.show = function (toast) {
this.position = toast._position;
this.content = toast._content;
};
this.simple = function () {
var self = this;
self.content = function (content) {
self._content = content;
return self;
};
self._position = '';
self.position = function (position) {
self._position = position;
return self;
};
return this;
};
spyOn(this, 'show').and.callThrough();
};
return MdToastMock;
Related
I want to override "_render: function ()" function from pivot_renderer.js file in web but not working in custom module. Here is the code i am implementing in my custom module:-
odoo.define('MY_CUSTOM_MODULE_NAME.renderer', function (require) {
"use strict";
var PivotRenderer = require('web.PivotRenderer');
var field_utils = require('web.field_utils');
var core = require('web.core');
var _t = core._t;
PivotRenderer.include({
init: function(parent, state, params) {
this._super.apply(this, arguments);
},
_render: function () {
if (!this._hasContent()) {
// display the nocontent helper
this.replaceElement(QWeb.render('PivotView.nodata'));
return this._super.apply(this, arguments);
}
if (!this.$el.is('table')) {
// coming from the no content helper, so the root element has to be
// re-rendered before rendering and appending its content
this.renderElement();
}
var $fragment = $(document.createDocumentFragment());
var $table = $('<table>').appendTo($fragment);
var $thead = $('<thead>').appendTo($table).addClass("CLASS_NAME");
var $tbody = $('<tbody>').appendTo($table);
var nbr_measures = this.state.measures.length;
var nbrCols = (this.state.mainColWidth === 1) ?
nbr_measures :
(this.state.mainColWidth + 1) * nbr_measures;
for (var i=0; i < nbrCols + 1; i++) {
$table.prepend($('<col>'));
}
this._renderHeaders($thead, this.state.headers);
this._renderRows($tbody, this.state.rows);
// todo: make sure the next line does something
$table.find('.o_pivot_header_cell_opened,.o_pivot_header_cell_closed').tooltip();
this.$el.html($table.contents());
return this._super.apply(this, arguments);
},
});
});
In the above, i want to add a class in the header for calling my custom css "var $thead = $('').appendTo($table).addClass("CLASS_NAME");" with this syntax but it is not reflecting in my custom module. Although, for testing, I have implemented same class in default web module and it is working fine. The issue is in custom module.
So how to solve this issue? Is there any other way for calling class or i am doing it in a wrong way?
var $thead = $('').addClass("CLASS_NAME").appendTo($table);
This will work in my case. You can try it.
This question took me one day to debug it, but still no luck.
Problem: this.gridOptions.data = this.allTemplatesFromClassificationRepo ;
**this.allTemplatesFromClassificationRepo ** is still a empty array. Before this line of code executes, I have call activate() function to assign array to **this.allTemplatesFromClassificationRepo **. Please see this line this.allTemplatesFromClassificationRepo = templateReorderProperties;
P.S. Although I cannot get the value of allTemplatesFromClassificationRepo in controller, but I can get the value of it in html.
namespace app.admin {
'use strict';
class FooController {
static $inject: Array<string> = [];
constructor() {
this.activate();
}
activate() {
this.getData();
this.classificationFoo = this.data[0];
this.getTemplateFromGivenRepo(this.classificationFoo.id, this.classificationFoo.displayName);
this.populateData();
}
data: any;
classificationFoo: any;
allDataFromclassificationFoo: any = [];
// demo grid
gridOptions = {
enableFiltering: true,
},
data: []
};
populateData() {
this.gridOptions.data = this.allTemplatesFromClassificationRepo ;
}
getData() {
this.fooService.getUserData();
this.data = this.fooService.userdata;
}
getTemplateFromGivenRepo(fooId: string, fooName: string) {
switch (fooId) {
case 'FOO':
this.TemplateApi.templatesAvaiableForRepoIdGET(fooId).then(data => {
data.forEach(element => {
element.fooName = fooName;
});
let templateReorderProperties = data
this.allTemplatesFromClassificationRepo = templateReorderProperties;
}, error => {
});
break;
default:
break;
}
};
}
class Bar implements ng.IDirective {
static $inject: Array<string> = [];
constructor() {
}
bindToController: boolean = true;
controller = FooController;
controllerAs: string = 'vm';
templateUrl: string = 'app/foo.html';
static instance(): ng.IDirective {
return new Bar();
}
}
angular
.module('app.admin')
.directive('bar', Bar.instance);
}
getTemplateFromGivenRepo is async operation.
Move this.populateGridData(); call inside getTemplateFromGivenRepo after
this.allTemplatesFromClassificationRepo = templateReorderProperties;
getTemplateFromGivenRepo(repoId: string, repoName: string) {
switch (repoId) {
case 'CLASSIFICATION':
this.TemplateApi.templatesAvaiableForRepoIdGET(repoId).then(data => {
this.allTemplatesFromClassificationRepo = templateReorderProperties;
this.populateGridData(); // call here
}, error => {
});
}
};
OR
You can return promise from getTemplateFromGivenRepo and in then able success callback,call
this.populateGridData();
I think the problem is in this instance that different inside Promise resolve.
Try to write in beginning something like:
var self = this;
and after that change all this to self key.
a.e.:
self.gridOptions.data = self.allTemplatesFromClassificationRepo;
// and so on ...
By this way you will guarantee that you use same scope instance
Hope it will work
I started to use angular-jsdoc for document my AngularJS code.
I have a service with some methods.
Some of the methods, return an object with another methods:
Here is an example of my service (with simple method and complex method)
angular.module('map').service('pointUtils', function ($http) {
var self = this;
// simple function
self.removeAllPoints = function () {
// remove all points
};
// complex function
self.createPoint = function (params) {
var pointData = {
isVisible :params.isVisible || true,
color : params.color || 'blue'
};
var pointObj = {};
pointObj.setColor = function (color) {
pointData.color = color;
};
pointObj.getColor = function () {
return pointData.color;
};
pointObj.setVisible = function (visible) {
pointData.isVisible = visible;
};
return pointObj
};
});
what is the way to document this complex method?
thanks,
kfir
I created an Angular controller to list ebooks as follows:
function EBookListController() {
var vm = this;
vm.ebooks = [];
vm.catalogSlug = null;
vm.pagination = { pageNumber: 1, pageSize: 9 };
vm.init = function (catalogSlug) {
vm.catalogSlug = catalogSlug;
load(vm.pageNumber, vm.pageSize);
};
vm.load = function (pageNumber, pageSize) {
// Call service to load ebooks
};
}
Should I define pagination default values in vm.pagination initialization or in init function?
Should load function have pageNumber and pageSize parameters or just use vm.pagination values?
Basically I am not sure if the functions should use the vm parameters values or always take them as arguments ...
Keep the pageSize a scope variable which can be accessed by page rendering functions.
It is enough to set the catalogSlug inside the init() function,
var vm = this;
vm.ebooks = [];
vm.pageSize = 9;
vm.init = function (catalogSlug) {
vm.catalogSlug = catalogSlug;
vm.load(1);
};
vm.load = function(pageNumber) {
// Call service to load ebooks
// Render the pageNumber and use vm.pageSize to set it's size.
};
I try to start testing with protractor and now I have a problem, that I can't solve.
I have this test:
describe('Test_3', function() {
var my_url = 'http://wks-15103:8010/ps/ng-components/examples/ps-checkbox.html'
var main_checkbox = element(by.xpath("//div[#ng-model='My_Group']/div[1]/span/span[1]"));
var checkbox_list = element.all(by.xpath("//div[#ng-model='My_Group']/div[2]/div/span/span[1]"));
var title_checkbox_list = element.all(by.xpath("//div[#ng-model='My_Group']/div[2]/div/span"));
var disabled_pri = 'n-check-checkbox';
var enabled_pri = 'n-check-checkbox n-check-checkbox_checked';
beforeEach(function() {
browser.get(my_url);
});
it('schould be chosen',function(){
main_checkbox.click();
checkbox_list.filter(function(elem, index) {
return elem.getAttribute('class').then(function(text) {
return text != 'n-check-checkbox n-check-checkbox_disabled' & text!='n-check-checkbox n-check-checkbox_disabled n-check-checkbox_checked';
});
}).then(function(filteredElements) {
filteredElements.each(function(element, index) {
expect(element.getAttribute('class')).toEqual(disabled_pri);
});
});
});
});
It isn't working.
But then I try to use filtering without cycle .each it is working fine.
describe('Test_3', function() {
var my_url = 'http://wks-15103:8010/ps/ng-components/examples/ps-checkbox.html'
var main_checkbox = element(by.xpath("//div[#ng-model='My_Group']/div[1]/span/span[1]"));
var checkbox_list = element.all(by.xpath("//div[#ng-model='My_Group']/div[2]/div/span/span[1]")); //это список самих чекбоксов
var title_checkbox_list = element.all(by.xpath("//div[#ng-model='My_Group']/div[2]/div/span")); //это список чекбоксов с названиями
var disabled_pri = 'n-check-checkbox';
var enabled_pri = 'n-check-checkbox n-check-checkbox_checked';
beforeEach(function() {
browser.get(my_url);
});
it('schould be chosen',function(){
main_checkbox.click(); //Убрали флажок с группового чекбокса
checkbox_list.filter(function(elem, index) {
return elem.getAttribute('class').then(function(text) {
return text != 'n-check-checkbox n-check-checkbox_disabled' & text!='n-check-checkbox n-check-checkbox_disabled n-check-checkbox_checked';
});
}).then(function(filteredElements) {
filteredElements[0].click();
filteredElements[0].click();
expect(filteredElements[0].getAttribute('class')).toEqual(disabled_pri);
});
});
});
What is my mistake?
As described in the docs for filter it returns an instance of ElementArrayFinder. When you call a then method on instance of ElementArrayFinder, it resolves to an array of ElementFinders, so in the callback for then you receive a pure JavaScript Array of ElementFinders. To iterate it you can use native JavaScrupt forEach:
checkbox_list.filter(function(elem, index) {
// ...
})
.then(function(filteredElements) {
filteredElements.forEach(function(element, index) {
// ....
});
});
Otherwise, ElementArrayFinder has it's own method each, you should call it right on the result of filter, not inside a callback for then:
checkbox_list.filter(function(elem, index) {
// ...
})
.each(function(element, index) {
// ....
});
Maybe the source code for ElementArrayFinder could also help you.