From 827abde41b0d14b60f0cbe3d6cc5cda720e41baf Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Wed, 27 May 2026 19:57:12 +0300 Subject: [PATCH 1/2] test element rich text --- backend/tests/Fakes/FakeElementRepository.php | 2 ++ .../tests/Feature/ElementsEndpointTest.php | 4 ++++ backend/tests/Feature/SetsEndpointTest.php | 1 + .../Controllers/ElementControllerTest.php | 9 +++++++++ backend/tests/Unit/Element/ElementTest.php | 6 ++++++ .../Element/UseCases/CreateElementTest.php | 20 ++++++++++++++++++- .../Unit/Element/UseCases/GetElementTest.php | 13 ++++++++++++ frontend/rabbi_gerzi/cypress/e2e/media.cy.ts | 15 ++++++++++++++ 8 files changed, 69 insertions(+), 1 deletion(-) diff --git a/backend/tests/Fakes/FakeElementRepository.php b/backend/tests/Fakes/FakeElementRepository.php index 09acc9d..4cf8bce 100644 --- a/backend/tests/Fakes/FakeElementRepository.php +++ b/backend/tests/Fakes/FakeElementRepository.php @@ -21,6 +21,7 @@ class FakeElementRepository implements ElementRepository id: $id, title: $dto->title, description: $dto->description, + richText: $dto->richText, set: $dto->set, parentElement: $dto->parentElement, ); @@ -97,6 +98,7 @@ class FakeElementRepository implements ElementRepository id: $element->getId(), title: $element->getTitle(), description: $element->getDescription(), + richText: $element->getRichText(), set: $element->getSet(), parentElement: $parentElement, ); diff --git a/backend/tests/Feature/ElementsEndpointTest.php b/backend/tests/Feature/ElementsEndpointTest.php index b4949e4..8f24235 100644 --- a/backend/tests/Feature/ElementsEndpointTest.php +++ b/backend/tests/Feature/ElementsEndpointTest.php @@ -26,18 +26,21 @@ class ElementsEndpointTest extends TestCase set: $set, title: 'Baderech HaAvodah', description: 'A structured path for growth', + richText: '

A structured path for growth

', parentElement: null, )); $firstChildElement = $elementRepository->create(new CreateElementDto( set: $set, title: 'Avodah Foundations', description: 'Foundations for steady avodah', + richText: '

Foundations rich text

', parentElement: $element, )); $secondChildElement = $elementRepository->create(new CreateElementDto( set: $set, title: 'Daily Practice', description: 'Daily practices for growth', + richText: '

Daily practice rich text

', parentElement: $element, )); @@ -61,6 +64,7 @@ class ElementsEndpointTest extends TestCase 'id' => $element->getId(), 'title' => 'Baderech HaAvodah', 'description' => 'A structured path for growth', + 'richText' => '

A structured path for growth

', ], ]); } diff --git a/backend/tests/Feature/SetsEndpointTest.php b/backend/tests/Feature/SetsEndpointTest.php index a1c3ce9..32aabd2 100644 --- a/backend/tests/Feature/SetsEndpointTest.php +++ b/backend/tests/Feature/SetsEndpointTest.php @@ -32,6 +32,7 @@ class SetsEndpointTest extends TestCase set: $baderechSet, title: $baderechSet->getName(), description: $baderechSet->getDescription(), + richText: '', parentElement: null, ) ); diff --git a/backend/tests/Unit/Controllers/ElementControllerTest.php b/backend/tests/Unit/Controllers/ElementControllerTest.php index 0d6e0f2..569835e 100644 --- a/backend/tests/Unit/Controllers/ElementControllerTest.php +++ b/backend/tests/Unit/Controllers/ElementControllerTest.php @@ -30,18 +30,21 @@ class ElementControllerTest extends TestCase $set, 'Baderech HaAvodah', 'A structured path for growth', + '

A structured path for growth

', null, ); $firstChildElement = $this->createElement( $set, 'Avodah Foundations', 'Foundations for steady avodah', + '

Foundations rich text

', $element, ); $secondChildElement = $this->createElement( $set, 'Daily Practice', 'Daily practices for growth', + '

Daily practice rich text

', $element, ); @@ -55,6 +58,10 @@ class ElementControllerTest extends TestCase 'A structured path for growth', $body['element']['description'], ); + $this->assertSame( + '

A structured path for growth

', + $body['element']['richText'], + ); $this->assertSame([ [ 'id' => $firstChildElement->getId(), @@ -105,12 +112,14 @@ class ElementControllerTest extends TestCase DomainSet $set, string $title, string $description, + string $richText, ?Element $parentElement, ): Element { return $this->elementRepo->create(new CreateElementDto( set: $set, title: $title, description: $description, + richText: $richText, parentElement: $parentElement, )); } diff --git a/backend/tests/Unit/Element/ElementTest.php b/backend/tests/Unit/Element/ElementTest.php index 3a0cdce..8c09251 100644 --- a/backend/tests/Unit/Element/ElementTest.php +++ b/backend/tests/Unit/Element/ElementTest.php @@ -20,6 +20,7 @@ class ElementTest extends TestCase id: 1, title: 'Root', description: 'Root description', + richText: '

Root rich text

', set: $set, parentElement: null, ); @@ -27,6 +28,7 @@ class ElementTest extends TestCase id: 2, title: 'Child', description: 'Child description', + richText: '

Child rich text

', set: $set, parentElement: $rootElement, ); @@ -37,6 +39,10 @@ class ElementTest extends TestCase 'Child description', $childElement->getDescription(), ); + $this->assertSame( + '

Child rich text

', + $childElement->getRichText(), + ); $this->assertSame($set, $childElement->getSet()); $this->assertSame($rootElement, $childElement->getParentElement()); $this->assertNull($rootElement->getParentElement()); diff --git a/backend/tests/Unit/Element/UseCases/CreateElementTest.php b/backend/tests/Unit/Element/UseCases/CreateElementTest.php index cef6aa4..55458eb 100644 --- a/backend/tests/Unit/Element/UseCases/CreateElementTest.php +++ b/backend/tests/Unit/Element/UseCases/CreateElementTest.php @@ -48,12 +48,14 @@ class CreateElementTest extends TestCase setId: $set->getId(), title: 'Root', description: 'Root description', + richText: '

Root rich text

', parentElementId: null, )); $this->assertInstanceOf(Element::class, $element); $this->assertSame('Root', $element->getTitle()); $this->assertSame('Root description', $element->getDescription()); + $this->assertSame('

Root rich text

', $element->getRichText()); $this->assertSame($set->getId(), $element->getSet()->getId()); $this->assertNull($element->getParentElement()); } @@ -66,6 +68,7 @@ class CreateElementTest extends TestCase setId: $set->getId(), title: 'Root', description: 'Root description', + richText: '

Root rich text

', parentElementId: null, ) ); @@ -75,6 +78,7 @@ class CreateElementTest extends TestCase setId: $set->getId(), title: 'Child', description: 'Child description', + richText: '

Child rich text

', parentElementId: $rootElement->getId(), ) ); @@ -84,13 +88,17 @@ class CreateElementTest extends TestCase 'Child description', $childElement->getDescription(), ); + $this->assertSame( + '

Child rich text

', + $childElement->getRichText(), + ); $this->assertSame( $rootElement->getId(), $childElement->getParentElement()->getId(), ); } - public function testCreatesElementWithBlankDescriptionWhenMissing(): void + public function testCreatesElementWithBlankContentWhenMissing(): void { $set = $this->createSet('Daily learning'); @@ -98,10 +106,12 @@ class CreateElementTest extends TestCase setId: $set->getId(), title: 'Root', description: null, + richText: null, parentElementId: null, )); $this->assertSame('', $element->getDescription()); + $this->assertSame('', $element->getRichText()); } public function testThrowsWhenSetIdMissing(): void @@ -113,6 +123,7 @@ class CreateElementTest extends TestCase setId: null, title: 'Root', description: 'Root description', + richText: '

Root rich text

', parentElementId: null, )); } @@ -126,6 +137,7 @@ class CreateElementTest extends TestCase setId: 1, title: null, description: 'Root description', + richText: '

Root rich text

', parentElementId: null, )); } @@ -139,6 +151,7 @@ class CreateElementTest extends TestCase setId: 99, title: 'Root', description: 'Root description', + richText: '

Root rich text

', parentElementId: null, )); } @@ -156,6 +169,7 @@ class CreateElementTest extends TestCase setId: $set->getId(), title: 'Child', description: 'Child description', + richText: '

Child rich text

', parentElementId: 99, )); } @@ -167,6 +181,7 @@ class CreateElementTest extends TestCase setId: $set->getId(), title: 'Root', description: 'Root description', + richText: '

Root rich text

', parentElementId: null, )); @@ -179,6 +194,7 @@ class CreateElementTest extends TestCase setId: $set->getId(), title: 'Another root', description: 'Another root description', + richText: '

Another root rich text

', parentElementId: null, )); } @@ -192,6 +208,7 @@ class CreateElementTest extends TestCase setId: $parentSet->getId(), title: 'Parent root', description: 'Parent root description', + richText: '

Parent root rich text

', parentElementId: null, ) ); @@ -205,6 +222,7 @@ class CreateElementTest extends TestCase setId: $childSet->getId(), title: 'Invalid child', description: 'Invalid child description', + richText: '

Invalid child rich text

', parentElementId: $parentElement->getId(), )); } diff --git a/backend/tests/Unit/Element/UseCases/GetElementTest.php b/backend/tests/Unit/Element/UseCases/GetElementTest.php index 9e398f4..71c67a0 100644 --- a/backend/tests/Unit/Element/UseCases/GetElementTest.php +++ b/backend/tests/Unit/Element/UseCases/GetElementTest.php @@ -31,6 +31,7 @@ class GetElementTest extends TestCase $set, 'Baderech HaAvodah', 'A structured path for growth', + '

A structured path for growth

', null, ); @@ -46,6 +47,10 @@ class GetElementTest extends TestCase 'A structured path for growth', $foundElement->getDescription(), ); + $this->assertSame( + '

A structured path for growth

', + $foundElement->getRichText(), + ); } public function testReturnsDirectChildElements(): void @@ -55,24 +60,28 @@ class GetElementTest extends TestCase $set, 'Baderech HaAvodah', 'A structured path for growth', + '

A structured path for growth

', null, ); $firstChildElement = $this->createElement( $set, 'Avodah Foundations', 'Foundations for steady avodah', + '

Foundations rich text

', $parentElement, ); $secondChildElement = $this->createElement( $set, 'Daily Practice', 'Daily practices for growth', + '

Daily practice rich text

', $parentElement, ); $this->createElement( $set, 'Nested Practice', 'Nested description', + '

Nested rich text

', $firstChildElement, ); $otherSet = $this->createSet(2, 'Daily Learning'); @@ -80,12 +89,14 @@ class GetElementTest extends TestCase $otherSet, 'Other Parent', 'Other parent description', + '

Other parent rich text

', null, ); $this->createElement( $otherSet, 'Other Child', 'Other child description', + '

Other child rich text

', $otherParentElement, ); @@ -145,12 +156,14 @@ class GetElementTest extends TestCase DomainSet $set, string $title, string $description, + string $richText, ?Element $parentElement, ): Element { return $this->elementRepo->create(new CreateElementDto( set: $set, title: $title, description: $description, + richText: $richText, parentElement: $parentElement, )); } diff --git a/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts b/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts index 832233d..3816baf 100644 --- a/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts +++ b/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts @@ -41,7 +41,17 @@ describe('media page sets', () => { cy.location('pathname').should('eq', '/element/1') cy.get('[data-cy="element-page"]').should('be.visible') cy.contains('h1', 'Baderech HaAvodah').should('be.visible') + cy.get('[data-cy="element-rich-text"]').within(() => { + cy.contains('Begin with a clear map for avodah growth.') + .should('be.visible') + cy.contains('strong', 'Move steadily').should('be.visible') + }) cy.get('[data-cy="child-element-list"]').should('be.visible') + cy.get('[data-cy="child-element-list"]') + .should( + 'not.contain.text', + 'Foundations rich text belongs on its own page.', + ) cy.contains('[data-cy="child-element-link"]', 'Avodah Foundations') .as('avodahFoundationsLink') .should('have.attr', 'href', '/element/2') @@ -63,5 +73,10 @@ describe('media page sets', () => { .click() cy.location('pathname').should('eq', '/element/2') cy.contains('h1', 'Avodah Foundations').should('be.visible') + cy.get('[data-cy="element-rich-text"]') + .should( + 'contain.text', + 'Foundations rich text belongs on its own page.', + ) }) }) From 457dbbb7de9aaead5c8280166cb83554f1b0074c Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Wed, 27 May 2026 20:02:31 +0300 Subject: [PATCH 2/2] add element rich text --- backend/app/Controllers/ElementController.php | 1 + backend/app/Element/CreateElementDto.php | 1 + backend/app/Element/Element.php | 6 ++++ backend/app/Element/ElementModel.php | 3 ++ .../app/Element/EloquentElementRepository.php | 3 ++ .../UseCases/CreateElement/CreateElement.php | 3 ++ .../CreateElement/CreateElementRequest.php | 1 + .../2026_05_24_000001_elements_table.php | 1 + backend/database/seeders/ElementSeeder.php | 7 +++++ frontend/rabbi_gerzi/cypress/e2e/media.cy.ts | 4 +-- frontend/rabbi_gerzi/src/stores/elements.ts | 10 +++++-- .../rabbi_gerzi/src/views/ElementPage.vue | 28 +++++++++++++++++++ 12 files changed, 63 insertions(+), 5 deletions(-) diff --git a/backend/app/Controllers/ElementController.php b/backend/app/Controllers/ElementController.php index 0e71cea..4942d19 100644 --- a/backend/app/Controllers/ElementController.php +++ b/backend/app/Controllers/ElementController.php @@ -46,6 +46,7 @@ class ElementController 'id' => $element->getId(), 'title' => $element->getTitle(), 'description' => $element->getDescription(), + 'richText' => $element->getRichText(), ], ], 200); } diff --git a/backend/app/Element/CreateElementDto.php b/backend/app/Element/CreateElementDto.php index 3bad829..1e48b41 100644 --- a/backend/app/Element/CreateElementDto.php +++ b/backend/app/Element/CreateElementDto.php @@ -10,6 +10,7 @@ class CreateElementDto public Set $set, public string $title, public string $description, + public string $richText, public ?Element $parentElement, ) { } diff --git a/backend/app/Element/Element.php b/backend/app/Element/Element.php index 7f007ce..2c9395a 100644 --- a/backend/app/Element/Element.php +++ b/backend/app/Element/Element.php @@ -10,6 +10,7 @@ class Element private int $id, private string $title, private string $description, + private string $richText, private Set $set, private ?Element $parentElement, ) { @@ -30,6 +31,11 @@ class Element return $this->description; } + public function getRichText(): string + { + return $this->richText; + } + public function getSet(): Set { return $this->set; diff --git a/backend/app/Element/ElementModel.php b/backend/app/Element/ElementModel.php index 4f79f3b..a1ffa17 100644 --- a/backend/app/Element/ElementModel.php +++ b/backend/app/Element/ElementModel.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Model; * @property int $set_id * @property string $title * @property string $description + * @property string $rich_text * @property int|null $parent_element_id * * @method static Builder|ElementModel newModelQuery() @@ -20,6 +21,7 @@ use Illuminate\Database\Eloquent\Model; * @method static Builder|ElementModel whereSetId($value) * @method static Builder|ElementModel whereTitle($value) * @method static Builder|ElementModel whereDescription($value) + * @method static Builder|ElementModel whereRichText($value) * * @mixin \Eloquent */ @@ -33,6 +35,7 @@ class ElementModel extends Model 'set_id', 'title', 'description', + 'rich_text', 'parent_element_id', ]; diff --git a/backend/app/Element/EloquentElementRepository.php b/backend/app/Element/EloquentElementRepository.php index 7b7065a..455852c 100644 --- a/backend/app/Element/EloquentElementRepository.php +++ b/backend/app/Element/EloquentElementRepository.php @@ -18,6 +18,7 @@ class EloquentElementRepository implements ElementRepository 'set_id' => $dto->set->getId(), 'title' => $dto->title, 'description' => $dto->description, + 'rich_text' => $dto->richText, 'parent_element_id' => $dto->parentElement?->getId(), ]); @@ -25,6 +26,7 @@ class EloquentElementRepository implements ElementRepository id: $model->id, title: $dto->title, description: $dto->description, + richText: $dto->richText, set: $dto->set, parentElement: $dto->parentElement, ); @@ -105,6 +107,7 @@ class EloquentElementRepository implements ElementRepository id: $model->id, title: $model->title, description: $model->description, + richText: $model->rich_text, set: $set, parentElement: $parentElement, ); diff --git a/backend/app/Element/UseCases/CreateElement/CreateElement.php b/backend/app/Element/UseCases/CreateElement/CreateElement.php index 1cb4b37..47d5684 100644 --- a/backend/app/Element/UseCases/CreateElement/CreateElement.php +++ b/backend/app/Element/UseCases/CreateElement/CreateElement.php @@ -31,6 +31,7 @@ class CreateElement throw new BadRequestException('title is required'); } $description = $request->description ?? ''; + $richText = $request->richText ?? ''; $set = $this->setRepo->find($request->setId); if ($set === null) { @@ -46,6 +47,7 @@ class CreateElement set: $set, title: $request->title, description: $description, + richText: $richText, parentElement: null, )); } @@ -68,6 +70,7 @@ class CreateElement set: $set, title: $request->title, description: $description, + richText: $richText, parentElement: $parentElement, )); } diff --git a/backend/app/Element/UseCases/CreateElement/CreateElementRequest.php b/backend/app/Element/UseCases/CreateElement/CreateElementRequest.php index b028326..908a4d6 100644 --- a/backend/app/Element/UseCases/CreateElement/CreateElementRequest.php +++ b/backend/app/Element/UseCases/CreateElement/CreateElementRequest.php @@ -8,6 +8,7 @@ class CreateElementRequest public ?int $setId, public ?string $title, public ?string $description, + public ?string $richText, public ?int $parentElementId, ) { } diff --git a/backend/database/migrations/2026_05_24_000001_elements_table.php b/backend/database/migrations/2026_05_24_000001_elements_table.php index f09b3b0..0f96d3a 100644 --- a/backend/database/migrations/2026_05_24_000001_elements_table.php +++ b/backend/database/migrations/2026_05_24_000001_elements_table.php @@ -13,6 +13,7 @@ return new class extends Migration $table->foreignId('set_id')->constrained('sets'); $table->string('title'); $table->text('description')->default(''); + $table->text('rich_text')->default(''); $table->foreignId('parent_element_id') ->nullable() ->constrained('elements'); diff --git a/backend/database/seeders/ElementSeeder.php b/backend/database/seeders/ElementSeeder.php index b356df9..02d2467 100644 --- a/backend/database/seeders/ElementSeeder.php +++ b/backend/database/seeders/ElementSeeder.php @@ -18,6 +18,9 @@ class ElementSeeder extends Seeder set: $baderechSet, title: $baderechSet->getName(), description: $baderechSet->getDescription(), + richText: '

Begin with a clear map for avodah growth.

' + . '

Move steadily from awareness ' + . 'to practice.

', parentElement: null, )); $elementRepository->create(new CreateElementDto( @@ -25,12 +28,16 @@ class ElementSeeder extends Seeder title: 'Avodah Foundations', description: 'Core foundations for building a steady ' . 'avodah practice.', + richText: '

Avodah foundations begin with honest awareness ' + . 'and small repeatable steps.

', parentElement: $rootElement, )); $elementRepository->create(new CreateElementDto( set: $baderechSet, title: 'Daily Practice', description: 'Practical steps for consistent daily growth.', + richText: '

Daily practice turns inspiration into a ' + . 'dependable rhythm.

', parentElement: $rootElement, )); } diff --git a/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts b/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts index 3816baf..4dda0e4 100644 --- a/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts +++ b/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts @@ -50,7 +50,7 @@ describe('media page sets', () => { cy.get('[data-cy="child-element-list"]') .should( 'not.contain.text', - 'Foundations rich text belongs on its own page.', + 'Avodah foundations begin with honest awareness', ) cy.contains('[data-cy="child-element-link"]', 'Avodah Foundations') .as('avodahFoundationsLink') @@ -76,7 +76,7 @@ describe('media page sets', () => { cy.get('[data-cy="element-rich-text"]') .should( 'contain.text', - 'Foundations rich text belongs on its own page.', + 'Avodah foundations begin with honest awareness', ) }) }) diff --git a/frontend/rabbi_gerzi/src/stores/elements.ts b/frontend/rabbi_gerzi/src/stores/elements.ts index b7ae058..6c5f1f4 100644 --- a/frontend/rabbi_gerzi/src/stores/elements.ts +++ b/frontend/rabbi_gerzi/src/stores/elements.ts @@ -1,22 +1,26 @@ import { ref } from 'vue' import { defineStore } from 'pinia' -export interface Element { +export interface ChildElement { id: number title: string description: string } +export interface Element extends ChildElement { + richText: string +} + interface ElementResponse { element: Element - childElements: Element[] + childElements: ChildElement[] } const API_BASE_URL = import.meta.env.VITE_API_BASE_URL as string export const useElementsStore = defineStore('elements', () => { const element = ref(null) - const childElements = ref([]) + const childElements = ref([]) const isLoading = ref(false) const error = ref(null) diff --git a/frontend/rabbi_gerzi/src/views/ElementPage.vue b/frontend/rabbi_gerzi/src/views/ElementPage.vue index fd8a5fa..1956a22 100644 --- a/frontend/rabbi_gerzi/src/views/ElementPage.vue +++ b/frontend/rabbi_gerzi/src/views/ElementPage.vue @@ -49,6 +49,13 @@ watch( {{ element.title }} +
+