2

Since my project has deployed multiple domain names, the API interface that needs to be tested is using the api.example.test domain name as the entrance.

Using $this->get('/v1/ping') in Feature Test will request to www.example.test, I hope to set up $this->withHeader('Host', config('domain.api_domain')) uniformly in setUp in ApiFeatureBaseTestCase to automatically request API related tests to api.example.test Go in.

However, in practice, I found that this is invalid. By tracing the code, I found two codes that may cause the invalid Host setting:

First place (Laravel):

Code in Laravel Framework src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:503, pass the parameter $uri ='/v1/ping' into $this->prepareUrlForRequest($uri) and get a complete Url with the default Host, the return value is http://www.example.test/v1/ping.

Second place (Symfony):

In the code of Symfony HttpFoundation Component Request.php:355, the parsing in $uri will be used first The coming out host is overwritten in the Header as the default Host.

The above two codes eventually caused the Host I set by withHeader to fail. Obviously, in this code logic, Symfony HttpFoundation Component's choice of Host in conflict cannot be considered wrong, but I submitted this question issue was closed when it was given to Laravel Framework.

I don't know if this issue is a bug or feature?

Finally, I am sorry that my question has interrupted everyone's time, but if there is a conclusion on this question, please tell me what should be more appropriate?

My current approach is $this->get($this->api_base_url . '/v1/ping'), but I don’t think this is elegant

3Q!!1

Code example

// File: config/domain.php
return [
    'api_domain' => 'api.example.test',
    'web_domain' => 'www.example.test',
];

// File: routes/demo.php
Route::domain(config('domain.api_domain'))
     ->middleware(['auth:api', 'api.sign.check'])
     ->namespace($this->namespace)
     ->group(function () {
         Route::get('/v1/ping', function () {
             return 'This Api v1';
         });
     });

Route::domain(config('domain.web_domain'))
     ->middleware('web')
     ->namespace($this->namespace)
     ->group(base_path('routes/web.php'));

// File: tests/ApiFeatureBaseTestCase.php
namespace Tests;

class ApiFeatureBaseTestCase extends TestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        $this->withHeader('Host', config('domain.api_domain'));
    }
}

// File: tests/Feature/ApiPingTest.php
namespace Tests\Feature;

use Tests\ApiFeatureBaseTestCase;


class ApiPingTest extends ApiFeatureBaseTestCase
{
    public function testPing()
    {
       $this->get('/v1/ping');
    }
}
Liam Wang
  • 21
  • 3

2 Answers2

0

Can you create a wrapper method on your ApiFeatureBaseTestCase class?

public function get($uri, array $headers = [])
{
    return parent::get(config('domain.api_domain') . $uri, $headers);
}

Then in your ApiPingTest class:

public function testPing()
{
    $this->get('/v1/ping');
}
brice
  • 1,801
  • 1
  • 10
  • 15
  • Thanks! It's also a good suggestion, but... I need to also define other functions like `get` `post` `getJson` `postJson` (if I will use it) – Liam Wang Nov 23 '20 at 09:50
0

I've encountered same problem, as we have 3 types of subdomains for application. To resolve this issue you need to change root URL domain which will be used by url generator before it will be used by TestClass:

public function setUp(): void
{
        /**
         * We need this to start test application with merchant app type.
         */

        parent::setUp();

        URL::forceRootUrl('http://subdomain.domain.test');
}

Now you can call $this->get('/v1/ping'); without specifying subdomain and it will work properly.

Sadly, but problem with MakesHttpRequests.php:503 still exists in 2023 and you can't set host header from test as you would like.

This also works in parallel tests php artisan test --parallel --processes=4

KorbenDallas
  • 944
  • 9
  • 16