Write Phpunit Test for Filament PHP Resource

Write Phpunit Test for Filament PHP Resource

Posted on:December 25, 2023 at 08:00 PM

Officially filament php use pest for testing purpose. All the example of it’s documentation is depends on PEST which might be bit challenging for developers (like me) those are not used to pest. In this post, I will show you how can you write tests for a resources via phpunit. Let’s jump into it.

I will write a test for user resources. The user resource allows me:

  • View list of the users
  • Create a new user
  • Edit a user

Generate the test file

Let’s create a test file:

php artisan make:test UserResourceTest

Minimum Setup

I need to do minimum setup because all tests are required:

  • Database interaction
  • Authentication

Let’s add following in the UserResourceTest class.

use RefreshDatabase;

protected function setUp(): void
{
    parent::setUp();

    $this->actingAs(User::factory()->create());
}

Test for /index page listing

The following test basically confirm me that the /users page is loading successfully.

/** @test */
public function it_can_render_page()
{
    $this->get(UserResource::getUrl('index'))
        ->assertSuccessful();
}

Now, let’s test it loads the respective records.

# Don't forget to import this
use Livewire\Livewire;

/** @test */
public function it_can_list_users()
{
    $users = User::factory()->count(10)->create();

    Livewire::test(ListUsers::class)
        ->assertSee($users->pluck('email')->toArray());
}

Test for /create page

Let’s write test that confirm the create a new user page is loading successfully.

/** @test */
public function it_can_render_create_page()
{
    $this->get(UserResource::getUrl('create'))
        ->assertSuccessful();
}

Now, let’s confirm that it create a new user when we submit the form with the data.

use Livewire\Livewire;

/** @test */
public function it_can_crate_user()
{
    // Arrange
    $newUser = User::factory()->make();

    // Pre-assertion
    $this->assertDatabaseIsEmpty('users');

    // Act
    Livewire::test(CreateUser::class)
        // Setting the orm value
        ->set('data.name', $newUser->name)
        ->set('data.email', $newUser->email)
        ->set('data.password', $newUser->password)
        ->set('data.type', $newUser->type)
        // Trying to hook the data store mechanism
        ->call('create')
        ->assertHasNoErrors();

    // Assert
    $this->assertDatabaseCount('users', 1);
    $this->assertDatabaseHas('users', [
        'name' => $newUser->name,
        'email' => $newUser->email,
        'password' => $newUser->password,
        'type' => $newUser->type,
    ]);
}

Now, let’s confirm a field e.g. email is required to create a user.

use Livewire\Livewire;

/** @test */
public function email_is_required_for_creating_user()
{
    $this->assertDatabaseIsEmpty('users');

    $newUser = User::factory()->make();

    Livewire::test(CreateUser::class)
        ->set('data.email', NULL)   // Explicitly set the email value is "NULL"
        ->set('data.name', $newUser->name)
        ->set('data.password', $newUser->password)
        ->set('data.type', $newUser->type)
        ->call('create')
        ->assertHasFormErrors(['email' => 'required']);

    $this->assertDatabaseIsEmpty('users');
}

Test for /edit a user

First, let’s confirm that the edit a user page is loading successfully.

use Livewire\Livewire;

/** @test */
public function it_can_render_edit_page()
{
    $user = User::factory()->create();

    Livewire::test(EditUser::class, [
        'record' => $user->getRouteKey(),
    ])->assertSuccessful();
}

Secondly, let’s confirm the form has loaded with the right user’s data.

use Livewire\Livewire;

/** @test */
public function it_can_retrieve_data()
{
    $user = User::factory()->create();

    Livewire::test(EditUser::class, [
        'record' => $user->getRouteKey(),
    ])
        ->set('data.name', $user->name)
        ->set('data.slug', $user->slug)
        ->set('data.email', $user->email)
        ->set('data.type', $user->type)
        ->assertHasNoFormErrors();
}

Finally, let’s confirm the behavior by changing a user’s data.

/** @test */
public function it_can_update_user_data()
{
    // Arrange
    $user = User::factory()->create();
    $newData = User::factory()->make();

    // Act
    Livewire::test(EditUser::class, [
        'record' => $user->getRouteKey(),
    ])
        // Set the changed data
        ->set('data.name', $newData->name)
        ->set('data.slug', $newData->slug)
        ->set('data.email', $newData->email)
        ->set('data.type', $newData->type)
        // Hook the update mechanism
        ->call('save')
        ->assertHasNoFormErrors();

    // Assert
    $this->assertDatabaseHas('users', [
        'name' => $newData->name,
        'email' => $newData->email,
        'password' => $newData->password,
        'type' => $newData->type,
    ]);
}

Disclaimer: I totally aware that, I didn’t cover the delete and form required test for edit. If you need to extends that, at least you can get idea how to continue from here.

I hope it will work for you. Thanks for reading.