File Coverage

blib/lib/Test2/Thunderhorse.pm
Criterion Covered Total %
statement 112 119 94.1
branch 18 22 81.8
condition 6 16 37.5
subroutine 17 17 100.0
pod 7 7 100.0
total 160 181 88.4


line stmt bran cond sub pod time code
1             package Test2::Thunderhorse;
2             $Test2::Thunderhorse::VERSION = '0.102';
3 18     18   3958223 use v5.40;
  18         69  
4              
5 18     18   123 use Test2::API qw(context);
  18         42  
  18         1050  
6 18     18   10707 use PAGI::Test::Client;
  18         655679  
  18         2667  
7 18     18   203 use Carp qw(croak);
  18         43  
  18         1338  
8              
9 18     18   132 use Exporter 'import';
  18         40  
  18         30622  
10              
11             our @EXPORT = qw(
12             pagi_run
13             http
14             http_status_is
15             http_header_is
16             http_text_is
17             websocket
18             sse
19             );
20              
21             die 'Error: Test2::Thunderhorse loaded in a PAGI environment'
22             if ($ENV{PAGI_ENV} // 'test') ne 'test';
23             $ENV{PAGI_ENV} = 'test';
24              
25             our $THIS_CLIENT;
26             my $LAST_HTTP;
27             my $LAST_WS;
28             my $LAST_SSE;
29              
30 103         183 sub _build_client ($app, %args)
31 103     103   253 {
  103         194  
  103         168  
32 103 50       425 return $THIS_CLIENT if defined $THIS_CLIENT;
33              
34 103 100       539 if (ref $app eq 'ARRAY') {
    50          
35 1         9 %args = ($app->@[1, $app->$#*], app => $app->[0]->run, %args);
36             }
37             elsif (ref $app eq 'HASH') {
38 0         0 %args = ($app->%*, %args);
39             }
40             else {
41 102         826 $args{app} = $app->run;
42             }
43              
44             $args{raise_app_exceptions} = true
45 103 100       527 unless exists $args{raise_app_exceptions};
46              
47 103         864 return PAGI::Test::Client->new(%args);
48             }
49              
50 2         5 sub pagi_run ($app, $code)
51 2     2 1 132 {
  2         5  
  2         5  
52 2         13 my $client = _build_client($app, lifespan => true);
53 2         61 local $THIS_CLIENT = $client;
54              
55 2         31 $client->start;
56 2         816 $code->();
57 2         15 $client->stop;
58              
59 2         1032 return $client->state;
60             }
61              
62 94         178 sub _http ($app, $http_request, %args)
  94         143  
63 94     94   213 {
  94         171  
  94         136  
64             # Extract method and path
65 94         404 my $method = lc $http_request->method;
66 94         1258 my $path = $http_request->uri->path_query;
67              
68             # Extract headers
69 94         2945 my %headers;
70 19         120 $http_request->headers->scan(
71 19     19   343 sub ($key, $value) {
  19         23  
  19         21  
72 19         56 push $headers{$key}->@*, $value;
73             }
74 94         531 );
75              
76 94 100       3023 $args{headers} = \%headers
77             if %headers;
78              
79             # Extract body for POST/PUT/PATCH
80 94         457 my $content = $http_request->content;
81 94 100 50     1606 $args{body} = $content
82             if length $content // '';
83              
84 94         376 $LAST_HTTP = _build_client($app)->$method($path, %args);
85              
86 93         10932 return $LAST_HTTP;
87             }
88              
89             sub http (@args)
90 132     132 1 423258 {
  132         376  
  132         211  
91 132 100 33     702 return $LAST_HTTP // croak 'no last http in Test2::Thunderhorse'
92             if @args == 0;
93              
94 94         407 return _http @args;
95             }
96              
97             sub http_status_is ($expected)
98 90     90 1 1129 {
  90         164  
  90         138  
99 90         438 my $ctx = context();
100              
101 90         11122 my $got = $LAST_HTTP->status;
102 90         506 my $pass = $got == $expected;
103              
104 90         788 $ctx->ok($pass, 'status ok', ["expected: $expected", "got: $got"]);
105              
106 90         17279 $ctx->release;
107 90         3824 return $pass;
108             }
109              
110             sub http_text_is ($expected)
111 53     53 1 756 {
  53         255  
  53         80  
112 53         129 my $ctx = context();
113              
114 53   50     4575 my $got = $LAST_HTTP->text // '';
115 53         20629 my $pass = $got eq $expected;
116              
117 53         419 $ctx->ok($pass, 'body ok', ["expected: $expected", "got: $got"]);
118              
119 53         7869 $ctx->release;
120 53         1926 return $pass;
121             }
122              
123 21         54 sub http_header_is ($header, $expected)
124 21     21 1 300 {
  21         41  
  21         31  
125 21         173 my $ctx = context();
126              
127 21         1842 my $got = $LAST_HTTP->header($header);
128 21   33     457 my $pass = defined($got) && defined($expected) && $got eq $expected;
129              
130 21         171 $ctx->ok($pass, "$header header ok", ["expected: $expected", "got: $got"]);
131              
132 21         2647 $ctx->release;
133 21         666 return $pass;
134             }
135              
136 3         7 sub _websocket ($app, $path, @args)
  3         5  
137 3     3   10 {
  3         7  
  3         6  
138 3         14 $LAST_WS = _build_client($app)->websocket($path, @args);
139              
140 3 50       691 if ($LAST_WS->is_closed) {
141 0         0 my $ctx = context();
142 0         0 $ctx->fail("Connecting to websocket $path failed");
143 0         0 $ctx->release;
144             }
145              
146 3         39 return $LAST_WS;
147             }
148              
149             sub websocket (@args)
150 13     13 1 19419 {
  13         31  
  13         24  
151 13 100 33     120 return $LAST_WS // croak 'no last websocket in Test2::Thunderhorse'
152             if @args == 0;
153              
154 3         12 return _websocket @args;
155             }
156              
157 4         9 sub _sse ($app, $path, @args)
  4         10  
158 4     4   11 {
  4         10  
  4         7  
159 4         26 $LAST_SSE = _build_client($app)->sse($path, @args);
160              
161 4 50       516 if ($LAST_SSE->is_closed) {
162 0         0 my $ctx = context();
163 0         0 $ctx->fail("Connecting to sse $path failed");
164 0         0 $ctx->release;
165             }
166              
167 4         49 return $LAST_SSE;
168             }
169              
170             sub sse (@args)
171 14     14 1 28407 {
  14         37  
  14         30  
172 14 100 33     144 return $LAST_SSE // croak 'no last sse in Test2::Thunderhorse'
173             if @args == 0;
174              
175 4         20 return _sse @args;
176             }
177              
178             1;
179              
180             __END__