Skip to content

Commit

Permalink
Add test for "What's new" section
Browse files Browse the repository at this point in the history
  • Loading branch information
danon committed Feb 7, 2024
1 parent 00dad89 commit 6e22deb
Show file tree
Hide file tree
Showing 8 changed files with 225 additions and 36 deletions.
54 changes: 33 additions & 21 deletions app/Services/Widgets/WhatsNew.php
Original file line number Diff line number Diff line change
@@ -1,38 +1,50 @@
<?php

namespace Coyote\Services\Widgets;

use Coyote\Repositories\Contracts\MicroblogRepositoryInterface as MicroblogRepository;
use Coyote\Repositories\Contracts\UserRepositoryInterface as UserRepository;
use Coyote\Microblog;
use Coyote\Repositories\Criteria\Microblog\OnlyMine;
use Coyote\Repositories\Criteria\Microblog\WithTag;
use Illuminate\Contracts\Cache\Repository as Cache;
use Coyote\Repositories\Eloquent\MicroblogRepository;
use Coyote\User;
use Illuminate\Contracts\Cache;
use Illuminate\Contracts\View\View;

class WhatsNew
{
protected MicroblogRepository $microblog;
protected UserRepository $user;
protected Cache $cache;

public function __construct(MicroblogRepository $microblog, UserRepository $user, Cache $cache)
public function __construct(
private MicroblogRepository $microblog,
private Cache\Repository $cache)
{
$this->microblog = $microblog;
$this->user = $user;
$this->cache = $cache;
}

public function render(): string
{
return $this->cache->remember('widget:whats-new', now()->addHour(), function () {
$this->user->resetCriteria();

$user = $this->user->findBy('name', '4programmers.net', ['id']);
return $this->cache->remember(
'widget:whats-new',
now()->addHour(),
fn() => $this->widgetView()->render());
}

$this->microblog->resetCriteria();
$this->microblog->pushCriteria(new WithTag('4programmers.net'));
$this->microblog->pushCriteria(new OnlyMine($user->id ?? null));
private function widgetView(): View
{
$this->microblog->resetCriteria();
$this->microblog->pushCriteria(new WithTag('4programmers.net'));
$this->microblog->pushCriteria(new OnlyMine($this->userIdByName('4programmers.net')));

return view('homepage.whats-new', [
'href' => route('microblog.tag', ['4programmers.net']),
'microblogs' => $this->microblog->recent()->map(fn(Microblog $microblog) => [
'id' => $microblog->id,
'summary' => excerpt($microblog->html),
'href' => route('microblog.view', [$microblog->id]),
'date' => $microblog->created_at->formatLocalized('%d %b %y'),
]),
]);
}

return view('homepage.whats-new', ['microblogs' => $this->microblog->recent()])->render();
});
private function userIdByName(string $name): ?int
{
$user = User::query()->where('name', '=', $name)->first(['id']);
return $user->id ?? null;
}
}
17 changes: 13 additions & 4 deletions resources/views/homepage/whats-new.twig
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
<div class="card bg-dark">
<div class="card-body">
<h5 class="card-title"><a class="text-light" title="Zobacz zmiany w serwisie 4programmers.net" href="{{ route('microblog.tag', ['4programmers.net']) }}">Nowości od #4programmers.net</a></h5>

<h5 class="card-title">
<a class="text-light"
title="Zobacz zmiany w serwisie 4programmers.net"
href="{{ href }}">
Nowości od #4programmers.net
</a>
</h5>
<ul class="list-unstyled mb-0">
{% for microblog in microblogs %}
<li class="pt-1 pb-2">
<a class="d-block text-white-50 text-truncate" href="{{ route('microblog.view', [microblog.id]) }}">{{ excerpt(microblog.html) }}</a>
<small class="d-block text-light" style="font-size: 11px">— {{ microblog.created_at|date_localized('%d %b %y') }}</small>
<a class="d-block text-white-50 text-truncate" href="{{ microblog.href }}">
{{ microblog.summary }}
</a>
<div class="text-light" style="font-size: 11px">
— {{ microblog.date }}
</div>
</li>
{% endfor %}
</ul>
Expand Down
20 changes: 20 additions & 0 deletions tests/Unit/BaseFixture/ClearedCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
namespace Tests\Unit\BaseFixture;

use Illuminate\Contracts\Cache;
use Tests\Unit\BaseFixture\Server\Laravel;

trait ClearedCache
{
use Laravel\Application;

/**
* @before
*/
function clearCache(): void
{
/** @var Cache\Repository $cache */
$cache = $this->laravel->app[Cache\Repository::class];
$cache->clear();
}
}
13 changes: 2 additions & 11 deletions tests/Unit/Seo/Link/Fixture/Assertion.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,14 @@
namespace Tests\Unit\Seo\Link\Fixture;

use Coyote\Services\Parser\Factories\PostFactory;
use Illuminate\Contracts\Cache;
use PHPUnit\Framework\Assert;
use Tests\Unit\BaseFixture;
use Tests\Unit\BaseFixture\Server\Laravel;

trait Assertion
{
use Laravel\Application;

/**
* @before
*/
function clearCache(): void
{
/** @var Cache\Repository $cache */
$cache = $this->laravel->app[Cache\Repository::class];
$cache->clear();
}
use BaseFixture\ClearedCache;

function assertRenderPost(string $text, string $expected): void
{
Expand Down
50 changes: 50 additions & 0 deletions tests/Unit/WhatsNew/Fixture/Models.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
namespace Tests\Unit\WhatsNew\Fixture;

use Carbon\Carbon;
use Coyote\Microblog;
use Coyote\Tag;
use Coyote\User;
use Tests\Unit\BaseFixture\Server\Laravel;
use Tests\Unit\Seo;

trait Models
{
use Laravel\Transactional;

function newWhatsNewItem(string $text, string $dateTime): int
{
return $this->newMicroblog(
$text,
new Carbon($dateTime),
$this->newTag('4programmers.net'));
}

function newMicroblog(string $text, Carbon $date, Tag $tag): int
{
$microblog = new Microblog([
'user_id' => $this->systemUser()->id,
'text' => $text,
]);
$microblog->created_at = $date;
$microblog->save();
$microblog->tags()->save($tag);
return $microblog->id;
}

function newTag(string $name): Tag
{
$tag = new Tag(['name' => $name]);
$tag->save();
return $tag;
}

function systemUser(): User
{
$user = new User();
$user->name = '4programmers.net';
$user->email = 'irrelevant';
$user->save();
return $user;
}
}
36 changes: 36 additions & 0 deletions tests/Unit/WhatsNew/Fixture/NewsItems.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
namespace Tests\Unit\WhatsNew\Fixture;

use Tests\Unit\BaseFixture\View;
use Tests\Unit\BaseFixture\View\ViewDom;

trait NewsItems
{
use View\HtmlView;

function newsItem(): array
{
$dom = new ViewDom($this->htmlView('/'));
/** @var \DOMElement $listItem */
foreach ($dom->elements(xPath:'//aside//div[@class="card bg-dark"]//ul/li') as $listItem) {
return $this->listItem($listItem);
}
throw new \AssertionError("Failed finding news item.");
}

function listItem(\DOMElement $listItem): array
{
$item = [];
/** @var \DOMElement $child */
foreach ($listItem->childNodes as $child) {
if ($child->nodeName === 'a') {
$item['text'] = $child->textContent;
$item['href'] = $child->getAttribute('href');
}
if ($child->nodeName === 'div') {
$item['date'] = $child->textContent;
}
}
return $item;
}
}
42 changes: 42 additions & 0 deletions tests/Unit/WhatsNew/Fixture/TrimmedString.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php
namespace Tests\Unit\WhatsNew\Fixture;

use PHPUnit\Framework\Constraint\Constraint;
use SebastianBergmann\Comparator\ComparisonFailure;

class TrimmedString extends Constraint
{
public function __construct(private string $value)
{
}

public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
{
$success = $this->value === \trim($other);
if ($returnResult) {
return $success;
}
if (!$success) {
$this->fail($other, $description, new ComparisonFailure(
$this->value,
$other,
"'$this->value'",
"'$other'",
));
}
return null;
}

public function toString(): string
{
return 'is identical to trimmed ' . $this->exporter()->export($this->value);
}

protected function failureDescription($other): string
{
if (\is_string($other)) {
return 'two strings are identical';
}
return parent::failureDescription($other);
}
}
29 changes: 29 additions & 0 deletions tests/Unit/WhatsNew/Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
namespace Tests\Unit\WhatsNew;

use PHPUnit\Framework\TestCase;
use Tests\Unit\BaseFixture;
use Tests\Unit\BaseFixture\Constraint\ArrayKey;
use Tests\Unit\Seo;
use Tests\Unit\WhatsNew;
use Tests\Unit\WhatsNew\Fixture\TrimmedString;

class Test extends TestCase
{
use BaseFixture\ClearedCache;
use BaseFixture\Server\RelativeUri;
use WhatsNew\Fixture\Models;
use WhatsNew\Fixture\NewsItems;

public function test()
{
$id = $this->newWhatsNewItem('Valar morghulis.', '2005-04-02 21:37:13');
$this->assertThat(
$this->newsItem(),
$this->logicalAnd(
new ArrayKey('text', new TrimmedString('Valar morghulis.')),
new ArrayKey('href', $this->relativeUri("/Mikroblogi/View/$id")),
new ArrayKey('date', new TrimmedString('— 02 kwi 05')),
));
}
}

0 comments on commit 6e22deb

Please sign in to comment.