0

I have a Trait that I use on multiple models in my app for setting a UUID on the model:

<?php

namespace App\Traits;

use Illuminate\Support\Str;

trait UsesUuid
{
    protected static function bootUsesUuid()
    {
        static::creating(function ($model) {
            if (!$model->uuid) {
                $model->uuid = (string) Str::orderedUuid();
            }
        });
    }
}

It works fine when using the app normally, but when I try to write tests for creating the model via a post route and dump the response I get an Integrity constraint violation: 19 NOT NULL constraint failed: venues.uuid 500 error.

An example of the test I'm doing is:

public function testOwnerCanSuccessfullyCreateVenue()
{
    $amenity = Amenity::inRandomOrder()->pluck('id')->first();

    $response = $this->actingAs($this->createdUser('owner'))->post(route('venues.store'), [
        "name" => "create-name",
        "address_line_1" => "create-address_line_1",
        "address_line_2" => "create-address_line_2",
        "county" => "create-county",
        "postcode" => "create-postcode",
        "phone_number" => "create-phone_number",
        "notes" => "create-notes",
        "amenities" => [$amenity]
    ]);

    dd($response);
}

And the column in my migration is $table->uuid('uuid')->unique();

Everything else is working brilliantly, but I'm new to writing tests and not sure how to get around this problem.

The reason I was using a Trait was to get around outlining all the column values when persisting to the database, as I'm using $request->validated() to fill the model:

$venue = Venue::create($request->validated()); 

And obviously because the UUID isn't being set here, it's being done by a Trait, its failing the test. I can get the test to pass and have the app still work if I remove the Trait and do:

$venue = Venue::create(
    $request->validated() + ['uuid' => Str::orderedUuid()]
); 

Which is fine, I can live with that, but I would like to understand more about why the Trait isn't firing and how to get around it.

Edit: Just to add more based on the answer below, the fillable fields are defined correctly:

/**
 * The attributes that are mass assignable.
 *
 * @var array
 */
protected $fillable = [
    'uuid',
    'name',
    'address_line_1',
    'address_line_2',
    'county',
    'postcode',
    'phone_number',
    'notes',
];
Andy Holmes
  • 7,817
  • 10
  • 50
  • 83

2 Answers2

0

I think it's problem in model. Venue model should use a protected $fillable = ['uuid'];. Laravel protect mass assignment by default. In case you provide array on create model, Laravel doesn't allow it. You need to provide a protected fillable array, So laravel can unlock only for those fields.

Bapi
  • 309
  • 1
  • 16
0

it's a bit late answer but did you figure out what was the problem and if you did, can you please provide an answer?

In older versions of Laravel problem was that the composer could not find the trait because of the way tests are autoloaded, and autoloading was defined in composer as "tests/TestCase.php"

I had a similar problem with Traits but one that was created in the test/Billing folder.

So in composer, it should be:

"autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },

and, don't forget like me, trait needs to be namespaced. After all of that setup, I had to run composer dump-autoload

Dach0
  • 309
  • 4
  • 11
  • I don't have access to this codebase at the minute, but when I do I'll give this a go. Everything I tried didn't work at all, so unfortunately no insight from me - I just decided to go the long-winded way to get it working, annoyingly – Andy Holmes Feb 05 '22 at 13:30