now = Chronos::now(); Chronos::setTestNow($this->now); $this->generator = new PublishingUpdatesGenerator( new ShortUrlDataTransformer(new ShortUrlStringifier()), ); } protected function tearDown(): void { Chronos::setTestNow(); } #[Test, DataProvider('provideMethod')] public function visitIsProperlySerializedIntoUpdate(string $method, string $expectedTopic, string|null $title): void { $shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([ 'customSlug' => 'foo', 'longUrl' => 'https://longUrl', 'title' => $title, ])); $visit = Visit::forValidShortUrl($shortUrl, Visitor::empty()); /** @var Update $update */ $update = $this->generator->{$method}($visit); self::assertEquals($expectedTopic, $update->topic); self::assertEquals([ 'shortUrl' => [ 'shortCode' => $shortUrl->getShortCode(), 'shortUrl' => 'http:/' . $shortUrl->getShortCode(), 'longUrl' => 'https://longUrl', 'dateCreated' => $this->now->toAtomString(), 'tags' => [], 'meta' => [ 'validSince' => null, 'validUntil' => null, 'maxVisits' => null, ], 'domain' => null, 'title' => $title, 'crawlable' => false, 'forwardQuery' => true, 'visitsSummary' => VisitsSummary::fromTotalAndNonBots(0, 0), 'hasRedirectRules' => false, ], 'visit' => [ 'referer' => '', 'userAgent' => '', 'visitLocation' => null, 'date' => $visit->date->toAtomString(), 'potentialBot' => false, 'visitedUrl' => '', ], ], $update->payload); } public static function provideMethod(): iterable { yield 'newVisitUpdate' => ['newVisitUpdate', 'https://shlink.io/new-visit', 'the cool title']; yield 'newShortUrlVisitUpdate' => ['newShortUrlVisitUpdate', 'https://shlink.io/new-visit/foo', null]; } #[Test, DataProvider('provideOrphanVisits')] public function orphanVisitIsProperlySerializedIntoUpdate(Visit $orphanVisit): void { $update = $this->generator->newOrphanVisitUpdate($orphanVisit); self::assertEquals('https://shlink.io/new-orphan-visit', $update->topic); self::assertEquals([ 'visit' => [ 'referer' => '', 'userAgent' => '', 'visitLocation' => null, 'date' => $orphanVisit->date->toAtomString(), 'potentialBot' => false, 'visitedUrl' => $orphanVisit->visitedUrl, 'type' => $orphanVisit->type->value, ], ], $update->payload); } public static function provideOrphanVisits(): iterable { $visitor = Visitor::empty(); yield VisitType::REGULAR_404->value => [Visit::forRegularNotFound($visitor)]; yield VisitType::INVALID_SHORT_URL->value => [Visit::forInvalidShortUrl($visitor)]; yield VisitType::BASE_URL->value => [Visit::forBasePath($visitor)]; } #[Test] public function shortUrlIsProperlySerializedIntoUpdate(): void { $shortUrl = ShortUrl::create(ShortUrlCreation::fromRawData([ 'customSlug' => 'foo', 'longUrl' => 'https://longUrl', 'title' => 'The title', ])); $update = $this->generator->newShortUrlUpdate($shortUrl); self::assertEquals(Topic::NEW_SHORT_URL->value, $update->topic); self::assertEquals(['shortUrl' => [ 'shortCode' => $shortUrl->getShortCode(), 'shortUrl' => 'http:/' . $shortUrl->getShortCode(), 'longUrl' => 'https://longUrl', 'dateCreated' => $this->now->toAtomString(), 'tags' => [], 'meta' => [ 'validSince' => null, 'validUntil' => null, 'maxVisits' => null, ], 'domain' => null, 'title' => 'The title', 'crawlable' => false, 'forwardQuery' => true, 'visitsSummary' => VisitsSummary::fromTotalAndNonBots(0, 0), 'hasRedirectRules' => false, ]], $update->payload); } }