PHPUnit assertDatabaseHas with Laravel and Inertia - php

I have a Laravel 8 setup that utilises Intertia.js. I'm trying to test my post routes to store new resources and want to assert that the database has the new record stored, using the assertDatabaseHas() method.
Controller.php
public function store(SlotCreate $request): RedirectResponse
{
$slot = CreateSlot::dispatchNow($request);
return redirect()->back()->with([
'message' => 'Slot Created Successfully.',
'slot' => new SlotResource($slot)
]);
}
CreateSlotTest.php
public function testCreateSlot()
{
$response = $this->actingAs($this->teamAdminOne)->post('/slots', [
'start_time' => '09:00',
'end_time' => '10:00',
'max_bookings' => 3
]);
$response->assertStatus(302);
$this->assertDatabaseHas('slots', [
'id' => ???
'team_id' => $this->teamAdminOne->currentTeam(),
'start_time' => '09:00',
'end_time' => '10:00',
'max_bookings' => 3
]);
}
When I debug the session I can see the slot that I added to the with() method but I can't figure out how to access it.
I'd like to know if I'm returning the slot correctly in the controller and if yes, how do I access the response to assert if the database has this record?

Actually when you call redirect()->with(), it adds the variables into the session by calling the session()->flush() method. So in this case you can retrieve the variables via Illuminate\Support\Facades\Session facade.
$slot = Illuminate\Support\Facades\Session::get('slot')

Related

There is nothing happening when store data for Laravel API

I making laravel API where i can store a new data where the value in body raw json. but when i try to send request using post, i got nothing but the status is 200 OK. when i chek my mysql there is no data inputed.
So, what should i do?
mysql data
Laravel Controller, and API,
// function in controller
use App\Models\ChartAge;
class ChartController extends Controller
{
public function saveChart(Request $request)
{
$data = $request->validate([
'entity' => 'required|string|max:10',
'code' => 'required|string|max:10',
'year' => 'required|int|max:10',
'under_age_15' => 'required|string|max:50',
'age_15_64' => 'required|string|max:50',
'age_65_over' => 'required|string|max:50',
]);
$values = ChartAge::create($request);
return response()->json(
[
'status' => true,
'message' => "the videos has been favorites",
'data' => $values,
],
201
);
}
}
//in api.php
Route::post("charts", [ChartController::class, 'saveChart']);
and here is when i tried to send request using postman.
because there is no error, i don't know what's wrong??
First double check your ChartAge model, does it have $fillable or not?
and Edit your code:
From
$values = ChartAge::create($request);
To:
$values = ChartAge::create($request->all());
Hope this will be useful.
With validation:
$data = \Validator::make($request->all(),[
'entity' => 'required|string|max:10',
'code' => 'required|string|max:10',
'year' => 'required|int|max:10',
'under_age_15' => 'required|string|max:50',
'age_15_64' => 'required|string|max:50',
'age_65_over' => 'required|string|max:50',
]);
if($data-> fails()){
return back()->withErrors($data)->withInput();
}
$values = ChartAge::create($request->all());
Do you set fillable fields in your 'ChartAge' model?
protected $fillable = ['entity','code','year'...];
Do you try to test code with disabling validation?
Please try to put dd($request) in the first row of the controller code.
Method create expects a plain PHP array, not a Request object.

Matching factory values in Laravel 7

Good Afternoon,
I'm trying to create a Laravel factory where 2 of the 'columns' have the same values every time its called and the rest of the factory can be random.
For instance, I have the following columns in my DB
name
email
phone_number
status_message
status_code
I currently have my factory as follows;
$factory->define(Brand::class, function (Faker $faker) {
return [
'name' => $faker->unique()->company,
'email' => $faker->companyEmail,
'phone_number' => $faker->phoneNumber
];
});
This part works perfectly, as it should, the problem is that each specific status message comes with an individual status code. Is there a way I could add an array of status messages with a status code and have the factory pick a set at random for that record?
The status code / messages are listed below in array format;
[
'3e2s' => 'tangled web',
'29d7' => 'get certified',
'2r5g' => 'art of war',
]
I hope this makes sense. any help would be greatly appreciated.
as i can understand u need to pick random from this array u mentioned in above
$factory->define(Brand::class, function (Faker $faker) {
$data = [
'3e2s' => 'tangled web',
'29d7' => 'get certified',
'2r5g' => 'art of war',
];
$statusCode = array_rand($data);
$statusMessage = $data[$statusCode];
return [
'name' => $faker->unique()->company,
'email' => $faker->companyEmail,
'phone_number' => $faker->phoneNumber,
'status_message' => $statusMessage,
'status_code' => $statusCode,
];
});

How should I use factories in Laravel when I have default values in DB

I have a factory:
$factory->define(\App\MissingData::class, function (Faker $faker) {
$operations = Operation::all()->pluck('id')->toArray();
$operationId = $faker->randomElement($operations);
$operation = Operation::find($operationId);
$meters = $operation->meters->pluck('id')->toArray();
$arrStatus = ['Done', 'Undone'];
return [
'operation_id' => $operationId,
'meter_id' => $faker->randomElement($meters),
'date_ini' => $faker->dateTimeThisYear,
'date_end' => $faker->dateTimeThisYear,
'status' => $faker->randomElement($arrStatus),
];
});
In my migration, I have:
$table->string('status')->default('Undone');
When I want to insert an array in DB, I always prefer to use factory:
factory(MissingData::class)->create($missingData);
with
return [
'operation_id' => $measure->operation_id,
'meter_id' => $measure->meter_id,
'conso_prod' => $measure->conso_prod,
'date_ini' => $missingDataIni,
'date_end' => $missingDataEnd,
];
The wanted behaviour is to insert the status: 'Undone' configured in DB, but my factory will generate a fake status, so I will always have to send Undone status to my factory, which is not the point of using a DB default.
How am I supposed to manage this. Using factory to create and insert model is a good practice.
Using default in DB is also very practical, I believe they can be used both at the same time, but I don't see how should I do that.
Any idea ?
Your best bet is probably to default the status to undone then have a seperate state for done and any other status' that you may add.
$factory->define(\App\MissingData::class, function (Faker $faker) {
$operations = Operation::all()->pluck('id')->toArray();
$operationId = $faker->randomElement($operations);
$operation = Operation::find($operationId);
$meters = $operation->meters->pluck('id')->toArray();
return [
'operation_id' => $operationId,
'meter_id' => $faker->randomElement($meters),
'date_ini' => $faker->dateTimeThisYear,
'date_end' => $faker->dateTimeThisYear,
'status' => 'Undone',
];
});
$factory->state(\App\MissingData::class, 'done', fn() => ['status' => 'Done']);
Then when you want the status to be done you would use the state like this.
factory(\App\MissingData)->state('done')->create();

Lumen 5.4: PHPUnit: How to test authorisation?

I am working on an ecommerce project, a generic book shop.
I started out with a Test Driven approach, and I adhered to it fully till now.
Different endpoints on this Lumen Microservice project have been successfully tested earlier to make sure they do CRUD operations. However, as I have to protect the Create, Update and Delete method with token authorisation, I am quite confused how to introduce tests for authorisation.
As of now this is my testing structure:
tests/app/Exceptions/HandlerTest.php
tests/app/Http/Controllers/BooksControllerTest.php
The tests are for index, show, store, update, delete. This is one of the tests:
public function testStoreBookByPost()
{
$book = factory('App\Book')->make();
$this->post(
'/books',
[
'isbn' => $book->isbn,
'title' => $book->title,
'description' => $book->description,
'author' => $book->author,
'image' => $book->image,
'price' => $book->price,
'slug' => $book->slug
]
);
$this
->seeJson(
[
'created' => true
]
)
->seeInDatabase(
'books',
[
'title' => $book->title
]
);
}
I had earlier separated Exception Handler tests, similarly I would prefer to separate the AuthControllerTest to AuthControllerTest.php.
What is the best way to do this?
Do I need to write the authorisation tests by refactoring all the BooksControllerTest?
Or should I just test for issuing of token and inability to manipulate database? Would that be fine?
Short answer: I needed to write the authorisation tests by refactoring all the BooksControllerTest
Long answer: I found out a fantastic way of logging in dummy users during testing.
With that I have created this method.
public function loginWithUserGetJWT()
{
$user = factory('App\User')->create(
[
'password' => bcrypt('366643') // random password
]
);
$content = $this
->post(
'/auth/login',
[
'email' => $user->email,
'password' => '366643'
]
)
->seeStatusCode(200)
->response->getContent();
$token = json_decode($content)->token;
return $token;
}
And I am reusing this method in all the test cases, like so:
public function testStoreBookByPost()
{
$token = $this->loginWithUserGetJWT();
$book = factory('App\Book')->make();
$this->post(
'/books',
[
'isbn' => $book->isbn,
'title' => $book->title,
'description' => $book->description,
'author' => $book->author,
'image' => $book->image,
'price' => $book->price,
'slug' => $book->slug,
'token' => $token
]
);
$this
->seeJson(
[
'created' => true
]
)
->seeInDatabase(
'books',
[
'title' => $book->title
]
);
}

How to use updateOrCreate proprely

Here is my code :
$user = \App\User::where('id', $uid)->firstOrFail();
$user->token()->updateOrCreate(['user_id' => $uid, 'type' => $type], [
'auth' => $auth_token,
'refresh' => $refresh_token,
'type' => $type
]);
I've got two models User and Token with an 'one to one' relationship.
On the first line, I try to catch a User into the database, then I update my model with the updateOrCreate() method.
However, as you can read it, I must use a selector 'user_id' => $uid before to successfully update my model. I think Eloquent should be able to manage it in a different way without making two requests.
You don't have to use the user_id => $uid on that query. It's injected based on the relationship already. You can rewrite that to:
$token = \App\User::where('id', $uid)->firstOrFail()->token()->updateOrCreate(['type' => $type], [
'auth' => $auth_token,
'refresh' => $refresh_token,
'type' => $type
]);

Categories