MediaLibrary::fake() swaps the manager for a recording fake and returns it:
use RoundlyConsulting\MediaLibrary\Facades\MediaLibrary;
$fake = MediaLibrary::fake();
$this->post('/profile/avatar', ['avatar' => UploadedFile::fake()->image('me.png')]);
$fake->assertAdded('avatar', to: $user);
$fake->assertNothingDeleted();- It writes nothing — no file on any disk, no row, no queued job, no event — so a test needs neither real disks nor Storage::fake().
- It records every call, whether it came through the facade, an injected MediaLibraryManager, a for() handle, the InteractsWithMedia trait or a Media model method.
- Mutations still return something realistic: adds, attaches and copies return an unsaved Media with a fresh uuid, owner, bucket, disk, visibility and the same safe file name a real add stores; moves re-point the media in memory.
- Bucket acceptance rules (mime allowlist, size cap, image dimensions) still apply to adds and draft binds, and an unknown or expired draft token still throws. Reads run against the database as usual.
Assertions
Every argument is an optional filter; null matches anything:
$fake->assertAdded('avatar', to: $user);
$fake->assertAttached($logo, to: $user, bucket: 'avatar');
$fake->assertDraftBound($token, to: $user, bucket: 'avatar');
$fake->assertMoved($media, to: $otherUser, bucket: 'gallery', disk: 'cold');
$fake->assertVariantsMoved($media, disk: 'hot');
$fake->assertCopied($media, to: $otherUser, bucket: 'gallery');
$fake->assertReplaced($media);
$fake->assertDeleted($media); // clear() records one delete per media
$fake->assertRegenerated($media, only: ['thumb'], force: true);
$fake->assertDraftsPruned();
// The negative counterparts
$fake->assertNothingAdded();
$fake->assertNothingAttached();
$fake->assertNothingBound();
$fake->assertNothingMoved();
$fake->assertNoVariantsMoved();
$fake->assertNothingCopied();
$fake->assertNothingReplaced();
$fake->assertNothingDeleted();
$fake->assertNothingRegenerated();
$fake->assertDraftsNotPruned();End-to-end against a faked disk
When you want real files and generated variants, skip the fake and use Storage::fake() for the bucket's disks:
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use RoundlyConsulting\MediaLibrary\Facades\MediaLibrary;
it('stores an avatar and generates a thumbnail', function () {
Storage::fake('cold');
Storage::fake('hot');
$user = User::factory()->create();
MediaLibrary::for($user)
->add(UploadedFile::fake()->image('me.jpg', 600, 600))
->toBucket('avatar');
$avatar = MediaLibrary::for($user)->first('avatar');
expect($avatar->hasGeneratedVariant('thumb'))->toBeTrue();
Storage::disk('cold')->assertExists($avatar->getPath());
});Run your suite with the package's migration loaded (RefreshDatabase). Queued variants run synchronously under the sync queue in tests, so generated variants are assertable immediately.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.