File Coverage

blib/lib/Weasel.pm
Criterion Covered Total %
statement 16 17 94.1
branch 1 2 50.0
condition 1 3 33.3
subroutine 5 6 83.3
pod 2 2 100.0
total 25 30 83.3


line stmt bran cond sub pod time code
1              
2             =head1 NAME
3              
4             Weasel - Perl's php/Mink-inspired abstracted web-driver framework
5              
6             =head1 VERSION
7              
8             version 0.32
9              
10             =head1 SYNOPSIS
11              
12             use Weasel;
13             use Weasel::Session;
14             use Weasel::Driver::Selenium2;
15              
16             my $weasel = Weasel->new(
17             default_session => 'default',
18             sessions => {
19             default => Weasel::Session->new(
20             driver => Weasel::Driver::Selenium2->new(%opts),
21             ),
22             });
23              
24             $weasel->session->get('http://localhost/index');
25              
26             =head1 DESCRIPTION
27              
28             This module abstracts away the differences between the various
29             web-driver protocols, like the Mink project does for PHP.
30              
31             While heavily inspired by Mink, C<Weasel> aims to improve over it
32             by being extensible, providing not just access to the underlying
33             browser, yet to provide building blocks for further development
34             and abstraction.
35              
36             L<Pherkin::Extension::Weasel> provides integration with
37             L<Test::BDD::Cucumber> (aka pherkin), for BDD testing.
38              
39             For the actual page interaction, this module needs a driver to
40             be installed. Currently, that means L<Weasel::Driver::Selenium2>.
41             Other driver implementations, such as L<Sahi|http://sahipro.com/>
42             can be independently developed and uploaded to CPAN, or contributed.
43             (We welcome and encourage both!)
44              
45              
46             =head2 Differences with other frameworks
47              
48             =over
49              
50             =item Mnemonics for element lookup patterns
51              
52             The central registry of xpath expressions to find common page elements
53             helps to keep page access code clean. E.g. compare:
54              
55             use Weasel::FindExpanders::HTML;
56             $session->page->find('*contains', text => 'Some text');
57              
58             With
59              
60             $session->page->find(".//*[contains(.,'Some text')]
61             [not(.//*[contains(.,'Some text')])]");
62              
63             Multiple patterns can be registered for a single mnemonic, which
64             will be concatenated to a single xpath expression to find the matching
65             tags in a single driver query.
66              
67             Besides good performance, this has the benefit that the following
68              
69             $session->page->find('*button', text => 'Click!');
70              
71             can be easily extended to match
72             L<Dojo toolkit's|http://dojotoolkit.org/documentation/> buttons, which
73             on the HTML level don't contain visible button or input tags, simply
74             by using the widget support set:
75              
76             use Weasel::Widgets::Dojo;
77              
78             =item Widgets encapsulate specific behaviours
79              
80             All elements in C<Weasel> are of the base type C<Weasel::Element>, which
81             encapsulates the regular element interactions (click, find children, etc).
82              
83             While most elements will be represented by C<Weasel::Element>, it's possible
84             to implement other wrappers. These offer a logical extension point to
85             implement tag-specific utility functions. E.g.
86             C<Weasel::Widgets::HTML::Select>, which adds the utility function
87             C<select_option>.
88              
89             These widgets also offer a good way to override default behaviours. One
90             such case is the Dojo implementation of a 'select' element. This element
91             replaces the select tag entirely and in contrast with the original, doesn't
92             keep the options as child elements of the 'select'-replacing tag. By using
93             the Dojo widget library
94              
95             use Weasel::Widget::Dojo;
96              
97             the lack of the parent/child relation between the the select and its options
98             is transparently handled by overriding the widget's C<find> and C<find_all>
99             methods.
100              
101             =back
102              
103             =head2 PageObject architecture pattern support
104              
105             The functionality to encapsulate behaviours in widgets, enables intuitive
106             integration of the L<Page Object architectural pattern|https://www.selenium.dev/documentation/test_practices/encouraged/page_object_models/>
107             for design of test code. This pattern allows reduction of test code due
108             and separation of concerns between the functional test and the page interaction.
109              
110             =cut
111              
112             =head1 DEPENDENCIES
113              
114              
115              
116             =cut
117              
118             package Weasel 0.32;
119              
120 2     2   814717 use strict;
  2         4  
  2         58  
121 2     2   7 use warnings;
  2         3  
  2         87  
122              
123 2     2   632 use Moose;
  2         408446  
  2         10  
124 2     2   15181 use namespace::autoclean;
  2         20561  
  2         7  
125              
126             # From https://w3c.github.io/webdriver/webdriver-spec.html#keyboard-actions
127             my %key_codes = (
128             NULL => "\N{U+E000}",
129             CANCEL => "\N{U+E001}",
130             HELP => "\N{U+E002}",
131             BACK_SPACE => "\N{U+E003}",
132             TAB => "\N{U+E004}",
133             CLEAR => "\N{U+E005}",
134             RETURN => "\N{U+E006}",
135             ENTER => "\N{U+E007}",
136             SHIFT => "\N{U+E008}",
137             CONTROL => "\N{U+E009}",
138             ALT => "\N{U+E00A}",
139             PAUSE => "\N{U+E00B}",
140             ESCAPE => "\N{U+E00C}",
141             SPACE => "\N{U+E00D}",
142             PAGE_UP => "\N{U+E00E}",
143             PAGE_DOWN => "\N{U+E00F}",
144             'END' => "\N{U+E010}",
145             HOME => "\N{U+E011}",
146             ARROW_LEFT => "\N{U+E012}",
147             ARROW_UP => "\N{U+E013}",
148             ARROW_RIGHT => "\N{U+E014}",
149             ARROW_DOWN => "\N{U+E015}",
150             INSERT => "\N{U+E016}",
151             DELETE => "\N{U+E017}",
152             SEMICOLON => "\N{U+E018}",
153             EQUALS => "\N{U+E019}",
154             NUMPAD0 => "\N{U+E01A}",
155             NUMPAD1 => "\N{U+E01B}",
156             NUMPAD2 => "\N{U+E01C}",
157             NUMPAD3 => "\N{U+E01D}",
158             NUMPAD4 => "\N{U+E01E}",
159             NUMPAD5 => "\N{U+E01F}",
160             NUMPAD6 => "\N{U+E020}",
161             NUMPAD7 => "\N{U+E021}",
162             NUMPAD8 => "\N{U+E022}",
163             NUMPAD9 => "\N{U+E023}",
164             MULTIPLY => "\N{U+E024}",
165             ADD => "\N{U+E025}",
166             SEPARATOR => "\N{U+E026}",
167             SUBTRACT => "\N{U+E027}",
168             DECIMAL => "\N{U+E028}",
169             DIVIDE => "\N{U+E029}",
170             F1 => "\N{U+E031}",
171             F2 => "\N{U+E032}",
172             F3 => "\N{U+E033}",
173             F4 => "\N{U+E034}",
174             F5 => "\N{U+E035}",
175             F6 => "\N{U+E036}",
176             F7 => "\N{U+E037}",
177             F8 => "\N{U+E038}",
178             F9 => "\N{U+E039}",
179             F10 => "\N{U+E03A}",
180             F11 => "\N{U+E03B}",
181             F12 => "\N{U+E03C}",
182             META => "\N{U+E03D}",
183             COMMAND => "\N{U+E03D}",
184             ZENKAKU_HANKAKU => "\N{U+E040}",
185             );
186              
187             =over
188              
189             =item KEYS
190              
191             Returns a reference to a hash with names of the keys in the
192             hash keys and single-character strings containing the key
193             codes as the values.
194              
195             =cut
196              
197             sub KEYS {
198 0     0 1 0 return \%key_codes;
199             }
200              
201             =back
202              
203             =head1 ATTRIBUTES
204              
205              
206             =over
207              
208             =item default_session
209              
210             The name of the default session to return from C<session>, in case
211             no name argument is provided.
212              
213             =cut
214              
215             has 'default_session' => (is => 'rw',
216             isa => 'Str',
217             default => 'default',
218             );
219              
220             =item sessions
221              
222             Holds the sessions registered with the C<Weasel> instance.
223              
224             =cut
225              
226             has 'sessions' => (is => 'ro',
227             isa => 'HashRef[Weasel::Session]',
228             default => sub { {} },
229             );
230              
231             =back
232              
233             =head1 SUBROUTINES/METHODS
234              
235             =over
236              
237             =item session([$name [, $value]])
238              
239             Returns the session identified by C<$name>.
240              
241             If C<$value> is specified, it's associated with the given C<$name>.
242              
243             =cut
244              
245             sub session {
246 1     1 1 6 my ($self, $name, $value) = @_;
247              
248 1   33     25 $name //= $self->default_session;
249 1 50       2 $self->sessions->{$name} = $value
250             if defined $value;
251              
252 1         16 return $self->sessions->{$name};
253             }
254              
255              
256             =back
257              
258             =head1 AUTHOR
259              
260             Erik Huelsmann
261              
262             =head1 CONTRIBUTORS
263              
264             Erik Huelsmann
265             Yves Lavoie
266              
267             =head1 MAINTAINERS
268              
269             Erik Huelsmann
270              
271             =head1 BUGS AND LIMITATIONS
272              
273             Bugs can be filed in the GitHub issue tracker for the Weasel project:
274             L<https://github.com/perl-weasel/weasel/issues>
275              
276             =head1 SOURCE
277              
278             The source code repository for Weasel is at
279             https://github.com/perl-weasel/weasel
280              
281             =head1 SUPPORT
282              
283             Community support is available through
284             L<perl-weasel@googlegroups.com|mailto:perl-weasel@googlegroups.com>.
285              
286             =head1 BUGS
287              
288             Bugs can be filed in the GitHub issue tracker for the Weasel project:
289             L<https://github.com/perl-weasel/weasel/issues>
290              
291             =head1 SOURCE
292              
293             The source code repository for Weasel is at
294             L<https://github.com/perl-weasel/weasel>
295              
296             =head1 SUPPORT
297              
298             Community support is available through
299             L<perl-weasel@googlegroups.com|mailto:perl-weasel@googlegroups.com>.
300              
301             =head1 LICENSE AND COPYRIGHT
302              
303             (C) 2016-2023 Erik Huelsmann
304              
305             Licensed under the same terms as Perl.
306              
307             =cut
308              
309              
310             __PACKAGE__->meta->make_immutable;
311              
312             1;