authorizationChecker = $this->createMock(ActionAuthorizationChecker::class); $this->container = new DefaultContainer(); $this->container->instance(ActionAuthorizationChecker::class, $this->authorizationChecker); $this->guard = new LiveComponentPermissionGuard($this->authorizationChecker); } public function test_allows_authorized_action(): void { $component = $this->createComponent(); $params = ActionParameters::fromArray([]); $context = $this->createContext($component, $params); $permissionAttribute = new RequiresPermission('edit_post'); $this->authorizationChecker ->expects($this->once()) ->method('isAuthorized') ->with($component, 'testAction', $permissionAttribute) ->willReturn(true); // Should not throw $this->guard->check($context, $permissionAttribute); $this->assertTrue(true); } public function test_rejects_unauthorized_action(): void { $component = $this->createComponent(); $params = ActionParameters::fromArray([]); $context = $this->createContext($component, $params); $permissionAttribute = new RequiresPermission('edit_post'); $this->authorizationChecker ->expects($this->once()) ->method('isAuthorized') ->willReturn(false); $this->authorizationChecker ->expects($this->once()) ->method('isAuthenticated') ->willReturn(true); $this->authorizationChecker ->expects($this->once()) ->method('getUserPermissions') ->willReturn(['view_post']); $this->expectException(UnauthorizedActionException::class); $this->guard->check($context, $permissionAttribute); } public function test_rejects_unauthenticated_user(): void { $component = $this->createComponent(); $params = ActionParameters::fromArray([]); $context = $this->createContext($component, $params); $permissionAttribute = new RequiresPermission('edit_post'); $this->authorizationChecker ->expects($this->once()) ->method('isAuthorized') ->willReturn(false); $this->authorizationChecker ->expects($this->once()) ->method('isAuthenticated') ->willReturn(false); $this->expectException(UnauthorizedActionException::class); $this->expectExceptionMessage('requires authentication'); $this->guard->check($context, $permissionAttribute); } public function test_rejects_context_without_live_component_data(): void { $context = AttributeExecutionContext::forMethod( container: $this->container, className: ClassName::create('TestComponent'), methodName: MethodName::create('testMethod') ); $permissionAttribute = new RequiresPermission('edit_post'); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('LiveComponentContextData'); $this->guard->check($context, $permissionAttribute); } private function createComponent(): LiveComponentContract { return new TestComponent( ComponentId::create('test', 'demo'), CounterState::empty() ); } private function createContext(LiveComponentContract $component, ActionParameters $params): AttributeExecutionContext { return LiveComponentContextHelper::createForAction( container: $this->container, componentClass: ClassName::create($component::class), actionMethod: MethodName::create('testAction'), componentId: $component->id, actionParameters: $params, component: $component ); } }