TheGeeky
TheGeeky

Reputation: 971

How to test Laravel resource

I am testing an API endpoint returned Laravel resource with pagination

 public function test_showing_all_plans(): void
 {
    $plans = Plan::where('is_active', true)
        ->paginate(10);

    $resource = PlansResource::collection($plans);

    $this->withHeaders([
        'Accept' => 'application/json',
        'Content-Type' => 'application/json',
        'AppKey' => 5,
    ])
        ->json('GET', '/api/customer/plans')
        ->assertStatus(200)
        ->assertExactJson([
            $resource->response()->getData(true),
        ]);
}

so my problem is the returned result is not the same because of the path of the endpoint is not equal to the returned of the resource.

This is the result returned from the endpoint:

"links": {
        "first": "http://www.site.local/api/customer/plans?page=1",
        "last": "http://www.site.local/api/customer/plans?page=3",
        "next": "http://www.site.local/api/customer/plans?page=2",
        "prev": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 3,
        "path": "http://www.site.local/api/customer/plans",
        "per_page": 10,
        "to": 10,
        "total": 24
    }

This is the code returned from the resource ' $resource->response()->getData(true) '

 "links": {
            "first": "http://www.site.local?page=1",
            "last": "http://www.site.local?page=3",
            "next": "http://www.site.local?page=2",
            "prev": null
        },
        "meta": {
            "current_page": 1,
            "from": 1,
            "last_page": 3,
            "path": "http://www.site.local",
            "per_page": 10,
            "to": 10,
          }

so how can I pass the endpoint to my code or how can I make them equal, and is there is a proper way to test Laravel resource?

Upvotes: 4

Views: 8754

Answers (2)

glaucomorais
glaucomorais

Reputation: 366

In my case (Laravel 8.x), I was forced to use Paginator::currentPathResolver to achieve success:

use Illuminate\Http\Request;

public function test_showing_all_plans(): void
 {
    $request  = Request::create('/api/customer/plans', 'GET');
    Paginator::currentPathResolver(fn () => $request->url());
    $plans    = Plan::where('is_active', true)->paginate(10);
    $resource = PlansResource::collection($plans);

    $this->getJson('/api/customer/plans', [
         'AppKey' => 5,
       ])
        ->assertStatus(200)
        ->assertExactJson([
            $resource->response($request)->getData(true),
        ]);
}

Upvotes: 0

Steve Grunwell
Steve Grunwell

Reputation: 896

The answer lies in the JsonResource::response() method — this method accepts an optional Illuminate\Http\Request $request parameter, which will give context as to where you're trying to use the resource.

Calling $this->json('GET', '/api/customer/plans') will produce a Request object that looks something like this (heavily truncated for brevity):

Illuminate\Http\Request {
  pathInfo: "/api/customer/plans"
  requestUri: "/api/customer/plans"
  method: "GET"
}

Meanwhile, if no Request object is provided when resolving API resources, Laravel will create a new one using defaults, which will look more like this:

Illuminate\Http\Request {
  pathInfo: "/"
  requestUri: "/"
  method: "GET"
}

To make sure these match, you'll want to create a new Request object in your test case that looks something like what you're requesting, then pass it to the $resource->response() call:

use Illuminate\Http\Request;

public function test_showing_all_plans(): void
 {
    $plans    = Plan::where('is_active', true)->paginate(10);
    $resource = PlansResource::collection($plans);
    $request  = Request::create('/api/customer/plans', 'GET');

    $this->getJson('/api/customer/plans', [
         'AppKey' => 5,
       ])
        ->assertStatus(200)
        ->assertExactJson([
            $resource->response($request)->getData(true),
        ]);
}

Upvotes: 13

Related Questions