1 package Test::WWW::Selenium::Catalyst;
7 use Test::WWW::Selenium;
10 use Catalyst::EngineLoader;
12 BEGIN { $ENV{CATALYST_ENGINE} ||= 'HTTP'; }
14 local $SIG{CHLD} = 'IGNORE';
16 our $DEBUG = $ENV{CATALYST_DEBUG};
17 our $app; # app name (MyApp)
18 our $sel_pid; # pid of selenium server
19 our $app_pid; # pid of myapp server
24 Test::WWW::Selenium::Catalyst - Test your Catalyst application with Selenium
28 our $VERSION = '0.06';
30 =head1 DEVELOPERISH RELEASE
32 This is still a test release. It's working for me in production, but
33 it depends on a Java application (SeleniumRC), which can be
34 unreliable. On my Debian system, I had to put C<firefox-bin> in my
35 path, and add C</usr/lib/firefox> to C<LD_LIBRARY_PATH>. Every distro
36 and OS is different, so I'd like some feedback on how this works on
37 your system. I would like to find a clean solution that lets this
38 module "Just Work" for everyone, but I have a feeling that it's going
39 to look more like C<if(gentoo){ ... } elsif (debian) { ... }> and so
40 on. I can live with that, but I need your help to get to that stage!
42 Please report any problems to RT, the Catalyst mailing list, or the
43 #catalyst IRC channel on L<irc.perl.org>. Thanks!
47 use Test::WWW::Selenium::Catalyst 'MyApp', 'command line to selenium';
48 use Test::More tests => 2;
50 my $sel = Test::WWW::Selenium::Catalyst->start;
52 $sel->is_text_present_ok('Welcome to MyApp');
54 This module starts the SeleniumRC server and your Catalyst app so that
55 you can test it with SeleniumRC. Once you've called
56 C<< Test::WWW::Selenium::Catalyst->start >>, everything is just like
57 L<Test::WWW::Selenium|Test::WWW:Selenium>.
63 Starts the Selenium and Catalyst servers, and returns a pre-initialized,
64 ready-to-use Test::WWW::Selenium object.
72 URI at which the application can be reached. If this is specified then no
73 application server will be started.
79 Port on which to run the catalyst application server. The C<MYAPP_PORT>
80 environment variable is also respected.
85 B<Default>: Test::WWW::Selenium
87 Classname of Selenium object to create. Use this if you want to subclass
88 selenium to add custom logic.
94 Location of externally running selenium server if you do not wish this module
95 to control one. See also for details.
99 All other options passed verbatim to the selenium constructor.
101 B<NOTE>: By default a selenium server is started when you C<use> this module,
102 and it's killed when your test exits. If wish to manage a selenium server
103 yourself, (for instance you wish to start up a server once and run a number of
104 tests against it) pass C<-no_selenium_server> to import:
106 use Test::WWW::Selenium 'MyApp',
107 -no_selenium_server => 1
109 Along a similar vein you can also pass command line arguments to the selenium
110 server via C<-selenium_args>:
112 use Test::WWW::Selenium 'MyApp',
113 -selenium_args => "-singleWindow -port 4445"
117 Returns the process ID of the Selenium Server.
121 Returns the process ID of the Catalyst server.
127 my ($class, $args) = @_;
128 # fork off a selenium server
130 if(0 == ($pid = fork())){
131 local $SIG{TERM} = sub {
132 diag("Selenium server $$ going down (TERM)") if $DEBUG;
144 diag("Selenium running in $$") if $DEBUG;
145 $class->_start_selenium($args);
146 diag("Selenium server $$ going down") if $DEBUG;
152 # Moved out to be subclassable seperately to the fork logic
153 sub _start_selenium {
154 my ($class, $arg) = @_;
155 $arg = '' unless defined $arg;
156 Alien::SeleniumRC::start($arg)
157 or croak "Can't start Selenium server";
169 my ($class, $appname, %args) = @_;
171 croak q{Specify your app's name} if !$appname;
174 my $d = $ENV{Catalyst::Utils::class2env($appname). "_DEBUG"}; # MYAPP_DEBUG
179 $args{-selenium_args} ||= '-singleWindow';
181 if ($ENV{SELENIUM_SERVER}) {
182 $args{-no_selenium_server} = 1;
184 elsif ($ENV{SELENIUM_PORT}) {
185 $args{-selenium_args} .= " -port " . $ENV{SELENIUM_PORT};
188 unless ($args{-no_selenium_server}) {
189 $class->_start_server($args{-selenium_args}) or croak "Couldn't start selenium server";
196 my $args = shift || {};
198 my $port = delete $args->{port};
199 $port ||= $ENV{Catalyst::Utils::class2env($app). "_PORT"} # MYAPP_PORT
204 # Check for CATALYST_SERVER env var like TWMC does.
205 if ( $ENV{CATALYST_SERVER} ) {
206 $uri = $ENV{CATALYST_SERVER};
207 } elsif ( $args->{app_uri} ) {
208 $uri = delete $args->{app_uri}
210 # start a Catalyst MyApp server
212 croak "Couldn't load $app: $@" if $@;
215 if(0 == ($pid = fork())){
216 local $SIG{TERM} = sub {
217 diag("Catalyst server $$ going down (TERM)") if $DEBUG;
220 diag("Catalyst server running in pid $$ with port $port") if $DEBUG;
221 my $loader = Catalyst::EngineLoader->new(application_name => $app);
222 my $server = $loader->auto(port => $port, host => 'localhost',
223 server_ready => sub {
224 diag("Server started on port $port") if $DEBUG;
227 $app->run($port, 'localhost', $server);
229 diag("Process $$ (catalyst server) exiting.") if $DEBUG;
232 $uri = 'http://localhost:' . $port;
238 my $sel_class = delete $args->{selenium_class} || 'Test::WWW::Selenium';
241 if ($ENV{SELENIUM_SERVER}) {
242 my $uri = $ENV{SELENIUM_SERVER};
243 $uri =~ s!^(?:http://)?!http://!;
244 $uri = new URI($uri);
245 $args->{selenium_host} = $uri->host;
246 $args->{selenium_port} = $uri->port;
248 elsif ($ENV{SELENIUM_PORT}) {
249 $args->{selenium_port} = $ENV{SELENIUM_PORT};
252 my $sel_host = delete $args->{selenium_host} || 'localhost';
253 my $sel_port = delete $args->{selenium_port} || 4444;
254 while(!$sel && $tries--){
256 diag("Waiting for selenium server to start")
260 $sel = $sel_class->new(
263 browser => '*firefox',
271 croak "Can't start selenium: $error" if $error;
273 return $www_selenium = $sel;
279 diag("Shutting down Selenium Server $sel_pid") if $DEBUG;
280 $www_selenium->stop();
281 # This can fail if a page hasn't been requested yet.
282 eval { $www_selenium->do_command('shutDownSeleniumServer') };
285 diag("Killing Selenium Server $sel_pid") if $DEBUG;
286 kill 15, $sel_pid or diag "Killing Selenium: $!";
289 } elsif ($www_selenium) {
290 diag("Using external Selenium server. Don't shut it down.") if $DEBUG;
295 diag("Killing catalyst server $app_pid") if $DEBUG;
296 kill 15, $app_pid or diag "Killing MyApp: $!";
299 diag("Waiting for children to die") if $DEBUG;
300 waitpid $sel_pid, 0 if $sel_pid;
301 waitpid $app_pid, 0 if $app_pid;
307 Debugging messages are shown if C<CATALYST_DEBUG> or C<MYAPP_DEBUG>
308 are set. C<MYAPP> is the name of your application, uppercased. (This
309 is the same syntax as Catalyst itself.)
311 C<CATALYST_SERVER> can be set to test against an externally running server,
312 in a similar manner to how L<Test::WWW::Mechanize::Catalyst> behaves.
314 The port that the application sever runs on can be affected by C<MYAPP_PORT>
315 in addition to being specifiable in the arguments passed to start.
319 =head2 Specify your app's name
321 You need to pass your Catalyst app's name as the argument to the use
324 use Test::WWW::Selenium::Catalyst 'MyApp'
326 C<MyApp> is the name of your Catalyst app.
334 Selenium website: L<http://seleniumhq.org/>
338 Description of what you can do with the C<$sel> object: L<Test::WWW::Selenium>
343 If you don't need a real web browser: L<Test::WWW::Mechanize::Catalyst>
349 Ash Berlin C<< <ash@cpan.org> >>
351 Jonathan Rockway, C<< <jrockway at cpan.org> >>
355 Please report any bugs or feature requests to
356 C<bug-test-www-selenium-catalyst at rt.cpan.org>, or through the web interface at
357 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-WWW-Selenium-Catalyst>.
358 I will be notified, and then you'll automatically be notified of progress on
359 your bug as I make changes.
363 Send me unified diffs against the git HEAD at:
365 git://github.com/jrockway/test-www-selenium-catalyst.git
367 You can view the repository online at
369 http://github.com/jrockway/test-www-selenium-catalyst/tree/master
371 Thanks in advance for your contributions!
373 =head1 ACKNOWLEDGEMENTS
375 Thanks for mst for getting on my (jrockway's) case to actually write this thing
378 =head1 COPYRIGHT & LICENSE
380 Copyright 2009 Ash Berlin, all rights reserved.
382 Copyright 2006 Jonathan Rockway, all rights reserved.
384 This program is free software; you can redistribute it and/or modify it
385 under the same terms as Perl itself.
389 1; # End of Test::WWW::Selenium::Catalyst