3

My question is about phpunit+selenium usage.
The standard usage of this union is

class BlaBlaTest extends PHPUnit_Extensions_SeleniumTestCase
{... }  

OR

class BlaBlaTest extends PHPUnit_Extensions_Selenium2TestCase  
{...}  

The first one (PHPUnit_Extensions_SeleniumTestCase) is not very convinient to use (e.g. there is no such thing as $this->elements('xpath')).
Second(PHPUnit_Extensions_Selenium2TestCase) also has limited functionality (e.g. there is no such functions as waitForPageToLoad() or clickAndWait(), and using something like $this->timeouts()->implicitWait(10000) looks for me like complete nonsense).

Is it possible to use the functional

PHPUnit_Extensions_SeleniumTestCase + PHPUnit_Extensions_Selenium2TestCase

in one test class? Maybe smb knows good alternatives to phpunit+selenium?

Michael Celey
  • 12,645
  • 6
  • 57
  • 62
tarnum26
  • 31
  • 2

4 Answers4

4

Inspired by Dan I've written this for use in PHPUnit_Extensions_Selenium2TestCase and it seems to work ok:

/** 
 * @param string $id - DOM id
 * @param int $wait - maximum (in seconds)
 * @retrn element|false - false on time-out
 */ 
protected function waitForId($id, $wait=30) { 
  for ($i=0; $i <= $wait; $i++) { 
    try{ 
      $x = $this->byId($id); 
      return $x; 
    } 
    catch (Exception $e) { 
      sleep(1); 
    } 
  } 
  return false; 
} 
ErichBSchulz
  • 15,047
  • 5
  • 57
  • 61
  • 1
    Works great for me too! Extended the code with a switch statement on a type variable to accept multiple find methods instead of just ID. This method is a good base to extend to fit your individual needs. :) Could also make something like waitClick, or instead of returning false you could force a failed assertion so your test fails when this method cannot return an element. – nicholeous Feb 19 '14 at 21:58
  • Great, this is simple, clear and very effective solution. I use this try cache loop in different contexts, for example wait for element to be clickable. Thx – Arek Kostrzeba Jan 04 '18 at 13:53
  • look at @Paradiddley's answer – Richard Tyler Miles Feb 19 '20 at 22:19
1

Sorry for resurrecting this but I'd like to hopefully clear up some confusion for anyone stumbling across this.

You're saying that you wanted functionality from RC and WebDriver combined where there are workarounds to it, but I wouldn't recommend it. Firstly you'll need to understand the difference between both frameworks.

My brief definitions...

  • Selenium RC (PHPUnit_Extensions_SeleniumTestCase) is script oriented. By that I mean it will run your tests exactly how you expect the page to respond. This often will require more explicit commands such as the waitForPageToLoad() that you have mentioned when waiting for elements to appear and/or pages to loads.
  • Selenium WebDriver (PHPUnit_Extensions_Selenium2TestCase) uses a more native approach. It cuts off 'the middle-man' and runs your tests through your chosen browsers driver. Using the waitForPageToLoad() example, you wont need to explicitly put that wherever you open a page in your code because the WebDriver already knows when the page is loading and will resume the test when the page load request is complete.

If you need to define an implicit timeout in WebDriver, you will only need to place that in the setUp() method within a base Selenium class that will be extended in your test classes;

class BaseSelenium extends PHPUnit_Extensions_Selenium2TestCase {

     protected function setUp() {

           // Whatever else needs to be in here like setting
           // the host url and port etc.

           $this->setSeleniumServerRequestsTimeout( 100 ); // <- seconds
     }
}

That will happily span across all of your tests and will timeout whenever a page takes longer than that to load.

Although I personally prefer WebDriver over RC (mainly because it's a lot faster!) there is a big difference between the methods available. Whenever I got stuck when recently converting a lot a RC tests to WebDriver I always turned to this first. It's a great reference to nearly every situation.

I hope that helps?

Community
  • 1
  • 1
0

For functions such as waitForPageToLoad() and clickAndWait(), which are unavailable in Selenium2, you can reproduce those functions by using try catch blocks, in conjunction with implicit waits and explicit sleeps.

So, for a function like clickAndWait(), you can define what element you are waiting for, and then check for that element's existence for a set amount of seconds. If the element doesn't exist, the try catch block will stop the error from propagating. If the element does exist, you can continue. If the element doesn't exist after the set amount of time, then bubble up the error.

I would recommend using Selenium2 and then reproducing any functionality that you feel is missing from within your framework.

EXAMPLE:

def wait_for_present(element, retry = 10, seconds = 2)
  for i in 0...retry
    return true if element.present?
    sleep(seconds)
  end
  return false
end
Dan Chan
  • 494
  • 4
  • 14
  • Thanks for your answer! Could you please give me example of code? I would prefer to use smth wich works like an observer, when after page is loaded completely, only then next piece of code will be executed,and not to use smth like sleep() . I have an idea now to use loop which in try catch form checks existing of elements each second, but this approach looks for me like a hack. – tarnum26 Apr 02 '13 at 08:27
  • I've updated my answer with some example Ruby code to help explain my answer. The idea is to combine an implicit wait, such as element.present, into an explicit loop, such as a for loop with a sleep statement included. You can achieve similar techniques by using try catch blocks, if the implicit wait happens to throw an error. – Dan Chan Apr 02 '13 at 17:23
  • 3
    PHPUnit_Extensions_Selenium2TestCase uses webdriver and as you already know from your example `$this->timeouts()->implicitWait(10000)`, it has an implicit timeout. This is the timeout that Selenium will try to find an element. So when an ajax-call is executed, just selecting the result should work most of the time. I'd definitely go the Webdriver-route, it seems more stable on the whole compared to the old RC-way – qrazi Apr 02 '13 at 19:56
  • @qrazi I'd post that as an answer, you nailed it – Fabian Schmengler Apr 04 '13 at 05:50
  • @fab - cant get qrazi's answer to work hence my function below (on 3.8) – ErichBSchulz Jun 19 '13 at 11:31
  • 1
    @qrazi I like that solution! It's clean and simple. The problem arises when you receive errors like " Element is not currently visible and so may not be interacted with" on a site where the element may be loaded and find-able but not ready to be interacted with. In the above solutions you could still catch those exceptions and continue waiting. – nicholeous Feb 19 '14 at 21:27
0

you can try use traits to extend two different classes http://php.net/manual/en/language.oop5.traits.php

    class PHPUnit_Extensions_SeleniumTestCase{
       ...
    }

change PHPUnit_Extensions_Selenium2TestCase class to trait:

 trait PHPUnit_Extensions_Selenium2TestCase {
       ...
    }

    class blabla extends PHPUnit_Extensions_SeleniumTestCase {
        use PHPUnit_Extensions_Selenium2TestCase;

        your tests here..
    }
Dennis
  • 704
  • 1
  • 9
  • 25