Testing elements by CSS selector

Careful : this documentation refers to un-released code. It's only available in SVN.

Before SimpleTest2 gets a new browser (PHP5 only and DOM based), a new extension made its way to the SimpleTest trunk.

Note : it's already PHP5 only.

Testing for Web2.0

1998 seems a long time ago now : it's the year the the Web Standards Project (WaSP) started fighting for standards.

Nearly ten years later, every web developper is now familiar with CSS : id & class are the new tools of the trade. The tricks you've learned while styling, you can re-use them when testing your web site.

I was about to start with the Flickr home page but then again, this is what the HTML source looks like :

<body>
<div id="beacon"><img src="http://geo.yahoo.com/f?s=792600119&t=7797cfa4695ea4166ba6c8ee269ec1b6" width="0" height="0" alt="" /></div>
<div align="center">
  <table cellspacing="0" border="0" cellpadding="0" class="Photo">
    <tr valign="top"> 
<!-- PHOTO -->
      <td>
[...]

Who said too many tables ? So I picked something else... the SimpleTest home page !

<body>
<div>
  <div id="actions">
    <div id="logo">
      <a href="http://simpletest.org/index.html"><img name="simpletestlogo" src="images/simpletest-logo.png" width="335" height="127" border="0" id="simpletestlogo" alt="" /></a>
    </div>
    <div>
      <div>
        <a href="en/download.html"><img name="simpletestdownload" src="images/simpletest-download.png" width="305" height="109" border="0" id="simpletestdownload" alt="" /></a>
[...]

Basic CSS selectors...

As usual we start with the necessary require_once

<?php
require_once(dirname(__FILE__) . '/../../autorun.php');
require_once(dirname(__FILE__) . '/../dom_tester.php');
?>

The DomTestCase extends the WebTestCase, we can just use it the same way.

<?php
require_once(dirname(__FILE__) . '/../../autorun.php');
require_once(dirname(__FILE__) . '/../dom_tester.php');

class TestOfLiveCssSelectors extends DomTestCase {
  function testGet() {
    $url = 'http://simpletest.org/';
    $this->assertTrue($this->get($url));
    $this->assertEqual($this->getUrl(), $url);
    $this->assertElementsBySelector(
      'h2',
      array('Screenshots', 'Documentation', 'Contributing')
    );
  }
}
?>

I was expecting to get a nice green bar straight away : I did wrote the HTML template after all. Unfortunately it didn't happen, PHP gave me some nice exceptions :

home: /$ php dom_tester_doc_test.php
dom_tester_doc_test.php
Exception 1!
Unexpected PHP error [DOMDocument::loadHTML() [function.DOMDocument-loadHTML]: ID simpletestlogo already defined in Entity, line: 12] severity [E_WARNING] in [/Users/perrick/Sites/simpletest/extensions/dom_tester.php line 103]
in testGet
in TestOfLiveCssSelectors
Exception 2!
Unexpected PHP error [DOMDocument::loadHTML() [function.DOMDocument-loadHTML]: ID simpletestdownload already defined in Entity, line: 16] severity [E_WARNING] in [/Users/perrick/Sites/simpletest/extensions/dom_tester.php line 103]
in testGet
in TestOfLiveCssSelectors
Exception 3!
Unexpected PHP error [DOMDocument::loadHTML() [function.DOMDocument-loadHTML]: ID simpleteststarttesting already defined in Entity, line: 24] severity [E_WARNING] in [/Users/perrick/Sites/simpletest/extensions/dom_tester.php line 103]
in testGet
in TestOfLiveCssSelectors
Exception 4!
Unexpected PHP error [DOMDocument::loadHTML() [function.DOMDocument-loadHTML]: ID simpletestsupport already defined in Entity, line: 38] severity [E_WARNING] in [/Users/perrick/Sites/simpletest/extensions/dom_tester.php line 103]
in testGet
in TestOfLiveCssSelectors
FAILURES!!!
Test cases run: 1/1, Passes: 3, Failures: 0, Exceptions: 4
That's what validation is all about I guess.

Back to the drawing board... A simple fix later, everything is fine.

home: /$ php dom_tester_doc_test.php
dom_tester_doc_test.php
OK
Test cases run: 1/1, Passes: 3, Failures: 0, Exceptions: 0

...and non so basic selectors

If you thought it was easy, we can make things a little bit more difficult - or precise - with attribute selectors :

[...]
class TestOfLiveCssSelectors extends DomTestCase {
  function testGet() {
    $url = 'http://simpletest.org/';
    $this->assertTrue($this->get($url));
    $this->assertEqual($this->getUrl(), $url);
    $this->assertElementsBySelector(
      'h2',
      array('Screenshots', 'Documentation', 'Contributing')
    );
    $this->assertElementsBySelector(
      'a[href="http://simpletest.org/api/"]',
      array('the complete API', 'documented API')
    );
  }
}
[...]

home: /$ php dom_tester_doc_test.php
dom_tester_doc_test.php
OK
Test cases run: 1/1, Passes: 4, Failures: 0, Exceptions: 0

Oh and by the way, combinators do work as well :

[...]
class TestOfLiveCssSelectors extends DomTestCase {
  function testGet() {
    $url = 'http://simpletest.org/';
    $this->assertTrue($this->get($url));
    $this->assertEqual($this->getUrl(), $url);
    $this->assertElementsBySelector(
      'h2',
      array('Screenshots', 'Documentation', 'Contributing')
    );
    $this->assertElementsBySelector(
      'a[href="http://simpletest.org/api/"]',
      array('the complete API', 'documented API')
    );
    $this->assertElementsBySelector(
      'div#content > p > strong',
      array('SimpleTest PHP unit tester')
    );
  }
}
[...]

home: /$ php dom_tester_doc_test.php
dom_tester_doc_test.php
OK
Test cases run: 1/1, Passes: 5, Failures: 0, Exceptions: 0

A Recorder for non-developpers.
Exploring the Recorder results.
The JUnit FAQ has plenty of useful testing advice.
Next is grouping test cases together.
You will need the SimpleTest testing framework for these examples.