X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FTest%2FWWW%2FSelenium%2FCatalyst.pm;h=8b4ed3420677e65bc87d0a8029831e1782a6a646;hb=2465a6eeee856129064680701fcf658ec8a1f0c0;hp=3edf014d02e2feb42f31fd19986b35e2a514d91f;hpb=4f6d213e1b66ba3fd93ce439309af5857775a143;p=catagits%2FTest-WWW-Selenium-Catalyst.git diff --git a/lib/Test/WWW/Selenium/Catalyst.pm b/lib/Test/WWW/Selenium/Catalyst.pm index 3edf014..8b4ed34 100644 --- a/lib/Test/WWW/Selenium/Catalyst.pm +++ b/lib/Test/WWW/Selenium/Catalyst.pm @@ -12,37 +12,104 @@ 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 -Test::WWW::Selenium::Catalyst - Test your Catalyst app with Selenium +Test::WWW::Selenium::Catalyst - Test your Catalyst application with Selenium =cut -our $VERSION = '0.00_01'; +our $VERSION = '0.06'; + +=head1 DEVELOPERISH RELEASE + +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 +and OS is different, so I'd like some feedback on how this works on +your system. I would like to find a clean solution that lets this +module "Just Work" for everyone, but I have a feeling that it's going +to look more like C and so +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! =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; $sel->open_ok('/'); $sel->is_text_present_ok('Welcome to MyApp'); -=head1 FUNCTIONS +This module starts the SeleniumRC server and your Catalyst app so that +you can test it with SeleniumRC. Once you've called +C<< Test::WWW::Selenium::Catalyst->start >>, everything is just like +L. + +=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 + +Classname of Selenium object to create. Use this if you want to subclass +selenium to add custom logic. -=head2 start +=item selenium_host -Starts the Selenium and Catalyst servers, and returns a -pre-initialized, ready-to-use Test::WWW::Selenium object. +=item selenium_port -[NOTE] The selenium server is actually started when you C this -module, and it's killed when your test exits. +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 '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 'MyApp', + -selenium_args => "-singleWindow -port 4445" =head2 sel_pid @@ -56,31 +123,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; } @@ -90,78 +165,127 @@ 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; } - elsif(defined $d && $d == 0){ - $DEBUG = 0; + + $args{-selenium_args} ||= '-singleWindow'; + + if ($ENV{SELENIUM_SERVER}) { + $args{-no_selenium_server} = 1; + } + 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 $$") if $DEBUG; + $app->run($port, 'localhost'); + 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; @@ -175,6 +299,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 @@ -186,50 +316,60 @@ statement: C is the name of your Catalyst app. -=head1 AUTHOR +=head1 SEE ALSO -Jonathan Rockway, C<< >> +=over 4 -=head1 BUGS +=item * -Please report any bugs or feature requests to -C, or through the web interface at -L. -I will be notified, and then you'll automatically be notified of progress on -your bug as I make changes. +Selenium website: L + +=item * + +Description of what you can do with the C<$sel> object: L +and L -=head1 SUPPORT +=item * -You can find documentation for this module with the perldoc command. +If you don't need a real web browser: L - perldoc Test::WWW::Selenium::Catalyst +=back -You can also look for information at: +=head1 AUTHOR -=over 4 +Ash Berlin C<< >> -=item * AnnoCPAN: Annotated CPAN documentation +Jonathan Rockway, C<< >> -L +=head1 BUGS -=item * CPAN Ratings +Please report any bugs or feature requests to +C, or through the web interface at +L. +I will be notified, and then you'll automatically be notified of progress on +your bug as I make changes. -L +=head1 PATCHES -=item * RT: CPAN's request tracker +Send me unified diffs against the git HEAD at: -L + git://github.com/jrockway/test-www-selenium-catalyst.git -=item * Search CPAN +You can view the repository online at -L + http://github.com/jrockway/test-www-selenium-catalyst/tree/master -=back +Thanks in advance for your contributions! =head1 ACKNOWLEDGEMENTS +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