Bug 33528: 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 $itemtype = $sample_data->{itemtype};
134
135     my @biblionumbers;
136     for my $i ( 1 .. $number_of_biblios_to_insert ) {
137         my $biblio = MARC::Record->new();
138         my $title = 'test biblio '.$i;
139         if ( C4::Context->preference('marcflavour') eq 'UNIMARC' ) {
140             $biblio->append_fields(
141                 MARC::Field->new('200', ' ', ' ', a => 'test biblio '.$i),
142                 MARC::Field->new('200', ' ', ' ', f => 'test author '.$i),
143                 MARC::Field->new('200', ' ', ' ', b => $itemtype->{itemtype}),
144             );
145         } else {
146             $biblio->append_fields(
147                 MARC::Field->new('245', ' ', ' ', a => 'test biblio '.$i),
148                 MARC::Field->new('100', ' ', ' ', a => 'test author '.$i),
149                 MARC::Field->new('942', ' ', ' ', c => $itemtype->{itemtype}),
150             );
151         }
152         my ($biblionumber, $biblioitemnumber) = AddBiblio($biblio, '');
153         push @biblionumbers, $biblionumber;
154     }
155
156     time_diff("add biblio");
157
158     my $issuing_rules = $sample_data->{issuingrule};
159     Koha::CirculationRules->set_rules(
160         {
161             categorycode => $issuing_rules->{categorycode},
162             itemtype     => $issuing_rules->{itemtype},
163             branchcode   => $issuing_rules->{branchcode},
164             rules => {
165                 maxissueqty     => $issuing_rules->{maxissueqty},
166                 issuelength     => $issuing_rules->{issuelength},
167                 lengthunit      => $issuing_rules->{lengthunit},
168                 renewalperiod   => $issuing_rules->{renewalperiod},
169                 reservesallowed => $issuing_rules->{reservesallowed},
170                 onshelfholds    => $issuing_rules->{onshelfholds},
171                 opacitemholds   => $issuing_rules->{opacitemholds},
172
173               }
174         }
175     );
176
177
178     for my $biblionumber ( @biblionumbers ) {
179         $driver->get($base_url."/cataloguing/additem.pl?biblionumber=$biblionumber");
180         like( $driver->get_title(), qr(test biblio \d+ by test author), );
181         my $form = $driver->find_element('//form[@name="f"]');
182         # select the text inputs that don't have display:none
183         my $inputs = $driver->find_child_elements($form, '/.//*[not(self::node()[contains(@style,"display:none")])]/*[@type="text"]');
184         for my $input ( @$inputs ) {
185             my $id = $input->get_attribute('id');
186             next unless $id =~ m|^tag_952_subfield|;
187
188             my $effective_input = $input;
189             my $v;
190
191             # FIXME This is based on default values
192             if (   $id =~ m|^tag_952_subfield_g|   # price
193                 or $id =~ m|^tag_952_subfield_v| ) # replacementprice
194             {
195                 $v = '42';    # It's a price
196             }
197             elsif (
198                 $id =~ m|^tag_952_subfield_f| #tag_952_subfield_g
199             ) {
200                 # It's a varchar(10)
201                 $v = 't_value_x';
202             }
203             elsif (
204                 $id =~ m|^tag_952_subfield_w| # replacementpricedate
205             ) {
206                 $v = strftime("%Y-%m-%d", localtime);
207                 $effective_input = $driver->find_element('//div[@id="subfield952w"]/input[@type="text" and @class="input_marceditor items.replacementpricedate noEnterSubmit flatpickr-input"]');
208             }
209             elsif (
210                 $id =~ m|^tag_952_subfield_y| # itemtype
211             ) {
212                 next; # auto-filled
213             }
214             elsif (
215                 $id =~ m|^tag_952_subfield_d| # dateaccessioned
216             ) {
217                 next; # The input has been prefilled with %Y-%m-%d already
218             }
219             elsif (
220                 $id =~ m|^tag_952_subfield_3| # materials
221             ) {
222                 $v = ""; # We don't want the checkin/checkout to need confirmation if CircConfirmItemParts is on
223             }
224             else {
225                 $v = 't_value_bib' . $biblionumber;
226             }
227             $effective_input->send_keys( $v );
228         }
229
230         # Find itemtype select2 and open it
231         my $itype_select = $driver->find_element('//*[@id="subfield952y"]/span[1]');
232         $itype_select->click;
233         # Select an itemtype
234         my $options = $driver->find_elements('.select2-results__option', 'css');
235         @$options[0]->click;
236
237         $driver->find_element('//input[@name="add_submit"]')->click;
238         like( $driver->get_title(), qr(Items.*Record #$biblionumber) );
239
240         $dbh->do(q|UPDATE items SET notforloan=0 WHERE biblionumber=?|, {}, $biblionumber );
241         $dbh->do(q|UPDATE biblioitems SET itemtype=? WHERE biblionumber=?|, {}, $itemtype->{itemtype}, $biblionumber);
242         $dbh->do(q|UPDATE items SET itype=? WHERE biblionumber=?|, {}, $itemtype->{itemtype}, $biblionumber);
243     }
244
245     time_diff("add items");
246
247     my $nb_of_checkouts = 0;
248     for my $biblionumber ( @biblionumbers ) {
249         $driver->get($base_url."/circ/circulation.pl?borrowernumber=".$borrowernumber);
250         $driver->find_element('//input[@id="barcode"]')->send_keys('t_value_bib'.$biblionumber);
251         $driver->find_element('//fieldset[@id="circ_circulation_issue"]/button[@type="submit"]')->click;
252         $nb_of_checkouts++;
253         like( $driver->get_title(), qr(Checking out to $sample_data->{patron}{surname}) );
254         like( $driver->find_element('//a[@href="#checkouts_panel"]')->get_attribute('text'), qr/Checkouts \($nb_of_checkouts\)/ );
255     }
256
257     time_diff("checkout");
258
259     for my $biblionumber ( @biblionumbers ) {
260         $driver->get($base_url."/circ/returns.pl");
261         $driver->find_element('//input[@id="barcode"]')->send_keys('t_value_bib'.$biblionumber);
262         $driver->find_element('//*[@id="circ_returns_checkin"]//button[@type="submit"]')->click;
263         like( $driver->get_title(), qr(Check in test biblio \d+) );
264     }
265
266     time_diff("checkin");
267
268     #Place holds
269     $driver->get($base_url."/reserve/request.pl?borrowernumber=$borrowernumber&biblionumber=".$biblionumbers[0]);
270     $driver->find_element('//form[@id="hold-request-form"]//button[@type="submit"]')->click; # Biblio level
271     $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)
272     my $patron = Koha::Patrons->find($borrowernumber);
273     is( $patron->holds->count, 1, );
274
275     $driver->get($base_url."/reserve/request.pl?borrowernumber=$borrowernumber&biblionumber=".$biblionumbers[1]);
276     $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
277     $driver->find_element('//form[@id="hold-request-form"]//button[@type="submit"]')->click;
278     $driver->pause(1000);
279     is( $patron->holds->count, 2, );
280
281     time_diff("holds");
282
283     close $fh;
284     $driver->quit();
285 };
286
287 END {
288     cleanup() if $cleanup_needed;
289 };
290
291 sub cleanup {
292     my $dbh = C4::Context->dbh;
293     $dbh->do(q|DELETE FROM issues where borrowernumber=?|, {}, $borrowernumber);
294     $dbh->do(q|DELETE FROM old_issues where borrowernumber=?|, {}, $borrowernumber);
295     for my $i ( 1 .. $number_of_biblios_to_insert ) {
296         $dbh->do(qq|DELETE items, biblio FROM biblio INNER JOIN items ON biblio.biblionumber = items.biblionumber WHERE biblio.title = "test biblio$i"|);
297     };
298     $dbh->do(q|DELETE FROM borrowers WHERE userid = ?|, {}, $sample_data->{patron}{userid});
299     $dbh->do(q|DELETE FROM categories WHERE categorycode = ?|, {}, $sample_data->{category}{categorycode});
300     for my $i ( 1 .. $number_of_biblios_to_insert ) {
301         $dbh->do(qq|DELETE FROM biblio WHERE title = "test biblio $i"|);
302     };
303     $dbh->do(q|DELETE FROM itemtypes WHERE itemtype=?|, undef, $sample_data->{itemtype}{itemtype});
304     $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});
305 }
306
307 sub time_diff {
308     my $lib = shift;
309     my $now = gettimeofday;
310     warn "CP $lib = " . sprintf("%.2f", $now - $prev_time ) . "\n";
311     $prev_time = $now;
312 }