From b7cba1daa7bb3967c3c760a69749fcf7e4f96c1b Mon Sep 17 00:00:00 2001 From: Olli-Antti Kivilahti 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 | 84 +++++++++++++++++++++++++ 2 files changed, 236 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 . + +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..bc76721 --- /dev/null +++ b/t/lib/webDriverFactory.t @@ -0,0 +1,84 @@ +#!/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 . + +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 Selenium::PhantomJS; +use Selenium::Firefox; +use t::lib::WebDriverFactory; + +use C4::Members; +use Koha::Database; +use Koha::Borrower; + + +my $branchcode = Koha::Database->new()->schema()->resultset('Branch')->first()->branchcode(); + +############################################### +## Setting up test context Koha-style! ## +#This should be refactored when a proper automagic setUp-tearDown framework for integration tests is deployed. +############################################### +my $borrower = C4::Members::GetMember(cardnumber => '11A001'); #These tests can crash and leave the context behind, +my $borrowernumber = $borrower->{borrowernumber} if $borrower; #so when we rerun them, we get nasty issues with existing DB objects. +unless ($borrower) { + $borrowernumber = C4::Members::AddMember( + firstname => 'Olli', + lastname => 'Kivi', + categorycode => 'PT', + userid => '11Aadmin', + password => '1234', + cardnumber => '11A001', + dateofbirth => DateTime->now(time_zone => C4::Context->tz)->subtract(years => 21), #I am always 21 :) + flags => '1', #Giving specific permission flags here is REALLY HARD! Just giving superlibrarian-permission. + branchcode => 'CPL', + ); + $borrower = C4::Members::GetMember(borrowernumber => $borrowernumber); +} + +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"; + } + }; +} + +################################### +## TearDown test context.. ## +################################### +Koha::Database->new()->schema()->resultset('Borrower')->search({borrowernumber => $borrower->{borrowernumber}})->delete_all(); +done_testing; \ No newline at end of file -- 1.9.1