LinKeeper an alternative to LinkTree with Laravel and Filament - Tests and Resources
Par HappyToDev · 8 mins · Tutorial
Cet article existe aussi en version française 🇫🇷

In this episode, we're going to take FilamentPHP a step further.

But first, we're going to set up our testing environment.

To do this, we're going to use PestPHP. PestPHP is already present because it was installed at the same time as Laravel.

To get to grips with Pest, we're going to create two very simple tests. Once we have the basics down, we can develop the rest of our application based on the tests.

What we'll be looking at today :

Prior configuration of Pest

Using SQLite for testing

In order to separate your application's database from the one used for testing, we're going to modify the phpunit.xml file located at the root of your project.

Simply uncomment the following two lines:

        <!-- <env name="DB_CONNECTION" value="sqlite"/> -->
        <!-- <env name="DB_DATABASE" value=":memory:"/> -->
        <env name="DB_CONNECTION" value="sqlite"/>
        <env name="DB_DATABASE" value=":memory:"/>

This will allow Pest, which is a PHPUnit overlay, to use SQLite as its database engine and use it directly in memory.

Refresh the database for each test

Load a default account before each test

We're going to be doing a lot of work with FilamentPHP administration. So to avoid repeating for each test that we want to connect with a registered user, we'll simply tell Pest that for each test, it will act as if it were connected with the user with id #1.

To make this user ex

To do this, we'll edit the tests\TestCase.php file and add the following setUp function:


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

        $this->actingAs(User::find(1));
    }

So before each test is run, the actingAs function will define the user with id #1 as the logged-in user. Here it's my HappyToDev account.

Remove the tests provided by default by PestPHP

When you install Pest, it provides you with two default tests:

You can delete them or keep them for inspiration.

Checking the administration home page

In this test, we'll go to the /admin page to check that

We'll start by creating a test file using Artisan.

php artisan pest:test GeneralAdminPageTest

By default, the tests created will be stored directly in the tests\Feature directory.

Here are the contents of the file :

<?php

use Illuminate\Support\Facades\Config;

it('can view admin page', function () {
    $response = $this->get('/admin');

    $response
        ->assertStatus(200)
        ->assertSee('Dashboard')
        ->assertSee(Config('APP_NAME'));
});

Explanation:

We ask for get access to the /admin page and we get the response.

In this response, we check that we do indeed have an HTTP 200 code, that in the HTML code returned we do indeed have the word Dashboard and that we do indeed see the name of the application defined in our .env file, in this case LinKeeper. To do this, use the config() helper.

Running the test

To run the test, at the root of your project, run the following command:

./vendor/bin/pest

Normally you should get a 403 error, so your test will not pass.

Error 403

Correct the 403 error

To correct this, you need to read the FilamentPHP documentation which indicates that when you go into production, you need to modify the User model to avoid hitting a wall with the 403 error.

I'll leave it to you to implement the necessary changes so that your test can pass.

If you encounter the slightest difficulty, let me know in the comments.

Run the test again

If you have correctly made the changes requested in the documentation, you should get this result when you run your tests.

Test OK

Testing the user profile

We saw in lesson 2 that we normally have access to the user's profile. Let's set up a test to check this.

php artisan pest:test UserProfileTest

and add the following code:

it('has user profile page', function () {
    actingAs(User::find(1))->get('/admin/profile')
    ->assertStatus(200)
    ->assertSee('Profile')
    ->assertSee('Save changes');
});

This will allow us to check that when I'm logged in with the user with id #1 (my user) I do indeed get an HTTP 200 code when I go to the /admin/profile page and I can see the words: 'Profile' and 'Save changes'.

This is a very simple test, but it validates that the user does indeed have access to this page.

Run the tests

As before, run the appropriate command in your terminal:

./vendor/bin/pest

and you should get the following result:

Tests OK

Now that we've taken our first steps with tests, we'll be able to take a test-driven development approach using PestPHP throughout this project.

This is the next stage in the development of our application.

As we are using FilamentPHP for the backend, a number of features are being developed by the FilamentPHP teams and the aim here will not be to test how well Filament works as I have no doubt that this has been tested extensively.

To view the list of links, the user will have a Links link in the dashboard menu and this link, by FilamentPHP convention, will lead to an admin/links address.

Let's create a new test, using artisan :

php artisan pest:test PageLinksTest

First of all, we want to make sure that the page is accessible.

To do this, we're going to add the following code to our PageLinksTest file:

it("can access the user's links page and see 'Links' on the page", function () {
    $response = $this->get('/admin/links');

    $response
        ->assertOk()
        ->assertSeeText('Links');
});

This code will ask PestPHP to load the /admin/links page and to check firstly that the page returns the HTTP code 200 and then to ensure that the word 'Links' is present in the page.

You can run the tests with the --filter option to execute only the test that matches the regex passed in parameter (see doc). For example with :

./vendor/bin/pest --filter "links page"

PestPHP will only run our last test because 'links page' is present in its description.

This avoids having to run all the tests each time, especially when you have to iterate several times when setting up your test.

Tests KO

The test fails and that's normal because the Links page doesn't exist at the moment.

But now that the test is here and has failed, it tells us exactly what to do:

Expected response status code [200] but received 404.

We were expecting an HTTP 200 code and instead we get a 404, which means that the requested page doesn't exist.

We simply need to create it.

The 'Links' page will be a FilamentPHP administration page. It will therefore be a resource.

If I take the definition from the tutorial provided with PestPHP :

In Filament, resources are static classes used to build CRUD interfaces for your Eloquent models. They describe how administrators can interact with data from your panel using tables and forms.

We therefore understand that each Eloquent model will be associated with a resource in FilamentPHP.

It is therefore time to create our resource associated with our Link model, which is itself linked to our 'links' table in our database.

php artisan make:filament-resource Link

In our application tree, under app/Filament/Resources, we can see a LinkResource directory and a LinkResource.php file.

Arborescence Filament Resources

The LinkResource directory itself has a Pages sub-directory which contains the CreateLink.php, EditLink.php and ListLinks.php files. We'll talk about these later in this tutorial, so don't worry about these extra files for now.

FilamentPHP, via this Artisan command, will generate the following skeleton for you:

<?php

namespace App\Filament\Resources;

use App\Filament\Resources\LinkResource\Pages;
use App\Filament\Resources\LinkResource\RelationManagers;
use App\Models\Link;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;

class LinkResource extends Resource
{
    protected static ?string $model = Link::class;

    protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                //
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                //
            ])
            ->filters([
                //
            ])
            ->actions([
                Tables\Actions\EditAction::make(),
            ])
            ->bulkActions([
                Tables\Actions\BulkActionGroup::make([
                    Tables\Actions\DeleteBulkAction::make(),
                ]),
            ]);
    }

    public static function getRelations(): array
    {
        return [
            //
        ];
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListLinks::route('/'),
            'create' => Pages\CreateLink::route('/create'),
            'edit' => Pages\EditLink::route('/{record}/edit'),
        ];
    }
}

Let's not worry about that for the moment. But let's run our test again:

./vendor/bin/pest --filter "links page"

We can see that this time our test is green.

Tests OK

If we go to the admin/links page, we can see that the page does exist (HTTP code 200) and that it does indeed say 'Links'. This is why our test turns green.

Page admin/links

However, we soon realise that something isn't quite right. There seem to be records but nothing is visible in the table that shows us the links.

This is normal, we'll need to configure our resource file.

Conclusion

We'll stop here for episode 3.

In this chapter, we started doing TDD for our application development and touched on resources in FilamentPHP.

In the next episode, we'll continue our testing strategy with PestPHP and get to know FilamentPHP's resources better.

As usual, I look forward to your comments below.

See you soon.

Cet article existe aussi en version française 🇫🇷

#laravel #filamentphp #php

Ce contenu t'a plu ou appris quelque chose ? 👀

Si la réponse est oui, alors tu peux peut-être me supporter 💪 ?

Il y a plusieurs façon de me supporter et certaines sont gratuites, je t'invite à les découvrir dans ma page dédiée 👇