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];
133 my $itemtype = $sample_data->{itemtype};
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}),
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}),
152 my ($biblionumber, $biblioitemnumber) = AddBiblio($biblio, '');
153 push @biblionumbers, $biblionumber;
156 time_diff("add biblio");
158 my $issuing_rules = $sample_data->{issuingrule};
159 Koha::CirculationRules->set_rules(
161 categorycode => $issuing_rules->{categorycode},
162 itemtype => $issuing_rules->{itemtype},
163 branchcode => $issuing_rules->{branchcode},
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},
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|;
188 my $effective_input = $input;
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
195 $v = '42'; # It's a price
198 $id =~ m|^tag_952_subfield_f| #tag_952_subfield_g
204 $id =~ m|^tag_952_subfield_w| # replacementpricedate
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"]');
210 $id =~ m|^tag_952_subfield_y| # itemtype
215 $id =~ m|^tag_952_subfield_d| # dateaccessioned
217 next; # The input has been prefilled with %Y-%m-%d already
220 $id =~ m|^tag_952_subfield_3| # materials
222 $v = ""; # We don't want the checkin/checkout to need confirmation if CircConfirmItemParts is on
225 $v = 't_value_bib' . $biblionumber;
227 $effective_input->send_keys( $v );
230 # Find itemtype select2 and open it
231 my $itype_select = $driver->find_element('//*[@id="subfield952y"]/span[1]');
232 $itype_select->click;
234 my $options = $driver->find_elements('.select2-results__option', 'css');
237 $driver->find_element('//input[@name="add_submit"]')->click;
238 like( $driver->get_title(), qr(Items.*Record #$biblionumber) );
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);
245 time_diff("add items");
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;
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\)/ );
257 time_diff("checkout");
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+) );
266 time_diff("checkin");
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, );
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, );
288 cleanup() if $cleanup_needed;
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"|);
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"|);
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});
309 my $now = gettimeofday;
310 warn "CP $lib = " . sprintf("%.2f", $now - $prev_time ) . "\n";