Reputation: 127
I have written the following test in Laravel:
public function testUserCanUploadFile()
{
$this->withoutExceptionHandling();
$user = $this->signIn();
Storage::fake('public'); //Mock a disk
$file = UploadedFile::fake()->image('test.jpg'); //Upload a fake image.
$assortmentAttributes = Assortment::factory()->raw(); // Use the assortment factory.
$assortmentAttributes['image_path'] = $file; // Add a additional field in the assortment factory.
$this->post(route('assortments.store'), $assortmentAttributes)->assertRedirect(); // Post the fields to the assortmentcontroller store method.
//Storage::disk('public')->assertExists($file->hashName()); // Check if the field exists.
$this->assertFileExists($user->image_path);
}
I want to check if the file also exists in the database. In practice, the file upload works just fine. My test however, does not.
When I run my test I get the following error:
TypeError: Argument 1 passed to PHPUnit\Framework\Assert::assertFileExists() must be of the type string, null given
The field is not set on ->nullable()
in my migration. I also did dd($user->image_path)
. This just returns null
.
I also changed:
$assortmentAttributes['image'] = $file; // Add a additional field in the assortment factory.
To:
$assortmentAttributes['image_path'] = $file; // Add a additional field in the assortment factory.
To make sure the field name matches the field name in my assortment migration. Does anyone know how I can make sure that the file is found in my database field, so that my test finally works?
The code in my store method in my controller:
if ($request->hasFile('image')) {
$image = $request->file('image'); //request the file
$fileName = md5_file($image . microtime()) . '.' . $image->getClientOriginalExtension(); //use md5 for security reasons and get the extension.
$image->storeAs('', $fileName, 'public'); //store the file in the public folder disk.
}
if ($request->wantsJson()) {
return response([], 204);
}
What signIn()
does:
protected function signIn($user = null)
{
$user = $user ?: User::factory()->create();
$this->actingAs($user);
return $user;
}
Greetings,
Parsa
Upvotes: 0
Views: 2024
Reputation: 9
I noticed in your controller you are checking
($request->hasFile('image'))
While in the test you are sending
$assortmentAttributes['image_path'] = $file; // Add a additional field in the assortment factory.
You should instead update the test to
$assortmentAttributes['image'] = $file; // Add a additional field in the assortment factory.
Upvotes: 0
Reputation: 657
Based on my comment here you are creating a user of fly and it's not persisted so your endpoint assortments.store
does not know anything about it. You are mixing different kinds of testing approaches.
There are a few issues you need to address:
Probably the best way for you to tackle your specific problem: you need to call an action which is responsible for "assortments.store" directly from your test omitting Laravel Http Stack
Your code MAY looks like:
public function testUserCanUploadFile()
{
$this->withoutExceptionHandling();
$user = $this->signIn();
// saving fake storage into variable for later
$storage = Storage::fake('public'); // Mock a disk
$file = UploadedFile::fake()->image('test.jpg'); //Upload a fake image.
$assortmentAttributes = Assortment::factory()->raw(); // Use the assortment factory.
$assortmentAttributes['image_path'] = $file; // Add a additional field in the assortment factory.
$assortmentAttributes['user'] = $user; // passing user with request to controller
// init controller and pass fake "storage" as dependencies (that's probably you have it)
$controller = new AssortmentStoreController($storage);
$request = new Request($assortmentAttributes);
$response = $controller->handleAction($request); // calling action
// Assert your response
// Assert your fake storage
// Assert user image because it was changed by object reference.
$this->assertFileExists($user->image_path);
}
Upvotes: 2
Reputation: 71
It would be helpful to see exactly what your User
model looks like, but I think you just need to pull the updated user back from the database. Your current $user
variable will not contain the updated value because you haven't asked for it.
Try changing your assertion to:
$this->assertFileExists($user->fresh()->image_path);
fresh
will return a new instance of the model with the latest data from the database.
To update your user in your controller:
$request->user()->update(['image_path' => $fileName]);
Upvotes: 1
Reputation: 51
I would do dd($user);
Just after: $user = $this->signIn();
Probably you're getting wrong data in user
.
Upvotes: 1
Reputation: 3220
When $user->image_path
is null, file does not exist. You will receive failed test results. So, I suggest one line where you verify $user->image_path
value that is null or not.
$this->assertNotNull($user->image_path);
$this->assertFileExists($user->image_path);
Upvotes: 1