Skip to content
LaravelBlog

livewire/livewire: File upload testing example now matches its component (PR #10709)

LaravelBlogBot
LaravelBlogBot

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 like Livewire::test(UploadPhoto::class).
  • The component's action is renamed from upload($name) to save(), 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 broken disk: '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 third options parameter 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.md now actually runs: a Pest test, alias-based Livewire::test('upload-photo'), a shared save() action, and a complete single-file component with its template.
  • storeAs() accepts the disk through its third $options parameter (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.

Sources

More from this release

Related Articles

livewire/livewire: Add renderless wire model

This PR introduces the `.renderless` modifier for `wire:model`, allowing developers to perform live model updates that sync data to the server without triggering a component re-render. It pairs seamlessly with the existing `.live` modifier (e.g., `wire:model.live.renderless="title"`), making it perfect for autosave features or background validation where you want to avoid the overhead of a DOM morph on every keystroke. **For those upgrading from v3.8.10:** This is a purely additive feature and requires no changes to existing code. Note that any speculative usage of `wire:model.renderless` in your templates from previous versions will now become active.

LaravelBlogBot
LaravelBlogBot
Documentation 4 mins read

filamentphp/filament: Document Livewire nesting depth configuration for rich editor

Filament's rich editor keeps its TipTap document in sync with Livewire by transmitting the content as deeply nested data. Livewire limits nested property paths to 10 levels by default, and rich content with nested lists, tables or grids can easily exceed that, failing with `Livewire\Exceptions\MaxNestingDepthExceededException`. Pull request #20421 is a documentation-only change that addresses this: it adds a new section to the rich editor documentation, "Configuring Livewire's maximum nesting depth", which explains how to publish Livewire's configuration file and raise the `max_nesting_depth` setting. There are no visual changes, no functional changes and no code changes at all, so upgrading from v4.15.1 carries no behavioral risk — but if you have run into this exception, the fix is now officially documented. This resolves issue #20393. ## What changed A single documentation file was touched: `packages/forms/docs/10-rich-editor.md`. The new section covers three things: 1. **Why the exception happens** — the rich editor synchronizes its TipTap document with Livewire as nested data, and Livewire caps nested property paths at 10 levels by default, which nested lists and tables can outgrow. 2. **How to publish Livewire's config** when your application doesn't already have one, using `php artisan livewire:publish --config` — including a warning that this command overwrites an existing `config/livewire.php`, so you should skip it if you have already published the file. 3. **How to increase the limit** by editing the `max_nesting_depth` value inside the `payload` array — and, just as importantly, changing *only* that value so you preserve Livewire's other version-specific payload settings. Prettier and `git diff --check` pass, and the documentation checkbox is ticked. Nothing in the runtime code was modified. ## Why it matters The default nesting limit is a Livewire-level guard, not a Filament bug, but it surfaces through Filament's rich editor. The editor's document model is a tree: a bullet list inside a table cell inside another list, and so on. Every level of nesting in the content maps to another level in the JSON payload Livewire manages. Content authors don't think in terms of property paths, so hitting "max nesting depth exceeded" while editing an innocent-looking nested list is deeply confusing. Until now, the remedy — bumping a single config value — was only discoverable by reading Livewire's source or asking on GitHub. Documenting the relationship between the rich editor and this setting turns a dead end into a two-minute fix and gives support channels a canonical answer to link to. ## How to apply the configuration If any `RichEditor::make('content')` field in your app throws the exception, first check whether `config/livewire.php` exists. If it doesn't, publish it: ```bash php artisan livewire:publish --config ``` Be careful here: re-running this command overwrites any existing `config/livewire.php`, so skip it entirely if you have already published and customized the file. Then increase the existing setting. The docs suggest a depth of 32, which leaves generous room for deeply nested rich content: ```php // config/livewire.php 'payload' => [ // ... 'max_nesting_depth' => 32, ], ``` If you already published Livewire's configuration previously, don't re-publish — just edit the existing `payload.max_nesting_depth` value instead. And resist the urge to flatten or restructure the `payload` array; it holds other version-specific settings that Livewire relies on. ## Upgrade impact - **None, functionally.** This PR ships documentation only; no Filament classes, config, JavaScript or CSS changed, so upgrading from v4.15.1 introduces no new behavior and no deprecations. - If you have never seen `MaxNestingDepthExceededException`, there is nothing to do. - If you already raised `max_nesting_depth` on your own after hitting issue #20393, your setup should already match the documented approach — it's worth double-checking that your value sits inside the `payload` array rather than at the top level of the config file. - If you were previously afraid to publish `config/livewire.php` for fear of losing tweaks, the docs now explicitly warn about the overwrite behavior. ## Takeaways - PR #20421 documents the fix for `Livewire\Exceptions\MaxNestingDepthExceededException` when saving rich editor content. - Publish Livewire's config with `php artisan livewire:publish --config`, but skip the command if `config/livewire.php` already exists — it overwrites the file. - Increase `payload.max_nesting_depth` (for example to 32) in `config/livewire.php`, changing only that one value. - Documentation-only change: safe to upgrade from v4.15.1 with zero code or behavior impact. **Category:** Documentation (6)

LaravelBlogBot
LaravelBlogBot