Skip to content

Commit

Permalink
adds tests
Browse files Browse the repository at this point in the history
  • Loading branch information
fabio-ivona committed Nov 20, 2021
1 parent f5a1877 commit 4ebfde0
Show file tree
Hide file tree
Showing 23 changed files with 416 additions and 65 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/php-cs-fixer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ jobs:
- name: Run PHP CS Fixer
uses: docker://oskarstark/php-cs-fixer-ga
with:
args: --config=.php_cs.dist.php --allow-risky=yes
args: --config=.php-cs-fixer.dist.php --allow-risky=yes

- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Fix styling
commit_message: Lint
File renamed without changes.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.4",
"spatie/laravel-ray": "^1.26"
"spatie/laravel-ray": "^1.26",
"spatie/pest-plugin-snapshots": "^1.1"
},
"autoload": {
"psr-4": {
Expand Down
7 changes: 7 additions & 0 deletions src/Exceptions/TelegramWebhookException.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@

namespace DefStudio\LaravelTelegraph\Exceptions;

use DefStudio\LaravelTelegraph\Handlers\WebhookHandler;

class TelegramWebhookException extends \Exception
{
public static function invalidAction(string $action): TelegramWebhookException
{
return new self("No Telegram Webhook handler defined for received action: $action");
}

public static function invalidActionName(string $action): TelegramWebhookException
{
return new self(sprintf("Cannot use [%s] as action name, it is a reserved method from %s class", $action, WebhookHandler::class));
}
}
32 changes: 20 additions & 12 deletions src/Facades/LaravelTelegraph.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,32 @@

/**
* @method static string getUrl()
* @method \DefStudio\LaravelTelegraph\LaravelTelegraph bot(string $botToken)
* @method \DefStudio\LaravelTelegraph\LaravelTelegraph chat(string $chatId)
* @method \DefStudio\LaravelTelegraph\LaravelTelegraph html(string $message)
* @method \DefStudio\LaravelTelegraph\LaravelTelegraph markdown(string $message)
* @method \DefStudio\LaravelTelegraph\LaravelTelegraph keyboard(array $keyboard)
* @method \DefStudio\LaravelTelegraph\LaravelTelegraph registerWebhook()
* @method \DefStudio\LaravelTelegraph\LaravelTelegraph getWebhookDebugInfo()
* @method \DefStudio\LaravelTelegraph\LaravelTelegraph replyWebhook(string $callbackQueryId, string $message)
* @method \DefStudio\LaravelTelegraph\LaravelTelegraph replaceKeyboard(string $messageId, array $newKeyboard)
* @method \DefStudio\LaravelTelegraph\LaravelTelegraph send()
* @method static \DefStudio\LaravelTelegraph\LaravelTelegraph bot(string $botToken)
* @method static \DefStudio\LaravelTelegraph\LaravelTelegraph chat(string $chatId)
* @method static \DefStudio\LaravelTelegraph\LaravelTelegraph html(string $message)
* @method static \DefStudio\LaravelTelegraph\LaravelTelegraph markdown(string $message)
* @method static \DefStudio\LaravelTelegraph\LaravelTelegraph keyboard(array $keyboard)
* @method static \DefStudio\LaravelTelegraph\LaravelTelegraph registerWebhook()
* @method static \DefStudio\LaravelTelegraph\LaravelTelegraph getWebhookDebugInfo()
* @method static \DefStudio\LaravelTelegraph\LaravelTelegraph replyWebhook(string $callbackQueryId, string $message)
* @method static \DefStudio\LaravelTelegraph\LaravelTelegraph replaceKeyboard(string $messageId, array $newKeyboard)
* @method static \DefStudio\LaravelTelegraph\LaravelTelegraph send()
* @method static void assertSentData(string $endpoint, array $data = null)
* @method static void assertSent(string $message)
* @method static void assertRegisteredWebhook()
* @method static void assertRequestedWebhookDebugInfo()
* @method static void assertRepliedWebhook(string $message)
*
* @see \DefStudio\LaravelTelegraph\LaravelTelegraph
*/
class LaravelTelegraph extends Facade
{
public static function fake(): LaravelTelegraphFake
/**
* @param array<string, array<mixed>> $replies
*/
public static function fake(array $replies = []): LaravelTelegraphFake
{
static::swap($fake = new LaravelTelegraphFake());
static::swap($fake = new LaravelTelegraphFake($replies));

return $fake;
}
Expand Down
71 changes: 44 additions & 27 deletions src/Handlers/WebhookHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use ReflectionMethod;

abstract class WebhookHandler
{
Expand All @@ -21,44 +22,25 @@ abstract class WebhookHandler
protected Collection $data;
protected Collection $originalKeyboard;

public function handle(Request $request): void
{
$this->request = $request;
$this->extractData();

$action = $this->data->get('action');

if (!method_exists($this, $action)) {
report(TelegramWebhookException::invalidAction($action));
$this->reply('Invalid action');

return;
}

$this->$action();
}

private function extractData(): void
protected function extractData(): void
{
$this->chatId = $this->request->input('callback_query.message.chat.id'); //@phpstan-ignore-line
$this->messageId = $this->request->input('callback_query.message.message_id'); //@phpstan-ignore-line
$this->callbackQueryId = $this->request->input('callback_query.id'); //@phpstan-ignore-line
$this->originalKeyboard = collect($this->request->input('callback_query.message.reply_markup.inline_keyboard', []))->flatten(1); //@phpstan-ignore-line
$this->data = Str::of($this->request->input('callback_query.data'))->explode(';') //@phpstan-ignore-line
->mapWithKeys(function (string $entity) {
$entity = explode(':', $entity);
$key = $entity[0];
$value = $entity[1];
->mapWithKeys(function (string $entity) {
$entity = explode(':', $entity);
$key = $entity[0];
$value = $entity[1];

return [$key => $value];
});
return [$key => $value];
});
}

protected function reply(string $message): void
{
/** @noinspection PhpUndefinedClassInspection */
/** @phpstan-ignore-next-line */
Telegraph::answerWebhook($this->callbackQueryId, $message)->send();
LaravelTelegraph::replyWebhook($this->callbackQueryId, $message)->send();
}

/**
Expand All @@ -73,4 +55,39 @@ protected function deleteKeyboard(): void
{
LaravelTelegraph::chat($this->chatId)->replaceKeyboard($this->messageId, [])->send();
}

protected function canHandle(string $action): bool
{
if (!method_exists($this, $action)) {
return false;
}

$reflector = new ReflectionMethod($this::class, $action);
if (!$reflector->isPublic()) {
return false;
}

if (method_exists(WebhookHandler::class, $action)) {
throw TelegramWebhookException::invalidActionName($action);
}

return true;
}

public function handle(Request $request): void
{
$this->request = $request;
$this->extractData();

$action = $this->data->get('action');

if (!$this->canHandle($action)) {
report(TelegramWebhookException::invalidAction($action));
$this->reply('Invalid action');

return;
}

$this->$action();
}
}
12 changes: 6 additions & 6 deletions src/LaravelTelegraph.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

class LaravelTelegraph implements TelegraphContract
{
protected const TELEGRAM_API_BASE_URL = 'https://api.telegram.org/bot';
protected const ENDPOINT_SET_WEBHOOK = 'setWebhook';
protected const ENDPOINT_GET_WEBHOOK_DEBUG_INFO = 'getWebhookInfo';
protected const ENDPOINT_ANSWER_WEBHOOK = 'answerCallbackQuery';
protected const ENDPOINT_REPLACE_KEYBOARD = 'editMessageReplyMarkup';
protected const ENDPOINT_MESSAGE = 'sendMessage';
private const TELEGRAM_API_BASE_URL = 'https://api.telegram.org/bot';
public const ENDPOINT_SET_WEBHOOK = 'setWebhook';
public const ENDPOINT_GET_WEBHOOK_DEBUG_INFO = 'getWebhookInfo';
public const ENDPOINT_ANSWER_WEBHOOK = 'answerCallbackQuery';
public const ENDPOINT_REPLACE_KEYBOARD = 'editMessageReplyMarkup';
public const ENDPOINT_MESSAGE = 'sendMessage';

protected string $endpoint;

Expand Down
90 changes: 85 additions & 5 deletions src/Support/Testing/Fakes/LaravelTelegraphFake.php
Original file line number Diff line number Diff line change
@@ -1,22 +1,35 @@
<?php

/** @noinspection PhpUnused */

/** @noinspection PhpPropertyOnlyWrittenInspection */

namespace DefStudio\LaravelTelegraph\Support\Testing\Fakes;

use DefStudio\LaravelTelegraph\LaravelTelegraph;
use GuzzleHttp\Psr7\BufferStream;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Arr;
use PHPUnit\Framework\Assert;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\StreamInterface;

class LaravelTelegraphFake extends LaravelTelegraph
{
/** @var array<int, mixed> */
private array $messages = [];
private array $sentMessages = [];

/**
* @param array<string, array<mixed>> $replies
*/
public function __construct(private array $replies = [])
{
parent::__construct();
}

protected function sendRequestToTelegram(): Response
{
$this->messages[] = [
$this->sentMessages[] = [
'url' => $this->getUrl(),
'endpoint' => $this->endpoint ?? null,
'data' => $this->data ?? null,
Expand All @@ -29,6 +42,13 @@ protected function sendRequestToTelegram(): Response


$messageClass = new class () implements MessageInterface {
/**
* @param array<mixed> $reply
*/
public function __construct(private array $reply = [])
{
}

public function getProtocolVersion(): string
{
return "";
Expand Down Expand Up @@ -76,9 +96,12 @@ public function withoutHeader($name): static

public function getBody(): StreamInterface
{
$buffer = new BufferStream();

/** @phpstan-ignore-next-line */
$buffer->write(json_encode($this->reply));

/** @noinspection PhpIncompatibleReturnTypeInspection */
return ''; /** @phpstan-ignore-line */
return $buffer;
}

public function withBody(StreamInterface $body): static
Expand All @@ -87,6 +110,63 @@ public function withBody(StreamInterface $body): static
}
};

return new Response(new $messageClass());
$response = $this->replies[$this->endpoint] ?? ['ok' => true];

return new Response(new $messageClass($response));
}

/**
* @param array<string, string> $data
*/
public function assertSentData(string $endpoint, array $data = []): void
{
$foundMessages = collect($this->sentMessages)
->filter(fn (array $message): bool => $message['endpoint'] == $endpoint)
->filter(function (array $message) use ($data): bool {
foreach ($data as $key => $value) {
if (!Arr::has($message['data'], $key)) {
return false;
}

if ($value != $message['data'][$key]) {
return false;
}
}

return true;
});


if ($data == null) {
$errorMessage = sprintf("Failed to assert that a request was sent to [%s] endpoint (sent %d requests so far)", $endpoint, count($this->sentMessages));
} else {
$errorMessage = sprintf("Failed to assert that a request was sent to [%s] endpoint with the given data (sent %d requests so far)", $endpoint, count($this->sentMessages));
}

Assert::assertNotEmpty($foundMessages->toArray(), $errorMessage);
}

public function assertSent(string $message): void
{
$this->assertSentData(LaravelTelegraph::ENDPOINT_MESSAGE, [
'text' => $message,
]);
}

public function assertRegisteredWebhook(): void
{
$this->assertSentData(LaravelTelegraph::ENDPOINT_SET_WEBHOOK);
}

public function assertRequestedWebhookDebugInfo(): void
{
$this->assertSentData(LaravelTelegraph::ENDPOINT_GET_WEBHOOK_DEBUG_INFO);
}

public function assertRepliedWebhook(string $message): void
{
$this->assertSentData(LaravelTelegraph::ENDPOINT_ANSWER_WEBHOOK, [
'text' => $message,
]);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<?php

use Illuminate\Support\Facades\Http;
use DefStudio\LaravelTelegraph\Facades\LaravelTelegraph as Facade;
use DefStudio\LaravelTelegraph\LaravelTelegraph;
use function Pest\Laravel\artisan;

test('can retrieve telegram bot webhook info', function () {
Http::fake([
'https://api.telegram.org/bot123456AAABBB/getWebhookInfo' => Http::response([
Facade::fake([
LaravelTelegraph::ENDPOINT_GET_WEBHOOK_DEBUG_INFO => [
'ok' => true,
'result' => [
'url' => 'https://local.testing/telegraph/123456AAABBB/webhook',
Expand All @@ -14,7 +15,7 @@
'max_connections' => 40,
'ip_address' => "1.234.567.890",
],
]),
],
]);

/** @phpstan-ignore-next-line */
Expand Down
11 changes: 4 additions & 7 deletions tests/Feature/Commands/SetTelegramWebhookCommandTest.php
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
<?php

use Illuminate\Support\Facades\Http;

use DefStudio\LaravelTelegraph\Facades\LaravelTelegraph;
use function Pest\Laravel\artisan;

test('can retrieve telegram bot webhook info', function () {
Http::fake([
'https://api.telegram.org/bot123456AAABBB/setWebhook?url=http%3A%2F%2Flocalhost%2Ftelegraph%2F123456AAABBB%2Fwebhook' => Http::response([
'ok' => true,
]),
]);
test('can set telegram webhook address', function () {
LaravelTelegraph::fake();

/** @phpstan-ignore-next-line */
artisan('telegraph:set-webhook')
Expand Down
Loading

0 comments on commit 4ebfde0

Please sign in to comment.