Improve tests

This commit is contained in:
Jonny Barnes 2022-05-14 17:44:14 +01:00
parent 427debaba4
commit 48d1c9a00b
18 changed files with 267 additions and 14 deletions

View file

@ -4,6 +4,9 @@ namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
/**
* @codeCoverageIgnore
*/
class Authenticate extends Middleware
{
/**

View file

@ -7,6 +7,9 @@ use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
/**
* @codeCoverageIgnore
*/
class RedirectIfAuthenticated
{
/**

View file

@ -4,6 +4,9 @@ namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustHosts as Middleware;
/**
* @codeCoverageIgnore
*/
class TrustHosts extends Middleware
{
/**

View file

@ -60,7 +60,7 @@ class ProcessLike implements ShouldQueue
//POSSE like
try {
$response = $client->request(
$client->request(
'POST',
'https://brid.gy/publish/webmention',
[
@ -70,8 +70,8 @@ class ProcessLike implements ShouldQueue
],
]
);
} catch (RequestException $exception) {
//no biggie
} catch (RequestException) {
return 0;
}
return 0;

View file

@ -38,6 +38,8 @@ class AppServiceProvider extends ServiceProvider
});
// Bind the Codebird client
// Codebird gets mocked in tests
// @codeCoverageIgnoreStart
$this->app->bind('Codebird\Codebird', function () {
Codebird::setConsumerKey(
env('TWITTER_CONSUMER_KEY'),
@ -53,6 +55,7 @@ class AppServiceProvider extends ServiceProvider
return $cb;
});
// @codeCoverageIgnoreEnd
/**
* Paginate a standard Laravel Collection.

View file

@ -34,9 +34,7 @@ class HorizonServiceProvider extends HorizonApplicationServiceProvider
protected function gate()
{
Gate::define('viewHorizon', function ($user) {
return in_array($user->name, [
'jonny',
]);
return $user->name === 'jonny';
});
}
}

View file

@ -44,6 +44,8 @@ class RouteServiceProvider extends ServiceProvider
* Configure the rate limiters for the application.
*
* @return void
*
* @codeCoverageIgnore
*/
protected function configureRateLimiting()
{

View file

@ -79,11 +79,12 @@ class BookmarkService
}
/**
* Given a URL, use browsershot to save an image of the page.
* Given a URL, use `browsershot` to save an image of the page.
*
* @param string $url
* @return string The uuid for the screenshot
* @throws CouldNotTakeBrowsershot
* @codeCoverageIgnore
*/
public function saveScreenshot(string $url): string
{

View file

@ -24,7 +24,7 @@ class WebMentionFactory extends Factory
return [
'source' => $this->faker->url,
'target' => url('notes/1'),
'type' => 'reply',
'type' => 'in-reply-to',
'content' => $this->faker->paragraph,
];
}

View file

@ -25,6 +25,19 @@ class ActivityStreamTest extends TestCase
]);
}
/** @test */
public function notesPageContainsAuthorActivityStreamData(): void
{
$response = $this->get('/notes', ['Accept' => 'application/activity+json']);
$response->assertHeader('Content-Type', 'application/activity+json');
$response->assertJson([
'@context' => 'https://www.w3.org/ns/activitystreams',
'id' => config('app.url'),
'type' => 'Person',
'name' => config('user.displayname'),
]);
}
/** @test */
public function requestForNoteIncludesActivityStreamData(): void
{

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Tests\Feature\Admin;
use App\Models\User;
use Tests\TestCase;
class AdminTest extends TestCase
@ -31,4 +32,51 @@ class AdminTest extends TestCase
]);
$response->assertRedirect('/login');
}
/** @test */
public function loginSucceeds(): void
{
User::factory([
'name' => 'admin',
'password' => bcrypt('password'),
])->create();
$response = $this->post('/login', [
'name' => 'admin',
'password' => 'password',
]);
$response->assertRedirect('/');
}
/** @test */
public function whenLoggedInRedirectsToAdminPage(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)->get('/login');
$response->assertRedirect('/');
}
/** @test */
public function loggedOutUsersSimplyRedirected(): void
{
$response = $this->get('/logout');
$response->assertRedirect('/');
}
/** @test */
public function loggedInUsersShownLogoutForm(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)->get('/logout');
$response->assertViewIs('logout');
}
/** @test */
public function loggedInUsersCanLogout(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)->post('/logout');
$response->assertRedirect('/');
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace Tests\Feature;
use App\Models\Article;
use App\Models\Bookmark;
use App\Models\Like;
use App\Models\Note;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class FrontPageTest extends TestCase
{
use RefreshDatabase;
/** @test */
public function frontPageLoadsAllContent(): void
{
Note::factory()->create(['note' => 'Note 1']);
Article::factory()->create(['title' => 'Article 1']);
Bookmark::factory()->create(['url' => 'https://example.com']);
Like::factory()->create([
'url' => 'https://example.org/1',
'content' => 'Like 1',
]);
$this->get('/')
->assertSee('Note 1')
->assertSee('Article 1')
->assertSee('https://example.com')
->assertSee('Like 1');
}
}

View file

@ -0,0 +1,28 @@
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class HorizonTest extends TestCase
{
/**
* Horizon has its own test suite, here we just test it has been installed successfully.
*
* @test
* @return void
*/
public function horizonIsInstalled(): void
{
$user = User::factory()->create([
'name' => 'jonny',
]);
$response = $this->actingAs($user)->get('/horizon');
$response->assertStatus(200);
}
}

View file

@ -233,6 +233,44 @@ class LikesTest extends TestCase
$this->assertEquals('Jonny Barnes', Like::find($id)->author_name);
}
/** @test */
public function noErrorForFailureToPosseWithBridgy(): void
{
$like = new Like();
$like->url = 'https://twitter.com/jonnybarnes/status/1050823255123251200';
$like->save();
$id = $like->id;
$job = new ProcessLike($like);
$mock = new MockHandler([
new Response(404, [], 'Not found'),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$this->app->bind(Client::class, function () use ($client) {
return $client;
});
$info = (object) [
'author_name' => 'Jonny Barnes',
'author_url' => 'https://twitter.com/jonnybarnes',
'html' => '<div>HTML of the tweet embed</div>',
];
$codebirdMock = $this->getMockBuilder(Codebird::class)
->addMethods(['statuses_oembed'])
->getMock();
$codebirdMock->method('statuses_oembed')
->willReturn($info);
$this->app->instance(Codebird::class, $codebirdMock);
$authorship = new Authorship();
$job->handle($client, $authorship);
$this->assertEquals('Jonny Barnes', Like::find($id)->author_name);
}
/** @test */
public function unknownLikeGivesNotFoundResponse(): void
{

View file

@ -34,6 +34,50 @@ class MicropubMediaTest extends TestCase
$response->assertJson(['url' => null]);
}
/** @test */
public function getRequestWithInvalidTokenReturnsErrorResponse(): void
{
$response = $this->get(
'/api/media?q=last',
['HTTP_Authorization' => 'Bearer abc123']
);
$response->assertStatus(400);
$response->assertJsonFragment(['error_description' => 'The provided token did not pass validation']);
}
/** @test */
public function getRequestWithTokenWithoutScopeReturnsErrorResponse(): void
{
$response = $this->get(
'/api/media?q=last',
['HTTP_Authorization' => 'Bearer ' . $this->getTokenWithNoScope()]
);
$response->assertStatus(400);
$response->assertJsonFragment(['error_description' => 'The provided token has no scopes']);
}
/** @test */
public function getRequestWithTokenWithInsufficientScopeReturnsErrorResponse(): void
{
$response = $this->get(
'/api/media?q=last',
['HTTP_Authorization' => 'Bearer ' . $this->getTokenWithIncorrectScope()]
);
$response->assertStatus(401);
$response->assertJsonFragment(['error_description' => 'The tokens scope does not have the necessary requirements.']);
}
/** @test */
public function emptyGetRequestWithTokenReceivesOkResponse(): void
{
$response = $this->get(
'/api/media',
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
);
$response->assertStatus(200);
$response->assertJson(['status' => 'OK']);
}
/** @test */
public function clientCanListLastUpload(): void
{
@ -124,6 +168,22 @@ class MicropubMediaTest extends TestCase
unlink(storage_path('app/') . $filename);
}
/** @test */
public function mediaEndpointUploadRequiresFile(): void
{
$response = $this->post(
'/api/media',
[],
['HTTP_Authorization' => 'Bearer ' . $this->getToken()]
);
$response->assertStatus(400);
$response->assertJson([
'response' => 'error',
'error' => 'invalid_request',
'error_description' => 'No file was sent with the request',
]);
}
/** @test */
public function errorResponseForUnknownQValue(): void
{

View file

@ -79,5 +79,12 @@ class ArticlesTest extends TestCase
$emptyScope = Article::date()->get();
$this->assertCount(2, $emptyScope);
// Check the December case
$article = Article::factory()->create([
'created_at' => Carbon::now()->setMonth(12)->toDateTimeString(),
'updated_at' => Carbon::now()->setMonth(12)->toDateTimeString(),
]);
$this->assertCount(1, Article::date(date('Y'), 12)->get());
}
}

View file

@ -89,23 +89,25 @@ class ProcessWebMentionJobTest extends TestCase
Queue::fake();
$parser = new Parser();
$note = Note::factory()->create();
$source = 'https://aaronpk.localhost/reply/1';
WebMention::factory()->create([
'source' => $source,
'target' => $note->longurl,
]);
$html = <<<HTML
<div class="h-entry">
<p>In reply to <a class="u-in-reply-to" href="/notes/E">a note</a></p>
<p>In reply to <a class="u-in-reply-to" href="{$note->longurl}">a note</a></p>
<div class="e-content">Updated reply</div>
</div>
HTML;
$html = str_replace('href="', 'href="' . config('app.url'), $html);
$mock = new MockHandler([
new Response(200, [], $html),
]);
$handler = HandlerStack::create($mock);
$client = new Client(['handler' => $handler]);
$note = Note::factory()->create();
$source = 'https://aaronpk.localhost/reply/1';
$job = new ProcessWebMention($note, $source);
$job->handle($parser, $client);
@ -114,7 +116,7 @@ class ProcessWebMentionJobTest extends TestCase
'source' => $source,
'type' => 'in-reply-to',
// phpcs:ignore Generic.Files.LineLength.TooLong
'mf2' => '{"rels": [], "items": [{"type": ["h-entry"], "properties": {"content": [{"html": "Updated reply", "value": "Updated reply"}], "in-reply-to": ["' . config('app.url') . '/notes/E"]}}], "rel-urls": []}',
'mf2' => '{"rels": [], "items": [{"type": ["h-entry"], "properties": {"content": [{"html": "Updated reply", "value": "Updated reply"}], "in-reply-to": ["' . $note->longurl . '"]}}], "rel-urls": []}',
]);
}

View file

@ -31,6 +31,17 @@ class LikesTest extends TestCase
$this->assertEquals('some plaintext content', $like->content);
}
/** @test */
public function weCanHandleBlankContent(): void
{
$like = new Like();
$like->url = 'https://example.org/post/123';
$like->content = null;
$like->save();
$this->assertNull($like->content);
}
/** @test */
public function htmlLikeContentIsFiltered(): void
{