CI / Tests (PHP 8.1) (pull_request) Successful in 46s
CI / Coding Standards (pull_request) Successful in 2m53s
CI / Tests (PHP 8.2) (pull_request) Successful in 44s
CI / No Debug Code (pull_request) Successful in 3s
CI / PHPStan (pull_request) Successful in 3m12s
CI / Tests (PHP 8.3) (pull_request) Successful in 2m36s
CI / Build Plugin Zip (pull_request) Skipped
Front end: the student "upcoming lessons" panel now shows each booked offering's name and length next to the time, and renders only the soonest five lessons with a "Show all" reveal. GET /bookings returns offering_title and duration_minutes so the list needs no extra request. Admin: the Scheduler and My Lessons week/list views now show the booked offering, and each lesson links to a detail view showing the policy versions the student accepted (with acceptance time and IP) and their intake answers. On My Lessons an instructor may only open their own lessons; the studio Scheduler may open any. composer test / composer lint / composer cs all pass. Co-Authored-By: Claude Opus 4.8 <[email protected]>
96 lines
3.7 KiB
PHP
96 lines
3.7 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace Unsupervised\Schedular\Tests\Unit\Booking;
|
|
|
|
use Mockery;
|
|
use Unsupervised\Schedular\Booking\LessonDetail;
|
|
use Unsupervised\Schedular\Policy\AcceptanceRepository;
|
|
use Unsupervised\Schedular\Policy\Policy;
|
|
use Unsupervised\Schedular\Policy\PolicyAcceptance;
|
|
use Unsupervised\Schedular\Policy\PolicyRepository;
|
|
use Unsupervised\Schedular\Policy\PolicyVersion;
|
|
use Unsupervised\Schedular\Policy\PolicyVersionRepository;
|
|
use Unsupervised\Schedular\Registration\Answer;
|
|
use Unsupervised\Schedular\Registration\AnswerRepository;
|
|
use Unsupervised\Schedular\Registration\Question;
|
|
use Unsupervised\Schedular\Registration\QuestionRepository;
|
|
use Unsupervised\Schedular\Tests\Unit\TestCase;
|
|
|
|
class LessonDetailTest extends TestCase
|
|
{
|
|
private AnswerRepository&Mockery\MockInterface $answers;
|
|
private QuestionRepository&Mockery\MockInterface $questions;
|
|
private AcceptanceRepository&Mockery\MockInterface $acceptances;
|
|
private PolicyRepository&Mockery\MockInterface $policies;
|
|
private PolicyVersionRepository&Mockery\MockInterface $versions;
|
|
private LessonDetail $detail;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$this->answers = Mockery::mock(AnswerRepository::class);
|
|
$this->questions = Mockery::mock(QuestionRepository::class);
|
|
$this->acceptances = Mockery::mock(AcceptanceRepository::class);
|
|
$this->policies = Mockery::mock(PolicyRepository::class);
|
|
$this->versions = Mockery::mock(PolicyVersionRepository::class);
|
|
|
|
$this->detail = new LessonDetail(
|
|
$this->answers,
|
|
$this->questions,
|
|
$this->acceptances,
|
|
$this->policies,
|
|
$this->versions
|
|
);
|
|
}
|
|
|
|
public function testAnswersPairEachAnswerWithItsQuestionLabel(): void
|
|
{
|
|
$this->answers->shouldReceive('findByRegistration')->once()->with(Answer::REG_LESSON, 7)->andReturn([
|
|
new Answer(questionId: 2, registrationType: Answer::REG_LESSON, registrationId: 7, studentId: 5, answerValue: 'Beginner'),
|
|
new Answer(questionId: 9, registrationType: Answer::REG_LESSON, registrationId: 7, studentId: 5, answerValue: null),
|
|
]);
|
|
|
|
$this->questions->shouldReceive('findById')->with(2)->andReturn(new Question(offeringId: 1, label: 'Skill level', id: 2));
|
|
$this->questions->shouldReceive('findById')->with(9)->andReturn(null);
|
|
|
|
self::assertSame(
|
|
[
|
|
['question' => 'Skill level', 'answer' => 'Beginner'],
|
|
['question' => '#9', 'answer' => '—'],
|
|
],
|
|
$this->detail->answers(7)
|
|
);
|
|
}
|
|
|
|
public function testAcceptancesResolvePolicyTitleVersionAndAuditTrail(): void
|
|
{
|
|
$this->acceptances->shouldReceive('findByRegistration')->once()->with(PolicyAcceptance::REG_LESSON, 7)->andReturn([
|
|
new PolicyAcceptance(
|
|
policyVersionId: 4,
|
|
studentId: 5,
|
|
registrationType: PolicyAcceptance::REG_LESSON,
|
|
registrationId: 7,
|
|
ipAddress: '1.2.3.4',
|
|
acceptedAt: '2026-07-01 10:00:00'
|
|
),
|
|
]);
|
|
|
|
$this->versions->shouldReceive('findById')->with(4)->andReturn(new PolicyVersion(policyId: 3, versionNumber: 2, id: 4));
|
|
$this->policies->shouldReceive('findById')->with(3)->andReturn(new Policy(title: 'Cancellation', slug: 'cancellation', id: 3));
|
|
|
|
self::assertSame(
|
|
[
|
|
[
|
|
'policy' => 'Cancellation',
|
|
'version' => 'v2',
|
|
'accepted_at' => '2026-07-01 10:00:00',
|
|
'ip' => '1.2.3.4',
|
|
],
|
|
],
|
|
$this->detail->acceptances(7)
|
|
);
|
|
}
|
|
}
|