pest icon indicating copy to clipboard operation
pest copied to clipboard

[Bug]: Browser tests for subdomains point to local environment instead of testing environment

Open pindab0ter opened this issue 5 months ago • 8 comments

What Happened

We use subdomains as an integral part of our application. E.g. our login route auth.login points to portal.example.test/login.

For illustration purposes:

Route::domain('portal.example.test')->group(function () {
    Route::get('/login', /* ... */))->name('auth.login');
});

We develop locally using Valet, Valet Linux and Homestead, in each instance using <domain>.test.

When running a browser test against a route that does not exist in a subdomain, the actual route being visited by the browser is something like http://127.0.0.1:52149/ (the port might differ).

However, when visiting a route that has a subdomain, it points to the exact literal route; no port (e.g. https://portal.example.test/login), causing it to use the local environment (.env) instead of the testing environment (.env.testing).

How to Reproduce

  • Install a fresh Laravel app, add Pest and host it in a way that uses a local domain.

    I used Laravel Valet to host it on https://pest-browser-subdomains.test.

  • Register the following routes in routes/web.php:

    Route::get('/test', fn () => response()->json([
        'environment' => app()->environment(),
    ]))->name('no-subdomain.test');
    
    Route::domain('test.pest-browser-subdomains.test')->group(function () {
        Route::get('/test', fn () => response()->json([
            'environment' => app()->environment(),
        ]))->name('subdomain.test');
    });
    
  • Create tests/Browser/SubdomainTest.php and add Browser tests to phpunit.xml and tests/Pest.php

    it('serves non-subdomain routes in the correct environment', function () {
        expect(app()->environment())->toBe('testing'); // Passes
    
        visit(route('no-subdomain.test')) // Visits `http://localhost:<random port>/test`
            ->assertSee('testing');       // Passes
    });
    
    it('serves non-subdomain routes in the correct environment', function () {
        expect(app()->environment())->toBe('testing'); // Passes
    
    
        visit(route('subdomain.test')) // Visits `https://test.pest-browser-subdomains.test/test`, no port
            ->assertSee('testing');    // Fails, displays 'local' instead
    });
    

Sample Repository

https://github.com/pindab0ter/pest-browser-subdomains

Pest Version

4.1.0

PHP Version

8.4.12

Operation System

macOS

Notes

No response

pindab0ter avatar Sep 24 '25 06:09 pindab0ter

This issue relates to and is a possible duplicate of #1443.

pindab0ter avatar Sep 24 '25 09:09 pindab0ter

This is a tough one, without having tried anything out, we could possibly update LaravelHttpServer#handleRequest method so before kernel receives the request it updates the url to the correct url. Meaning the kernel will think the request came from test.pest-browser-subdomains.test while the request actually came from http://localhost:<random port>.

However the problem with this is all assets, links etc. returned from the controller would point to test.pest-browser-subdomains.test, causing them to fail to load as they are not hitting the temporary web server started. 🤔

olivernybroe avatar Sep 24 '25 11:09 olivernybroe

This is a tough one, without having tried anything out, we could possibly update LaravelHttpServer#handleRequest method so before kernel receives the request it updates the url to the correct url. Meaning the kernel will think the request came from test.pest-browser-subdomains.test while the request actually came from http://localhost:<random port>.

I don't think this will work for the reason you already mentioned. The server cannot decide what a request's destination should have been. For example, you could load the page portal.example.com/login which launches an AJAX request to api.example.com/v1/foo. How would the server know that the second request is meant for a different (sub)domain?

Is it maybe possible to use existing infrastructure (e.g. Valet) to route the requests, but with the port changed?

As it stands anyone that uses (sub)domain specific routing in their application is currently unable to use Pest's browser testing until a solution is found. We would love to be able to use browser testing, so I look forward to finding a solution or workaround.

pindab0ter avatar Sep 25 '25 07:09 pindab0ter

I am interested in this one as well 👍

I am using laravel tenancy from stancl and we have subdomains. We can make it work by passing the whole subdomain in visit() but I don’t think it’s a good idea because we are still in the context of main domain which means other functionality will not work as expected such as checking authenticated user.

habibalkhabbaz avatar Sep 25 '25 13:09 habibalkhabbaz

Also interested as I'm also experiencing issues with subdomains and stancl's laravel tenancy.

dkdps avatar Sep 26 '25 14:09 dkdps

We also use subdomains with stancl/tenancy. I'm writing tests now. Good thing I found this!

thammer67 avatar Oct 06 '25 19:10 thammer67

Subdomain routes don't seem to get picked up when running pest browser testing.

I have root domain routes in routes/web.php and app subdomain routes in routes/app.php.

The domain is setup in bootstrap/app.php

When using the app in a browser it works. When running pest tests, subdomain routes return a 404 (or a catch all route in web.php if I add one).

enkay avatar Oct 07 '25 14:10 enkay

Yeah, auth()->login() or ::fake() calls does not work when using subdomains. eg

Notification::fake();

...

Notification::assertSentTo($user, ResetPasswordNotification::class); // does not work

abrardev99 avatar Dec 01 '25 07:12 abrardev99