1 package Test::WWW::Selenium::Catalyst;
7 use Test::WWW::Selenium;
11 BEGIN { $ENV{CATALYST_ENGINE} ||= 'HTTP'; }
13 local $SIG{CHLD} = 'IGNORE';
15 our $DEBUG = $ENV{CATALYST_DEBUG};
16 our $app; # app name (MyApp)
17 our $sel_pid; # pid of selenium server
18 our $app_pid; # pid of myapp server
23 Test::WWW::Selenium::Catalyst - Test your Catalyst application with Selenium
27 our $VERSION = '0.06';
29 =head1 DEVELOPERISH RELEASE
31 This is still a test release. It's working for me in production, but
32 it depends on a Java application (SeleniumRC), which can be
33 unreliable. On my Debian system, I had to put C<firefox-bin> in my
34 path, and add C</usr/lib/firefox> to C<LD_LIBRARY_PATH>. Every distro
35 and OS is different, so I'd like some feedback on how this works on
36 your system. I would like to find a clean solution that lets this
37 module "Just Work" for everyone, but I have a feeling that it's going
38 to look more like C<if(gentoo){ ... } elsif (debian) { ... }> and so
39 on. I can live with that, but I need your help to get to that stage!
41 Please report any problems to RT, the Catalyst mailing list, or the
42 #catalyst IRC channel on L<irc.perl.org>. Thanks!
46 use Test::WWW::Selenium::Catalyst 'MyApp', 'command line to selenium';
47 use Test::More tests => 2;
49 my $sel = Test::WWW::Selenium::Catalyst->start;
51 $sel->is_text_present_ok('Welcome to MyApp');
53 This module starts the SeleniumRC server and your Catalyst app so that
54 you can test it with SeleniumRC. Once you've called
55 C<< Test::WWW::Selenium::Catalyst->start >>, everything is just like
56 L<Test::WWW::Selenium|Test::WWW:Selenium>.
62 Starts the Selenium and Catalyst servers, and returns a pre-initialized,
63 ready-to-use Test::WWW::Selenium object.
71 URI at which the application can be reached. If this is specified then no
72 application server will be started.
78 Port on which to run the catalyst application server. The C<MYAPP_PORT>
79 environment variable is also respected.
84 B<Default>: Test::WWW::Selenium
86 Classname of Selenium object to create. Use this if you want to subclass
87 selenium to add custom logic.
93 Location of externally running selenium server if you do not wish this module
94 to control one. See also for details.
98 All other options passed verbatim to the selenium constructor.
100 B<NOTE>: By default a selenium server is started when you C<use> this module,
101 and it's killed when your test exits. If wish to manage a selenium server
102 yourself, (for instance you wish to start up a server once and run a number of
103 tests against it) pass C<-no_selenium_server> to import:
105 use Test::WWW::Selenium 'MyApp'
106 -no_selenium_server => 1
108 Along a similar vein you can also pass command line arguments to the selenium
109 server via C<-selenium_args>:
111 use Test::WWW::Selenium 'MyApp'
112 -selenium_args => "-singleWindow -port 4445"
116 Returns the process ID of the Selenium Server.
120 Returns the process ID of the Catalyst server.
126 my ($class, $args) = @_;
127 # fork off a selenium server
129 if(0 == ($pid = fork())){
130 local $SIG{TERM} = sub {
131 diag("Selenium server $$ going down (TERM)") if $DEBUG;
143 diag("Selenium running in $$") if $DEBUG;
144 $class->_start_selenium($args);
145 diag("Selenium server $$ going down") if $DEBUG;
151 # Moved out to be subclassable seperately to the fork logic
152 sub _start_selenium {
153 my ($class, $arg) = @_;
154 $arg = '' unless defined $arg;
155 Alien::SeleniumRC::start($arg)
156 or croak "Can't start Selenium server";
168 my ($class, $appname, %args) = @_;
170 croak q{Specify your app's name} if !$appname;
173 my $d = $ENV{Catalyst::Utils::class2env($appname). "_DEBUG"}; # MYAPP_DEBUG
178 $args{-selenium_args} ||= '-singleWindow';
180 if ($ENV{SELENIUM_SERVER}) {
181 $args{-no_selenium_server} = 1;
183 elsif ($ENV{SELENIUM_PORT}) {
184 $args{-selenium_args} .= " -port " . $ENV{SELENIUM_PORT};
187 unless ($args{-no_selenium_server}) {
188 $class->_start_server($args{-selenium_args}) or croak "Couldn't start selenium server";
195 my $args = shift || {};
197 my $port = delete $args->{port};
198 $port ||= $ENV{Catalyst::Utils::class2env($app). "_PORT"} # MYAPP_PORT
203 # Check for CATALYST_SERVER env var like TWMC does.
204 if ( $ENV{CATALYST_SERVER} ) {
205 $uri = $ENV{CATALYST_SERVER};
206 } elsif ( $args->{app_uri} ) {
207 $uri = delete $args->{app_uri}
209 # start a Catalyst MyApp server
211 croak "Couldn't load $app: $@" if $@;
214 if(0 == ($pid = fork())){
215 local $SIG{TERM} = sub {
216 diag("Catalyst server $$ going down (TERM)") if $DEBUG;
219 diag("Catalyst server running in $$") if $DEBUG;
220 $app->run($port, 'localhost');
223 $uri = 'http://localhost:' . $port;
229 my $sel_class = delete $args->{selenium_class} || 'Test::WWW::Selenium';
232 if ($ENV{SELENIUM_SERVER}) {
233 my $uri = $ENV{SELENIUM_SERVER};
234 $uri =~ s!^(?:http://)?!http://!;
235 $uri = new URI($uri);
236 $args->{selenium_host} = $uri->host;
237 $args->{selenium_port} = $uri->port;
239 elsif ($ENV{SELENIUM_PORT}) {
240 $args->{selenium_port} = $ENV{SELENIUM_PORT};
243 my $sel_host = delete $args->{selenium_host} || 'localhost';
244 my $sel_port = delete $args->{selenium_port} || 4444;
245 while(!$sel && $tries--){
247 diag("Waiting for selenium server to start")
251 $sel = $sel_class->new(
254 browser => '*firefox',
262 croak "Can't start selenium: $error" if $error;
264 return $www_selenium = $sel;
270 diag("Shutting down Selenium Server $sel_pid") if $DEBUG;
271 $www_selenium->stop();
272 # This can fail if a page hasn't been requested yet.
273 eval { $www_selenium->do_command('shutDownSeleniumServer') };
276 diag("Killing Selenium Server $sel_pid") if $DEBUG;
277 kill 15, $sel_pid or diag "Killing Selenium: $!";
280 } elsif ($www_selenium) {
281 diag("Stopping Selenium Session $sel_pid") if $DEBUG;
282 $www_selenium->stop();
287 diag("Killing catalyst server $app_pid") if $DEBUG;
288 kill 15, $app_pid or diag "Killing MyApp: $!";
291 diag("Waiting for children to die") if $DEBUG;
292 waitpid $sel_pid, 0 if $sel_pid;
293 waitpid $app_pid, 0 if $app_pid;
299 Debugging messages are shown if C<CATALYST_DEBUG> or C<MYAPP_DEBUG>
300 are set. C<MYAPP> is the name of your application, uppercased. (This
301 is the same syntax as Catalyst itself.)
303 C<CATALYST_SERVER> can be set to test against an externally running server,
304 in a similar manner to how L<Test::WWW::Mechanize::Catalyst> behaves.
306 The port that the application sever runs on can be affected by C<MYAPP_PORT>
307 in addition to being specifiable in the arguments passed to start.
311 =head2 Specify your app's name
313 You need to pass your Catalyst app's name as the argument to the use
316 use Test::WWW::Selenium::Catalyst 'MyApp'
318 C<MyApp> is the name of your Catalyst app.
326 Selenium website: L<http://seleniumhq.org/>
330 Description of what you can do with the C<$sel> object: L<Test::WWW::Selenium>
335 If you don't need a real web browser: L<Test::WWW::Mechanize::Catalyst>
341 Ash Berlin C<< <ash@cpan.org> >>
343 Jonathan Rockway, C<< <jrockway at cpan.org> >>
347 Please report any bugs or feature requests to
348 C<bug-test-www-selenium-catalyst at rt.cpan.org>, or through the web interface at
349 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-WWW-Selenium-Catalyst>.
350 I will be notified, and then you'll automatically be notified of progress on
351 your bug as I make changes.
355 Send me unified diffs against the git HEAD at:
357 git://github.com/jrockway/test-www-selenium-catalyst.git
359 You can view the repository online at
361 http://github.com/jrockway/test-www-selenium-catalyst/tree/master
363 Thanks in advance for your contributions!
365 =head1 ACKNOWLEDGEMENTS
367 Thanks for mst for getting on my (jrockway's) case to actually write this thing
370 =head1 COPYRIGHT & LICENSE
372 Copyright 2009 Ash Berlin, all rights reserved.
374 Copyright 2006 Jonathan Rockway, all rights reserved.
376 This program is free software; you can redistribute it and/or modify it
377 under the same terms as Perl itself.
381 1; # End of Test::WWW::Selenium::Catalyst