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
=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<firefox-bin> in my
path, and add C</usr/lib/firefox> to C<LD_LIBRARY_PATH>. Every distro
Please report any problems to RT, the Catalyst mailing list, or the
#catalyst IRC channel on L<irc.perl.org>. Thanks!
-=head2 KNOWN ISSUES
-
-Sometimes the Selenium server doesn't die after the tests when running
-under C<make test>. C<prove> works fine, so until I (or you!) figure
-out the problem, use C<prove>.
-
=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;
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
+C<< Test::WWW::Selenium::Catalyst->start >>, everything is just like
L<Test::WWW::Selenium|Test::WWW:Selenium>.
-=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<Default>: 3000
+
+Port on which to run the catalyst application server. The C<MYAPP_PORT>
+environment variable is also respected.
+
+
+=item selenium_class
+
+B<Default>: 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<use> 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<NOTE>: By default a selenium server is started when you C<use> 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
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;
}
}
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 $$") 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('shutDown') };
+ 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("Stopping Selenium Session $sel_pid") if $DEBUG;
+ $www_selenium->stop();
+ 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;
are set. C<MYAPP> is the name of your application, uppercased. (This
is the same syntax as Catalyst itself.)
+C<CATALYST_SERVER> can be set to test against an externally running server,
+in a similar manner to how L<Test::WWW::Mechanize::Catalyst> behaves.
+
+The port that the application sever runs on can be affected by C<MYAPP_PORT>
+in addition to being specifiable in the arguments passed to start.
+
=head1 DIAGNOSTICS
=head2 Specify your app's name
=item *
-Selenium website: L<http://www.openqa.org/>
+Selenium website: L<http://seleniumhq.org/>
=item *
Description of what you can do with the C<$sel> object: L<Test::WWW::Selenium>
+and L<WWW::Selenium>
=item *
=head1 AUTHOR
+Ash Berlin C<< <ash@cpan.org> >>
+
Jonathan Rockway, C<< <jrockway at cpan.org> >>
=head1 BUGS
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<http://annocpan.org/dist/Test-WWW-Selenium-Catalyst>
+ git://github.com/jrockway/test-www-selenium-catalyst.git
-=item * CPAN Ratings
+You can view the repository online at
-L<http://cpanratings.perl.org/d/Test-WWW-Selenium-Catalyst>
+ http://github.com/jrockway/test-www-selenium-catalyst/tree/master
-=item * RT: CPAN's request tracker
-
-L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Test-WWW-Selenium-Catalyst>
-
-=item * Search CPAN
-
-L<http://search.cpan.org/dist/Test-WWW-Selenium-Catalyst>
-
-=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