jthijs's avatar
Level 11

Subdomain testing

Hi,

I'm working a new Laravel project at work. We are going to use Jetstream for authentication.

We are going to have a multi tennant application. The User modal will have to login on "https://admin.example.com/login". The participants on "https://www.example.com/login" with a Participant model

Howver the view of the admin login and public login is different. That can be done in the FortifyServiceProvider.

In the FortifyServiceProvider I want to check which domain is visited and do

dd(\Illuminate\Support\Facades\Request::getHost());

When I surf to "https://admin.example.test" I do get "admin.example.test" as expected. Also when I surf to "https://example.test" I get "example.test"

So that is working all as should.

However I am going to use TDD to create further my website. So in my pest test i want to check if the view is correct.

When i do

get('https://admin.example.com/login')
->assertViewIs('admin.auth.login');

Still with the dd in my FortifyServiceProvider I get "example.test" as output instead of "admin.example.test"

I've been using numerous other options but all still gives me "example.test"

$response = $this->call('GET', 'https://admin.example.test/login', [], [], [], [
    'HTTP_HOST' => 'admin.example.test',
]);
$response = $this->withHeaders([
    'Host' => 'admin.example.test',
])->get('https://admin.example.test/login');
$response = $this->call('GET', '/login', [], [], [], [
    'SERVER_NAME' => 'admin.example.test',
]);

Any help on pointing me in the correct direction would be appreciated.

0 likes
5 replies
Merklin's avatar

Have you tried naming your routes and then test like $response = $this->get(route('route_name'));?

P.S: Naming your routes can save you a lot of head-bangs ;)

jthijs's avatar
Level 11

@Merklin

I normally use named routes. However for using Jetstream and Fortify it just has it general names. What I want is to use the general login route. But in the FortifyServiceProvider I then need to know which subdomain is used so I can then set a different view for admin or for the main domain.

So in both cases the route name is just route('login'); I have to use that as well for register, forget-password, ...

In my admin subdomain however no register is possible. As we create the user ourselves and limit the users who can have access the admin pages.

In the FortifyServiceProvider I then use the following

$subdomain = str(\Illuminate\Support\Facades\Request::getHost())->replaceEnd("." . config('APP_DOMAIN'), '');

Fortify::loginView(function() use ($subdomain) {
    if ($subdomain === "admin") {
        return view('admin.auth.login');
    }

    return view('auth.login');
});
Merklin's avatar

@jthijs Then you can try something like this:

Route::domain('{subdomain}.myapp.com')->group(function () {
    Route::get('/login', function ($subdomain) {
        if ($subdomain == 'admin') {
        return view('login.admin'); // or something like this
    }
    return view('login.user')

    });
});
LaryAI's avatar
Level 58

To test subdomain-specific logic in your Laravel application, especially when using Pest or PHPUnit, you need to ensure that the request is correctly simulating the subdomain. The issue you're facing is likely due to the way the test environment is handling the request host.

Here's a step-by-step solution to ensure your tests correctly simulate requests to different subdomains:

  1. Use the withServerVariables Method:

    Laravel's testing suite allows you to set server variables, which can be used to simulate different host headers. You can use the withServerVariables method to set the HTTP_HOST server variable.

  2. Example Test Code:

    Here's how you can structure your test to ensure the correct subdomain is being used:

    use Illuminate\Support\Facades\Request;
    use function Pest\Laravel\get;
    
    it('displays the correct view for admin login', function () {
        $response = $this->withServerVariables([
            'HTTP_HOST' => 'admin.example.test',
        ])->get('https://admin.example.test/login');
    
        $response->assertViewIs('admin.auth.login');
    });
    
    it('displays the correct view for participant login', function () {
        $response = $this->withServerVariables([
            'HTTP_HOST' => 'www.example.test',
        ])->get('https://www.example.test/login');
    
        $response->assertViewIs('participant.auth.login');
    });
    
  3. Ensure Your Application is Configured for Subdomains:

    Make sure your application is set up to handle subdomains correctly. This might involve configuring your local environment (e.g., /etc/hosts file) to recognize these subdomains.

  4. Check Your FortifyServiceProvider:

    Ensure that your FortifyServiceProvider is correctly differentiating between the subdomains. You might have logic like this:

    use Illuminate\Support\Facades\Request;
    use Laravel\Fortify\Fortify;
    
    Fortify::loginView(function () {
        $host = Request::getHost();
    
        if ($host === 'admin.example.test') {
            return view('admin.auth.login');
        }
    
        return view('participant.auth.login');
    });
    

By following these steps, you should be able to correctly test subdomain-specific logic in your Laravel application using Pest or PHPUnit.

Please or to participate in this conversation.