TDD Laravel - Feature test in laravel and spatie/laravel-activitylog get JSON encoding errors

2.1k Views Asked by At

I'm writing some tests to my models in laravel and i've getting some troubles when i enable Activity Log by using spatie/laravel-activitylog.

So, i create a user, using Factory, i authenticate in system, and when i'll try to logout, i get this error:

1) Tests\Feature\Usuario\CriarUsuarioTest::testAcessaPaginaDeRegistro Illuminate\Database\Eloquent\JsonEncodingException: Unable to encode attribute [properties] for model [Spatie\Activitylog\Models\Activity] to JSON: Type is not supported.

My test TestCase.php:

protected function setUp()
{
    parent::setUp();
    $this->user = create('App\Models\Usuario');
    $this->singIn($this->user)
         ->disableExceptionHandling();

}

...
...
...

protected function singIn($user)
{
    $this->actingAs($user);
    return $this;
}

protected function singOut()
{
    // routeLogout() goes to '/logout' route.
    $this->post(routeLogout()); // <- Here, where the error occurs
    return $this;
}

My App/Models/Usuario.php model:

namespace App\Models;

use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Webpatser\Uuid\Uuid;
use Spatie\Activitylog\Traits\LogsActivity;

class Usuario extends Authenticatable
{
    use LogsActivity, Notifiable, SoftDeletes;
    protected $table = 'usuario';
    protected $fillable = [/*...*/] ; // I remove this to post here on SO
    protected static $logFillable = true;
    public $timestamps = true;
    protected $dates = [
        'created_at',
        'updated_at',
        'deleted_at'
    ];
    protected static function boot() 
    {
        // Handle the \LogsActivity boot method
        parent::boot();
        static::saving(function ($usuario){
            $usuario->uuid = Uuid::generate()->string;
        });
    }
    public function getRouteKeyName()
    {
        return 'uuid';
    }
}

My config/activitylog.php file:

return [
    'enabled' => env('ACTIVITY_LOGGER_ENABLED', true),
    'delete_records_older_than_days' => 365,
    'default_log_name' => 'default',
    'default_auth_driver' => null,
    'subject_returns_soft_deleted_models' => false,
    'activity_model' => \Spatie\Activitylog\Models\Activity::class,
];

My phpunit.xml file:

<?xml version="1.0" encoding="UTF-8"?>
    <phpunit backupGlobals="false" 
             backupStaticAttributes="false" 
             bootstrap="vendor/autoload.php" 
             colors="true" 
             convertErrorsToExceptions="true" 
             convertNoticesToExceptions="true" 
             convertWarningsToExceptions="true" 
             processIsolation="false" 
             stopOnFailure="false">
                 <testsuites>
                      <testsuite name="Feature">
                           <directory suffix="Test.php">./tests/Feature</directory>
                      </testsuite>
                      <testsuite name="Unit">
                           <directory suffix="Test.php">./tests/Unit</directory>
                      </testsuite>
                 </testsuites>
                 <filter>
                    <whitelist processUncoveredFilesFromWhitelist="true">
                        <directory suffix=".php">./app</directory>
                    </whitelist>
                 </filter>
                 <php>
                    <env name="APP_ENV" value="testing"/>
                    <env name="CACHE_DRIVER" value="array"/>
                    <env name="SESSION_DRIVER" value="array"/>
                    <env name="QUEUE_DRIVER" value="sync"/>
                    <env name="API_DEBUG" value="true"/>
                    <env name="memory_limit" value="512M"/>
                    <env name="APP_DATABASE" value="test"/>
                 </php>
    </phpunit>

My create_activity_log_migration file:

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateActivityLogTable extends Migration
{
    /**
     * Run the migrations.
     */
    public function up()
    {
        Schema::create('activity_log', function (Blueprint $table) {
            $table->increments('id');
            $table->string('log_name')->nullable();
            $table->string('description');
            $table->integer('subject_id')->nullable();
            $table->string('subject_type')->nullable();
            $table->integer('causer_id')->nullable();
            $table->string('causer_type')->nullable();
            $table->text('properties')->nullable();
            $table->timestamps();

            $table->index('log_name');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down()
    {
        Schema::drop('activity_log');
    }
}

I notice then when i disable Activity Log for model, its work fine. And, when i use the system by tinker or browser, logs also work as well.

2

There are 2 best solutions below

0
On BEST ANSWER

I haven't been able to reproduce the error, but I do have some considerations:

  • You say the error is triggered when you post to the logout route, but that shouldn't trigger the activity logger, right? I mean, no created, updated or deleted events are triggered there.
  • Instead, a created event is indeed triggered when you create the user with the factory. That in turn triggers the activity log.
  • When the logger tries to create the new Activity you get the exception Illuminate\Database\Eloquent\JsonEncodingException: Unable to encode attribute [properties] for model [Spatie\Activitylog\Models\Activity] to JSON: Type is not supported.. That is almost definitely thrown in Illuminate\Database\Eloquent\Concerns\HasAttributes@castAttributeAsJson method, which does a simple json_encode on the attribute value.
  • JSON_ERROR_UNSUPPORTED_TYPE - A value of an unsupported type was given to json_encode(), such as a resource.

  • The value being encoded. Can be any type except a resource.

  • So, is there any chance a resource is part of the properties to be logged? try dd($user->attributeValuesToBeLogged('created')) just after creating the User.
0
On

I've found the answer (but i don't know if it's the best way to solve this);

By just putting a $this->createApplication(); in SetUp method, inside TestCase.php file, the error disappear.

Thank all of you, guys.