test assignment completion

This commit is contained in:
Yisroel Baum 2026-08-15 22:39:34 +03:00
parent 8218de16f5
commit 916f070455
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
4 changed files with 378 additions and 3 deletions

View file

@ -22,7 +22,7 @@ class ListAssignmentsForDateTest extends TestCase
$user = $this->user(1, 'reader@example.com');
$otherUser = $this->user(2, 'other@example.com');
$repository = new FakeScheduleRepository;
$repository->create($this->schedule(
$olderSchedule = $repository->create($this->schedule(
user: $user,
setName: 'Older plan',
date: '2026-08-15',
@ -46,6 +46,12 @@ class ListAssignmentsForDateTest extends TestCase
date: '2026-08-16',
assignmentNames: ['Later'],
));
$completedAssignment = $olderSchedule->getAssignments()[0];
$completedAssignment->complete(new DateTimeImmutable(
'2026-08-15T12:00:00',
new DateTimeZone('UTC'),
));
$repository->updateAssignment($completedAssignment);
$assignments = (new ListAssignmentsForDate($repository))->execute(
new ListAssignmentsForDateRequest(
@ -55,13 +61,13 @@ class ListAssignmentsForDateTest extends TestCase
);
$this->assertSame(
['Newer plan', 'Older plan', 'Older plan'],
['Newer plan', 'Older plan'],
array_map(function ($assignment): string {
return $assignment->getSetName();
}, $assignments),
);
$this->assertSame(
['Third', 'First', 'Second'],
['Third', 'Second'],
array_map(function ($assignment): string {
return $assignment->getAssignment()->getName();
}, $assignments),

View file

@ -0,0 +1,175 @@
<?php
namespace Tests\Unit\Schedule\UseCases;
use App\Exceptions\BadRequestException;
use App\Exceptions\NotFoundException;
use App\Schedule\CreateScheduleAssignmentDto;
use App\Schedule\CreateScheduleDto;
use App\Schedule\UseCases\SetAssignmentCompletion\SetAssignmentCompletion;
use App\Schedule\UseCases\SetAssignmentCompletion\SetAssignmentCompletionRequest;
use App\Shared\ValueObject\EmailAddress;
use App\User\User;
use DateTimeImmutable;
use DateTimeZone;
use PHPUnit\Framework\TestCase;
use Tests\Fakes\FakeClock;
use Tests\Fakes\FakeScheduleRepository;
class SetAssignmentCompletionTest extends TestCase
{
public function test_it_completes_an_owned_assignment_at_the_current_time(): void
{
$user = $this->user(1, 'reader@example.com');
$repository = new FakeScheduleRepository;
$schedule = $repository->create($this->schedule($user));
$now = $this->utc('2026-08-15T12:00:00');
$assignment = (new SetAssignmentCompletion(
$repository,
new FakeClock($now),
))->execute(new SetAssignmentCompletionRequest(
assignmentId: $schedule->getAssignments()[0]->getId(),
user: $user,
completed: true,
));
$this->assertSame($now, $assignment->getCompletedAt());
$this->assertSame(
$now,
$repository->findAssignmentForUser(
$assignment->getId(),
$user,
)?->getCompletedAt(),
);
}
public function test_it_preserves_the_first_completion_time(): void
{
$user = $this->user(1, 'reader@example.com');
$repository = new FakeScheduleRepository;
$schedule = $repository->create($this->schedule($user));
$assignmentId = $schedule->getAssignments()[0]->getId();
$firstCompletion = $this->utc('2026-08-15T12:00:00');
$laterCompletion = $this->utc('2026-08-15T13:00:00');
(new SetAssignmentCompletion(
$repository,
new FakeClock($firstCompletion),
))->execute(new SetAssignmentCompletionRequest(
assignmentId: $assignmentId,
user: $user,
completed: true,
));
$assignment = (new SetAssignmentCompletion(
$repository,
new FakeClock($laterCompletion),
))->execute(new SetAssignmentCompletionRequest(
assignmentId: $assignmentId,
user: $user,
completed: true,
));
$this->assertSame(
$firstCompletion,
$assignment->getCompletedAt(),
);
}
public function test_it_reopens_a_completed_assignment(): void
{
$user = $this->user(1, 'reader@example.com');
$repository = new FakeScheduleRepository;
$schedule = $repository->create($this->schedule($user));
$assignmentId = $schedule->getAssignments()[0]->getId();
$useCase = new SetAssignmentCompletion(
$repository,
new FakeClock($this->utc('2026-08-15T12:00:00')),
);
$useCase->execute(new SetAssignmentCompletionRequest(
assignmentId: $assignmentId,
user: $user,
completed: true,
));
$assignment = $useCase->execute(
new SetAssignmentCompletionRequest(
assignmentId: $assignmentId,
user: $user,
completed: false,
),
);
$this->assertNull($assignment->getCompletedAt());
}
public function test_it_hides_another_users_assignment(): void
{
$repository = new FakeScheduleRepository;
$owner = $this->user(1, 'owner@example.com');
$schedule = $repository->create($this->schedule($owner));
$this->expectException(NotFoundException::class);
$this->expectExceptionMessage('assignment not found');
(new SetAssignmentCompletion(
$repository,
new FakeClock($this->utc('2026-08-15T12:00:00')),
))->execute(new SetAssignmentCompletionRequest(
assignmentId: $schedule->getAssignments()[0]->getId(),
user: $this->user(2, 'viewer@example.com'),
completed: true,
));
}
public function test_it_requires_a_boolean_completion_value(): void
{
$this->expectException(BadRequestException::class);
$this->expectExceptionMessage('completed must be a boolean');
(new SetAssignmentCompletion(
new FakeScheduleRepository,
new FakeClock($this->utc('2026-08-15T12:00:00')),
))->execute(new SetAssignmentCompletionRequest(
assignmentId: 1,
user: $this->user(1, 'reader@example.com'),
completed: null,
));
}
private function schedule(User $user): CreateScheduleDto
{
$scheduledDate = $this->utc('2026-08-20');
return new CreateScheduleDto(
user: $user,
setName: 'Course',
elementKind: 'lesson',
startDate: $scheduledDate,
targetDate: $scheduledDate,
assignments: [
new CreateScheduleAssignmentDto(
name: 'Lesson',
kind: 'lesson',
path: ['Course', 'Lesson'],
scheduledDate: $scheduledDate,
position: 1,
),
],
);
}
private function user(int $id, string $email): User
{
return new User(
id: $id,
email: new EmailAddress($email),
passwordHash: 'hashed-password',
);
}
private function utc(string $value): DateTimeImmutable
{
return new DateTimeImmutable($value, new DateTimeZone('UTC'));
}
}