userRepo = new FakeUserRepository(); $this->planRepo = new FakePlanRepository(); $this->scheduledNodeRepo = new FakeScheduledNodeRepository(); $this->user = $this->userRepo->create(new CreateUserDto( email: new EmailAddress('test@test.com'), passwordHash: '', isAdmin: false, )); $this->getTodaysSchedule = new GetTodaysSchedule( userRepo: $this->userRepo, scheduledNodeRepo: $this->scheduledNodeRepo, ); $this->controller = new ScheduledNodeController(); } private function makeRequest( ?string $date, ?User $user, ): ServerRequestInterface { $request = new ServerRequestFactory() ->createServerRequest( 'GET', 'http://localhost/api/scheduled-nodes' ); if ($user !== null) { $request = $request->withAttribute('user', $user); } if ($date !== null) { $request = $request->withQueryParams(['date' => $date]); } return $request; } private function seedScheduledNode( User $user, string $date, string $planName, string $nodeTitle, ): void { $plan = $this->planRepo->create(new CreatePlanDto( name: $planName, user: $user, )); $this->scheduledNodeRepo->create(new CreateScheduledNodeDto( date: new DateTimeImmutable($date), plan: $plan, node: new Node( id: 0, title: $nodeTitle, text: new Text(id: 0, name: 'test text', user: $user), parentNode: null, ), )); } public function test_returns_200_with_scheduled_nodes_for_user(): void { $this->seedScheduledNode( $this->user, '2025-01-02', 'My reading plan', 'Bereishis', ); $response = $this->controller->getScheduledNodes( $this->makeRequest('2025-01-02', $this->user), new Response(), $this->getTodaysSchedule, ); $this->assertEquals(200, $response->getStatusCode()); $body = json_decode((string) $response->getBody(), true); $this->assertIsArray($body); $this->assertCount(1, $body); } public function test_response_has_expected_fields(): void { $this->seedScheduledNode( $this->user, '2025-01-02', 'My reading plan', 'Bereishis', ); $response = $this->controller->getScheduledNodes( $this->makeRequest('2025-01-02', $this->user), new Response(), $this->getTodaysSchedule, ); $body = json_decode((string) $response->getBody(), true); $this->assertArrayHasKey('id', $body[0]); $this->assertArrayHasKey('date', $body[0]); $this->assertEquals('2025-01-02', $body[0]['date']); $this->assertEquals('My reading plan', $body[0]['planName']); $this->assertEquals('Bereishis', $body[0]['nodeTitle']); $this->assertEquals(false, $body[0]['completed']); } public function test_returns_401_when_no_user_attribute(): void { $response = $this->controller->getScheduledNodes( $this->makeRequest('2025-01-02', null), new Response(), $this->getTodaysSchedule, ); $this->assertEquals(401, $response->getStatusCode()); } public function test_returns_400_when_date_query_param_missing(): void { $response = $this->controller->getScheduledNodes( $this->makeRequest(null, $this->user), new Response(), $this->getTodaysSchedule, ); $this->assertEquals(400, $response->getStatusCode()); $body = json_decode((string) $response->getBody(), true); $this->assertArrayHasKey('error', $body); $this->assertEquals('date is required', $body['error']); } public function test_returns_400_when_date_query_param_empty_string(): void { $response = $this->controller->getScheduledNodes( $this->makeRequest('', $this->user), new Response(), $this->getTodaysSchedule, ); $this->assertEquals(400, $response->getStatusCode()); $body = json_decode((string) $response->getBody(), true); $this->assertArrayHasKey('error', $body); $this->assertEquals('date is required', $body['error']); } public function test_excludes_future_scheduled_nodes(): void { $this->seedScheduledNode( $this->user, '2025-01-10', 'My reading plan', 'Bereishis', ); $response = $this->controller->getScheduledNodes( $this->makeRequest('2025-01-02', $this->user), new Response(), $this->getTodaysSchedule, ); $body = json_decode((string) $response->getBody(), true); $this->assertCount(0, $body); } public function test_excludes_completed_scheduled_nodes(): void { $this->seedScheduledNode( $this->user, '2025-01-02', 'My reading plan', 'Bereishis', ); $stored = $this->scheduledNodeRepo->find(0); $stored->setCompleted(true); $this->scheduledNodeRepo->update($stored); $response = $this->controller->getScheduledNodes( $this->makeRequest('2025-01-02', $this->user), new Response(), $this->getTodaysSchedule, ); $body = json_decode((string) $response->getBody(), true); $this->assertCount(0, $body); } public function test_returns_empty_array_when_user_has_no_nodes(): void { $response = $this->controller->getScheduledNodes( $this->makeRequest('2025-01-02', $this->user), new Response(), $this->getTodaysSchedule, ); $this->assertEquals(200, $response->getStatusCode()); $body = json_decode((string) $response->getBody(), true); $this->assertEquals([], $body); } public function test_returns_404_when_use_case_throws_domain_exception(): void { $unknownUser = new User( id: 999, email: new EmailAddress('ghost@test.com'), passwordHash: '', isAdmin: false, ); $response = $this->controller->getScheduledNodes( $this->makeRequest('2025-01-02', $unknownUser), new Response(), $this->getTodaysSchedule, ); $this->assertEquals(404, $response->getStatusCode()); $body = json_decode((string) $response->getBody(), true); $this->assertArrayHasKey('error', $body); $this->assertEquals( 'User with id: 999 doesnt exist', $body['error'] ); } }