Simulate a http request and parse route parameters in Laravel testcase

phplaravelhttpparametersrouteparserequestsimulatetestcase

Last Update : 2023-09-22 UTC 09:14:11 AM

Answers of > Simulate a http request and parse route parameters in Laravel testcase

I assume you need to simulate a request w3coded laravel route without actually dispatching it. With a w3coded laravel route simulated request in place, you want to probe it w3coded laravel route for parameter values and develop your w3coded laravel route testcase.,How could I manually initialize the w3coded laravel route router and feed some routing parameters to it? w3coded laravel route Or simply make request()->route()->parameter() w3coded laravel route available?,I'm writing unit tests for a w3coded laravel route middleware, it needs to check for some route w3coded laravel route parameters, so what I'm doing is creating a w3coded laravel route fixed request to pass it to the middleware,So w3coded laravel route passing that ['info' => 5] to Request w3coded laravel route constructor has no effect whatsoever. Let's have w3coded laravel route a look at the Route class and see how its w3coded laravel route $parameters property is getting populated.

OK, enough with the chatter. Let's try to simulate a request:

<?php

use Illuminate\Http\Request;

class ExampleTest extends TestCase
{
    public function testBasicExample()
    {
        $request = new Request([], [], ['info' => 5]);

        dd($request->route()->parameter('info'));
    }
}

In a real HTTP request context, Laravel sets up its route resolver, so you won't get such errors. Now that you're simulating the request, you need to set up that by yourself. Let's see how.

<?php

use Illuminate\Http\Request;
use Illuminate\Routing\Route;

class ExampleTest extends TestCase
{
    public function testBasicExample()
    {
        $request = new Request([], [], ['info' => 5]);

        $request->setRouteResolver(function () use ($request) {
            return (new Route('GET', 'testing/{info}', []))->bind($request);
        });

        dd($request->route()->parameter('info'));
    }
}

So, now you won't get that error because you actually have a route with the request object bound to it. But it won't work yet. If we run phpunit at this point, we'll get a null in the face! If you do a dd($request->route()) you'll see that even though it has the info parameter name set up, its parameters array is empty:

Illuminate\Routing\Route {#250
  #uri: "testing/{info}"
  #methods: array:2 [
    0 => "GET"
    1 => "HEAD"
  ]
  #action: array:1 [
    "uses" => null
  ]
  #controller: null
  #defaults: []
  #wheres: []
  #parameters: [] <===================== HERE
  #parameterNames: array:1 [
    0 => "info"
  ]
  #compiled: Symfony\Component\Routing\CompiledRoute {#252
    -variables: array:1 [
      0 => "info"
    ]
    -tokens: array:2 [
      0 => array:4 [
        0 => "variable"
        1 => "/"
        2 => "[^/]++"
        3 => "info"
      ]
      1 => array:2 [
        0 => "text"
        1 => "/testing"
      ]
    ]
    -staticPrefix: "/testing"
    -regex: "#^/testing/(?P<info>[^/]++)$#s"
    -pathVariables: array:1 [
      0 => "info"
    ]
    -hostVariables: []
    -hostRegex: null
    -hostTokens: []
  }
  #router: null
  #container: null
}

That method matches request's decoded path against a regex of Symfony's Symfony\Component\Routing\CompiledRoute (You can see that regex in the above dump as well) and returns the matches which are path parameters. It will be empty if the path doesn't match the pattern (which is our case).

/**
 * Get the parameter matches for the path portion of the URI.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return array
 */
protected function bindPathParameters(Request $request)
{
    preg_match($this->compiled->getRegex(), '/'.$request->decodedPath(), $matches);
    return $matches;
}

It's figuring out the request URI by probing a bunch of HTTP headers. It first checks for X_ORIGINAL_URL, then X_REWRITE_URL, then a few others and finally for the REQUEST_URI header. You can set either of these headers to actually spoof the request URI and achieve minimum simulation of a http request. Let's see.

<?php

use Illuminate\Http\Request;
use Illuminate\Routing\Route;

class ExampleTest extends TestCase
{
    public function testBasicExample()
    {
        $request = new Request([], [], [], [], [], ['REQUEST_URI' => 'testing/5']);

        $request->setRouteResolver(function () use ($request) {
            return (new Route('GET', 'testing/{info}', []))->bind($request);
        });

        dd($request->route()->parameter('info'));
    }
}

Even if it was absolutely impossible to spoof the request URI like the approach above, you could partially mock the request class and set your expected request URI. Something along the lines of:

<?php

use Illuminate\Http\Request;
use Illuminate\Routing\Route;

class ExampleTest extends TestCase
{

    public function testBasicExample()
    {
        $requestMock = Mockery::mock(Request::class)
            ->makePartial()
            ->shouldReceive('path')
            ->once()
            ->andReturn('testing/5');

        app()->instance('request', $requestMock->getMock());

        $request = request();

        $request->setRouteResolver(function () use ($request) {
            return (new Route('GET', 'testing/{info}', []))->bind($request);
        });

        dd($request->route()->parameter('info'));
    }
}

I'm writing unit tests for a middleware, it needs to check for some route parameters, so what I'm doing is creating a fixed request to pass it to the middleware

        $request = Request::create('/api/company/{company}', 'GET');            
        $request->setRouteResolver(function()  use ($company) {
            $stub = $this->createStub(Route::class);
            $stub->expects($this->any())->method('hasParameter')->with('company')->willReturn(true);
            $stub->expects($this->any())->method('parameter')->with('company')->willReturn($company->id); // not $adminUser's company
            return $stub;
        });

Since route is implemented as a closure, you can access a route parameter directly in the route, without explicitly calling parameter('info'). These two calls returns the same:

$info = $request->route()->parameter('info');
$info = $request->route('info');

The second way, makes mocking the 'info' parameter very easy:

$request = $this->createMock(Request::class);
$request->expects($this->once())->method('route')->willReturn('HelloWorld');
$info = $request->route('info');
$this->assertEquals($info, 'HelloWorld');

If you want to be stricter (which in unit testing is probably a good thing), this method isn't really recommended.

class UserTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testExample()
    {
        // This is readable but there's a lot of under-the-hood magic
        $this->visit('/home')
             ->see('Welcome')
             ->seePageIs('/home');

        // You can still be explicit and use phpunit functions
        $this->assertTrue(true);
    }
}

Current topics : Simulate a http request and parse route parameters in Laravel testcase

Newly Added Questions

Similar Questions

Questions :

How To Group Array Key Value

Last Update : 2023-09-22 UTC 13:28:21 PM

Questions :

PhpStorm Warning For React Attributes In Jsx File With SCSS File

Last Update : 2023-09-22 UTC 13:28:13 PM

Questions :

Why Is The File Not Showing Up In Request.files And In Request.forms Instead?

Last Update : 2023-09-22 UTC 13:27:57 PM

Questions :

Proxying Assets From React App Directory In Slim Framework?

Last Update : 2023-09-22 UTC 13:27:40 PM

Questions :

Laravel 5.4 Can't Run “php Artisan Preset React” Comand

Last Update : 2023-09-22 UTC 13:27:31 PM

Questions :

How To Update Session Values Without Signing Out?

Last Update : 2023-09-22 UTC 13:27:23 PM

Questions :

Array Is Not Visible

Last Update : 2023-09-22 UTC 13:27:16 PM

Questions :

React Routing For Login Using Symfony

Last Update : 2023-09-22 UTC 13:27:01 PM

Questions :

Sanctum With React SPA Returning 419 Page Expired

Last Update : 2023-09-22 UTC 13:26:44 PM

Questions :

How Do I Import An Input String Into Another Page

Last Update : 2023-09-22 UTC 13:26:30 PM

Top
© 2023 W3CODED - All Rights Reserved.