ElementFinder error when I do getText in a console.log in protractor - protractor

Im trying to do a element.all like this
element.all(by.className('col-md-4 ng-scope')).all(by.className('chart-small-titles dashboard-alignment ng-binding')).then(function(items) {
console.log(items[1].getText());
});
This code return this:
ElementFinder {
browser_:
ProtractorBrowser {
controlFlow: [Function],
schedule: [Function],
setFileDetector: [Function],
getExecutor: [Function],
getSession: [Function],
and more lines of code like this.
I am doing something wrong? Maybe I am using wrong the .all function, i don't know.

There may be different things that go wrong. Try this
element.all(by.className('col-md-4 ng-scope')).all(by.className('chart-small-titles dashboard-alignment ng-binding')).then(function(items) {
items.get(1).getText().then(
function (text) {
console.log(text);
})
)
});

Related

Protractor : not able to find element in login page

I am novice user of protractor and trying to use it for angularjs application,
Config file snippet :
exports.config = {
directConnect: true,
capabilities: {
'browserName': 'chrome'
},
framework: 'jasmine',
specs: ['plugins/./test_spec.js'],
allScriptsTimeout: 60000,
getPageTimeout: 30000,
jasmineNodeOpts: {
defaultTimeoutInterval: 1240000
}
};
Working test case (spec file):
describe('Login', function () {
it('Login Page', function () {
browser.get('http://localhost:9000/apps/admin/');
element(by.model('ctrl.user.name'))
element(by.model('ctrl.user.password'))
expect(true).toBe(true)
});
});
Failing test case (spec file):
describe('Login', function () {
it('Login Page', function () {
browser.get('http://localhost:9000/apps/admin/');
element(by.model('ctrl.user.name')).sendKeys("test1");
element(by.model('ctrl.user.password')).sendKeys("test1");
element(by.css('[type="submit"]')).click();
expect(true).toBe(true)
});
});
Trying to use sendKeys for login page is failing but without sendkeys test case passes, I am getting following error:
Failed: script timeout: result was not received in 60 seconds
(Session info: chrome = 72.0.3626.109)
(Driver info: chromedriver = 2.46.628402(536cd7adbad73a3783fdc2cab92ab2ba7ec361e1), platform = Windows NT 10.0.17134 x86_64)
I suspect element not being found.
Please guide me through this.
Thanks in Advance
I highly recommended to add SELENIUM_PROMISE_MANAGER: false, to your protractor.config file due to this thread, if tells it shortly - better to don't use Control Flow. So how will look your config file:
exports.config = {
directConnect: true,
capabilities: {
'browserName': 'chrome'
},
framework: 'jasmine',
specs: ['plugins/./test_spec.js'],
allScriptsTimeout: 60000,
getPageTimeout: 30000,
jasmineNodeOpts: {
defaultTimeoutInterval: 1240000
},
SELENIUM_PROMISE_MANAGER: false,
};
After it you should update your tests (all actions that returns promise should resolve it, I prefer async ... await style). Also, your expect true is useless, let get rid off it, and add some explicit waiters.
describe('Login', () => {
it('Login Page' async () => {
await browser.get('http://localhost:9000/apps/admin/');
const name = element(by.model('ctrl.user.name'));
await browser.wait(ExpectedConditions.elementToBeClickable(name), 10000);
await name.sendKeys("test1");
const password = element(by.model('ctrl.user.password'));
await browser.wait(ExpectedConditions.elementToBeClickable(password), 10000);
await password.sendKeys("test1");
element(by.css('[type="submit"]')).click();
expect(true).toBe(true)
});
});
Also, It would be better to find locators using CSS. Update your question with what error this test will fail.
Protractor is wrapper on selenium, thus when you are plainning to use await/async methods just disable the SELENIUM_PROMISE_MANAGER by setting it as false, so that the protractor promises work well with async/await methods.
I also suggest using pagemodel design pattern which will make the code much readable.
enter code here
export class loginPageObject{
public emailTextBox: ElementFinder;
public passwordTextBox: ElementFinder;
public signInButton: ElementFinder;
public errorMessage: ElementFinder;
constructor(){ //this.emailTextBox = $("input[type='email']");
//this.emailTextBox = element(by.css("body > app-root > div > app-login > div > div > form > div > input"));
this.emailTextBox = $("input[type='email']");
this.passwordTextBox = $("input[type='password']");
this.signInButton = $("button[type='submit']");
this.errorMessage = $("span");
}
}
above is one such sample .. later on you can use it like following way

No element found using locator: By(css selector, *[id="more"])

protractor.e2e-sepc.ts
import {browser, element, by} from 'protractor';
describe('Open the link', () => {
beforeEach(() => {
browser.waitForAngularEnabled(false);
browser.get('url');
browser.sleep(2000);
});
it('Click on more button', () => {
element(by.id('more').click();
})
})
When I ran the above test case on chrome as a browser it ran succcessfully, but when I ran it with chrome --headless browser it fails the spec by displaying error as No element found using locator: By(css selector, *[id="more"])
protractor.config.js
multiCapabilities: [{
'browserName': 'chrome',
'chromeOptions': {
args: ["--headless", "--disable-gpu"]
}
}]
My assumption is that the 2-second sleep is not enough and you just need to explicitly wait for the presence of the desired element:
var more = element(by.id('more'));
var EC = protractor.ExpectedConditions;
browser.wait(EC.presenceOf(more), 10000)
more.click();
Note that you had a missing closing parenthesis, but I think that's just a typo:
element(by.id('more')).click();
// HERE^

Protractor ignoreSynchronization issue

I am developing the e2e test suite for one of my applications. We have a sso that is a non angular site, our site is an angular site. in the start of my test i make a call to SSO settings:
browser.ignoreSynchronization = true;
browser.get(browser.baseUrl + '/agoda/home?mock=mock-jax);
I am able to log on sucessfully and it redirects to my application which is an angular site. I set browser.ignoreSynchronization = false; as soon as i redirect to my application and its loaded. After this nothing works.
I try to read following:
var books= element.all(by.repeater('book in books'));
console.log(licenses.count());
results into
{ ptor_:
{ controlFlow: [Function],
schedule: [Function],
setFileDetector: [Function],
getSession: [Function],
getCapabilities: [Function],
quit: [Function],
actions: [Function],
touchActions: [Function],
executeScript: [Function],
executeAsyncScript: [Function],
call: [Function],
wait: [Function],
sleep: [Function],
getWindowHandle: [Function],
getAllWindowHandles: [Function],
getPageSource: [Function],
close: [Function],
getCurrentUrl: [Function],
getTitle: [Function],
findElementInternal_: [Function],
findDomElement_: [Function],
findElementsInternal_: [Function],
takeScreenshot: [Function],
..
}
I believe this has something to do with the ignoreSynchronization but not sure what i am doing wrong?
You are not catching the promise that the count() function returns as a callback after its execution. Protractor is built on WebDriverJs model of async with promises. It has nothing to do with your ignoreSynchronization and you are console logging a protractor instance object instead of its value. You need to console log the value that is returned through the promise. Here's how -
var books= element.all(by.repeater('book in books'));
books.count().then(function(booksCount){
console.log(booksCount);
});
The above way of using .then() in above code should solve your problem. More about promises. Hope it helps.

Extending own classes

i am develop an app with several windows. Many windows are similar, so i think write a superclass, and extend it.
I have, the superclass:
Ext.define('AM.view.ui.DecoratorAbstract',{
extend: 'Ext.window.Window',
alias: 'widget.decoratorAbstract',
initComponent: function(){
this.title = this.aTitle;
this.resizable = this.cfg[0];
this.closable = this.cfg[1];
this.minimizable = this.cfg[2];
//this.items = this.anItem;
this.callParent(arguments);
}
});
And the subclass:
Ext.define('AM.view.ui.DecoratorForm',{
extend: 'AM.view.ui.DecoratorAbstract',
alias: 'widget.decoratorForm',
initComponent: function(){
this.callParent();
this.buttons = [
{ text:'Guardar', action:'save', iconCls: 'ico-save' },
{ text:'Cancelar', action:'cancel', iconCls: 'ico-cancel' }
];
}
});
Both classes are included in the Controller:
Ext.define('AM.controller.Ui',{
extend: 'Ext.app.Controller',
views: [
'ui.Toolbar',
'ui.Statusbar',
'ui.AlertErr',
'ui.AlertOk',
'ui.AlertWar',
'ui.AlertDelete',
'ui.AlertUndelete',
'ui.DecoratorAbstract',
'ui.DecoratorForm',
'ui.DecoratorGrid'
],
model: [],
store: [],
});
From the Firebug js console i create the subclass:
Ext.create('AM.view.ui.DecoratorForm',{cfg:[true,true,true],aTitle: 'Title'}).show();
The window is showed but, not the buttons.
Any ideas ?.
There are a few things here... First, move this.callParent() to the end of your initComponent. This is because the initComponent further up the inheritance does something with this.buttons, and you are missing out on that by calling callParent before setting the buttons.
Next, you really shouldn't use this cfg thing that you are passing in. Just pass in the config parameters that you want to use, and they will be available:
Ext.define('AM.view.ui.DecoratorAbstract',{
extend: 'Ext.window.Window',
alias: 'widget.decoratorAbstract',
initComponent: function(){
this.callParent(arguments);
}
});
Ext.define('AM.view.ui.DecoratorForm',{
extend: 'AM.view.ui.DecoratorAbstract',
alias: 'widget.decoratorForm',
initComponent: function(){
this.buttons = [
{ text:'Guardar', action:'save', iconCls: 'ico-save' },
{ text:'Cancelar', action:'cancel', iconCls: 'ico-cancel' }
];
this.callParent();
}
});
//to instantiate:
Ext.create('AM.view.ui.DecoratorForm',{
resizable: true,
closable: true,
minimizable: true,
title: 'Title'
}).show();
Anytime you are trying to "trick" the component by using something like that cfg array, you should probably re-think what you're doing and see if there's a smarter way.
One other thing you should look into using is Ext.apply(). It will save a lot of bytes by changing what you had before into something like this:
Ext.apply(this, {
title: 'my title',
resizable: cfg[0],
closable: cfg[1],
///...etc...
})
What if you move
this.callParent(arguments);
To the end of initComponent in your DecoratorForm.

RESTful Model, get rid of the id query param in the GET request

I'm a little bit stuck here. My model code is
Ext.define('MyFancyModel', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id', type: 'string' },
{ name: 'name', type: 'string' }
],
proxy: {
type: 'rest',
url: '/fancymodel',
noCache: false
}
});
When I try to load data by id using
Ext.ModelManager.getModel('MyFancyModel').load('some-id', {});
the request url is /fancymodel/some-id?id=some-id which is obviously not correct. So how can I achieve the right request url: /fancymodel/some-id without any patches or overrides?
EDIT:
jsfiddle
In the developer console you can see failed GET request
http://fiddle.jshell.net/fancymodel/some-id?id=some-id
EDIT:
Thread on the Sencha forum
I haven't found any ExtJS solution, so I have written a small patch (not sure it works in every situations) :
Ext.override(Ext.data.proxy.Rest, {
buildUrl: function (request) {
delete request.params.id;
return this.callParent(arguments);
}
});
The standard way :
Ext.define('MyPatches.data.proxy.Rest', {
override: 'Ext.data.proxy.Rest',
buildUrl: function (request) {
delete request.params.id;
return this.callParent(arguments);
}
});