I'm trying to test Event Listener in Laravel.
This is my listener:
class FlashNotifier
{
public function handleMenuItemWasStored()
{
Session::flash('flash-status', 'success');
Session::flash('flash-message', 'Item was stored.');
}
public function subscribe($events)
{
$events->listen(
MenuItemWasStored::class,
'\App\Listeners\Menu\FlashNotifier#handleMenuItemWasStored'
);
}
}
And this is the test I came up so far:
public function testEventListenerWasTriggered()
{
$listener = Mockery::mock('App\Listeners\Menu\FlashNotifier');
$d = new Dispatcher;
$listener->shouldReceive('handleMenuItemWasStored')->once();
$d->fire('App\Events\Menu\MenuItemWasStored');
}
However, I get the following exception:
1) FlashListenerTest::testEventListenerWasTriggered
Mockery\Exception\InvalidCountException: Method handleMenuItemWasStored() from Mockery_1_App_Listeners_Menu_FlashNotifier should be called
exactly 1 times but called 0 times.
What am I doing wrong?
Related
I am upgrading a project from Laravel 5 to Laravel 9, and one of the Controller methods seems to break and I cant figure out why. It works perfectly fine in Laravel 5, I get all the models returned. It fails when trying to load the 'liveConfig' and 'draftConfig' models.
Error
PHP Error: Call to a member function addEagerConstraints() on null in /var/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php
Controller
public function show($siteId)
{
return auth()->user()->editing()->findOrFail($siteId)->augmented();
}
Relationships
public function liveConfig()
{
if (!$this->theme) {
return;
}
return $this->hasOne(LiveConfig::class)->where('status',
'live');
}
public function draftConfig()
{
if (!$this->theme) {
return;
}
return $this->hasOne(LiveConfig::class)->where('status',
'draft');
}
Eager Loading method
public function augmented()
{
$this->load([
'theme',
'theme.renewalPlans',
'subscription',
'subscription.nextSubscription',
'liveConfig',
'draftConfig',
])->append('open_invoices_count', 'cmsStyling', 'cmsStylesheets');
}
I have a Controller that has a dependency with BillingService, and BillingService has another dependency on UserService.
I need to call the Controller method getPlans and in this call I need to mock two functions:
loadPlans that is inside BillingService
getUsage that is in UserService
This is the full example:
class BillingPlanController
{
public function __construct(private BillingPlanService $billingPlanService)
{
}
public function getPlans()
{
$plans = $this->billingPlanService->getPlans();
//
}
}
class BillingPlanService
{
public function __construct(private UserService $userService)
{
}
public function getPlans()
{
$plans = $this->loadPlans();
$user = auth()->user();
$usage = $this->userService->getUsage(user); // DO SOMETHING, NEED TO MOCK .. HOW ?
}
public function loadPlans()
{
// DO SOMETHING, NEED TO MOCK .. HOW ?
}
}
At the end, in my test i simply call:
getJson(action([BillingPlanController::class, "getPlans"]));
In other tests, I'm able to mock a single Service, but in this scenario, I don't know how to write the mocks.
Sorry if I don't provide any "tries", but I really don't know how I can do that.
UPDATE
I tried to use partialMock and mock, but I get this error (when getUsage is called) - partialMock is used because i just need to mock a single function:
Typed property App\Modules\Billing\Services\BillingPlanService::$userService must not be accessed before initialization
$this->mock(UserService::class, function ($mock) {
$mock->shouldReceive("getUsage")->andReturn([]);
});
$this->partialMock(BillingPlanService::class, function ($mock) {
$mock->shouldReceive("loadPlans")->andReturn([]);
});
getJson(action([BillingPlanController::class, "getPlans"]));
Your exception in your partial mock, is because when you mock the BillingPlanService you do not intilize the userService due to it being a mock. You can simply set it on the mock and i think it should work in your context.
$userServiceMock = $this->mock(UserService::class, function ($mock) {
$mock->shouldReceive("getUsage")->andReturn([]);
});
$this->partialMock(BillingPlanService::class, function ($userServiceMock) use ($userServiceMock) {
$mock->set('userService', $userServiceMock);
$mock->shouldReceive("loadPlans")->andReturn([]);
});
I want to set the session after user login in opencart-3.0.2.0
I am new to opencart, I have just created this two files only in the corresponding folder.anything else I need to be done to trigger the event.
I am referring this link to trigger the event in opencart:https://isenselabs.com/posts/opencart2-event-system-tutorial
I have searched a lot on google still no result found.
Code that I am using to trigger event in opencart.
path : admin/controller/module/mymodule.php
Code :
public function install() {
$this->load->model('extension/event');
$this->model_extension_event->addEvent('mymodule', 'pre.admin.store.delete', 'module/mymodule/on_store_delete');
$this->model_extension_event->addEvent('mymodule', 'post.customer.login', 'module/mymodule/post_customer_login_customtoken');
$this->model_extension_event->addEvent('mymodule', 'post.customer.logout', 'module/mymodule/post_customer_logout_function');
}
public function uninstall() {
$this->load->model('extension/event');
$this->model_extension_event->deleteEvent('mymodule');
}
public function on_store_delete($store_id) {
$this->load->model('setting/store');
$store_info = $this->model_setting_store->getStore($store_id);
$admin_mail = $this->config->get('config_email');
mail($admin_mail, "A store has been deleted", "The store " . $store_info['url'] . " was deleted.");
}
}
path : catalog/controller/module/mymodule.php
Code :
<?php
class ControllerModuleMyModule extends Controller {
public function post_customer_login_customtoken() {
$str = 'abcdefghigklmnopqrstuvwxyz';
$shuffled = str_shuffle($str);
$this->session->data['custom_token'] = $shuffled;
}
public function post_customer_logout_function(){
$this->log->write("post_customer_logout_function");
unset($this->session->data['custom_token']);
}
}
That tutorial is for OpenCart 2.0 - 2.1, in OpenCart 2.2 and above Event system has been changed.
For OpenCart 3.0.2.0 instead of:
$this->load->model('extension/event');
// and
$this->model_extension_event->addEvent
use:
$this->load->model('setting/event');
// and
$this->model_setting_event->addEvent
Instead of:
'post.customer.login'
use:
'catalog/controller/account/login/after'
Instead of:
deleteEvent
Use:
deleteEventByCode
So it must be:
admin\controller\extension\module\mymodule.php
public function install(){
$this->load->model('setting/event');
$this->model_setting_event->addEvent('mymodule', 'catalog/controller/account/login/after', 'extension/module/mymodule/after_customer_login_customtoken');
}
public function uninstall(){
$this->load->model('setting/event');
$this->model_setting_event->deleteEventByCode('mymodule');
}
catalog\controller\extension\module\mymodule.php
class ControllerExtensionModuleMyModule extends Controller {
public function after_customer_login_customtoken(){
$this->log->write('test');
}
}
Is there anyone here used CIUnit?
Having trouble understanding it. T_T.
What I'm doing is pretty simple
E.g
I have a controller method myphp()
function myphp()
{
echo 'boom';
}
CI Unit Testing:
public function setUp()
{
// Set the tested controller
$this->CI = set_controller('home');
// date_default_timezone_set('America/Los_Angeles');
}
function testMyPhp()
{
$this->CI->myphp();
$out = output();
var_dump($out); //return empty eventhough function myphp is returning a string ('boom')
}
What happening.?? I just want to test whether I can fetch the output of my method myphp.
I have a Zend Framework controller with an editAction().
class WidgetController extends BaseController
{
public function editAction()
{
//code here
}
}
This controller extends a base controller which checks if the user is logged in before allowing the user to edit a record.
class BaseController extends Zend_Controller_Action
{
public function init()
{
if ($this->userNotLoggedIn()) {
return $this->_redirect('/auth/login');
}
}
}
However, now that I am performing an AJAX request, I will be sending a JSON response back, so a redirect will no longer work. I need to stop further controller execution so I can immediately send a response:
class BaseController extends Zend_Controller_Action
{
public function init()
{
if ($this->userNotLoggedIn()) {
if ($this->_request->isXmlHttpRequest()) {
$jsonData = Zend_Json::encode(array('error'=>'You are not logged in!'));
$this->getResponse()
->setHttpResponseCode(401)
->setBody($jsonData)
->setHeader('Content-Type', 'text/json');
//now stop controller execution so that the WidgetController does not continue
} else {
return $this->_redirect('/auth/login');
}
}
}
}
How can I stop controller execution?
I would define the user not being logged in and trying to make an XMLHTTPRequest as an exceptional state and let the error handler deal with it by throwing an exception (which stops dispatching of the current action). That way you are also able to handle other kinds of exceptions that might happen:
class BaseController extends Zend_Controller_Action
{
public function init()
{
if ($this->userNotLoggedIn()) {
if ($this->_request->isXmlHttpRequest()) {
throw new Exception('You are not logged in', 401);
} else {
return $this->_redirect('/auth/login');
}
}
}
}
class ErrorController extends Zend_Controller_Action
{
public function errorAction()
{
$errors = $this->_getParam('error_handler');
$exception = $errors->exception;
if ($this->_request->isXmlHttpRequest()) {
$jsonData = Zend_Json::encode($exception);
$jsonData = Zend_Json::encode(array('error'=> $exception->getMessage()));
$isHttpError = $exception->getCode() > 400 && $exception->getCode();
$code = $isHttpError ? $exception->getCode() : 500;
$this->getResponse()
->setHttpResponseCode($code)
->setBody($jsonData)
->setHeader('Content-Type', 'application/json');
} else {
// Render error view
}
}
}
I can think of many ways to stop the controller at this point in your code.
//now stop controller execution so that the WidgetController does not continue
For one, you can replace that line with this the following:
$this->getResponse()->sendResponse();
exit;
That may not be the cleanest but gets the job done rather nicely. The other option is going to be to change the action of the request in the init and let another action handle it. Replace that line with this:
$this->getRequest()->setActionName('invalid-user');
Because your already inside the dispatcher, it's going to run an action inside your action class whether you want it to or not. Trying to change the request in preDispatch will do nothing to change this dispatch. It's determined at this point to run an action inside your class. So, make an action to handle it.
public function invalidUserAction()
{
$this->_helper->layout->disableLayout();
$this->_helper->viewRenderer->setNoRender();
}
For more information see Zend_Controller_Dispatcher_Standard::dispatch.