Test Case with laravel Dusk showing error 'users_email_unique' - laravel

I'm getting error as on below screenshot
Please help me i am trying and for this i have spend too much time but still issue no luck.
I am using laravel official dusk package for front-web testing. When i am running login test case its showing error "users_email_unique" which is above showing in picture. I am using use DatabaseTransactions but it is not reverting my last transaction. For this i am using test database also. Here is my my code:
<?php
namespace Tests\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\DuskTestCase;
use App\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class LoginTest extends DuskTestCase
{
use DatabaseTransactions;
/**
* A Dusk test example.
*
* #return void
*/
public function test_I_can_login_successfully()
{
$user = factory(User::class)->create([
'email' => 'login#gmail.com',
'password' => bcrypt('password'),
]);
$this->browse(function ($browser) use ($user) {
$browser->visit('/')
->type('email', 'login#gmail.com')
->type('password', 'password')
->press('Login')
->assertSee($user->name);
});
}
}

For Dusk you cannot use use DatabaseTransactions. You need to use DatabaseMigrations instead. When you update trait then you should get rid of the error.
You have sample Dusk test in documentation and it looks like this:
<?php
namespace Tests\Browser;
use App\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Chrome;
use Tests\DuskTestCase;
class ExampleTest extends DuskTestCase
{
use DatabaseMigrations;
/**
* A basic browser test example.
*
* #return void
*/
public function testBasicExample()
{
$user = factory(User::class)->create([
'email' => 'taylor#laravel.com',
]);
$this->browse(function ($browser) use ($user) {
$browser->visit('/login')
->type('email', $user->email)
->type('password', 'password')
->press('Login')
->assertPathIs('/home');
});
}
}
As you see it's also using DatabaseMigrations trait.

Related

Missing required parameter for [Route: verification.verify]

On a project I have I am using Fortify as my BE. I need a multilingual app, therefore I added the
'prefix' => {locale}' to config/fortify.php.
Login, registering, and 2FA, are working ok, but the problem arrives with the email verification process.
If I try to click on the link received by email, it goes to the /email/verify and returns a forbidden page error.
Then if I request to get another verification email it returns the error displayed on the title of the question.
Probably it has something to be with the locale parameter because when I run route::list, the verification.verify route is displayed with the endpoint of {locale}/email/verify/{id}/{hash}, so I assume that the link on the request another mail is causing the error since it is referenced as /email/verify/{id}/{hash}.
So does anyone know how to change it?
Or has anyone faced a similar problem regarding Fortify and these localization routes?
What I had to do was to customize some of the default Fortify functions, extending some classes in order to add the locale parameter to them.
When a new user is registered (event) it sends the verification email (listener), so I had to configure the files involved in this flow.
<?php
namespace App\Listeners;
use Illuminate\Auth\Events\Registered;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
class SendEmailVerificationNotification implements ShouldQueue
{
use Queueable;
public function handle(Registered $event)
{
if ($event->user instanceof MustVerifyEmail && ! $event->user->hasVerifiedEmail()) {
$event->user->sendCustomVerificationEmailNotification();
}
}
}
And create the function sendCustomVerificationEmailNotification on the user's model and the notification CustomVerificationNotification that will be sent.
public function sendCustomVerificationEmailNotification()
{
$this->notify(new CustomVerificationNotification);
}
<?php
namespace App\Notifications;
use Carbon\Carbon;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\URL;
class CustomVerificationNotification extends VerifyEmail
{
protected function verificationUrl($notifiable)
{
if (static::$createUrlCallback) {
return call_user_func(static::$createUrlCallback, $notifiable);
}
return URL::temporarySignedRoute(
'verification.verify',
Carbon::now()->addMinutes(Config::get('auth.verification.expire', 60)),
[
'locale' => app()->getLocale(),
'id' => $notifiable->getKey(),
'hash' => sha1($notifiable->getEmailForVerification()),
]
);
}
}
Then in case, the user wants an additional verification email notification, this is handled through a function on the EmailVerificationNotificationController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Laravel\Fortify\Fortify;
use Laravel\Fortify\Http\Controllers\EmailVerificationNotificationController;
class CustomEmailVerificationController extends EmailVerificationNotificationController
{
/**
* Send a new email verification notification.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
if ($request->user()->hasVerifiedEmail()) {
return $request->wantsJson()
? new JsonResponse('', 204)
: redirect()->intended(Fortify::redirects('email-verification'));
}
$request->user()->sendEmail();
return $request->wantsJson()
? new JsonResponse('', 202)
: back()->with('status', 'verification-link-sent');
}
}

Laravel Auth::attemp() is not working, even with valid credentials

This is the unit test which I want to run. This is always failing. I have tried with wrong data. Still it fails and with correct data still it fails. Please someone help me out from this.
If anyone wants to explore more: http://github.com/PawanRoy1997/forum.git
Php Unit Test:
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Auth;
use Tests\TestCase;
class UserTest extends TestCase
{
use RefreshDatabase;
/** ##test */
public function login()
{
$data = ['name'=>'some', 'email'=>'some#some.com','password'=>'password'];
User::create($data);
$this->assertTrue(Auth::attempt($data));
}
}
Output:
➜ forum git:(master) ✗ asn test
FAIL Tests\Unit\UserTest
⨯
FAIL Tests\Feature\UserTest
⨯ login
---
• Tests\Unit\UserTest >
Error
Call to a member function connection() on null
at vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1571
1567▕ * #return \Illuminate\Database\Connection
1568▕ */
1569▕ public static function resolveConnection($connection = null)
1570▕ {
➜ 1571▕ return static::$resolver->connection($connection);
1572▕ }
1573▕
1574▕ /**
1575▕ * Get the connection resolver instance.
+7 vendor frames
8 tests/Unit/UserTest.php:19
Illuminate\Database\Eloquent\Model::__callStatic()
• Tests\Feature\UserTest > login
Failed asserting that false is true.
at tests/Feature/UserTest.php:19
15▕ public function login()
16▕ {
17▕ $data = ['name'=>'some', 'email'=>'some#some.com','password'=>'password'];
18▕ User::create($data);
➜ 19▕ $this->assertTrue(Auth::attempt($data));
20▕ }
21▕ }
22▕
Tests: 2 failed
Time: 0.31s
➜ forum git:(master) ✗
Actually, I just figured it out that I need to hash the password while creating the user. I forgot to mention that I have updated Laravel then all of this started. In laravel 8.51, Auth::attempt checks for hashed passwords only. But in laravel 8.50 and before, it allows password to be not hashed.
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Tests\TestCase;
class UserTest extends TestCase
{
/**
* A basic feature test example.
*
* #return void
*/
public function test_example()
{
$data = [
'name' => 'someone',
'email' => 'some#some.com',
'password' => Hash::make('password'),
'confirm_password' => 'password'
];
User::create($data);
$this->assertDatabaseCount('users', 1);
$this->assertTrue(Auth::attempt(['email' => 'some#some.com', 'password' => 'password']));
}
}

Unable to locate factory in Laravel 7

I am making a unit test for PHPunit. The code is:
<?php
namespace Tests\Unit;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use PHPUnit\Framework\TestCase;
class ThreadTest extends TestCase
{
use DatabaseMigrations;
public function test_a_thread_has_replies()
{
$thread = factory('App\Thread')->create();
$this->assertInstanceOf('Illuminate\Database\Eloquent\Collection', $thread->replies);
}
}
When I run PHPUnit i get the error:
InvalidArgumentException: Unable to locate factory for [App\Thread].
I have a threadfactory:
<?php
/** #var \Illuminate\Database\Eloquent\Factory $factory */
use App\Thread;
use Faker\Generator as Faker;
$factory->define(Thread::class, function (Faker $faker) {
return [
'user_id' => factory(App\User::class),
'title' => $faker->sentence,
'body' => $faker->paragraph
];
});
If I use the factory in Tinker it works fine.
I have similar testfunctions and factories for other classes and these work fine.
Most likely I am making a very stupid error, but I cannot find it.
Any suggestions?
Kind regards,
HUbert
You are extending the php unit testcase class. Which does not load your Laravel application. You should extends the use Tests\TestCase provided by Laravel.
Using php artisan make:test UserTest on the CLI will create a test with the correct template fitting for testing a Laravel application.
What worked for me was to use
$factory->define(App\Model::class, function (Faker $faker) {
//return code here
}
Instead of just using the Model name without placing APP\ in front of the model name
$factory->define(Model::class, function (Faker $faker) {
//return code here
}

If logged with jwt-auth looks in controller Auth::user() is empty

In my Laravel 5.8/vuejs 2.6 app I use
"tymon/jwt-auth": "^1.0.0",
and my app/Http/Controllers/AuthController.php has method:
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if ($token = $this->guard('api')->attempt($credentials)) {
return $this->respondWithToken($token);
}
return response()->json(['error' => 'Unauthorized'], 401);
}
and I keep token on client side. It works but I want to add more checks on the server's side, when I save data and to make in control's method :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Auth;
use DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use App\Settings;
use App\Http\Traits\funcsTrait;
use App\Forum;
use App\ForumCategory;
use App\ForumThread;
use App\ForumPost;
use Illuminate\Routing\Controller as BaseController;
use App\User;
use App\library\CheckValueType;
use App\Http\Requests\ForumThreadRequest;
use JavaScript;
class ForumController extends BaseController
{
use funcsTrait;
public function __construct()
{
$this->middleware('auth');
}
public function add_new_thread(ForumThreadRequest $request)
{
$loggedUser = Auth::user();
if ( empty($loggedUser->id) ) {
return response()->json(['error_code'=> 1, 'message'=> "You must be logged!", 'forumThreadRow'=>null],HTTP_RESPONSE_INTERNAL_SERVER_ERROR);
}
try {
But even if I have logged into the system it looks like that in add_new_thread method $loggedUser is empty.
Have I to make some additive actions in login method of AuthController.php or in which way ?
As I use api guard decision is to use :
$user = Auth::guard('api')->user();
This is a late answer, but maybe could help someone.
I had the same issue and it was fixed by adding $table property to the user model User.php
/**
* Specify table name otherwise Auth::user() will return null
*
* #var string
*/
protected $table = 'users';
see here

Laravel - How to use faker in PHPUnit test?

It's giving me this error when I run the test:
undefined variable $faker.
This is the WithFaker file.
https://github.com/laravel/framework/blob/5.5/src/Illuminate/Foundation/Testing/WithFaker.php
<?php
namespace Tests\Unit;
use App\User;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class LoginTest extends TestCase
{
use WithFaker;
/**
* A basic test example.
*
* #return void
*/
/** #test */
public function test_example()
{
$user = User::create([
'username' => $faker->firstName(),
]);
}
}
You have to use $this->faker->firstName() not just $faker->firstName()
Update 1
Now when we use WithFaker Trait $this->faker will give us null, to get around this make sure to call $this->setupFaker() first.
e.g.
class SomeFactory
{
use WithFaker;
public function __construct()
{
$this->setUpFaker();
}
}
credit #Ebi
For anyone coming here from 2021. We no longer require the addition of
$this->setUpFaker();
You only need to include the trait as described in the accepted answer.
once you completed installation of Faker.
include autoload file and create instance
$faker = \Faker\Factory::create();
$faker->firstname()
$faker->lastname()
For more information visit
check you seed function run (Faker $faker).

Resources