Invalid Argument Exception - Laravel Unit Testing - laravel

I am running a unit test to check that
View page exists
AssertSee that text appears on the page and with a string limit
I am getting an invalid argument exception:
1) Tests\Feature\ViewAllPostTest::testCanViewAllPosts
InvalidArgumentException: You requested 1 items, but there are only 0 items available.
C:\projects\car-torque-laravel\vendor\laravel\framework\src\Illuminate\Support\Arr.php:472
C:\projects\car-torque-laravel\vendor\laravel\framework\src\Illuminate\Support\Collection.php:1486
C:\projects\car-torque-laravel\database\factories\PostFactory.php:12
C:\projects\car-torque-laravel\vendor\laravel\framework\src\Illuminate\Database\Eloquent\FactoryBuilder.php:274
C:\projects\car-torque-laravel\vendor\laravel\framework\src\Illuminate\Database\Eloquent\FactoryBuilder.php:292
C:\projects\car-torque-laravel\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\GuardsAttributes.php:122
C:\projects\car-torque-laravel\vendor\laravel\framework\src\Illuminate\Database\Eloquent\FactoryBuilder.php:300
C:\projects\car-torque-laravel\vendor\laravel\framework\src\Illuminate\Database\Eloquent\FactoryBuilder.php:219
C:\projects\car-torque-laravel\vendor\laravel\framework\src\Illuminate\Database\Eloquent\FactoryBuilder.php:178
C:\projects\car-torque-laravel\tests\Feature\ViewAllPostTest.php:19
My source code is as follows:
Test Function
namespace Tests\Feature;
use App\Post;
use Tests\TestCase;
class ViewAllPostTest extends TestCase
{
/**
* #group posts
*
* #return void
*/
public function testCanViewAllPosts()
{
//arrange
$post = factory(Post::class)->create();
//action
$response = $this->get('/posts');
//assert
$response->assertStatus(200);
$response->assertSee($post->body);
$response->assertSee(str_limit($post->body));
}
}
Factory Class
use App\Post;
use App\User;
use Faker\Generator as Faker;
$factory->define(Post::class, function (Faker $faker) {
return [
'body' => $faker->text,
'user_id' => User::all()->random()->id,
'created_at' => now(),
'updated_at' => now(),
];
});

'user_id' => User::all()->random()->id,
In the above line of your factory, you want random id form your users table. But have you created any User before running the test. At least a user should be created before creating post using post factory.

Related

Why my resource do not return all meta data having "with" method?

In lumen 8 app I use resources and reading here
https://laravel.com/docs/8.x/eloquent-resources
I try to use “with” method, as I want to add some meta data to any request and I have no
this meta data in returned data :
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
use App\Models\Page As PageModel;
use App\Http\Resources\User as UserResource;
class Page extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
...
'created_at' => $this->created_at,
];
}
public function with($request)
{
\Log::info( '-1 unction with ::' . print_r( 1, true ) ); // I DO NOT SEE THIS LOGGINHG line
return [
'meta' => [
'version'=>getAppVersion()
]
];
}
}
In the referenced docs resource is declared a bit different from ResourceCollection:
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
{
public function toArray($request)
{
return parent::toArray($request);
}
public function with($request)
{
return [
'meta' => [
'key' => 'value',
],
];
}
}
Could it be the issue and how can fix my resource to get all meta data ?
Updated block:
UserCollection - that is collection https://laravel.com/docs/8.x/eloquent-resources
my collection is Page and I use it in controller as :
namespace App\Http\Controllers;
use Carbon\Carbon;
use App\Models\Page;
use Illuminate\Http\Request;
use App\Http\Resources\Page as PageResource;
use Config;
use App\Http\Requests\PageRequest;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Storage;
use Validator;
class PageController extends Controller
{
public function index()
{
$pages = Page
...
->get();
return $this->sendOkResponse(PageResource::collection($pages), '');
}
sendOkResponse defined in Http/Controllers/Controller.php :
class Controller extends BaseController
{
protected $requestData;
public function __construct()
{
$request = request();
$this->requestData = $request->all();
}
public function sendOkResponse($responseResult, $message)
{
$response = [
'success' => true,
'data' => $responseResult,
'message' => $message,
];
return response()->json($response, HTTP_RESPONSE_OK);
}
I suppose PageResource is destroyed at PageController controller index method exit...
Updated block # 2:
After some tests I found that Resource method “with” does not work if collection is returned
and I need to use ->additional in controller like:
return (PageResource::collection($pages))
->additional([
'meta' => [
'version' => getAppVersion()
]
]);
But in cases when I return sinopgle element(ex store method) like
return (new PageResource($page));
method “with” works ok.
That exludes using of wrapper like sendOkResponse.
Is is the only proper way?
Thanks in advance!
Laravel resources are intended to be returned directly from your controller's action method, not as part of an associative array representing JSON.
When wrapping your responses with the sendOkResponse method, the resource is not being returned directly from the method and thus toArray is being called on your resource. The with method on your resources is being ignored.
Try returning the resources directly from your controller's method. Use the additional method when constructing your resources to pass the extra attributes in the response. See: https://laravel.com/docs/8.x/eloquent-resources#adding-meta-data-when-constructing-resources.
If you can control the API contracts, I'd recommend changing them to omit success entirely, this can be derived from the HTTP status code.

Static model class is null in feature test laravel

I have this test in my feature folder and I've imported model on top of the class but it keeps failing and I think $event is null!
namespace Tests\Feature\Events;
use App\Models\Event;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class EventManagementTest extends TestCase
{
use RefreshDatabase;
/**
* #test
* #group event
* A basic feature test to check event registration
*
*/
public function an_event_can_be_registered()
{
$this->withoutExceptionHandling();
$response = $this->post('/events',$this->data());
$event = Event::first();
$this->assertCount(1,Event::all());
$response->assertRedirect('/events/' . $event->event_id);
}
private function data()
{
return[
'event_title' => 'Internet Businesses',
'event_location' => 'Milad Tower',
'event_description' => 'In this event Amin will present you the most recent methods in Internet Businesses',
'event_start_date' => '2020-06-01',
'event_end_date' => '2020-06-05',
];
}
...
}
And this is the results:
FAIL Tests\Feature\Events\EventManagementTest ✕ an event can be registered
Tests: 1 failed
Failed asserting that two strings are equal.
....
--- Expected
+++ Actual
## ##
-'http://localhost/events/1'
+'http://localhost/events'
these two URIs are different and I think that's because $event is null and I don't know why?!
UPDATE: I've added the Route and the controller:
Route::post('/events','Web\EventsController#store');
and the controller is:
public function store(){
$event = Event::create($this->validateRequest());
return redirect('/events/'.$event->event_id);
}
protected function validateRequest(){
return request()->validate([
'event_title' => 'required',
'event_location' => 'required',
'event_description' => 'required',
'event_start_date' => 'required',
'event_end_date' => 'required',
]);
}
Your do not use the standard primary id column, therefor you need to define it in your model. If it is not defined, it will not set it on create().
class Event extends Model {
protected $primaryKey = 'event_id';
}

Faker get streetAddress throwing ErrorException

I'm building a laravel application, and I've created a FakerServiceProvider to populate factories for testing and local dev.
<?php
namespace App\Providers;
use Faker\Factory;
use Faker\Generator;
use Faker\Provider\en_GB\Address;
use Faker\Provider\en_GB\Person;
use Faker\Provider\en_GB\PhoneNumber;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
/**
* Class FakerServiceProvider
* #package App\Providers
*/
class FakerServiceProvider extends ServiceProvider implements DeferrableProvider
{
/**
*
*/
public function register()
{
$this->app->singleton(Generator::class, function ($app) {
$factory = Factory::create('en_GB');
$factory->addProvider(Person::class);
$factory->addProvider(Address::class);
$factory->addProvider(PhoneNumber::class);
return $factory;
});
}
/**
* #return array
*/
public function provides()
{
return [Generator::class];
}
}
I have created an address factory:
<?php
use App\Address;
use App\Country;
$factory->define(Address::class, function (Faker\Generator $faker) {
return [
'line_1' => $faker->secondaryAddress,
'line_2' => $faker->streetAddress,
'town' => $faker->city,
'county' => $faker->county,
'country_id' => factory(Country::class)->make()->id,
'postcode' => $faker->postcode,
'phone' => $faker->phoneNumber,
];
});
When I try to use this factory I get the following error:
ErrorException: call_user_func_array() expects parameter 1 to be a valid callback, non-static method Faker\Provider\Address::streetAddress() should not be called statically
I have checked the source for the Faker library and there is a streetAddress method here
I have tried calling both $faker->streetAddress and $faker->streetAddress()with no luck. I would expect$faker->streetAddressto produce something like ` or something similar.
Can anyone shed a bit of light on this for me
Removing the added providers in the Faker Service Provider fixed the issue

InvalidArgumentException: Unable to locate factory with name [default] - laravel, faker, phpunit

Since I am developing package, so I put my factories to custom path like this:
-- app
-- packages
-----mockizart
-------blog
---------database
--------------factories
----------------- PageModelFactory.php
---------src
this is how i load factory in my service provider (I already make sure the path is correct by clicking it on phpstorm):
function boot()
{
Factory::construct($this->app->make(\Faker\Generator::class), __DIR__."/../database/factories");
}
this is my page model factory (I already made sure this file was really loaded):
<?php
/** #var \Illuminate\Database\Eloquent\Factory $factory */
use Mockizart\Blog\Dodols\PageModel;
use Faker\Generator as Faker;
$factory->define(PageModel::class, function (Faker $faker) {
return [
'name' => "retretre",
'slug' => "retretret",
'type' => 0,
'category' => 0,
'tags' => "",
'content' => "",
];
});
and this is my script test :
use Mockizart\Blog\Dodols\PageModel;
.....
.....
/** #test */
public function edit_page()
{
dd(PageModel::find(1)); <-- this return was NULL so I think my class and namespace does exist.
factory(PageModel::class)->make(); <-- this cause error "unable to locate factory......"
$response = $this->get('/blog/page/edit/15');
$response->assertStatus(200);
}
so if you are using orchestra\Testbench, the correct way to load custom factories is in the setUp() method of your Test class or TestCase NOT in your Service Provider.
the code would be like this:
class TestCase extends \Orchestra\Testbench\TestCase
{
public function setUp(): void
{
parent::setUp();
// additional setup
$this->loadMigrationsFrom(__DIR__ . '/../database/migrations');
$this->withFactories(__DIR__.'/../database/factories');
}
protected function getPackageProviders($app)
{
return BlogServiceProvider::class;
}
}

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'db.store' doesn't exist

When I try to save data from laravel form to a database table I am getting the following exception:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'db.store' doesn't exist (SQL: select count(*) as aggregate from store where name = samplename)
the table store exists but still I am getting the error
this is my contoller that is processing the form:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\storestore;
use App\Http\Requests\storeFormRequest;
class AddstoreController extends Controller
{
//
public function create()
{
//
}
public function store( storeFormRequest $request)
{
$store = new Store;
$store->name = Input::get('name');
$store->description = Input::get('description');
$store->store_vendor_id = Input::get('owner');
$store->contact_email = Input::get('contact_email');
$store->postal_address = Input::get('postal_address');
$store->city = Input::get('city');
$store->zip = Input::get('zip');
$store->phone = Input::get('phone');
$store->business_logo = Input::get('logo');
$store->save();
return \Redirect::route('add_store_success')
->with('message', 'Thanks for joining us!');
}
}
This is my Store model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Store extends Model
{
//
protected $table = 'stores';
protected $fillable = ['name', 'description', 'vendor_id',
'contact_email','postal_address','city','zip','phone',
'meta_description','business_logo'];
}
StoreRequest file:
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
use App\StoreController;
class StoreFormRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
//
'name' => 'required|unique:dstore',
'vendor_id' => 'required',
'contact_email' => 'required|email|max:100|unique:dstore',
'business_logo' => 'required',
];
//validate
if ($validation->fails())
{
return redirect()->back()->withErrors($v->errors());
}
}
}
These are the get and post routes:
Route::get('/store_form', ['as' => 'add_store_form', 'uses' => 'StoreController#create']);
Route::post('/store_form',['as' => 'dstore', 'uses' => 'StoreController#store']);
Both routes are listed when I run php artisan route:list command
I have tried to goggle for solution but the one I landed on pointed out to missing tables as a course, but in my case the store table is existing but still I am getting the error.
Any help please!
Look at your Store model class:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Store extends Model
{
//
protected $table = 'stores';
protected $fillable = ['name', 'description', 'vendor_id',
'contact_email','postal_address','city','zip','phone',
'meta_description','business_logo'];
}
As you see property $table is set to stores so I assume table name in your database is stores and not store.
You should probably change in your StoreFormRequest content or rules method to use in unique rule valid table name, for example:
public function rules()
{
return [
//
'name' => 'required|unique:stores',
'vendor_id' => 'required',
'contact_email' => 'required|email|max:100|unique:stores',
'business_logo' => 'required',
];
//validate
if ($validation->fails())
{
return redirect()->back()->withErrors($v->errors());
}
}

Resources