From e0924c68b3d0d446490adf9ada56ad4d0a469cf2 Mon Sep 17 00:00:00 2001 From: James Wragg <5068769+jerotire@users.noreply.github.com> Date: Fri, 16 Feb 2024 17:23:28 +0000 Subject: [PATCH] feat: Merge project/messaging (dvsa/olcs-selfserve#59) * feat: OLCS composer packages to dev-project/messaging (dvsa/olcs-selfserve#19) * feat: Messaging conversation list (dvsa/olcs-selfserve#22) * feat: Messaging conversation list * fix: Missing route from branch re-create * fix: Rename messages to conversations * fix: Unused null check * feat: Update olcs-comon lock * feat: List messages in a conversation. (dvsa/olcs-selfserve#23) * feat: Conversation messages list * feat: Controller view test * fix: Unused null check * fix: Test PR changes (case and unused var) * fix: Just added whitespace! * feat: Messaging tab visibility (dvsa/olcs-selfserve#32) * Update README.md * WIP * Tab WIP * Messaging tab view based on feature toggle only * Messaging tab logic without extra query * Change routing to conversations * Clean unused * Review improvement * Revert whitespace from bad resolution --------- Co-authored-by: Joshua License Co-authored-by: Saul Wilcox * feat: Project branch change for composer.lock * feat: Composer update due to common and transfer merges from main * fix: Navigation unit test (dvsa/olcs-selfserve#36) * Add messaging feature in NavigationTest * fix: Add once() assertions to shouldReceive() * Fix test to match CI error_reporting * Formatting improvements --------- Co-authored-by: Saul Wilcox * feat: Message list split in to two columns (dvsa/olcs-selfserve#41) * feat: Message list split in to two columns * feat: composer.lock * feat: Start conversation link (dvsa/olcs-selfserve#45) * feat: Start a new conversation link (and empty page) * fix: PR: Rename newAction to addAction * feat: Add header to new sidebar for start link (dvsa/olcs-selfserve#50) * feat: Reply to conversation (dvsa/olcs-selfserve#49) * feat: Reply to a conversation * fix: Strong types on form * feat: Messsaging new conversation form (dvsa/olcs-selfserve#53) * chore: so far * chore: so far * chore: so far * olcs-transfer bump * feat: use GOVUK-SELECT class * chore: code clean-up * bump: olcs-common * chore: bump olcs-common and olcs-transfer * Add "Messaging not disabled" to tab display conditions (dvsa/olcs-selfserve#57) * Add condition for messaging disabled for organisation * Adjust to match call count * Add full return to tests * Whitespace --------- Co-authored-by: Saul Wilcox * fix: Trying to access array key on null in navigation (dvsa/olcs-selfserve#60) * fix: swapped container interface interop for Psr (dvsa/olcs-selfserve#62) * chore: form annotation changes (dvsa/olcs-selfserve#63) * chore: revert composer.json/lock to use non-messaging project branches (dvsa/olcs-selfserve#64) --------- Co-authored-by: Wade Womersley <155439365+wadedvsa@users.noreply.github.com> Co-authored-by: Saul Wilcox <1481742+hobbyhacker0@users.noreply.github.com> Co-authored-by: Joshua License Co-authored-by: Saul Wilcox --- app/selfserve/composer.lock | 24 +- .../module/Olcs/config/module.config.php | 78 ++++-- .../Controller/ConversationsController.php | 218 +++++++++++++++++ .../ConversationsControllerFactory.php | 37 +++ .../src/Controller/Initializer/Navigation.php | 1 + .../src/Controller/Listener/Navigation.php | 37 +++ .../Controller/Listener/NavigationFactory.php | 2 +- .../Form/Model/Fieldset/Message/Create.php | 81 +++++++ .../src/Form/Model/Fieldset/Message/Reply.php | 40 ++++ .../src/Form/Model/Form/Message/Create.php | 17 ++ .../src/Form/Model/Form/Message/Reply.php | 37 +++ .../Navigation/DashboardNavigationFactory.php | 1 + .../src/Service/Data/MessagingAppOrLicNo.php | 72 ++++++ .../src/Table/Tables/messages-view.table.php | 29 +++ .../Olcs/src/Table/Tables/messages.table.php | 39 +++ .../module/Olcs/view/messages-new.phtml | 33 +++ .../module/Olcs/view/messages-view.phtml | 41 ++++ app/selfserve/module/Olcs/view/messages.phtml | 27 +++ .../partials/conversations-right-column.phtml | 10 + .../ConversationsControllerTest.php | 226 ++++++++++++++++++ .../Controller/Initializer/NavigationTest.php | 3 +- .../Controller/Listener/NavigationTest.php | 134 ++++++++--- .../Form/Lva/PsvVehiclesVehicleTest.php | 2 + .../Olcs/src/Mvc/CookieBannerListenerTest.php | 4 +- .../DashboardNavigationFactoryTest.php | 3 +- 25 files changed, 1134 insertions(+), 62 deletions(-) create mode 100644 app/selfserve/module/Olcs/src/Controller/ConversationsController.php create mode 100644 app/selfserve/module/Olcs/src/Controller/Factory/ConversationsControllerFactory.php create mode 100644 app/selfserve/module/Olcs/src/Form/Model/Fieldset/Message/Create.php create mode 100644 app/selfserve/module/Olcs/src/Form/Model/Fieldset/Message/Reply.php create mode 100644 app/selfserve/module/Olcs/src/Form/Model/Form/Message/Create.php create mode 100644 app/selfserve/module/Olcs/src/Form/Model/Form/Message/Reply.php create mode 100644 app/selfserve/module/Olcs/src/Service/Data/MessagingAppOrLicNo.php create mode 100644 app/selfserve/module/Olcs/src/Table/Tables/messages-view.table.php create mode 100644 app/selfserve/module/Olcs/src/Table/Tables/messages.table.php create mode 100644 app/selfserve/module/Olcs/view/messages-new.phtml create mode 100644 app/selfserve/module/Olcs/view/messages-view.phtml create mode 100644 app/selfserve/module/Olcs/view/messages.phtml create mode 100644 app/selfserve/module/Olcs/view/partials/conversations-right-column.phtml create mode 100644 app/selfserve/test/Olcs/src/Controller/ConversationsControllerTest.php diff --git a/app/selfserve/composer.lock b/app/selfserve/composer.lock index 1547b04a5f..2509701d27 100644 --- a/app/selfserve/composer.lock +++ b/app/selfserve/composer.lock @@ -3983,16 +3983,16 @@ }, { "name": "olcs/olcs-common", - "version": "5.0.0-beta.10", + "version": "v5.1.1", "source": { "type": "git", "url": "https://github.com/dvsa/olcs-common.git", - "reference": "530e47d0d8bc3574ded6ed980694c866894979ba" + "reference": "73b1c0cf809b50138dd1f5b471905361f1cd868e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dvsa/olcs-common/zipball/530e47d0d8bc3574ded6ed980694c866894979ba", - "reference": "530e47d0d8bc3574ded6ed980694c866894979ba", + "url": "https://api.github.com/repos/dvsa/olcs-common/zipball/73b1c0cf809b50138dd1f5b471905361f1cd868e", + "reference": "73b1c0cf809b50138dd1f5b471905361f1cd868e", "shasum": "" }, "require": { @@ -4050,9 +4050,9 @@ "notification-url": "https://packagist.org/downloads/", "description": "Common library for the OLCS Project", "support": { - "source": "https://github.com/dvsa/olcs-common/tree/5.0.0-beta.10" + "source": "https://github.com/dvsa/olcs-common/tree/v5.1.1" }, - "time": "2024-02-12T10:53:54+00:00" + "time": "2024-02-16T10:40:20+00:00" }, { "name": "olcs/olcs-logging", @@ -4108,16 +4108,16 @@ }, { "name": "olcs/olcs-transfer", - "version": "5.0.0-beta.8", + "version": "v5.1.0", "source": { "type": "git", "url": "https://github.com/dvsa/olcs-transfer.git", - "reference": "9b20f1f18e02c42775e85b87ed362765a2177ed3" + "reference": "b1fe910e1dafbf495367d16fe1953cf1aa9f88b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dvsa/olcs-transfer/zipball/9b20f1f18e02c42775e85b87ed362765a2177ed3", - "reference": "9b20f1f18e02c42775e85b87ed362765a2177ed3", + "url": "https://api.github.com/repos/dvsa/olcs-transfer/zipball/b1fe910e1dafbf495367d16fe1953cf1aa9f88b6", + "reference": "b1fe910e1dafbf495367d16fe1953cf1aa9f88b6", "shasum": "" }, "require": { @@ -4157,9 +4157,9 @@ "notification-url": "https://packagist.org/downloads/", "description": "OLCS Transfer", "support": { - "source": "https://github.com/dvsa/olcs-transfer/tree/5.0.0-beta.8" + "source": "https://github.com/dvsa/olcs-transfer/tree/v5.1.0" }, - "time": "2024-01-25T22:35:27+00:00" + "time": "2024-02-16T10:21:39+00:00" }, { "name": "olcs/olcs-utils", diff --git a/app/selfserve/module/Olcs/config/module.config.php b/app/selfserve/module/Olcs/config/module.config.php index b29b92eebd..eb30f7230e 100644 --- a/app/selfserve/module/Olcs/config/module.config.php +++ b/app/selfserve/module/Olcs/config/module.config.php @@ -18,6 +18,7 @@ use Olcs\Controller\Factory\IndexControllerFactory; use Olcs\Controller\Factory\MyDetailsControllerFactory; use Olcs\Controller\IndexController; +use Common\Service\Data as CommonDataService; use Olcs\Controller\Licence\Vehicle\ListVehicleController; use Olcs\Controller\Lva\Adapters\ApplicationPeopleAdapter; use Olcs\Controller\Lva\Adapters\LicencePeopleAdapter; @@ -45,6 +46,7 @@ use Olcs\Logging\Log\Processor\CorrelationId; use Olcs\Logging\Log\Processor\CorrelationIdFactory; use Olcs\Service\Cookie as CookieService; +use Olcs\Service\Data as DataService; use Olcs\Service\Processing as ProcessingService; use Olcs\Service\Qa as QaService; use Olcs\Session\LicenceVehicleManagement; @@ -437,6 +439,37 @@ ] ] ], + 'conversations' => [ + 'type' => 'segment', + 'options' => [ + 'route' => '/conversations[/]', + 'defaults' => [ + 'controller' => Olcs\Controller\ConversationsController::class, + 'action' => 'index' + ] + ], + 'may_terminate' => true, + 'child_routes' => [ + 'view' => [ + 'type' => 'segment', + 'options' => [ + 'route' => ':conversationId[/]', + 'defaults' => [ + 'action' => 'view', + ], + ] + ], + 'new' => [ + 'type' => 'segment', + 'options' => [ + 'route' => 'new[/]', + 'defaults' => [ + 'action' => 'add', + ], + ] + ], + ] + ], 'create_variation' => [ 'type' => 'segment', 'options' => [ @@ -1044,6 +1077,11 @@ 'label' => 'dashboard-nav-documents', 'route' => 'correspondence', ), + array( + 'id' => 'dashboard-messaging', + 'label' => 'dashboard-nav-messaging', + 'route' => 'conversations', + ), ), ), ), @@ -1301,25 +1339,26 @@ Olcs\Controller\Licence\Surrender\PrintSignReturnController::class => Olcs\Controller\Licence\Surrender\PrintSignReturnControllerFactory::class, \Olcs\Controller\Licence\Surrender\InformationChangedController::class => \Olcs\Controller\Licence\Surrender\InformationChangedControllerFactory::class, // Licence - Vehicles - \Olcs\Controller\Licence\Vehicle\AddVehicleSearchController::class => \Olcs\Controller\Licence\Vehicle\AddVehicleSearchControllerFactory::class, - \Olcs\Controller\Licence\Vehicle\AddDuplicateVehicleController::class => \Olcs\Controller\Licence\Vehicle\AddDuplicateVehicleControllerFactory::class, - \Olcs\Controller\Licence\Vehicle\RemoveVehicleController::class => \Olcs\Controller\Licence\Vehicle\RemoveVehicleControllerFactory::class, - \Olcs\Controller\Licence\Vehicle\RemoveVehicleConfirmationController::class => \Olcs\Controller\Licence\Vehicle\RemoveVehicleConfirmationControllerFactory::class, - \Olcs\Controller\Licence\Vehicle\TransferVehicleController::class => \Olcs\Controller\Licence\Vehicle\TransferVehicleControllerFactory::class, - \Olcs\Controller\Licence\Vehicle\ViewVehicleController::class => \Olcs\Controller\Licence\Vehicle\ViewVehicleControllerFactory::class, - \Olcs\Controller\Licence\Vehicle\TransferVehicleConfirmationController::class => \Olcs\Controller\Licence\Vehicle\TransferVehicleConfirmationControllerFactory::class, - \Olcs\Controller\Licence\Vehicle\Reprint\ReprintLicenceVehicleDiscController::class => \Olcs\Controller\Licence\Vehicle\Reprint\ReprintLicenceVehicleDiscControllerFactory::class, + \Olcs\Controller\Licence\Vehicle\AddVehicleSearchController::class => \Olcs\Controller\Licence\Vehicle\AddVehicleSearchControllerFactory::class, + \Olcs\Controller\Licence\Vehicle\AddDuplicateVehicleController::class => \Olcs\Controller\Licence\Vehicle\AddDuplicateVehicleControllerFactory::class, + \Olcs\Controller\Licence\Vehicle\RemoveVehicleController::class => \Olcs\Controller\Licence\Vehicle\RemoveVehicleControllerFactory::class, + \Olcs\Controller\Licence\Vehicle\RemoveVehicleConfirmationController::class => \Olcs\Controller\Licence\Vehicle\RemoveVehicleConfirmationControllerFactory::class, + \Olcs\Controller\Licence\Vehicle\TransferVehicleController::class => \Olcs\Controller\Licence\Vehicle\TransferVehicleControllerFactory::class, + \Olcs\Controller\Licence\Vehicle\ViewVehicleController::class => \Olcs\Controller\Licence\Vehicle\ViewVehicleControllerFactory::class, + \Olcs\Controller\Licence\Vehicle\TransferVehicleConfirmationController::class => \Olcs\Controller\Licence\Vehicle\TransferVehicleConfirmationControllerFactory::class, + \Olcs\Controller\Licence\Vehicle\Reprint\ReprintLicenceVehicleDiscController::class => \Olcs\Controller\Licence\Vehicle\Reprint\ReprintLicenceVehicleDiscControllerFactory::class, \Olcs\Controller\Licence\Vehicle\Reprint\ReprintLicenceVehicleDiscConfirmationController::class => \Olcs\Controller\Licence\Vehicle\Reprint\ReprintLicenceVehicleDiscConfirmationControllerFactory::class, - PromptController::class => \Olcs\Controller\PromptControllerFactory::class, + Olcs\Controller\ConversationsController::class => Olcs\Controller\Factory\ConversationsControllerFactory::class, + PromptController::class => \Olcs\Controller\PromptControllerFactory::class, // Process Signature from GOV.UK Account - \Olcs\Controller\SignatureVerificationController::class => \Olcs\Controller\SignatureVerificationControllerFactory::class, + \Olcs\Controller\SignatureVerificationController::class => \Olcs\Controller\SignatureVerificationControllerFactory::class, // LVA Controller Factories - LvaLicenceControllers\AddressesController::class => LvaLicenceControllerFactories\AddressesControllerFactory::class, - LvaLicenceControllers\BusinessDetailsController::class => LvaLicenceControllerFactories\BusinessDetailsControllerFactory::class, - LvaLicenceControllers\BusinessTypeController::class => LvaLicenceControllerFactories\BusinessTypeControllerFactory::class, - LvaLicenceControllers\ConditionsUndertakingsController::class => LvaLicenceControllerFactories\ConditionsUndertakingsControllerFactory::class, - LvaLicenceControllers\DiscsController::class => LvaLicenceControllerFactories\DiscsControllerFactory::class, - LvaLicenceControllers\OperatingCentresController::class => LvaLicenceControllerFactories\OperatingCentresControllerFactory::class, + LvaLicenceControllers\AddressesController::class => LvaLicenceControllerFactories\AddressesControllerFactory::class, + LvaLicenceControllers\BusinessDetailsController::class => LvaLicenceControllerFactories\BusinessDetailsControllerFactory::class, + LvaLicenceControllers\BusinessTypeController::class => LvaLicenceControllerFactories\BusinessTypeControllerFactory::class, + LvaLicenceControllers\ConditionsUndertakingsController::class => LvaLicenceControllerFactories\ConditionsUndertakingsControllerFactory::class, + LvaLicenceControllers\DiscsController::class => LvaLicenceControllerFactories\DiscsControllerFactory::class, + LvaLicenceControllers\OperatingCentresController::class => LvaLicenceControllerFactories\OperatingCentresControllerFactory::class, LvaLicenceControllers\OverviewController::class => LvaLicenceControllerFactories\OverviewControllerFactory::class, LvaLicenceControllers\PeopleController::class => LvaLicenceControllerFactories\PeopleControllerFactory::class, LvaLicenceControllers\SafetyController::class => LvaLicenceControllerFactories\SafetyControllerFactory::class, @@ -1425,7 +1464,7 @@ VariationTransportManagerAdapter::class => VariationTransportManagerAdapterFactory::class, VariationPeopleAdapter::class => VariationPeopleAdapterFactory::class, \Olcs\Logging\Log\Processor\CorrelationId::class => \Olcs\Logging\Log\Processor\CorrelationIdFactory::class, - ] + ], ), 'log_processors' => [ 'factories' => [ @@ -1467,6 +1506,11 @@ 'simple_date_format' => array( 'default' => 'd-m-Y' ), + 'data_services' => [ + 'factories' => [ + DataService\MessagingAppOrLicNo::class => CommonDataService\AbstractListDataServiceFactory::class, + ], + ], 'view_helpers' => array( 'factories' => [ \Olcs\View\Helper\SessionTimeoutWarning\SessionTimeoutWarning::class => \Olcs\View\Helper\SessionTimeoutWarning\SessionTimeoutWarningFactory::class, diff --git a/app/selfserve/module/Olcs/src/Controller/ConversationsController.php b/app/selfserve/module/Olcs/src/Controller/ConversationsController.php new file mode 100644 index 0000000000..026c9d3fa8 --- /dev/null +++ b/app/selfserve/module/Olcs/src/Controller/ConversationsController.php @@ -0,0 +1,218 @@ + [FeatureToggle::MESSAGING], + ]; + + protected FlashMessengerHelperService $flashMessengerHelper; + protected TableFactory $tableFactory; + protected FormHelperService $formHelperService; + + public function __construct( + NiTextTranslation $niTextTranslationUtil, + AuthorizationService $authService, + FlashMessengerHelperService $flashMessengerHelper, + TableFactory $tableFactory, + FormHelperService $formHelperService + ) { + $this->flashMessengerHelper = $flashMessengerHelper; + $this->tableFactory = $tableFactory; + $this->formHelperService = $formHelperService; + + parent::__construct($niTextTranslationUtil, $authService); + } + + public function indexAction(): ViewModel + { + $params = [ + 'page' => $this->params()->fromQuery('page', 1), + 'limit' => $this->params()->fromQuery('limit', 10), + 'sort' => $this->params()->fromQuery('sort', 'd.issuedDate'), + 'order' => $this->params()->fromQuery('order', 'DESC'), + 'organisation' => $this->getCurrentOrganisationId(), + 'query' => $this->params()->fromQuery(), + ]; + + $response = $this->handleQuery(ByOrganisationQuery::create($params)); + + if ($response->isOk()) { + $messages = $response->getResult(); + } else { + $this->flashMessengerHelper->addErrorMessage('unknown-error'); + $messages = []; + } + + $table = $this->tableFactory + ->buildTable('messages', $messages, $params); + + $view = new ViewModel(['table' => $table]); + $view->setTemplate('messages'); + + return $view; + } + + /** + * @throws \Exception + */ + public function addAction(): ViewModel + { + $form = $this->formHelperService->createForm(CreateForm::class, true, false); + if ($this->getRequest()->isPost()) { + $form->setData($this->getRequest()->getPost()); + if ($form->isValid()) { + return $this->submitConversation($form); + } + } + + $view = new ViewModel(); + $view->setVariable('form', $form); + $view->setTemplate('messages-new'); + + return $view; + } + + /** + * @return Response|ViewModel + * @throws \Exception + */ + private function submitConversation(\Laminas\Form\Form $form) + { + $response = $this->handleCommand($this->mapFormDataToCommand($form)); + if (!$response->isOk()) { + $this->flashMessengerHelper->addErrorMessage('There was an server error when submitting your conversation; please try later'); + return $this->addAction(); + } + + $conversationId = $response->getResult()['id']['conversation'] ?? null; + if (empty($conversationId)) { + $this->flashMessengerHelper->addErrorMessage('There was an server error when submitting your conversation; please try later'); + return $this->addAction(); + } + + $this->flashMessengerHelper->addSuccessMessage('Conversation was created successfully'); + return $this->redirect()->toRoute('conversations/view', ['conversationId' => $conversationId]); + } + + /** + * @throws \Exception + */ + private function mapFormDataToCommand(\Laminas\Form\Form $form): Create + { + $data = $form->getData(); + $processedData = [ + 'messageSubject' => $data['form-actions']['messageSubject'], + 'messageContent' => $data['form-actions']['messageContent'], + ]; + + $appOrLicNoPrefix = substr($data['form-actions']['appOrLicNo'], 0, 1); + $appOrLicNoSuffix = substr($data['form-actions']['appOrLicNo'], 1); + switch($appOrLicNoPrefix) { + case MessagingAppOrLicNo::PREFIX_LICENCE: + $processedData['licence'] = $appOrLicNoSuffix; + break; + case MessagingAppOrLicNo::PREFIX_APPLICATION: + $processedData['application'] = $appOrLicNoSuffix; + break; + default: + throw new \Exception('Invalid prefix on appOrLicNo'); + } + + return Create::create($processedData); + } + + /** @return ViewModel|Response */ + public function viewAction() + { + $params = [ + 'page' => $this->params()->fromQuery('page', 1), + 'limit' => $this->params()->fromQuery('limit', 10), + 'conversation' => $this->params()->fromRoute('conversationId'), + 'query' => $this->params()->fromQuery(), + ]; + + $response = $this->handleQuery(ByConversationQuery::create($params)); + + if ($response->isOk()) { + $messages = $response->getResult(); + } else { + $this->flashMessengerHelper->addErrorMessage('unknown-error'); + $messages = []; + } + + $form = $this->formHelperService->createForm(ReplyForm::class, true, false); + $this->formHelperService->setFormActionFromRequest($form, $this->getRequest()); + + $table = $this->tableFactory + ->buildTable('messages-view', $messages, $params); + + $view = new ViewModel( + [ + 'table' => $table, + 'form' => $form, + ], + ); + $view->setTemplate('messages-view'); + + if ($this->getRequest()->isPost() && $this->params()->fromPost('action') === 'reply') { + return $this->parseReply($view, $form); + } + + return $view; + } + + /** @return Response|ViewModel */ + protected function parseReply(ViewModel $view, Form $form) + { + $form->setData((array)$this->params()->fromPost()); + $form->get('id')->setValue($this->params()->fromRoute('conversation')); + + if (!$form->isValid()) { + return $view; + } + + $response = $this->handleCommand( + CreateMessageCommand::create( + [ + 'conversation' => $this->params()->fromRoute('conversationId'), + 'messageContent' => $form->get('form-actions')->get('reply')->getValue(), + ], + ), + ); + + if ($response->isOk()) { + $this->flashMessengerHelper->addSuccessMessage('Reply submitted successfully'); + return $this->redirect()->toRoute('conversations/view', $this->params()->fromRoute()); + } + + $this->handleErrors($response->getResult()); + + return parent::indexAction(); + } +} diff --git a/app/selfserve/module/Olcs/src/Controller/Factory/ConversationsControllerFactory.php b/app/selfserve/module/Olcs/src/Controller/Factory/ConversationsControllerFactory.php new file mode 100644 index 0000000000..c4f4a45b37 --- /dev/null +++ b/app/selfserve/module/Olcs/src/Controller/Factory/ConversationsControllerFactory.php @@ -0,0 +1,37 @@ +get(NiTextTranslation::class); + $authService = $container->get(AuthorizationService::class); + $flashMessengerHelper = $container->get(FlashMessengerHelperService::class); + $tableFactory = $container->get(TableFactory::class); + $formHelperService = $container->get(FormHelperService::class); + + return new ConversationsController( + $niTextTranslationUtil, + $authService, + $flashMessengerHelper, + $tableFactory, + $formHelperService, + ); + } +} diff --git a/app/selfserve/module/Olcs/src/Controller/Initializer/Navigation.php b/app/selfserve/module/Olcs/src/Controller/Initializer/Navigation.php index 5a7ea2979e..ab90c9b857 100644 --- a/app/selfserve/module/Olcs/src/Controller/Initializer/Navigation.php +++ b/app/selfserve/module/Olcs/src/Controller/Initializer/Navigation.php @@ -1,4 +1,5 @@ shouldShowPermitsTab($e); $this->togglePermitsMenus($shouldShowPermitsTab); + + $shouldShowMessagesTab = $this->shouldShowMessagesTab(); + $this->toggleMessagesTab($shouldShowMessagesTab); } /** @@ -153,6 +157,39 @@ private function referedFromGovUkPermits(MvcEvent $e): bool return in_array($referer->getUri(), $this->govUkReferers); } + /** + * Toggle Messaging menus + * + * @param bool $shouldShowMessagesTab whether to show messages tab + * + * @return void + */ + private function toggleMessagesTab(bool $shouldShowMessagesTab): void + { + $this->navigation->findBy('id', 'dashboard-messaging') + ->setVisible($shouldShowMessagesTab); + } + + private function shouldShowMessagesTab(): bool + { + $messagingToggleEnabled = $this->querySender->featuresEnabled([FeatureToggle::MESSAGING]); + + $userData = $this->identity->getUserData(); + + $hasOrganisationSubmittedLicenceApplication = $userData['hasOrganisationSubmittedLicenceApplication']; + + $isMessagingEnabled = false; + if (isset($userData['organisationUsers'][0]['organisation']['isMessagingDisabled'])) { + $isMessagingEnabled = $userData['organisationUsers'][0]['organisation']['isMessagingDisabled'] === false; + } + + return ( + $messagingToggleEnabled && + $hasOrganisationSubmittedLicenceApplication && + $isMessagingEnabled + ); + } + /** * For the benefit of unit testing * diff --git a/app/selfserve/module/Olcs/src/Controller/Listener/NavigationFactory.php b/app/selfserve/module/Olcs/src/Controller/Listener/NavigationFactory.php index 82fd2db1a3..d6005767be 100644 --- a/app/selfserve/module/Olcs/src/Controller/Listener/NavigationFactory.php +++ b/app/selfserve/module/Olcs/src/Controller/Listener/NavigationFactory.php @@ -16,7 +16,7 @@ class NavigationFactory implements FactoryInterface * * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function __invoke(ContainerInterface $container, $requestedName, array $options = null) : Navigation + public function __invoke(ContainerInterface $container, $requestedName, array $options = null): Navigation { return new Navigation( $container->get('navigation'), diff --git a/app/selfserve/module/Olcs/src/Form/Model/Fieldset/Message/Create.php b/app/selfserve/module/Olcs/src/Form/Model/Fieldset/Message/Create.php new file mode 100644 index 0000000000..9ec239155e --- /dev/null +++ b/app/selfserve/module/Olcs/src/Form/Model/Fieldset/Message/Create.php @@ -0,0 +1,81 @@ +getData('licapp'); + + if (count($data) !== 0) { + return $data; + } + + $response = $this->handleQuery( + TransferQry\Messaging\ApplicationLicenceList\ByOrganisation::create([]) + ); + + if (!$response->isOk()) { + throw new DataServiceException('Unknown Error - ' . json_encode($response)); + } + + $result = $response->getResult(); + + $this->setData('licapp', ($result['results'] ?? null)); + + return $this->getData('licapp'); + } + + public function formatDataForGroups(array $data): array + { + $optionData = [ + [ + 'label' => 'Licence', + 'options' => [] + ], + [ + 'label' => 'Application', + 'options' => [] + ] + ]; + + $optionData[0]['options'] = $data['licences']; + $optionData[1]['options'] = $data['applications']; + + $this->prefixArrayKey($optionData[0]['options'], static::PREFIX_LICENCE); + $this->prefixArrayKey($optionData[1]['options'], static::PREFIX_APPLICATION); + + return $optionData; + } + + private function prefixArrayKey(array &$array, string $prefix): void + { + foreach ($array as $k => $v) + { + $array[$prefix . $k] = $v; + unset($array[$k]); + } + } +} diff --git a/app/selfserve/module/Olcs/src/Table/Tables/messages-view.table.php b/app/selfserve/module/Olcs/src/Table/Tables/messages-view.table.php new file mode 100644 index 0000000000..adde0edad7 --- /dev/null +++ b/app/selfserve/module/Olcs/src/Table/Tables/messages-view.table.php @@ -0,0 +1,29 @@ + [ + 'class' => 'no-row-border-separator' + ], + 'variables' => [ + 'id' => 'messages-list-table', + 'title' => 'Messages', + 'empty_message' => 'There are no message records linked to this conversation to display' + ], + 'settings' => [ + 'paginate' => [ + 'limit' => [ + 'options' => [10, 25, 50], + ], + ], + ], + 'columns' => [ + [ + 'name' => 'id', + 'formatter' => ExternalConversationMessage::class, + ], + ], +]; diff --git a/app/selfserve/module/Olcs/src/Table/Tables/messages.table.php b/app/selfserve/module/Olcs/src/Table/Tables/messages.table.php new file mode 100644 index 0000000000..ae1c0ee2f8 --- /dev/null +++ b/app/selfserve/module/Olcs/src/Table/Tables/messages.table.php @@ -0,0 +1,39 @@ + [ + 'title' => 'dashboard-messages.table.title', + 'titleSingular' => 'dashboard-messages.table.title', + 'empty_message' => 'dashboard-messages.empty-message', + ], + 'settings' => [ + 'crud' => [ + 'formName' => 'messages', + 'actions' => [], + ], + 'paginate' => [ + 'limit' => [ + 'default' => 10, + 'options' => [10, 25, 50], + ], + ], + ], + 'attributes' => [], + 'columns' => [ + [ + 'title' => 'Subject', + 'name' => 'id', + 'formatter' => ExternalConversationLink::class, + ], + [ + 'title' => 'Status', + 'name' => 'status', + 'formatter' => ExternalConversationStatus::class, + ], + ], +]; diff --git a/app/selfserve/module/Olcs/view/messages-new.phtml b/app/selfserve/module/Olcs/view/messages-new.phtml new file mode 100644 index 0000000000..ae6ad71053 --- /dev/null +++ b/app/selfserve/module/Olcs/view/messages-new.phtml @@ -0,0 +1,33 @@ +partial( + 'partials/page-header-simple', + [ + 'pageTitle' => $this->translate('dashboard.messages.new.title'), + ], +); +?> + +
+
+ flashMessengerAll(); + + /* @var \Laminas\View\Helper\Navigation\Menu $menu */ + $menu = $this->navigation($this->navigation('navigation')->getContainer()->findBy('id', 'dashboard-licences-applications'))->menu(); + + echo $menu->setMinDepth(0) + ->setMaxDepth(0) + ->setPartial('partials/tabs-nav'); + ?> + +
+ formErrors($this->form); + echo $this->form($this->form); + ?> +
+ +
+ + partial('partials/conversations-right-column'); ?> +
diff --git a/app/selfserve/module/Olcs/view/messages-view.phtml b/app/selfserve/module/Olcs/view/messages-view.phtml new file mode 100644 index 0000000000..db5596f432 --- /dev/null +++ b/app/selfserve/module/Olcs/view/messages-view.phtml @@ -0,0 +1,41 @@ +partial( + 'partials/page-header-simple', + [ + 'pageTitle' => $this->translate('dashboard.messages.view.title'), + ], +); +?> + +
+
+ flashMessengerAll(); + + /* @var \Laminas\View\Helper\Navigation\Menu $menu */ + $menu = $this->navigation($this->navigation('navigation')->getContainer()->findBy('id', 'dashboard-licences-applications'))->menu(); + + echo $menu->setMinDepth(0) + ->setMaxDepth(0) + ->setPartial('partials/tabs-nav'); + ?> +
+ + + Send a reply + + +
+ formErrors($this->form); + echo $this->form($this->form); + ?> +
+
+ table; + ?> +
+ + partial('partials/conversations-right-column'); ?> +
diff --git a/app/selfserve/module/Olcs/view/messages.phtml b/app/selfserve/module/Olcs/view/messages.phtml new file mode 100644 index 0000000000..ce75193bf0 --- /dev/null +++ b/app/selfserve/module/Olcs/view/messages.phtml @@ -0,0 +1,27 @@ +partial( + 'partials/page-header-simple', + [ + 'pageTitle' => $this->translate('dashboard.messages.title'), + ], +); +?> + +
+
+ flashMessengerAll(); + + /* @var \Laminas\View\Helper\Navigation\Menu $menu */ + $menu = $this->navigation($this->navigation('navigation')->getContainer()->findBy('id', 'dashboard-licences-applications'))->menu(); + + echo $menu->setMinDepth(0) + ->setMaxDepth(0) + ->setPartial('partials/tabs-nav'); + + echo $this->table; + ?> +
+ + partial('partials/conversations-right-column'); ?> +
diff --git a/app/selfserve/module/Olcs/view/partials/conversations-right-column.phtml b/app/selfserve/module/Olcs/view/partials/conversations-right-column.phtml new file mode 100644 index 0000000000..e4723d7836 --- /dev/null +++ b/app/selfserve/module/Olcs/view/partials/conversations-right-column.phtml @@ -0,0 +1,10 @@ + diff --git a/app/selfserve/test/Olcs/src/Controller/ConversationsControllerTest.php b/app/selfserve/test/Olcs/src/Controller/ConversationsControllerTest.php new file mode 100644 index 0000000000..d37c63e44b --- /dev/null +++ b/app/selfserve/test/Olcs/src/Controller/ConversationsControllerTest.php @@ -0,0 +1,226 @@ +mockNiTextTranslationUtil = m::mock(NiTextTranslation::class)->makePartial(); + $this->mockAuthService = m::mock(AuthorizationService::class)->makePartial(); + $this->mockFlashMessengerHelper = m::mock(FlashMessengerHelperService::class)->makePartial(); + $this->mockTableFactory = m::mock(TableFactory::class)->makePartial(); + $this->mockFormHelperService = m::mock(FormHelperService::class)->makePartial(); + $this->mockForm = m::mock(Form::class); + $this->mockParams = m::mock(Params::class); + + $this->sut = m::mock(Sut::class) + ->makePartial() + ->shouldAllowMockingProtectedMethods(); + + $reflectionClass = new ReflectionClass(Sut::class); + $this->setMockedProperties($reflectionClass, 'niTextTranslationUtil', $this->mockNiTextTranslationUtil); + $this->setMockedProperties($reflectionClass, 'authService', $this->mockAuthService); + $this->setMockedProperties($reflectionClass, 'flashMessengerHelper', $this->mockFlashMessengerHelper); + $this->setMockedProperties($reflectionClass, 'tableFactory', $this->mockTableFactory); + $this->setMockedProperties($reflectionClass, 'formHelperService', $this->mockFormHelperService); + + $this->mockFormHelperService->shouldReceive('createForm') + ->once() + ->with(Reply::class, true, false) + ->andReturn($this->mockForm); + + $this->mockFormHelperService->shouldReceive('setFormActionFromRequest') + ->once() + ->withArgs( + function ($form, $request) { + $this->assertInstanceOf(Form::class, $form); + return true; + }, + ); + } + + public function setMockedProperties(ReflectionClass $reflectionClass, string $property, $value): void + { + $reflectionProperty = $reflectionClass->getProperty($property); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($this->sut, $value); + } + + public function testViewAction(): void + { + $mockResponse = m::mock(Response::class); + $mockResponse->shouldReceive('isOk') + ->andReturn(true); + $mockResponse->shouldReceive('getResult') + ->andReturn([]); + + $mockHandleQuery = m::mock(HandleQuery::class) + ->makePartial(); + $mockHandleQuery->shouldReceive('__invoke') + ->andReturn($mockResponse); + + $this->mockParams->shouldReceive('fromQuery') + ->with('page', 1) + ->andReturn(1); + $this->mockParams->shouldReceive('fromQuery') + ->with('limit', 10) + ->andReturn(10); + $this->mockParams->shouldReceive('fromQuery') + ->withNoArgs() + ->andReturn([]); + $this->mockParams->shouldReceive('fromRoute') + ->with('conversationId') + ->andReturn(1); + + $this->sut->shouldReceive('params') + ->andReturn($this->mockParams); + $this->sut->shouldReceive('plugin') + ->with('handleQuery') + ->andReturn($mockHandleQuery); + + $table = ''; + + $this->mockTableFactory->shouldReceive('buildTable') + ->with( + 'messages-view', + [], + ['page' => 1, 'limit' => 10, 'conversation' => 1, 'query' => []], + ) + ->andReturn($table); + + $view = $this->sut->viewAction(); + $this->assertInstanceOf(ViewModel::class, $view); + $this->assertEquals($table, $view->getVariable('table')); + } + + public function testReply(): void + { + $mockRequest = m::mock(Request::class); + $mockRequest->shouldReceive('isPost') + ->once() + ->andReturn(true); + + $this->mockParams->shouldReceive('fromPost') + ->once() + ->with('action') + ->andReturn('reply'); + $this->mockParams->shouldReceive('fromPost') + ->once() + ->withNoArgs() + ->andReturn(['a' => 'b']); + $this->mockParams->shouldReceive('fromRoute') + ->once() + ->with('conversation') + ->andReturn('1'); + $this->mockParams->shouldReceive('fromRoute') + ->once() + ->withNoArgs() + ->andReturn(['a' => 'b']); + + $this->sut->shouldReceive('getRequest') + ->twice() + ->andReturn($mockRequest); + + $mockCommandReturn = m::mock(Response::class); + $mockCommandReturn->shouldReceive('isOk') + ->once() + ->andReturn(true); + + $mockCommandHandler = m::mock(HandleCommand::class); + $mockCommandHandler->shouldReceive('__invoke') + ->once() + ->withArgs( + function ($command) { + $this->assertInstanceOf(CreateMessageCommand::class, $command); + + return true; + }, + ) + ->andReturn($mockCommandReturn); + + $this->sut->shouldReceive('plugin') + ->with('handleCommand') + ->andReturn($mockCommandHandler); + + $this->mockForm->shouldReceive('setData') + ->once() + ->with(['a' => 'b']); + + $mockFormElement = m::mock(Text::class); + $mockFormElement->shouldReceive('setValue') + ->once() + ->with('1'); + $mockFormElement->shouldReceive('getValue') + ->once() + ->andReturn('abc'); + + $this->mockForm->shouldReceive('get') + ->once() + ->with('id') + ->andReturn($mockFormElement); + + $mockFormActionsElement = m::mock(Fieldset::class); + $mockFormActionsElement->shouldReceive('get') + ->once() + ->with('reply') + ->andReturn($mockFormElement); + $this->mockForm->shouldReceive('get') + ->once() + ->with('form-actions') + ->andReturn($mockFormActionsElement); + + $this->mockForm->shouldReceive('isValid') + ->once() + ->with() + ->andReturn(true); + + $this->mockFlashMessengerHelper->shouldReceive('addSuccessMessage') + ->once() + ->with('Reply submitted successfully'); + + $mockViewModel = m::mock(ViewModel::class); + $mockViewModel->shouldReceive('getVariable') + ->once() + ->with('table') + ->andReturn('
'); + + $mockRedirect = m::mock(Redirect::class); + $mockRedirect->shouldReceive('toRoute') + ->once() + ->with('conversations/view', ['a' => 'b']) + ->andReturn($mockViewModel); + + $this->sut->shouldReceive('plugin') + ->once() + ->with('redirect') + ->andReturn($mockRedirect); + + $this->testViewAction(); + } +} diff --git a/app/selfserve/test/Olcs/src/Controller/Initializer/NavigationTest.php b/app/selfserve/test/Olcs/src/Controller/Initializer/NavigationTest.php index 18f08c8c2f..377aceac69 100644 --- a/app/selfserve/test/Olcs/src/Controller/Initializer/NavigationTest.php +++ b/app/selfserve/test/Olcs/src/Controller/Initializer/NavigationTest.php @@ -1,4 +1,5 @@ mockQuerySender = m::mock(QuerySender::class); $this->mockIdentity = m::mock(RbacUser::class); $this->sut = new NavigationListener($this->mockNavigation, $this->mockQuerySender, $this->mockIdentity); + + $this->dashboardPermitsKey = 'dashboard-permits'; + $this->dashboardPermitsPage = new Uri(); + + $this->dashboardMessagingKey = 'dashboard-messaging'; + $this->dashboardMessagingPage = new Uri(); + $this->messagingToggle = 'messaging'; } public function testAttach() @@ -50,16 +57,34 @@ public function testAttach() public function testOnDispatchWithNoReferalAnonymousUser() { - $dashboardPermitsKey = 'dashboard-permits'; - $dashboardPermitsPage = new Uri(); - $this->mockIdentity->shouldReceive('isAnonymous')->once()->withNoArgs()->andReturn(true); + $this->mockIdentity->expects('getUserData') + ->once() + ->andReturn([ + 'hasOrganisationSubmittedLicenceApplication' => false, + 'organisationUsers' => [ + 0 => [ + 'organisation' => [ + 'isMessagingDisabled' => false + ] + ] + ] + ]); + + $this->mockQuerySender->shouldReceive('featuresEnabled')->with([$this->messagingToggle])->once(); + + $this->mockNavigation + ->shouldReceive('findBy') + ->with('id', $this->dashboardPermitsKey) + ->twice() + ->andReturn($this->dashboardPermitsPage); + $this->mockNavigation ->shouldReceive('findBy') - ->with('id', $dashboardPermitsKey) + ->with('id', $this->dashboardMessagingKey) ->twice() - ->andReturn($dashboardPermitsPage); + ->andReturn($this->dashboardMessagingPage); $request = m::mock(HttpRequest::class); $request->shouldReceive('getHeader')->once()->with('referer')->andReturn(false); @@ -72,7 +97,12 @@ public function testOnDispatchWithNoReferalAnonymousUser() $this->assertEquals( false, - $this->mockNavigation->findBy('id', $dashboardPermitsKey)->getVisible() + $this->mockNavigation->findBy('id', $this->dashboardPermitsKey)->getVisible() + ); + + $this->assertEquals( + false, + $this->mockNavigation->findBy('id', $this->dashboardMessagingKey)->getVisible() ); } @@ -81,18 +111,35 @@ public function testOnDispatchWithNoReferalAnonymousUser() */ public function testOnDispatchWithNoReferal($eligibleForPermits) { - $dashboardPermitsKey = 'dashboard-permits'; - $dashboardPermitsPage = new Uri(); - $this->mockIdentity->shouldReceive('isAnonymous')->once()->withNoArgs()->andReturn(false); + $this->mockIdentity->expects('getUserData') - ->andReturn(['eligibleForPermits' => $eligibleForPermits]); + ->twice() + ->andReturn([ + 'eligibleForPermits' => $eligibleForPermits, + 'hasOrganisationSubmittedLicenceApplication' => false, + 'organisationUsers' => [ + 0 => [ + 'organisation' => [ + 'isMessagingDisabled' => false + ] + ] + ] + ]); + + $this->mockQuerySender->shouldReceive('featuresEnabled')->with([$this->messagingToggle])->once(); $this->mockNavigation ->shouldReceive('findBy') - ->with('id', $dashboardPermitsKey) + ->with('id', $this->dashboardPermitsKey) ->twice() - ->andReturn($dashboardPermitsPage); + ->andReturn($this->dashboardPermitsPage); + + $this->mockNavigation + ->shouldReceive('findBy') + ->with('id', $this->dashboardMessagingKey) + ->once() + ->andReturn($this->dashboardMessagingPage); $request = m::mock(HttpRequest::class); $request->shouldReceive('getHeader')->once()->with('referer')->andReturn(false); @@ -105,7 +152,7 @@ public function testOnDispatchWithNoReferal($eligibleForPermits) $this->assertEquals( $eligibleForPermits, - $this->mockNavigation->findBy('id', $dashboardPermitsKey)->getVisible() + $this->mockNavigation->findBy('id', $this->dashboardPermitsKey)->getVisible() ); } @@ -119,8 +166,6 @@ public function dpDispatchNoReferer() public function testOnDispatchWithGovUkReferalMatch() { - $dashboardPermitsKey = 'dashboard-permits'; - $dashboardPermitsPage = new Uri(); $uri = 'uri'; $this->sut->setGovUkReferers([$uri]); @@ -130,11 +175,32 @@ public function testOnDispatchWithGovUkReferalMatch() $request = m::mock(HttpRequest::class); $request->shouldReceive('getHeader')->once()->with('referer')->andReturn($referer); + $this->mockIdentity->expects('getUserData') + ->once() + ->andReturn([ + 'hasOrganisationSubmittedLicenceApplication' => false, + 'organisationUsers' => [ + 0 => [ + 'organisation' => [ + 'isMessagingDisabled' => false + ] + ] + ] + ]); + + $this->mockQuerySender->shouldReceive('featuresEnabled')->once()->with([$this->messagingToggle]); + $this->mockNavigation ->shouldReceive('findBy') ->twice() - ->with('id', $dashboardPermitsKey) - ->andReturn($dashboardPermitsPage); + ->with('id', $this->dashboardPermitsKey) + ->andReturn($this->dashboardPermitsPage); + + $this->mockNavigation + ->shouldReceive('findBy') + ->with('id', $this->dashboardMessagingKey) + ->once() + ->andReturn($this->dashboardMessagingPage); /** @var \Laminas\Mvc\MvcEvent | m\MockInterface $mockEvent */ $mockEvent = m::mock(\Laminas\Mvc\MvcEvent::class); @@ -143,7 +209,7 @@ public function testOnDispatchWithGovUkReferalMatch() $this->sut->onDispatch($mockEvent); $this->assertTrue( - $this->mockNavigation->findBy('id', $dashboardPermitsKey)->getVisible() + $this->mockNavigation->findBy('id', $this->dashboardPermitsKey)->getVisible() ); } @@ -152,22 +218,34 @@ public function testOnDispatchWithGovUkReferalMatch() */ public function testOnDispatchWithNoGovUkReferal($eligibleForPermits) { - $dashboardPermitsKey = 'dashboard-permits'; - $dashboardPermitsPage = new Uri(); - $this->mockIdentity->shouldReceive('isAnonymous') - ->once() - ->withNoArgs() ->andReturn(false); $this->mockIdentity->expects('getUserData') - ->andReturn(['eligibleForPermits' => $eligibleForPermits]); + ->twice() + ->andReturn([ + 'eligibleForPermits' => $eligibleForPermits, + 'hasOrganisationSubmittedLicenceApplication' => false, + 'organisationUsers' => [ + 0 => [ + 'organisation' => [ + 'isMessagingDisabled' => false + ] + ] + ] + ]); $this->mockNavigation ->shouldReceive('findBy') ->twice() - ->with('id', $dashboardPermitsKey) - ->andReturn($dashboardPermitsPage); + ->with('id', $this->dashboardPermitsKey) + ->andReturn($this->dashboardPermitsPage); + + $this->mockNavigation + ->shouldReceive('findBy') + ->once() + ->with('id', $this->dashboardMessagingKey) + ->andReturn($this->dashboardMessagingPage); //mock the http referer - this will be checked against our list of gov.uk referers (and won't match) $referer = m::mock(HttpReferer::class); @@ -179,11 +257,13 @@ public function testOnDispatchWithNoGovUkReferal($eligibleForPermits) $mockEvent = m::mock(\Laminas\Mvc\MvcEvent::class); $mockEvent->shouldReceive('getRequest')->once()->withNoArgs()->andReturn($request); + $this->mockQuerySender->shouldReceive('featuresEnabled')->once()->with([$this->messagingToggle]); + $this->sut->onDispatch($mockEvent); $this->assertEquals( $eligibleForPermits, - $this->mockNavigation->findBy('id', $dashboardPermitsKey)->getVisible() + $this->mockNavigation->findBy('id', $this->dashboardPermitsKey)->getVisible() ); } diff --git a/app/selfserve/test/Olcs/src/FormService/Form/Lva/PsvVehiclesVehicleTest.php b/app/selfserve/test/Olcs/src/FormService/Form/Lva/PsvVehiclesVehicleTest.php index 2ff8d79e3e..a04e1c62f2 100644 --- a/app/selfserve/test/Olcs/src/FormService/Form/Lva/PsvVehiclesVehicleTest.php +++ b/app/selfserve/test/Olcs/src/FormService/Form/Lva/PsvVehiclesVehicleTest.php @@ -38,9 +38,11 @@ public function testAlterForm() $this->fsm->setService('lva-vehicles-vehicle', $mockVehiclesVehicle); $mockVehiclesVehicle->shouldReceive('alterForm') + ->once() ->with($mockForm); $this->formHelper->shouldReceive('remove') + ->once() ->with($mockForm, 'licence-vehicle->receivedDate'); $this->sut->alterForm($mockForm, $params); diff --git a/app/selfserve/test/Olcs/src/Mvc/CookieBannerListenerTest.php b/app/selfserve/test/Olcs/src/Mvc/CookieBannerListenerTest.php index 0c1fe495b8..7d6c8006b0 100644 --- a/app/selfserve/test/Olcs/src/Mvc/CookieBannerListenerTest.php +++ b/app/selfserve/test/Olcs/src/Mvc/CookieBannerListenerTest.php @@ -64,7 +64,7 @@ public function setUp(): void public function testAttach() { $em = m::mock(EventManagerInterface::class); - $em->shouldReceive('attach')->with(MvcEvent::EVENT_ROUTE, [$this->sut, 'onRoute'], 1); + $em->shouldReceive('attach')->once()->with(MvcEvent::EVENT_ROUTE, [$this->sut, 'onRoute'], 1); $this->sut->attach($em); } @@ -74,7 +74,7 @@ public function testOnRouteNonHttp() $request = m::mock(); $event = m::mock(MvcEvent::class); - $event->shouldReceive('getRequest')->andReturn($request); + $event->shouldReceive('getRequest')->once()->andReturn($request); $this->sut->onRoute($event); } diff --git a/app/selfserve/test/Olcs/src/Navigation/DashboardNavigationFactoryTest.php b/app/selfserve/test/Olcs/src/Navigation/DashboardNavigationFactoryTest.php index 6d00e3ab93..04fdedb567 100644 --- a/app/selfserve/test/Olcs/src/Navigation/DashboardNavigationFactoryTest.php +++ b/app/selfserve/test/Olcs/src/Navigation/DashboardNavigationFactoryTest.php @@ -3,7 +3,6 @@ namespace OlcsTest\Navigation; use PHPUnit_Framework_TestCase; - use Olcs\Navigation\DashboardNavigationFactory; /** @@ -14,7 +13,7 @@ class DashboardNavigationFactoryTest extends \PHPUnit\Framework\TestCase { public function testGetName() { - $sut = new DashboardNavigationFactory; + $sut = new DashboardNavigationFactory(); $this->assertEquals('dashboard', $sut->getName()); }