NAME
PAGI::Test::WebSocket - WebSocket connection for testing PAGI applications
SYNOPSIS
use PAGI::Test::Client;
my $client = PAGI::Test::Client->new(app => $ws_app);
# Callback style (auto-close)
$client->websocket('/ws', sub {
my ($ws) = @_;
$ws->send_text('hello');
is $ws->receive_text, 'echo: hello';
});
# Explicit style
my $ws = $client->websocket('/ws');
$ws->send_text('hello');
is $ws->receive_text, 'echo: hello';
$ws->close;
# JSON convenience
$ws->send_json({ action => 'ping' });
my $data = $ws->receive_json;
DESCRIPTION
PAGI::Test::WebSocket provides a test client for WebSocket connections in PAGI applications. It handles the WebSocket protocol handshake and message exchange, making it easy to test WebSocket endpoints without starting a real server.
This module is typically used via PAGI::Test::Client's websocket method rather than directly.
CONSTRUCTOR
new
my $ws = PAGI::Test::WebSocket->new(
app => $app, # Required: PAGI app coderef
scope => $scope, # Required: WebSocket scope hashref
);
Creates a new WebSocket test connection. Typically you don't call this directly; use PAGI::Test::Client's websocket method instead.
METHODS
send_text
$ws->send_text('Hello, server!');
Sends a text message to the WebSocket application.
send_bytes
$ws->send_bytes("\x00\x01\x02\x03");
Sends a binary message to the WebSocket application.
send_json
$ws->send_json({ action => 'ping', id => 123 });
Encodes a Perl data structure as JSON and sends it as a text message.
receive_text
my $text = $ws->receive_text;
my $text = $ws->receive_text($timeout); # custom timeout in seconds
Waits for and returns the next text message from the server. Returns undef if the connection is closed. Throws an exception if timeout is reached (default: 5 seconds).
Only returns text messages; binary messages are skipped.
receive_bytes
my $bytes = $ws->receive_bytes;
my $bytes = $ws->receive_bytes($timeout);
Waits for and returns the next binary message from the server. Returns undef if the connection is closed. Throws an exception if timeout is reached (default: 5 seconds).
Only returns binary messages; text messages are skipped.
receive_json
my $data = $ws->receive_json;
my $data = $ws->receive_json($timeout);
Waits for a text message, decodes it as JSON, and returns the resulting Perl data structure. Dies if the message is not valid JSON.
close
$ws->close;
$ws->close($code);
$ws->close($code, $reason);
Closes the WebSocket connection. Default close code is 1000 (normal closure).
close_code
my $code = $ws->close_code;
Returns the WebSocket close code if the connection has been closed, or undef if still open.
close_reason
my $reason = $ws->close_reason;
Returns the WebSocket close reason if the connection has been closed, or an empty string if still open.
is_closed
if ($ws->is_closed) {
say "Connection closed";
}
Returns true if the WebSocket connection has been closed.
INTERNAL METHODS
_start
$ws->_start;
Internal method called by PAGI::Test::Client to start the WebSocket connection, send the initial connect event, and wait for acceptance.
WEBSOCKET PROTOCOL
This module implements the PAGI WebSocket protocol:
- 1. Test sends
websocket.connectevent - 2. App sends
websocket.acceptevent - 3. Test sends
websocket.receiveevents withtextorbytes - 4. App sends
websocket.sendevents withtextorbytes - 5. Either side sends
websocket.disconnectorwebsocket.close
EXAMPLE
use Test2::V0;
use PAGI::Test::Client;
use Future::AsyncAwait;
# Simple echo WebSocket app
my $ws_app = async sub {
my ($scope, $receive, $send) = @_;
return unless $scope->{type} eq 'websocket';
my $event = await $receive->();
return unless $event->{type} eq 'websocket.connect';
await $send->({ type => 'websocket.accept' });
while (1) {
my $msg = await $receive->();
last if $msg->{type} eq 'websocket.disconnect';
if (defined $msg->{text}) {
await $send->({
type => 'websocket.send',
text => "echo: $msg->{text}"
});
}
}
};
# Test it
my $client = PAGI::Test::Client->new(app => $ws_app);
$client->websocket('/ws', sub {
my ($ws) = @_;
$ws->send_text('hello');
is $ws->receive_text, 'echo: hello', 'echoed text';
});
SEE ALSO
PAGI::Test::Client, PAGI::Test::Response, PAGI::WebSocket
AUTHOR
PAGI Contributors