diff --git a/.claude/commands/login.md b/.claude/commands/login.md deleted file mode 100644 index 06e3399..0000000 --- a/.claude/commands/login.md +++ /dev/null @@ -1,9 +0,0 @@ -# Auto-Login for Local Development - -Login as the first user using Playwright MCP. - -## Instructions - -1. Navigate Playwright to: `http://chat.test/dev/login` -2. This auto-logs in as the first user (or creates one if none exist) -3. Confirm you're on the dashboard diff --git a/.env.example b/.env.example index 46096e0..adc7cf1 100644 --- a/.env.example +++ b/.env.example @@ -2,7 +2,7 @@ APP_NAME=Laravel APP_ENV=local APP_KEY= APP_DEBUG=true -APP_URL=http://localhost +APP_URL=http://chat.test APP_LOCALE=en APP_FALLBACK_LOCALE=en diff --git a/app/Console/Commands/LoginCommand.php b/app/Console/Commands/LoginCommand.php new file mode 100644 index 0000000..07b7cf3 --- /dev/null +++ b/app/Console/Commands/LoginCommand.php @@ -0,0 +1,70 @@ +option('email'); + + if (! $this->shouldLogin()) { + $this->fixLoginRequirements($email); + } + + $url = config('app.url'); + + $this->info("Logging in as: {$email}"); + + $result = Process::path(base_path()) + ->run(['npx', 'playwright', 'test', '--', 'node', 'scripts/login.cjs', $url, $email, 'password']); + + if (! $result->successful()) { + // Try direct node execution + $result = Process::path(base_path()) + ->run(['node', 'scripts/login.cjs', $url, $email, 'password']); + } + + $this->line($result->output()); + + if ($result->failed()) { + $this->error($result->errorOutput()); + return self::FAILURE; + } + + return self::SUCCESS; + } + + protected function shouldLogin(): bool + { + $email = $this->option('email'); + + if (! User::where('email', $email)->exists()) { + return false; + } + + return true; + } + + protected function fixLoginRequirements(string $email): void + { + if (! User::where('email', $email)->exists()) { + $this->info("Creating user: {$email}"); + + User::create([ + 'name' => 'Dev User', + 'email' => $email, + 'password' => Hash::make('password'), + ]); + } + } +} diff --git a/eslint.config.js b/eslint.config.js index ea86a49..1edc89d 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -7,7 +7,7 @@ export default defineConfigWithVueTs( vue.configs['flat/essential'], vueTsConfigs.recommended, { - ignores: ['vendor', 'node_modules', 'public', 'bootstrap/ssr', 'tailwind.config.js', 'resources/js/components/ui/*'], + ignores: ['vendor', 'node_modules', 'public', 'bootstrap/ssr', 'tailwind.config.js', 'resources/js/components/ui/*', 'scripts/*'], }, { rules: { diff --git a/resources/js/pages/settings/Providers.vue b/resources/js/pages/settings/Providers.vue index 2e51382..ea1240a 100644 --- a/resources/js/pages/settings/Providers.vue +++ b/resources/js/pages/settings/Providers.vue @@ -31,7 +31,6 @@ import { SelectValue, } from '@/components/ui/select'; import { Checkbox } from '@/components/ui/checkbox'; -import InputError from '@/components/InputError.vue'; import { Form } from '@inertiajs/vue3'; import { Trash2, Plus, Eye, EyeOff, Loader2, CheckCircle, XCircle } from 'lucide-vue-next'; diff --git a/scripts/login.cjs b/scripts/login.cjs new file mode 100644 index 0000000..6f2e98b --- /dev/null +++ b/scripts/login.cjs @@ -0,0 +1,20 @@ +const { chromium } = require('playwright'); + +const url = process.argv[2] || 'http://chat.test'; +const email = process.argv[3] || 'dev@test.com'; +const password = process.argv[4] || 'password'; + +(async () => { + const browser = await chromium.launch({ headless: false }); + const page = await browser.newPage(); + + await page.goto(url + '/login'); + await page.fill('input[type="email"], input[name="email"]', email); + await page.fill('input[type="password"], input[name="password"]', password); + await page.click('button[type="submit"]'); + + await page.waitForURL('**/dashboard**'); + + const finalUrl = page.url(); + console.log('Logged in as ' + email + ' - now on ' + finalUrl); +})(); diff --git a/tests/Feature/Http/Controllers/Settings/ProviderCredentialControllerTest.php b/tests/Feature/Http/Controllers/Settings/ProviderCredentialControllerTest.php index ee178a2..2c0f3f4 100644 --- a/tests/Feature/Http/Controllers/Settings/ProviderCredentialControllerTest.php +++ b/tests/Feature/Http/Controllers/Settings/ProviderCredentialControllerTest.php @@ -549,8 +549,8 @@ it('prevents toggling model when both credential and model belong to different users', function () { $user = User::factory()->create(); $other = User::factory()->create(); - $otherCredential = UserApiCredential::factory()->for($other)->create(); - $anotherCredential = UserApiCredential::factory()->for($other)->create(); + $otherCredential = UserApiCredential::factory()->for($other)->openai()->create(); + $anotherCredential = UserApiCredential::factory()->for($other)->anthropic()->create(); $model = \App\Models\AiModel::factory()->forCredential($anotherCredential)->create(['enabled' => true]); $response = $this->actingAs($user)->patch(