source: trunk/server/www/vendors/simpletest/browser.php @ 6

Last change on this file since 6 was 6, checked in by sander, 12 years ago

Added SimpleTest? test framework

File size: 35.3 KB
Line 
1<?php
2/**
3 *  Base include file for SimpleTest
4 *  @package    SimpleTest
5 *  @subpackage WebTester
6 *  @version    $Id: browser.php 1723 2008-04-08 00:34:10Z lastcraft $
7 */
8
9/**#@+
10 *  include other SimpleTest class files
11 */
12require_once(dirname(__FILE__) . '/simpletest.php');
13require_once(dirname(__FILE__) . '/http.php');
14require_once(dirname(__FILE__) . '/encoding.php');
15require_once(dirname(__FILE__) . '/page.php');
16require_once(dirname(__FILE__) . '/selector.php');
17require_once(dirname(__FILE__) . '/frames.php');
18require_once(dirname(__FILE__) . '/user_agent.php');
19/**#@-*/
20
21if (!defined('DEFAULT_MAX_NESTED_FRAMES')) {
22    define('DEFAULT_MAX_NESTED_FRAMES', 3);
23}
24
25/**
26 *    Browser history list.
27 *    @package SimpleTest
28 *    @subpackage WebTester
29 */
30class SimpleBrowserHistory {
31    var $_sequence;
32    var $_position;
33
34    /**
35     *    Starts empty.
36     *    @access public
37     */
38    function SimpleBrowserHistory() {
39        $this->_sequence = array();
40        $this->_position = -1;
41    }
42
43    /**
44     *    Test for no entries yet.
45     *    @return boolean        True if empty.
46     *    @access private
47     */
48    function _isEmpty() {
49        return ($this->_position == -1);
50    }
51
52    /**
53     *    Test for being at the beginning.
54     *    @return boolean        True if first.
55     *    @access private
56     */
57    function _atBeginning() {
58        return ($this->_position == 0) && ! $this->_isEmpty();
59    }
60
61    /**
62     *    Test for being at the last entry.
63     *    @return boolean        True if last.
64     *    @access private
65     */
66    function _atEnd() {
67        return ($this->_position + 1 >= count($this->_sequence)) && ! $this->_isEmpty();
68    }
69
70    /**
71     *    Adds a successfully fetched page to the history.
72     *    @param SimpleUrl $url                 URL of fetch.
73     *    @param SimpleEncoding $parameters     Any post data with the fetch.
74     *    @access public
75     */
76    function recordEntry($url, $parameters) {
77        $this->_dropFuture();
78        array_push(
79                $this->_sequence,
80                array('url' => $url, 'parameters' => $parameters));
81        $this->_position++;
82    }
83
84    /**
85     *    Last fully qualified URL for current history
86     *    position.
87     *    @return SimpleUrl        URL for this position.
88     *    @access public
89     */
90    function getUrl() {
91        if ($this->_isEmpty()) {
92            return false;
93        }
94        return $this->_sequence[$this->_position]['url'];
95    }
96
97    /**
98     *    Parameters of last fetch from current history
99     *    position.
100     *    @return SimpleFormEncoding    Post parameters.
101     *    @access public
102     */
103    function getParameters() {
104        if ($this->_isEmpty()) {
105            return false;
106        }
107        return $this->_sequence[$this->_position]['parameters'];
108    }
109
110    /**
111     *    Step back one place in the history. Stops at
112     *    the first page.
113     *    @return boolean     True if any previous entries.
114     *    @access public
115     */
116    function back() {
117        if ($this->_isEmpty() || $this->_atBeginning()) {
118            return false;
119        }
120        $this->_position--;
121        return true;
122    }
123
124    /**
125     *    Step forward one place. If already at the
126     *    latest entry then nothing will happen.
127     *    @return boolean     True if any future entries.
128     *    @access public
129     */
130    function forward() {
131        if ($this->_isEmpty() || $this->_atEnd()) {
132            return false;
133        }
134        $this->_position++;
135        return true;
136    }
137
138    /**
139     *    Ditches all future entries beyond the current
140     *    point.
141     *    @access private
142     */
143    function _dropFuture() {
144        if ($this->_isEmpty()) {
145            return;
146        }
147        while (! $this->_atEnd()) {
148            array_pop($this->_sequence);
149        }
150    }
151}
152
153/**
154 *    Simulated web browser. This is an aggregate of
155 *    the user agent, the HTML parsing, request history
156 *    and the last header set.
157 *    @package SimpleTest
158 *    @subpackage WebTester
159 */
160class SimpleBrowser {
161    var $_user_agent;
162    var $_page;
163    var $_history;
164    var $_ignore_frames;
165    var $_maximum_nested_frames;
166
167    /**
168     *    Starts with a fresh browser with no
169     *    cookie or any other state information. The
170     *    exception is that a default proxy will be
171     *    set up if specified in the options.
172     *    @access public
173     */
174    function SimpleBrowser() {
175        $this->_user_agent = &$this->_createUserAgent();
176        $this->_user_agent->useProxy(
177                SimpleTest::getDefaultProxy(),
178                SimpleTest::getDefaultProxyUsername(),
179                SimpleTest::getDefaultProxyPassword());
180        $this->_page = &new SimplePage();
181        $this->_history = &$this->_createHistory();
182        $this->_ignore_frames = false;
183        $this->_maximum_nested_frames = DEFAULT_MAX_NESTED_FRAMES;
184    }
185
186    /**
187     *    Creates the underlying user agent.
188     *    @return SimpleFetcher    Content fetcher.
189     *    @access protected
190     */
191    function &_createUserAgent() {
192        $user_agent = &new SimpleUserAgent();
193        return $user_agent;
194    }
195
196    /**
197     *    Creates a new empty history list.
198     *    @return SimpleBrowserHistory    New list.
199     *    @access protected
200     */
201    function &_createHistory() {
202        $history = &new SimpleBrowserHistory();
203        return $history;
204    }
205
206    /**
207     *    Disables frames support. Frames will not be fetched
208     *    and the frameset page will be used instead.
209     *    @access public
210     */
211    function ignoreFrames() {
212        $this->_ignore_frames = true;
213    }
214
215    /**
216     *    Enables frames support. Frames will be fetched from
217     *    now on.
218     *    @access public
219     */
220    function useFrames() {
221        $this->_ignore_frames = false;
222    }
223   
224    /**
225     *    Switches off cookie sending and recieving.
226     *    @access public
227     */
228    function ignoreCookies() {
229        $this->_user_agent->ignoreCookies();
230    }
231   
232    /**
233     *    Switches back on the cookie sending and recieving.
234     *    @access public
235     */
236    function useCookies() {
237        $this->_user_agent->useCookies();
238    }
239
240    /**
241     *    Parses the raw content into a page. Will load further
242     *    frame pages unless frames are disabled.
243     *    @param SimpleHttpResponse $response    Response from fetch.
244     *    @param integer $depth                  Nested frameset depth.
245     *    @return SimplePage                     Parsed HTML.
246     *    @access private
247     */
248    function &_parse($response, $depth = 0) {
249        $page = &$this->_buildPage($response);
250        if ($this->_ignore_frames || ! $page->hasFrames() || ($depth > $this->_maximum_nested_frames)) {
251            return $page;
252        }
253        $frameset = &new SimpleFrameset($page);
254        foreach ($page->getFrameset() as $key => $url) {
255            $frame = &$this->_fetch($url, new SimpleGetEncoding(), $depth + 1);
256            $frameset->addFrame($frame, $key);
257        }
258        return $frameset;
259    }
260   
261    /**
262     *    Assembles the parsing machinery and actually parses
263     *    a single page. Frees all of the builder memory and so
264     *    unjams the PHP memory management.
265     *    @param SimpleHttpResponse $response    Response from fetch.
266     *    @return SimplePage                     Parsed top level page.
267     *    @access protected
268     */
269    function &_buildPage($response) {
270        $builder = &new SimplePageBuilder();
271        $page = &$builder->parse($response);
272        $builder->free();
273        unset($builder);
274        return $page;
275    }
276
277    /**
278     *    Fetches a page. Jointly recursive with the _parse()
279     *    method as it descends a frameset.
280     *    @param string/SimpleUrl $url          Target to fetch.
281     *    @param SimpleEncoding $encoding       GET/POST parameters.
282     *    @param integer $depth                 Nested frameset depth protection.
283     *    @return SimplePage                    Parsed page.
284     *    @access private
285     */
286    function &_fetch($url, $encoding, $depth = 0) {
287        $response = &$this->_user_agent->fetchResponse($url, $encoding);
288        if ($response->isError()) {
289            $page = &new SimplePage($response);
290        } else {
291            $page = &$this->_parse($response, $depth);
292        }
293        return $page;
294    }
295
296    /**
297     *    Fetches a page or a single frame if that is the current
298     *    focus.
299     *    @param SimpleUrl $url                   Target to fetch.
300     *    @param SimpleEncoding $parameters       GET/POST parameters.
301     *    @return string                          Raw content of page.
302     *    @access private
303     */
304    function _load($url, $parameters) {
305        $frame = $url->getTarget();
306        if (! $frame || ! $this->_page->hasFrames() || (strtolower($frame) == '_top')) {
307            return $this->_loadPage($url, $parameters);
308        }
309        return $this->_loadFrame(array($frame), $url, $parameters);
310    }
311
312    /**
313     *    Fetches a page and makes it the current page/frame.
314     *    @param string/SimpleUrl $url            Target to fetch as string.
315     *    @param SimplePostEncoding $parameters   POST parameters.
316     *    @return string                          Raw content of page.
317     *    @access private
318     */
319    function _loadPage($url, $parameters) {
320        $this->_page = &$this->_fetch($url, $parameters);
321        $this->_history->recordEntry(
322                $this->_page->getUrl(),
323                $this->_page->getRequestData());
324        return $this->_page->getRaw();
325    }
326
327    /**
328     *    Fetches a frame into the existing frameset replacing the
329     *    original.
330     *    @param array $frames                    List of names to drill down.
331     *    @param string/SimpleUrl $url            Target to fetch as string.
332     *    @param SimpleFormEncoding $parameters   POST parameters.
333     *    @return string                          Raw content of page.
334     *    @access private
335     */
336    function _loadFrame($frames, $url, $parameters) {
337        $page = &$this->_fetch($url, $parameters);
338        $this->_page->setFrame($frames, $page);
339        return $page->getRaw();
340    }
341
342    /**
343     *    Removes expired and temporary cookies as if
344     *    the browser was closed and re-opened.
345     *    @param string/integer $date   Time when session restarted.
346     *                                  If omitted then all persistent
347     *                                  cookies are kept.
348     *    @access public
349     */
350    function restart($date = false) {
351        $this->_user_agent->restart($date);
352    }
353
354    /**
355     *    Adds a header to every fetch.
356     *    @param string $header       Header line to add to every
357     *                                request until cleared.
358     *    @access public
359     */
360    function addHeader($header) {
361        $this->_user_agent->addHeader($header);
362    }
363
364    /**
365     *    Ages the cookies by the specified time.
366     *    @param integer $interval    Amount in seconds.
367     *    @access public
368     */
369    function ageCookies($interval) {
370        $this->_user_agent->ageCookies($interval);
371    }
372
373    /**
374     *    Sets an additional cookie. If a cookie has
375     *    the same name and path it is replaced.
376     *    @param string $name       Cookie key.
377     *    @param string $value      Value of cookie.
378     *    @param string $host       Host upon which the cookie is valid.
379     *    @param string $path       Cookie path if not host wide.
380     *    @param string $expiry     Expiry date.
381     *    @access public
382     */
383    function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
384        $this->_user_agent->setCookie($name, $value, $host, $path, $expiry);
385    }
386
387    /**
388     *    Reads the most specific cookie value from the
389     *    browser cookies.
390     *    @param string $host        Host to search.
391     *    @param string $path        Applicable path.
392     *    @param string $name        Name of cookie to read.
393     *    @return string             False if not present, else the
394     *                               value as a string.
395     *    @access public
396     */
397    function getCookieValue($host, $path, $name) {
398        return $this->_user_agent->getCookieValue($host, $path, $name);
399    }
400
401    /**
402     *    Reads the current cookies for the current URL.
403     *    @param string $name   Key of cookie to find.
404     *    @return string        Null if there is no current URL, false
405     *                          if the cookie is not set.
406     *    @access public
407     */
408    function getCurrentCookieValue($name) {
409        return $this->_user_agent->getBaseCookieValue($name, $this->_page->getUrl());
410    }
411
412    /**
413     *    Sets the maximum number of redirects before
414     *    a page will be loaded anyway.
415     *    @param integer $max        Most hops allowed.
416     *    @access public
417     */
418    function setMaximumRedirects($max) {
419        $this->_user_agent->setMaximumRedirects($max);
420    }
421
422    /**
423     *    Sets the maximum number of nesting of framed pages
424     *    within a framed page to prevent loops.
425     *    @param integer $max        Highest depth allowed.
426     *    @access public
427     */
428    function setMaximumNestedFrames($max) {
429        $this->_maximum_nested_frames = $max;
430    }
431
432    /**
433     *    Sets the socket timeout for opening a connection.
434     *    @param integer $timeout      Maximum time in seconds.
435     *    @access public
436     */
437    function setConnectionTimeout($timeout) {
438        $this->_user_agent->setConnectionTimeout($timeout);
439    }
440
441    /**
442     *    Sets proxy to use on all requests for when
443     *    testing from behind a firewall. Set URL
444     *    to false to disable.
445     *    @param string $proxy        Proxy URL.
446     *    @param string $username     Proxy username for authentication.
447     *    @param string $password     Proxy password for authentication.
448     *    @access public
449     */
450    function useProxy($proxy, $username = false, $password = false) {
451        $this->_user_agent->useProxy($proxy, $username, $password);
452    }
453
454    /**
455     *    Fetches the page content with a HEAD request.
456     *    Will affect cookies, but will not change the base URL.
457     *    @param string/SimpleUrl $url                Target to fetch as string.
458     *    @param hash/SimpleHeadEncoding $parameters  Additional parameters for
459     *                                                HEAD request.
460     *    @return boolean                             True if successful.
461     *    @access public
462     */
463    function head($url, $parameters = false) {
464        if (! is_object($url)) {
465            $url = new SimpleUrl($url);
466        }
467        if ($this->getUrl()) {
468            $url = $url->makeAbsolute($this->getUrl());
469        }
470        $response = &$this->_user_agent->fetchResponse($url, new SimpleHeadEncoding($parameters));
471        return ! $response->isError();
472    }
473
474    /**
475     *    Fetches the page content with a simple GET request.
476     *    @param string/SimpleUrl $url                Target to fetch.
477     *    @param hash/SimpleFormEncoding $parameters  Additional parameters for
478     *                                                GET request.
479     *    @return string                              Content of page or false.
480     *    @access public
481     */
482    function get($url, $parameters = false) {
483        if (! is_object($url)) {
484            $url = new SimpleUrl($url);
485        }
486        if ($this->getUrl()) {
487            $url = $url->makeAbsolute($this->getUrl());
488        }
489        return $this->_load($url, new SimpleGetEncoding($parameters));
490    }
491
492    /**
493     *    Fetches the page content with a POST request.
494     *    @param string/SimpleUrl $url                Target to fetch as string.
495     *    @param hash/SimpleFormEncoding $parameters  POST parameters.
496     *    @return string                              Content of page.
497     *    @access public
498     */
499    function post($url, $parameters = false) {
500        if (! is_object($url)) {
501            $url = new SimpleUrl($url);
502        }
503        if ($this->getUrl()) {
504            $url = $url->makeAbsolute($this->getUrl());
505        }
506        return $this->_load($url, new SimplePostEncoding($parameters));
507    }
508
509    /**
510     *    Equivalent to hitting the retry button on the
511     *    browser. Will attempt to repeat the page fetch. If
512     *    there is no history to repeat it will give false.
513     *    @return string/boolean   Content if fetch succeeded
514     *                             else false.
515     *    @access public
516     */
517    function retry() {
518        $frames = $this->_page->getFrameFocus();
519        if (count($frames) > 0) {
520            $this->_loadFrame(
521                    $frames,
522                    $this->_page->getUrl(),
523                    $this->_page->getRequestData());
524            return $this->_page->getRaw();
525        }
526        if ($url = $this->_history->getUrl()) {
527            $this->_page = &$this->_fetch($url, $this->_history->getParameters());
528            return $this->_page->getRaw();
529        }
530        return false;
531    }
532
533    /**
534     *    Equivalent to hitting the back button on the
535     *    browser. The browser history is unchanged on
536     *    failure. The page content is refetched as there
537     *    is no concept of content caching in SimpleTest.
538     *    @return boolean     True if history entry and
539     *                        fetch succeeded
540     *    @access public
541     */
542    function back() {
543        if (! $this->_history->back()) {
544            return false;
545        }
546        $content = $this->retry();
547        if (! $content) {
548            $this->_history->forward();
549        }
550        return $content;
551    }
552
553    /**
554     *    Equivalent to hitting the forward button on the
555     *    browser. The browser history is unchanged on
556     *    failure. The page content is refetched as there
557     *    is no concept of content caching in SimpleTest.
558     *    @return boolean     True if history entry and
559     *                        fetch succeeded
560     *    @access public
561     */
562    function forward() {
563        if (! $this->_history->forward()) {
564            return false;
565        }
566        $content = $this->retry();
567        if (! $content) {
568            $this->_history->back();
569        }
570        return $content;
571    }
572
573    /**
574     *    Retries a request after setting the authentication
575     *    for the current realm.
576     *    @param string $username    Username for realm.
577     *    @param string $password    Password for realm.
578     *    @return boolean            True if successful fetch. Note
579     *                               that authentication may still have
580     *                               failed.
581     *    @access public
582     */
583    function authenticate($username, $password) {
584        if (! $this->_page->getRealm()) {
585            return false;
586        }
587        $url = $this->_page->getUrl();
588        if (! $url) {
589            return false;
590        }
591        $this->_user_agent->setIdentity(
592                $url->getHost(),
593                $this->_page->getRealm(),
594                $username,
595                $password);
596        return $this->retry();
597    }
598
599    /**
600     *    Accessor for a breakdown of the frameset.
601     *    @return array   Hash tree of frames by name
602     *                    or index if no name.
603     *    @access public
604     */
605    function getFrames() {
606        return $this->_page->getFrames();
607    }
608
609    /**
610     *    Accessor for current frame focus. Will be
611     *    false if no frame has focus.
612     *    @return integer/string/boolean    Label if any, otherwise
613     *                                      the position in the frameset
614     *                                      or false if none.
615     *    @access public
616     */
617    function getFrameFocus() {
618        return $this->_page->getFrameFocus();
619    }
620
621    /**
622     *    Sets the focus by index. The integer index starts from 1.
623     *    @param integer $choice    Chosen frame.
624     *    @return boolean           True if frame exists.
625     *    @access public
626     */
627    function setFrameFocusByIndex($choice) {
628        return $this->_page->setFrameFocusByIndex($choice);
629    }
630
631    /**
632     *    Sets the focus by name.
633     *    @param string $name    Chosen frame.
634     *    @return boolean        True if frame exists.
635     *    @access public
636     */
637    function setFrameFocus($name) {
638        return $this->_page->setFrameFocus($name);
639    }
640
641    /**
642     *    Clears the frame focus. All frames will be searched
643     *    for content.
644     *    @access public
645     */
646    function clearFrameFocus() {
647        return $this->_page->clearFrameFocus();
648    }
649
650    /**
651     *    Accessor for last error.
652     *    @return string        Error from last response.
653     *    @access public
654     */
655    function getTransportError() {
656        return $this->_page->getTransportError();
657    }
658
659    /**
660     *    Accessor for current MIME type.
661     *    @return string    MIME type as string; e.g. 'text/html'
662     *    @access public
663     */
664    function getMimeType() {
665        return $this->_page->getMimeType();
666    }
667
668    /**
669     *    Accessor for last response code.
670     *    @return integer    Last HTTP response code received.
671     *    @access public
672     */
673    function getResponseCode() {
674        return $this->_page->getResponseCode();
675    }
676
677    /**
678     *    Accessor for last Authentication type. Only valid
679     *    straight after a challenge (401).
680     *    @return string    Description of challenge type.
681     *    @access public
682     */
683    function getAuthentication() {
684        return $this->_page->getAuthentication();
685    }
686
687    /**
688     *    Accessor for last Authentication realm. Only valid
689     *    straight after a challenge (401).
690     *    @return string    Name of security realm.
691     *    @access public
692     */
693    function getRealm() {
694        return $this->_page->getRealm();
695    }
696
697    /**
698     *    Accessor for current URL of page or frame if
699     *    focused.
700     *    @return string    Location of current page or frame as
701     *                      a string.
702     */
703    function getUrl() {
704        $url = $this->_page->getUrl();
705        return $url ? $url->asString() : false;
706    }
707
708    /**
709     *    Accessor for base URL of page if set via BASE tag
710     *    @return string    base URL
711     */
712    function getBaseUrl() {
713        $url = $this->_page->getBaseUrl();
714        return $url ? $url->asString() : false;
715    }
716
717    /**
718     *    Accessor for raw bytes sent down the wire.
719     *    @return string      Original text sent.
720     *    @access public
721     */
722    function getRequest() {
723        return $this->_page->getRequest();
724    }
725
726    /**
727     *    Accessor for raw header information.
728     *    @return string      Header block.
729     *    @access public
730     */
731    function getHeaders() {
732        return $this->_page->getHeaders();
733    }
734
735    /**
736     *    Accessor for raw page information.
737     *    @return string      Original text content of web page.
738     *    @access public
739     */
740    function getContent() {
741        return $this->_page->getRaw();
742    }
743
744    /**
745     *    Accessor for plain text version of the page.
746     *    @return string      Normalised text representation.
747     *    @access public
748     */
749    function getContentAsText() {
750        return $this->_page->getText();
751    }
752
753    /**
754     *    Accessor for parsed title.
755     *    @return string     Title or false if no title is present.
756     *    @access public
757     */
758    function getTitle() {
759        return $this->_page->getTitle();
760    }
761
762    /**
763     *    Accessor for a list of all links in current page.
764     *    @return array   List of urls with scheme of
765     *                    http or https and hostname.
766     *    @access public
767     */
768    function getUrls() {
769        return $this->_page->getUrls();
770    }
771
772    /**
773     *    Sets all form fields with that name.
774     *    @param string $label   Name or label of field in forms.
775     *    @param string $value   New value of field.
776     *    @return boolean        True if field exists, otherwise false.
777     *    @access public
778     */
779    function setField($label, $value, $position=false) {
780        return $this->_page->setField(new SimpleByLabelOrName($label), $value, $position);
781    }
782
783    /**
784     *    Sets all form fields with that name. Will use label if
785     *    one is available (not yet implemented).
786     *    @param string $name    Name of field in forms.
787     *    @param string $value   New value of field.
788     *    @return boolean        True if field exists, otherwise false.
789     *    @access public
790     */
791    function setFieldByName($name, $value, $position=false) {
792        return $this->_page->setField(new SimpleByName($name), $value, $position);
793    }
794
795    /**
796     *    Sets all form fields with that id attribute.
797     *    @param string/integer $id   Id of field in forms.
798     *    @param string $value        New value of field.
799     *    @return boolean             True if field exists, otherwise false.
800     *    @access public
801     */
802    function setFieldById($id, $value) {
803        return $this->_page->setField(new SimpleById($id), $value);
804    }
805
806    /**
807     *    Accessor for a form element value within the page.
808     *    Finds the first match.
809     *    @param string $label       Field label.
810     *    @return string/boolean     A value if the field is
811     *                               present, false if unchecked
812     *                               and null if missing.
813     *    @access public
814     */
815    function getField($label) {
816        return $this->_page->getField(new SimpleByLabelOrName($label));
817    }
818
819    /**
820     *    Accessor for a form element value within the page.
821     *    Finds the first match.
822     *    @param string $name        Field name.
823     *    @return string/boolean     A string if the field is
824     *                               present, false if unchecked
825     *                               and null if missing.
826     *    @access public
827     */
828    function getFieldByName($name) {
829        return $this->_page->getField(new SimpleByName($name));
830    }
831
832    /**
833     *    Accessor for a form element value within the page.
834     *    @param string/integer $id  Id of field in forms.
835     *    @return string/boolean     A string if the field is
836     *                               present, false if unchecked
837     *                               and null if missing.
838     *    @access public
839     */
840    function getFieldById($id) {
841        return $this->_page->getField(new SimpleById($id));
842    }
843
844    /**
845     *    Clicks the submit button by label. The owning
846     *    form will be submitted by this.
847     *    @param string $label    Button label. An unlabeled
848     *                            button can be triggered by 'Submit'.
849     *    @param hash $additional Additional form data.
850     *    @return string/boolean  Page on success.
851     *    @access public
852     */
853    function clickSubmit($label = 'Submit', $additional = false) {
854        if (! ($form = &$this->_page->getFormBySubmit(new SimpleByLabel($label)))) {
855            return false;
856        }
857        $success = $this->_load(
858                $form->getAction(),
859                $form->submitButton(new SimpleByLabel($label), $additional));
860        return ($success ? $this->getContent() : $success);
861    }
862
863    /**
864     *    Clicks the submit button by name attribute. The owning
865     *    form will be submitted by this.
866     *    @param string $name     Button name.
867     *    @param hash $additional Additional form data.
868     *    @return string/boolean  Page on success.
869     *    @access public
870     */
871    function clickSubmitByName($name, $additional = false) {
872        if (! ($form = &$this->_page->getFormBySubmit(new SimpleByName($name)))) {
873            return false;
874        }
875        $success = $this->_load(
876                $form->getAction(),
877                $form->submitButton(new SimpleByName($name), $additional));
878        return ($success ? $this->getContent() : $success);
879    }
880
881    /**
882     *    Clicks the submit button by ID attribute of the button
883     *    itself. The owning form will be submitted by this.
884     *    @param string $id       Button ID.
885     *    @param hash $additional Additional form data.
886     *    @return string/boolean  Page on success.
887     *    @access public
888     */
889    function clickSubmitById($id, $additional = false) {
890        if (! ($form = &$this->_page->getFormBySubmit(new SimpleById($id)))) {
891            return false;
892        }
893        $success = $this->_load(
894                $form->getAction(),
895                $form->submitButton(new SimpleById($id), $additional));
896        return ($success ? $this->getContent() : $success);
897    }
898   
899    /**
900     *    Tests to see if a submit button exists with this
901     *    label.
902     *    @param string $label    Button label.
903     *    @return boolean         True if present.
904     *    @access public
905     */
906    function isSubmit($label) {
907        return (boolean)$this->_page->getFormBySubmit(new SimpleByLabel($label));
908    }
909
910    /**
911     *    Clicks the submit image by some kind of label. Usually
912     *    the alt tag or the nearest equivalent. The owning
913     *    form will be submitted by this. Clicking outside of
914     *    the boundary of the coordinates will result in
915     *    a failure.
916     *    @param string $label    ID attribute of button.
917     *    @param integer $x       X-coordinate of imaginary click.
918     *    @param integer $y       Y-coordinate of imaginary click.
919     *    @param hash $additional Additional form data.
920     *    @return string/boolean  Page on success.
921     *    @access public
922     */
923    function clickImage($label, $x = 1, $y = 1, $additional = false) {
924        if (! ($form = &$this->_page->getFormByImage(new SimpleByLabel($label)))) {
925            return false;
926        }
927        $success = $this->_load(
928                $form->getAction(),
929                $form->submitImage(new SimpleByLabel($label), $x, $y, $additional));
930        return ($success ? $this->getContent() : $success);
931    }
932
933    /**
934     *    Clicks the submit image by the name. Usually
935     *    the alt tag or the nearest equivalent. The owning
936     *    form will be submitted by this. Clicking outside of
937     *    the boundary of the coordinates will result in
938     *    a failure.
939     *    @param string $name     Name attribute of button.
940     *    @param integer $x       X-coordinate of imaginary click.
941     *    @param integer $y       Y-coordinate of imaginary click.
942     *    @param hash $additional Additional form data.
943     *    @return string/boolean  Page on success.
944     *    @access public
945     */
946    function clickImageByName($name, $x = 1, $y = 1, $additional = false) {
947        if (! ($form = &$this->_page->getFormByImage(new SimpleByName($name)))) {
948            return false;
949        }
950        $success = $this->_load(
951                $form->getAction(),
952                $form->submitImage(new SimpleByName($name), $x, $y, $additional));
953        return ($success ? $this->getContent() : $success);
954    }
955
956    /**
957     *    Clicks the submit image by ID attribute. The owning
958     *    form will be submitted by this. Clicking outside of
959     *    the boundary of the coordinates will result in
960     *    a failure.
961     *    @param integer/string $id    ID attribute of button.
962     *    @param integer $x            X-coordinate of imaginary click.
963     *    @param integer $y            Y-coordinate of imaginary click.
964     *    @param hash $additional      Additional form data.
965     *    @return string/boolean       Page on success.
966     *    @access public
967     */
968    function clickImageById($id, $x = 1, $y = 1, $additional = false) {
969        if (! ($form = &$this->_page->getFormByImage(new SimpleById($id)))) {
970            return false;
971        }
972        $success = $this->_load(
973                $form->getAction(),
974                $form->submitImage(new SimpleById($id), $x, $y, $additional));
975        return ($success ? $this->getContent() : $success);
976    }
977   
978    /**
979     *    Tests to see if an image exists with this
980     *    title or alt text.
981     *    @param string $label    Image text.
982     *    @return boolean         True if present.
983     *    @access public
984     */
985    function isImage($label) {
986        return (boolean)$this->_page->getFormByImage(new SimpleByLabel($label));
987    }
988
989    /**
990     *    Submits a form by the ID.
991     *    @param string $id       The form ID. No submit button value
992     *                            will be sent.
993     *    @return string/boolean  Page on success.
994     *    @access public
995     */
996    function submitFormById($id) {
997        if (! ($form = &$this->_page->getFormById($id))) {
998            return false;
999        }
1000        $success = $this->_load(
1001                $form->getAction(),
1002                $form->submit());
1003        return ($success ? $this->getContent() : $success);
1004    }
1005
1006    /**
1007     *    Finds a URL by label. Will find the first link
1008     *    found with this link text by default, or a later
1009     *    one if an index is given. The match ignores case and
1010     *    white space issues.
1011     *    @param string $label     Text between the anchor tags.
1012     *    @param integer $index    Link position counting from zero.
1013     *    @return string/boolean   URL on success.
1014     *    @access public
1015     */
1016    function getLink($label, $index = 0) {
1017        $urls = $this->_page->getUrlsByLabel($label);
1018        if (count($urls) == 0) {
1019            return false;
1020        }
1021        if (count($urls) < $index + 1) {
1022            return false;
1023        }
1024        return $urls[$index];
1025    }
1026
1027    /**
1028     *    Follows a link by label. Will click the first link
1029     *    found with this link text by default, or a later
1030     *    one if an index is given. The match ignores case and
1031     *    white space issues.
1032     *    @param string $label     Text between the anchor tags.
1033     *    @param integer $index    Link position counting from zero.
1034     *    @return string/boolean   Page on success.
1035     *    @access public
1036     */
1037    function clickLink($label, $index = 0) {
1038        $url = $this->getLink($label, $index);
1039        if ($url === false) {
1040            return false;
1041        }
1042        $this->_load($url, new SimpleGetEncoding());
1043        return $this->getContent();
1044    }
1045   
1046    /**
1047     *    Finds a link by id attribute.
1048     *    @param string $id        ID attribute value.
1049     *    @return string/boolean   URL on success.
1050     *    @access public
1051     */
1052    function getLinkById($id) {
1053        return $this->_page->getUrlById($id);
1054    }
1055
1056    /**
1057     *    Follows a link by id attribute.
1058     *    @param string $id        ID attribute value.
1059     *    @return string/boolean   Page on success.
1060     *    @access public
1061     */
1062    function clickLinkById($id) {
1063        if (! ($url = $this->getLinkById($id))) {
1064            return false;
1065        }
1066        $this->_load($url, new SimpleGetEncoding());
1067        return $this->getContent();
1068    }
1069
1070    /**
1071     *    Clicks a visible text item. Will first try buttons,
1072     *    then links and then images.
1073     *    @param string $label        Visible text or alt text.
1074     *    @return string/boolean      Raw page or false.
1075     *    @access public
1076     */
1077    function click($label) {
1078        $raw = $this->clickSubmit($label);
1079        if (! $raw) {
1080            $raw = $this->clickLink($label);
1081        }
1082        if (! $raw) {
1083            $raw = $this->clickImage($label);
1084        }
1085        return $raw;
1086    }
1087
1088    /**
1089     *    Tests to see if a click target exists.
1090     *    @param string $label    Visible text or alt text.
1091     *    @return boolean         True if target present.
1092     *    @access public
1093     */
1094    function isClickable($label) {
1095        return $this->isSubmit($label) || ($this->getLink($label) !== false) || $this->isImage($label);
1096    }
1097}
1098?>
Note: See TracBrowser for help on using the repository browser.