assertSame(0, Artisan::call('clusev:install', $args)); $out = Artisan::output(); // capture once — the buffer is cleared after the first read $this->assertMatchesRegularExpression('/CLUSEV_ADMIN_PASSWORD=(\S+)/', $out, 'must print the generated password once'); preg_match('/CLUSEV_ADMIN_PASSWORD=(\S+)/', $out, $m); return $m[1] ?? ''; } public function test_creates_admin_with_a_generated_password_and_forced_change(): void { $pw = $this->install(['--email' => 'admin@example.test']); // Not the old guessable literal, and strong enough to resist guessing even if kept. $this->assertNotSame('clusev', $pw); $this->assertGreaterThanOrEqual(12, strlen($pw)); $user = User::where('email', 'admin@example.test')->first(); $this->assertNotNull($user); $this->assertTrue(Hash::check($pw, $user->password), 'the printed password must authenticate'); $this->assertTrue((bool) $user->must_change_password, 'first login should still nudge a change'); } public function test_uses_the_fixed_default_email_when_none_is_given(): void { $pw = $this->install(); $user = User::sole(); $this->assertSame('admin@clusev.local', $user->email, 'a fresh install must default to the predictable admin@clusev.local'); $this->assertTrue(Hash::check($pw, $user->password)); $this->assertTrue((bool) $user->must_change_password); } public function test_generates_a_distinct_password_each_install(): void { $first = $this->install(['--email' => 'a@example.test']); User::query()->delete(); $second = $this->install(['--email' => 'b@example.test']); $this->assertNotSame($first, $second, 'the generated password must not be a fixed value'); } public function test_is_a_noop_when_an_admin_already_exists(): void { User::factory()->create(); $this->artisan('clusev:install', ['--email' => 'second@example.test'])->assertSuccessful(); $this->assertSame(1, User::count()); $this->assertNull(User::where('email', 'second@example.test')->first()); } }