---
title: "Testing — Translatable for Laravel | Roundly"
description: "No fake by design — pin locales and fallback via config or a manager swap, assert with plain Pest, run the suite on SQLite, PostgreSQL or MySQL."
url: https://roundly-consulting.com/open-source/docs/translatable-for-laravel/testing
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Translatable for Laravel](https://roundly-consulting.com/open-source/docs/translatable-for-laravel.md)

# Testing

## No fake, by design

The Translatable facade has no fake(). Nothing on it writes to the database, queues, mails, dispatches an event or calls out, so there is nothing for a fake to record. To pin behaviour in a test, set the config — or swap in a TranslationManager subclass to override one method; facade calls and every model observe it (see DI and actions):

```php
use RoundlyConsulting\Translatable\Enums\FallbackMode;
use RoundlyConsulting\Translatable\Facades\Translatable;
use RoundlyConsulting\Translatable\Support\TranslationManager;

config()->set('translatable.locales', ['en', 'de']);        // the locale set
config()->set('translatable.fallback', FallbackMode::None); // the fallback chain

// or override one method — facade calls and every model observe the subclass:
Translatable::swap(new class extends TranslationManager {
    public function supported(): array { return ['en', 'de']; }
});
```

## Testing your models

Translations live in an ordinary column, so tests run against real models: set the app locale and config per test, then assert through the public API. The examples assume the default en/sk locales and a Topic model with name fillable; the event test also needs DispatchesTranslationEvents:

```php
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Event;
use RoundlyConsulting\Translatable\Enums\FallbackMode;
use RoundlyConsulting\Translatable\Events\TranslationsChanged;

it('falls back to English for an untranslated locale', function () {
    app()->setLocale('sk');

    $topic = new Topic(['name' => ['en' => 'Investing']]);

    expect($topic->name)->toBe('Investing')
        ->and($topic->translatedOrNull('name'))->toBeNull()
        ->and($topic->missingLocales('name'))->toBe(['sk']);
});

it('renders nothing for a missing locale in None mode', function () {
    config()->set('translatable.fallback', FallbackMode::None);
    app()->setLocale('sk');

    $topic = new Topic(['name' => ['en' => 'Investing']]);

    expect($topic->name)->toBeNull();
});

it('dispatches TranslationsChanged on create', function () {
    Event::fake([TranslationsChanged::class]);

    $topic = Topic::create(['name' => ['en' => 'Investing']]);

    Event::assertDispatched(TranslationsChanged::class, fn (TranslationsChanged $event): bool =>
        $event->model->is($topic) && $event->changedAttributes === ['name']);
});

it('shows the missing-locales badge', function () {
    $topic = new Topic(['name' => ['en' => 'Investing']]);

    $html = Blade::render('<x-translatable-status :model="$model" />', ['model' => $topic]);

    expect($html)->toContain('translatable-status--incomplete');
});
```

## The package’s own suite

The suite runs on SQLite by default. Point it at a real engine with the standard TESTING\_DB\_\* variables — TESTING\_DB\_DRIVER is the one that actually moves it:

```bash
composer test

TESTING_DB_DRIVER=pgsql TESTING_DB_HOST=127.0.0.1 TESTING_DB_PORT=5432 \
  TESTING_DB_DATABASE=testing TESTING_DB_USERNAME=testing TESTING_DB_PASSWORD=secret \
  vendor/bin/pest
```

CI runs all three engines: SQLite catches a LIKE without an ESCAPE clause, PostgreSQL covers the ilike path and real jsonb columns (including sluggable’s per-locale slugs over them), and MySQL proves the like branch on a real server. PostgreSQL-only cases skip visibly when no engine is reachable, so a run that asserts nothing can’t report green.

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/translatable-for-laravel.md)
