From 8142801f1f9f9f9512f3eac55f9c20c21a775c7a Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Mon, 16 Dec 2019 23:03:32 +0100 Subject: [PATCH] Updated ListShortUrlsAction api test so that it covers filtering use cases --- .../src/Repository/ShortUrlRepository.php | 19 +- .../test-api/Action/ListShortUrlsTest.php | 233 +++++++++++------- .../test-api/Fixtures/ShortUrlsFixture.php | 9 +- 3 files changed, 158 insertions(+), 103 deletions(-) diff --git a/module/Core/src/Repository/ShortUrlRepository.php b/module/Core/src/Repository/ShortUrlRepository.php index 1c26c122..ac7b5f50 100644 --- a/module/Core/src/Repository/ShortUrlRepository.php +++ b/module/Core/src/Repository/ShortUrlRepository.php @@ -54,15 +54,9 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI private function processOrderByForList(QueryBuilder $qb, $orderBy): array { - // Map public field names to column names - $fieldNameMap = [ - 'originalUrl' => 'longUrl', - 'longUrl' => 'longUrl', - 'shortCode' => 'shortCode', - 'dateCreated' => 'dateCreated', - ]; - $fieldName = is_array($orderBy) ? key($orderBy) : $orderBy; - $order = is_array($orderBy) ? $orderBy[$fieldName] : 'ASC'; + $isArray = is_array($orderBy); + $fieldName = $isArray ? key($orderBy) : $orderBy; + $order = $isArray ? $orderBy[$fieldName] : 'ASC'; if (contains(['visits', 'visitsCount', 'visitCount'], $fieldName)) { $qb->addSelect('COUNT(DISTINCT v) AS totalVisits') @@ -73,6 +67,13 @@ class ShortUrlRepository extends EntityRepository implements ShortUrlRepositoryI return array_column($qb->getQuery()->getResult(), 0); } + // Map public field names to column names + $fieldNameMap = [ + 'originalUrl' => 'longUrl', + 'longUrl' => 'longUrl', + 'shortCode' => 'shortCode', + 'dateCreated' => 'dateCreated', + ]; if (array_key_exists($fieldName, $fieldNameMap)) { $qb->orderBy('s.' . $fieldNameMap[$fieldName], $order); } diff --git a/module/Rest/test-api/Action/ListShortUrlsTest.php b/module/Rest/test-api/Action/ListShortUrlsTest.php index d2171b3a..eaa13a0a 100644 --- a/module/Rest/test-api/Action/ListShortUrlsTest.php +++ b/module/Rest/test-api/Action/ListShortUrlsTest.php @@ -4,107 +4,160 @@ declare(strict_types=1); namespace ShlinkioApiTest\Shlink\Rest\Action; +use Cake\Chronos\Chronos; +use GuzzleHttp\RequestOptions; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; +use function count; + class ListShortUrlsTest extends ApiTestCase { - /** @test */ - public function shortUrlsAreProperlyListed(): void + private const SHORT_URL_SHLINK = [ + 'shortCode' => 'abc123', + 'shortUrl' => 'http://doma.in/abc123', + 'longUrl' => 'https://shlink.io', + 'dateCreated' => '2018-05-01T00:00:00+00:00', + 'visitsCount' => 3, + 'tags' => ['foo'], + 'meta' => [ + 'validSince' => null, + 'validUntil' => null, + 'maxVisits' => null, + ], + 'originalUrl' => 'https://shlink.io', + ]; + private const 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', + 'visitsCount' => 0, + 'tags' => [], + 'meta' => [ + 'validSince' => null, + 'validUntil' => null, + 'maxVisits' => null, + ], + 'originalUrl' => 'https://google.com', + ]; + private const SHORT_URL_META = [ + 'shortCode' => 'def456', + 'shortUrl' => 'http://doma.in/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:00+00:00', + 'visitsCount' => 2, + 'tags' => ['bar', 'foo'], + 'meta' => [ + 'validSince' => '2020-05-01T00:00:00+00:00', + 'validUntil' => null, + 'maxVisits' => null, + ], + 'originalUrl' => + 'https://blog.alejandrocelaya.com/2017/12/09' + . '/acmailer-7-0-the-most-important-release-in-a-long-time/', + ]; + private const SHORT_URL_CUSTOM_SLUG = [ + 'shortCode' => 'custom', + 'shortUrl' => 'http://doma.in/custom', + 'longUrl' => 'https://shlink.io', + 'dateCreated' => '2019-01-01T00:00:00+00:00', + 'visitsCount' => 0, + 'tags' => [], + 'meta' => [ + 'validSince' => null, + 'validUntil' => null, + 'maxVisits' => 2, + ], + 'originalUrl' => 'https://shlink.io', + ]; + private const 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:00+00:00', + 'visitsCount' => 0, + 'tags' => [], + 'meta' => [ + 'validSince' => null, + 'validUntil' => null, + 'maxVisits' => null, + ], + 'originalUrl' => + 'https://blog.alejandrocelaya.com/2019/04/27' + . '/considerations-to-properly-use-open-source-software-projects/', + ]; + + /** + * @test + * @dataProvider provideFilteredLists + */ + public function shortUrlsAreProperlyListed(array $query, array $expectedShortUrls): void { - $resp = $this->callApiWithKey(self::METHOD_GET, '/short-urls'); + $resp = $this->callApiWithKey(self::METHOD_GET, '/short-urls', [RequestOptions::QUERY => $query]); $respPayload = $this->getJsonResponsePayload($resp); $this->assertEquals(self::STATUS_OK, $resp->getStatusCode()); $this->assertEquals([ 'shortUrls' => [ - 'data' => [ - [ - 'shortCode' => 'abc123', - 'shortUrl' => 'http://doma.in/abc123', - 'longUrl' => 'https://shlink.io', - 'dateCreated' => '2019-01-01T00:00:00+00:00', - 'visitsCount' => 3, - 'tags' => ['foo'], - 'meta' => [ - 'validSince' => null, - 'validUntil' => null, - 'maxVisits' => null, - ], - 'originalUrl' => 'https://shlink.io', - ], - [ - 'shortCode' => 'def456', - 'shortUrl' => 'http://doma.in/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:00+00:00', - 'visitsCount' => 2, - 'tags' => ['bar', 'foo'], - 'meta' => [ - 'validSince' => '2020-05-01T00:00:00+00:00', - 'validUntil' => null, - 'maxVisits' => null, - ], - 'originalUrl' => - 'https://blog.alejandrocelaya.com/2017/12/09' - . '/acmailer-7-0-the-most-important-release-in-a-long-time/', - ], - [ - 'shortCode' => 'custom', - 'shortUrl' => 'http://doma.in/custom', - 'longUrl' => 'https://shlink.io', - 'dateCreated' => '2019-01-01T00:00:00+00:00', - 'visitsCount' => 0, - 'tags' => [], - 'meta' => [ - 'validSince' => null, - 'validUntil' => null, - 'maxVisits' => 2, - ], - 'originalUrl' => 'https://shlink.io', - ], - [ - '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:00+00:00', - 'visitsCount' => 0, - 'tags' => [], - 'meta' => [ - 'validSince' => null, - 'validUntil' => null, - 'maxVisits' => null, - ], - 'originalUrl' => - 'https://blog.alejandrocelaya.com/2019/04/27' - . '/considerations-to-properly-use-open-source-software-projects/', - ], - [ - 'shortCode' => 'custom-with-domain', - 'shortUrl' => 'http://some-domain.com/custom-with-domain', - 'longUrl' => 'https://google.com', - 'dateCreated' => '2019-01-01T00:00:00+00:00', - 'visitsCount' => 0, - 'tags' => [], - 'meta' => [ - 'validSince' => null, - 'validUntil' => null, - 'maxVisits' => null, - ], - 'originalUrl' => 'https://google.com', - ], - ], - 'pagination' => [ - 'currentPage' => 1, - 'pagesCount' => 1, - 'itemsPerPage' => 10, - 'itemsInCurrentPage' => 5, - 'totalItems' => 5, - ], + 'data' => $expectedShortUrls, + 'pagination' => $this->buildPagination(count($expectedShortUrls)), ], ], $respPayload); } + + public function provideFilteredLists(): iterable + { + yield [[], [ + self::SHORT_URL_SHLINK, + self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN, + self::SHORT_URL_META, + self::SHORT_URL_CUSTOM_SLUG, + self::SHORT_URL_CUSTOM_DOMAIN, + ]]; + yield [['orderBy' => 'shortCode'], [ + self::SHORT_URL_SHLINK, + self::SHORT_URL_CUSTOM_SLUG, + self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN, + self::SHORT_URL_META, + self::SHORT_URL_CUSTOM_DOMAIN, + ]]; + yield [['startDate' => Chronos::parse('2018-12-01')->toAtomString()], [ + self::SHORT_URL_META, + self::SHORT_URL_CUSTOM_SLUG, + self::SHORT_URL_CUSTOM_DOMAIN, + ]]; + yield [['endDate' => Chronos::parse('2018-12-01')->toAtomString()], [ + self::SHORT_URL_SHLINK, + self::SHORT_URL_CUSTOM_SLUG_AND_DOMAIN, + ]]; + yield [['tags' => ['foo']], [ + self::SHORT_URL_SHLINK, + self::SHORT_URL_META, + ]]; + yield [['tags' => ['bar']], [ + self::SHORT_URL_META, + ]]; + yield [['tags' => ['foo'], 'endDate' => Chronos::parse('2018-12-01')->toAtomString()], [ + self::SHORT_URL_SHLINK, + ]]; + yield [['searchTerm' => 'alejandro'], [ + self::SHORT_URL_META, + self::SHORT_URL_CUSTOM_DOMAIN, + ]]; + } + + private function buildPagination(int $itemsCount): array + { + return [ + 'currentPage' => 1, + 'pagesCount' => 1, + 'itemsPerPage' => 10, + 'itemsInCurrentPage' => $itemsCount, + 'totalItems' => $itemsCount, + ]; + } } diff --git a/module/Rest/test-api/Fixtures/ShortUrlsFixture.php b/module/Rest/test-api/Fixtures/ShortUrlsFixture.php index 3282e575..62ec00a9 100644 --- a/module/Rest/test-api/Fixtures/ShortUrlsFixture.php +++ b/module/Rest/test-api/Fixtures/ShortUrlsFixture.php @@ -21,7 +21,8 @@ class ShortUrlsFixture extends AbstractFixture public function load(ObjectManager $manager): void { $abcShortUrl = $this->setShortUrlDate( - new ShortUrl('https://shlink.io', ShortUrlMeta::createFromRawData(['customSlug' => 'abc123'])) + new ShortUrl('https://shlink.io', ShortUrlMeta::createFromRawData(['customSlug' => 'abc123'])), + Chronos::parse('2018-05-01') ); $manager->persist($abcShortUrl); @@ -46,7 +47,7 @@ class ShortUrlsFixture extends AbstractFixture $withDomainAndSlugShortUrl = $this->setShortUrlDate(new ShortUrl( 'https://google.com', ShortUrlMeta::createFromRawData(['domain' => 'some-domain.com', 'customSlug' => 'custom-with-domain']) - )); + ), Chronos::parse('2018-10-20')); $manager->persist($withDomainAndSlugShortUrl); $manager->flush(); @@ -55,12 +56,12 @@ class ShortUrlsFixture extends AbstractFixture $this->addReference('def456_short_url', $defShortUrl); } - private function setShortUrlDate(ShortUrl $shortUrl): ShortUrl + private function setShortUrlDate(ShortUrl $shortUrl, ?Chronos $date = null): ShortUrl { $ref = new ReflectionObject($shortUrl); $dateProp = $ref->getProperty('dateCreated'); $dateProp->setAccessible(true); - $dateProp->setValue($shortUrl, Chronos::create(2019, 1, 1, 0, 0, 0)); + $dateProp->setValue($shortUrl, $date ?? Chronos::parse('2019-01-01')); return $shortUrl; }