Summer Sale! All accounts are 50% off this week.

Ashraam's avatar
Level 41

Weird migration problem while testing

Hi, I'm implementing tests in my app and I've got this weird situation.

I've done several change to my users tables with using migration obviously.

When I try a php artisan migrate:fresh everything is working.

On local env, User::factory()->create() works too but in this test I've got an error this specific error General error: 1 table users has no column named firstname (SQL: insert into "users" ("firstname", "lastname", "phone", "email", "email_verified_at", "address", "address_1", "zip_code", "city", "password", "updated_at", "created_at") values (David, Martinez, +33 7 90 93 44 45, [email protected], 2014-08-04 00:00:00, 167, rue Maurice, ?, 07599, Denisboeuf, $2y$04$amnt7y7.ydQ0XPCE2nK0GuKj6ftiHqnUVkODSuQC8Yo3djmA4iN.K, 2022-08-25 13:37:47, 2022-08-25 13:37:47))

I've added a var_dump on the up method in the migration (I can see yhe up method is called in the test)

The test:

test('admins can browses clients', function() {
    $clients = User::factory()->create();

    $this->get(route('clients.index'))
        ->assertSuccessful()
        ->assertSee($clients[0]->firstname)
        ->assertSee($clients[1]->firstname);
});

In order to debug I've added this line of code in my test

dd(\Illuminate\Support\Facades\Schema::getColumnListing("users"));

But the results show there is no "firstname" column (wtf ?)

Here is the latest migration for the users table

return new class extends Migration {
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn(['name']);

            $table->string('firstname')->after('id');
            $table->string('lastname')->after('firstname');
            $table->string('phone', 20)->after('lastname');
            $table->string('address')->nullable()->default(null)->after('email_verified_at');
            $table->string('address_1')->nullable()->default(null)->after('address');
            $table->string('zip_code', 10)->nullable()->default(null)->after('address_1');
            $table->string('city')->nullable()->default(null)->after('zip_code');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('name')->after('id');

            $table->dropColumn(['firstname', 'lastname', 'phone', 'address', 'address_1', 'zip_code', 'city']);
        });
    }
};

Is there anything I'm missing ? A typo ? A can't see what's the problem.

All other tests are working great

thanks

0 likes
18 replies
Sinnbeck's avatar

Do you have the RefreshDatabase trait on your TestCase.php class?

tykus's avatar

Does your test suite RefreshDatabase or LazilyRefreshDatabase?

Ashraam's avatar
Level 41

Sure, the LazilyRefreshDatabase is called, I mean I've got more than 100 tests working in this app. @tykus @sinnbeck

Also when I dd the schema, I've got all the columns (but it's like the latest migration isn't called)

But I'm 100% sure it's called, the added a var_dump in the up method and when I run the test I can see the var_dump

tykus's avatar

@Ashraam did I read this incorrectly

when I dd the schema, I've got all the columns

But the results show there is no "firstname" column (wtf ?)

Ashraam's avatar
Level 41

@tykus I meani all the iniatial columns, not the new from the latest migration.

Here is the result from the DD of the users columns

array:11 [
  0 => "id"
  1 => "email"
  2 => "email_verified_at"
  3 => "password"
  4 => "remember_token"
  5 => "current_team_id"
  6 => "profile_photo_path"
  7 => "created_at"
  8 => "updated_at"
  9 => "two_factor_secret"
  10 => "two_factor_recovery_codes"
]
Ashraam's avatar
Level 41

@tykus If you look well at the output of the schema, the "name" column have been dropped but the firstname etc didn't get created

Sinnbeck's avatar

@Ashraam Not sure how laravels sqlite driver will handle it, but im pretty sure sqlite does not support ->after() when adding new columns. I personally test on mysql to avoid issues.

Sinnbeck's avatar

@Ashraam Great. Then either use mysql (suggested) or rewrite the migration to work with sqlite

Ashraam's avatar
Level 41

Damn, so maybe I should split the migration in two pieces, dropping and then adding

@sinnbeck But Mysql is so damn long for testing :(

tykus's avatar

@Ashraam If you really like SQLite just split the migration, no big deal. But be aware of these subtle differences between two difference database systems!

Sinnbeck's avatar

@Ashraam Its a bit slower yes, but you will avoid false positives and "bugs" like this one. But I'm curious how slow it is? Mine takes around 39 seconds for 571 feature tests

Please or to participate in this conversation.