From 7443409ffc3b8e1e39d1c27eac2b3c978a7a2043 Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Thu, 12 Mar 2015 17:57:01 +0100 Subject: [PATCH] Bug 13849: POC - my first Cucumber contact During the hackfest 15 in Marseille, akafred present us how he integrated acceptance tests in Koha using Cucumber. With this patch, I would like to get other developer opinions on the usefulness of this kind of tests for the Koha software. To test: 0/ * Install the selenium server (have a look at bug 13691) * Install libtest-bdd-cucumber-perl (pkg) and App::pherkin (cpan) * Edit t/db_dependent/cucumber/features/step_definitions/basic_steps.pl and fill the login and password of a superlibrarian user. Maybe you should also change the address of the selenium server (search for 'remote_server_addr'). 1/ Start the selenium server and launch the tests: $ cd t/db_dependent/cucumber $ pherkin or $ prove tests.t Even if the second method is recommended in Test::BDD::Cucumber::Manual::Integration, I prefer the first one Indeed, the tests will pass if a step is not defined (maybe something is wrong somewhere...). --- .../prog/en/modules/admin/categorie.tt | 16 +++-- .../cucumber/features/0-category.feature | 21 ++++++ t/db_dependent/cucumber/features/1-patron.feature | 22 +++++++ .../features/step_definitions/0-category_steps.pl | 13 ++++ .../features/step_definitions/1-patron_steps.pl | 13 ++++ .../features/step_definitions/basic_steps.pl | 75 ++++++++++++++++++++++ .../features/step_definitions/hooks_steps.pl | 5 ++ t/db_dependent/cucumber/tests.t | 23 +++++++ t/lib/Cucumber.pm | 3 + t/lib/Cucumber/Form.pm | 16 +++++ t/lib/Cucumber/Paths.pm | 19 ++++++ 11 files changed, 220 insertions(+), 6 deletions(-) create mode 100644 t/db_dependent/cucumber/features/0-category.feature create mode 100644 t/db_dependent/cucumber/features/1-patron.feature create mode 100644 t/db_dependent/cucumber/features/step_definitions/0-category_steps.pl create mode 100644 t/db_dependent/cucumber/features/step_definitions/1-patron_steps.pl create mode 100644 t/db_dependent/cucumber/features/step_definitions/basic_steps.pl create mode 100644 t/db_dependent/cucumber/features/step_definitions/hooks_steps.pl create mode 100644 t/db_dependent/cucumber/tests.t create mode 100644 t/lib/Cucumber.pm create mode 100644 t/lib/Cucumber/Form.pm create mode 100644 t/lib/Cucumber/Paths.pm diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categorie.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categorie.tt index a2ad329..47757de 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categorie.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/categorie.tt @@ -44,7 +44,9 @@ return true; } // to check if the data are correctly entered. - function Check(ff) { + $(document).ready(function() { + $('form[name="Aform"]').on('submit', function(e) { + var ff = this; var ok=0; var _alertString=_("Form not submitted because of the following problem(s)"); _alertString +="\n-------------------------------------------------------------------\n\n"; @@ -79,16 +81,16 @@ } if(ff.enrolmentperioddate.value && ff.enrolmentperiod.value){ document.getElementById('enrolmentmessage').className = "error"; - return false; + e.preventDefault(); } if (ok) { // if there is a problem alert(_alertString); - return false; + e.preventDefault(); } // if all is good - ff.submit(); - } + }); + }); //]]> @@ -253,7 +255,9 @@ [% INCLUDE 'messaging-preference-form.inc' %] [% END %] -
+
+ +
[% END %] diff --git a/t/db_dependent/cucumber/features/0-category.feature b/t/db_dependent/cucumber/features/0-category.feature new file mode 100644 index 0000000..14771d0 --- /dev/null +++ b/t/db_dependent/cucumber/features/0-category.feature @@ -0,0 +1,21 @@ +Feature: Create a category + As a librarian + In order to create a patron + I want to create a new patron category + + Background: + Given I am logged in as a library admin + + Scenario: Go to the new patron category page + Given I have gone to the patron category list page + When I have clicked on the newcategory link + Then I should see the new patron category page + + Scenario: Create a patron category + Given I have gone to the new patron category page + When I have filled the field categorycode with "test_cat" + And I have filled the field description with "test cat description" + And I have filled the field enrolmentperiod with "12" + And I have filled the field category_type with "A" + And I have clicked on the submit button + Then The patron category "TEST_CAT" should exist diff --git a/t/db_dependent/cucumber/features/1-patron.feature b/t/db_dependent/cucumber/features/1-patron.feature new file mode 100644 index 0000000..e4f146e --- /dev/null +++ b/t/db_dependent/cucumber/features/1-patron.feature @@ -0,0 +1,22 @@ +Feature: Create a patron + As a librarian + I want to create a new patron + + Background: + Given I am logged in as a library admin + + # FIXME No id on the link + # Scenario: Go to the new patron page + # Given I have gone to the patron home page + # When I have clicked on the "New patron" link + # Then I should see the new patron page + + Scenario: Create a patron + Given I have gone to the new patron page + When I have filled the field surname with "test_patron_surname" + And I have filled the field cardnumber with "4242424242" + And I have filled the field userid with "test_username" + And I have filled the field password with "password" + And I have filled the field password2 with "password" + And I have clicked on the submit button + Then The patron "test_username" should have been created diff --git a/t/db_dependent/cucumber/features/step_definitions/0-category_steps.pl b/t/db_dependent/cucumber/features/step_definitions/0-category_steps.pl new file mode 100644 index 0000000..6147b89 --- /dev/null +++ b/t/db_dependent/cucumber/features/step_definitions/0-category_steps.pl @@ -0,0 +1,13 @@ +use Modern::Perl; + +use Test::More; +use Test::BDD::Cucumber::StepFile; +use Selenium::Remote::Driver; +use t::lib::Cucumber; + +Then qr{The patron category "(.*)" should exist}, sub { + S->{patron_category_code} = $1; + my @e = S->{driver}->find_elements('//td'); + my $elt = S->{driver}->find_element('//td[contains(.,"'.S->{patron_category_code}.'")]'); + is( ref($elt), 'Selenium::Remote::WebElement' ); +}; diff --git a/t/db_dependent/cucumber/features/step_definitions/1-patron_steps.pl b/t/db_dependent/cucumber/features/step_definitions/1-patron_steps.pl new file mode 100644 index 0000000..42e5619 --- /dev/null +++ b/t/db_dependent/cucumber/features/step_definitions/1-patron_steps.pl @@ -0,0 +1,13 @@ +use Modern::Perl; + +use Test::More; +use Test::BDD::Cucumber::StepFile; +use C4::Context; + +Then qr(The patron "(.*)" should have been created), sub { + S->{userid} = $1; + my $dbh = C4::Context->dbh; + my $exists = $dbh->selectcol_arrayref(q| + SELECT COUNT(*) FROM borrowers where userid = ?|, {}, S->{userid} ); + is( $exists->[0], 1, 'The patron '.S->{userid}.' should exist' ); +}; diff --git a/t/db_dependent/cucumber/features/step_definitions/basic_steps.pl b/t/db_dependent/cucumber/features/step_definitions/basic_steps.pl new file mode 100644 index 0000000..c50a26d --- /dev/null +++ b/t/db_dependent/cucumber/features/step_definitions/basic_steps.pl @@ -0,0 +1,75 @@ +use Modern::Perl; + +use Test::More; +use Test::BDD::Cucumber::StepFile; +use Selenium::Remote::Driver; +use t::lib::Cucumber::Form; +use t::lib::Cucumber::Paths; +use C4::Context; + +our $login = 'koha'; +our $password = 'koha'; + +# FIXME The body ids don't depend on the action we are doing (list or add views) +#our $body_ids = { +# 'new patron category' => 'admin/admin-home.pl', +#}; + + +Given qr{I am logged in as a library admin}, sub { + my $driver = Selenium::Remote::Driver->new({remote_server_addr => 'localhost'}); + my $mainpage = t::lib::Cucumber::Paths::get('mainpage'); + $driver->get($mainpage); + t::lib::Cucumber::Form::fill( $driver, { userid => $login, password => $password } ); + my $login_button = $driver->find_element('//input[@id="submit"]'); + $login_button->submit(); + S->{driver} = $driver; +}; + +Given qr{I have gone to the (.*) page}, sub { + my $page = $1; + my $path = t::lib::Cucumber::Paths::get( $page ); + S->{driver}->get( $path ); +}; + +When qr(I have clicked on the submit button), sub { + my $button; + # Try to find submit button + eval { + $button = S->{driver}->find_element('//fieldset[@class="action"]/input[@type="submit"]'); + }; + eval { + $button = S->{driver}->find_element('//input[@id="submit"]'); + } unless $button; + eval { + $button = S->{driver}->find_element('//input[@type="submit"]'); + } unless $button; + + die "There is no submit button on this page" unless $button; + $button->click; +}; + +When qr(I have clicked on the (\S+) (\S+)), sub { + my $id = $1; + my $type = $2; + + my $tag; + if ( $type eq 'link' ) { + $tag = 'a'; + } + S->{driver}->find_element('//'.$tag.'[@id="'.$id.'"]')->click; +}; + +When qr{I have filled the field (\S+) with "(.*)"}, sub { + my ($id, $value) = ($1, $2); + t::lib::Cucumber::Form::fill( S->{driver}, { $id => $value } ); +}; + +Then qr{I should see the (.*) page}, sub { + my $page = $1; + my $title; + if ( $page eq "new patron category" ) { + $title = 'New category'; + } + like( S->{driver}->get_title(), qr($title) ); +}; diff --git a/t/db_dependent/cucumber/features/step_definitions/hooks_steps.pl b/t/db_dependent/cucumber/features/step_definitions/hooks_steps.pl new file mode 100644 index 0000000..a5bb0ee --- /dev/null +++ b/t/db_dependent/cucumber/features/step_definitions/hooks_steps.pl @@ -0,0 +1,5 @@ +After sub { + my $dbh = C4::Context->dbh; + $dbh->do(q|DELETE FROM categories WHERE categorycode = ?|, {}, S->{patron_category_code}); + $dbh->do(q|DELETE FROM borrowers WHERE userid=?|, {}, S->{patron_userid}); +}; diff --git a/t/db_dependent/cucumber/tests.t b/t/db_dependent/cucumber/tests.t new file mode 100644 index 0000000..8ed78dd --- /dev/null +++ b/t/db_dependent/cucumber/tests.t @@ -0,0 +1,23 @@ +use Modern::Perl; +use Test::More; + +# This will find step definitions and feature files in the directory you point +# it at below +use Test::BDD::Cucumber::Loader; + +# This harness prints out nice TAP +use Test::BDD::Cucumber::Harness::TestBuilder; + +# Load a directory with Cucumber files in it. It will recursively execute any +# file matching .*_steps.pl as a Step file, and .*\.feature as a feature file. +# The features are returned in @features, and the executor is created with the +# step definitions loaded. +my ( $executor, @features ) = Test::BDD::Cucumber::Loader->load( + 'features/' ); + +# Create a Harness to execute against. TestBuilder harness prints TAP +my $harness = Test::BDD::Cucumber::Harness::TestBuilder->new({}); + +# For each feature found, execute it, using the Harness to print results +$executor->execute( $_, $harness ) for @features; +done_testing; diff --git a/t/lib/Cucumber.pm b/t/lib/Cucumber.pm new file mode 100644 index 0000000..0974a42 --- /dev/null +++ b/t/lib/Cucumber.pm @@ -0,0 +1,3 @@ +package t::lib::Cucumber; + +1; diff --git a/t/lib/Cucumber/Form.pm b/t/lib/Cucumber/Form.pm new file mode 100644 index 0000000..18b83b9 --- /dev/null +++ b/t/lib/Cucumber/Form.pm @@ -0,0 +1,16 @@ +package t::lib::Cucumber::Form; + +sub fill { + my ( $driver, $values ) = @_; + while ( my ( $id, $value ) = each %$values ) { + my $element = $driver->find_element('//*[@id="'.$id.'"]'); + my $tag = $element->get_tag_name(); + if ( $tag eq 'input' ) { + $driver->find_element('//input[@id="'.$id.'"]')->send_keys($value); + } elsif ( $tag eq 'select' ) { + $driver->find_element('//select[@id="'.$id.'"]/option[@value="'.$value.'"]')->click; + } + } +} + +1; diff --git a/t/lib/Cucumber/Paths.pm b/t/lib/Cucumber/Paths.pm new file mode 100644 index 0000000..91c64ab --- /dev/null +++ b/t/lib/Cucumber/Paths.pm @@ -0,0 +1,19 @@ +package t::lib::Cucumber::Paths; + +use C4::Context; + +sub get { + my ( $page ) = @_; + my $base_url = 'http://'.C4::Context->preference("staffClientBaseURL")."/cgi-bin/koha/"; + my $paths = { + 'mainpage' => $base_url.'mainpage.pl?logout.x=1', + 'patron category list' => $base_url.'admin/categorie.pl', + 'new patron category' => $base_url.'admin/categorie.pl?op=add_form', + 'patron home' => $base_url.'members/members-home.pl', + 'new patron' => $base_url.'members/memberentry.pl?op=add&category_type=A' + }; + die "Invalid path" unless exists $paths->{$page}; + return $paths->{$page}; +} + +1; -- 2.1.0