0

I just created a factory in order to run some tests:

CategoryFactory.php

<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Category>
 */
class CategoryFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            //
            'company_id' => 1,
            'name' => fake()->name(),
            'parent_id' => null
        ];
    }
}

And added it to the model:

Category.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

use App\Scopes\CompanyScope;

class Category extends Model
{
    //
    use SoftDeletes, HasFactory;

    protected $fillable = [
        'company_id',
        'name',
        'parent_id'
    ];

public function __construct() {
    parent::__construct();
    if(isset(auth()->user()->company_id)) {
        $this->attributes['company_id'] = auth()->user()->company_id;
    }
}


protected static function boot()
{
    parent::boot();

    static::addGlobalScope(new CompanyScope);
}

My test file looks like this:

public function test_category_edit_can_be_redered(): void
    {
        $user = User::factory()->create();
        $category = Category::factory()->create();

        $response = $this->actingAs($user)->get('/devices/categories/1/edit');

        $response->assertStatus(200);
    }

But when I try to run the test, I get the following error:

General error: 1364 Field 'company_id' doesn't have a default value (Connection: mysql, SQL: insert into `categories` (`updated_at`, `created_at`) values (2023-08-08 01:55:43, 2023-08-08 01:55:43))

It looks like the definition in the factory is not being applied to the create method... Any idea what I am doing wrong?

Tomas Lucena
  • 1,204
  • 1
  • 14
  • 31
  • First look at the relationships of your user model. Is there a relationship to the category model? – UnderDog Aug 08 '23 at 02:21
  • @UnderDog no, but I have a boot and a construct and it seems to be the problem! check if you can help me! I have added to my question – Tomas Lucena Aug 08 '23 at 02:30
  • @UnderDog I think is the construct that is resetting all the atributes – Tomas Lucena Aug 08 '23 at 02:32
  • @UnderDog https://stackoverflow.com/questions/69993946/laravel-factory-fails-when-the-model-has-a-constructor found the answer here... the issue whats the constructor – Tomas Lucena Aug 08 '23 at 02:42

1 Answers1

1

You trigger your category before you signIn a user so that the code doesn't have a default auth()->user()

Your code trigger a global scope event which is overriding the default company_id

you can use use Illuminate\Database\Console\Seeds\WithoutModelEvents or saveQuietly() in your seeder to not trigger global scope events.

You can also do this I think:

public function test_category_edit_can_be_redered(): void
    {
        $user = User::factory()->create();
        Auth::loginUsingId($user->id);
        $category = Category::factory()->create();

        $response = $this->actingAs($user)->get('/devices/categories/1/edit');

        $response->assertStatus(200);
    }
Japs
  • 977
  • 2
  • 10
  • 19
  • no, this is wrong! the issue is in the link I passed below that for some reason was downvoted – Tomas Lucena Aug 08 '23 at 03:22
  • 1
    I don't know why you are using constructor, when you can use `Observer` and `GlobalScope`. Especially when you're using laravel eloquent. It defeat the purpose instead of `model -> database` you're doing `model -> repository -> model -> database` – Japs Aug 08 '23 at 09:27