questions = Mockery::mock(QuestionRepository::class); $this->answers = Mockery::mock(AnswerRepository::class); $this->policies = Mockery::mock(PolicyRepository::class); $this->versions = Mockery::mock(PolicyVersionRepository::class); $this->acceptances = Mockery::mock(AcceptanceRepository::class); $this->gate = new RegistrationGate( $this->questions, $this->answers, $this->policies, $this->versions, $this->acceptances ); } private function requiredQuestion(): Question { return new Question(offeringId: 7, label: 'Level?', isRequired: true, id: 3); } private function bookingPolicy(): Policy { return new Policy('Cancellation', 'cancellation', currentVersionId: 9, acceptanceScope: Policy::SCOPE_BOOKING, id: 1); } public function testValidatePassesWhenAnswersAndPoliciesProvided(): void { $this->questions->shouldReceive('findByOffering')->with(7, true)->andReturn([$this->requiredQuestion()]); $this->policies->shouldReceive('findForScope')->with(Policy::SCOPE_BOOKING)->andReturn([$this->bookingPolicy()]); $this->versions->shouldReceive('findById')->with(9)->andReturn(new PolicyVersion(1, 1, 'body', PolicyVersion::STATUS_PUBLISHED, null, 9)); self::assertNull($this->gate->validate(7, [3 => 'Beginner'], [9])); } public function testValidateFailsWhenRequiredQuestionUnanswered(): void { $this->questions->shouldReceive('findByOffering')->with(7, true)->andReturn([$this->requiredQuestion()]); $result = $this->gate->validate(7, [3 => ' '], [9]); self::assertInstanceOf(\WP_Error::class, $result); self::assertSame('missing_answer', $result->get_error_code()); } public function testValidateFailsWhenPolicyNotAccepted(): void { $this->questions->shouldReceive('findByOffering')->with(7, true)->andReturn([$this->requiredQuestion()]); $this->policies->shouldReceive('findForScope')->with(Policy::SCOPE_BOOKING)->andReturn([$this->bookingPolicy()]); $this->versions->shouldReceive('findById')->with(9)->andReturn(new PolicyVersion(1, 1, 'body', PolicyVersion::STATUS_PUBLISHED, null, 9)); $result = $this->gate->validate(7, [3 => 'Beginner'], []); self::assertInstanceOf(\WP_Error::class, $result); self::assertSame('policy_required', $result->get_error_code()); } public function testRecordPersistsAnswersAndAcceptances(): void { $this->questions->shouldReceive('findByOffering')->with(7, true)->andReturn([$this->requiredQuestion()]); $this->policies->shouldReceive('findForScope')->with(Policy::SCOPE_BOOKING)->andReturn([$this->bookingPolicy()]); $this->versions->shouldReceive('findById')->with(9)->andReturn(new PolicyVersion(1, 1, 'body', PolicyVersion::STATUS_PUBLISHED, null, 9)); $this->answers->shouldReceive('insert') ->once() ->with(Mockery::on(static fn (Answer $a): bool => $a->questionId === 3 && $a->registrationId === 50 && $a->answerValue === 'Beginner')); $this->acceptances->shouldReceive('insert') ->once() ->with(Mockery::on(static fn (PolicyAcceptance $a): bool => $a->policyVersionId === 9 && $a->registrationType === PolicyAcceptance::REG_LESSON && $a->registrationId === 50)); $this->gate->record(PolicyAcceptance::REG_LESSON, 50, 5, 7, [3 => 'Beginner'], [9], '203.0.113.7'); } }