use expectException() on laravel custom exception - php

Here is a custom exception
namespace App\Exceptions;
use Exception;
class CustomException extends Exception
{
public function render($request)
{
return response()->view('custom-exception');
}
}
I throw it inside a Request class
class LoginRequest extends FormRequest
{
public function authenticate()
{
if (! Auth::attempt($this->only('email', 'password'))) {
throw CustomException(); //
}
}
}
This is the controller which call the LoginRequest class
class AuthenticatedSessionController extends Controller
{
public function store(LoginRequest $request) //
{
$request->authenticateMember();
$request->session()->regenerate();
return redirect()->intended(RouteServiceProvider::Home);
}
}
This is the test
use Tests\TestCase;
use App\Models\User;
use App\Exceptions\CustomException;
class EmailVerificationTest extends TestCase
{
public function test_email_verification_screen_can_be_rendered()
{
$user = User::factory()->create([
'email_verified_at' => null,
]);
// $this->expectException(CustomException::class); //this cannot pass
$response = $this->post(
'/login',
[
'email' => 'john#example.com',
'password' => 'secret'
]
);
$response->assertViewIs('custom-exception');
$this->assertInstanceOf(CustomException::class, $response->exception);
}
}
These assertions can pass:
$response->assertViewIs('custom-exception');
$this->assertInstanceOf(CustomException::class, $response->exception);
But this one cannot pass:
$this->expectException(CustomException::class);
Failed asserting that exception of type "App\Exceptions\CustomException" is thrown.
Why? Any idea?

The method expectException() will only work when the exception thrown is not handled.
Please add the below line in your function
$this->withoutExceptionHandling();
then this method expectException() will work.

Related

How to create custom validation rule in Laravel 6 API

I need to use my custom validation rule for validating API requests.
Request Class:
This is my request validation rule.
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class LoginRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'username' => 'required',
'password' => 'required'
];
}
public function messages()
{
return [
'username.required' => 'The Username field is required',
'password.required' => 'The Password field is required'
];
}
}
API Controller:
This is my API controller and method.
use Illuminate\Http\Request;
use App\Http\Controllers\API\BaseController as BaseController;
use Illuminate\Support\Facades\Auth;
use App\Http\Requests\LoginRequest;
class LoginController extends BaseController
{
public function login(LoginRequest $request)
{
print_r($validatorMsg);
die();
}
}
Unable to get error message.
guys, I resolved the problem this is the solution:
public function login(Request $request)
{
$LoginRequest = New LoginRequest;
$validator = Validator::make($request->all(), $LoginRequest->rules(),$LoginRequest->messages());
if($validator->fails()){
return response()->json($validator->errors(), 422);
}
}
In order to display error messages in your API's, use response() method in your LoginRequest class, so you always return JSON. Something like this:
public function response(array $errors)
{
// Always return JSON.
return response()->json($errors, 422);
}
Now try to submit empty form, and you should be able to view the error message.

How to mock a Validation Rule in Laravel

I want to mock a custom Validation rule (e.g. App\Rules\SomeRule). But when I run my test, it gives an Mockery\Exception\InvalidCountException: Method...should be called
exactly 1 times but called 0 times.
I've read Laravel's documentation on Mocking, on custom Validation Rules, Service Containers, Service Providers and I cannot figure out why I'm not successfully mocking the rule.
I read this thread but I'm struggling to connect it with my problem which is, "How can I test that my app is using this Rule". Or is that something I cannot test?
Here's my Rule
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class SomeRule implements Rule
{
public function passes($attribute, $value)
{
// some logic, returns TRUE if valid.
}
public function message()
{
//
}
}
My controller
namespace App\Http\Controllers;
use App\Rules\SomeRule;
use Illuminate\Http\Request;
class LoanController extends Controller
{
public function store(Request $request)
{
$request->validate([
'email' => ['required', new SomeRule]
]);
// ...insert in database, return json.
}
}
My Test
namespace Tests\Feature;
use Mockery;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Rules\SomeRule;
class LoansTest extends TestCase
{
use RefreshDatabase;
public function tearDown(): void
{
parent::tearDown();
Mockery::close();
}
/** #test */
public function the_sad_path__when_email_is_invalid()
{
$rule = Mockery::mock(SomeRule::class)->shouldReceive('passes')->once();
$this->app->instance(SomeRule::class, $rule);
$response = $this->json('POST', '/api/loans', ['email' => 'whatevs#gmail.com']);
}
}
I played with the idea of registering SomeRule in the AppServiceProvider. But that still didn't do anything:
public function register()
{
$this->app->bind(SomeRule::class, function ($app) {
return new SomeRule();
});
}
Code in Github
you need to use like this
class LoanController extends Controller
{
public function store(Request $request)
{
$request->validate([
'email' => ['required', new SomeRule()]
]);
// ...insert in database, return json.
}
}

AuthorizationException not handled in Handler.php Laravel

Hello I have a problem with exception handler in Laravel 5.4.
I have in my controller a function that make a check for permission like:
function foo(){
try{
$this->authorize("bar", MyClass::class);
}catch(AuthorizationException $e){
}
}
In my handler.php I have this:
namespace App\Exceptions;
use Exception;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
protected $dontReport = [
\Illuminate\Auth\AuthenticationException::class,
\Symfony\Component\HttpKernel\Exception\HttpException::class,
\Illuminate\Database\Eloquent\ModelNotFoundException::class,
\Illuminate\Session\TokenMismatchException::class,
\Illuminate\Validation\ValidationException::class,
];
public function render($request, Exception $exception)
{
if ($exception instanceof AuthorizationException) {
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthorized.'], 403);
}
// TODO: Redirect to error page instead
}
return parent::render($request, $exception);
}
}
But the problem is that handler is never called.
But If I do:
function foo(){
try{
throw new AuthorizationException() //test for throw exception
$this->authorize("bar", MyClass::class);
}catch(AuthorizationException $e){
}
}
It will call handler.
So Can I handler AuthorizationException with $this->authorize ?
For Now I've resolve in this way:
I created a Custom class that extends AuthorizationException like:
namespace App\Exceptions;
namespace Illuminate\Auth\Access;
use Throwable;
class CustomAuthorizationException extends AuthorizationException
{
public function __construct($message = "", $code = 0, Throwable $previous = null)
{
throw new AuthorizationException();
}
}
And In Controller:
function foo(){
try{
$this->authorize("bar", MyClass::class);
}catch(CustomAuthorizationException $e){
}
}
And now it works, but I don't know if It is a good way.
The advices are well accepted!

how can call user that created in setup function in other function

this is my full code that I write it to test function from controller
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\Concerns\MakesHttpRequests;
class RouteForecastTest extends TestCase
{
protected $password = 'rightpassword';
public function setUp()
{
parent::setUp();
$this->createApplication();
$this->user = factory(App\User::class)->create([
'email' => 'testuser#email.com',
'password' => bcrypt($this->password),
'type' => 'admin'
]);
}
/** #test */
public function createTest()
{
$this->actingAs($user);
$this->visit('/client/ocp/profile/247')
->click('New ')
->seePageIs('/client/ocp/profile/247/create')
->see('name');
}
public function tearDown(){
parent::tearDown();
$this->user->delete();
}
}
i try this code with setup and teardown methods and run test using phpunit i got this error
ErrorException: Undefined variable: user
how can I fix this error?

Class App\Http\Controllers\Auth\Request does not exist. Laravel 5.3

I am using Laravel 5.3 My ForgotPasswordController looks like that:
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Base\BaseController;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class ForgotPasswordController extends BaseController
{
use SendsPasswordResetEmails;
public function __construct()
{
$this->middleware('guest');
}
public function showLinkRequestForm()
{
$title = $this->title;
$appName = $this->appName;
$action = $this->action;
return view('password.forgotPassword')->with(compact('title', 'appName', 'action'));
}
}
ResetPasswordController code :
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Base\BaseController;
use Illuminate\Foundation\Auth\ResetsPasswords;
class ResetPasswordController extends BaseController
{
use ResetsPasswords;
public function __construct()
{
$this->middleware('guest');
}
public function showResetForm(Request $request, $token = null)
{
return view('passwords.resetPassword')->with(
['token' => $token, 'email' => $request->email]
);
}
public function reset(Request $request)
{
$this->validate($request, [
'token' => 'required',
'password' => 'required|confirmed|min:6',
]);
// Here we will attempt to reset the user's password. If it is successful we
// will update the password on an actual user model and persist it to the
// database. Otherwise we will parse the error and return the response.
$response = $this->broker()->reset(
$this->credentials($request), function ($user, $password) {
$this->resetPassword($user, $password);
}
);
// If the password was successfully reset, we will redirect the user back to
// the application's home authenticated view. If there is an error we can
// redirect them back to where they came from with their error message.
return $response == Password::PASSWORD_RESET
? $this->sendResetResponse($response)
: $this->sendResetFailedResponse($request, $response);
}
}
My Admin Route :
Route::group(['namespace' => 'Auth'], function() {
Route::get('/forgotpassword/reset', 'ForgotPasswordController#showLinkRequestForm');
Route::post('/forgotpassword/email', 'ForgotPasswordController#sendResetLinkEmail');
Route::get('/password/reset/{token}', 'ResetPasswordController#showResetForm');
Route::post('/password/reset', 'ResetPasswordController#reset');
});
BaseController Code :
<?php
namespace App\Http\Controllers\Base;
use App\Http\Controllers\Controller;
class BaseController extends Controller
{
protected $appName = 'Stackoverflow';
protected $title = 'Welcome to Stackoverflow';
protected $action;
}
I can send the link to my email, but once I click the link/button.
It throws an error like above. Any idea ?
You are not using the required namespace, try to use the following in your controller:
use Illuminate\Http\Request;
You are getting the error due to the fact that your script tries to load the Request class from the current namespace :App\Http\Controllers\Auth
Request docs for Laravel 5.3

Categories