extend(TestCase::class) ->use(RefreshDatabase::class) ->in('Feature'); pest()->extend(BrowserTestCase::class) ->use(RefreshDatabase::class) ->in('Browser'); /* |-------------------------------------------------------------------------- | Expectations |-------------------------------------------------------------------------- | | When you're writing tests, you often need to check that values meet certain conditions. The | "expect()" function gives you access to a set of "expectations" methods that you can use | to assert different things. Of course, you may extend the Expectation API at any time. | */ expect()->extend('toBeOne', function () { return $this->toBe(1); }); /* |-------------------------------------------------------------------------- | Functions |-------------------------------------------------------------------------- | | While Pest is very powerful out-of-the-box, you may have some testing code specific to your | project that you don't want to repeat in every file. Here you can also expose helpers as | global functions to help you to reduce the number of lines of code in your test files. | */ function something() { // .. } /* |-------------------------------------------------------------------------- | Helpers |-------------------------------------------------------------------------- */ /** * Issue a Passport personal access token bound to the user's current * workspace, the same way the settings screen does, and return the plain * token to send as a bearer. */ function apiTokenFor(User $user, ?string $name = 'Test key'): string { // Personal access grants need a client; create one per test database. if (! Passport::client()->newQuery() ->whereJsonContains('grant_types', 'personal_access') ->exists()) { app(ClientRepository::class)->createPersonalAccessGrantClient( 'Test Personal Access Client', 'users', ); } return CreateApiKey::execute( $user, $user->currentWorkspace, ['name' => $name], )['plain_token']; } /** * Attach another workspace the user can pick on the MCP consent screen. * * @param array $attributes */ function attachWorkspaceTo(User $user, array $attributes = []): Workspace { $workspace = Workspace::factory()->create($attributes); $workspace->forceFill(['owner_id' => $user->id])->save(); $user->workspaces()->attach($workspace->id, ['role' => Role::ROLE_ADMIN->value]); return $workspace->fresh(); } /** * Insert an OAuth client suitable for MCP connection tests. */ function mcpOauthClient(string $name = 'My Agent'): string { $id = (string) Str::uuid(); DB::table('oauth_clients')->insert([ 'id' => $id, 'name' => $name, 'secret' => null, 'provider' => null, 'redirect_uris' => '[]', 'grant_types' => json_encode(['authorization_code', 'refresh_token']), 'revoked' => false, 'created_at' => now(), 'updated_at' => now(), ]); return $id; } /** * @return array */ function oauthAuthorizeQuery( string $clientId, string $redirectUri = 'https://client.example/callback', string $prompt = 'consent', ): array { $verifier = Str::random(64); $challenge = rtrim(strtr(base64_encode(hash('sha256', $verifier, true)), '+/', '-_'), '='); return [ 'client_id' => $clientId, 'redirect_uri' => $redirectUri, 'response_type' => 'code', 'scope' => 'mcp:use', 'state' => 'test-state', 'code_challenge' => $challenge, 'code_challenge_method' => 'S256', 'prompt' => $prompt, ]; } /** * Create an active OAuth access token for MCP connection tests. * * @param list $scopes */ function mcpAccessToken( User $user, string $clientId, ?Workspace $workspace = null, array $scopes = ['mcp:use'], ): AccessToken { $token = new AccessToken; $token->forceFill([ 'id' => Str::random(80), 'user_id' => $user->id, 'client_id' => $clientId, 'workspace_id' => $workspace?->id, 'name' => 'MCP', 'scopes' => $scopes, 'revoked' => false, 'expires_at' => now()->addYear(), ])->save(); return $token->refresh(); }