Bug 31139: Fix basic_workflow.t
[koha.git] / 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 );
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 SKIP: {
89     eval { require Selenium::Remote::Driver; };
90     skip "Selenium::Remote::Driver is needed for selenium tests.", 22 if $@;
91
92     $cleanup_needed = 1;
93
94     $dbh->do(q|INSERT INTO itemtypes(itemtype) VALUES (?)|, undef, $sample_data->{itemtype}{itemtype});
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 $effective_input = $input;
187             my $v;
188
189             # FIXME This is based on default values
190             if (   $id =~ m|^tag_952_subfield_g|   # price
191                 or $id =~ m|^tag_952_subfield_v| ) # replacementprice
192             {
193                 $v = '42';    # It's a price
194             }
195             elsif (
196                 $id =~ m|^tag_952_subfield_f| #tag_952_subfield_g
197             ) {
198                 # It's a varchar(10)
199                 $v = 't_value_x';
200             }
201             elsif (
202                 $id =~ m|^tag_952_subfield_w| # replacementpricedate
203             ) {
204                 $v = strftime("%Y-%m-%d", localtime);
205                 $effective_input = $driver->find_element('//div[@id="subfield952w"]/input[@class="input_marceditor flatpickr-input"]');
206             }
207             elsif (
208                 $id =~ m|^tag_952_subfield_d| # dateaccessioned
209             ) {
210                 next; # The input has been prefilled with %Y-%m-%d already
211             }
212             elsif (
213                 $id =~ m|^tag_952_subfield_3| # materials
214             ) {
215                 $v = ""; # We don't want the checkin/checkout to need confirmation if CircConfirmItemParts is on
216             }
217             else {
218                 $v = 't_value_bib' . $biblionumber;
219             }
220             $effective_input->send_keys( $v );
221         }
222
223         $driver->find_element('//input[@name="add_submit"]')->click;
224         like( $driver->get_title(), qr(Items.*Record #$biblionumber) );
225
226         $dbh->do(q|UPDATE items SET notforloan=0 WHERE biblionumber=?|, {}, $biblionumber );
227         $dbh->do(q|UPDATE biblioitems SET itemtype=? WHERE biblionumber=?|, {}, $itemtype->{itemtype}, $biblionumber);
228         $dbh->do(q|UPDATE items SET itype=? WHERE biblionumber=?|, {}, $itemtype->{itemtype}, $biblionumber);
229     }
230
231     time_diff("add items");
232
233     my $nb_of_checkouts = 0;
234     for my $biblionumber ( @biblionumbers ) {
235         $driver->get($base_url."/circ/circulation.pl?borrowernumber=".$borrowernumber);
236         $driver->find_element('//input[@id="barcode"]')->send_keys('t_value_bib'.$biblionumber);
237         $driver->find_element('//fieldset[@id="circ_circulation_issue"]/button[@type="submit"]')->click;
238         $nb_of_checkouts++;
239         like( $driver->get_title(), qr(Checking out to $sample_data->{patron}{surname}) );
240         is( $driver->find_element('//a[@href="#checkouts"]')->get_attribute('text'), 'Checkouts ('.$nb_of_checkouts.')' );
241     }
242
243     time_diff("checkout");
244
245     for my $biblionumber ( @biblionumbers ) {
246         $driver->get($base_url."/circ/returns.pl");
247         $driver->find_element('//input[@id="barcode"]')->send_keys('t_value_bib'.$biblionumber);
248         $driver->find_element('//*[@id="circ_returns_checkin"]/div[2]/div[1]/div[2]/button')->click;
249         like( $driver->get_title(), qr(Check in test biblio \d+) );
250     }
251
252     time_diff("checkin");
253
254     #Place holds
255     $driver->get($base_url."/reserve/request.pl?borrowernumber=$borrowernumber&biblionumber=".$biblionumbers[0]);
256     $driver->find_element('//form[@id="hold-request-form"]//button[@type="submit"]')->click; # Biblio level
257     $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)
258     my $patron = Koha::Patrons->find($borrowernumber);
259     is( $patron->holds->count, 1, );
260
261     $driver->get($base_url."/reserve/request.pl?borrowernumber=$borrowernumber&biblionumber=".$biblionumbers[1]);
262     $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
263     $driver->find_element('//form[@id="hold-request-form"]//button[@type="submit"]')->click;
264     $driver->pause(1000);
265     is( $patron->holds->count, 2, );
266
267     time_diff("holds");
268
269     close $fh;
270     $driver->quit();
271 };
272
273 END {
274     cleanup() if $cleanup_needed;
275 };
276
277 sub cleanup {
278     my $dbh = C4::Context->dbh;
279     $dbh->do(q|DELETE FROM issues where borrowernumber=?|, {}, $borrowernumber);
280     $dbh->do(q|DELETE FROM old_issues where borrowernumber=?|, {}, $borrowernumber);
281     for my $i ( 1 .. $number_of_biblios_to_insert ) {
282         $dbh->do(qq|DELETE items, biblio FROM biblio INNER JOIN items ON biblio.biblionumber = items.biblionumber WHERE biblio.title = "test biblio$i"|);
283     };
284     $dbh->do(q|DELETE FROM borrowers WHERE userid = ?|, {}, $sample_data->{patron}{userid});
285     $dbh->do(q|DELETE FROM categories WHERE categorycode = ?|, {}, $sample_data->{category}{categorycode});
286     for my $i ( 1 .. $number_of_biblios_to_insert ) {
287         $dbh->do(qq|DELETE FROM biblio WHERE title = "test biblio $i"|);
288     };
289     $dbh->do(q|DELETE FROM itemtypes WHERE itemtype=?|, undef, $sample_data->{itemtype}{itemtype});
290     $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});
291 }
292
293 sub time_diff {
294     my $lib = shift;
295     my $now = gettimeofday;
296     warn "CP $lib = " . sprintf("%.2f", $now - $prev_time ) . "\n";
297     $prev_time = $now;
298 }