CucumberJS tests passing even though it's not possible - selenium

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?

Related

Find all clickable elements using webdriverio

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");
});

Accessing elements using $$ or elements in webdriverio

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)
})

Check if image is valid and loaded with Protractor

I am writing tests using Protractor (with Cucumber.js, Chai and Chai As Promised, though I think these details don't matter). I would like to write a test that checks whether an image element is valid and loaded - i.e. that it has a src attribute and has not errored out while loading.
There are some nice-looking answers elsewhere to the question of how to check if an image is loaded from within a browser, via the DOM API. But how can I cleanly perform this check using Protractor's API?
I expect my test will look something like:
this.Then(/^I should see the "([^"]*)" image$/, function (imageId, callback) {
expect(
element(by.id(imageId))
).to.eventually.satisfy(isImageOk).notify(callback);
});
but I don't know how to implement the isImageOk function via the Protractor API.
You need to evaluate a JavaScript expression in the context of the browser, using Protractor's executeAsyncScript function.
Here is the code from my answer to a similar question:
it('should find all images', function () {
browser.executeAsyncScript(function (callback) {
var imgs = document.getElementsByTagName('img'),
loaded = 0;
for (var i = 0; i < imgs.length; i++) {
if (imgs[i].naturalWidth > 0) {
loaded = loaded + 1;
};
};
callback(imgs.length - loaded);
}).then(function (brokenImagesCount) {
expect(brokenImagesCount).toBe(0);
});
});
The function executed within the browser returns the number of non-loaded images.
Just an updated version of the previous answer - test is made to fail if there are broken images, because we expect 0
it('should check if there are broken images', function () {
browser.executeAsyncScript(function (callback: (arg0: number) => void) {
const imgs = document.getElementsByTagName("img");
let loaded = 0;
for (let i = 0; i < imgs.length; i++) {
if (imgs[i].naturalWidth > 0) {
loaded = loaded + 1;
}
}
callback(imgs.length - loaded);
})
.then(function (brokenImagesCount) {
expect(brokenImagesCount).toBe(0);
});
});

Karma Chai How to access DOM element

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;
});
});

casperJS Can't find variable : $

I'm trying to call a function defined in another module using this.evaluate().
The code snippet(calling the function) is:
this.waitFor(function check() {
var re = this.evaluate(universe.answer(couponElement, url));
if (re != 'no' & re!='yes' & re!=null) {
couponObj.push(re);
and the module in which the function is defined is like this:
var require = patchRequire(require);
var utils = require('utils');
exports.answer = function(couponElement, url) {
var lblInvalidCoupon = 'lblInvalidCoupon';
var tolTipCouponinner='tolTipCouponinner';
var txtFCCoupondisocunt = 'txtFCCoupondisocunt';
var btnRemoveFCCoupon = 'btnRemoveFCCoupon';
var check = $('#txtCouponCode').css('backgroundImage');
if (check.indexOf('ajax-loader.gif')>-1){
return 'no';
} else {
if (document.getElementById(lblInvalidCoupon)!=null){
Basically, I want to call the function using this.evaluate but unable to do so.
First, try with the simplest evaluate: remote.message event to capture console.log from page.
casper.on("remote.message", function(msg) {
console.log("[page] " + msg);
});
this.evaluate(function () {
console.log("Hi phantomworld! I am hello-ing from remote page!");
});
Next, check if jQuery is present:
this.evaluate(function () {
console.log(typeof jQuery);
});
If it says, [page] function, jQuery is present in the page. You need to dig more...
If not, inject it:
var casper = require('casper').create({
clientScripts: [
'includes/jquery.js'
]
});
You didn't actually pass the answer function to casper.evaluate, but you called it instead. The problem is that in this way answer was not executed in page context and because of this $ is not defined. casper.evaluate which executes a function in page context is sandboxed. It cannot use variables which are defined outside. The passed function must be self contained.
To fix this the arguments which are consumed by answer can be passed as additional parameters to casper.evaluate.
Change the line
var re = this.evaluate(universe.answer(couponElement, url));
to
var re = this.evaluate(universe.answer, couponElement, url);
If JQuery is not present in the page you need to follow sudipto's answer.