You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pixelfed/tests/Feature/Api/DirectMessageReadTest.php

125 lines
4.0 KiB
PHP

<?php
use App\Models\DmConversationParticipant;
use App\Models\DmMessage;
use App\Models\Profile;
use App\Models\User;
use App\Models\UserSetting;
use App\Services\DirectMessageService;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Redis;
use Laravel\Passport\Passport;
uses(LazilyRefreshDatabase::class);
/*
|--------------------------------------------------------------------------
| Direct Message read endpoint
|--------------------------------------------------------------------------
|
| DirectMessageController@read is the legacy way to mark a thread read. It
| is addressed by the other person's profile id and a message id, and
| returns the ids it marked. Read state now lives on the conversation
| participant, so these tests lock in the observable behaviour: messages
| from that sender at or after the given id are reported and the thread is
| read up to the newest of them.
|
*/
beforeEach(function () {
Redis::spy();
Queue::fake();
$this->withoutMiddleware(ThrottleRequests::class);
config(['snowflake.datacenter_id' => 1, 'snowflake.worker_id' => 1]);
});
function readTestUser(): User
{
$user = User::factory()->create(['created_at' => now()->subYear()]);
$user->refresh();
UserSetting::updateOrCreate(['user_id' => $user->id], ['public_dm' => true]);
return $user;
}
function readTestSend(User $from, User $to, string $text): DmMessage
{
$service = app(DirectMessageService::class);
$sender = Profile::findOrFail($from->profile_id);
return $service->sendMessage(
$service->findOrCreateDm($sender, Profile::findOrFail($to->profile_id)),
$sender,
['body' => $text]
);
}
describe('POST /api/v1.1/direct/thread/read', function () {
it('marks matching messages as read and returns their ids', function () {
$recipient = readTestUser();
$sender = readTestUser();
$one = readTestSend($sender, $recipient, 'one');
$two = readTestSend($sender, $recipient, 'two');
Passport::actingAs($recipient, ['write']);
$response = $this->postJson('/api/v1.1/direct/thread/read', [
'pid' => $sender->profile_id,
'sid' => $one->id,
]);
$response->assertOk();
$returned = collect($response->json())->map(fn ($id) => (int) $id)->all();
expect($returned)->toContain($one->id)->toContain($two->id);
$state = DmConversationParticipant::where('profile_id', $recipient->profile_id)->first();
expect($state->last_read_message_id)->toBe($two->id)
->and($state->unread_count)->toBe(0);
});
it('does not report messages below the given id', function () {
$recipient = readTestUser();
$sender = readTestUser();
$older = readTestSend($sender, $recipient, 'older');
$newer = readTestSend($sender, $recipient, 'newer');
Passport::actingAs($recipient, ['write']);
$returned = collect($this->postJson('/api/v1.1/direct/thread/read', [
'pid' => $sender->profile_id,
'sid' => $newer->id,
])->assertOk()->json())->map(fn ($id) => (int) $id)->all();
expect($returned)->toBe([$newer->id]);
});
it('does not mark another senders messages as read', function () {
$recipient = readTestUser();
$sender = readTestUser();
$other = readTestUser();
$fromSender = readTestSend($sender, $recipient, 'hi');
readTestSend($other, $recipient, 'hey');
Passport::actingAs($recipient, ['write']);
$this->postJson('/api/v1.1/direct/thread/read', [
'pid' => $sender->profile_id,
'sid' => $fromSender->id,
])->assertOk();
$states = DmConversationParticipant::where('profile_id', $recipient->profile_id)->get();
expect($states->firstWhere('last_read_message_id', $fromSender->id))->not->toBeNull()
->and($states->sum('unread_count'))->toBe(1);
});
});