From: jrockway Date: Wed, 27 Sep 2006 08:18:24 +0000 (+0000) Subject: Adding Test::WWW::Selenium::Catalyst X-Git-Tag: 0.04~16 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FTest-WWW-Selenium-Catalyst.git;a=commitdiff_plain;h=4f6d213e1b66ba3fd93ce439309af5857775a143 Adding Test::WWW::Selenium::Catalyst git-svn-id: http://dev.catalystframework.org/repos/Catalyst/trunk/Test-WWW-Selenium-Catalyst@5029 4ad37cd2-5fec-0310-835f-b3785c72a374 --- diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..cea704a --- /dev/null +++ b/.cvsignore @@ -0,0 +1,10 @@ +blib* +Makefile +Makefile.old +Build +_build* +pm_to_blib* +*.tar.gz +.lwpcookies +Test-WWW-Selenium-Catalyst-* +cover_db diff --git a/Changes b/Changes new file mode 100644 index 0000000..4f21a6f --- /dev/null +++ b/Changes @@ -0,0 +1,5 @@ +Revision history for Test-WWW-Selenium-Catalyst + +0.00_01 19 September 2006 + First version, released on an unsuspecting world. + diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..b5d915c --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,18 @@ +use strict; +use warnings; +use inc::Module::Install; + +name('Test-WWW-Selenium-Catalyst'); +author('Jonathan Rockway '); +version_from('lib/Test/WWW/Selenium/Catalyst.pm'); +abstract_from('lib/Test/WWW/Selenium/Catalyst.pm'); +license('Perl'); +include('ExtUtils::AutoInstall'); +requires( + 'Alien::SeleniumRC' => 0, + 'Catalyst::Runtime' => 5.7001, + 'Test::WWW::Selenium' => 0, + 'Test::More' => 0, +); +auto_install(); +WriteAll(); diff --git a/README b/README new file mode 100644 index 0000000..47ae560 --- /dev/null +++ b/README @@ -0,0 +1,40 @@ +Test-WWW-Selenium-Catalyst + +Use Selenium to test your Catalyst application + +INSTALLATION + +To install this module, run the following commands: + + perl Makefile.PL + make + make test + make install + + +SUPPORT AND DOCUMENTATION + +After installing, you can find documentation for this module with the perldoc command. + + perldoc Test::WWW::Selenium::Catalyst + +You can also look for information at: + + Search CPAN + http://search.cpan.org/dist/Test-WWW-Selenium-Catalyst + + CPAN Request Tracker: + http://rt.cpan.org/NoAuth/Bugs.html?Dist=Test-WWW-Selenium-Catalyst + + AnnoCPAN, annotated CPAN documentation: + http://annocpan.org/dist/Test-WWW-Selenium-Catalyst + + CPAN Ratings: + http://cpanratings.perl.org/d/Test-WWW-Selenium-Catalyst + +COPYRIGHT AND LICENCE + +Copyright (C) 2006 Jonathan Rockway + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. diff --git a/lib/Test/WWW/Selenium/Catalyst.pm b/lib/Test/WWW/Selenium/Catalyst.pm new file mode 100644 index 0000000..3edf014 --- /dev/null +++ b/lib/Test/WWW/Selenium/Catalyst.pm @@ -0,0 +1,240 @@ +package Test::WWW::Selenium::Catalyst; + +use warnings; +use strict; +use Carp; +use Alien::SeleniumRC; +use Test::WWW::Selenium; +use Test::More; +use Catalyst::Utils; + +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 + +=head1 NAME + +Test::WWW::Selenium::Catalyst - Test your Catalyst app with Selenium + +=cut + +our $VERSION = '0.00_01'; + +=head1 SYNOPSIS + + use Test::WWW::Selenium::Catalyst 'MyApp'; + 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 + +=head2 start + +Starts the Selenium and Catalyst servers, and returns a +pre-initialized, ready-to-use Test::WWW::Selenium object. + +[NOTE] The selenium server is actually started when you C this +module, and it's killed when your test exits. + +=head2 sel_pid + +Returns the process ID of the Selenium Server. + +=head2 app_pid + +Returns the process ID of the Catalyst server. + +=cut + + +sub _start_server { + # 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; + } + $sel_pid = $pid; +} + +sub sel_pid { + return $sel_pid; +} + +sub app_pid { + return $app_pid; +} + +sub import { + my ($class, $appname) = @_; + 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; + } + elsif(defined $d && $d == 0){ + $DEBUG = 0; + } + # 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; + } + $app_pid = $pid; + + my $tries = 5; + my $error; + my $sel; + 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 = $@; + } + + eval { $sel->start } + or croak "Can't start selenium: $@ (previous error: $error)"; + + return $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($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; + waitpid $app_pid, 0 if $app_pid; +} + + +=head1 ENVIRONMENT + +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.) + +=head1 DIAGNOSTICS + +=head2 Specify your app's name + +You need to pass your Catalyst app's name as the argument to the use +statement: + + use Test::WWW::Selenium::Catalyst 'MyApp' + +C is the name of your Catalyst app. + +=head1 AUTHOR + +Jonathan Rockway, C<< >> + +=head1 BUGS + +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. + +=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 + +=item * AnnoCPAN: Annotated CPAN documentation + +L + +=item * CPAN Ratings + +L + +=item * RT: CPAN's request tracker + +L + +=item * Search CPAN + +L + +=back + +=head1 ACKNOWLEDGEMENTS + +=head1 COPYRIGHT & LICENSE + +Copyright 2006 Jonathan Rockway, all rights reserved. + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=cut + +1; # End of Test::WWW::Selenium::Catalyst diff --git a/t/01-live.t b/t/01-live.t new file mode 100644 index 0000000..5ef0c8e --- /dev/null +++ b/t/01-live.t @@ -0,0 +1,26 @@ +#!/usr/bin/perl +# 01-live.t +# Copyright (c) 2006 Jonathan Rockway + +use Test::More tests => 79; +use FindBin; +use lib "$FindBin::Bin/lib"; +use Test::WWW::Selenium::Catalyst 'TestApp'; + +diag("You need to have firefox-bin in your path for this to work!"); + +my $sel = Test::WWW::Selenium::Catalyst->start({browser => '*firefox'}); + +$sel->open_ok('/'); +$sel->text_is("link=Click here", "Click here"); +$sel->click_ok("link=Click here"); +$sel->wait_for_page_to_load_ok("30000"); +for my $i (1..10){ + $sel->open_ok("/words/$i"); + $sel->is_text_present_ok( + qq{Here you'll find all things "words" printed $i time(s)!}); + + for my $j (1..$i){ + $sel->is_text_present_ok("$j: foo bar baz bat qux quux"); + } +} diff --git a/t/boilerplate.t b/t/boilerplate.t new file mode 100644 index 0000000..40d59c1 --- /dev/null +++ b/t/boilerplate.t @@ -0,0 +1,48 @@ +#!perl -T + +use strict; +use warnings; +use Test::More tests => 3; + +sub not_in_file_ok { + my ($filename, %regex) = @_; + open my $fh, "<", $filename + or die "couldn't open $filename for reading: $!"; + + my %violated; + + while (my $line = <$fh>) { + while (my ($desc, $regex) = each %regex) { + if ($line =~ $regex) { + push @{$violated{$desc}||=[]}, $.; + } + } + } + + if (%violated) { + fail("$filename contains boilerplate text"); + diag "$_ appears on lines @{$violated{$_}}" for keys %violated; + } else { + pass("$filename contains no boilerplate text"); + } +} + +not_in_file_ok(README => + "The README is used..." => qr/The README is used/, + "'version information here'" => qr/to provide version information/, +); + +not_in_file_ok(Changes => + "placeholder date/time" => qr(Date/time) +); + +sub module_boilerplate_ok { + my ($module) = @_; + not_in_file_ok($module => + 'the great new $MODULENAME' => qr/ - The great new /, + 'boilerplate description' => qr/Quick summary of what the module/, + 'stub function definition' => qr/function[12]/, + ); +} + +module_boilerplate_ok('lib/Test/WWW/Selenium/Catalyst.pm'); diff --git a/t/lib/TestApp.pm b/t/lib/TestApp.pm new file mode 100755 index 0000000..bd5a456 --- /dev/null +++ b/t/lib/TestApp.pm @@ -0,0 +1,4 @@ +package TestApp; +use Catalyst; +__PACKAGE__->setup; +1; diff --git a/t/lib/TestApp/Controller/Root.pm b/t/lib/TestApp/Controller/Root.pm new file mode 100755 index 0000000..1e6ed15 --- /dev/null +++ b/t/lib/TestApp/Controller/Root.pm @@ -0,0 +1,56 @@ +#!/usr/bin/perl +# Root.pm +# Copyright (c) 2006 Jonathan Rockway + +package TestApp::Controller::Root; +use base qw(Catalyst::Controller); +__PACKAGE__->config->{namespace} = q{}; +my @words = qw(foo bar baz bat qux quux); + +sub index : Private { + my ($self, $c, @args) = @_; + my $words = $c->uri_for('/words'); + $c->response->body(<<"HERE"); + + +TestApp + + +

TestApp

+

This is the TestApp.

+

Click here to see some words.

+ + +HERE +} + +sub words : Local { + my ($self, $c, $times) = @_; + $times ||= 0; + my $html = <<"HEADER"; + + +TestApp + + +

TestApp << Words

+

Here you'll find all things "words" printed $times time(s)!

+
    +HEADER + local $" = q{ }; # single space + $html .= "
  • $_: @words
  • \n" for 1..$times; + $html .= <<"FOOTER"; +
+ + +FOOTER + $c->response->body($html); +} + +sub null : Path('/favicon.ico'){ + my ($self, $c) = @_; + $c->response->status(404); # doesn't exist +} + +1; # true. + diff --git a/t/pod-coverage.t b/t/pod-coverage.t new file mode 100644 index 0000000..703f91d --- /dev/null +++ b/t/pod-coverage.t @@ -0,0 +1,6 @@ +#!perl -T + +use Test::More; +eval "use Test::Pod::Coverage 1.04"; +plan skip_all => "Test::Pod::Coverage 1.04 required for testing POD coverage" if $@; +all_pod_coverage_ok(); diff --git a/t/pod.t b/t/pod.t new file mode 100644 index 0000000..976d7cd --- /dev/null +++ b/t/pod.t @@ -0,0 +1,6 @@ +#!perl -T + +use Test::More; +eval "use Test::Pod 1.14"; +plan skip_all => "Test::Pod 1.14 required for testing POD" if $@; +all_pod_files_ok();