File Coverage

blib/lib/RapidApp/Test/Client.pm
Criterion Covered Total %
statement 90 98 91.8
branch 20 28 71.4
condition 5 12 41.6
subroutine 25 29 86.2
pod 0 16 0.0
total 140 183 76.5


line stmt bran cond sub pod time code
1             package RapidApp::Test::Client;
2              
3 4     4   24 use strict;
  4         10  
  4         102  
4 4     4   21 use warnings;
  4         7  
  4         103  
5              
6             # Object class for simulating RapidApp HTTP client sessions
7              
8 4     4   1647 use Moo;
  4         31080  
  4         16  
9 4     4   17165 use Types::Standard qw(:all);
  4         243494  
  4         41  
10              
11 4     4   159248 use RapidApp;
  4         9  
  4         127  
12 4     4   25 use Scalar::Util qw(blessed);
  4         6  
  4         229  
13 4     4   23 use Time::HiRes qw(gettimeofday tv_interval);
  4         6  
  4         26  
14 4     4   9947 use LWP::UserAgent;
  4         73852  
  4         139  
15 4     4   32 use HTTP::Request::Common;
  4         11  
  4         320  
16 4     4   27 use JSON qw(decode_json);
  4         9  
  4         32  
17 4     4   417 use Try::Tiny;
  4         10  
  4         4982  
18              
19             # shorthand aliases:
20 0     0 0 0 sub lreq { (shift)->last_request }
21 8     8 0 117 sub lres { (shift)->last_response }
22              
23             has 'ajax_request_headers', is => 'ro', default => sub {{
24             'X-RapidApp-RequestContentType' => 'JSON',
25             'X-RapidApp-VERSION' => $RapidApp::VERSION,
26             'X-Requested-With' => 'XMLHttpRequest',
27             'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8',
28             }}, isa => HashRef;
29              
30             has 'request_num', is => 'rw', default => sub{0}, isa => Int;
31             has 'last_request', is => 'rw', default => sub{undef}, isa => Maybe[InstanceOf['HTTP::Request']];
32             has 'last_response', is => 'rw', default => sub{undef}, isa => Maybe[InstanceOf['HTTP::Response']];
33             has 'last_request_started', is => 'rw', default => sub{undef};
34             has 'last_request_elapsed', is => 'rw', default => sub{undef}, isa => Maybe[Str];
35             has 'last_url', is => 'rw', default => sub{undef}, isa => Maybe[Str];
36             has 'cookie', is => 'rw', default => sub{undef}, isa => Maybe[Str];
37              
38             # i.e. http://localhost:3000
39             has 'base_url', is => 'ro', isa => Maybe[Str], default => sub {undef};
40              
41             has 'agent_string', is => 'ro', lazy => 1, default => sub {
42             my $self = shift;
43             return (ref $self);
44             }, isa => Str;
45              
46             has 'request_caller', is => 'ro', lazy => 1, default => sub {
47             my $self = shift;
48            
49             # create in a closure:
50             my $ua = LWP::UserAgent->new;
51             $ua->agent($self->agent_string);
52            
53             return sub {
54             my $request = shift;
55             return $ua->request($request);
56             }
57             }, isa => CodeRef;
58              
59             sub make_request {
60 26     26 0 101 my ($self, $req) = @_;
61            
62 26         553 $self->last_request(undef);
63 26         1090 $self->last_response(undef);
64 26         1198 $self->last_request_elapsed(undef);
65 26         894 $self->request_num( $self->request_num + 1 );
66            
67 26         938 $self->last_request_started([gettimeofday]);
68            
69 26 100       403 $req->header( Cookie => $self->cookie ) if ($self->cookie);
70            
71 26         1859 my $res = $self->request_caller->( $self->last_request($req) );
72            
73             # Record the response unless the request_caller already did:
74 26 50       564 $self->record_response( $res ) unless ($self->last_response);
75            
76 26         253 return $res;
77             }
78              
79             sub record_response {
80 26     26 0 41763 my ($self, $res) = @_;
81 26 50       578 die "last_response already defined" if ($self->last_response);
82 26         565 $self->last_response( $res );
83 26         980 $self->cookie( $res->header('Set-Cookie') );
84 26         2460 $self->last_request_elapsed(sprintf("%0.5f sec",tv_interval(
85             $self->last_request_started
86             )));
87 26         2045 return $res;
88             }
89              
90             sub normalize_url {
91 26     26 0 76 my ($self, $url) = @_;
92            
93 26 50 33     191 $url = join('',$self->base_url,$url) if (
94             $self->base_url &&
95             $url =~ /^\// #<-- starts with '/'
96             );
97              
98 26         597 return $self->last_url($url);
99             }
100              
101              
102             sub get_request {
103 8     8 0 29 my ($self, $url, $headers) = @_;
104 8         28 $url = $self->normalize_url($url);
105 8         362 my $req = GET($url);
106 8 100       1107 $req->header( %$headers ) if ($headers);
107 8         320 $self->make_request($req);
108             }
109              
110             sub post_request {
111 18     18 0 74 my ($self, $url, $params, $headers) = @_;
112 18         57 $url = $self->normalize_url($url);
113 18 100       677 my $arr_arg = ref($params) eq 'HASH' ? [%$params] : $params;
114 18         95 my $req = POST($url,$params);
115 18 100       11930 $req->header( %$headers ) if ($headers);
116 18         1909 $self->make_request($req);
117             }
118              
119             sub last_request_is_ajax {
120 26     26 0 54 my $self = shift;
121 26 50       334 my $req = $self->last_request or return 0;
122 26         230 my $req_with = $req->header('X-Requested-With');
123 26   66     1540 return $req_with && $req_with eq 'XMLHttpRequest';
124             }
125              
126             sub last_request_type {
127 26     26 0 228 my $self = shift;
128 26 50       333 return '(none)' unless ($self->last_request);
129 26 100       199 return $self->last_request_is_ajax ? 'Ajax' : 'Browser';
130             }
131              
132             sub last_response_set_cookie {
133 26     26 0 63 my $self = shift;
134 26 50       333 my $res = $self->last_response or return 0;
135 26         211 return $res->header('Set-Cookie');
136             }
137              
138             sub describe_request {
139 26     26 0 57 my $self = shift;
140 26 50       432 my $req = $self->last_request or return '(no request)';
141            
142 26         589 my @list = (
143             ' <r', $self->request_num,'> ',
144             $self->last_request_type,
145             '->', $req->method, '(\'',$req->uri->path,'\')',
146             );
147            
148             # If we already have the response, include the elapsed time:
149 26 50       1394 push @list,(' [',$self->last_request_elapsed,']')
150             if ($self->last_response);
151            
152 26 100       671 push @list, ' **set-cookie**' if ($self->last_response_set_cookie);
153            
154 26         1341 return join('',@list);
155             }
156              
157             #####################
158              
159              
160             # Simulate an Ajax POST request as if it was generated by the
161             # RapidApp/ExtJS JavaScript client/browser to a JSON-encoded
162             # resource. Decodes and returns the JSON as perl ref
163             sub ajax_post_decode {
164 13     13 0 49 my ($self, $url, $params) = @_;
165 13         78 my $res = $self->post_request($url, $params, $self->ajax_request_headers);
166 13   66 13   120 return try{decode_json($res->decoded_content)} || $res->decoded_content;
  13         414  
167             }
168              
169              
170             sub ajax_get_raw {
171 2     2 0 8 my ($self, $url) = @_;
172 2         16 my $res = $self->get_request($url, $self->ajax_request_headers);
173 2         13 return $res->decoded_content;
174             }
175              
176              
177             sub ajax_get_decode {
178 0     0 0 0 my ($self, $url) = @_;
179 0         0 my $content = $self->ajax_get_raw($url);
180 0   0 0   0 return try{decode_json($content)} || $content;
  0         0  
181             }
182              
183             sub browser_get_raw {
184 3     3 0 14 my ($self, $url) = @_;
185 3         14 my $res = $self->get_request($url);
186 3         19 return $res->decoded_content;
187             }
188              
189             sub browser_post_raw {
190 0     0 0   my ($self, $url, $params) = @_;
191 0           my $res = $self->post_request($url,$params);
192 0           return $res->decoded_content;
193             }
194              
195              
196             1;