$job->id is coming back as null because you used the make() factory method instead of create(). You can clearly see that $job has no id field in the dump you shared. Your BidReserve factory is already creating a User and Job when it builds a BidReserve. Remove the first two factory()->make(). Then pass $bidreseve->job (assuming you have setup the relation) to payBidReserve. Or if you haven't setup relations, just pass on $bireserve->job_id and make sure to edit the function to work with an integer.
findOrFail($jobId); returns 404 but test creates $job
error: Symfony\Component\HttpKernel\Exception\NotFoundHttpException: POST http://bidbird.test/jobs//bidreserve
As you can see above, the $job->id is not found.
class BidReservesController extends Controller
{
private $paymentGateway;
public function __construct(PaymentGateway $paymentGateway)
{
$this->middleware('auth');
$this->paymentGateway = $paymentGateway;
}
....
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store($jobId)
{
// dd($job);
$job = Job::incomplete()->findOrFail($jobId);
dd($job);
// dd($this->request);
$this->validate(request(), [
'bidreserve' => 'required|integer'
]);
$bidreserve = BidReserve::create([
'bidreserve' => 500,
'job_id' => request($job->id),
'user_id' => auth()->user()->id
]);
// Charging the customer
$this->paymentGateway->charge(request('bidreserve'), request('payment_token'));
// dd($job);
return response()->json([], 201);
return view('jobs.show', compact('bidreserve', 'job'));
}
<?php
namespace Tests\Feature;
use App\BidReserve;
use App\Job;
use App\User;
use App\Billing\FakePaymentGateway;
use App\Billing\PaymentGateway;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;
class PayBidReservesTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
$this->paymentGateway = new FakePaymentGateway;
$this->app->instance(PaymentGateway::class, $this->paymentGateway);
Event::fake();
}
private function payBidReserve($job, $params)
{
$this->response = $this->json('POST', "/jobs/{$job->id}/bidreserve", $params);
}
/**
* A basic feature test example.
*
* @return void
*/
/** @test */
public function a_bidder_can_pay_reserve_fee()
{
$this->withoutExceptionHandling();
Event::fake();
$job = factory(Job::class)->make();
$user = factory(User::class)->make();
$bidreserve = factory(BidReserve::class)->create();
// dd($job);
// dd($this->paymentGateway);
// $this->actingAs($user);
// dd($user);
$this->actingAs($user)->payBidReserve($job, [
'bidreserve' => 500,
'user_id' => $user->id,
'job_id' => $job->id,
'payment_token' => $this->paymentGateway->getValidTestToken()
]);
$this->response->assertStatus(201);
}
}
<?php
/* @var $factory \Illuminate\Database\Eloquent\Factory */
use App\BidReserve;
use App\Job;
use App\User;
use Faker\Generator as Faker;
$factory->define(BidReserve::class, function (Faker $faker) {
return [
'user_id' => function() {
return factory(User::class)->create()->id;
},
'job_id' => function() {
return factory(Job::class)->create()->id;
},
'bidreserve' => 500,
// 'job_id' => $this->faker->numberBetween(1, 10),
// 'user_id' => $this->faker->numberBetween(1, 100),
];
});
Ok, when I dd($job); at the test it gives:
#attributes: array:11 [
"jobtitle" => "Sequi veniam quia explicabo omnis quidem."
"body" => "Qui veritatis quia sunt id distinctio soluta fugit. Temporibus ut aliquid veniam alias. Debitis optio maxime non a quos. Velit voluptatem dicta placeat quia possimus. Ex delectus debitis voluptas aperiam."
"deadline" => "2019-09-10 01:16:36"
"user_id" => 1
"projectaddress" => "354 Rolfson Skyway Suite 563"
"city" => "New Heavenchester"
"state" => "Indiana"
"zipcode" => "78306"
"biddertype" => "consectetur"
"job" => "eveniet"
"subjob" => "cumque"
]
as expected.
when dd($bidreserve); it gives:
#attributes: array:6 [
"user_id" => 2
"job_id" => 1
"bidreserve" => 500
"updated_at" => "2019-08-13 01:17:32"
"created_at" => "2019-08-13 01:17:32"
"id" => 1
]
#original: array:6 [
"user_id" => 2
"job_id" => 1
"bidreserve" => 500
"updated_at" => "2019-08-13 01:17:32"
"created_at" => "2019-08-13 01:17:32"
"id" => 1
]
//routes.web
Route::post('/jobs/{job}/bidreserve', 'BidReservesController@store')->name('bidreserve');
I have a few questions: if you create job_id and user_id in the BidReserveFactory is it proper to use make() in the test vs. create()?
Is that why there are two users?
But still perplexed why the $job->id is not available when it hits the controller....
thank you ~
I want to point out a couple of things here. From what I understand, a BidReserve is an object created when a when a User places a bid on a Job. I noticed your tests are performing the test in a wrong way. Here is how you should go about testing the process.
First of all, you want to create a Job and a User. This is easy enough with the following lines:
$user = factory (User::class)->create();
$job = factory (Job::class)->create();
Then you'll need to hit some endpoint to create a BidReserve. In your case that'll look something like this:
$response = $this->actingAs($user)->json('POST', "jobs/{$job->id}/bidreserve", [
"bid_reserve" => 500,
"payment_token" => $this->paymentGateway->getValidTestToken()
]);
You don't need to pass in a user_id because it's better to fetch that from the Auth facade or auth() helper. You also don't need to pass the job_id because you can get that from the URL. Then you can have assertions such as:
$response->assertStatus(201);
$this->assertCount(1, $job->bids); // assuming there exists such a relationship
Then in your BidReservesController.php make the following changes:
public function store($jobId)
{
$job = Job::incomplete()->findOrFail($jobId);
$this->validate(request(), [
'bid_reserve' => 'required | integer | min:1'
]);
$bidReserve = BidReserve::create([
'bid_reserve' => request('bid_reserve'),
'user_id' => auth()->user()->id,
'job_id' => $jobId
]);
$this->paymentGateway->charge(request('bid_reserve'), request('payment_token'));
return response()->json($bidReserve, 201);
}
Things to note here. There is probably a better way of creating BidReseves. Like using a relationship on the User or Job. Like auth()->user()->bids()->create(...). You should also account for situations where the payment might fail. Maybe create the bid only after a successful charge. And you had two return statements in your store method which is kinda wrong because the second return is never reached.
Please or to participate in this conversation.