optimizations
This commit is contained in:
@@ -13,6 +13,7 @@ use App\Events\ConversationUpdated;
|
||||
use App\Events\MessageCreated;
|
||||
use App\Events\MessageRead;
|
||||
use App\Services\Messaging\MessagingPresenceService;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -177,6 +178,80 @@ test('sending a message dispatches realtime events and preserves client temp id'
|
||||
Event::assertDispatched(ConversationUpdated::class);
|
||||
});
|
||||
|
||||
test('retrying a send with the same client temp id reuses the existing message', function () {
|
||||
Event::fake([MessageCreated::class]);
|
||||
|
||||
$userA = makeMessagingUser();
|
||||
$userB = makeMessagingUser();
|
||||
$conv = makeDirectConversation($userA, $userB);
|
||||
|
||||
$first = $this->actingAs($userA)->postJson("/api/messages/{$conv->id}", [
|
||||
'body' => 'Retry safe hello',
|
||||
'client_temp_id' => 'tmp_retry_safe_001',
|
||||
]);
|
||||
|
||||
$second = $this->actingAs($userA)->postJson("/api/messages/{$conv->id}", [
|
||||
'body' => 'Retry safe hello',
|
||||
'client_temp_id' => 'tmp_retry_safe_001',
|
||||
]);
|
||||
|
||||
$first->assertStatus(201);
|
||||
$second->assertStatus(201);
|
||||
|
||||
expect(Message::query()->count())->toBe(1)
|
||||
->and($second->json('id'))->toBe($first->json('id'))
|
||||
->and($second->json('uuid'))->toBe($first->json('uuid'))
|
||||
->and($second->json('client_temp_id'))->toBe('tmp_retry_safe_001');
|
||||
|
||||
Event::assertDispatchedTimes(MessageCreated::class, 1);
|
||||
});
|
||||
|
||||
test('client temp id dedupe is scoped to sender', function () {
|
||||
Event::fake([MessageCreated::class]);
|
||||
|
||||
$userA = makeMessagingUser();
|
||||
$userB = makeMessagingUser();
|
||||
$conv = makeDirectConversation($userA, $userB);
|
||||
|
||||
$first = $this->actingAs($userA)->postJson("/api/messages/{$conv->id}", [
|
||||
'body' => 'Sender A',
|
||||
'client_temp_id' => 'tmp_sender_scope_001',
|
||||
]);
|
||||
|
||||
$second = $this->actingAs($userB)->postJson("/api/messages/{$conv->id}", [
|
||||
'body' => 'Sender B',
|
||||
'client_temp_id' => 'tmp_sender_scope_001',
|
||||
]);
|
||||
|
||||
$first->assertStatus(201);
|
||||
$second->assertStatus(201);
|
||||
|
||||
expect(Message::query()->count())->toBe(2)
|
||||
->and($second->json('id'))->not->toBe($first->json('id'));
|
||||
|
||||
Event::assertDispatchedTimes(MessageCreated::class, 2);
|
||||
});
|
||||
|
||||
test('database enforces sender scoped client temp id uniqueness', function () {
|
||||
$userA = makeMessagingUser();
|
||||
$userB = makeMessagingUser();
|
||||
$conv = makeDirectConversation($userA, $userB);
|
||||
|
||||
Message::create([
|
||||
'conversation_id' => $conv->id,
|
||||
'sender_id' => $userA->id,
|
||||
'body' => 'Stored once',
|
||||
'client_temp_id' => 'tmp_db_guard_001',
|
||||
]);
|
||||
|
||||
expect(fn () => Message::create([
|
||||
'conversation_id' => $conv->id,
|
||||
'sender_id' => $userA->id,
|
||||
'body' => 'Stored twice',
|
||||
'client_temp_id' => 'tmp_db_guard_001',
|
||||
]))->toThrow(QueryException::class);
|
||||
});
|
||||
|
||||
test('non participant cannot send a message', function () {
|
||||
$userA = makeMessagingUser();
|
||||
$userB = makeMessagingUser();
|
||||
@@ -338,6 +413,9 @@ test('delta endpoint returns only messages after requested id in ascending order
|
||||
$response = $this->actingAs($userA)->getJson("/api/messages/{$conv->id}/delta?after_message_id={$first->id}");
|
||||
|
||||
$response->assertStatus(200)
|
||||
->assertJsonPath('conversation.id', $conv->id)
|
||||
->assertJsonPath('conversation.latest_message.id', $third->id)
|
||||
->assertJsonPath('summary.unread_total', 2)
|
||||
->assertJsonPath('data.0.id', $second->id)
|
||||
->assertJsonPath('data.1.id', $third->id);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user