4d0410450c4178d559534c6d9d57f35f81c3708a
[srvgit] / t / db_dependent / selenium / basic_workflow.t
1 #!/usr/bin/perl
2
3 # This file is part of Koha.
4 #
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
19
20 # wget https://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.1.jar # Does not work with 3.4, did not test the ones between
21 # sudo apt-get install xvfb firefox-esr
22 # SELENIUM_PATH=/home/vagrant/selenium-server-standalone-2.53.1.jar
23 # Xvfb :1 -screen 0 1024x768x24 2>&1 >/dev/null &
24 # DISPLAY=:1 java -jar $SELENIUM_PATH
25 #
26 # Then you can execute the test file.
27 #
28 # If you get:
29 # Wide character in print at /usr/local/share/perl/5.20.2/Test2/Formatter/TAP.pm line 105.
30 # #                   'Koha › Patrons › Add patron test_patron_surname (Adult)'
31 # #     doesn't match '(?^u:Patron details for test_patron_surname)'
32 #
33 # Ignore and retry (FIXME LATER...)
34
35 use Modern::Perl;
36
37 use Time::HiRes qw(gettimeofday);
38 use POSIX qw(strftime);
39 use C4::Context;
40 use C4::Biblio qw( AddBiblio ); # We shouldn't use it
41
42 use Koha::CirculationRules;
43
44 use Test::More tests => 22;
45 use MARC::Record;
46 use MARC::Field;
47
48 use t::lib::Selenium;
49
50 my $dbh      = C4::Context->dbh;
51
52 my $number_of_biblios_to_insert = 3;
53 our $sample_data = {
54     category => {
55         categorycode    => 'TEST_CAT',
56         description     => 'test cat description',
57         enrolmentperiod => '12',
58         category_type   => 'A'
59     },
60     patron => {
61         surname    => 'test_patron_surname',
62         cardnumber => '4242424242',
63         userid     => 'test_username',
64         password   => '1BetterPassword',
65         password2  => '1BetterPassword'
66     },
67     itemtype => {
68         itemtype     => 'IT4TEST',
69         description  => 'Just an itemtype for tests',
70         rentalcharge => 0,
71         notforloan   => 0,
72     },
73     issuingrule => {
74         categorycode  => 'test_cat',
75         itemtype      => 'IT4test',
76         branchcode    => undef,
77         maxissueqty   => '5',
78         issuelength   => '5',
79         lengthunit    => 'days',
80         renewalperiod => '5',
81         reservesallowed => '5',
82         onshelfholds  => '1',
83         opacitemholds => 'Y',
84       },
85 };
86 our ( $borrowernumber, $start, $prev_time, $cleanup_needed );
87
88 $dbh->do(q|INSERT INTO itemtypes(itemtype) VALUES (?)|, undef, $sample_data->{itemtype}{itemtype});
89
90 SKIP: {
91     eval { require Selenium::Remote::Driver; };
92     skip "Selenium::Remote::Driver is needed for selenium tests.", 22 if $@;
93
94     $cleanup_needed = 1;
95
96     open my $fh, '>>', '/tmp/output.txt';
97
98     my $s = t::lib::Selenium->new;
99
100     my $driver = $s->driver;
101     my $base_url = $s->base_url;
102
103     $start = gettimeofday;
104     $prev_time = $start;
105     $driver->get($base_url."mainpage.pl");
106     like( $driver->get_title(), qr(Log in to Koha), );
107     $s->auth;
108     time_diff("main");
109
110     $driver->get($base_url.'admin/categories.pl');
111     like( $driver->get_title(), qr(Patron categories), );
112     $driver->find_element('//a[@id="newcategory"]')->click;
113     like( $driver->get_title(), qr(New category), );
114     $s->fill_form( $sample_data->{category} );
115     $driver->find_element('//fieldset[@class="action"]/input[@type="submit"]')->click;
116
117     time_diff("add patron category");
118     $driver->get($base_url.'/members/memberentry.pl?op=add&amp;categorycode='.$sample_data->{category}{categorycode});
119     like( $driver->get_title(), qr(Add .*$sample_data->{category}{description}), );
120     $s->fill_form( $sample_data->{patron} );
121     $driver->find_element('//button[@id="saverecord"]')->click;
122     like( $driver->get_title(), qr(Patron details for $sample_data->{patron}{surname}), );
123
124     ####$driver->get($base_url.'/members/members-home.pl');
125     ####fill_form( $driver, { searchmember => $sample_data->{patron}{cardnumber} } );
126     ####$driver->find_element('//div[@id="header_search"]/div/form/input[@type="submit"]')->click;
127     ####like( $driver->get_title(), qr(Patron details for), );
128
129     time_diff("add patron");
130
131     $borrowernumber = $dbh->selectcol_arrayref(q|SELECT borrowernumber FROM borrowers WHERE userid=?|, {}, $sample_data->{patron}{userid} )->[0];
132
133     my @biblionumbers;
134     for my $i ( 1 .. $number_of_biblios_to_insert ) {
135         my $biblio = MARC::Record->new();
136         my $title = 'test biblio '.$i;
137         if ( C4::Context->preference('marcflavour') eq 'UNIMARC' ) {
138             $biblio->append_fields(
139                 MARC::Field->new('200', ' ', ' ', a => 'test biblio '.$i),
140                 MARC::Field->new('200', ' ', ' ', f => 'test author '.$i),
141             );
142         } else {
143             $biblio->append_fields(
144                 MARC::Field->new('245', ' ', ' ', a => 'test biblio '.$i),
145                 MARC::Field->new('100', ' ', ' ', a => 'test author '.$i),
146             );
147         }
148         my ($biblionumber, $biblioitemnumber) = AddBiblio($biblio, '');
149         push @biblionumbers, $biblionumber;
150     }
151
152     time_diff("add biblio");
153
154     my $itemtype = $sample_data->{itemtype};
155
156     my $issuing_rules = $sample_data->{issuingrule};
157     Koha::CirculationRules->set_rules(
158         {
159             categorycode => $issuing_rules->{categorycode},
160             itemtype     => $issuing_rules->{itemtype},
161             branchcode   => $issuing_rules->{branchcode},
162             rules => {
163                 maxissueqty     => $issuing_rules->{maxissueqty},
164                 issuelength     => $issuing_rules->{issuelength},
165                 lengthunit      => $issuing_rules->{lengthunit},
166                 renewalperiod   => $issuing_rules->{renewalperiod},
167                 reservesallowed => $issuing_rules->{reservesallowed},
168                 onshelfholds    => $issuing_rules->{onshelfholds},
169                 opacitemholds   => $issuing_rules->{opacitemholds},
170
171               }
172         }
173     );
174
175
176     for my $biblionumber ( @biblionumbers ) {
177         $driver->get($base_url."/cataloguing/additem.pl?biblionumber=$biblionumber");
178         like( $driver->get_title(), qr(test biblio \d+ by test author), );
179         my $form = $driver->find_element('//form[@name="f"]');
180         # select the text inputs that don't have display:none
181         my $inputs = $driver->find_child_elements($form, '/.//*[not(self::node()[contains(@style,"display:none")])]/*[@type="text"]');
182         for my $input ( @$inputs ) {
183             my $id = $input->get_attribute('id');
184             next unless $id =~ m|^tag_952_subfield|;
185
186             my $v;
187
188             # FIXME This is based on default values
189             if (   $id =~ m|^tag_952_subfield_g|   # price
190                 or $id =~ m|^tag_952_subfield_v| ) # replacementprice
191             {
192                 $v = '42';    # It's a price
193             }
194             elsif (
195                 $id =~ m|^tag_952_subfield_f| #tag_952_subfield_g
196             ) {
197                 # It's a varchar(10)
198                 $v = 't_value_x';
199             }
200             elsif (
201                 $id =~ m|^tag_952_subfield_w| # replacementpricedate
202             ) {
203                 $v = strftime("%Y-%m-%d", localtime);
204             }
205             elsif (
206                 $id =~ m|^tag_952_subfield_d| # dateaccessioned
207             ) {
208                 next; # The input has been prefilled with %Y-%m-%d already
209             }
210             elsif (
211                 $id =~ m|^tag_952_subfield_3| # materials
212             ) {
213                 $v = ""; # We don't want the checkin/checkout to need confirmation if CircConfirmItemParts is on
214             }
215             else {
216                 $v = 't_value_bib' . $biblionumber;
217             }
218             $input->send_keys( $v );
219         }
220
221         $driver->find_element('//input[@name="add_submit"]')->click;
222         like( $driver->get_title(), qr(Items.*Record #$biblionumber) );
223
224         $dbh->do(q|UPDATE items SET notforloan=0 WHERE biblionumber=?|, {}, $biblionumber );
225         $dbh->do(q|UPDATE biblioitems SET itemtype=? WHERE biblionumber=?|, {}, $itemtype->{itemtype}, $biblionumber);
226         $dbh->do(q|UPDATE items SET itype=? WHERE biblionumber=?|, {}, $itemtype->{itemtype}, $biblionumber);
227     }
228
229     time_diff("add items");
230
231     my $nb_of_checkouts = 0;
232     for my $biblionumber ( @biblionumbers ) {
233         $driver->get($base_url."/circ/circulation.pl?borrowernumber=".$borrowernumber);
234         $driver->find_element('//input[@id="barcode"]')->send_keys('t_value_bib'.$biblionumber);
235         $driver->find_element('//fieldset[@id="circ_circulation_issue"]/button[@type="submit"]')->click;
236         $nb_of_checkouts++;
237         like( $driver->get_title(), qr(Checking out to $sample_data->{patron}{surname}) );
238         is( $driver->find_element('//a[@href="#checkouts"]')->get_attribute('text'), $nb_of_checkouts.' Checkout(s)', );
239     }
240
241     time_diff("checkout");
242
243     for my $biblionumber ( @biblionumbers ) {
244         $driver->get($base_url."/circ/returns.pl");
245         $driver->find_element('//input[@id="barcode"]')->send_keys('t_value_bib'.$biblionumber);
246         $driver->find_element('//*[@id="circ_returns_checkin"]/div[2]/div[1]/div[2]/button')->click;
247         like( $driver->get_title(), qr(Check in test biblio \d+) );
248     }
249
250     time_diff("checkin");
251
252     #Place holds
253     $driver->get($base_url."/reserve/request.pl?borrowernumber=$borrowernumber&biblionumber=".$biblionumbers[0]);
254     $driver->find_element('//form[@id="hold-request-form"]//button[@type="submit"]')->click; # Biblio level
255     $driver->pause(1000); # This seems wrong, since bug 19618 the hold is created async with an AJAX call. Not sure what is happening here but the next statements are exectuted before the hold is created and the count is wrong (still 0)
256     my $patron = Koha::Patrons->find($borrowernumber);
257     is( $patron->holds->count, 1, );
258
259     $driver->get($base_url."/reserve/request.pl?borrowernumber=$borrowernumber&biblionumber=".$biblionumbers[1]);
260     $driver->find_element('//form[@id="hold-request-form"]//input[@type="radio"]')->click; # Item level, there is only 1 item per bib so we are safe
261     $driver->find_element('//form[@id="hold-request-form"]//button[@type="submit"]')->click;
262     $driver->pause(1000);
263     is( $patron->holds->count, 2, );
264
265     time_diff("holds");
266
267     close $fh;
268     $driver->quit();
269 };
270
271 END {
272     cleanup() if $cleanup_needed;
273 };
274
275 sub cleanup {
276     my $dbh = C4::Context->dbh;
277     $dbh->do(q|DELETE FROM issues where borrowernumber=?|, {}, $borrowernumber);
278     $dbh->do(q|DELETE FROM old_issues where borrowernumber=?|, {}, $borrowernumber);
279     for my $i ( 1 .. $number_of_biblios_to_insert ) {
280         $dbh->do(qq|DELETE items, biblio FROM biblio INNER JOIN items ON biblio.biblionumber = items.biblionumber WHERE biblio.title = "test biblio$i"|);
281     };
282     $dbh->do(q|DELETE FROM borrowers WHERE userid = ?|, {}, $sample_data->{patron}{userid});
283     $dbh->do(q|DELETE FROM categories WHERE categorycode = ?|, {}, $sample_data->{category}{categorycode});
284     for my $i ( 1 .. $number_of_biblios_to_insert ) {
285         $dbh->do(qq|DELETE FROM biblio WHERE title = "test biblio $i"|);
286     };
287     $dbh->do(q|DELETE FROM itemtypes WHERE itemtype=?|, undef, $sample_data->{itemtype}{itemtype});
288     $dbh->do(q|DELETE FROM circulation_rules WHERE categorycode=? AND itemtype=? AND branchcode=?|, undef, $sample_data->{issuingrule}{categorycode}, $sample_data->{issuingrule}{itemtype}, $sample_data->{issuingrule}{branchcode});
289 }
290
291 sub time_diff {
292     my $lib = shift;
293     my $now = gettimeofday;
294     warn "CP $lib = " . sprintf("%.2f", $now - $prev_time ) . "\n";
295     $prev_time = $now;
296 }