Commit 65eb8709 65eb8709bf3dfe70c7dd5251ab395983266ff235 by Nicolas Perriault

Merge pull request #469 from hexid/master

#455 - Add support for getElementsAttribute() and getElementsInfo()
2 parents 02e4bbf7 acd7739f
......@@ -972,6 +972,25 @@ Retrieves the value of an attribute on the first element matching the provided :
.. index:: DOM
``getElementsAttribute()``
-------------------------------------------------------------------------------
**Signature:** ``getElementsAttribute(String selector, String attribute)``
.. versionadded:: 1.1
Retrieves the values of an attribute on each element matching the provided :doc:`selector <../selectors>`::
var casper = require('casper').create();
casper.start('http://www.google.fr/', function() {
require('utils').dump(this.getElementsAttribute('div[title="Google"]', 'title')); // "['Google']"
});
casper.run();
.. index:: DOM
``getElementBounds()``
-------------------------------------------------------------------------------
......@@ -1024,32 +1043,71 @@ It returns an array of objects with four keys: ``top``, ``left``, ``width`` and
Retrieves information about the first element matching the provided :doc:`selector <../selectors>`::
casper.start('http://google.com/', function() {
casper.start('http://google.fr/', function() {
require('utils').dump(this.getElementInfo('#hplogo'));
});
Gives something like::
{
"nodeName": "div",
"attributes": {
"dir": "ltr",
"title": "Google",
"align": "left",
"dir": "ltr",
"id": "hplogo",
"onload": "window.lol&&lol()",
"style": "background:url(images/srpr/logo3w.png) no-repeat;background-size:275px 95px;height:95px;width:275px"
"style": "height:110px;width:276px;background:url(/images/srpr/logo1w.png) no-repeat",
"title": "Google"
},
"tag": "<div dir=\"ltr\" title=\"Google\" align=\"left\" id=\"hplogo\" onload=\"window.lol&amp;&amp;lol()\" style=\"background:url(images/srpr/logo3w.png) no-repeat;background-size:275px 95px;height:95px;width:275px\"><div nowrap=\"nowrap\" style=\"color:#777;font-size:16px;font-weight:bold;position:relative;left:214px;top:70px\">France</div></div>",
"height": 110,
"html": "<div nowrap=\"nowrap\" style=\"color:#777;font-size:16px;font-weight:bold;position:relative;left:214px;top:70px\">France</div>",
"nodeName": "div",
"tag": "<div dir=\"ltr\" title=\"Google\" align=\"left\" id=\"hplogo\" onload=\"window.lol&amp;&amp;lol()\" style=\"height:110px;width:276px;background:url(/images/srpr/logo1w.png) no-repeat\"><div nowrap=\"nowrap\" style=\"color:#777;font-size:16px;font-weight:bold;position:relative;left:214px;top:70px\">France</div></div>",
"text": "France\n",
"x": 582.5,
"y": 192,
"width": 275,
"height": 95,
"visible": true
"visible": true,
"width": 276,
"x": 62,
"y": 76
}
.. index:: DOM
``getElementsInfo()``
-------------------------------------------------------------------------------
**Signature:** ``getElementsInfo(String selector)``
.. versionadded:: 1.1
Retrieves information about all elements matching the provided :doc:`selector <../selectors>`::
casper.start('http://google.fr/', function() {
require('utils').dump(this.getElementsInfo('#hplogo'));
});
Gives something like::
[
{
"attributes": {
"align": "left",
"dir": "ltr",
"id": "hplogo",
"onload": "window.lol&&lol()",
"style": "height:110px;width:276px;background:url(/images/srpr/logo1w.png) no-repeat",
"title": "Google"
},
"height": 110,
"html": "<div nowrap=\"nowrap\" style=\"color:#777;font-size:16px;font-weight:bold;position:relative;left:214px;top:70px\">France</div>",
"nodeName": "div",
"tag": "<div dir=\"ltr\" title=\"Google\" align=\"left\" id=\"hplogo\" onload=\"window.lol&amp;&amp;lol()\" style=\"height:110px;width:276px;background:url(/images/srpr/logo1w.png) no-repeat\"><div nowrap=\"nowrap\" style=\"color:#777;font-size:16px;font-weight:bold;position:relative;left:214px;top:70px\">France</div></div>",
"text": "France\n",
"visible": true,
"width": 276,
"x": 62,
"y": 76
}
]
.. index:: Form
``getFormValues()``
......
......@@ -963,6 +963,25 @@ Casper.prototype.getElementAttr = function getElementAttr(selector, attribute) {
};
/**
* Retrieves the value of an attribute for each element matching the provided
* DOM CSS3/XPath selector.
*
* @param String selector A DOM CSS3/XPath selector
* @param String attribute The attribute name to lookup
* @return Array
*/
Casper.prototype.getElementsAttribute =
Casper.prototype.getElementsAttr = function getElementsAttr(selector, attribute) {
"use strict";
this.checkStarted();
return this.evaluate(function _evaluate(selector, attribute) {
return [].map.call(__utils__.findAll(selector), function(element) {
return element.getAttribute(attribute);
});
}, selector, attribute);
}
/**
* Retrieves boundaries for a DOM element matching the provided DOM CSS3/XPath selector.
*
* @param String selector A DOM CSS3/XPath selector
......@@ -1001,6 +1020,23 @@ Casper.prototype.getElementInfo = function getElementInfo(selector) {
};
/**
* Retrieves information about the nodes matching the provided selector.
*
* @param String|Objects selector CSS3/XPath selector
* @return Array
*/
Casper.prototype.getElementsInfo = function getElementsInfo(selector) {
"use strict";
this.checkStarted();
if (!this.exists(selector)) {
throw new CasperError(f("Cannot get information from %s: no elements found.", selector));
}
return this.evaluate(function(selector) {
return __utils__.getElementsInfo(selector);
}, selector);
};
/**
* Retrieves boundaries for all the DOM elements matching the provided DOM CSS3/XPath selector.
*
* @param String selector A DOM CSS3/XPath selector
......
......@@ -128,6 +128,24 @@
};
/**
* Checks if a given DOM element is visible in remove page.
*
* @param Object element DOM element
* @return Boolean
*/
this.elementVisible = function elementVisible(elem) {
try {
var comp = window.getComputedStyle(elem, null);
return comp.visibility !== 'hidden' &&
comp.display !== 'none' &&
elem.offsetHeight > 0 &&
elem.offsetWidth > 0;
} catch (e) {
return false;
}
}
/**
* Base64 encodes a string, even binary ones. Succeeds where
* window.btoa() fails.
*
......@@ -437,6 +455,35 @@
};
/**
* Retrieves information about the nodes matching the provided selector.
*
* @param String|Object selector CSS3/XPath selector
* @return Array
*/
this.getElementsInfo = function getElementsInfo(selector) {
var bounds = this.getElementsBounds(selector);
var eleVisible = this.elementVisible;
return [].map.call(this.findAll(selector), function(element, index) {
var attributes = {};
[].forEach.call(element.attributes, function(attr) {
attributes[attr.name.toLowerCase()] = attr.value;
});
return {
nodeName: element.nodeName.toLowerCase(),
attributes: attributes,
tag: element.outerHTML,
html: element.innerHTML,
text: element.innerText,
x: bounds[index].left,
y: bounds[index].top,
width: bounds[index].width,
height: bounds[index].height,
visible: eleVisible(element)
};
});
};
/**
* Retrieves a single DOM element matching a given XPath expression.
*
* @param String expression The XPath expression
......@@ -796,24 +843,13 @@
};
/**
* Checks if a given DOM element is visible in remote page.
* Checks if any element matching a given selector is visible in remote page.
*
* @param String selector CSS3 selector
* @return Boolean
*/
this.visible = function visible(selector) {
try {
var elems = this.findAll(selector);
return Array.prototype.some.call(elems, function(el) {
var comp = window.getComputedStyle(el, null);
return comp.visibility !== 'hidden' &&
comp.display !== 'none' &&
el.offsetHeight > 0 &&
el.offsetWidth > 0;
});
} catch (e) {
return false;
}
return [].some.call(this.findAll(selector), this.elementVisible);
};
};
})(typeof exports === "object" ? exports : window);
......
......@@ -2,5 +2,6 @@
<html>
<body>
<div class="tester testo testme" data-stuff="beautiful string"></div>
<div class="tester testo testme" data-stuff="not as beautiful string"></div>
</body>
</html>
\ No newline at end of file
......
......@@ -2,12 +2,19 @@
/*jshint strict:false*/
var x = require('casper').selectXPath;
casper.test.begin('getElementAttribute() tests', 2, function(test) {
casper.test.begin('getElementAttribute() tests', 4, function(test) {
casper.start('tests/site/elementattribute.html', function() {
test.assertEquals(this.getElementAttribute('.testo', 'data-stuff'),
'beautiful string', 'Casper.getElementAttribute() works with a CSS selector');
test.assertEquals(this.getElementAttribute(x('//div[@class]'), 'data-stuff'),
'beautiful string', 'Casper.getElementAttribute() works with a XPath selector');
}).then(function() {
test.assertEquals(this.getElementsAttribute('.testo', 'data-stuff'),
['beautiful string', 'not as beautiful string'],
'Casper.getElementsAttribute() works with a CSS selector');
test.assertEquals(this.getElementsAttribute(x('//div[@class]'), 'data-stuff'),
['beautiful string', 'not as beautiful string'],
'Casper.getElementsAttribute() works with a XPath selector');
}).run(function() {
test.done();
});
......
......@@ -161,3 +161,43 @@ casper.test.begin('ClientUtils.getElementInfo() tests', 10, function(test) {
'ClientUtils.getElementInfo() retrieves element whole tag contents');
test.done();
});
casper.test.begin('ClientUtils.getElementsInfo() first element tests', 10, function(test) {
casper.page.content = '<a href="plop" class="plip plup"><i>paf</i></a><a href="plap" class="plip plup"><i>puf</i></a>';
var info = casper.getElementsInfo('a.plip');
test.assertEquals(info[0].nodeName, 'a', 'ClientUtils.getElementsInfo() retrieves first element name');
test.assertEquals(info[0].attributes, {
'href': 'plop',
'class': 'plip plup'
}, 'ClientUtils.getElementsInfo() retrieves first element attributes');
test.assertEquals(info[0].html, '<i>paf</i>', 'ClientUtils.getElementsInfo() retrieves first element html content');
test.assertEquals(info[0].text, 'paf', 'ClientUtils.getElementsInfo() retrieves first element text');
test.assert(info[0].x > 0, 'ClientUtils.getElementsInfo() retrieves first element x pos');
test.assert(info[0].y > 0, 'ClientUtils.getElementsInfo() retrieves first element y pos');
test.assert(info[0].width > 0, 'ClientUtils.getElementsInfo() retrieves first element width');
test.assert(info[0].height > 0, 'ClientUtils.getElementsInfo() retrieves first element height');
test.assert(info[0].visible, 'ClientUtils.getElementsInfo() retrieves first element visibility');
test.assertEquals(info[0].tag, '<a href="plop" class="plip plup"><i>paf</i></a>',
'ClientUtils.getElementsInfo() retrieves first element whole tag contents');
test.done();
});
casper.test.begin('ClientUtils.getElementsInfo() second element tests', 10, function(test) {
casper.page.content = '<a href="plop" class="plip plup"><i>paf</i></a><a href="plap" class="plip plup"><i>puf</i></a>';
var info = casper.getElementsInfo('a.plip');
test.assertEquals(info[1].nodeName, 'a', 'ClientUtils.getElementsInfo() retrieves second element name');
test.assertEquals(info[1].attributes, {
'href': 'plap',
'class': 'plip plup'
}, 'ClientUtils.getElementsInfo() retrieves second element attributes');
test.assertEquals(info[1].html, '<i>puf</i>', 'ClientUtils.getElementsInfo() retrieves second element html content');
test.assertEquals(info[1].text, 'puf', 'ClientUtils.getElementsInfo() retrieves second element text');
test.assert(info[1].x > 0, 'ClientUtils.getElementsInfo() retrieves second element x pos');
test.assert(info[1].y > 0, 'ClientUtils.getElementsInfo() retrieves second element y pos');
test.assert(info[1].width > 0, 'ClientUtils.getElementsInfo() retrieves second element width');
test.assert(info[1].height > 0, 'ClientUtils.getElementsInfo() retrieves second element height');
test.assert(info[1].visible, 'ClientUtils.getElementsInfo() retrieves second element visibility');
test.assertEquals(info[1].tag, '<a href="plap" class="plip plup"><i>puf</i></a>',
'ClientUtils.getElementsInfo() retrieves second element whole tag contents');
test.done();
});
......