user = User::factory()->create(); Passport::actingAs($this->user); }); test('can list events', function () { Event::factory()->count(3)->create(['user_id' => $this->user->id]); $response = $this->getJson('/api/events'); $response->assertOk() ->assertJsonCount(3, 'data'); }); test('list only returns own events', function () { Event::factory()->count(2)->create(['user_id' => $this->user->id]); Event::factory()->count(3)->create(); // other user $response = $this->getJson('/api/events'); $response->assertOk() ->assertJsonCount(2, 'data'); }); test('can filter events by since parameter', function () { Event::factory()->create([ 'user_id' => $this->user->id, 'updated_at' => now()->subDays(5), ]); Event::factory()->create([ 'user_id' => $this->user->id, 'updated_at' => now()->subHour(), ]); $response = $this->getJson('/api/events?since=' . now()->subDay()->toISOString()); $response->assertOk() ->assertJsonCount(1, 'data'); }); test('can create an event', function () { $clientId = Str::uuid()->toString(); $response = $this->postJson('/api/events', [ 'id' => $clientId, 'title' => 'Mein Event', 'date' => '2024-06-15', 'emotion' => 0.75, 'customColor' => null, 'gradientPreset' => 2, 'image' => null, 'note' => 'Eine Notiz', ]); $response->assertCreated() ->assertJsonPath('data.id', $clientId) ->assertJsonPath('data.title', 'Mein Event') ->assertJsonPath('data.syncStatus', 'synced'); $this->assertDatabaseHas('events', [ 'client_id' => $clientId, 'user_id' => $this->user->id, ]); }); test('create validates required fields', function () { $response = $this->postJson('/api/events', []); $response->assertUnprocessable() ->assertJsonValidationErrors(['id', 'title', 'date', 'emotion']); }); test('can show a single event', function () { $event = Event::factory()->create(['user_id' => $this->user->id]); $response = $this->getJson("/api/events/{$event->client_id}"); $response->assertOk() ->assertJsonPath('data.id', $event->client_id) ->assertJsonPath('data.title', $event->title); }); test('cannot show another users event', function () { $event = Event::factory()->create(); $response = $this->getJson("/api/events/{$event->client_id}"); $response->assertNotFound(); }); test('can update an event', function () { $event = Event::factory()->create(['user_id' => $this->user->id]); $response = $this->putJson("/api/events/{$event->client_id}", [ 'title' => 'Updated Title', 'emotion' => -0.5, ]); $response->assertOk() ->assertJsonPath('data.title', 'Updated Title'); }); test('can delete an event', function () { $event = Event::factory()->create(['user_id' => $this->user->id]); $response = $this->deleteJson("/api/events/{$event->client_id}"); $response->assertNoContent(); $this->assertDatabaseMissing('events', ['id' => $event->id]); }); test('cannot delete another users event', function () { $event = Event::factory()->create(); $response = $this->deleteJson("/api/events/{$event->client_id}"); $response->assertNotFound(); }); test('batch sync creates updates and deletes', function () { $existingEvent = Event::factory()->create(['user_id' => $this->user->id]); $newId = Str::uuid()->toString(); $deleteEvent = Event::factory()->create(['user_id' => $this->user->id]); $response = $this->postJson('/api/events/sync', [ 'mutations' => [ [ 'action' => 'create', 'eventId' => $newId, 'payload' => [ 'title' => 'New via sync', 'date' => '2025-01-01', 'emotion' => 0.3, ], ], [ 'action' => 'update', 'eventId' => $existingEvent->client_id, 'payload' => [ 'title' => 'Updated via sync', ], ], [ 'action' => 'delete', 'eventId' => $deleteEvent->client_id, 'payload' => null, ], ], ]); $response->assertOk() ->assertJsonCount(3, 'results'); $this->assertDatabaseHas('events', ['client_id' => $newId, 'title' => 'New via sync']); $this->assertDatabaseHas('events', ['client_id' => $existingEvent->client_id, 'title' => 'Updated via sync']); $this->assertDatabaseMissing('events', ['client_id' => $deleteEvent->client_id]); }); test('sync is idempotent for creates', function () { $clientId = Str::uuid()->toString(); $this->postJson('/api/events/sync', [ 'mutations' => [[ 'action' => 'create', 'eventId' => $clientId, 'payload' => ['title' => 'First', 'date' => '2025-01-01', 'emotion' => 0], ]], ])->assertOk(); $this->postJson('/api/events/sync', [ 'mutations' => [[ 'action' => 'create', 'eventId' => $clientId, 'payload' => ['title' => 'Duplicate', 'date' => '2025-01-01', 'emotion' => 0], ]], ])->assertOk(); expect(Event::where('client_id', $clientId)->count())->toBe(1); });