I want to access web elements using the $$ or elements command using webdriverio. I know they return array of web elements but I am facing tough time accessing them, probably because I am new to webdriverio.
I tried the below code:
var webdriverio = require('webdriverio');
var options = {
desiredCapabilities: {
browserName: 'firefox',
},
};
var client = webdriverio.remote(options);
client
.init()
.url(some url)
.isExisting(selector).then(function(isExisting)) {
if(isExisting) {
var bText = this.$$('textarea[name="message_text]') // this code onwards it is not working
bText.then(function (res) {
console.log(res.length);
console.log(res);
res.value.forEach(function (elem) {
return this.click(elem.ELEMENT)
.setValue(elem.ELEMENT,'some text')
.keys('Enter')
})
})
In the above code, I can see the array res in console but the forEach loop doesn't seem to work. I want to perform click, setValue and keys('Enter') for each of the element present in this.$$('textarea[name="message_text"]') also not able to understand why the returned elements are in a form of JSON objects?
If anyone could guide me in right direction that would help!
Use 'client' instead of 'this' to select the elements.
var bText = client.$$('textarea[name="message_text]') // this code onwards it is not working
bText.then(function (res) {
console.log(res.length);
console.log(res);
See use of runner here -
https://github.com/webdriverio/webdriverio/issues/1043
#ChristianB's suggestion worked actually,since webdriverio's standalone app is built on top of webdriverjs whose methods return promises we need to resolve them properly.I was able to do this using map & Promise.all :
var bText = this.$$('textarea[name="message_text]')
bText.then(function (res) {
console.log(res.length);
console.log(res);
var promises = res.map(function (elem) {
return client
.elementIdClick(elem.ELEMENT)
.setValue(elem.selector,'some text')
.keys('Enter')
})
return Promise.all(promises)
})
Related
I am new to webdriver io and I want to get all clickable elements using webdriver io and iterate through them. I came across 'browser.findElements' API, but could not get it to work. Can anyone provide me a sample code ?
var assert = require('assert');
var homePage = require("../../pages/home_page");
describe('Keyboard friendly home page', () => {
it('User should be able to navigate using tab',() => {
browser.url(homePage.url);
elements = browser.findElements("div");
clickableElements = [];
elements.forEach(element => {
if (element.isDiplayed() && element.isClickable()) {
clickableElements.push(element);
}
});
clickableElements.array.forEach(element => {
console.log(elemtent.getText() + "is clickable");
});
});
});
There might be two problems with your example:
incorrect use of findElements, see documentation; you can use $$ command where you pass only a selector, no need to pass a location strategy as well
the last forEach loop should look like this:
clickableElements.forEach(element => {
console.log(elemtent.getText() + "is clickable");
});
I'm trying to convert some old ruby tests (which used cucumber, phantomjs and capybara) into JavaScript (using cucumber, phantomjs and selenium) as my project is 100% node based and I want to remove the Ruby dependency.
When I run the tests, they all pass. The problem is, I've not created the conditions for the test to pass yet so a pass is impossible. I'm not sure where I'm going wrong.
Here is my world.js file:
var {defineSupportCode} = require('cucumber');
var seleniumWebdriver = require('selenium-webdriver'),
By = seleniumWebdriver.By,
until = seleniumWebdriver.until;
function CustomWorld() {
this.driver = new seleniumWebdriver.Builder()
.withCapabilities(seleniumWebdriver.Capabilities.phantomjs())
.build()
// Returns a promise that resolves to the element
this.waitForElement = function(locator) {
var condition = seleniumWebdriver.until.elementLocated(locator);
return this.driver.wait(condition)
}
}
defineSupportCode(function({setWorldConstructor}) {
setWorldConstructor(CustomWorld)
});
And here is my step definitions file:
require('dotenv').config();
var chalk = require('chalk');
var {defineSupportCode} = require('cucumber');
var seleniumWebdriver = require('selenium-webdriver'),
By = seleniumWebdriver.By,
until = seleniumWebdriver.until;
defineSupportCode(function({ Given, When, Then }) {
Given(/^I show my environment$/, function (next) {
console.log(chalk.green("Running against:" + process.env.TARGET_URI))
next()
})
When(/^I visit "(.*?)"$/, function (url) {
return this.driver.get(url);
})
Then(/^I should be on "([^"]*)"$/, function(page_name) {
this.driver.get(process.env.TARGET_URI+'/'+page_name)
.then(function() {
return this.driver.getCurrentUrl();
})
})
Then(/^I should see "([^"]*)"$/, function (text) {
var xpath = "//*[contains(text(),'" + text + "')]";
var condition = seleniumWebdriver.until.elementLocated({xpath: xpath});
return this.driver.wait(condition, 5000);
});
})
The only possible tests that could be passing there are: When(/^I visit "(.*?)"$/... and Given(/^I show my environment$/...
For reference, here is my .feature file too:
Feature: Test the global header works as expected
Scenario: Header components should exist
Given I visit "/hello"
Then I expect to see a ".c-logo-bar" element
And I expect to see a ".c-search-bar" element
And I expect to see a ".c-main-nav-bar" element
Any ideas where I'm going wrong?
I am writing test cases using Karma Mocha.
Following is my function:
fun : function()
{
if(a == 1)
$("#test").hide();
}
We set the DOM element property based on some condition.
While writing its test:
it('fun', function (){
var a = 1;
// how do I test the DOM element.
// Is it possible to access the DOM element of the source file in the test file.
})
I tried using chai-jquery but it accesses only body and not the other elements.I guess it works on DOM elements of test file.
Can anyone please help.?
I assume you have your jQuery loaded upon testing then you would select you element with $('#test') and then do you tests.
Like so:
describe('obj.fun', function (){
before(function() {
$('<div id="test"></div>').appendTo(document.body);
});
after(function() {
$('#test').remove();
});
it('should hide the element when a is 1', function() {
var $test = $('#test');
expect( $test.is(':hidden') ).to.be.false;
obj.a = 1;
obj.fun();
expect( $test.is(':hidden') ).to.be.true;
});
});
In my ExtJS 4.0.7 app I have some 3rd party javascripts that I need to dynamically load to render certain panel contents (some fancy charting/visualization widgets).
I run in to the age-old problem that the script doesn't finish loading before I try to use it. I thought ExtJS might have an elegant solution for this (much like the class loader: Ext.Loader).
I've looked at both Ext.Loader and Ext.ComponentLoader, but neither seem to provide what I'm looking for. Do I have to just "roll my own" and setup a timer to wait for a marker variable to exist?
Here's an example of how it's done in ExtJS 4.1.x:
Ext.Loader.loadScript({
url: '...', // URL of script
scope: this, // scope of callbacks
onLoad: function() { // callback fn when script is loaded
// ...
},
onError: function() { // callback fn if load fails
// ...
}
});
I've looked at both Ext.Loader and Ext.ComponentLoader, but neither
seem to provide what I'm looking for
Really looks like it's true. The only thing that can help you here, I think, is Loader's injectScriptElement method (which, however, is private):
var onError = function() {
// run this code on error
};
var onLoad = function() {
// run this code when script is loaded
};
Ext.Loader.injectScriptElement('/path/to/file.js', onLoad, onError);
Seems like this method would do what you want (here is example). But the only problem is that , ... you know, the method is marked as private.
This is exactly what newest Ext.Loader.loadScript from Ext.4-1 can be used for.
See http://docs.sencha.com/ext-js/4-1/#!/api/Ext.Loader-method-loadScript
For all you googlers out there, I ended up rolling my own by borrowing some Ext code:
var injectScriptElement = function(id, url, onLoad, onError, scope) {
var script = document.createElement('script'),
documentHead = typeof document !== 'undefined' && (document.head || document.getElementsByTagName('head')[0]),
cleanupScriptElement = function(script) {
script.id = id;
script.onload = null;
script.onreadystatechange = null;
script.onerror = null;
return this;
},
onLoadFn = function() {
cleanupScriptElement(script);
onLoad.call(scope);
},
onErrorFn = function() {
cleanupScriptElement(script);
onError.call(scope);
};
// if the script is already loaded, don't load it again
if (document.getElementById(id) !== null) {
onLoadFn();
return;
}
script.type = 'text/javascript';
script.src = url;
script.onload = onLoadFn;
script.onerror = onErrorFn;
script.onreadystatechange = function() {
if (this.readyState === 'loaded' || this.readyState === 'complete') {
onLoadFn();
}
};
documentHead.appendChild(script);
return script;
}
var error = function() {
console.log('error occurred');
}
var init = function() {
console.log('should not get run till the script is fully loaded');
}
injectScriptElement('myScriptElem', 'http://www.example.com/script.js', init, error, this);
From looking at the source it seems to me that you could do it in a bit of a hackish way. Try using Ext.Loader.setPath() to map a bogus namespace to your third party javascript files, and then use Ext.Loader.require() to try to load them. It doesn't look like ExtJS actually checks if required class is defined in the file included.
I can't seem to get a handle on my list of sortables. They are a list of list elements, each with a
form inside, which I need to get the values from.
Sortables.implement({
serialize: function(){
var serial = [];
this.list.getChildren().each(function(el, i){
serial[i] = el.getProperty('id');
}, this);
return serial;
}
});
var sort = new Sortables('.teams', {
handle: '.drag-handle',
clone: true,
onStart: function(el) {
el.fade('hide');
},
onComplete: function(el) {
//go go gadget go
order = this.serialize();
alert(order);
for(var i=0; i<order.length;i++) {
if (order[i]) {
//alert(order[i].substr(5, order[i].length));
}
}
}
});
the sortables list is then added to a list in a loop with sort.addItems(li); . But when I try to get the sortables outside of the sortables onComplete declaration, js says this.list is undefined.
Approaching the problem from another angle:
Trying to loop through the DOM gives me equally bizarre results. Here are the firebug console results for some code:
var a = document.getElementById('teams').childNodes;
var b = document.getElementById('teams').childNodes.length;
try {
console.log('myVar: ', a);
console.log('myVar.length: ', b);
} catch(e) {
alert("error logging");
}
Hardcoding one li element into the HTML (rather than being injected via JS) changes length == 1, and allows me to access that single element, leading me to believe that accessing injected elements via the DOM is the problem (for this method)
Trying to get the objects with document.getElementById('teams').childNodes[i] returns undefined.
thank you for any help!
not sure why this would fail, i tried it in several ways and it all works
http://www.jsfiddle.net/M7zLG/ test case along with html markup
here is the source that works for local refernece, using the native built-in .serialize method as well as a custom one that walks the dom and gets a custom attribute rel, which can be your DB IDs in their new order (I tend to do that)
var order = []; // global
var sort = new Sortables('.teams', {
handle: '.drag-handle',
clone: true,
onStart: function(el) {
el.fade('hide');
},
onComplete: function(el) {
//go go gadget go
order = this.serialize();
}
});
var mySerialize = function(parentEl) {
var myIds = [];
parentEl.getElements("li").each(function(el) {
myIds.push(el.get("rel"));
});
return myIds;
};
$("saveorder").addEvents({
click: function() {
console.log(sort.serialize());
console.log(order);
console.log(mySerialize($("teams")));
}
});