From e0e2f255ac664b71336169b970fc1f8235e6f9ea Mon Sep 17 00:00:00 2001 From: myrmidex Date: Sat, 27 Jun 2026 08:30:32 +0200 Subject: [PATCH] =?UTF-8?q?58=20-=20Pin=20scenario=20create-from-UI=20cont?= =?UTF-8?q?ract=20with=20create=E2=86=92show=20round-trip=20and=20optional?= =?UTF-8?q?=20description?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/Functional/ScenarioApiTest.php | 97 ++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/tests/Functional/ScenarioApiTest.php b/tests/Functional/ScenarioApiTest.php index d0f58d2..8c61371 100644 --- a/tests/Functional/ScenarioApiTest.php +++ b/tests/Functional/ScenarioApiTest.php @@ -212,6 +212,103 @@ final class ScenarioApiTest extends WebTestCase ); } + public function testPostThenGetOnReturnedIriRoundTripsForTheOwner(): void + { + $this->login(); + + $this->client->request( + 'POST', + '/api/scenarios', + server: [ + 'CONTENT_TYPE' => 'application/ld+json', + 'HTTP_ACCEPT' => 'application/ld+json', + ], + content: json_encode(['name' => 'New Scenario From UI']), + ); + + $created = json_decode((string) $this->client->getResponse()->getContent(), true); + + self::assertIsArray($created, 'The created resource response must be a JSON-LD object.'); + self::assertArrayHasKey( + '@id', + $created, + 'POST must return the created scenario IRI so the SPA can redirect to its show page.', + ); + + $iri = $created['@id']; + + $this->client->request('GET', $iri, server: [ + 'HTTP_ACCEPT' => 'application/ld+json', + ]); + + $response = $this->client->getResponse(); + + self::assertSame( + 200, + $response->getStatusCode(), + 'A GET on the just-created IRI by the same owner must return 200 — the create->redirect->show flow must never land on an owner-scope 404.', + ); + + $body = json_decode((string) $response->getContent(), true); + + self::assertIsArray($body, 'The item response must be a JSON-LD object.'); + self::assertSame( + $iri, + $body['@id'] ?? null, + 'The show page must resolve the same IRI the create response returned.', + ); + self::assertSame('New Scenario From UI', $body['name'] ?? null); + } + + public function testPostWithDescriptionPersistsAndEchoesIt(): void + { + $this->login(); + + $this->client->request( + 'POST', + '/api/scenarios', + server: [ + 'CONTENT_TYPE' => 'application/ld+json', + 'HTTP_ACCEPT' => 'application/ld+json', + ], + content: json_encode([ + 'name' => 'Documented Fund', + 'description' => 'Money set aside for the kitchen renovation.', + ]), + ); + + $response = $this->client->getResponse(); + + self::assertSame( + 201, + $response->getStatusCode(), + 'POST /api/scenarios with name + optional description must return 201 Created.', + ); + + $body = json_decode((string) $response->getContent(), true); + + self::assertIsArray($body, 'The created resource response must be a JSON-LD object.'); + self::assertSame( + 'Money set aside for the kitchen renovation.', + $body['description'] ?? null, + 'The create response must echo the supplied optional description back to the SPA.', + ); + + $this->em->clear(); + + $persisted = $this->em->getRepository(Scenario::class)->findOneBy(['name' => 'Documented Fund']); + + self::assertNotNull( + $persisted, + 'A successful POST with a description must persist the new Scenario.', + ); + self::assertSame( + 'Money set aside for the kitchen renovation.', + $persisted->getDescription(), + 'The optional description must survive persistence.', + ); + } + public function testPostWithMissingNameIsRejectedAsUnprocessable(): void { $this->login();