Closed sandervanhooft closed 7 years ago
Why are you trying to test this? This package already tests that cover the thing you mention. You can take a look at them.
Our package already has test to make sure that this functionality works.
I'm assuming your test doesn't work because behind the screens Storage::fake
is a real disk and expect real files and UploadFile::fake()
is not a real file.
Hi @canvural , @freekmurze ,
I understand that these feature tests are already covered in the package (which is great). But I need to test the package's integration within my app - I was talking about my app's feature tests, not the package's, sorry for any confusion.
How would you recommend doing this, as Storage::fake()
seems to not support this?
By the way, I experience the same issue with all medialibrary storage methods when combined with Storage::fake()
, including addMediaFromUrl()
(so no UploadFile::fake()
here).
Addendum: the test I shared above is a stripped-down shareable example of what happens when I try to test this functionality. The actual tests are richer, testing real app behavior.
Haven't worked with Storage::fake
myself just yet, so can't advise you there.
You could take the same approach as we did in our package tests. Create a real disk and manually make asserts against the filesystem.
I will give that a try, thanks!
On Wed, 26 Apr 2017 at 13:56 Freek Van der Herten notifications@github.com wrote:
Haven't worked with Storage::fake myself just yet, so can't advise you there.
You could take the same approach as we did in our package tests. Create a real disk and manually make asserts against the filesystem.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/spatie/laravel-medialibrary/issues/623#issuecomment-297378700, or mute the thread https://github.com/notifications/unsubscribe-auth/AG7dp8wxxQOYPcpB1TACE2D_qfgiCo6Hks5rzzDKgaJpZM4NImXs .
Hi @sandervanhooft ,
Did you finally find a way ? Thanks.
I'm on the road currently so I can't access my code the next two weeks...
This is what I think I did in the end:
I dropped the fake and used the normal mode instead, used a stub file, learned the path used by medialibrary to save it. The test now checks if the file is stored at that path. On Tue, 5 Sep 2017 at 18:31, Jérôme Coppée notifications@github.com wrote:
Hi @sandervanhooft https://github.com/sandervanhooft ,
Did you finally find a way ? Thanks.
— You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/spatie/laravel-medialibrary/issues/623#issuecomment-327230975, or mute the thread https://github.com/notifications/unsubscribe-auth/AG7dp8yLy7g6EBDlmRopR1uhtHxArsCNks5sfXcsgaJpZM4NImXs .
And ofcourse clean up the stub file afterward :) On Tue, 5 Sep 2017 at 20:11, Sander van Hooft info@sandervanhooft.nl wrote:
I'm on the road currently so I can't access my code the next two weeks...
This is what I think I did in the end:
I dropped the fake and used the normal mode instead, used a stub file, learned the path used by medialibrary to save it. The test now checks if the file is stored at that path. On Tue, 5 Sep 2017 at 18:31, Jérôme Coppée notifications@github.com wrote:
Hi @sandervanhooft https://github.com/sandervanhooft ,
Did you finally find a way ? Thanks.
— You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/spatie/laravel-medialibrary/issues/623#issuecomment-327230975, or mute the thread https://github.com/notifications/unsubscribe-auth/AG7dp8yLy7g6EBDlmRopR1uhtHxArsCNks5sfXcsgaJpZM4NImXs .
Of course :) Thanks for your message !
In case anyone else is still struggling with testing file uploads using MediaLibrary. As noted above, when faking the 'media' storage, the uploaded files can't be found.
This basic test example works for me. I'm running this test in a package repo, using orchestral/testbench, but I suppose this should also work in a normal Laravel app. I'm using Laravel 5.5.
Instead of faking the storage disk, I just change the root path of the disk in the config.
I have this controller method to add a photo to a Post
:
public function store(Post $post)
{
request()->validate([
'photo' => "required|image",
]);
return $post->addMediaFromRequest('photo')->toMediaCollection('photos');
}
In the test I create a fake photo, send it via a POST request and then assert that it is added to the Post
and that it exists in the filesystem. This also works with conversions.
/** @test */
public function a_photo_can_be_added_to_a_post()
{
$this->withoutExceptionHandling();
config()->set('filesystems.disks.media', [
'driver' => 'local',
'root' => __DIR__.'/../../temp', // choose any path...
]);
config()->set('medialibrary.default_filesystem', 'media');
$photo = \Illuminate\Http\Testing\File::image('photo.jpg');
$response = $this->postJson($this->url(), [
'photo' => $photo,
]);
$response->assertStatus(200);
$photos = $this->post->getMedia('photos');
$this->assertCount(1, $photos);
$this->assertFileExists($photos->first()->getPath());
$this->assertFileExists($photos->first()->getPath('thumb'));
}
Note that the temp folder is not cleared automatically, so you should do that in the setUp
probably.
Thank you for sharing!
I’d make sure the temp folder is clean both at tearDown() and setUp() (in case the testrun for whatever reason crashes and does not make it to tearDown()). On Fri, 10 Nov 2017 at 16:48, Ivan Vermeyen notifications@github.com wrote:
In case anyone else is still struggling with testing file uploads using MediaLibrary. As noted above, when faking the 'media' storage, the uploaded files can't be found.
This basic test example works for me. I'm running this test in a package repo, using orchestral/testbench https://github.com/orchestral/testbench, but I suppose this should also work in a normal Laravel app. I'm using Laravel 5.5.
Instead of faking the storage disk, I just change the root path of the disk in the config.
I have this controller method to add a photo to a Post:
public function store(Post $post){ request()->validate([ 'photo' => "required|image", ]); return $post->addMediaFromRequest('photo')->toMediaCollection('photos');}
In the test I create a fake photo, send it via a POST request and then assert that it is added to the Post and that it exists in the filesystem. This also works with conversions.
/* @test /public function a_photo_can_be_added_to_a_post(){ $this->withoutExceptionHandling(); config()->set('filesystems.disks.media', [ 'driver' => 'local', 'root' => DIR.'/../../temp', // choose any path... ]); config()->set('medialibrary.default_filesystem', 'media'); $photo = \Illuminate\Http\Testing\File::image('photo.jpg'); $response = $this->postJson($this->url(), [ 'photo' => $photo, ]); $response->assertStatus(200); $photos = $this->post->getMedia('photos'); $this->assertCount(1, $photos); $this->assertFileExists($photos->first()->getPath()); $this->assertFileExists($photos->first()->getPath('thumb'));}
Note that the temp folder is not cleared automatically, so you should do that in the setUp probably.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/spatie/laravel-medialibrary/issues/623#issuecomment-343508764, or mute the thread https://github.com/notifications/unsubscribe-auth/AG7dp79M8VmghW8zFxTcr1F3xI8rDntkks5s1HBcgaJpZM4NImXs .
Just in case anyone else finds this, on the back of @ivanvermeyen 's code above - if you want to take advantage of Laravel's Storage::fake() so that your test uploads are cleaned up etc, you can try this :
// some test function
Storage::fake('images');
config()->set('filesystems.disks.images', [
'driver' => 'local',
'root' => Storage::disk('images')->getAdapter()->getPathPrefix(),
]);
// do some test code that triggers your upload, then if you want you can :
$this->assertFileExists($model->getFirstMedia('my-collection')->getPath());
Edit: oh, and if you're trying to test code that outputs a view that uses the getUrl() from a media item, you might need to over-ride the default LocalUrlGenerator too as it throws an exception if the URL doesn't seem to be public (as far as I can see anyway). So I made a fake url generator which just skipped the exception check :
<?php
namespace Tests\Feature;
use Spatie\MediaLibrary\UrlGenerator\LocalUrlGenerator;
class FakeStorageUrlGenerator extends LocalUrlGenerator
{
protected function getBaseMediaDirectoryUrl() : string
{
if ($diskUrl = $this->config->get("filesystems.disks.{$this->media->disk}.url")) {
return str_replace(url('/'), '', $diskUrl);
}
// conditional that throws exception was here
return $this->getBaseMediaDirectory();
}
}
Then in the test :
Storage::fake('images');
config()->set('filesystems.disks.images', [
'driver' => 'local',
'root' => Storage::disk('images')->getAdapter()->getPathPrefix(),
]);
config()->set('medialibrary.url_generator', 'Tests\Feature\FakeStorageUrlGenerator');
// now you can get your view without an exception being thrown
@ohnotnow I might be wrong, but seems like provided solution stopped working after this commit: https://github.com/spatie/laravel-medialibrary/blob/1f4dabfb84a2f4cb795ed075e7a75a2daebfa549/src/Support/File.php
Finfo
returns application/x-empty mimetype
hi,
is it possible to fake addMediaFromUrl()?
I've seen it uses fopen internally, so I tried to trick it with passing a local file, but it throws an exception if the path does not start with http.
My scenario is that I have some service that calls an external api, then gets a list of file URIs to download. This list is then passed to $model->addMediaFromUrl()
I can fake the api output, but how could I pass some fake url to addMediaFromUrl and expect it to add a file?
thanks, dan
Hi! If you absolutely need to use fake storage, you can replace assertExists with assertEquals, using the id and filename that should be generated:
$this->assertEquals('/storage/1/name-of-uploaded-file.jpg', $yourModel->getFirstMediaUrl('media_collection_name'));
thanks @paolocaccavo , but what I need is to be able to access $model->addMediaFromUrl within a service, not just test the url of the item
The main problem seems to be that the assertExists
expects a path relative to the disk, but the getPath
method return full path from the root of the actual filesystem.
The default path within the disk is $file->id.'/'.$file->file_name
, but that can be overriden. It seems that to get the "actual" path we have to reach inside for the generator: $file->getUrlGenerator('')->getPathRelativeToRoot()
. Here's a full example:
Storage::fake('media');
$response = $this->post(
$uri,
[
...$otherData,
'attachments' => [
UploadedFile::fake()->create('somefile.docx', 13),
UploadedFile::fake()->create('otherfile.png', 17),
],
],
)->assertCreated();
$id = $response->getData()->data->id;
$obj = MyObject::find($id);
$media = $obj->getMedia('attachments');
$this->assertEquals(2, $media->count());
foreach ($media as $file)
Storage::disk('media')->assertExists($file->getUrlGenerator('')->getPathRelativeToRoot());
Storage::disk('media')->assertExists($file->getUrlGenerator('')->getPathRelativeToRoot());
Thanks :+1: That was the line of code that I was looking for!
In my case, it was even shortened
Storage::disk('media')->assertExists($file->getPathRelativeToRoot());
When I have done those steps, test works but I can see that all pictures are uploaded to the server and after test they are still there. Is there a solution for fix this ?
Just in case anyone wants to write a test case for file upload in Laravel 11, can use the provided code sample below.
it('can update own profile', function () {
$user = User::factory()->create();
$header = $this->getAuthHeader($user); // set Authorization Bearer Token
Storage::fake('avatars');
config()->set('filesystems.disks.media', [
'driver' => 'local',
'root' => Storage::disk('avatars')->path(''),
]);
$data = [
'first_name' => 'test',
'last_name' => 'user',
'avatar' => UploadedFile::fake()->image('avatar.jpg', 500, 500)->size(512)
];
$response = $this->putJson( url('/api/v1/profile'), $data, $header );
$response->assertStatus(Response::HTTP_OK)
->assertJson([
'status' => 'success',
'message' => 'Profile has been updated successfully.'
]);
$this->assertDatabaseHas('users', [
'first_name' => $data['first_name'],
'last_name' => $data['last_name']
]);
$this->assertFileExists($user->getFirstMedia( 'PUT_YOUR_COLLECTION_NAME_HERE' )->getPath());
});
Thanks for sharing this great package!
What would be the recommended way of asserting that a file was stored in a feature test? I have tried the Laravel Storage::fake('media') facade with this package to no avail. It would be great to have this documented.
Result:
The files appear to be stored on the expected path in production just fine though.