1 package t::lib::Selenium;
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>.
21 use JSON qw( from_json );
25 use base qw(Class::Accessor);
26 __PACKAGE__->mk_accessors(qw(login password base_url opac_base_url selenium_addr selenium_port driver));
29 my ( $class, $driver ) = @_;
31 my $lutim_server = q|https://framapic.org|; # Thanks Framasoft!
32 $driver->capture_screenshot('selenium_failure.png');
33 my $from_json = from_json qx{curl -s -F "format=json" -F "file=\@selenium_failure.png" -F "delete-day=1" $lutim_server};
35 print STDERR "\nSCREENSHOT: $lutim_server/" . $from_json->{msg}->{short} . "\n";
40 my ( $class, $params ) = @_;
42 my $config = $class->config;
43 $self->{login} = $params->{login} || $config->{login};
44 $self->{password} = $params->{password} || $config->{password};
45 $self->{base_url} = $params->{base_url} || $config->{base_url};
46 $self->{opac_base_url} = $params->{opac_base_url} || $config->{opac_base_url};
47 $self->{selenium_addr} = $params->{selenium_addr} || $config->{selenium_addr};
48 $self->{selenium_port} = $params->{selenium_port} || $config->{selenium_port};
49 $self->{driver} = Selenium::Remote::Driver->new(
50 port => $self->{selenium_port},
51 remote_server_addr => $self->{selenium_addr},
52 error_handler => sub {
53 my ( $driver, $selenium_error ) = @_;
54 print STDERR "\nSTRACE:";
56 while ( (my @call_details = (caller($i++))) ){
57 print STDERR "\t" . $call_details[1]. ":" . $call_details[2] . " in " . $call_details[3]."\n";
60 $class->capture( $driver );
61 croak $selenium_error;
64 return bless $self, $class;
69 login => $ENV{KOHA_USER} || 'koha',
70 password => $ENV{KOHA_PASS} || 'koha',
71 base_url => ( $ENV{KOHA_INTRANET_URL} || C4::Context->preference("staffClientBaseURL") ) . "/cgi-bin/koha/",
72 opac_base_url => ( $ENV{KOHA_OPAC_URL} || C4::Context->preference("OPACBaseURL") ) . "/cgi-bin/koha/",
73 selenium_addr => $ENV{SELENIUM_ADDR} || 'localhost',
74 selenium_port => $ENV{SELENIUM_PORT} || 4444,
79 my ( $self, $login, $password ) = @_;
81 $login ||= $self->login;
82 $password ||= $self->password;
83 my $mainpage = $self->base_url . 'mainpage.pl';
85 $self->driver->get($mainpage);
86 $self->fill_form( { userid => $login, password => $password } );
87 my $login_button = $self->driver->find_element('//input[@id="submit"]');
88 $login_button->submit();
92 my ( $self, $login, $password ) = @_;
94 $login ||= $self->login;
95 $password ||= $self->password;
96 my $mainpage = $self->opac_base_url . 'opac-main.pl';
98 $self->driver->get($mainpage);
99 $self->fill_form( { userid => $login, password => $password } );
104 my ( $self, $values ) = @_;
105 while ( my ( $id, $value ) = each %$values ) {
106 my $element = $self->driver->find_element('//*[@id="'.$id.'"]');
107 my $tag = $element->get_tag_name();
108 if ( $tag eq 'input' ) {
109 $self->driver->find_element('//input[@id="'.$id.'"]')->send_keys($value);
110 } elsif ( $tag eq 'select' ) {
111 $self->driver->find_element('//select[@id="'.$id.'"]/option[@value="'.$value.'"]')->click;
119 my $default_submit_selector = '//fieldset[@class="action"]/input[@type="submit"]';
120 $self->click_when_visible( $default_submit_selector );
124 my ( $self, $params ) = @_;
126 if ( exists $params->{main} ) {
127 $xpath_selector = '//div[@id="'.$params->{main}.'"]';
128 } elsif ( exists $params->{main_class} ) {
129 $xpath_selector = '//div[@class="'.$params->{main_class}.'"]';
131 if ( exists $params->{href} ) {
132 if ( ref( $params->{href} ) ) {
133 for my $k ( keys %{ $params->{href} } ) {
134 if ( $k eq 'ends-with' ) {
135 # ends-with version for xpath version 1
136 my $ends_with = $params->{href}{"ends-with"};
137 $xpath_selector .= '//a[substring(@href, string-length(@href) - string-length("'.$ends_with.'") + 1 ) = "'.$ends_with.'"]';
138 # ends-with version for xpath version 2
139 #$xpath_selector .= '//a[ends-with(@href, "'.$ends_with.'") ]';
142 die "Only ends-with is supported so far ($k)";
146 $xpath_selector .= '//a[contains(@href, "'.$params->{href}.'")]';
149 if ( exists $params->{id} ) {
150 $xpath_selector .= '//*[@id="'.$params->{id}.'"]';
152 $self->click_when_visible( $xpath_selector );
155 sub click_when_visible {
156 my ( $self, $xpath_selector ) = @_;
157 $self->driver->set_implicit_wait_timeout(20000);
159 while ( not $visible ) {
160 $elt = $self->driver->find_element($xpath_selector);
161 $visible = $elt->is_displayed;
162 $self->driver->pause(1000) unless $visible;
169 t::lib::Selenium - Selenium helper module
173 my $s = t::lib::Selenium->new;
174 my $driver = $s->driver;
175 my $base_url = $s->base_url;
177 $driver->get($s->base_url . 'mainpage.pl');
178 $s->fill_form({ input_id => 'value' });
182 The goal of this module is to group the different actions we need
183 when we use automation test using Selenium
189 my $s = t::lib::Selenium->new;
191 Constructor - Returns the object Selenium
192 You can pass login, password, base_url, selenium_addr, selenium_port
193 If not passed, the environment variables will be used
194 KOHA_USER, KOHA_PASS, KOHA_INTRANET_URL, SELENIUM_ADDR SELENIUM_PORT
195 Or koha, koha, syspref staffClientBaseURL, localhost, 4444
201 Will login into Koha.
208 element_id => 'other_value',
211 Will fill the different elements of a form.
212 The keys must be element ids (input and select are supported so far)
213 The values must a string.
219 It will submit the form using the submit button present in in the fieldset with a clas="action".
220 It should be the default way. If it does not work you should certainly fix the Koha interface.
226 This is a bit dirty for now but will evolve depending on the needs
227 3 parameters possible but only the following 2 forms are used:
228 $s->click({ href => '/module/script.pl?foo=bar', main => 'doc3' }); # Sometimes we have doc or doc3. To make sure we are not going to hit a link in the header
229 $s->click({ id => 'element_id });
231 =head2 click_when_visible
233 $c->click_when_visible
235 Should always be called to avoid the "An element could not be located on the page" error
240 Capture a screenshot and upload it using the excellent lut.im service provided by framasoft
241 The url of the image will be printed on STDERR (it should be better to return it instead)
245 Jonathan Druart <jonathan.druart@bugs.koha-community.org>
247 Alex Buckley <alexbuckley@catalyst.net.nz>
249 Koha Development Team
253 Copyright 2017 - Koha Development Team
257 This file is part of Koha.
259 Koha is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
260 the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
262 Koha is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
264 You should have received a copy of the GNU General Public License along with Koha; if not, see <http://www.gnu.org/licenses>.