Nov 28, 2023 | jetstream, phpunit, pest

How to Separate (and Skip) Laravel Jetstream's Tests

!
Warning: This post is over a year old. I don't always update old posts with new information, so some of this information may be out of date.

I normally use Laravel Breeze to build my projects, but recently I started a new project that needed team support, so I figured I'd finally use Jetstream on a real project, instead of just for fun.

There's a lot I really like about Jetstream, but one thing that bothers me—I know, it's not super reasonable, but whatever—is that it publishes so many tests out of the box. I want them to run in CI, so I can be confident the things they're testing are still covered, but I'd rather skip them locally.

But... how?

PHPUnit Testsuites

PHPUnit allows you to define one or more testsuites, each of which point to one or more files, and which can be given a name.

In Laravel, here's the default configuration (from phpunit.xml) (with extraneous information removed):

<?xml>
<phpunit>
    <testsuites>
        <testsuite name="Unit">
            <directory>tests/Unit</directory>
        </testsuite>
        <testsuite name="Feature">
            <directory>tests/Feature</directory>
        </testsuite>
    </testsuites>

So, we're loading two sets of tests, each of which gets a nickname.

Since I want to treat the Jetstream tests as separate from the others, I realized the best way to accomplish this is to move them out of the tests/Feature folder and into their own folder, and their own testsuite. So, I moved all of the default Jetstream tests from the tests/Feature directory into a new folder tests/Jetstream instead, and added a new testsuite attached to that folder:

<?xml>
<phpunit>
    <testsuites>
        <testsuite name="Unit">
            <directory>tests/Unit</directory>
        </testsuite>
        <testsuite name="Feature">
            <directory>tests/Feature</directory>
        </testsuite>
        <testsuite name="Jetstream">
            <directory>tests/Jetstream</directory>
        </testsuite>
    </testsuites>

Note: If you're using Pest tests, you can move these files and they'll just be good to go. If you're using PHPUnit tests, you'll also have to modify the files to update their namespaces from Tests\Feature to Tests\Jetstream.

Now, we can control when our Jetstream tests are and aren't running.

If we want to run just one testsuite, we can pass that suite's name to the --testsuite flag:

php artisan test --testsuite Unit

We can also choose to exclude a test suite:

php artisan test --exclude-testsuite Jetstream

However, what I want is to define that that test suite should be ignored by default; that's not something we can do from the command line.

PHPUnit's defaultTestSuite

Tighten's Keith Damiani pointed me in the direction of the defaultTestSuite configuration in PHPUnit. It allows to you define which test suites run when you don't pass the --testsuite or --exclude-testsuite parameters.

Now that we have our Jetstream testsuite separated, we can exclude it by default, by setting the defaultTestSuite property on the base <phpunit> declaration in phpunit.xml:

<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
    bootstrap="vendor/autoload.php"
    colors="true"
    defaultTestSuite="Unit,Feature"
>

Loading test suites in Pest

If your app is using Pest, there's a line in tests/Pest.php that loads the tests in tests/Feature with RefreshDatabase as a trait:

uses(TestCase::class, RefreshDatabase::class)->in('Feature');

Since the Jetstream tests expect a database, you'll want to duplicate that line for the Jetstream tests, and end up with the following:

uses(TestCase::class, RefreshDatabase::class)->in('Feature');
uses(TestCase::class, RefreshDatabase::class)->in('Jetstream');

Wrapping it all together

Here are my steps, simplified:

  1. Move all the Jetstream tests from tests/Feature folder into a new tests/Jetstream folder.
  2. Add a new testsuite for that folder in phpunit.xml:
<xml>
<phpunit>
    <testsuites>
        <!-- ... -->
        <testsuite name="Jetstream">
            <directory>tests/Jetstream</directory>
        </testsuite>
    </testsuites>
  1. Update Pest.php to load that folder separately:
uses(TestCase::class, RefreshDatabase::class)->in('Feature');
uses(TestCase::class, RefreshDatabase::class)->in('Jetstream');
  1. Update phpunit.xml to run only Unit and Feature testsuites by default:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true"
         defaultTestSuite="Unit,Feature"
>

That's it!

Now, when I run php artisan test, it excludes the Jetstream testsuite by default; but if I want to run those tests myself in CI, I still can, with php artisan test --testsuite Jetstream.


Comments? I'm @stauffermatt on Twitter


Tags: jetstream  •  phpunit  •  pest

Subscribe

For quick links to fresh content, and for more thoughts that don't make it to the blog.