Chapter 7. Having Fun Doing Browser Testing

We have finally arrived at the last stage of testing: acceptance testing. This is the topmost way of testing your application with Codeception in Yii.

As we saw in the initial chapters , functional and acceptance tests are quite similar in form and implementation, so you won't see anything particularly new in this chapter.

It is important to grasp the nature of the tests that we are going to create. We can recall from Chapter 6, Testing the API – PHPBrowser to the Rescue, that functional tests are used to ensure the technical correctness of what we've built from a higher standpoint than unit tests. Whereas acceptance tests are the best way of ensuring that the acceptance criteria that were defined at the very beginning are still standing after everything is implemented and put together.

In this chapter, we are going to review the existing tests, install and configure Selenium, and then implement a small feature that will tie everything together with the work that has already been done.

In this chapter, we will discuss two main topics:

  • Introducing Selenium WebDriver
  • Creating acceptance tests

Introducing Selenium WebDriver

Yii is shipped with some acceptance tests. They cover the same elements as the functional tests that we've already seen. The only difference between these two tests is technical, and by looking at the configuration you can see that they've been configured to run with PHPBrowser. This setup may be good enough for you, or it may even be better because PHPBrowser runs faster than the available acceptance testing suites.

Setting aside PHPBrowser, which we've covered in Chapter 6, Testing the API – PHPBrowser to the Rescue, Codeception can be used with other testing suites, which can perform more realistic frontend tests, including the JavaScript interaction.

Two of the choices you can have are Selenium WebDriver and PhantomJS. We won't touch PhantomJS, and it should be sufficient to know that it is a headless browser testing suite, which uses the WebDriver interface definition.

Selenium WebDriver is also known as Selenium 2.0 + WebDriver. Together with Cucumber, it is probably the most well-known frontend testing tool available. Their use has been improved by some big companies, such as Google. They are stable and have lots of features.

This is a somewhat natural evolution of Selenium 1.0, which had limitations, such as using JavaScript for interacting with web pages. For this reason, it was running on the JavaScript sandbox. This meant that, in order to get around the same-origin policy, it had to run in conjunction with a Selenium RC server, which had some issues with the browser setup.

Now the Selenium Server has replaced the RC, while remaining retro-compatible and supporting WebDriver natively.

WebDriver uses a native implementation of the browser to interact with it. This means that it might not always be available for a specific combination of language /device. However, it provides the best flexibility for controlling a page without needing emulation.

Codeception uses a PHP implementation called php-webdriver, which was developed by Facebook; its source code and issue tracker can be found at https://github.com/facebook/php-webdriver.

In its simplest implementation and configuration, the Selenium Server just listens for calls as a service on a specific machine, and fires up the browser on the request to perform the tests.

So, as a first step, we need to install the Selenium Server, run it, configure it in Codeception, adjust the already existing tests such that they work with it, and then add the new tests to it.

Installing and running Selenium Server

From version 1.7 onwards, Codeception includes the out-of-the-box php-webdriver library.

As reported in the documentation, which can be found either from Codeception (http://codeception.com/11-20-2013/webdriver-tests-with-codeception.html) or from the official page of Selenium (http://docs.seleniumhq.org/docs/03_webdriver.jsp), you need to download the server binary and then run it on the machine from, which you intend to run your browser.

Head to http://www.seleniumhq.org/download/ and download the latest version of the software. In my case, it would be selenium-server-standalone-2.44.0.jar.

Where you save it doesn't matter because once it starts, its server will be listening to any network interface:

$ java -jar selenium-server-standalone-2.44.0.jar
22:03:31.892 INFO - Launching a standalone server
22:03:31.980 INFO - Java: Oracle Corporation 24.65-b04
22:03:31.980 INFO - OS: Linux 3.17.1 amd64
22:03:32.002 INFO - v2.44.0, with Core v2.44.0. Built from revision 76d78cf
...

Configuring Yii to work with Selenium

In order to have Codeception automatically pick up and use WebDriver, we need to adjust our acceptance suite configuration:

# tests/codeception/acceptance.suite.yml
class_name: AcceptanceTester
modules:
    enabled:
        - WebDriver
    config:
        WebDriver:
            url: 'http://basic-dev.yii2.sandbox'
            browser: firefox
            host: 192.168.56.1
            restart: true
            window_size: 1024x768

This is a straightforward process. We need to replace the PHPBrowser module with WebDriver and configure it.

  • url (required): This is the hostname used to connect to your application to perform the tests.
  • browser (required): This will specify the browser that you want to use. Some other drivers are also available for mobile phones (Android and iOS), and more information about these can be obtained from the online Selenium documentation, available at http://docs.seleniumhq.org/docs/03_webdriver.jsp#selenium-webdriver-s-drivers.
  • host: This key specifies the machine that will run the Selenium Server. By default, it will connect to your localhost. For example, I am using the VirtualBox host machine IP address. You can also specify the port and by default, it will use 4444.
  • restart: This tells WebDriver to reset a session when a test is performed. This is particularly handy if you don't want a state to be carried over from one test to another. For instance, you can use this when you need to (re)set the cookies to test the auto login functionality.
  • window_size: This just specifies the size of the window.

There are other options, some of which will be quite handy for testing with multiple browsers. In particular, you have the ability to set the desired capabilities for Selenium 2.0, such as being able to pass a specific profile for the browser (quite handy when performing regression testing) and so on. More information about the WebDriver module, albeit not as much as I'd love to see, can be found on the Codeception documentation page at http://codeception.com/docs/modules/WebDriver.

Implementing WebDriver-led tests

Before we start implementing the interface that will hook into the API, which we implemented in Chapter 6, Testing the API – PHPBrowser to the Rescue, it would be quite useful to look at the existing acceptance tests and see if there's anything new that we need to take into consideration.

You will find four tests: HomeCept, AboutCept, LoginCept, and ContactCept.

As stated previously, the syntax is not unusual, and we can see that the level of knowledge of the underlying structure is more limited than the functional tests that we've covered.

The important thing that we need to stress on once again is that all the actions that our AcceptanceTester can perform on the page, such as click(), fillField(), and the assertions that it can perform, such as see(), seeLink() and so on, accept a so-called Locator as one of its actual parameters.

The Locator parameter can be either a string or an array.

When passed as a string or a fuzzy locator, as it is called in the Codeception terminology, it tries to guess what you're looking for by formally going through a series of steps. If you write click('foo'), then it will do the following:

  1. It tries to find the element with the ID #foo.
  2. It tries to find the class .foo.
  3. Then, it interprets it as an XPath expression.
  4. Finally, it will throw an ElementNotFound exception.

You can be more prescriptive when using the array notation or a strict locator.

  • ['id' => 'foo'] matches <div id="foo">
  • ['name' => 'foo'] matches <div name="foo">
  • ['css' => 'input[type=input][value=foo]'] matches <input type="input" value="foo">
  • ['xpath' => "//input[@type='submit'][contains(@value, 'foo')]"] matches <input type="submit" value="foobar">
  • ['link' => 'Click here'] matches <a href="google.com">Click here</a>
  • ['class' => 'foo'] matches <div class="foo">

The preceding examples have been taken from the Codeception documentation, which can be found at http://codeception.com/docs/modules/WebDriver.

This explains clearly how to interact with the webpage. Now, the other important bit can be found in the already existing tests, such as LoginCept and ContactCept. Here, right before asserting the presence of the validation errors, we have the following condition-led statement:

if (method_exists($I, 'wait')) {
    $I->wait(3); // only for selenium
}

Selenium introduces two types of wait: an implicit one and an explicit one. These cause the information to be fetched from the server, and then this information is interpreted and rendered.

The implicit wait can be configured in the acceptance.suite.yml file, and it silently tells Selenium to poll for X seconds if the element it's looking for is not immediately available. By default, no implicit wait is set.

The explicit wait is similar to the preceding code snippet. Doing a simple $I->wait(X) triggers a sleep(), and allows the browser to perform the required operation. For example, it would help the browser in completing animations or finishing fetching and manipulating the server-side data.

There are other ways in which you can wait for something, and some of these ways can be a little more proactive, such as waitForElement(), waitForElementChange(), waitForElementVisible() and waitForElementNotVisible(). All these methods take a locator, using the aforementioned format, and a timeout in seconds as parameters. We will see how we can use these later on.

There are other methods provided by the WebDriver Codeception module that you can use, along with the ability to debug your tests, in case something doesn't go as you want.

Now, let's try to run the available tests and see them pass:

$ ../vendor/bin/codecept run acceptance
Codeception PHP Testing Framework v2.0.9
Powered by PHPUnit 4.6-dev by Sebastian Bergmann and contributors.

Acceptance Tests (5) --------------------------------------------------------------
Trying to ensure that about works (AboutCept) Ok
Trying to ensure that contact works (ContactCept) Ok
Trying to ensure that home page works (HomeCept) Ok
Trying to ensure that login works (LoginCept) Ok
--------------------------------------------------------------

Time: 38.54 seconds, Memory: 13.00Mb

OK (4 tests, 23 assertions)

Note

Depending on which machine you'll be using for running these tests, their speed will change sensibly, although it will never be as fast as it's when performing unit tests, mostly because the whole browser stack has to be started for running these tests.

You will briefly see the browser opening and closing several times while performing the tests. Everything should look good at the end, and if it doesn't, then look into the tests/codeception/_output/ folder. Here, you will find a markup and a screenshot of the page taken at the time of the failure. This debugging behavior is also found in the functional tests while using PHPBrowser.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset