livewire/livewire: File upload testing example now matches its component (PR #10709)
Contributed by calebporzio
Part of the livewire v4.4.7 release
Category: Documentation
If you have ever copy-pasted the file-upload testing example from the Livewire docs and been greeted by a "component not found" error, pull request #10709 explains why. The example in docs/uploads.md shipped a test and a component that could never run together: the test referenced a namespaced class the example never defined, the component called storeAs() with a parameter that does not exist, and the two halves disagreed about which method they were exercising. This PR rewrites the example so the test and the single-file component actually match, then proves the pair works by executing it. It is a documentation-only change, so upgrading from v3.8.10 has no runtime impact — but if you pasted the old snippet into your own project, this is your cue to fix it.
What changed
The diff touches a single file, docs/uploads.md, and rewrites the "testing file uploads" section end to end:
- The test is now written in Pest style (
it('can upload a photo', function () { ... })) instead of a PHPUnit class, matching the Pest-first testing examples used elsewhere in the Livewire docs. - The test resolves the component by its alias,
Livewire::test('upload-photo'), rather than by a class reference likeLivewire::test(UploadPhoto::class). - The component's action is renamed from
upload($name)tosave(), and the test calls->call('save')with no arguments. - The storage disk is passed the supported way:
storeAs(path: '/', name: 'uploaded-avatar.png', options: 'avatars')instead of the brokendisk: 'avatars'named argument. - The component snippet is now a complete single-file component, including the Blade template with
<form wire:submit="save">and<input type="file" wire:model="photo">, so the example runs as-is.
Why the old example failed
Three independent problems compounded each other.
First, the test imported and targeted App\Livewire\UploadPhoto, but the accompanying example defines an anonymous, single-file component — class and template living in one file. That component is resolved by its kebab-case alias (upload-photo), not by a namespaced class, so the old test crashed with a component-not-found error. The PR author reproduced exactly that failure before fixing it.
Second, storeAs() has no $disk parameter. Its signature is storeAs($path, $name, $options = []), and when $options is a plain string Laravel interprets it as the disk name. Calling storeAs('/', $name, disk: 'avatars') therefore throws an "unknown named parameter" error at runtime — the disk was never actually honored.
Third, the test called ->call('upload', 'uploaded-avatar.png') even though the page's own guidance uses save(). A reader pasting both halves would face a failing component lookup, a failing store call, and a method-name mismatch between the two.
The corrected test and component
Here is what the docs now show — the Pest test:
<?php
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Livewire\Livewire;
it('can upload a photo', function () {
Storage::fake('avatars');
$file = UploadedFile::fake()->image('avatar.png');
Livewire::test('upload-photo')
->set('photo', $file)
->call('save');
Storage::disk('avatars')->assertExists('uploaded-avatar.png');
});
And the matching single-file component:
<?php
use Livewire\Component;
new class extends Component {
public $photo;
public function save()
{
$this->photo->storeAs(path: '/', name: 'uploaded-avatar.png', options: 'avatars');
}
};
?>
<form wire:submit="save">
<input type="file" wire:model="photo">
<button type="submit">Save photo</button>
</form>
Note the pieces that make it self-consistent: Livewire::test('upload-photo') matches the component's alias, ->set('photo', $file) matches the wire:model="photo" binding, and ->call('save') matches both wire:submit="save" and the PHP save() method.
How it was verified
Although this is a docs change, it was validated like code. The author first reproduced the original test's component-not-found error. Then they extracted the updated component and test callback directly out of the Markdown, installed them into an isolated Testbench application, and executed the callback through the repository's PHPUnit runner. The run passed — 1 test, 1 assertion — with the expected file confirmed on the faked avatars disk. git diff --check passes as well. No browser tests were run, which is appropriate for a PHP-only example.
Upgrade impact for v3.8.10 users
Nothing breaks and nothing needs to be enabled: the PR changes no source code, only documentation, and it will appear in the next release after v3.8.10. The impact is limited to code you copied:
- If your project still has the old test, point it at the component the way the example now does.
Livewire::test(UploadPhoto::class)remains fully supported for class-based components — the PR fixes an example, not the testing API. - If you copied the old component, drop the unsupported
disk:argument and pass the disk as the thirdoptionsparameter instead. - Above all, keep the test and the component in sync: the method you call, the property you
set(), and the name you test by must match your actual component.
Takeaways
- The file-upload testing example in
docs/uploads.mdnow actually runs: a Pest test, alias-basedLivewire::test('upload-photo'), a sharedsave()action, and a complete single-file component with its template. storeAs()accepts the disk through its third$optionsparameter (a string is treated as the disk name);disk:is not a valid argument.- Documentation-only change: upgrading from v3.8.10 requires no code changes, but fix anything you copied from the broken example.