number6's avatar

(SQLite) migration "down" on tests can't find columns

Given the following migration, when I run my tests I get the error:

Doctrine\DBAL\Schema\SchemaException: There is no column with name 'accreditation_start' on table 'validation_reviews'.

I also notice the // dd($table->getColumns()); in my up() method. It printed the two columns I created, but only those columns. This migration works as expected on the standard DB, but fails with that error on a SQLite DB during testing.

public function up()
  {
    Schema::table('validation_reviews', function (Blueprint $table) {
      $table->date('accreditation_start')->nullable()->after('score');
      $table->date('accreditation_end')->nullable()->after('accreditation_start');
      $table->dropColumn('accredited_at');
      // dd($table->getColumns());
    });
  }

  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
      Schema::table('validation_reviews', function (Blueprint $table) {
// ****** ERROR HAPPENS HERE ******
        $table->dropColumn(['accreditation_start', 'accreditation_end']);
        $table->dateTime('accredited_at')->after('score');
      });
  }

And here's the original table, made months before

public function up()
  {
    Schema::create('validation_reviews', function (Blueprint $table) {
      $table->bigIncrements('id');
      $table->unsignedBigInteger('product_id');
      $table->string('state')->nullable();
      $table->string('score')->nullable();
      $table->dateTime('accredited_at');
      $table->timestamps();

      $table->index(['product_id']);
    });
  }

  /**
   * Reverse the migrations.
   *
   * @return void
   */
  public function down()
  {
    Schema::dropIfExists('validation_reviews');
  }
0 likes
3 replies
Nakov's avatar

You could maybe add a check if the column exists: https://laravel.com/docs/8.x/migrations#checking-for-table-column-existence

But I am curious on why the down method is used, do you use the RefreshDatabase trait in your test class:

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ExampleTest extends TestCase
{

    use RefreshDatabase;

 // your tests here
}

If you use it, that one uses the migrate:fresh command which skips all the down methods and it just executes the up method of each migration.

number6's avatar

Apologies for such a late reply. I did add a check to make sure the column exists on down() and my tests pass, but was mostly curious why it was failing in the first place. I did dd($table->getColumns()); and it printed an empty array, which obviously wasn't expected.

I do not use RefershDatabase but do use DatabaseMigrations. I also seed the table in my setUp(). The basics of this app is it collects a ton of information that is then reviewed by someone. So I seed the DB with a bunch of test data so I can verify the review process.

class ReviewerTest extends TestCase
{
  use DatabaseMigrations;

  protected $director;

  public function setUp(): void
  {
    parent::setUp();
    $this->artisan('db:seed');
    $this->artisan('db:seed --class=StagingSeeder');
    $this->director = $this->getUserByRole(UserConstants::DIRECTOR);
  }
number6's avatar
number6
OP
Best Answer
Level 6

I had to separate each command.

 Schema::table('validation_reviews', function (Blueprint $table) {
      $table->dropColumn(['accreditation_start']);
    });
    Schema::table('validation_reviews', function (Blueprint $table) {
      $table->dropColumn(['accreditation_end']);
    });
    Schema::table('validation_reviews', function (Blueprint $table) {
      $table->dateTime('accredited_at')->nullable()->after('score');
    });

Please or to participate in this conversation.