db->listTables(): CI4 caches the result in dataCache and, in a // long-lived test process, that cached list is stale (populated by a // prior test class's connection), so drops would be skipped and the // next up() would hit "Table ... already exists". $db = $this->db; $result = $db->query('SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = ?', [$db->database]); $tables = $result ? array_column($result->getResultArray(), 'TABLE_NAME') : []; // Preserve the migrations tracking table: MigrationRunner::regress() // calls removeHistory() AFTER down(), so dropping it here would raise // "Table '...ospos_migrations' doesn't exist". $migrationsTable = $db->getPrefix() . 'migrations'; $db->query('SET FOREIGN_KEY_CHECKS = 0'); foreach ($tables as $table) { if ($table === $migrationsTable) { continue; } $db->query('DROP TABLE IF EXISTS `' . $table . '`'); } $db->query('SET FOREIGN_KEY_CHECKS = 1'); // Invalidate the stale in-connection table-name cache so a subsequent // listTables() in the same process sees the fresh state. $db->dataCache['table_names'] = []; } }