test level based scheduling
This commit is contained in:
parent
99e1ba051c
commit
a64df64b76
7 changed files with 415 additions and 94 deletions
|
|
@ -8,92 +8,110 @@ use App\Exceptions\NotFoundException;
|
|||
use App\Schedule\UseCases\CreateSchedule\CreateSchedule;
|
||||
use App\Schedule\UseCases\CreateSchedule\CreateScheduleRequest;
|
||||
use App\Set\CreateSetDto;
|
||||
use App\Set\CreateSetLevelDto;
|
||||
use App\Set\Set;
|
||||
use App\Set\SetLevel;
|
||||
use App\Shared\ValueObject\EmailAddress;
|
||||
use App\User\User;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Tests\Fakes\FakeElementRepository;
|
||||
use Tests\Fakes\FakeScheduleRepository;
|
||||
use Tests\Fakes\FakeSetRepository;
|
||||
use Tests\Fakes\FakeSetLevelRepository;
|
||||
|
||||
class CreateScheduleTest extends TestCase
|
||||
{
|
||||
public function test_it_schedules_every_matching_element_in_tree_order(): void
|
||||
public function test_it_schedules_every_element_on_the_selected_level(): void
|
||||
{
|
||||
$user = $this->user();
|
||||
$setRepository = new FakeSetRepository;
|
||||
$setLevelRepository = new FakeSetLevelRepository;
|
||||
$elementRepository = new FakeElementRepository;
|
||||
$scheduleRepository = new FakeScheduleRepository;
|
||||
$set = $setRepository->create(new CreateSetDto(
|
||||
name: 'Bible',
|
||||
creator: $user,
|
||||
));
|
||||
$bookLevel = $this->createLevel(
|
||||
$setLevelRepository,
|
||||
$set,
|
||||
'book',
|
||||
);
|
||||
$portionLevel = $this->createLevel(
|
||||
$setLevelRepository,
|
||||
$set,
|
||||
'portion',
|
||||
);
|
||||
$chapterLevel = $this->createLevel(
|
||||
$setLevelRepository,
|
||||
$set,
|
||||
'chapter',
|
||||
);
|
||||
$genesis = $elementRepository->create(new CreateElementDto(
|
||||
set: $set,
|
||||
name: 'Genesis',
|
||||
kind: 'book',
|
||||
level: $bookLevel,
|
||||
parentElement: null,
|
||||
));
|
||||
$exodus = $elementRepository->create(new CreateElementDto(
|
||||
set: $set,
|
||||
name: 'Exodus',
|
||||
kind: 'book',
|
||||
level: $bookLevel,
|
||||
parentElement: null,
|
||||
));
|
||||
$exodusChapterOne = $elementRepository->create(
|
||||
new CreateElementDto(
|
||||
set: $set,
|
||||
name: 'Exodus 1',
|
||||
kind: 'chapter',
|
||||
parentElement: $exodus,
|
||||
),
|
||||
);
|
||||
$creation = $elementRepository->create(new CreateElementDto(
|
||||
set: $set,
|
||||
name: 'Creation',
|
||||
kind: 'portion',
|
||||
level: $portionLevel,
|
||||
parentElement: $genesis,
|
||||
));
|
||||
$shemot = $elementRepository->create(new CreateElementDto(
|
||||
name: 'Shemot',
|
||||
level: $portionLevel,
|
||||
parentElement: $exodus,
|
||||
));
|
||||
$genesisChapterOne = $elementRepository->create(
|
||||
new CreateElementDto(
|
||||
set: $set,
|
||||
name: 'Genesis 1',
|
||||
kind: 'chapter',
|
||||
level: $chapterLevel,
|
||||
parentElement: $creation,
|
||||
),
|
||||
);
|
||||
$genesisChapterTwo = $elementRepository->create(
|
||||
new CreateElementDto(
|
||||
set: $set,
|
||||
name: 'Genesis 2',
|
||||
kind: 'chapter',
|
||||
level: $chapterLevel,
|
||||
parentElement: $creation,
|
||||
),
|
||||
);
|
||||
$genesisChapterThree = $elementRepository->create(
|
||||
new CreateElementDto(
|
||||
set: $set,
|
||||
name: 'Genesis 3',
|
||||
kind: 'chapter',
|
||||
level: $chapterLevel,
|
||||
parentElement: $creation,
|
||||
),
|
||||
);
|
||||
$exodusChapterOne = $elementRepository->create(
|
||||
new CreateElementDto(
|
||||
name: 'Exodus 1',
|
||||
level: $chapterLevel,
|
||||
parentElement: $shemot,
|
||||
),
|
||||
);
|
||||
$exodusChapterTwo = $elementRepository->create(
|
||||
new CreateElementDto(
|
||||
set: $set,
|
||||
name: 'Exodus 2',
|
||||
kind: 'chapter',
|
||||
parentElement: $exodus,
|
||||
level: $chapterLevel,
|
||||
parentElement: $shemot,
|
||||
),
|
||||
);
|
||||
|
||||
$schedule = (new CreateSchedule(
|
||||
$setRepository,
|
||||
$setLevelRepository,
|
||||
$elementRepository,
|
||||
$scheduleRepository,
|
||||
))->execute(new CreateScheduleRequest(
|
||||
user: $user,
|
||||
setId: $set->getId(),
|
||||
elementKind: 'chapter',
|
||||
levelId: $chapterLevel->getId(),
|
||||
startDate: '2026-08-10',
|
||||
targetDate: '2026-08-12',
|
||||
));
|
||||
|
|
@ -139,29 +157,35 @@ class CreateScheduleTest extends TestCase
|
|||
{
|
||||
$user = $this->user();
|
||||
$setRepository = new FakeSetRepository;
|
||||
$setLevelRepository = new FakeSetLevelRepository;
|
||||
$elementRepository = new FakeElementRepository;
|
||||
$set = $setRepository->create(new CreateSetDto(
|
||||
name: 'Course',
|
||||
creator: $user,
|
||||
));
|
||||
$lessonLevel = $this->createLevel(
|
||||
$setLevelRepository,
|
||||
$set,
|
||||
'lesson',
|
||||
);
|
||||
|
||||
foreach (['First', 'Second', 'Third'] as $name) {
|
||||
$elementRepository->create(new CreateElementDto(
|
||||
set: $set,
|
||||
name: $name,
|
||||
kind: 'lesson',
|
||||
level: $lessonLevel,
|
||||
parentElement: null,
|
||||
));
|
||||
}
|
||||
|
||||
$schedule = (new CreateSchedule(
|
||||
$setRepository,
|
||||
$setLevelRepository,
|
||||
$elementRepository,
|
||||
new FakeScheduleRepository,
|
||||
))->execute(new CreateScheduleRequest(
|
||||
user: $user,
|
||||
setId: $set->getId(),
|
||||
elementKind: 'lesson',
|
||||
levelId: $lessonLevel->getId(),
|
||||
startDate: '2026-08-10',
|
||||
targetDate: '2026-08-16',
|
||||
));
|
||||
|
|
@ -178,26 +202,32 @@ class CreateScheduleTest extends TestCase
|
|||
{
|
||||
$user = $this->user();
|
||||
$setRepository = new FakeSetRepository;
|
||||
$setLevelRepository = new FakeSetLevelRepository;
|
||||
$elementRepository = new FakeElementRepository;
|
||||
$set = $setRepository->create(new CreateSetDto(
|
||||
name: 'Project',
|
||||
creator: $user,
|
||||
));
|
||||
$milestoneLevel = $this->createLevel(
|
||||
$setLevelRepository,
|
||||
$set,
|
||||
'milestone',
|
||||
);
|
||||
$elementRepository->create(new CreateElementDto(
|
||||
set: $set,
|
||||
name: 'Ship it',
|
||||
kind: 'milestone',
|
||||
level: $milestoneLevel,
|
||||
parentElement: null,
|
||||
));
|
||||
|
||||
$schedule = (new CreateSchedule(
|
||||
$setRepository,
|
||||
$setLevelRepository,
|
||||
$elementRepository,
|
||||
new FakeScheduleRepository,
|
||||
))->execute(new CreateScheduleRequest(
|
||||
user: $user,
|
||||
setId: $set->getId(),
|
||||
elementKind: 'milestone',
|
||||
levelId: $milestoneLevel->getId(),
|
||||
startDate: '2020-01-01',
|
||||
targetDate: '2030-01-01',
|
||||
));
|
||||
|
|
@ -217,18 +247,19 @@ class CreateScheduleTest extends TestCase
|
|||
|
||||
(new CreateSchedule(
|
||||
new FakeSetRepository,
|
||||
new FakeSetLevelRepository,
|
||||
new FakeElementRepository,
|
||||
new FakeScheduleRepository,
|
||||
))->execute(new CreateScheduleRequest(
|
||||
user: $this->user(),
|
||||
setId: 999,
|
||||
elementKind: 'chapter',
|
||||
levelId: 1,
|
||||
startDate: '2026-08-10',
|
||||
targetDate: '2026-08-12',
|
||||
));
|
||||
}
|
||||
|
||||
public function test_it_rejects_an_unavailable_element_kind(): void
|
||||
public function test_it_rejects_a_missing_level(): void
|
||||
{
|
||||
$user = $this->user();
|
||||
$setRepository = new FakeSetRepository;
|
||||
|
|
@ -238,18 +269,85 @@ class CreateScheduleTest extends TestCase
|
|||
));
|
||||
|
||||
$this->expectException(BadRequestException::class);
|
||||
$this->expectExceptionMessage(
|
||||
'elementKind is not available for set',
|
||||
);
|
||||
$this->expectExceptionMessage('levelId is required');
|
||||
|
||||
(new CreateSchedule(
|
||||
$setRepository,
|
||||
new FakeSetLevelRepository,
|
||||
new FakeElementRepository,
|
||||
new FakeScheduleRepository,
|
||||
))->execute(new CreateScheduleRequest(
|
||||
user: $user,
|
||||
setId: $set->getId(),
|
||||
elementKind: 'Chapter',
|
||||
levelId: null,
|
||||
startDate: '2026-08-10',
|
||||
targetDate: '2026-08-12',
|
||||
));
|
||||
}
|
||||
|
||||
public function test_it_rejects_a_level_from_another_set(): void
|
||||
{
|
||||
$user = $this->user();
|
||||
$setRepository = new FakeSetRepository;
|
||||
$setLevelRepository = new FakeSetLevelRepository;
|
||||
$bible = $setRepository->create(new CreateSetDto(
|
||||
name: 'Bible',
|
||||
creator: $user,
|
||||
));
|
||||
$course = $setRepository->create(new CreateSetDto(
|
||||
name: 'Course',
|
||||
creator: $user,
|
||||
));
|
||||
$moduleLevel = $this->createLevel(
|
||||
$setLevelRepository,
|
||||
$course,
|
||||
'module',
|
||||
);
|
||||
|
||||
$this->expectException(BadRequestException::class);
|
||||
$this->expectExceptionMessage('level is not available for set');
|
||||
|
||||
(new CreateSchedule(
|
||||
$setRepository,
|
||||
$setLevelRepository,
|
||||
new FakeElementRepository,
|
||||
new FakeScheduleRepository,
|
||||
))->execute(new CreateScheduleRequest(
|
||||
user: $user,
|
||||
setId: $bible->getId(),
|
||||
levelId: $moduleLevel->getId(),
|
||||
startDate: '2026-08-10',
|
||||
targetDate: '2026-08-12',
|
||||
));
|
||||
}
|
||||
|
||||
public function test_it_rejects_a_level_without_elements(): void
|
||||
{
|
||||
$user = $this->user();
|
||||
$setRepository = new FakeSetRepository;
|
||||
$setLevelRepository = new FakeSetLevelRepository;
|
||||
$set = $setRepository->create(new CreateSetDto(
|
||||
name: 'Bible',
|
||||
creator: $user,
|
||||
));
|
||||
$chapterLevel = $this->createLevel(
|
||||
$setLevelRepository,
|
||||
$set,
|
||||
'chapter',
|
||||
);
|
||||
|
||||
$this->expectException(BadRequestException::class);
|
||||
$this->expectExceptionMessage('level has no elements');
|
||||
|
||||
(new CreateSchedule(
|
||||
$setRepository,
|
||||
$setLevelRepository,
|
||||
new FakeElementRepository,
|
||||
new FakeScheduleRepository,
|
||||
))->execute(new CreateScheduleRequest(
|
||||
user: $user,
|
||||
setId: $set->getId(),
|
||||
levelId: $chapterLevel->getId(),
|
||||
startDate: '2026-08-10',
|
||||
targetDate: '2026-08-12',
|
||||
));
|
||||
|
|
@ -259,22 +357,29 @@ class CreateScheduleTest extends TestCase
|
|||
{
|
||||
$user = $this->user();
|
||||
$setRepository = new FakeSetRepository;
|
||||
$setLevelRepository = new FakeSetLevelRepository;
|
||||
$set = $setRepository->create(new CreateSetDto(
|
||||
name: 'Bible',
|
||||
creator: $user,
|
||||
));
|
||||
$chapterLevel = $this->createLevel(
|
||||
$setLevelRepository,
|
||||
$set,
|
||||
'chapter',
|
||||
);
|
||||
|
||||
$this->expectException(BadRequestException::class);
|
||||
$this->expectExceptionMessage('startDate must be a valid date');
|
||||
|
||||
(new CreateSchedule(
|
||||
$setRepository,
|
||||
$setLevelRepository,
|
||||
new FakeElementRepository,
|
||||
new FakeScheduleRepository,
|
||||
))->execute(new CreateScheduleRequest(
|
||||
user: $user,
|
||||
setId: $set->getId(),
|
||||
elementKind: 'chapter',
|
||||
levelId: $chapterLevel->getId(),
|
||||
startDate: '2026-02-30',
|
||||
targetDate: '2026-08-12',
|
||||
));
|
||||
|
|
@ -284,10 +389,16 @@ class CreateScheduleTest extends TestCase
|
|||
{
|
||||
$user = $this->user();
|
||||
$setRepository = new FakeSetRepository;
|
||||
$setLevelRepository = new FakeSetLevelRepository;
|
||||
$set = $setRepository->create(new CreateSetDto(
|
||||
name: 'Bible',
|
||||
creator: $user,
|
||||
));
|
||||
$chapterLevel = $this->createLevel(
|
||||
$setLevelRepository,
|
||||
$set,
|
||||
'chapter',
|
||||
);
|
||||
|
||||
$this->expectException(BadRequestException::class);
|
||||
$this->expectExceptionMessage(
|
||||
|
|
@ -296,17 +407,29 @@ class CreateScheduleTest extends TestCase
|
|||
|
||||
(new CreateSchedule(
|
||||
$setRepository,
|
||||
$setLevelRepository,
|
||||
new FakeElementRepository,
|
||||
new FakeScheduleRepository,
|
||||
))->execute(new CreateScheduleRequest(
|
||||
user: $user,
|
||||
setId: $set->getId(),
|
||||
elementKind: 'chapter',
|
||||
levelId: $chapterLevel->getId(),
|
||||
startDate: '2026-08-12',
|
||||
targetDate: '2026-08-10',
|
||||
));
|
||||
}
|
||||
|
||||
private function createLevel(
|
||||
FakeSetLevelRepository $repository,
|
||||
Set $set,
|
||||
string $kind,
|
||||
): SetLevel {
|
||||
return $repository->create(new CreateSetLevelDto(
|
||||
set: $set,
|
||||
kind: $kind,
|
||||
));
|
||||
}
|
||||
|
||||
private function user(): User
|
||||
{
|
||||
return new User(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue