Adding Test::WWW::Selenium::Catalyst
jrockway [Wed, 27 Sep 2006 08:18:24 +0000 (08:18 +0000)]
git-svn-id: http://dev.catalystframework.org/repos/Catalyst/trunk/Test-WWW-Selenium-Catalyst@5029 4ad37cd2-5fec-0310-835f-b3785c72a374

.cvsignore [new file with mode: 0644]
Changes [new file with mode: 0644]
Makefile.PL [new file with mode: 0644]
README [new file with mode: 0644]
lib/Test/WWW/Selenium/Catalyst.pm [new file with mode: 0644]
t/01-live.t [new file with mode: 0644]
t/boilerplate.t [new file with mode: 0644]
t/lib/TestApp.pm [new file with mode: 0755]
t/lib/TestApp/Controller/Root.pm [new file with mode: 0755]
t/pod-coverage.t [new file with mode: 0644]
t/pod.t [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..cea704a
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..b5d915c
--- /dev/null
@@ -0,0 +1,18 @@
+use strict;
+use warnings;
+use inc::Module::Install;
+
+name('Test-WWW-Selenium-Catalyst');
+author('Jonathan Rockway <jrockway@cpan.org>');
+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 (file)
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 (file)
index 0000000..3edf014
--- /dev/null
@@ -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<use> 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<CATALYST_DEBUG> or C<MYAPP_DEBUG>
+are set.  C<MYAPP> 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<MyApp> is the name of your Catalyst app.
+
+=head1 AUTHOR
+
+Jonathan Rockway, C<< <jrockway at cpan.org> >>
+
+=head1 BUGS
+
+Please report any bugs or feature requests to
+C<bug-test-www-selenium-catalyst at rt.cpan.org>, or through the web interface at
+L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Test-WWW-Selenium-Catalyst>.
+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<http://annocpan.org/dist/Test-WWW-Selenium-Catalyst>
+
+=item * CPAN Ratings
+
+L<http://cpanratings.perl.org/d/Test-WWW-Selenium-Catalyst>
+
+=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
+
+=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 (file)
index 0000000..5ef0c8e
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+# 01-live.t 
+# Copyright (c) 2006 Jonathan Rockway <jrockway@cpan.org>
+
+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 (file)
index 0000000..40d59c1
--- /dev/null
@@ -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 (executable)
index 0000000..bd5a456
--- /dev/null
@@ -0,0 +1,4 @@
+package TestApp;\r
+use Catalyst;\r
+__PACKAGE__->setup; \r
+1;\r
diff --git a/t/lib/TestApp/Controller/Root.pm b/t/lib/TestApp/Controller/Root.pm
new file mode 100755 (executable)
index 0000000..1e6ed15
--- /dev/null
@@ -0,0 +1,56 @@
+#!/usr/bin/perl\r
+# Root.pm \r
+# Copyright (c) 2006 Jonathan Rockway <jrockway@cpan.org>\r
+\r
+package TestApp::Controller::Root;\r
+use base qw(Catalyst::Controller);\r
+__PACKAGE__->config->{namespace} = q{};\r
+my @words = qw(foo bar baz bat qux quux);\r
+\r
+sub index : Private {\r
+    my ($self, $c, @args) = @_;\r
+    my $words = $c->uri_for('/words');\r
+    $c->response->body(<<"HERE");\r
+<html>\r
+<head>\r
+<title>TestApp</title>\r
+</head>\r
+<body>\r
+<h1>TestApp</h1>\r
+<p>This is the TestApp.</p>\r
+<p><a href="$words">Click here</a> to <i>see</i> some words.</p>\r
+</body>\r
+</html>    \r
+HERE\r
+}\r
+\r
+sub words : Local {\r
+    my ($self, $c, $times) = @_;\r
+    $times ||= 0;\r
+    my $html = <<"HEADER";\r
+<html>\r
+<head>\r
+<title>TestApp</title>\r
+</head>\r
+<body>\r
+<h1>TestApp &lt;&lt; Words</h1>\r
+<p>Here you'll find all things "words" printed $times time(s)!</p>\r
+<ul>\r
+HEADER\r
+    local $" = q{ }; # single space\r
+    $html .= " <li>$_: @words</li>\n" for 1..$times;\r
+    $html .= <<"FOOTER"; \r
+</ul>\r
+</body>\r
+</html>\r
+FOOTER\r
+    $c->response->body($html);\r
+}\r
+\r
+sub null : Path('/favicon.ico'){\r
+    my ($self, $c) = @_;\r
+    $c->response->status(404); # doesn't exist\r
+}\r
+\r
+1; # true.\r
+\r
diff --git a/t/pod-coverage.t b/t/pod-coverage.t
new file mode 100644 (file)
index 0000000..703f91d
--- /dev/null
@@ -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 (file)
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();