From 0a5fd68fb40d1126491bcf4935ae8568c270d50a Mon Sep 17 00:00:00 2001
From: Olli-Antti Kivilahti <olli-antti.kivilahti@jns.fi>
Date: Mon, 6 Jul 2015 12:11:06 +0000
Subject: [PATCH] Bug 14495 - WebDriver/WebTester Factory for easy generation
 of Web testing UserAgents.

Has an optional dependency to Buugg 13799

Because life is short, getting test web drivers must be easy.

    use t::lib::WebDriverFactory;
    my ($firefox) = t::lib::WebDriverFactory::getUserAgentDrivers('firefox');

In Ubuntu 14.04, Selenium no longer requires a stand-alone testing Server, so
running integration tests is much much more fun!

This factory encapsulates all the boring bits about getting a web driver to mimic
user behaviour in the GUI. And makes it super easy to get a test driver for any
testing type environment.

Adds support for Test::Mojo and Selenium,
see t::lib::WebDriverFactory for installation and usage instructions.

run t::lib::webDriverFactory.t to see your configured capabilities.
---
 t/lib/WebDriverFactory.pm | 152 ++++++++++++++++++++++++++++++++++++++++++++++
 t/lib/webDriverFactory.t  |  51 ++++++++++++++++
 2 files changed, 203 insertions(+)
 create mode 100644 t/lib/WebDriverFactory.pm
 create mode 100644 t/lib/webDriverFactory.t

diff --git a/t/lib/WebDriverFactory.pm b/t/lib/WebDriverFactory.pm
new file mode 100644
index 0000000..83838fa
--- /dev/null
+++ b/t/lib/WebDriverFactory.pm
@@ -0,0 +1,152 @@
+package t::lib::WebDriverFactory;
+
+# Copyright 2015 Open Source Freedom Fighters
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
+
+use Modern::Perl;
+
+use Koha::Exception::VersionMismatch;
+use Koha::Exception::UnknownProgramState;
+
+=head NAME t::lib::WebDriverFactory
+
+=head SYNOPSIS
+
+This Factory is responsible for creating all WebTesters/WebDrivers supported by Koha.
+
+=cut
+
+=head getUserAgentDrivers
+
+    my ($phantomjs)      = getUserAgentDrivers('phantomjs');
+    my ($phantomjs, $ff) = getUserAgentDrivers(['phantomjs', 'firefox']);
+    my ($firefox)        = getUserAgentDrivers({firefox => { version => '39.0', platform => 'LINUX' }});
+    my ($ff1, $ff2)      = getUserAgentDrivers({firefox1 => { version => '39.0', platform => 'LINUX' },
+                                                firefox2 => { version => '38.0', platform => 'WINDOWS' }, #yuck...
+                                              });
+
+Test Driver factory-method to get various web-userAgents.
+This is a direct wrapper for Selenium::Remote::Driver->new(), check the valid parameters from it's perldoc.
+
+Valid userAgent names:
+    'phantomjs',  is a headless browser which can be ran as standalone without an installed
+                  GUI( like X-server ), this is recommended for test servers.
+                  See Selenium::PhantomJS for installation instructions.
+    'firefox',    launches a Firefox-instance to run the automated tests.
+                  See Selenium::Firefox for installation instructions.
+    'mojolicious' is the Test::Mojo-test userAgent used to test Mojolicious framework routes.
+                  Is installed with the Mojolicius framework.
+                  No accepted configuration parameters at this time.
+                  You can give the 'version', but we default to the only version we currently have, 'V1'.
+
+@PARAM1 String, the name of the userAgent requested with default config, eg. 'selenium' or 'firefox'
+@RETURNS List of, the requested Selenium::Remote::Driver-implementation, eg. Selenium::PhantomJS
+@OR
+@PARAM1 ARRAYRef, names of the userAgents requested with default config
+@RETURNS List of, the requested Selenium::Remote::Driver-implementations
+@OR
+@PARAM1 HASHRef, names of the userAgents requested as HASH keys, keys must start with
+                 the desired userAgent-implementation name and be suffixed with an identifier
+                 so the keys don't conflict with each other.
+                 UserAgent keys correspond to HASHRefs of extra configuration parameters for
+                 Selenium::Remote::Driver->new()
+@RETURNS List of, the requested Selenium::Remote::Driver-implementations
+
+@THROWS Koha::Exception::UnknownProgramState, see _getTestMojoDriver()
+@THROWS Koha::Exception::VersionMismatch, see _getTestMojoDriver()
+=cut
+
+sub getUserAgentDrivers {
+    my ($requestedUserAgents) = @_;
+
+    my $requestedUserAgentNames;
+    if( ref($requestedUserAgents) eq 'HASH' ) {
+        $requestedUserAgentNames = [keys(%$requestedUserAgents)];
+    }
+    elsif ( ref($requestedUserAgents) eq 'ARRAY' ) {
+        $requestedUserAgentNames = $requestedUserAgents;
+    }
+    else {
+        $requestedUserAgentNames = [$requestedUserAgents];
+    }
+
+    ##Collect the user agents requested for.
+    #Find out if the $requestedUserAgents-parameters contain a configuration
+    #HASH for all/some of the requested user agents, and merge that over the
+    #default configuration values for each user agent.
+    #For some reason the Selenium constructors want HASHes in List-context?
+    my @userAgents;
+    foreach my $reqUAName (@$requestedUserAgentNames) {
+        require Selenium::PhantomJS;
+        my $reqUAConf = $requestedUserAgents->{$reqUAName} if ref($requestedUserAgents) eq 'HASH';
+
+        if ($reqUAName =~ /^phantomjs/) {
+            my $defaultConf = {
+                                javascript         => 1,
+                                accept_ssl_certs   => 1,
+            };
+            @$defaultConf{keys %$reqUAConf} = values %$reqUAConf if ref($reqUAConf) eq 'HASH';
+
+            my @hashInListContext = %$defaultConf;
+            push @userAgents, Selenium::PhantomJS->new(@hashInListContext);
+        }
+        elsif ($reqUAName =~ /^firefox/) {
+            require Selenium::Firefox;
+            my $defaultConf = {
+                                javascript         => 1,
+                                accept_ssl_certs   => 1,
+            };
+            @$defaultConf{keys %$reqUAConf} = values %$reqUAConf if ref($reqUAConf) eq 'HASH';
+
+            my @hashInListContext = %$defaultConf;
+            push @userAgents, Selenium::Firefox->new(@hashInListContext);
+        }
+        elsif ($reqUAName =~ /^mojolicious/) {
+            my $defaultConf = {
+                                version => 'V1',
+            };
+            @$defaultConf{keys %$reqUAConf} = values %$reqUAConf if ref($reqUAConf) eq 'HASH';
+
+            push @userAgents, _getTestMojoDriver($defaultConf);
+        }
+    }
+
+    return @userAgents;
+}
+
+=head _getTestMojoDriver
+
+@THROWS Koha::Exception::UnknownProgramState, if Test::Mojo doesn't die out of failure, but we get no Test Driver.
+@THROWS Koha::Exception::VersionMismatch, if we try to get an unsupported API version test driver.
+=cut
+sub _getTestMojoDriver {
+    require Test::Mojo;
+    my ($config) = @_;
+
+    if ((uc($config->{version}) eq 'V1') || not(exists($config->{version}))) { #Default to V1
+        $ENV{MOJO_LOGFILES} = undef;
+        $ENV{MOJO_CONFIG} = undef;
+        my $mojoDriver = Test::Mojo->new('Koha::REST::V1');
+        return $mojoDriver if $mojoDriver;
+        Koha::Exception::UnknownProgramState->throw(error => "WebDriverFactory::_getTestMojoDriver():> Unexpected exception.");
+    }
+    else {
+        Koha::Exception::VersionMismatch->throw(error => "WebDriverFactory::_getTestMojoDriver():> Unknown version, supported version 'V1'");
+    }
+}
+
+1; #Make the compiler happy!
\ No newline at end of file
diff --git a/t/lib/webDriverFactory.t b/t/lib/webDriverFactory.t
new file mode 100644
index 0000000..2f619cb
--- /dev/null
+++ b/t/lib/webDriverFactory.t
@@ -0,0 +1,51 @@
+#!/usr/bin/env perl
+
+# Copyright 2015 Open Source Freedom Fighters
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
+
+use Modern::Perl;
+
+use Test::More; #Please don't set the test count here. It is nothing but trouble when rebasing against master
+                #and is of dubious help, especially since we are running dynamic tests here which are triggered
+                #based on the reported test infrastucture capabilities.
+use Try::Tiny; #Even Selenium::Remote::Driver uses Try::Tiny :)
+use Scalar::Util qw(blessed);
+
+use t::lib::WebDriverFactory;
+
+
+my $testingModules = {  firefox => {version => '39.0', platform => 'LINUX'},
+                        phantomjs => {},
+                        mojolicious => {version => 'V1'},
+                    };
+
+foreach my $name (keys %$testingModules) {
+    try {
+        my $conf = $testingModules->{$name};
+        my ($webDriver) = t::lib::WebDriverFactory::getUserAgentDrivers({$name => $conf});
+        ok(blessed($webDriver), "'$name' WebDriver/UserAgent capability.");
+    } catch {
+        if ($_ =~ /is not an executable file/) {
+            print "$name-driver is not installed. See Selenium::$name for installation instructions.\n";
+        }
+        else {
+            print "$name-driver not operational.\n";
+        }
+    };
+}
+
+done_testing;
\ No newline at end of file
-- 
1.9.1