Laravel Unit Testing for update method not working - laravel

I am trying to unit test the update function in a resource controller and I keep getting an error Call to undefined method assertStatus(). Here is my code: $this->withoutExceptionHandling();
$this->withoutExceptionHandling();
$timesheet = factory(TimeSheets::class)->create();
$user = factory(UsersLoginModel::class)->create();
$data = [
'subject' => $this->faker->text,
'subjectmatter' => $this->faker->text,
'description' => $this->faker->text,
];
;
$update = $this->actingAs($user)->json('PATCH','timesheets/update'.$timesheet->id, $data);
$this->assertStatus(200);
$this->assertEquals($data['subject'], $timesheet->subject);
$this->assertEquals($data['subjectmatter'], $timesheet->subjectmatter);
$this->assertEquals($data['description'], $timesheet->description);

The assertStatus assertion, is not on the Illuminate\Foundation\Testing\TestCase class, but on the Illuminate\Foundation\Testing\TestResponse class so in your code you need to use it like so:
$update = $this->actingAs($user)->json('PATCH','timesheets/update'.$timesheet->id, $data);
$update->assertStatus(200);

Related

Laravel 8 multiple models to single view Error $address Not defined

I'm trying to create 2 rows in the DB using findOrNew() but when I use the ID from the Users model to create another model(Address) the programs returns undefined variable $address. I don't know if I'm using the correct approach or not. Bellow you can view my approach. Can you lead me to the right approach or where to find it?
2 models one view:
seeing what you have in your method is returning an undefined because it is not executing the findOrNew method correctly, check this link, maybe it will help you and this same
the second is that if you are passing the values by post everything will come to you in the $req parameter and only there then if you want to use the id you would have to access through $req->id if you send the data correctly
the third I see that in the view method you are passing 3 parameters when you should only pass two the first the name of the view the second the arrangement with the data that you will pass to the view
public function detail(Request $req)
{
$user = User::firstOrNew($req->id);
$user->user_type_id = 1;
$user->name = $req->name;
$user->last_name = $req->last_name;
$user->email = $req->email;
$user->password = Hash::make(Str::random(8));
$user->save();
$address = UserAddress::firstOrCreate(['user_id' => $req->id]); //or maybe $user->id
return view('user.detail', [
'user' => $user,
'adderss' => $address
]);
}
finally you may prefer to use the updateOrCreate method
public function detailV2(Request $req)
{
$user = User::updateOrCreate(
['id' => $req->id],
[
'user_type_id' => 1,
'name' => $req->name,
'last_name' => $req->last_name,
'email' => $req->email,
'password' => Hash::make(Str::random(8)),
]
);
$address = UserAddress::firstOrCreate(['user_id' => $user->id]);
return view('user.detail', [
'user' => $user,
'adderss' => $address
]);
}

How do I run a phpunit test on Redis pub/sub?

I'm building a messenger system with Redis publishing on the Laravel end and subscribing on a node server. I would like to test what is stored in the redis pub method using PHPUnit, but I have no idea where to start.
Controller
class MessageController extends Controller
{
public function store(Conversation $conversation, Request $request)
{
$user = Auth::user();
$message = Message::create([
'body' => $request->input('message'),
'conversation_id' => $conversation->id,
'sender_id' => $user->id,
'type' => 'user_message'
]);
$redis = Redis::connection();
$data = new MessageResource($message);
$redis->publish('message', $data);
}
}
Current Test
/** #test */
public function a_user_can_send_a_message()
{
$this->actingAs($user = User::factory()->create());
$message = Message::factory()->make(['sender_id' => $user->id]);
$conversation Conversation::factory()->create();
$response = $this->json('POST', '/api/message/'. $conversation->id, ['message' => $message->body])
->assertStatus(201);
$response->assertJsonStructure([
'data' => [
'body',
'sender',
]
]);
}
Essentially what I'm trying to see is if message has been published on Redis. I'm unsure how to do this, and I think you would probably need to clear the message from Redis after, would you not?
Your test should be like this:
public function test_a_user_can_send_a_message()
{
$redisSpy = Redis::spy();
$redisSpy->shouldReceive('connection')->andReturnSelf();
$this->actingAs($user = User::factory()->create());
$message = Message::factory()->make(['sender_id' => $user->id]);
$conversation = Conversation::factory()->create();
$this->postJson("/api/message/{$conversation->id}", ['message' => $message->body]);
$this->assertDatabaseCount('messages', 1);
$redisSpy->shouldHaveReceived('publish')
->with('message', new MessageResource(Message::first()));
}
As you can see, I have added Redis::spy(); this is going to allow is to "spy" what is called from Redis. You can still mock methods, and we have to do so, because you use Redis::connect(); and then $redis->publish(...), so we will return the spy when connect is called, that is why we do shouldReceive('connection')->andReturnSelf().
At the end of the code, we check that $redis->publish was called with parameters 'message' and a resource with the desired message. Both must match for this assertion to pass, else you will see a mock error.

Laravel factory cannot create because already has one

I want to create with factory in the test case but i got a validation error it say The name has already been taken. But how? It always refresh database every time the test start run.
The factory
$factory->define(Companies::class, function (Faker $faker) {
return [
'name' => $faker->unique()->company,
'email' => $faker->email,
'website' => $faker->url,
];
});
The test
Storage::fake('local');
$image = UploadedFile::fake()->image('avatar.jpg', 150, 150);
$companies = factory(Companies::class)->create([
'logo' => $image
]);
$company = $companies->toArray();
$this->actingAs($this->user);
$response = $this->postJson('/home/companies/create/add', $company);
$response->assertStatus(302);
i suggest to use the trait RefreshDatabase in your test then you reset the database after each test to avoid side effect.
just on the top of your test class write :
use RefreshDatabase;
Good luck

Trying to get property 'access_token' of non-object laravel-google-sheets

Good Night,I'm using google api sheets with laravel following this tutorial
https://github.com/kawax/laravel-google-sheets
when I try to do the first example
use Sheets;
$user = $request->user();
$token = [
'access_token' => $user->access_token,
'refresh_token' => $user->refresh_token,
'expires_in' => $user->expires_in,
'created' => $user->updated_at->getTimestamp(),
];
// all() returns array
$values = Sheets::setAccessToken($token)->spreadsheet('spreadsheetId')->sheet('Sheet 1')->all();
my code:
namespace App\Http\Controllers;
use Sheets;
use Google;
class PlanilhaController extends Controller
{
public function index(Request $request)
{
$user = $request->user();
$token = [
'access_token' => $user->access_token,
'refresh_token'=> $user->refresh_token,
'expires_in'=> $user->expires_in,
'created' => $user->updated_at->getTimestamp(),
];
$values = Sheets::setAccessToken($token)
>spreadsheet('spreadsheetId')->sheet('Sheet 1')->all();
// all() returns array
return view('planilha', compact('values'));
}
error: Trying to get property 'access_token' of non-object
which is not requested, but I do not know how to solve it
Actually you do not need that token, what you need is to set up your .env so it has following key
GOOGLE_APPLICATION_NAME=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_REDIRECT=
GOOGLE_DEVELOPER_KEY=
GOOGLE_SERVICE_ENABLED=
GOOGLE_SERVICE_ACCOUNT_JSON_LOCATION=
POST_SPREADSHEET_ID=
POST_SHEET_ID=
then in your controller
$sheets = Sheets::spreadsheet(config('sheets.post_spreadsheet_id'))
->sheet(config('sheets.post_sheet_id'))
->get();
$header = $sheets->pull(0);
$posts = Sheets::collection($header, $sheets);
$posts = $posts->reverse()->take(10);
then in your config file write this
'post_spreadsheet_id' => env('POST_SPREADSHEET_ID'),
'post_sheet_id' => env('POST_SHEET_ID'),

Method not allowed exception while updating a record

Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpExceptionNomessage
I'm getting this error while trying to update a record in the database. Don't know what's the problem. This question might be a duplicate but I've checked all and couldn't find the answer. Please Help me with this.
Controller Update Method:
public function updateEvent(Request $request, $id=''){
$name = $request->name;
$startdate = date_create($request->start_date);
$start_date = $startdate;
$time = $request->start_time;
$start_time = $time;//date("G:i", strtotime($time));
$endDate = date_create($request->end_date);
$end_date =$endDate;
$time_e = $request->end_time;
$end_time = $time_e;//date("G:i", strtotime($time_e));
$location = $request->location;
$description = $request->description;
$calendar_type = $request->calendar_type;
$timezone = $request->timezone;
if ($request->has('isFullDay')) {
$isFullDay = 1;
}else{
$isFullDay = 0;
}
DB::table('events')->where('id', $id)->update(
array(
'name' => $name,
'start_date' => $start_date,
'end_date' => $end_date,
'start_time' => $start_time,
'end_time' => $end_time,
'isFullDay' =>$isFullDay,
'description' => $description,
'calendar_type' => $calendar_type,
'timezone' => $timezone,
'location' => $location,
));
// Event Created and saved to the database
//now we will fetch this events id and store its reminder(if set) to the event_reminder table.
if(!empty($id))
{
if (!empty($request->reminder_type && $request->reminder_number && $request->reminder_duration)) {
DB::table('event_reminders')->where('id', $id)->update([
'event_id' => $id,
'type' => $request->reminder_type,
'number'=> $request->reminder_number,
'duration' => $request->reminder_duration
]);
}
}
else{
DB::table('event_reminders')->insert([
'type' => $request->reminder_type,
'number'=> $request->reminder_number,
'duration' => $request->reminder_duration
]);
}
return redirect()->back();
}
Route:
Route::post('/event/update/{id}', 'EventTasksController#updateEvent');
Form attributes :
<form action="/event/update/{{$event->id}}" method="POST">
{{ method_field('PATCH')}}
i'm calling the same update function inside my calendar page and it working fine there. Don't know why it doesn't work here.
Check the routeing method.
Route::patch('/event/update/{id}', 'EventTasksController#updateEvent');
patch should be the method called on route facade.
Change your route to patch:
Route::patch('/event/update/{id}', 'EventTasksController#updateEvent');
For your comment:
You can send the method to the ajax call by something like data-method attribute on the element you click on,take the method and use it in your ajax call. see this question/answer for help. How to get the data-id attribute?

Resources