Merge branch 'individual-text-page'
This commit is contained in:
commit
adc72961d0
15 changed files with 453 additions and 12 deletions
129
app/Node/JsonNodeRepository.php
Normal file
129
app/Node/JsonNodeRepository.php
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Node;
|
||||||
|
|
||||||
|
use App\Node\Node;
|
||||||
|
use App\Node\CreateNodeDto;
|
||||||
|
use App\Node\NodeRepository;
|
||||||
|
use App\Text\TextRepository;
|
||||||
|
|
||||||
|
class JsonNodeRepository implements NodeRepository
|
||||||
|
{
|
||||||
|
private string $filePath;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
private TextRepository $textRepository,
|
||||||
|
) {
|
||||||
|
$this->filePath = __DIR__.'/../../data/nodes.json';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create(CreateNodeDto $dto): Node
|
||||||
|
{
|
||||||
|
$nodes = $this->readNodes();
|
||||||
|
$id = $this->getNextId($nodes);
|
||||||
|
|
||||||
|
$nodes[] = [
|
||||||
|
'id' => $id,
|
||||||
|
'title' => $dto->title,
|
||||||
|
'textId' => $dto->text->getId(),
|
||||||
|
'parentNodeId' => $dto->parentNode?->getId(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->writeNodes($nodes);
|
||||||
|
|
||||||
|
return new Node(
|
||||||
|
id: $id,
|
||||||
|
title: $dto->title,
|
||||||
|
text: $dto->text,
|
||||||
|
parentNode: $dto->parentNode,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find(int $id): ?Node
|
||||||
|
{
|
||||||
|
$nodes = $this->readNodes();
|
||||||
|
|
||||||
|
foreach ($nodes as $data) {
|
||||||
|
if ($data['id'] === $id) {
|
||||||
|
return $this->hydrateNode($data, $nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Node[]
|
||||||
|
*/
|
||||||
|
public function findByTextId(int $id): array
|
||||||
|
{
|
||||||
|
$nodes = $this->readNodes();
|
||||||
|
|
||||||
|
$matching = array_filter(
|
||||||
|
$nodes,
|
||||||
|
fn(array $data) => $data['textId'] === $id
|
||||||
|
);
|
||||||
|
|
||||||
|
return array_values(array_map(
|
||||||
|
fn(array $data) => $this->hydrateNode($data, $nodes),
|
||||||
|
$matching
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hydrateNode(array $data, array $allNodes): Node
|
||||||
|
{
|
||||||
|
$text = $this->textRepository->find($data['textId']);
|
||||||
|
|
||||||
|
$parentNode = null;
|
||||||
|
if ($data['parentNodeId'] !== null) {
|
||||||
|
foreach ($allNodes as $parentData) {
|
||||||
|
if ($parentData['id'] === $data['parentNodeId']) {
|
||||||
|
$parentNode = $this->hydrateNode($parentData, $allNodes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Node(
|
||||||
|
id: $data['id'],
|
||||||
|
title: $data['title'],
|
||||||
|
text: $text,
|
||||||
|
parentNode: $parentNode,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function readNodes(): array
|
||||||
|
{
|
||||||
|
if (!file_exists($this->filePath)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$content = file_get_contents($this->filePath);
|
||||||
|
|
||||||
|
return json_decode($content, true) ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function writeNodes(array $nodes): void
|
||||||
|
{
|
||||||
|
file_put_contents(
|
||||||
|
$this->filePath,
|
||||||
|
json_encode($nodes, JSON_PRETTY_PRINT)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getNextId(array $nodes): int
|
||||||
|
{
|
||||||
|
if (empty($nodes)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxId = 0;
|
||||||
|
foreach ($nodes as $node) {
|
||||||
|
if ($node['id'] > $maxId) {
|
||||||
|
$maxId = $node['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $maxId + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
37
app/Node/NodeController.php
Normal file
37
app/Node/NodeController.php
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Node;
|
||||||
|
|
||||||
|
use App\Node\NodeRepository;
|
||||||
|
use App\Text\TextRepository;
|
||||||
|
use Psr\Http\Message\ResponseInterface as Response;
|
||||||
|
|
||||||
|
class NodeController
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private NodeRepository $nodeRepository,
|
||||||
|
private TextRepository $textRepository,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public function getNodes(Response $response, int $textId): Response
|
||||||
|
{
|
||||||
|
$text = $this->textRepository->find($textId);
|
||||||
|
|
||||||
|
if ($text === null) {
|
||||||
|
return $response->withStatus(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$nodes = $this->nodeRepository->findByTextId($textId);
|
||||||
|
|
||||||
|
$data = array_map(function ($node) {
|
||||||
|
return [
|
||||||
|
'id' => $node->getId(),
|
||||||
|
'title' => $node->getTitle(),
|
||||||
|
'parentNodeId' => $node->getParentNode()?->getId(),
|
||||||
|
];
|
||||||
|
}, $nodes);
|
||||||
|
|
||||||
|
$response->getBody()->write(json_encode(array_values($data)));
|
||||||
|
return $response->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,15 +18,32 @@ class TextController
|
||||||
{
|
{
|
||||||
$texts = $this->textRepository->getAll();
|
$texts = $this->textRepository->getAll();
|
||||||
|
|
||||||
$data = array_map(fn($text) => [
|
$data = array_map(function ($text) {
|
||||||
|
return [
|
||||||
'id' => $text->getId(),
|
'id' => $text->getId(),
|
||||||
'name' => $text->getName(),
|
'name' => $text->getName(),
|
||||||
], $texts);
|
];
|
||||||
|
}, $texts);
|
||||||
|
|
||||||
$response->getBody()->write(json_encode($data));
|
$response->getBody()->write(json_encode($data));
|
||||||
return $response->withHeader('Content-Type', 'application/json');
|
return $response->withHeader('Content-Type', 'application/json');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getText(Response $response, int $textId): Response
|
||||||
|
{
|
||||||
|
$text = $this->textRepository->find($textId);
|
||||||
|
|
||||||
|
if ($text === null) {
|
||||||
|
return $response->withStatus(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->getBody()->write(json_encode([
|
||||||
|
'id' => $text->getId(),
|
||||||
|
'name' => $text->getName(),
|
||||||
|
]));
|
||||||
|
return $response->withHeader('Content-Type', 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
public function createText(
|
public function createText(
|
||||||
Request $request,
|
Request $request,
|
||||||
Response $response,
|
Response $response,
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,28 @@ namespace App\Text\UseCases;
|
||||||
use App\Text\Text;
|
use App\Text\Text;
|
||||||
use App\Text\CreateTextDto;
|
use App\Text\CreateTextDto;
|
||||||
use App\Text\TextRepository;
|
use App\Text\TextRepository;
|
||||||
|
use App\Node\NodeRepository;
|
||||||
|
use App\Node\CreateNodeDto;
|
||||||
|
|
||||||
class CreateText
|
class CreateText
|
||||||
{
|
{
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private TextRepository $textRepo,
|
private TextRepository $textRepo,
|
||||||
|
private NodeRepository $nodeRepo,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public function execute(CreateTextRequest $request): Text
|
public function execute(CreateTextRequest $request): Text
|
||||||
{
|
{
|
||||||
return $this->textRepo->create(new CreateTextDto(
|
$text = $this->textRepo->create(new CreateTextDto(
|
||||||
name: $request->name,
|
name: $request->name,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$this->nodeRepo->create(new CreateNodeDto(
|
||||||
|
text: $text,
|
||||||
|
title: $text->getName(),
|
||||||
|
parentNode: null,
|
||||||
|
));
|
||||||
|
|
||||||
|
return $text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,4 +21,12 @@ class ViewController
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function text(Response $response): Response
|
||||||
|
{
|
||||||
|
$html = file_get_contents(__DIR__.'/../../views/templates/text.php', true);
|
||||||
|
$response->getBody()->write($html);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use Psr\Http\Message\ServerRequestInterface as Request;
|
||||||
use DI\Bridge\Slim\Bridge;
|
use DI\Bridge\Slim\Bridge;
|
||||||
use App\View\ViewController;
|
use App\View\ViewController;
|
||||||
use App\Text\TextController;
|
use App\Text\TextController;
|
||||||
|
use App\Node\NodeController;
|
||||||
|
|
||||||
$container = require __DIR__.'/container.php';
|
$container = require __DIR__.'/container.php';
|
||||||
$app = Bridge::create($container);
|
$app = Bridge::create($container);
|
||||||
|
|
@ -14,8 +15,11 @@ $app->addErrorMiddleware(true, true, true);
|
||||||
|
|
||||||
$app->get('/admin', [ViewController::class, 'admin']);
|
$app->get('/admin', [ViewController::class, 'admin']);
|
||||||
$app->get('/admin/texts', [ViewController::class, 'texts']);
|
$app->get('/admin/texts', [ViewController::class, 'texts']);
|
||||||
|
$app->get('/admin/texts/{textId}', [ViewController::class, 'text']);
|
||||||
|
|
||||||
$app->get('/api/texts', [TextController::class, 'getTexts']);
|
$app->get('/api/texts', [TextController::class, 'getTexts']);
|
||||||
|
$app->get('/api/texts/{textId}', [TextController::class, 'getText']);
|
||||||
|
$app->get('/api/texts/{textId}/nodes', [NodeController::class, 'getNodes']);
|
||||||
$app->post('/api/texts', [TextController::class, 'createText']);
|
$app->post('/api/texts', [TextController::class, 'createText']);
|
||||||
|
|
||||||
return $app;
|
return $app;
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,12 @@ use DI;
|
||||||
use DI\Container;
|
use DI\Container;
|
||||||
use App\Text\TextRepository;
|
use App\Text\TextRepository;
|
||||||
use App\Text\JsonTextRepository;
|
use App\Text\JsonTextRepository;
|
||||||
|
use App\Node\NodeRepository;
|
||||||
|
use App\Node\JsonNodeRepository;
|
||||||
|
|
||||||
$container = new Container([
|
$container = new Container([
|
||||||
TextRepository::class => DI\create(JsonTextRepository::class),
|
TextRepository::class => DI\autowire(JsonTextRepository::class),
|
||||||
|
NodeRepository::class => DI\autowire(JsonNodeRepository::class),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $container;
|
return $container;
|
||||||
|
|
|
||||||
|
|
@ -25,4 +25,34 @@ describe('The admin page', () => {
|
||||||
cy.get('#submit').click()
|
cy.get('#submit').click()
|
||||||
cy.contains('Test Text')
|
cy.contains('Test Text')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('shows one root node and child node on the seeded text page', () => {
|
||||||
|
cy.visit('/admin/texts/0')
|
||||||
|
cy.intercept('GET', '/api/texts/0/nodes').as('getNodes')
|
||||||
|
cy.wait('@getNodes')
|
||||||
|
cy.get('#text-detail > ul > li > ul > li').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows one root node on the text page', () => {
|
||||||
|
cy.visit('/admin/texts')
|
||||||
|
cy.get('#newTextName').type('My Node Text')
|
||||||
|
cy.get('#submit').click()
|
||||||
|
cy.intercept('GET', '/api/texts/1/nodes').as('getNodes')
|
||||||
|
cy.get('a').contains('My Node Text').click()
|
||||||
|
cy.wait('@getNodes')
|
||||||
|
cy.get('#text-detail > ul').should('have.length', 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('navigates to a specific texts page', () => {
|
||||||
|
cy.visit('/admin/texts')
|
||||||
|
cy.get('#newTextName').type('My New Text')
|
||||||
|
cy.get('#submit').click()
|
||||||
|
cy.intercept('GET', '/admin/texts/1').as('textPage')
|
||||||
|
cy.get('a')
|
||||||
|
.contains('My New Text')
|
||||||
|
.should('have.attr', 'href', '/admin/texts/1')
|
||||||
|
.click()
|
||||||
|
cy.url().should('include', '/admin/texts/1')
|
||||||
|
cy.wait('@textPage').its('response.statusCode').should('eq', 200)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,24 @@ $texts = [
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$nodes = [
|
||||||
|
[
|
||||||
|
'id' => 0,
|
||||||
|
'title' => 'Chapter 1',
|
||||||
|
'textId' => 0,
|
||||||
|
'parentNodeId' => null,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'title' => 'Section 1.1',
|
||||||
|
'textId' => 0,
|
||||||
|
'parentNodeId' => 0,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
$fileDataMap = [
|
$fileDataMap = [
|
||||||
'texts.json' => $texts,
|
'texts.json' => $texts,
|
||||||
|
'nodes.json' => $nodes,
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($fileDataMap as $file => $data) {
|
foreach ($fileDataMap as $file => $data) {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
$files = [
|
$files = [
|
||||||
'texts.json',
|
'texts.json',
|
||||||
|
'nodes.json',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
|
|
|
||||||
50
public/js/text.js
Normal file
50
public/js/text.js
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const textId = window.location.pathname.split('/').pop();
|
||||||
|
|
||||||
|
fetch('/api/texts/' + textId)
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(text => {
|
||||||
|
const h1 = document.createElement('h1');
|
||||||
|
h1.textContent = text.name;
|
||||||
|
document.getElementById('text-detail').appendChild(h1);
|
||||||
|
|
||||||
|
return fetch('/api/texts/' + textId + '/nodes');
|
||||||
|
})
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(nodes => {
|
||||||
|
const tree = buildTree(nodes);
|
||||||
|
const ul = renderTree(tree);
|
||||||
|
document.getElementById('text-detail').appendChild(ul);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function buildTree(nodes) {
|
||||||
|
const map = {};
|
||||||
|
nodes.forEach(node => {
|
||||||
|
map[node.id] = { ...node, children: [] };
|
||||||
|
});
|
||||||
|
|
||||||
|
const roots = [];
|
||||||
|
nodes.forEach(node => {
|
||||||
|
if (node.parentNodeId === null) {
|
||||||
|
roots.push(map[node.id]);
|
||||||
|
} else if (map[node.parentNodeId]) {
|
||||||
|
map[node.parentNodeId].children.push(map[node.id]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return roots;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTree(nodes) {
|
||||||
|
const ul = document.createElement('ul');
|
||||||
|
nodes.forEach(node => {
|
||||||
|
const li = document.createElement('li');
|
||||||
|
li.textContent = node.title;
|
||||||
|
if (node.children.length > 0) {
|
||||||
|
li.appendChild(renderTree(node.children));
|
||||||
|
}
|
||||||
|
ul.appendChild(li);
|
||||||
|
});
|
||||||
|
return ul;
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
async function loadTexts() {
|
async function loadTexts() {
|
||||||
const res = await fetch('/api/texts');
|
const res = await fetch('/api/texts');
|
||||||
const texts = await res.json();
|
const texts = await res.json();
|
||||||
textsList.innerHTML = texts.map(text => '<li>' + text.name + '</li>').join('');
|
textsList.innerHTML = texts.map(text =>
|
||||||
|
'<li><a href=/admin/texts/'
|
||||||
|
+ text.id
|
||||||
|
+ '>'
|
||||||
|
+ text.name
|
||||||
|
+ '</a></li>').join('');
|
||||||
}
|
}
|
||||||
|
|
||||||
form.addEventListener('submit', async (e) => {
|
form.addEventListener('submit', async (e) => {
|
||||||
|
|
@ -18,7 +23,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const text = await res.json();
|
const text = await res.json();
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
li.textContent = text.name;
|
const a = document.createElement('a');
|
||||||
|
a.href = '/admin/texts/' + text.id;
|
||||||
|
a.textContent = text.name;
|
||||||
|
li.appendChild(a);
|
||||||
textsList.appendChild(li);
|
textsList.appendChild(li);
|
||||||
form.reset();
|
form.reset();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,19 +7,48 @@ use App\Text\TextRepository;
|
||||||
use App\Text\UseCases\CreateText;
|
use App\Text\UseCases\CreateText;
|
||||||
use App\Text\UseCases\CreateTextRequest;
|
use App\Text\UseCases\CreateTextRequest;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Tests\Fakes\FakeNodeRepository;
|
||||||
use Tests\Fakes\FakeTextRepository;
|
use Tests\Fakes\FakeTextRepository;
|
||||||
|
|
||||||
class CreateTextTest extends TestCase
|
class CreateTextTest extends TestCase
|
||||||
{
|
{
|
||||||
|
private FakeTextRepository $textRepo;
|
||||||
|
|
||||||
|
private FakeNodeRepository $nodeRepo;
|
||||||
|
|
||||||
|
private CreateText $useCase;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->textRepo = new FakeTextRepository;
|
||||||
|
$this->nodeRepo = new FakeNodeRepository;
|
||||||
|
$this->useCase = new CreateText(
|
||||||
|
$this->textRepo,
|
||||||
|
$this->nodeRepo,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function test_create_text(): void
|
public function test_create_text(): void
|
||||||
{
|
{
|
||||||
$textRepo = new FakeTextRepository;
|
$text = $this->useCase->execute(new CreateTextRequest(
|
||||||
$useCase = new CreateText($textRepo);
|
|
||||||
$text = $useCase->execute(new CreateTextRequest(
|
|
||||||
name: 'test',
|
name: 'test',
|
||||||
));
|
));
|
||||||
$this->assertInstanceOf(TextRepository::class, $textRepo);
|
$this->assertInstanceOf(TextRepository::class, $this->textRepo);
|
||||||
$this->assertInstanceOf(Text::class, $text);
|
$this->assertInstanceOf(Text::class, $text);
|
||||||
$this->assertEquals('test', $text->getName());
|
$this->assertEquals('test', $text->getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_creates_root_node_on_text_creation(): void
|
||||||
|
{
|
||||||
|
$text = $this->useCase->execute(new CreateTextRequest(
|
||||||
|
name: 'my text',
|
||||||
|
));
|
||||||
|
|
||||||
|
$nodes = $this->nodeRepo->findByTextId($text->getId());
|
||||||
|
$this->assertCount(1, $nodes);
|
||||||
|
|
||||||
|
$rootNode = array_values($nodes)[0];
|
||||||
|
$this->assertEquals('my text', $rootNode->getTitle());
|
||||||
|
$this->assertNull($rootNode->getParentNode());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
87
tests/e2e/Controllers/TextControllerTest.php
Normal file
87
tests/e2e/Controllers/TextControllerTest.php
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\e2e\Controllers;
|
||||||
|
|
||||||
|
use App\Text\CreateTextDto;
|
||||||
|
use App\Text\TextController;
|
||||||
|
use App\Text\UseCases\CreateText;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Slim\Psr7\Factory\ServerRequestFactory;
|
||||||
|
use Slim\Psr7\Response;
|
||||||
|
use Tests\Fakes\FakeNodeRepository;
|
||||||
|
use Tests\Fakes\FakeTextRepository;
|
||||||
|
|
||||||
|
class TextControllerTest extends TestCase
|
||||||
|
{
|
||||||
|
private FakeTextRepository $textRepo;
|
||||||
|
|
||||||
|
private TextController $controller;
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
$this->textRepo = new FakeTextRepository;
|
||||||
|
$this->textRepo->create(new CreateTextDto(
|
||||||
|
name: 'test text',
|
||||||
|
));
|
||||||
|
$this->controller = new TextController($this->textRepo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_get_one_text(): void
|
||||||
|
{
|
||||||
|
$response = $this->controller->getText(
|
||||||
|
new Response(),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
json_encode([
|
||||||
|
'id' => 0,
|
||||||
|
'name' => 'test text',
|
||||||
|
]),
|
||||||
|
$response->getBody()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_get_all_texts(): void
|
||||||
|
{
|
||||||
|
$this->textRepo->create(new CreateTextDto(
|
||||||
|
name: 'test text 2',
|
||||||
|
));
|
||||||
|
$response = $this->controller->getTexts(new Response());
|
||||||
|
$this->assertEquals(
|
||||||
|
json_encode([
|
||||||
|
[
|
||||||
|
'id' => 0,
|
||||||
|
'name' => 'test text',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'name' => 'test text 2',
|
||||||
|
]
|
||||||
|
]),
|
||||||
|
$response->getBody()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_create_text(): void
|
||||||
|
{
|
||||||
|
$request = (new ServerRequestFactory())
|
||||||
|
->createServerRequest('POST', 'http://localhost/texts')
|
||||||
|
->withParsedBody(['name' => 'my new text']);
|
||||||
|
|
||||||
|
$response = $this->controller->createText(
|
||||||
|
$request,
|
||||||
|
new Response(),
|
||||||
|
new CreateText(
|
||||||
|
$this->textRepo,
|
||||||
|
new FakeNodeRepository,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$this->assertEquals(
|
||||||
|
json_encode([
|
||||||
|
'id' => 1,
|
||||||
|
'name' => 'my new text',
|
||||||
|
]),
|
||||||
|
$response->getBody()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
views/templates/text.php
Normal file
11
views/templates/text.php
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Daily Goals - Text</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a href="/admin/texts" id="back">Back to Texts</a>
|
||||||
|
<div id="text-detail"></div>
|
||||||
|
<script src="/js/text.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue