test: add notification, search, compose, report, and collection tests (332 total)

Api/NotificationTest: notification isolation, correct user filtering
Api/SearchTest: v2 search auth, structure, account lookup
Api/CollectionTest: self/user collections, auth requirement
Compose/ComposeTest: page access, settings, media validation, autocomplete
Account/ReportTest: report creation, type validation, auth requirement
pull/6858/head
Your Name 4 weeks ago
parent e1f883a41b
commit 0f3820e7bf

@ -0,0 +1,68 @@
<?php
use App\Report;
use App\Status;
use App\User;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
uses(LazilyRefreshDatabase::class);
/*
|--------------------------------------------------------------------------
| Report Tests
|--------------------------------------------------------------------------
*/
describe('report submission', function () {
it('creates a report for a status', function () {
$user = User::factory()->create();
$user->refresh();
$other = User::factory()->create();
$other->refresh();
$status = Status::factory()->create([
'profile_id' => $other->profile_id,
'type' => 'photo',
]);
$this->actingAs($user)
->postJson('/i/report', [
'report' => 'spam',
'type' => 'post',
'id' => $status->id,
'msg' => 'This is spam content',
])
->assertOk();
expect(Report::where('profile_id', $user->profile_id)->exists())->toBeTrue();
});
it('rejects report with invalid type', function () {
$user = User::factory()->create();
$user->refresh();
$this->actingAs($user)
->postJson('/i/report', [
'report' => 'invalid_type',
'type' => 'post',
'id' => 1,
])
->assertStatus(400);
});
it('validates required fields', function () {
$user = User::factory()->create();
$user->refresh();
$this->actingAs($user)
->postJson('/i/report', [])
->assertUnprocessable();
});
it('requires authentication', function () {
$this->postJson('/i/report', [
'report' => 'spam',
'type' => 'post',
'id' => 1,
])->assertUnauthorized();
});
});

@ -0,0 +1,49 @@
<?php
use App\User;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Laravel\Passport\Passport;
uses(LazilyRefreshDatabase::class);
/*
|--------------------------------------------------------------------------
| Collection Tests
|--------------------------------------------------------------------------
*/
describe('collections', function () {
it('lists self collections', function () {
$user = User::factory()->create();
$user->refresh();
Passport::actingAs($user, ['read']);
$this->getJson('/api/pixelfed/v1/collections/self')
->assertOk()
->assertJsonIsArray();
});
it('lists user collections by account id', function () {
$user = User::factory()->create();
$user->refresh();
Passport::actingAs($user, ['read']);
$this->getJson("/api/pixelfed/v1/collections/accounts/{$user->profile_id}")
->assertOk()
->assertJsonIsArray();
});
it('returns 404 for non-existent collection', function () {
$user = User::factory()->create();
$user->refresh();
Passport::actingAs($user, ['read']);
$this->getJson('/api/pixelfed/v1/collections/view/999999')
->assertNotFound();
});
it('requires authentication for self collections', function () {
$this->getJson('/api/pixelfed/v1/collections/self')
->assertUnauthorized();
});
});

@ -0,0 +1,74 @@
<?php
use App\Like;
use App\Notification;
use App\Status;
use App\User;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Laravel\Passport\Passport;
uses(LazilyRefreshDatabase::class);
/*
|--------------------------------------------------------------------------
| Notification API Tests
|--------------------------------------------------------------------------
*/
describe('GET /api/v1/notifications', function () {
it('returns empty array for user with no notifications', function () {
$user = User::factory()->create();
$user->refresh();
Passport::actingAs($user, ['read']);
$this->getJson('/api/v1/notifications')
->assertOk()
->assertJson([]);
});
it('returns notifications for authenticated user', function () {
$user = User::factory()->create();
$user->refresh();
$other = User::factory()->create();
$other->refresh();
$status = Status::factory()->create([
'profile_id' => $user->profile_id,
'type' => 'photo',
]);
Notification::create([
'profile_id' => $user->profile_id,
'actor_id' => $other->profile_id,
'action' => 'like',
'item_id' => $status->id,
'item_type' => Status::class,
]);
Passport::actingAs($user, ['read']);
$this->getJson('/api/v1/notifications')
->assertOk()
->assertJsonIsArray();
});
it('does not return other users notifications', function () {
$user = User::factory()->create();
$user->refresh();
$other = User::factory()->create();
$other->refresh();
Notification::create([
'profile_id' => $other->profile_id,
'actor_id' => $user->profile_id,
'action' => 'follow',
'item_id' => $other->profile_id,
'item_type' => \App\Profile::class,
]);
Passport::actingAs($user, ['read']);
$this->getJson('/api/v1/notifications')
->assertOk()
->assertJson([]);
});
});

@ -0,0 +1,54 @@
<?php
use App\User;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Laravel\Passport\Passport;
uses(LazilyRefreshDatabase::class);
/*
|--------------------------------------------------------------------------
| Search API Tests
|--------------------------------------------------------------------------
*/
describe('GET /api/v2/search', function () {
it('requires authentication', function () {
$this->getJson('/api/v2/search?q=test')
->assertUnauthorized();
});
it('returns results structure for a query', function () {
$user = User::factory()->create();
$user->refresh();
Passport::actingAs($user, ['read']);
$this->getJson('/api/v2/search?q=test')
->assertOk()
->assertJsonStructure(['accounts', 'statuses', 'hashtags']);
});
it('rejects empty query', function () {
$user = User::factory()->create();
$user->refresh();
Passport::actingAs($user, ['read']);
$this->getJson('/api/v2/search?q=')
->assertStatus(422);
});
it('finds local accounts by username', function () {
$target = User::factory()->create(['username' => 'searchable']);
$target->refresh();
$user = User::factory()->create();
$user->refresh();
Passport::actingAs($user, ['read']);
$response = $this->getJson('/api/v2/search?q=searchable&type=accounts');
$response->assertOk();
$accounts = $response->json('accounts');
$usernames = collect($accounts)->pluck('username')->toArray();
expect($usernames)->toContain('searchable');
});
});

@ -0,0 +1,102 @@
<?php
use App\User;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
uses(LazilyRefreshDatabase::class);
/*
|--------------------------------------------------------------------------
| Compose Tests
|--------------------------------------------------------------------------
*/
describe('compose page', function () {
it('loads for authenticated user', function () {
$user = User::factory()->create();
$user->refresh();
$this->actingAs($user)
->get('/i/compose')
->assertOk();
});
it('requires authentication', function () {
$this->get('/i/compose')
->assertStatus(403);
});
});
describe('compose settings', function () {
it('returns compose settings for authenticated user', function () {
$user = User::factory()->create();
$user->refresh();
$this->actingAs($user)
->getJson('/api/compose/v0/settings')
->assertOk()
->assertJsonStructure(['max_altext_length']);
});
});
describe('media upload', function () {
it('rejects upload without file', function () {
$user = User::factory()->create();
$user->refresh();
$this->actingAs($user)
->postJson('/api/compose/v0/media/upload', [])
->assertUnprocessable();
});
it('rejects file exceeding max size', function () {
$user = User::factory()->create();
$user->refresh();
$maxSize = (int) config('pixelfed.max_photo_size', 15000);
// Create a file larger than max
$file = UploadedFile::fake()->create('large.jpg', $maxSize + 1000, 'image/jpeg');
$this->actingAs($user)
->postJson('/api/compose/v0/media/upload', [
'file' => $file,
])
->assertUnprocessable();
});
it('rejects unsupported file types', function () {
$user = User::factory()->create();
$user->refresh();
$file = UploadedFile::fake()->create('document.pdf', 100, 'application/pdf');
$this->actingAs($user)
->postJson('/api/compose/v0/media/upload', [
'file' => $file,
])
->assertUnprocessable();
});
});
describe('hashtag autocomplete', function () {
it('returns results for hashtag search', function () {
$user = User::factory()->create();
$user->refresh();
$this->actingAs($user)
->getJson('/api/compose/v0/search/tag?q=pixel')
->assertOk()
->assertJsonIsArray();
});
it('rejects empty query', function () {
$user = User::factory()->create();
$user->refresh();
$this->actingAs($user)
->getJson('/api/compose/v0/search/tag?q=')
->assertStatus(422);
});
});
Loading…
Cancel
Save