I'm just starting out with looking at Dusk - and I'm testing some user functionality.
Below is my current test, however I'm trying to clean up after myself - for example the newly created user should be deleted from the database once it's done.
I've tried to use a tearDown method, but it doesn't seem to be be actually deleting it.
How would I typically go about spinning up temp models which need to be garbaged after?
<?php
namespace Tests\Browser;
use App\User;
use Tests\DuskTestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class LoginTest extends DuskTestCase
{
protected $user = null;
public function testIfPublicUsersLogin()
{
$this->user = $user = factory(User::class)->create([
'is_student' => 0
]);
$this->browse(function ($browser) use ($user) {
$browser->visit('/login')
->assertVisible('#email')
->type('#email', $user->email)
->type('#password', 'secret')
->press('#loginButton')
->assertPathIs('/play');
});
}
public function tearDown()
{
if ($this->user) {
User::destroy($this->user->id);
//$this->user->delete();
}
}
}
There are multiple ways to achieve this:
Use the DatabaseTransactions trait so that there's a transaction rollback after every test. To do so add: use Illuminate\Foundation\Testing\DatabaseTransactions; in your php file and add use DatabaseTransactions; in your test class
You might want to use the DatabaseMigrations trait if you want to migrate and migrate rollback before and after every test rather than wrap them into transactions. To do so add: use Illuminate\Foundation\Testing\DatabaseMigrations; in your php file and add use DatabaseMigrations; in your test class
If you want to use custom setup and teardown methods, use the
afterApplicationCreated and beforeApplicationDestroyed methods
instead to register callbacks
<?php
namespace Tests\Browser;
use App\User;
use Tests\DuskTestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;
class LoginTest extends DuskTestCase
{
protected $user = null;
public function testIfPublicUsersLogin()
{
$this->user = $user = factory(User::class)->create([
'is_student' => 0
]);
$this->browse(function ($browser) use ($user) {
$browser->visit('/login')
->assertVisible('#email')
->type('#email', $user->email)
->type('#password', 'secret')
->press('#loginButton')
->assertPathIs('/play');
$user->delete();
});
}
}
this code line $user->deletedelete your data after test. The tearDown method is useless.
Related
I've encountered an error when refactoring my Laravel tests by adding at setUp() method.
This works as expected:
<?php
namespace Tests\Feature;
use App\Models\Person;
use Tests\TestCase;
class MembershipTicketsTest extends TestCase
{
public function test_a_non_member_cannot_list_redeemable_events()
{
$user = Person::factory()->create();
$this->actingAs($user);
$this->get(route('event.index'))->assertStatus(302)->assertRedirect(route('membership.create'));
}
Where as this returns the error Unknown formatter "firstName":
<?php
namespace Tests\Feature;
use App\Models\Person;
use Tests\TestCase;
class MembershipTicketsTest extends TestCase
{
protected $user;
protected function setUp() : void
{
$this->user = Person::factory()->create();
}
public function test_a_non_member_cannot_list_redeemable_events()
{
$this->actingAs($this->user);
$this->get(route('event.index'))->assertStatus(302)->assertRedirect(route('membership.create'));
}
Every solution to this error I've found says to make sure that you have use Tests\TestCase; in your file, which I do.
I presume this means I cannot use factories in the setUp() method of a test in Laravel. Is this true, and why is it the case?
I have a custom middleware where I want to use a singleton I use to pass php variables into my frontend, however I get the following error:
ReflectionException (-1)
Class App\Http\Middleware\Javascript does not exist
My middleware:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Auth;
class AuthAdmin
{
public function handle($request, Closure $next)
{
$user = Auth::user();
if($user && $user['privileges'] > 2)
{
return $next($request);
}
app(Javascript::class)->put(['showLoginModal' => true]);
return redirect('/');
}
}
My ServiceProvider:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Helpers\Javascript;
class JavascriptServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(Javascript::class, Javascript::class);
}
}
composer dump-autoload didn't fix anything, I have been having problems where the Javascript Class is not found for some reason, any ideas or sugestions?
Try importing Javascript class in your middleware. It's trying to find it in wrong namespace.
middleware:
<?php
namespace App\Http\Middleware;
use App\Helpers\Javascript;
I've got the following factory in Laravel 5.7, when invoking it nothing is being returned:
<?php
use Faker\Generator as Faker;
use Illuminate\Database\Eloquent\Model;
$factory->define(App\Record::class, function (Faker $faker) {
return [
"name" => $faker->name,
];
});
Whereas my model is:
<?php
namespace App;
use App\Product;
use Illuminate\Database\Eloquent\Model;
class Record extends Model
{
protected $table = "records";
protected $fillable = ["name"];
function __construct()
{
parent::__construct();
}
}
And I'm invoking the factory here:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App;
use App\Product;
use App\Record;
use App\User;
class RecordTest extends TestCase
{
use RefreshDatabase;
use WithoutMiddleware;
/** #test */
public function when_record_page_for_existing_record_is_accessed_then_a_product_is_displayed()
{
//$record = factory(App\Record::class)->make();
$record = factory(App\Record::class)->create();
echo "\n\n$record->name\n\n";
}
}
when printing
$record->name
I'm getting nothing, not null, no empty string, just nothing. What seems to be the problem? If I save whatever is generated by the factory into a variable instead of returning it right away I can see that name is being populated, but after returning it nothing happens, it's gone
This piece of code is the problematic part:
function __construct()
{
parent::__construct();
}
You're not passing the attributes to the parent constructor. Eloquent accepts the model's attributes in the constructor, but your overriding constructor doesn't accept them, nor pass them up to the parent.
Change it to this:
function __construct(array $attributes = [])
{
parent::__construct($attributes);
}
BTW, you're overriding Eloquent's constructor, but you're not doing anything in there. Are you sure you actually want to override it?
By default phpunit won't print your echo.
To print it, please use phpunit -v
So I am having a few dramas with my controllers. They seem to operate properly, however they don't seem to use __construct() at all in any of the controllers.. I'm trying to use this to update our users table to show last activity.
<?php
namespace App\Http\Controllers;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Http\Request;
use App\Helpers\UserHelper;
use App\Helpers\ForumHelper;
use App\Helpers\ShopHelper;
use Auth;
use Image;
use App\User;
use DB;
use Hash;
use File;
class AdminController extends BaseController
{
public function __construct() {
if ($_SERVER["HTTP_CF_CONNECTING_IP"]) {
$_SERVER["REMOTE_ADDR"] = $_SERVER["HTTP_CF_CONNECTING_IP"];
}
if(Auth::check()) {
$time = strtotime("now");
DB::table('users')->where('userid', Auth::user()->userid)->update(['lastactivity' => $time]);
}
}
Any idea what I can do to check and try and get it working again?
I'm running Laravel Framework 5.4.28
A project I did similar on was running Laravel Framework version 5.2.45 and worked fine when I was doing that so I'm confused why this is happening on a newer version.
Any ideas how I can otherwise go about implementing the DB Update when loading stuff from my controllers?
If you want an activity tracker then add a web route middleware:
class ActivityTrackerMiddleware {
public function handle($request,$next) {
if ($request->user()) {
$request->user()->lastactivity = Carbon::now();
$request->user()->save();
}
return $next($request);
}
}
Add this in your web middleware:
'web' => [ ...
StartSession::class,
ActivityTrackerMiddleware::class,
...
];
You can also limit it to the admin controller if you prefer.
After trying to debug for a long time I run into an error of where I a variable does not seem to retrieve a value from the database.
Here is the code I use:
use App\Setting;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
use View;
use DB;
class SettingsServiceProvider extends ServiceProvider
{
public function boot()
{
if(\DB::connection()->getDatabaseName() && Schema::hasTable('settings') && \DB::table('settings')->count()){
$setting = new Setting;
config()->set('website_desc', $setting->gets('general')->website_desc);
config()->set('website_keywords', $setting->gets('general')->website_keywords);
}
}
public function register()
{
// this approach worked before updating to 5.4
view()->share('website_desc',config('website_desc'));
view()->share('website_keywords',config('website_keywords'));
//does not work either
// View::share(['website_desc' => 'values', 'website_keywords' => 'values']);
}
}
my App/setting.php looks like this
namespace App;
use Illuminate\Database\Eloquent\Model;
class Setting extends Model
{
protected $fillable = ['name','attributes'];
public function gets($name){
$attributes = $this->where('name',$name)->value('attributes');
if($attributes){
return json_decode($attributes);
}
return false;
}
}
Can anyone see anything that became incompatible?
This is the a database entry of the table settings and the column "attributes":
{"website_name":"name","website_title":"title","website_desc":"description","website_keywords":"keywords","website_footer_text":"footer"}
I am kind of at my wits end.