3 # This file is part of Koha.
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.
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.
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>.
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
26 # Then you can execute the test file.
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)'
33 # Ignore and retry (FIXME LATER...)
37 use Time::HiRes qw(gettimeofday);
38 use POSIX qw(strftime);
40 use C4::Biblio qw( AddBiblio );
42 use Koha::CirculationRules;
44 use Test::More tests => 22;
50 my $dbh = C4::Context->dbh;
52 my $number_of_biblios_to_insert = 3;
55 categorycode => 'TEST_CAT',
56 description => 'test cat description',
57 enrolmentperiod => '12',
61 surname => 'test_patron_surname',
62 cardnumber => '4242424242',
63 userid => 'test_username',
64 password => '1BetterPassword',
65 password2 => '1BetterPassword'
68 itemtype => 'IT4TEST',
69 description => 'Just an itemtype for tests',
74 categorycode => 'test_cat',
75 itemtype => 'IT4test',
81 reservesallowed => '5',
86 our ( $borrowernumber, $start, $prev_time, $cleanup_needed );
89 eval { require Selenium::Remote::Driver; };
90 skip "Selenium::Remote::Driver is needed for selenium tests.", 22 if $@;
94 $dbh->do(q|INSERT INTO itemtypes(itemtype) VALUES (?)|, undef, $sample_data->{itemtype}{itemtype});
96 open my $fh, '>>', '/tmp/output.txt';
98 my $s = t::lib::Selenium->new;
100 my $driver = $s->driver;
101 my $base_url = $s->base_url;
103 $start = gettimeofday;
105 $driver->get($base_url."mainpage.pl");
106 like( $driver->get_title(), qr(Log in to Koha), );
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;
117 time_diff("add patron category");
118 $driver->get($base_url.'/members/memberentry.pl?op=add&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}), );
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), );
129 time_diff("add patron");
131 $borrowernumber = $dbh->selectcol_arrayref(q|SELECT borrowernumber FROM borrowers WHERE userid=?|, {}, $sample_data->{patron}{userid} )->[0];
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),
143 $biblio->append_fields(
144 MARC::Field->new('245', ' ', ' ', a => 'test biblio '.$i),
145 MARC::Field->new('100', ' ', ' ', a => 'test author '.$i),
148 my ($biblionumber, $biblioitemnumber) = AddBiblio($biblio, '');
149 push @biblionumbers, $biblionumber;
152 time_diff("add biblio");
154 my $itemtype = $sample_data->{itemtype};
156 my $issuing_rules = $sample_data->{issuingrule};
157 Koha::CirculationRules->set_rules(
159 categorycode => $issuing_rules->{categorycode},
160 itemtype => $issuing_rules->{itemtype},
161 branchcode => $issuing_rules->{branchcode},
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},
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|;
186 my $effective_input = $input;
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
193 $v = '42'; # It's a price
196 $id =~ m|^tag_952_subfield_f| #tag_952_subfield_g
202 $id =~ m|^tag_952_subfield_w| # replacementpricedate
204 $v = strftime("%Y-%m-%d", localtime);
205 $effective_input = $driver->find_element('//div[@id="subfield952w"]/input[@class="input_marceditor flatpickr-input"]');
208 $id =~ m|^tag_952_subfield_d| # dateaccessioned
210 next; # The input has been prefilled with %Y-%m-%d already
213 $id =~ m|^tag_952_subfield_3| # materials
215 $v = ""; # We don't want the checkin/checkout to need confirmation if CircConfirmItemParts is on
218 $v = 't_value_bib' . $biblionumber;
220 $effective_input->send_keys( $v );
223 $driver->find_element('//input[@name="add_submit"]')->click;
224 like( $driver->get_title(), qr(Items.*Record #$biblionumber) );
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);
231 time_diff("add items");
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;
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.')' );
243 time_diff("checkout");
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+) );
252 time_diff("checkin");
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, );
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, );
274 cleanup() if $cleanup_needed;
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"|);
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"|);
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});
295 my $now = gettimeofday;
296 warn "CP $lib = " . sprintf("%.2f", $now - $prev_time ) . "\n";