X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FTest%2FWWW%2FSelenium%2FCatalyst.pm;h=4de39a425603acf0ee4b38799554b6594cc3f889;hb=765b2b209b5b16985939956f29cdcd6aae6d9c93;hp=509c22cea56c6590c579e16725f8cb1ed7d814a5;hpb=1cdeb21f11323218fd364b40f86e6b0df8a6a625;p=catagits%2FTest-WWW-Selenium-Catalyst.git diff --git a/lib/Test/WWW/Selenium/Catalyst.pm b/lib/Test/WWW/Selenium/Catalyst.pm index 509c22c..4de39a4 100644 --- a/lib/Test/WWW/Selenium/Catalyst.pm +++ b/lib/Test/WWW/Selenium/Catalyst.pm @@ -7,15 +7,17 @@ use Alien::SeleniumRC; use Test::WWW::Selenium; use Test::More; use Catalyst::Utils; +use Catalyst::EngineLoader; BEGIN { $ENV{CATALYST_ENGINE} ||= 'HTTP'; } local $SIG{CHLD} = 'IGNORE'; -my $DEBUG = $ENV{CATALYST_DEBUG}; -my $app; # app name (MyApp) -my $sel_pid; # pid of selenium server -my $app_pid; # pid of myapp server +our $DEBUG = $ENV{CATALYST_DEBUG}; +our $app; # app name (MyApp) +our $sel_pid; # pid of selenium server +our $app_pid; # pid of myapp server +our $www_selenium; =head1 NAME @@ -23,11 +25,11 @@ Test::WWW::Selenium::Catalyst - Test your Catalyst application with Selenium =cut -our $VERSION = '0.00_01'; +our $VERSION = '0.06'; -=head1 DEVELOPER RELEASE +=head1 DEVELOPERISH RELEASE -This is a developer release. It's working for me in production, but +This is still a test release. It's working for me in production, but it depends on a Java application (SeleniumRC), which can be unreliable. On my Debian system, I had to put C in my path, and add C to C. Every distro @@ -40,15 +42,9 @@ on. I can live with that, but I need your help to get to that stage! Please report any problems to RT, the Catalyst mailing list, or the #catalyst IRC channel on L. Thanks! -=head2 KNOWN ISSUES - -Sometimes the Selenium server doesn't die after the tests when running -under C. C works fine, so until I (or you!) figure -out the problem, use C. - =head1 SYNOPSIS - use Test::WWW::Selenium::Catalyst 'MyApp'; + use Test::WWW::Selenium::Catalyst 'MyApp', 'command line to selenium'; use Test::More tests => 2; my $sel = Test::WWW::Selenium::Catalyst->start; @@ -57,18 +53,64 @@ out the problem, use C. This module starts the SeleniumRC server and your Catalyst app so that you can test it with SeleniumRC. Once you've called -Cstart>, everything is just like +C<< Test::WWW::Selenium::Catalyst->start >>, everything is just like L. -=head1 FUNCTIONS +=head1 METHODS + +=head2 start(\%args) + +Starts the Selenium and Catalyst servers, and returns a pre-initialized, +ready-to-use Test::WWW::Selenium object. + +Arguments: + +=over + +=item app_uri + +URI at which the application can be reached. If this is specified then no +application server will be started. + +=item port + +B: 3000 + +Port on which to run the catalyst application server. The C +environment variable is also respected. + + +=item selenium_class + +B: Test::WWW::Selenium -=head2 start +Classname of Selenium object to create. Use this if you want to subclass +selenium to add custom logic. -Starts the Selenium and Catalyst servers, and returns a -pre-initialized, ready-to-use Test::WWW::Selenium object. +=item selenium_host -[NOTE] The selenium server is actually started when you C this -module, and it's killed when your test exits. +=item selenium_port + +Location of externally running selenium server if you do not wish this module +to control one. See also for details. + +=back + +All other options passed verbatim to the selenium constructor. + +B: By default a selenium server is started when you C this module, +and it's killed when your test exits. If wish to manage a selenium server +yourself, (for instance you wish to start up a server once and run a number of +tests against it) pass C<-no_selenium_server> to import: + + use Test::WWW::Selenium::Catalyst 'MyApp', + -no_selenium_server => 1 + +Along a similar vein you can also pass command line arguments to the selenium +server via C<-selenium_args>: + + use Test::WWW::Selenium::Catalyst 'MyApp', + -selenium_args => "-singleWindow -port 4445" =head2 sel_pid @@ -82,31 +124,39 @@ Returns the process ID of the Catalyst server. sub _start_server { + my ($class, $args) = @_; # fork off a selenium server my $pid; if(0 == ($pid = fork())){ - local $SIG{TERM} = sub { - diag("Selenium server $$ going down (TERM)"); - exit 0; - }; - - chdir '/'; - - if(!$DEBUG){ - close *STDERR; - close *STDOUT; - close *STDIN; - } - - diag("Selenium running in $$") if $DEBUG; - Alien::SeleniumRC->start() - or croak "Can't start Selenium server"; - diag("Selenium server $$ going down") if $DEBUG; - exit 1; + local $SIG{TERM} = sub { + diag("Selenium server $$ going down (TERM)") if $DEBUG; + exit 0; + }; + + chdir '/'; + + if(!$DEBUG){ + close *STDERR; + close *STDOUT; + #close *STDIN; + } + + diag("Selenium running in $$") if $DEBUG; + $class->_start_selenium($args); + diag("Selenium server $$ going down") if $DEBUG; + exit 1; } $sel_pid = $pid; } +# Moved out to be subclassable seperately to the fork logic +sub _start_selenium { + my ($class, $arg) = @_; + $arg = '' unless defined $arg; + Alien::SeleniumRC::start($arg) + or croak "Can't start Selenium server"; +} + sub sel_pid { return $sel_pid; } @@ -116,78 +166,135 @@ sub app_pid { } sub import { - my ($class, $appname) = @_; + my ($class, $appname, %args) = @_; + croak q{Specify your app's name} if !$appname; $app = $appname; my $d = $ENV{Catalyst::Utils::class2env($appname). "_DEBUG"}; # MYAPP_DEBUG - if(defined $d && $d){ - $DEBUG = 1; + if(defined $d){ + $DEBUG = $d; + } + + $args{-selenium_args} ||= '-singleWindow'; + + if ($ENV{SELENIUM_SERVER}) { + $args{-no_selenium_server} = 1; } - elsif(defined $d && $d == 0){ - $DEBUG = 0; + elsif ($ENV{SELENIUM_PORT}) { + $args{-selenium_args} .= " -port " . $ENV{SELENIUM_PORT}; + } + + unless ($args{-no_selenium_server}) { + $class->_start_server($args{-selenium_args}) or croak "Couldn't start selenium server"; } - # if it's something else, leave the CATALYST_DEBUG setting in tact - - _start_server() or croak "Couldn't start selenium server"; return 1; } sub start { my $class = shift; my $args = shift || {}; - - # start a Catalyst MyApp server - eval("use $app"); - croak "Couldn't load $app: $@" if $@; - - my $pid; - if(0 == ($pid = fork())){ - local $SIG{TERM} = sub { - diag("Catalyst server $$ going down (TERM)") if $DEBUG; - exit 0; - }; - diag("Catalyst server running in $$") if $DEBUG; - $app->run('3000', 'localhost'); - exit 1; + + my $port = delete $args->{port}; + $port ||= $ENV{Catalyst::Utils::class2env($app). "_PORT"} # MYAPP_PORT + || 3000; + + my $uri; + + # Check for CATALYST_SERVER env var like TWMC does. + if ( $ENV{CATALYST_SERVER} ) { + $uri = $ENV{CATALYST_SERVER}; + } elsif ( $args->{app_uri} ) { + $uri = delete $args->{app_uri} + } else { + # start a Catalyst MyApp server + eval("use $app"); + croak "Couldn't load $app: $@" if $@; + + my $pid; + if(0 == ($pid = fork())){ + local $SIG{TERM} = sub { + diag("Catalyst server $$ going down (TERM)") if $DEBUG; + exit 0; + }; + diag("Catalyst server running in pid $$ with port $port") if $DEBUG; + my $loader = Catalyst::EngineLoader->new(application_name => $app); + my $server = $loader->auto(port => $port, host => 'localhost', + server_ready => sub { + diag("Server started on port $port") if $DEBUG; + }, + ); + $app->run($port, 'localhost', $server); + + diag("Process $$ (catalyst server) exiting.") if $DEBUG; + exit 1; + } + $uri = 'http://localhost:' . $port; + $app_pid = $pid; } - $app_pid = $pid; my $tries = 5; my $error; + my $sel_class = delete $args->{selenium_class} || 'Test::WWW::Selenium'; my $sel; + + if ($ENV{SELENIUM_SERVER}) { + my $uri = $ENV{SELENIUM_SERVER}; + $uri =~ s!^(?:http://)?!http://!; + $uri = new URI($uri); + $args->{selenium_host} = $uri->host; + $args->{selenium_port} = $uri->port; + } + elsif ($ENV{SELENIUM_PORT}) { + $args->{selenium_port} = $ENV{SELENIUM_PORT}; + } + + my $sel_host = delete $args->{selenium_host} || 'localhost'; + my $sel_port = delete $args->{selenium_port} || 4444; while(!$sel && $tries--){ - sleep 1; - diag("Waiting for selenium server to start") - if $DEBUG; - - eval { - $sel = Test::WWW::Selenium-> - new(host => 'localhost', - port => 4444, - browser => $args->{browser} || '*firefox', - browser_url => 'http://localhost:3000/' - ); - }; - $error = $@; + sleep 1; + diag("Waiting for selenium server to start") + if $DEBUG; + + eval { + $sel = $sel_class->new( + host => $sel_host, + port => $sel_port, + browser => '*firefox', + browser_url => $uri, + auto_stop => 0, + %$args + ); + }; + $error = $@; } + croak "Can't start selenium: $error" if $error; - eval { $sel->start } - or croak "Can't start selenium: $@ (previous error: $error)"; - - return $sel; + return $www_selenium = $sel; } END { if($sel_pid){ - diag("Killing Selenium Server $sel_pid") if $DEBUG; - kill 15, $sel_pid or diag "Killing Selenium: $!"; - undef $sel_pid; + if($www_selenium){ + diag("Shutting down Selenium Server $sel_pid") if $DEBUG; + $www_selenium->stop(); + # This can fail if a page hasn't been requested yet. + eval { $www_selenium->do_command('shutDownSeleniumServer') }; + undef $www_selenium; + } + diag("Killing Selenium Server $sel_pid") if $DEBUG; + kill 15, $sel_pid or diag "Killing Selenium: $!"; + undef $sel_pid; + + } elsif ($www_selenium) { + diag("Using external Selenium server. Don't shut it down.") if $DEBUG; + undef $www_selenium; } + if($app_pid){ - diag("Killing catalyst server $app_pid") if $DEBUG; - kill 15, $app_pid or diag "Killing MyApp: $!"; - undef $app_pid; + diag("Killing catalyst server $app_pid") if $DEBUG; + kill 15, $app_pid or diag "Killing MyApp: $!"; + undef $app_pid; } diag("Waiting for children to die") if $DEBUG; waitpid $sel_pid, 0 if $sel_pid; @@ -201,6 +308,12 @@ Debugging messages are shown if C or C are set. C is the name of your application, uppercased. (This is the same syntax as Catalyst itself.) +C can be set to test against an externally running server, +in a similar manner to how L behaves. + +The port that the application sever runs on can be affected by C +in addition to being specifiable in the arguments passed to start. + =head1 DIAGNOSTICS =head2 Specify your app's name @@ -218,11 +331,12 @@ C is the name of your Catalyst app. =item * -Selenium website: L +Selenium website: L =item * Description of what you can do with the C<$sel> object: L +and L =item * @@ -232,6 +346,8 @@ If you don't need a real web browser: L =head1 AUTHOR +Ash Berlin C<< >> + Jonathan Rockway, C<< >> =head1 BUGS @@ -242,40 +358,27 @@ L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. -=head1 SUPPORT - -You can find documentation for this module with the perldoc command. - - perldoc Test::WWW::Selenium::Catalyst - -You can also look for information at: - -=over 4 +=head1 PATCHES -=item * AnnoCPAN: Annotated CPAN documentation +Send me unified diffs against the git HEAD at: -L + git://github.com/jrockway/test-www-selenium-catalyst.git -=item * CPAN Ratings +You can view the repository online at -L + http://github.com/jrockway/test-www-selenium-catalyst/tree/master -=item * RT: CPAN's request tracker - -L - -=item * Search CPAN - -L - -=back +Thanks in advance for your contributions! =head1 ACKNOWLEDGEMENTS -Thanks for mst for getting on my case to actually write this thing :) +Thanks for mst for getting on my (jrockway's) case to actually write this thing +:) =head1 COPYRIGHT & LICENSE +Copyright 2009 Ash Berlin, all rights reserved. + Copyright 2006 Jonathan Rockway, all rights reserved. This program is free software; you can redistribute it and/or modify it