+ SimpleTest's web browser component can be used not just + outside of the WebTestCase class, but also + independently of the SimpleTest framework itself. +
+ + ++ You can use the web browser in PHP scripts to confirm + services are up and running, or to extract information + from them at a regular basis. + For example, here is a small script to extract the current number of + open PHP 5 bugs from the PHP web site... +
+<?php + require_once('simpletest/browser.php'); + + $browser = &new SimpleBrowser(); + $browser->get('http://php.net/'); + $browser->clickLink('reporting bugs'); + $browser->clickLink('statistics'); + $page = $browser->clickLink('PHP 5 bugs only'); + preg_match('/status=Open.*?by=Any.*?(\d+)<\/a>/', $page, $matches); + print $matches[1]; +?> ++ There are simpler methods to do this particular example in PHP + of course. + For example you can just use the PHP file() + command against what here is a pretty fixed page. + However, using the web browser for scripts allows authentication, + correct handling of cookies, automatic loading of frames, redirects, + form submission and the ability to examine the page headers. + Such methods are fragile against a site that is constantly + evolving and you would want a more direct way of accessing + data in a permanent set up, but for simple tasks this can provide + a very rapid solution. + +
+ All of the navigation methods used in the + WebTestCase + are present in the SimpleBrowser class, but + the assertions are replaced with simpler accessors. + Here is a full list of the page navigation methods... +
addHeader($header) | Adds a header to every fetch | +
useProxy($proxy, $username, $password) | Use this proxy from now on | +
head($url, $parameters) | Perform a HEAD request | +
get($url, $parameters) | Fetch a page with GET | +
post($url, $parameters) | Fetch a page with POST | +
clickLink($label) | Follows a link by label | +
isLink($label) | See if a link is present by label | +
clickLinkById($id) | Follows a link by attribute | +
isLinkById($id) | See if a link is present by attribut | +
getUrl() | Current URL of page or frame | +
getTitle() | Page title | +
getContent() | Raw page or frame | +
getContentAsText() | HTML removed except for alt text | +
retry() | Repeat the last request | +
back() | Use the browser back button | +
forward() | Use the browser forward button | +
authenticate($username, $password) | Retry page or frame after a 401 response | +
restart($date) | Restarts the browser for a new session | +
ageCookies($interval) | Ages the cookies by the specified time | +
setCookie($name, $value) | Sets an additional cookie | +
getCookieValue($host, $path, $name) | Reads the most specific cookie | +
getCurrentCookieValue($name) | Reads cookie for the current context | +
+ Navigating forms is similar to the + WebTestCase form navigation... +
setField($name, $value) | Sets all form fields with that name | +
setFieldById($id, $value) | Sets all form fields with that id | +
getField($name) | Accessor for a form element value | +
getFieldById($id) | Accessor for a form element value | +
clickSubmit($label) | Submits form by button label | +
clickSubmitByName($name) | Submits form by button attribute | +
clickSubmitById($id) | Submits form by button attribute | +
clickImage($label, $x, $y) | Clicks the image by alt text | +
clickImageByName($name, $x, $y) | Clicks the image by attribute | +
clickImageById($id, $x, $y) | Clicks the image by attribute | +
submitFormById($id) | Submits by the form tag attribute | +
+ Within a page, individual frames can be selected. + If no selection is made then all the frames are merged together + in one large conceptual page. + The content of the current page will be a concatenation of all of the + frames in the order that they were specified in the "frameset" + tags. +
getFrames() | A dump of the current frame structure | +
getFrameFocus() | Current frame label or index | +
setFrameFocusByIndex($choice) | Select a frame numbered from 1 | +
setFrameFocus($name) | Select frame by label | +
clearFrameFocus() | Treat all the frames as a single page | +
+ All of this functionality is great when we actually manage to fetch pages, + but that doesn't always happen. + To help figure out what went wrong, the browser has some methods to + aid in debugging... +
setConnectionTimeout($timeout) | Close the socket on overrun | +
getRequest() | Raw request header of page or frame | +
getHeaders() | Raw response header of page or frame | +
getTransportError() | Any socket level errors in the last fetch | +
getResponseCode() | HTTP response of page or frame | +
getMimeType() | Mime type of page or frame | +
getAuthentication() | Authentication type in 401 challenge header | +
getRealm() | Authentication realm in 401 challenge header | +
setMaximumRedirects($max) | Number of redirects before page is loaded anyway | +
setMaximumNestedFrames($max) | Protection against recursive framesets | +
ignoreFrames() | Disables frames support | +
useFrames() | Enables frames support | +
+
+Complex unit tests with multiple browsers
+
+
+ Anything that could be done in a + WebTestCase can + now be done in a UnitTestCase. + This means that we can freely mix domain object testing with the + web interface... +
+ +class TestOfRegistration extends UnitTestCase { + function testNewUserAddedToAuthenticator() { + $browser = &new SimpleBrowser(); + $browser->get('http://my-site.com/register.php'); + $browser->setField('email', 'me@here'); + $browser->setField('password', 'Secret'); + $browser->clickSubmit('Register'); + + $authenticator = &new Authenticator(); + $member = &$authenticator->findByEmail('me@here'); + $this->assertEqual($member->getPassword(), 'Secret'); + } +} ++ While this may be a useful temporary expediency, I am not a fan + of this type of testing. + The testing has cut across application layers, make it twice as + likely it will need refactoring when the code changes. + +
+ A more useful case of where using the browser directly can be helpful + is where the WebTestCase cannot cope. + An example is where two browsers are needed at the same time. +
++ For example, say we want to disallow multiple simultaneous + usage of a site with the same username. + This test case will do the job... +
+class TestOfSecurity extends UnitTestCase { + function testNoMultipleLoginsFromSameUser() { + $first = &new SimpleBrowser(); + $first->get('http://my-site.com/login.php'); + $first->setField('name', 'Me'); + $first->setField('password', 'Secret'); + $first->clickSubmit('Enter'); + $this->assertEqual($first->getTitle(), 'Welcome'); + + $second = &new SimpleBrowser(); + $second->get('http://my-site.com/login.php'); + $second->setField('name', 'Me'); + $second->setField('password', 'Secret'); + $second->clickSubmit('Enter'); + $this->assertEqual($second->getTitle(), 'Access Denied'); + } +} ++ You can also use the SimpleBrowser class + directly when you want to write test cases using a different + test tool than SimpleTest. + + +