From 6c6b3ad257efe2c377b16c3cca10644118384eff Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Wed, 27 May 2026 20:15:51 +0300 Subject: [PATCH 1/3] test element pdf path --- .../tests/Feature/ElementsEndpointTest.php | 4 +++ .../Controllers/ElementControllerTest.php | 9 +++++ backend/tests/Unit/Element/ElementTest.php | 7 ++++ .../Element/UseCases/CreateElementTest.php | 34 +++++++++++++++++++ .../Unit/Element/UseCases/GetElementTest.php | 13 +++++++ frontend/rabbi_gerzi/cypress/e2e/media.cy.ts | 5 +++ 6 files changed, 72 insertions(+) diff --git a/backend/tests/Feature/ElementsEndpointTest.php b/backend/tests/Feature/ElementsEndpointTest.php index 8f24235..a24a6c8 100644 --- a/backend/tests/Feature/ElementsEndpointTest.php +++ b/backend/tests/Feature/ElementsEndpointTest.php @@ -27,6 +27,7 @@ class ElementsEndpointTest extends TestCase title: 'Baderech HaAvodah', description: 'A structured path for growth', richText: '

A structured path for growth

', + pdfPath: '/assets/pdfs/baderech.pdf', parentElement: null, )); $firstChildElement = $elementRepository->create(new CreateElementDto( @@ -34,6 +35,7 @@ class ElementsEndpointTest extends TestCase title: 'Avodah Foundations', description: 'Foundations for steady avodah', richText: '

Foundations rich text

', + pdfPath: '/assets/pdfs/foundations.pdf', parentElement: $element, )); $secondChildElement = $elementRepository->create(new CreateElementDto( @@ -41,6 +43,7 @@ class ElementsEndpointTest extends TestCase title: 'Daily Practice', description: 'Daily practices for growth', richText: '

Daily practice rich text

', + pdfPath: null, parentElement: $element, )); @@ -65,6 +68,7 @@ class ElementsEndpointTest extends TestCase 'title' => 'Baderech HaAvodah', 'description' => 'A structured path for growth', 'richText' => '

A structured path for growth

', + 'pdfPath' => '/assets/pdfs/baderech.pdf', ], ]); } diff --git a/backend/tests/Unit/Controllers/ElementControllerTest.php b/backend/tests/Unit/Controllers/ElementControllerTest.php index 569835e..d9ffe2f 100644 --- a/backend/tests/Unit/Controllers/ElementControllerTest.php +++ b/backend/tests/Unit/Controllers/ElementControllerTest.php @@ -31,6 +31,7 @@ class ElementControllerTest extends TestCase 'Baderech HaAvodah', 'A structured path for growth', '

A structured path for growth

', + '/assets/pdfs/baderech.pdf', null, ); $firstChildElement = $this->createElement( @@ -38,6 +39,7 @@ class ElementControllerTest extends TestCase 'Avodah Foundations', 'Foundations for steady avodah', '

Foundations rich text

', + '/assets/pdfs/foundations.pdf', $element, ); $secondChildElement = $this->createElement( @@ -45,6 +47,7 @@ class ElementControllerTest extends TestCase 'Daily Practice', 'Daily practices for growth', '

Daily practice rich text

', + null, $element, ); @@ -62,6 +65,10 @@ class ElementControllerTest extends TestCase '

A structured path for growth

', $body['element']['richText'], ); + $this->assertSame( + '/assets/pdfs/baderech.pdf', + $body['element']['pdfPath'], + ); $this->assertSame([ [ 'id' => $firstChildElement->getId(), @@ -113,6 +120,7 @@ class ElementControllerTest extends TestCase string $title, string $description, string $richText, + ?string $pdfPath, ?Element $parentElement, ): Element { return $this->elementRepo->create(new CreateElementDto( @@ -120,6 +128,7 @@ class ElementControllerTest extends TestCase title: $title, description: $description, richText: $richText, + pdfPath: $pdfPath, parentElement: $parentElement, )); } diff --git a/backend/tests/Unit/Element/ElementTest.php b/backend/tests/Unit/Element/ElementTest.php index 8c09251..7808344 100644 --- a/backend/tests/Unit/Element/ElementTest.php +++ b/backend/tests/Unit/Element/ElementTest.php @@ -21,6 +21,7 @@ class ElementTest extends TestCase title: 'Root', description: 'Root description', richText: '

Root rich text

', + pdfPath: null, set: $set, parentElement: null, ); @@ -29,6 +30,7 @@ class ElementTest extends TestCase title: 'Child', description: 'Child description', richText: '

Child rich text

', + pdfPath: '/assets/pdfs/child.pdf', set: $set, parentElement: $rootElement, ); @@ -43,8 +45,13 @@ class ElementTest extends TestCase '

Child rich text

', $childElement->getRichText(), ); + $this->assertSame( + '/assets/pdfs/child.pdf', + $childElement->getPdfPath(), + ); $this->assertSame($set, $childElement->getSet()); $this->assertSame($rootElement, $childElement->getParentElement()); + $this->assertNull($rootElement->getPdfPath()); $this->assertNull($rootElement->getParentElement()); } } diff --git a/backend/tests/Unit/Element/UseCases/CreateElementTest.php b/backend/tests/Unit/Element/UseCases/CreateElementTest.php index 55458eb..2b34873 100644 --- a/backend/tests/Unit/Element/UseCases/CreateElementTest.php +++ b/backend/tests/Unit/Element/UseCases/CreateElementTest.php @@ -49,6 +49,7 @@ class CreateElementTest extends TestCase title: 'Root', description: 'Root description', richText: '

Root rich text

', + pdfPath: '/assets/pdfs/root.pdf', parentElementId: null, )); @@ -56,6 +57,7 @@ class CreateElementTest extends TestCase $this->assertSame('Root', $element->getTitle()); $this->assertSame('Root description', $element->getDescription()); $this->assertSame('

Root rich text

', $element->getRichText()); + $this->assertSame('/assets/pdfs/root.pdf', $element->getPdfPath()); $this->assertSame($set->getId(), $element->getSet()->getId()); $this->assertNull($element->getParentElement()); } @@ -69,6 +71,7 @@ class CreateElementTest extends TestCase title: 'Root', description: 'Root description', richText: '

Root rich text

', + pdfPath: null, parentElementId: null, ) ); @@ -79,6 +82,7 @@ class CreateElementTest extends TestCase title: 'Child', description: 'Child description', richText: '

Child rich text

', + pdfPath: '/assets/pdfs/child.pdf', parentElementId: $rootElement->getId(), ) ); @@ -92,6 +96,10 @@ class CreateElementTest extends TestCase '

Child rich text

', $childElement->getRichText(), ); + $this->assertSame( + '/assets/pdfs/child.pdf', + $childElement->getPdfPath(), + ); $this->assertSame( $rootElement->getId(), $childElement->getParentElement()->getId(), @@ -107,11 +115,29 @@ class CreateElementTest extends TestCase title: 'Root', description: null, richText: null, + pdfPath: null, parentElementId: null, )); $this->assertSame('', $element->getDescription()); $this->assertSame('', $element->getRichText()); + $this->assertNull($element->getPdfPath()); + } + + public function testCreatesElementWithNullPdfPathWhenBlank(): void + { + $set = $this->createSet('Daily learning'); + + $element = $this->createElement->execute(new CreateElementRequest( + setId: $set->getId(), + title: 'Root', + description: 'Root description', + richText: '

Root rich text

', + pdfPath: '', + parentElementId: null, + )); + + $this->assertNull($element->getPdfPath()); } public function testThrowsWhenSetIdMissing(): void @@ -124,6 +150,7 @@ class CreateElementTest extends TestCase title: 'Root', description: 'Root description', richText: '

Root rich text

', + pdfPath: null, parentElementId: null, )); } @@ -138,6 +165,7 @@ class CreateElementTest extends TestCase title: null, description: 'Root description', richText: '

Root rich text

', + pdfPath: null, parentElementId: null, )); } @@ -152,6 +180,7 @@ class CreateElementTest extends TestCase title: 'Root', description: 'Root description', richText: '

Root rich text

', + pdfPath: null, parentElementId: null, )); } @@ -170,6 +199,7 @@ class CreateElementTest extends TestCase title: 'Child', description: 'Child description', richText: '

Child rich text

', + pdfPath: null, parentElementId: 99, )); } @@ -182,6 +212,7 @@ class CreateElementTest extends TestCase title: 'Root', description: 'Root description', richText: '

Root rich text

', + pdfPath: null, parentElementId: null, )); @@ -195,6 +226,7 @@ class CreateElementTest extends TestCase title: 'Another root', description: 'Another root description', richText: '

Another root rich text

', + pdfPath: null, parentElementId: null, )); } @@ -209,6 +241,7 @@ class CreateElementTest extends TestCase title: 'Parent root', description: 'Parent root description', richText: '

Parent root rich text

', + pdfPath: null, parentElementId: null, ) ); @@ -223,6 +256,7 @@ class CreateElementTest extends TestCase title: 'Invalid child', description: 'Invalid child description', richText: '

Invalid child rich text

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

A structured path for growth

', + '/assets/pdfs/baderech.pdf', null, ); @@ -51,6 +52,10 @@ class GetElementTest extends TestCase '

A structured path for growth

', $foundElement->getRichText(), ); + $this->assertSame( + '/assets/pdfs/baderech.pdf', + $foundElement->getPdfPath(), + ); } public function testReturnsDirectChildElements(): void @@ -61,6 +66,7 @@ class GetElementTest extends TestCase 'Baderech HaAvodah', 'A structured path for growth', '

A structured path for growth

', + '/assets/pdfs/baderech.pdf', null, ); $firstChildElement = $this->createElement( @@ -68,6 +74,7 @@ class GetElementTest extends TestCase 'Avodah Foundations', 'Foundations for steady avodah', '

Foundations rich text

', + '/assets/pdfs/foundations.pdf', $parentElement, ); $secondChildElement = $this->createElement( @@ -75,6 +82,7 @@ class GetElementTest extends TestCase 'Daily Practice', 'Daily practices for growth', '

Daily practice rich text

', + null, $parentElement, ); $this->createElement( @@ -82,6 +90,7 @@ class GetElementTest extends TestCase 'Nested Practice', 'Nested description', '

Nested rich text

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

Other parent rich text

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

Other child rich text

', + null, $otherParentElement, ); @@ -157,6 +168,7 @@ class GetElementTest extends TestCase string $title, string $description, string $richText, + ?string $pdfPath, ?Element $parentElement, ): Element { return $this->elementRepo->create(new CreateElementDto( @@ -164,6 +176,7 @@ class GetElementTest extends TestCase title: $title, description: $description, richText: $richText, + pdfPath: $pdfPath, parentElement: $parentElement, )); } diff --git a/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts b/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts index 4dda0e4..5901c8e 100644 --- a/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts +++ b/frontend/rabbi_gerzi/cypress/e2e/media.cy.ts @@ -46,6 +46,10 @@ describe('media page sets', () => { .should('be.visible') cy.contains('strong', 'Move steadily').should('be.visible') }) + cy.contains('[data-cy="element-pdf-link"]', 'View PDF') + .should('be.visible') + .and('have.attr', 'href', '/assets/pdfs/baderech.pdf') + .and('have.attr', 'target', '_blank') cy.get('[data-cy="child-element-list"]').should('be.visible') cy.get('[data-cy="child-element-list"]') .should( @@ -78,5 +82,6 @@ describe('media page sets', () => { 'contain.text', 'Avodah foundations begin with honest awareness', ) + cy.get('[data-cy="element-pdf-link"]').should('not.exist') }) }) From cc1735ee7b9a24aa34d8efcdd889366155e2cc91 Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Wed, 27 May 2026 20:19:11 +0300 Subject: [PATCH 2/3] add element pdf path --- 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 | 3 ++ backend/tests/Fakes/FakeElementRepository.php | 2 + backend/tests/Feature/SetsEndpointTest.php | 1 + frontend/rabbi_gerzi/src/stores/elements.ts | 1 + .../rabbi_gerzi/src/views/ElementPage.vue | 50 +++++++++++++++++++ 13 files changed, 76 insertions(+) diff --git a/backend/app/Controllers/ElementController.php b/backend/app/Controllers/ElementController.php index 4942d19..b485f73 100644 --- a/backend/app/Controllers/ElementController.php +++ b/backend/app/Controllers/ElementController.php @@ -47,6 +47,7 @@ class ElementController 'title' => $element->getTitle(), 'description' => $element->getDescription(), 'richText' => $element->getRichText(), + 'pdfPath' => $element->getPdfPath(), ], ], 200); } diff --git a/backend/app/Element/CreateElementDto.php b/backend/app/Element/CreateElementDto.php index 1e48b41..e5cc6fe 100644 --- a/backend/app/Element/CreateElementDto.php +++ b/backend/app/Element/CreateElementDto.php @@ -11,6 +11,7 @@ class CreateElementDto public string $title, public string $description, public string $richText, + public ?string $pdfPath, public ?Element $parentElement, ) { } diff --git a/backend/app/Element/Element.php b/backend/app/Element/Element.php index 2c9395a..f8e9f38 100644 --- a/backend/app/Element/Element.php +++ b/backend/app/Element/Element.php @@ -11,6 +11,7 @@ class Element private string $title, private string $description, private string $richText, + private ?string $pdfPath, private Set $set, private ?Element $parentElement, ) { @@ -36,6 +37,11 @@ class Element return $this->richText; } + public function getPdfPath(): ?string + { + return $this->pdfPath; + } + public function getSet(): Set { return $this->set; diff --git a/backend/app/Element/ElementModel.php b/backend/app/Element/ElementModel.php index a1ffa17..2655d04 100644 --- a/backend/app/Element/ElementModel.php +++ b/backend/app/Element/ElementModel.php @@ -11,6 +11,7 @@ use Illuminate\Database\Eloquent\Model; * @property string $title * @property string $description * @property string $rich_text + * @property string|null $pdf_path * @property int|null $parent_element_id * * @method static Builder|ElementModel newModelQuery() @@ -22,6 +23,7 @@ use Illuminate\Database\Eloquent\Model; * @method static Builder|ElementModel whereTitle($value) * @method static Builder|ElementModel whereDescription($value) * @method static Builder|ElementModel whereRichText($value) + * @method static Builder|ElementModel wherePdfPath($value) * * @mixin \Eloquent */ @@ -36,6 +38,7 @@ class ElementModel extends Model 'title', 'description', 'rich_text', + 'pdf_path', 'parent_element_id', ]; diff --git a/backend/app/Element/EloquentElementRepository.php b/backend/app/Element/EloquentElementRepository.php index 455852c..389d37b 100644 --- a/backend/app/Element/EloquentElementRepository.php +++ b/backend/app/Element/EloquentElementRepository.php @@ -19,6 +19,7 @@ class EloquentElementRepository implements ElementRepository 'title' => $dto->title, 'description' => $dto->description, 'rich_text' => $dto->richText, + 'pdf_path' => $dto->pdfPath, 'parent_element_id' => $dto->parentElement?->getId(), ]); @@ -27,6 +28,7 @@ class EloquentElementRepository implements ElementRepository title: $dto->title, description: $dto->description, richText: $dto->richText, + pdfPath: $dto->pdfPath, set: $dto->set, parentElement: $dto->parentElement, ); @@ -108,6 +110,7 @@ class EloquentElementRepository implements ElementRepository title: $model->title, description: $model->description, richText: $model->rich_text, + pdfPath: $model->pdf_path, set: $set, parentElement: $parentElement, ); diff --git a/backend/app/Element/UseCases/CreateElement/CreateElement.php b/backend/app/Element/UseCases/CreateElement/CreateElement.php index 47d5684..364ef0a 100644 --- a/backend/app/Element/UseCases/CreateElement/CreateElement.php +++ b/backend/app/Element/UseCases/CreateElement/CreateElement.php @@ -32,6 +32,7 @@ class CreateElement } $description = $request->description ?? ''; $richText = $request->richText ?? ''; + $pdfPath = $request->pdfPath === '' ? null : $request->pdfPath; $set = $this->setRepo->find($request->setId); if ($set === null) { @@ -48,6 +49,7 @@ class CreateElement title: $request->title, description: $description, richText: $richText, + pdfPath: $pdfPath, parentElement: null, )); } @@ -71,6 +73,7 @@ class CreateElement title: $request->title, description: $description, richText: $richText, + pdfPath: $pdfPath, parentElement: $parentElement, )); } diff --git a/backend/app/Element/UseCases/CreateElement/CreateElementRequest.php b/backend/app/Element/UseCases/CreateElement/CreateElementRequest.php index 908a4d6..b63628a 100644 --- a/backend/app/Element/UseCases/CreateElement/CreateElementRequest.php +++ b/backend/app/Element/UseCases/CreateElement/CreateElementRequest.php @@ -9,6 +9,7 @@ class CreateElementRequest public ?string $title, public ?string $description, public ?string $richText, + public ?string $pdfPath, 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 0f96d3a..c0edefa 100644 --- a/backend/database/migrations/2026_05_24_000001_elements_table.php +++ b/backend/database/migrations/2026_05_24_000001_elements_table.php @@ -14,6 +14,7 @@ return new class extends Migration $table->string('title'); $table->text('description')->default(''); $table->text('rich_text')->default(''); + $table->string('pdf_path')->nullable(); $table->foreignId('parent_element_id') ->nullable() ->constrained('elements'); diff --git a/backend/database/seeders/ElementSeeder.php b/backend/database/seeders/ElementSeeder.php index 02d2467..592396d 100644 --- a/backend/database/seeders/ElementSeeder.php +++ b/backend/database/seeders/ElementSeeder.php @@ -21,6 +21,7 @@ class ElementSeeder extends Seeder richText: '

Begin with a clear map for avodah growth.

' . '

Move steadily from awareness ' . 'to practice.

', + pdfPath: '/assets/pdfs/baderech.pdf', parentElement: null, )); $elementRepository->create(new CreateElementDto( @@ -30,6 +31,7 @@ class ElementSeeder extends Seeder . 'avodah practice.', richText: '

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

', + pdfPath: null, parentElement: $rootElement, )); $elementRepository->create(new CreateElementDto( @@ -38,6 +40,7 @@ class ElementSeeder extends Seeder description: 'Practical steps for consistent daily growth.', richText: '

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

', + pdfPath: null, parentElement: $rootElement, )); } diff --git a/backend/tests/Fakes/FakeElementRepository.php b/backend/tests/Fakes/FakeElementRepository.php index 4cf8bce..0ccdfeb 100644 --- a/backend/tests/Fakes/FakeElementRepository.php +++ b/backend/tests/Fakes/FakeElementRepository.php @@ -22,6 +22,7 @@ class FakeElementRepository implements ElementRepository title: $dto->title, description: $dto->description, richText: $dto->richText, + pdfPath: $dto->pdfPath, set: $dto->set, parentElement: $dto->parentElement, ); @@ -99,6 +100,7 @@ class FakeElementRepository implements ElementRepository title: $element->getTitle(), description: $element->getDescription(), richText: $element->getRichText(), + pdfPath: $element->getPdfPath(), set: $element->getSet(), parentElement: $parentElement, ); diff --git a/backend/tests/Feature/SetsEndpointTest.php b/backend/tests/Feature/SetsEndpointTest.php index 32aabd2..ed0bbca 100644 --- a/backend/tests/Feature/SetsEndpointTest.php +++ b/backend/tests/Feature/SetsEndpointTest.php @@ -33,6 +33,7 @@ class SetsEndpointTest extends TestCase title: $baderechSet->getName(), description: $baderechSet->getDescription(), richText: '', + pdfPath: null, parentElement: null, ) ); diff --git a/frontend/rabbi_gerzi/src/stores/elements.ts b/frontend/rabbi_gerzi/src/stores/elements.ts index 6c5f1f4..eb82ffc 100644 --- a/frontend/rabbi_gerzi/src/stores/elements.ts +++ b/frontend/rabbi_gerzi/src/stores/elements.ts @@ -9,6 +9,7 @@ export interface ChildElement { export interface Element extends ChildElement { richText: string + pdfPath: string | null } interface ElementResponse { diff --git a/frontend/rabbi_gerzi/src/views/ElementPage.vue b/frontend/rabbi_gerzi/src/views/ElementPage.vue index 1956a22..10fdbbf 100644 --- a/frontend/rabbi_gerzi/src/views/ElementPage.vue +++ b/frontend/rabbi_gerzi/src/views/ElementPage.vue @@ -56,6 +56,18 @@ watch( v-html="element.richText" /> + +