Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions docs/1-essentials/07-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ composer phpunit

## Test-specific discovery locations

Tempest will only discover non-dev namespaces defined in composer.json automatically. That means that `{:hl-keyword:require-dev:}` namespaces aren't discovered automatically. Whenever you need Tempest to discover test-specific locations, you may specify them within the `discoverTestLocations()` method of the provided `IntegrationTest` class.
Tempest will only discover non-dev namespaces defined in composer.json automatically. That means that `{:hl-keyword:require-dev:}` namespaces aren't discovered automatically. Whenever you need Tempest to discover test-specific locations, you may specify them within the `discoverTestLocations()` method of the provided `IntegrationTest` class.

On top of that, Tempest _will_ look for files in the `tests/Fixtures` directory and discover them by default. You can override this behavior by providing your own implementation of `discoverTestLocations()`, where you can return an array of `DiscoveryLocation` objects (or nothing).

Expand All @@ -46,7 +46,7 @@ final class HomeControllerTest extends IntegrationTest
If you want to test code that interacts with the database, your test class can call the `setupDatabase()` method. This method will create and migrate a clean database for you on the fly.

```php
class TodoControllerTest extends IntegrationTest
final class TodoControllerTest extends IntegrationTest
{
protected function setUp(): void
{
Expand All @@ -60,8 +60,6 @@ class TodoControllerTest extends IntegrationTest
Most likely, you'll want to use a test-specific database connection. You can create a `database.config.php` file anywhere within test-specific discovery locations, and Tempest will use that connection instead of the project's default. For example, you can create a file `tests/Fixtures/database.config.php` like so:

```php tests/Fixtures/database.config.php
<?php

use Tempest\Database\Config\SQLiteConfig;

return new SQLiteConfig(
Expand All @@ -72,7 +70,7 @@ return new SQLiteConfig(
By default, no tables will be migrated. You can choose to provide a list of migrations that will be run for every test that calls `setupDatabase()`, or you can run specific migrations on a per-test basis.

```php
class TodoControllerTest extends IntegrationTest
final class TodoControllerTest extends IntegrationTest
{
protected function migrateDatabase(): void
{
Expand All @@ -85,7 +83,7 @@ class TodoControllerTest extends IntegrationTest
```

```php
class TodoControllerTest extends IntegrationTest
final class TodoControllerTest extends IntegrationTest
{
public function test_create_todo(): void
{
Expand Down
2 changes: 1 addition & 1 deletion packages/database/src/Migrations/MigrationManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ private function getTableDefinitions(): array
);
}

private function getMigrationHash(MigratesUp $migration): string
private function getMigrationHash(MigratesUp|MigratesDown $migration): string
{
$sql = '';

Expand Down
2 changes: 1 addition & 1 deletion packages/database/src/Migrations/RunnableMigrations.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final class RunnableMigrations implements IteratorAggregate
public function __construct(
private array $migrations = [],
) {
usort($this->migrations, static fn (MigratesUp $a, MigratesUp $b) => strnatcmp($a->name, $b->name));
usort($this->migrations, static fn (MigratesUp|MigratesDown $a, MigratesUp|MigratesDown $b) => strnatcmp($a->name, $b->name));
}

public function getIterator(): Traversable
Expand Down
11 changes: 7 additions & 4 deletions src/Tempest/Framework/Testing/IntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,21 +166,24 @@ protected function setupBaseRequest(): self
protected function setupDatabase(): self
{
$migrationManager = $this->container->get(MigrationManager::class);

$migrationManager->dropAll();

$this->migrateDatabase();

return $this;
}

/**
* Creates the migration table. You may override this method to provide more migrations to run for every tests in this file.
*/
protected function migrateDatabase(): void
{
$this->migrate(
CreateMigrationsTable::class,
);
$this->migrate(CreateMigrationsTable::class);
}

/**
* Migrates the specified migration classes.
*/
protected function migrate(string|object ...$migrationClasses): void
{
$migrationManager = $this->container->get(MigrationManager::class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Tests\Tempest\Integration\Framework\Commands;

use PHPUnit\Framework\Assert;
use Tempest\Console\ExitCode;
use Tempest\Database\Migrations\Migration;
use Tempest\Framework\Commands\MigrateFreshCommand;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@

namespace Tests\Tempest\Integration\Framework\Commands;

use PHPUnit\Framework\Attributes\PreCondition;
use Tempest\Console\ExitCode;
use Tempest\Database\MigratesDown;
use Tempest\Database\Migrations\Migration;
use Tempest\Database\Migrations\RunnableMigrations;
use Tempest\Database\QueryStatement;
use Tempest\Database\QueryStatements\RawStatement;
use Tempest\Framework\Commands\MigrateFreshCommand;
use Tempest\Framework\Commands\MigrateValidateCommand;
use Tests\Tempest\Integration\FrameworkIntegrationTestCase;
Expand All @@ -15,6 +20,20 @@
*/
final class MigrateValidateCommandTest extends FrameworkIntegrationTestCase
{
#[PreCondition]
protected function configure(): void
{
$this->container->singleton(
className: RunnableMigrations::class,
definition: new RunnableMigrations(
migrations: [
...iterator_to_array($this->container->get(RunnableMigrations::class)->getIterator()),
new DownMigrationForRehash(),
],
),
);
}

public function test_migration_validate_command_verifies_valid_migrations(): void
{
$this->console
Expand Down Expand Up @@ -53,3 +72,13 @@ public function test_migration_validate_command_fails_when_migration_file_is_mis
->assertExitCode(ExitCode::ERROR);
}
}

final class DownMigrationForRehash implements MigratesDown
{
private(set) string $name = '2025-10-12_down_migration_for_rehash_test';

public function down(): QueryStatement
{
return new RawStatement('SELECT 1');
}
}
Loading