Files

454 lines
14 KiB
PHP
Raw Permalink Normal View History

2019-01-27 12:35:00 +01:00
<?php
2019-10-05 17:26:10 +02:00
2019-01-27 12:35:00 +01:00
declare(strict_types=1);
namespace ShlinkioApiTest\Shlink\Rest\Action;
use Cake\Chronos\Chronos;
use GuzzleHttp\RequestOptions;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\Core\Domain\Entity\Domain;
2019-08-11 16:30:46 +02:00
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
2019-01-27 12:35:00 +01:00
use function count;
2019-01-27 12:35:00 +01:00
class ListShortUrlsTest extends ApiTestCase
{
2024-12-02 09:13:20 +01:00
private const array SHORT_URL_SHLINK_WITH_TITLE = [
'shortCode' => 'abc123',
2023-01-19 09:05:52 +01:00
'shortUrl' => 'http://s.test/abc123',
'longUrl' => 'https://shlink.io',
'dateCreated' => '2018-05-01T00:00:00+00:00',
2022-12-16 10:53:44 +01:00
'visitsSummary' => [
'total' => 3,
'nonBots' => 3,
'bots' => 0,
],
'tags' => ['foo'],
'meta' => [
'validSince' => null,
'validUntil' => null,
'maxVisits' => 2,
],
2020-02-02 08:57:04 +01:00
'domain' => null,
2021-02-04 21:27:16 +01:00
'title' => 'My cool title',
2021-05-22 07:35:47 +02:00
'crawlable' => true,
'forwardQuery' => true,
2024-10-27 12:26:34 +01:00
'hasRedirectRules' => false,
];
2024-12-02 09:13:20 +01:00
private const array SHORT_URL_DOCS = [
'shortCode' => 'ghi789',
2023-01-19 09:05:52 +01:00
'shortUrl' => 'http://s.test/ghi789',
'longUrl' => 'https://shlink.io/documentation/',
'dateCreated' => '2018-05-01T00:00:00+00:00',
2022-12-16 10:53:44 +01:00
'visitsSummary' => [
'total' => 2,
'nonBots' => 2,
'bots' => 0,
],
'tags' => [],
'meta' => [
'validSince' => null,
'validUntil' => '2020-05-01T00:00:00+00:00',
'maxVisits' => null,
],
'domain' => null,
2021-02-02 20:51:28 +01:00
'title' => null,
2021-05-22 07:35:47 +02:00
'crawlable' => false,
'forwardQuery' => true,
2024-10-27 12:26:34 +01:00
'hasRedirectRules' => false,
];
2024-12-02 09:13:20 +01:00
private const array SHORT_URL_CUSTOM_SLUG_AND_DOMAIN = [
'shortCode' => 'custom-with-domain',
'shortUrl' => 'http://some-domain.com/custom-with-domain',
'longUrl' => 'https://google.com',
'dateCreated' => '2018-10-20T00:00:00+00:00',
2022-12-16 10:53:44 +01:00
'visitsSummary' => [
'total' => 0,
'nonBots' => 0,
'bots' => 0,
],
'tags' => [],
'meta' => [
'validSince' => null,
'validUntil' => null,
'maxVisits' => null,
],
2020-02-02 08:57:04 +01:00
'domain' => 'some-domain.com',
2021-02-02 20:51:28 +01:00
'title' => null,
2021-05-22 07:35:47 +02:00
'crawlable' => false,
'forwardQuery' => true,
2024-10-27 12:26:34 +01:00
'hasRedirectRules' => false,
];
2024-12-02 09:13:20 +01:00
private const array SHORT_URL_META = [
'shortCode' => 'def456',
2023-01-19 09:05:52 +01:00
'shortUrl' => 'http://s.test/def456',
'longUrl' => 'https://blog.alejandrocelaya.com/2017/12/09/acmailer-7-0-the-most-important-release-in-a-long-time/',
'dateCreated' => '2019-01-01T00:00:10+00:00',
2022-12-16 10:53:44 +01:00
'visitsSummary' => [
'total' => 2,
'nonBots' => 1,
'bots' => 1,
],
'tags' => ['bar', 'foo'],
'meta' => [
'validSince' => '2020-05-01T00:00:00+00:00',
'validUntil' => null,
'maxVisits' => null,
],
2020-02-02 08:57:04 +01:00
'domain' => null,
2021-02-02 20:51:28 +01:00
'title' => null,
2021-05-22 07:35:47 +02:00
'crawlable' => false,
'forwardQuery' => true,
2024-10-27 12:26:34 +01:00
'hasRedirectRules' => true,
];
2024-12-02 09:13:20 +01:00
private const array SHORT_URL_CUSTOM_SLUG = [
'shortCode' => 'custom',
2023-01-19 09:05:52 +01:00
'shortUrl' => 'http://s.test/custom',
'longUrl' => 'https://shlink.io',
'dateCreated' => '2019-01-01T00:00:20+00:00',
2022-12-16 10:53:44 +01:00
'visitsSummary' => [
'total' => 0,
'nonBots' => 0,
'bots' => 0,
],
'tags' => [],
'meta' => [
'validSince' => null,
'validUntil' => null,
'maxVisits' => 2,
],
2020-02-02 08:57:04 +01:00
'domain' => null,
2021-02-02 20:51:28 +01:00
'title' => null,
2023-02-10 20:26:18 +01:00
'crawlable' => true,
'forwardQuery' => false,
2024-10-27 12:26:34 +01:00
'hasRedirectRules' => false,
];
2024-12-02 09:13:20 +01:00
private const array SHORT_URL_CUSTOM_DOMAIN = [
'shortCode' => 'ghi789',
'shortUrl' => 'http://example.com/ghi789',
'longUrl' =>
'https://blog.alejandrocelaya.com/2019/04/27'
. '/considerations-to-properly-use-open-source-software-projects/',
'dateCreated' => '2019-01-01T00:00:30+00:00',
2022-12-16 10:53:44 +01:00
'visitsSummary' => [
'total' => 0,
'nonBots' => 0,
'bots' => 0,
],
'tags' => ['foo'],
'meta' => [
'validSince' => null,
'validUntil' => null,
'maxVisits' => null,
],
2020-02-02 08:57:04 +01:00
'domain' => 'example.com',
2021-02-02 20:51:28 +01:00
'title' => null,
2021-05-22 07:35:47 +02:00
'crawlable' => false,
'forwardQuery' => true,
2024-10-27 12:26:34 +01:00
'hasRedirectRules' => false,
];
#[Test, DataProvider('provideFilteredLists')]
2025-10-17 08:52:25 +02:00
public function shortUrlsAreProperlyListed(
array $query,
array $expectedShortUrls,
string $apiKey = 'valid_api_key',
): void {
$resp = $this->callApiWithKey(self::METHOD_GET, '/short-urls', [RequestOptions::QUERY => $query], $apiKey);
2019-01-27 12:35:00 +01:00
$respPayload = $this->getJsonResponsePayload($resp);
2020-10-04 00:35:14 +02:00
self::assertEquals(self::STATUS_OK, $resp->getStatusCode());
self::assertEquals(
[
'shortUrls' => [
'data' => $expectedShortUrls,
'pagination' => $this->buildPagination(count($expectedShortUrls)),
],
2019-01-27 12:35:00 +01:00
],
$respPayload,
);
2019-01-27 12:35:00 +01:00
}
2023-02-09 09:32:38 +01:00
public static function provideFilteredLists(): iterable
{
yield [
[],
[
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_META,
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
self::SHORT_URL_SHLINK_WITH_TITLE,
self::SHORT_URL_DOCS,
],
];
yield [
['excludePastValidUntil' => 'true'],
[
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_META,
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
self::SHORT_URL_SHLINK_WITH_TITLE,
],
];
yield [
['excludeMaxVisitsReached' => 'true'],
[
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_META,
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
self::SHORT_URL_DOCS,
],
];
yield [
['orderBy' => 'shortCode'],
[
self::SHORT_URL_SHLINK_WITH_TITLE,
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
self::SHORT_URL_META,
self::SHORT_URL_DOCS,
self::SHORT_URL_CUSTOM_DOMAIN,
],
];
yield [
['orderBy' => 'shortCode-DESC'],
[
self::SHORT_URL_DOCS,
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_META,
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_SHLINK_WITH_TITLE,
],
];
yield [
['orderBy' => 'title-DESC'],
[
self::SHORT_URL_SHLINK_WITH_TITLE,
self::SHORT_URL_META,
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_DOCS,
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
],
];
yield [
['startDate' => Chronos::parse('2018-12-01')->toAtomString()],
[
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_META,
],
];
yield [
['endDate' => Chronos::parse('2018-12-01')->toAtomString()],
[
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
self::SHORT_URL_SHLINK_WITH_TITLE,
self::SHORT_URL_DOCS,
],
];
yield [
['tags' => ['foo']],
[
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_META,
self::SHORT_URL_SHLINK_WITH_TITLE,
],
];
yield [
['tags' => ['bar']],
[
self::SHORT_URL_META,
],
];
yield [
['tags' => ['foo', 'bar']],
[
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_META,
self::SHORT_URL_SHLINK_WITH_TITLE,
],
];
yield [
['tags' => ['foo', 'bar'], 'tagsMode' => 'any'],
[
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_META,
self::SHORT_URL_SHLINK_WITH_TITLE,
],
];
yield [
['tags' => ['foo', 'bar'], 'tagsMode' => 'all'],
[
self::SHORT_URL_META,
],
];
yield [
['tags' => ['foo', 'bar', 'baz']],
[
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_META,
self::SHORT_URL_SHLINK_WITH_TITLE,
],
];
2025-10-17 08:52:25 +02:00
yield [['tags' => ['foo', 'bar', 'baz'], 'tagsMode' => 'all'], []];
yield [
['tags' => ['foo'], 'endDate' => Chronos::parse('2018-12-01')->toAtomString()],
[
self::SHORT_URL_SHLINK_WITH_TITLE,
],
];
yield [
['searchTerm' => 'alejandro'],
[
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_META,
],
];
yield [
['searchTerm' => 'cool'],
[
self::SHORT_URL_SHLINK_WITH_TITLE,
],
];
yield [
['searchTerm' => 'example.com'],
[
self::SHORT_URL_CUSTOM_DOMAIN,
],
];
yield [
['domain' => 'example.com'],
[
self::SHORT_URL_CUSTOM_DOMAIN,
],
];
yield [
['domain' => Domain::DEFAULT_AUTHORITY],
[
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_META,
self::SHORT_URL_SHLINK_WITH_TITLE,
self::SHORT_URL_DOCS,
],
];
2025-10-17 08:52:25 +02:00
// Exclude tags
yield [
['excludeTags' => ['foo']],
[
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
self::SHORT_URL_DOCS,
],
];
yield [
['excludeTags' => ['foo', 'bar']],
[
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
self::SHORT_URL_DOCS,
],
];
yield [
['excludeTags' => ['bar', 'foo'], 'excludeTagsMode' => 'all'],
[
self::SHORT_URL_CUSTOM_DOMAIN,
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN,
self::SHORT_URL_SHLINK_WITH_TITLE,
self::SHORT_URL_DOCS,
],
];
2025-10-17 08:52:25 +02:00
// Filter by API key name
yield [
['apiKeyName' => 'author_api_key'],
[
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_META,
self::SHORT_URL_SHLINK_WITH_TITLE,
],
];
yield [['apiKeyName' => 'invalid'], []];
yield [
['apiKeyName' => 'valid_api_key'],
[
// If the author_api_key is used, the `apiKeyName` param is ignored
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_META,
self::SHORT_URL_SHLINK_WITH_TITLE,
],
'author_api_key',
];
yield [
['apiKeyName' => 'valid_api_key'],
[
// If the domain_api_key is used, the `apiKeyName` param is ignored
self::SHORT_URL_CUSTOM_DOMAIN,
],
'domain_api_key',
];
2025-10-17 08:52:25 +02:00
// Different API keys
yield [
[],
[
self::SHORT_URL_CUSTOM_SLUG,
self::SHORT_URL_META,
self::SHORT_URL_SHLINK_WITH_TITLE,
],
'author_api_key',
];
yield [
[],
[
self::SHORT_URL_CUSTOM_DOMAIN,
],
'domain_api_key',
];
}
private function buildPagination(int $itemsCount): array
{
return [
'currentPage' => 1,
'pagesCount' => 1,
'itemsPerPage' => 10,
'itemsInCurrentPage' => $itemsCount,
'totalItems' => $itemsCount,
];
}
2022-01-04 14:42:31 +01:00
#[Test, DataProvider('provideInvalidFiltering')]
public function errorIsReturnedWhenProvidingInvalidValues(array $query, array $expectedInvalidElements): void
2022-01-04 14:42:31 +01:00
{
$resp = $this->callApiWithKey(self::METHOD_GET, '/short-urls', [RequestOptions::QUERY => $query]);
$respPayload = $this->getJsonResponsePayload($resp);
self::assertEquals(400, $resp->getStatusCode());
self::assertEquals(
[
'invalidElements' => $expectedInvalidElements,
'title' => 'Invalid data',
'type' => 'https://shlink.io/api/error/invalid-data',
'status' => 400,
'detail' => 'Provided data is not valid',
],
$respPayload,
);
2022-01-04 14:42:31 +01:00
}
2023-02-09 09:32:38 +01:00
public static function provideInvalidFiltering(): iterable
{
yield [['tagsMode' => 'invalid'], ['tagsMode']];
yield [['orderBy' => 'invalid'], ['orderBy']];
yield [['orderBy' => 'invalid', 'tagsMode' => 'invalid'], ['orderBy', 'tagsMode']];
}
2019-01-27 12:35:00 +01:00
}