1 package Test::Harness::Selenium;
5 use Socialtext::WikiFixture::Selenese;
6 use HTML::TableExtract;
13 package Test::Builder;
15 use Class::Method::Modifiers;
16 use ExtUtils::MakeMaker qw(prompt);
18 if (!$ENV{AUTOMATED_TESTING}) {
20 my ($orig, $self) = (shift, shift);
21 my $res = $self->$orig(@_);
23 if ('y' eq prompt "Well that didn't work, did it. Bail out?", 'y') {
33 my ($class, $self) = @_;
35 $ENV{DISPLAY} = $self->{xvnc};
36 my $xvnc_pid = fork();
37 if(!defined $xvnc_pid) {
38 die "couldn't fork xvnc: $!";
41 $self->{xvnc_pid} = $xvnc_pid;
44 exec("vncserver", $self->{xvnc});
52 $self->{server_pid} = fork();
53 if(!defined $self->{server_pid}) {
56 if($self->{server_pid} > 0) {
60 $self->{src} = Socialtext::WikiFixture::Selenese->new(
61 host => $self->{host},
62 port => $self->{port},
63 browser => $self->{browser},
64 browser_url => $self->{browser_url},
68 if(!defined $self->{src}) {
75 die "timed out waiting for selenium server to start" if $tries == 5;
77 elsif($self->{server_pid} == 0) {
78 # muttermutter, can't specify a host for selenium
79 exec("$^X -MAlien::SeleniumRC -e 'Alien::SeleniumRC::start(q{-port $self->{port}})'");
85 # okay, we're done, kill the server.
86 get("http://localhost:$self->{port}/selenium-server/driver/?cmd=shutDownSeleniumServer");
92 my ($self, $dir) = @_;
93 my @tests = File::Find::Rule->file()->name('*.html')->in($dir);
94 for my $test (@tests) {
96 $self->run_tests_for($test);
102 my ($self, $html_file) = @_;
103 my $rows = $self->get_rows_for($html_file);
104 $self->{src}->run_test_table($rows);
107 my $te = HTML::TableExtract->new;
109 my ($self, $html_file) = @_;
110 my $html = io($html_file)->all;
112 my $table = ($te->tables)[0];
114 [ map { (!defined $_ or $_ eq "\240") ? () : $_ } @$_ ]
115 } grep { defined $_->[1] } $table->rows;
121 if(exists $self->{xvnc_pid}) {
122 kill("KILL", $self->{xvnc_pid});
132 Test::Harness::Selenium - Test your app with Selenium
137 my $ths = Test::Harness::Selenium->new(
139 host => 'selenium_xvnc_server',
141 start => 1, # start xvnc and selenium RC via ssh(1)
143 browser => '*firefox',
144 # app_base is relative from the machine running selenium_rc
145 app_base => 'http://10.0.0.5:3000/',
146 app_start_cmd => 'script/myapp_server.pl -p 3000',
148 # HTML tables as emitted by the Selenium IDE
149 $ths->test_directory('t/selenium_corpus');
152 # or, if you've got a selenium server already running (say, on a designer's
154 my $ths = Test::Harness::Selenium->new(
156 host => 'designers_machine',
158 start => 0, # they've already got the RC running
160 browser => '*iexplore', # can't live with it, can't live without it
161 app_base => 'http://10.0.0.5:3000/',
162 app_start_cmd => 'script/myapp_server.pl -p 3000',
165 $ths->test_directory('t/selenium_corpus');
169 C<Test::Harness::Selenium> provides an abstracted way of doing Web app testing
170 using the Selenium framework. It will connect to a running Selenium RC server,
171 or start one using ssh(1) to connect to a machine and then launching the RC
172 server and an xvnc(1) instance in which to run the given browser. After the
173 connection is established, Test::Harness::Selenium will read the specified HTML
174 files from disk and massage them into a format that
175 L<Socialtext::WikiFixture::Selenese> can parse and send to the Selenium RC
176 server. The RC server will then script the browser to do the actions described
177 in the HTML files. These actions return results, which Test::Harness::Selenium
178 then interprets as passing or failing as appropriate.
186 =item arguments: %attrs
188 =item Return value: new Test::Harness::Selenium object
192 Constructor. Accepts a list of key/value pairs according to the following:
198 Hashref. Accepts the keys host, port, start. host and port describe the server
199 on which to start/find the Selenium RC server and possibly the xvnc server.
200 start is a Boolean indicating whether to start the Selenium RC server and xvnc
205 Scalar. The browser to use for testing the app. Must be in a form that Selenium
206 RC understands (e.g. '*firefox'); see the Selenium docs for more info.
210 Scalar. The URL, relative to the machine running Selenium RC, for the base of
211 the app. All requests made to the app are relative to this URL.
215 Scalar. This command will be run by start_app_server to run the app server to
220 =head2 test_directory
222 =item arguments: $dir
224 =item Return value: None
226 Object method. test_directory will use L<File::Find::Rule> to find all C<< .html >>
227 files in the given directory, and then formats massages them into data
228 structures that L<Socialtext::WikiFixture::Selenese> can send to the Selenium RC
229 server. test_directory will then output appropriate TAP according to whether the
230 tests and checks passed or failed, respectively.
234 =item arguments: $html_file
236 =item Return value: None
238 run_tests_for is called by test_directory for each C<< .html >> file it finds in
241 =head2 start_app_server, start_app_server
243 =item Arguments: None
245 =item Return value: None
247 Start and stop the app server using the command given to the constructor.
249 =head2 start_selenium_server, start_selenium_server
251 =item Arguments: None
253 =item Return value: None
255 Start and stop the selenium / xvnc servers using the params given to the
260 =head2 SELENIUM_RC_HOST, SELENIUM_RC_PORT, SELENIUM_RC_START
262 These values override the matching values in the selenium_rc hashref passed to
267 Chris Nehren <c.nehren/ths@shadowcat.co.uk>, Matt S. Trout <mst@shadowcat.co.uk>
271 No one, yet. Patches most welcome!
275 Copyright (c) 2011 the Test::Harness::Selenium "AUTHOR" and
276 "CONTRIBUTORS" as listed above.
280 This library is free software and may be distributed under the same terms as