Selenium RC: How to check if an element has a given attribute? - php

I have some buttons with an onclick attribute and some that don't. I want to check if the specified element has the onclick attribute. How can I do this?
getAttribute() returns the attribute value when it has one. When it doesn't, it throws a RuntimeException and stops the test (even when I wrap it in a try/catch block).
$onclickValue = $this->getAttribute("$locator#onclick"); //works when the attribute exists

By using getEval(), you can execute the javascript hasAttribute() function. Using findElement(), will allow you to work with any type of locator pattern.
$hasAttribute = $this->getEval('this.browserbot.findElement("' . $locator . '").hasAttribute("onclick")');
if ($hasAttribute === 'true') {
//attribute exists
}
Note that getEval() returns a string, not a boolean.

You could first check if the element is present using XPath //location/of/element[#onclick]

Please excuse me if this does not apply to Selenium RC. In Selenium IDE, one can use the
assertElementNotPresent
command, which (despite the name) can determine whether a given attribute is present. It's only parameter is an element locator that can be of the form
element-id#attribute.
Of course this will only be appropriate if you know which elements should have the attribute in question. If not then I guess you'll have to iterate through element sets using XPath expressions.

The reason why a RuntimeException is thrown is because the way PHPUnit's selenium driver works.
It considers certain situations as errors that perform a stop() of the test execution. In particular, the code that stops the test in that situation is the following:
protected function getString($command, array $arguments)
{
try {
$result = $this->doCommand($command, $arguments);
}
catch (RuntimeException $e) {
$this->stop();
throw $e;
}
return (strlen($result) > 3) ? substr($result, 3) : '';
}
I already opened an issue regarding this way of handling errors in the driver at https://github.com/sebastianbergmann/phpunit/issues/276
BTW, removing the calls to stop() in both doCommand() and getString() of /usr/share/php/PHPUnit/Extensions/SeleniumTestCase/Driver.php will make your code able of catching the exception and handling it as you prefer.

Related

Catch error messages from standard PHP functions with a Unit test

A bit unclear on the title, but here we go.
I am running a unit test on a method that essentially runs a strpos(). Like this:
return strpos($this->getHeaderLine($headerName), $value) !== false;
Now I also want to see what happens if I supply it an empty value. When provide an empty string, I get the following message:
strpos(): Empty needle
This message in itself is clear enough, I don't want to throw an exception here. I do want to know if it returned this message though. How would I go about doing this or do I need to rewrite my method?
Try the following:
public function testWarning()
{
$this->expectException(PHPUnit_Framework_Error_Warning::class);
$this->expectExceptionMessage("Empty needle");
strpos('meh', '');
}
This test passes, but if you comment out the expectations, it fails. There are more related classes in PHPUnit framework, like PHPUnit_Framework_Error_Deprecated, PHPUnit_Framework_Error_Notice and so on.

Continue bubbling up inside a loop in PHP

I adapted a web script I wrote to fit my needs for some data I need to retrieve from a server. I run this script from a terminal, so error messages are useful information.
The main part of the code is a loop inside a loop, and in that loop I call a function. In this function there's a call to a database. If there is a problem with connecting to the database, I can catch that error with a simple try {} catch(){}, but how should I structure my code so that I can just skip this iteration and move to the next item in the loop? In other words, do a continue only from within a function.
Below is how I would do it, but I am not sure this is the correct way.
foreach ($flavours as $icecream) {
foreach ($sauces as $sauce) {
$amount = dessertServings($icecream, $sauce);
if ($amount != null) {
// Some other functions like orderDessert, makePricingList and so on
fwrite(STDOUT, "$amount servings of $icecream with $sauce remaining!\n");
}
}
}
dessertServings($icecream, $sauce) {
try {
$dbConnection = new Connection("user", "password", "db$icecream$sauce");
$amountOfServings = $dbConnection->query($icecream, $sauce);
return $amountOfServings;
}
// E.g database connection could not be made
catch(Exception $e) {
fwrite(STDERR, $e->getMessage() . "\n");
return;
}
}
Is there a better way to do this?
To make things harder, what if the function doesn't actually return anything and thus isn't assigning a value to a variable? How should you deal with that?
foreach ($flavours as $icecream) {
foreach ($sauces as $sauce) {
prepareDessert($icecream, $sauce);
// Other functions, most importantly: eatDessert($dessert)
}
}
prepareDessert($icecream, $sauce) {
try {
$dbConnection = new Connection("user", "password", "db$icecream$sauce");
$dbConnection->query($icecream, $sauce)->do("prepare");
}
// E.g database connection could not be made
catch(Exception $e) {
fwrite(STDERR, $e->getMessage() . "\n");
}
}
In such a case, how do I make sure that when the try fails, the block in the loop never reaches the other functions, we can't eat an ice cream that wasn't prepared in the first place!
Would I use an empty variable that simply returns true on success and false and fail, and execute the following code in the main block only on true? Or is there a better convention for this in PHP?
how should I structure my code so that I can just skip this iteration and move to the next item in the loop
The first rule of exception handling: do not do exception handling. Allow it to bubble up and catch it when you need it (in your case, in your loop).
You can also re-throw an exception in your catch, if you want to do some processing within the function (like print to STDERR), but let it bubble up!
The other more traditional method is to have your function return some kind of error code - the most basic being "true" on success, "false" or "null" on failure like in your first example. I don't see anything wrong with that.
To make things harder, what if the function doesn't actually return anything and thus isn't assigning a value to a variable? How should you deal with that?
Throw exceptions, that's their job!
how do I make sure that when the try fails, the block in the loop never reaches the other functions
Don't try/catch within the function or re-throw an exception from within your "catch".
Would I use an empty variable that simply returns true on success and false and fail, and execute the following code in the main block only on true? Or is there a better convention for this in PHP?
Yes there is a better convention : throw exceptions.

PHP: Should a checking function throw an exception

This doesn't necessarily only apply to PHP, but that's my area of concern.
I have been writing a few checking functions recently, that get some argument and then check its validity in various ways. Like, checkXmlString($xml) will check whether the given string contains a well-formed xml document, etc.
The question is, should those functions return a boolean, or throw exceptions and not return anything on success.
So
function checkAbc($arg) { if ($arg is invalid) return false; else return true; }
or rather
function checkAbc($arg) { if ($arg is invalid) throw new Exception(...); }
You could throw a InvalidArgumentException to check if arguments are incorrect but i think for your case if you are writing "checkers" they should return a boolean so you know not to continue operations, for example if the foobar.xml is actually a CSV file you wouldn't want to continue with your operation but you wouldn't want to catch an exeption either
<?php
class Checker {
function validXml($string)
{
if(!(bool)$string) throw new \InvalidArgumentException("Cannot pass empty string as argument", 1);
// Check
// Is valid XML ? Return True : return false
}
}
try {
if(new Checker->validXml($xmlString))
{
// Continue Operation
// return
}
// Notify User of invalidity
// return
} catch (\InvalidArgumentException $e) {
// Log args
//
}
According to almost all books written on subject and not least, according to logic, the name should be the biggest hint of what the function does. In that case, only the first option applies. As Bet Lamed said previously, a function called "check" is not supposed to throw exceptions, just to let you know if the check is ok or not.
If you want exceptions, you might want to rename it to DeserialisationToAbc() or TryParseAbc() or something similar.
The question is, should those functions return a boolean, or throw
exceptions and not return anything on success.
First identify If It is an exceptional situation than use exception .You case does not seems to be exceptional, It is just a condition , so treat it like a condition.If It was like It is correct but fails on certain situation, you may not identify well than you may consider using exception.
Visit these two links and learn more about exception
Exception Best Practices in PHP 5.3
A primer on PHP exceptions
This is of course a bit opinion based, but ask yourself, what do you expect from a function like checkEmail() ? The purpose of the method is to validate something, so you propably expect an answer to this question.
$isValid = checkEmail($arg);
I think most developers expect a bool as return value, it makes the code readable. Wrong values are expected, so one cannot say it is an exception if an invalid argument is passed. To return an error message as well i would use an out parameter:
function checkAbc($arg, &$errorMessage)
{
if ($arg is invalid)
{
$errorMessage = 'The argument is invalid because of...';
return false;
}
else
{
$errorMessage = '';
return true;
}
}
I'm really not quite sure which form is preferrable in general.
On the one hand, in case of an error, you want a useful message, so you end up with mixed returns (true/string), which is ugly, or returning an array (even uglier). An exception gives you that for free.
On the other hand, a function called check...() should not be expected to throw an exception, because finding out that "this is not a valid thingie" is nothing exceptional and not an error.
The third way would be to call it "throwIfFalse", but that's ugly too....
Hmm....
One possible solution:
interface Checker {
public function check();
public function getMessage();
}
class WhateverChecker implements Checker { ... }
class ClientOfChecker {
public function doStuff() {
$checker = new Checker();
if (! $checker->check() )
throw new Exception($checker->getMessage());
}
}
However, that seems incredibly verbose, and, may I say, Javaesque to me.
There is generally 2 types of function regarding your question:
Pure function that tests whether a condition holds.
Function that ensures a condition holds and alters control flow if it does not.
Different programming language may have different conventions about the naming of both types. Take C++ as an example, one common naming is CHECK_XXX for type 2 and IsXXX for type 1.
Here is an example taken from a tutorial of the google-log library:
CHECK(fp->Write(x) == 4) << "Write failed!";
CHECK_NE(1, 2) << ": The world must be ending!";
Another example is the maktaba utility library for Vimscript , where maktaba#value#IsXXX() is used to test whether the argument is of a certain type while maktaba#ensure#IsXXX() is used to ensure IsXXX holds and throws an exception otherwise.
function! TakeAString(name)
" Ensure argument type is String.
let name = maktaba#ensure#IsString(a:name)
endfunction
if maktaba#value#IsString(name)
" Branch if name is a String.
echo name
endif
So here is the point: choose the one that suits your need best and name the function according to the convention of the language. In terms of use cases of both, roughly, use the type 2 to check pre-condition like argument type and use the type 1 in conditional statements.

Using a return keyword with no return value?

I have been noticing in some PHP design patterns, some authors who write code examples, have return inside the method but it doesn't specify return value .
It just says "return"
Can some one please explain me what is the purpose of doing that? Below is an example
Thank you!
function addListItem(ListItem $listItem){
if(in_array($listItem, $this->listitems, true)){
return;
}
$this->listitems[] = $listItem;
}
That's done for side-effects (IO, altering globals, or the arguments passed by reference, or an object property, like in your example -- $this->listitems[] = $listItem;), or to indicate it's impossible to yield a valid result.
return;
is equivalent to
return null;
The return statement will stop the function immediately after it has been called. Because we do not want any value to be returned like integers, string or booleans, we just stop it so the code will not continue.
This can also be compared to break in a for or while loop.
Well for starters, you may hit an if statement that makes the rest of the code in the method unnecessary.
For example:
if(user->log_in == "")
{
show_error_msg();
return;
}
The "technically more correct" way of writing such code is:
if( !in_array($listItem, $this->listitems, true)) {
$this->listitems[] = $listItem;
}
However, sometimes you may have more complex testing, and proceeding in this manner may result in a single if block spanning several lines with many &&s, or nested if statements that fall off the edge of your screen.
Therefore, it is common to see the pattern of your code, namely "check failure conditions and exit the current block if necessary". This means you can have as few or as many conditions as you want, each with their own failure conditions, and if the code manages to reach the end of it then you're good to go.
In some cases, error handling is useful. Something like:
try {
if( failure condition 1) throw new Exception("Error message 1");
if( failure condition 2) throw new Exception("Error message 2");
// ...
do something here;
}
catch(Exception $e) {
// report error here
}

PHPUnit_Selenium: Don't throw exceptions if element not found?

I am using the PHPUnit_Selenium extension and encounter some unwanted behaviour if an element does not exist:
Selenium Test Case:
$this->type('id=search', $searchTerm);
Test Output:
RuntimeException: Invalid response while accessing the Selenium Server at 'http:
//localhost:4444/selenium-server/driver/': ERROR: Element id=search not
found
So, I get an error but I would like to convert it to a failure instead
I considered this:
try {
$this->type('id=search', $searchTerm);
} catch (RuntimeException $e) {
$this->fail($e->getMessage());
}
But I don't really want to convert all runtime exceptions to failures and don't see a clean way to distinguish them.
An additional assertion would be great but I can't find one that fits my need. Something like:
$this->assertLocatorExists('id=search'); // ???
$this->type('id=search', $searchTerm);
Am I missing something? Or is there another method that I did not think about?
Used versions:
PHPUnit 3.7.14
PHPUnit_Selenium 1.2.12
Selenium Server 2.30.0
Why not do something like this:
$element = $this->byId('search');
//from https://github.com/sebastianbergmann/phpunit-selenium/blob/master/Tests/Selenium2TestCaseTest.php
In java (sorry, I use Selenium in Java) this would throw an exception if the element with id search is not found. I would check the documentation to see if it is the same behavior in php. Otherwise you can try to see if the $element is valid, eg: is_null($element)
For test cases based on SeleniumTestCase, I found the following methods to be useful:
getCssCount($cssSelector)
getXpathCount($xpath)
assertCssCount($cssSelector, $expectedCount)
assertXpathCount($xpath, $expectedCount)
For test cases based on Selenium2TestCase the solution suggested by #Farlan should work, the following methods retrieve an element and throw an exception if no element was found:
byCssSelector($value)
byClassName($value)
byId($value)
byName($value)
byXPath($value)
In my case the tests descend from SeleniumTestCase, so the solution for the example in the question was:
$this->assertCssCount('#search', 1);
Well, you could check the exception message text in the catch block, and re-throw it if it doesn't match Element id=search not found (or a suitable regex).
try {
$this->type('id=search', $searchTerm);
} catch (RuntimeException $e) {
$msg = $e->getMessage();
if(!preg_match('/Element id=[-_a-zA-Z0-9]+ not found/',$msg)) {
throw new RuntimeException($msg);
}
$this->fail($msg);
}
Not ideal, but it would do the trick.
I guess this demonstrates why one should write custom exception classes rather than re-using standard ones.
Or since it's open source, you could, of course, always modify the phpunit Selenium extension to give it a custom exception class.

Categories