laravel-json-api / testing

Test helpers for JSON API compliant APIs.
MIT License
3 stars 1 forks source link

No bound JSON API server - your application may not be handling an HTTP request. #1

Closed juljupy closed 3 years ago

juljupy commented 3 years ago

Hi, thanks for your great work.

I'm trying to create a Feature test for some routes: I've defined this one in my api.php route file:

JsonApiRoute::server('v1')
    ->middleware('auth:api')
    ->prefix($api_prefix)
    ->namespace('Api\V1')
    ->resources(function ($server) {
        $server->resource('users')->actions('-actions', function ($actions) {
            $actions->get('profile');
        })->only('profile');
    });

Making the request with a restful client I get a successful answer, but when I'm going to test it following the steps from documentation, I get the No bound JSON API server - your application may not be handling an HTTP request..

Screen Shot 2021-02-26 at 1 16 12 PM

This is my TestCase.php file:

Screen Shot 2021-02-26 at 1 13 52 PM

And my test file is this:

Screen Shot 2021-02-26 at 1 14 20 PM

BTW. I had to bind $this->app->bind(Server::class, ServerServer::class); because I was getting this error:

Screen Shot 2021-02-26 at 1 17 02 PM

I'm using a fresh installation of Laravel v8.27 and Pest v1.0.

Thanks.

lindyhopchris commented 3 years ago

Sorry, this is pretty difficult for me to debug from the information you've provided.

Can you share the test?

Also, when you're getting an error about there being no bound JSON API server, have you checked the full stack trace? There will be previous exceptions in the stack trace so you'd need to check what they say too.

Also, I have no idea what this is: $this->app->bind(Server::class, ServerServer::class); What do you mean by that?

In summary, the main thing to look at is the full stack trace including previous exceptions as that is likely to give some clue as to what is failing. It's unique to your set up which is why the stack trace is important.

juljupy commented 3 years ago

Hi @lindyhopchris thanks for your response.

Action to test:

JsonApiRoute::server('v1')
    ->middleware('auth:api')
    ->prefix('api/v1')
    ->namespace('Api\V1')
    ->resources(function ($server) {
        $server->resource('users')->actions('-actions', function ($actions) {
            $actions->get('profile');
        })->only('profile');
    });

Action controller:

<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use Illuminate\Contracts\Support\Responsable;
use Illuminate\Http\Request;
use LaravelJsonApi\Core\Responses\DataResponse;

class UserController extends Controller
{
    /**
     * Show logged user profile.
     *
     * @param Request $request
     * @return Responsable
     */
    public function profile(Request $request): Responsable
    {
        return new DataResponse($request->user());
    }
}

My TestCase file is this one:

<?php

namespace Tests;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use LaravelJsonApi\Testing\MakesJsonApiRequests;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication, RefreshDatabase, WithoutMiddleware, MakesJsonApiRequests;
}

The Pest.php file is:

<?php

use Tests\TestCase;

uses(TestCase::class)->in(__DIR__);

The test file is this one:

<?php

use App\Models\User;

test('should show logged user data', function () {
    $user = User::factory()->create();

    $endpoint = '/api/v1/users/-actions/profile';

    $response = $this->actingAs($user)->jsonApi('users')->get($endpoint);

    dd($response);  //For debugging purposes
});

Stack trace result:

LaravelJsonApi\Testing\TestResponse^ {#3953
  +baseResponse: Illuminate\Http\Response^ {#3992
    +headers: Symfony\Component\HttpFoundation\ResponseHeaderBag^ {#3997
      #computedCacheControl: array:2 [
        "no-cache" => true
        "private" => true
      ]
      #cookies: []
      #headerNames: array:3 [
        "content-type" => "Content-Type"
        "cache-control" => "Cache-Control"
        "date" => "Date"
      ]
      #headers: array:3 [
        "content-type" => array:1 [
          0 => "application/vnd.api+json"
        ]
        "cache-control" => array:1 [
          0 => "no-cache, private"
        ]
        "date" => array:1 [
          0 => "Sun, 28 Feb 2021 16:06:20 GMT"
        ]
      ]
      #cacheControl: []
    }
    #content: "{"jsonapi":{"version":"1.0"},"errors":[{"status":"500","title":"Internal Server Error"}]}"
    #version: "1.1"
    #statusCode: 500
    #statusText: "Internal Server Error"
    #charset: null
    +original: "{"jsonapi":{"version":"1.0"},"errors":[{"status":"500","title":"Internal Server Error"}]}"
    +exception: LogicException {#3963
      #message: "No bound JSON API server - your application may not be handling an HTTP request."
      #code: 0
      #file: "./vendor/laravel-json-api/core/src/Core/JsonApiService.php"
      #line: 78
      -previous: Illuminate\Contracts\Container\BindingResolutionException^ {#3979
        #message: "Target [LaravelJsonApi\Contracts\Server\Server] is not instantiable."
        #code: 0
        #file: "./vendor/laravel/framework/src/Illuminate/Container/Container.php"
        #line: 1038
        trace: {
          ./vendor/laravel/framework/src/Illuminate/Container/Container.php:1038 { …}
          ./vendor/laravel/framework/src/Illuminate/Container/Container.php:839 { …}
          ./vendor/laravel/framework/src/Illuminate/Container/Container.php:712 { …}
          ./vendor/laravel/framework/src/Illuminate/Foundation/Application.php:826 { …}
          ./vendor/laravel/framework/src/Illuminate/Container/Container.php:651 { …}
          ./vendor/laravel/framework/src/Illuminate/Foundation/Application.php:811 { …}
          ./vendor/laravel-json-api/core/src/Core/JsonApiService.php:76 { …}
          ./vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:261 { …}
          ./vendor/laravel-json-api/core/src/Core/Responses/DataResponse.php:118 { …}
          ./vendor/laravel-json-api/core/src/Core/Responses/DataResponse.php:84 { …}
          ./vendor/laravel-json-api/core/src/Core/Responses/DataResponse.php:98 { …}
          ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:766 { …}
          ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:753 { …}
          ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:693 { …}
          ./vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:128 { …}
          ./vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:103 { …}
          ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:695 { …}
          ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:670 { …}
          ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:636 { …}
          ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:625 { …}
          ./vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:166 { …}
          ./vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:128 { …}
          ./vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:103 { …}
          ./vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:141 { …}
          ./vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:110 { …}
          ./vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:508 { …}
          ./vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:474 { …}
          ./vendor/laravel-json-api/testing/src/TestBuilder.php:377 { …}
          ./vendor/laravel-json-api/testing/src/TestBuilder.php:302 { …}
          ./tests/Feature/API/Auth/V1/UserProfileTest.php:14 {
            P\Tests\Feature\API\Auth\V1\UserProfileTest->{closure}^
            › 
            › $response = $this->actingAs($user)->jsonApi('users')->get($endpoint);
            › 
            arguments: {
              $uri: "/api/v1/users/-actions/profile"
            }
          }
          P\Tests\Feature\API\Auth\V1\UserProfileTest->{closure}() {}
          ./vendor/pestphp/pest/src/Factories/TestCaseFactory.php:142 { …}
          P\Tests\Feature\API\Auth\V1\UserProfileTest->Pest\Factories\{closure}() {}
          ./vendor/pestphp/pest/src/Concerns/TestCase.php:175 { …}
          ./vendor/pestphp/pest/src/Support/ExceptionTrace.php:28 { …}
          ./vendor/pestphp/pest/src/Concerns/TestCase.php:176 { …}
          ./vendor/pestphp/pest/src/Concerns/TestCase.php:164 { …}
          ./vendor/phpunit/phpunit/src/Framework/TestCase.php:1526 { …}
          ./vendor/phpunit/phpunit/src/Framework/TestCase.php:1132 { …}
          ./vendor/phpunit/phpunit/src/Framework/TestResult.php:722 { …}
          ./vendor/phpunit/phpunit/src/Framework/TestCase.php:884 { …}
          ./vendor/phpunit/phpunit/src/Framework/TestSuite.php:677 { …}
          ./vendor/phpunit/phpunit/src/Framework/TestSuite.php:677 { …}
          ./vendor/phpunit/phpunit/src/TextUI/TestRunner.php:667 { …}
          ./vendor/phpunit/phpunit/src/TextUI/Command.php:142 { …}
          ./vendor/pestphp/pest/src/Console/Command.php:130 { …}
          ./vendor/pestphp/pest/bin/pest:44 { …}
          ./vendor/pestphp/pest/bin/pest:45 { …}
        }
      }
      trace: {
        ./vendor/laravel-json-api/core/src/Core/JsonApiService.php:78 { …}
        ./vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:261 { …}
        ./vendor/laravel-json-api/core/src/Core/Responses/DataResponse.php:118 { …}
        ./vendor/laravel-json-api/core/src/Core/Responses/DataResponse.php:84 { …}
        ./vendor/laravel-json-api/core/src/Core/Responses/DataResponse.php:98 { …}
        ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:766 { …}
        ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:753 { …}
        ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:693 { …}
        ./vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:128 { …}
        ./vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:103 { …}
        ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:695 { …}
        ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:670 { …}
        ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:636 { …}
        ./vendor/laravel/framework/src/Illuminate/Routing/Router.php:625 { …}
        ./vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:166 { …}
        ./vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:128 { …}
        ./vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php:103 { …}
        ./vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:141 { …}
        ./vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:110 { …}
        ./vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:508 { …}
        ./vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:474 { …}
        ./vendor/laravel-json-api/testing/src/TestBuilder.php:377 { …}
        ./vendor/laravel-json-api/testing/src/TestBuilder.php:302 { …}
        ./tests/Feature/API/Auth/V1/UserProfileTest.php:14 {
          P\Tests\Feature\API\Auth\V1\UserProfileTest->{closure}^
          › 
          › $response = $this->actingAs($user)->jsonApi('users')->get($endpoint);
          › 
          arguments: {
            $uri: "/api/v1/users/-actions/profile"
          }
        }
        P\Tests\Feature\API\Auth\V1\UserProfileTest->{closure}() {}
        ./vendor/pestphp/pest/src/Factories/TestCaseFactory.php:142 { …}
        P\Tests\Feature\API\Auth\V1\UserProfileTest->Pest\Factories\{closure}() {}
        ./vendor/pestphp/pest/src/Concerns/TestCase.php:175 { …}
        ./vendor/pestphp/pest/src/Support/ExceptionTrace.php:28 { …}
        ./vendor/pestphp/pest/src/Concerns/TestCase.php:176 { …}
        ./vendor/pestphp/pest/src/Concerns/TestCase.php:164 { …}
        ./vendor/phpunit/phpunit/src/Framework/TestCase.php:1526 { …}
        ./vendor/phpunit/phpunit/src/Framework/TestCase.php:1132 { …}
        ./vendor/phpunit/phpunit/src/Framework/TestResult.php:722 { …}
        ./vendor/phpunit/phpunit/src/Framework/TestCase.php:884 { …}
        ./vendor/phpunit/phpunit/src/Framework/TestSuite.php:677 { …}
        ./vendor/phpunit/phpunit/src/Framework/TestSuite.php:677 { …}
        ./vendor/phpunit/phpunit/src/TextUI/TestRunner.php:667 { …}
        ./vendor/phpunit/phpunit/src/TextUI/Command.php:142 { …}
        ./vendor/pestphp/pest/src/Console/Command.php:130 { …}
        ./vendor/pestphp/pest/bin/pest:44 { …}
        ./vendor/pestphp/pest/bin/pest:45 { …}
      }
    }
  }
  #streamedContent: null
  #document: null
  -expectedType: "users"
}

Doing $this->app->bind(Server::class, ServerServer::class); in my test case, avoids the Target [LaravelJsonApi\Contracts\Server\Server] is not instantiable. message that appears in the stack trace.

lindyhopchris commented 3 years ago

When you do:

php artisan route:list --path profile

and it lists the action route, what middleware is listed as being registered for that route?

juljupy commented 3 years ago

Hi @lindyhopchris

Screen Shot 2021-02-28 at 12 11 28 PM
lindyhopchris commented 3 years ago

So the BootJsonApi middleware registers the server in the service container.

So I have no idea what's going on in your app I'm afraid.... it's almost impossible for me to debug remotely. Sorry.

lindyhopchris commented 3 years ago

Have you disabled middleware in testing at all?

juljupy commented 3 years ago

Hi @lindyhopchris .

I've already found some problems, first I was using WithoutMiddleware trait in TestCase.php and second I was using the $this->actingAs() function in the enpoint call, since I'm using Laravel Passport I should've used Passport::actingAs() helper https://laravel.com/docs/8.x/passport#testing.

So sorry for the noise, and thanks for your responses.

Great work!, congrats.