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   28 use strict;
  4         8  
  4         129  
4 4     4   73 use warnings;
  4         11  
  4         111  
5              
6             # Object class for simulating RapidApp HTTP client sessions
7              
8 4     4   1908 use Moo;
  4         36601  
  4         17  
9 4     4   19961 use Types::Standard qw(:all);
  4         281302  
  4         43  
10              
11 4     4   187870 use RapidApp;
  4         11  
  4         140  
12 4     4   30 use Scalar::Util qw(blessed);
  4         19  
  4         285  
13 4     4   25 use Time::HiRes qw(gettimeofday tv_interval);
  4         9  
  4         32  
14 4     4   3463 use LWP::UserAgent;
  4         80297  
  4         150  
15 4     4   34 use HTTP::Request::Common;
  4         10  
  4         268  
16 4     4   26 use JSON qw(decode_json);
  4         10  
  4         35  
17 4     4   421 use Try::Tiny;
  4         10  
  4         5466  
18              
19             # shorthand aliases:
20 0     0 0 0 sub lreq { (shift)->last_request }
21 8     8 0 145 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 102 my ($self, $req) = @_;
61            
62 26         679 $self->last_request(undef);
63 26         1365 $self->last_response(undef);
64 26         1420 $self->last_request_elapsed(undef);
65 26         1177 $self->request_num( $self->request_num + 1 );
66            
67 26         1217 $self->last_request_started([gettimeofday]);
68            
69 26 100       510 $req->header( Cookie => $self->cookie ) if ($self->cookie);
70            
71 26         2434 my $res = $self->request_caller->( $self->last_request($req) );
72            
73             # Record the response unless the request_caller already did:
74 26 50       691 $self->record_response( $res ) unless ($self->last_response);
75            
76 26         402 return $res;
77             }
78              
79             sub record_response {
80 26     26 0 54484 my ($self, $res) = @_;
81 26 50       715 die "last_response already defined" if ($self->last_response);
82 26         723 $self->last_response( $res );
83 26         1217 $self->cookie( $res->header('Set-Cookie') );
84 26         3020 $self->last_request_elapsed(sprintf("%0.5f sec",tv_interval(
85             $self->last_request_started
86             )));
87 26         2717 return $res;
88             }
89              
90             sub normalize_url {
91 26     26 0 107 my ($self, $url) = @_;
92            
93 26 50 33     243 $url = join('',$self->base_url,$url) if (
94             $self->base_url &&
95             $url =~ /^\// #<-- starts with '/'
96             );
97              
98 26         774 return $self->last_url($url);
99             }
100              
101              
102             sub get_request {
103 8     8 0 31 my ($self, $url, $headers) = @_;
104 8         38 $url = $self->normalize_url($url);
105 8         451 my $req = GET($url);
106 8 100       1392 $req->header( %$headers ) if ($headers);
107 8         449 $self->make_request($req);
108             }
109              
110             sub post_request {
111 18     18 0 78 my ($self, $url, $params, $headers) = @_;
112 18         80 $url = $self->normalize_url($url);
113 18 100       899 my $arr_arg = ref($params) eq 'HASH' ? [%$params] : $params;
114 18         118 my $req = POST($url,$params);
115 18 100       15103 $req->header( %$headers ) if ($headers);
116 18         2350 $self->make_request($req);
117             }
118              
119             sub last_request_is_ajax {
120 26     26 0 65 my $self = shift;
121 26 50       425 my $req = $self->last_request or return 0;
122 26         302 my $req_with = $req->header('X-Requested-With');
123 26   66     1885 return $req_with && $req_with eq 'XMLHttpRequest';
124             }
125              
126             sub last_request_type {
127 26     26 0 297 my $self = shift;
128 26 50       423 return '(none)' unless ($self->last_request);
129 26 100       240 return $self->last_request_is_ajax ? 'Ajax' : 'Browser';
130             }
131              
132             sub last_response_set_cookie {
133 26     26 0 72 my $self = shift;
134 26 50       431 my $res = $self->last_response or return 0;
135 26         272 return $res->header('Set-Cookie');
136             }
137              
138             sub describe_request {
139 26     26 0 79 my $self = shift;
140 26 50       582 my $req = $self->last_request or return '(no request)';
141            
142 26         787 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       1659 push @list,(' [',$self->last_request_elapsed,']')
150             if ($self->last_response);
151            
152 26 100       902 push @list, ' **set-cookie**' if ($self->last_response_set_cookie);
153            
154 26         1652 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 48 my ($self, $url, $params) = @_;
165 13         93 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         480  
167             }
168              
169              
170             sub ajax_get_raw {
171 2     2 0 10 my ($self, $url) = @_;
172 2         18 my $res = $self->get_request($url, $self->ajax_request_headers);
173 2         14 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 13 my ($self, $url) = @_;
185 3         19 my $res = $self->get_request($url);
186 3         24 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;