Skip to content

Commit 95bc36b

Browse files
Checkpoint before follow-up message
Co-authored-by: me <[email protected]>
1 parent fb969ac commit 95bc36b

File tree

1 file changed

+45
-7
lines changed

1 file changed

+45
-7
lines changed

exercises/99.finished/99.solution/test/index.test.ts

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,43 @@ import { test, expect, inject } from 'vitest'
55
const mcpServerPort = inject('mcpServerPort')
66
const EPIC_ME_SERVER_URL = 'http://localhost:7788'
77

8+
// TypeScript interfaces for API responses
9+
interface AuthServerConfig {
10+
authorization_endpoint: string
11+
token_endpoint: string
12+
[key: string]: unknown
13+
}
14+
15+
interface ProtectedResourceConfig {
16+
resource: string
17+
scopes: string[]
18+
[key: string]: unknown
19+
}
20+
21+
interface ClientRegistration {
22+
client_id: string
23+
client_secret?: string
24+
[key: string]: unknown
25+
}
26+
27+
interface AuthResult {
28+
redirectTo: string
29+
[key: string]: unknown
30+
}
31+
32+
interface TokenResult {
33+
access_token: string
34+
token_type: string
35+
[key: string]: unknown
36+
}
37+
38+
interface OriginalParams {
39+
client_id: string
40+
redirect_uri: string
41+
response_type: string
42+
[key: string]: unknown
43+
}
44+
845
// Helper function to generate PKCE challenge
946
function generateCodeChallenge() {
1047
const codeVerifier = btoa(
@@ -46,21 +83,22 @@ test('OAuth integration flow works end-to-end', async () => {
4683
const authUrlMatch = wwwAuthHeader?.match(/authorization_url="([^"]+)"/)
4784
expect(authUrlMatch, '🚨 Could not extract authorization URL from WWW-Authenticate header').toBeTruthy()
4885
const authorizationUrl = authUrlMatch![1]
86+
expect(authorizationUrl, '🚨 Authorization URL should not be empty').toBeTruthy()
4987

5088
// Step 1: Metadata discovery
5189
// Test OAuth Authorization Server discovery
5290
const authServerDiscoveryResponse = await fetch(`${mcpServerUrl}/.well-known/oauth-authorization-server`)
5391
expect(authServerDiscoveryResponse.ok, '🚨 OAuth authorization server discovery should succeed').toBe(true)
5492

55-
const authServerConfig = await authServerDiscoveryResponse.json()
93+
const authServerConfig = await authServerDiscoveryResponse.json() as AuthServerConfig
5694
expect(authServerConfig.authorization_endpoint, '🚨 Authorization endpoint should be present in discovery').toBeTruthy()
5795
expect(authServerConfig.token_endpoint, '🚨 Token endpoint should be present in discovery').toBeTruthy()
5896

5997
// Test OAuth Protected Resource discovery
6098
const protectedResourceDiscoveryResponse = await fetch(`${mcpServerUrl}/.well-known/oauth-protected-resource/mcp`)
6199
expect(protectedResourceDiscoveryResponse.ok, '🚨 OAuth protected resource discovery should succeed').toBe(true)
62100

63-
const protectedResourceConfig = await protectedResourceDiscoveryResponse.json()
101+
const protectedResourceConfig = await protectedResourceDiscoveryResponse.json() as ProtectedResourceConfig
64102
expect(protectedResourceConfig.resource, '🚨 Resource identifier should be present').toBe('epicme-mcp')
65103
expect(protectedResourceConfig.scopes, '🚨 Scopes should be present').toContain('read')
66104
expect(protectedResourceConfig.scopes, '🚨 Scopes should contain write').toContain('write')
@@ -77,16 +115,16 @@ test('OAuth integration flow works end-to-end', async () => {
77115
})
78116

79117
expect(clientRegistrationResponse.ok, '🚨 Client registration should succeed').toBe(true)
80-
const clientRegistration = await clientRegistrationResponse.json()
118+
const clientRegistration = await clientRegistrationResponse.json() as ClientRegistration
81119
expect(clientRegistration.client_id, '🚨 Client ID should be returned from registration').toBeTruthy()
82120

83121
// Step 3: Preparing Authorization (getting the auth URL)
84122
const { codeVerifier, codeChallenge, codeChallengeMethod } = generateCodeChallenge()
85123
const state = crypto.randomUUID()
86124
const redirectUri = `${mcpServerUrl}/mcp`
87125

88-
const authUrl = new URL(authorizationUrl)
89-
const originalParams = JSON.parse(authUrl.searchParams.get('oauth_req_info') || '{}')
126+
const authUrl = new URL(authorizationUrl as string)
127+
const originalParams = JSON.parse(authUrl.searchParams.get('oauth_req_info') || '{}') as OriginalParams
90128

91129
expect(originalParams.client_id, '🚨 Client ID should be present in auth URL').toBeTruthy()
92130
expect(originalParams.redirect_uri, '🚨 Redirect URI should be present in auth URL').toBeTruthy()
@@ -106,7 +144,7 @@ test('OAuth integration flow works end-to-end', async () => {
106144
const authCodeResponse = await fetch(testAuthUrl.toString())
107145
expect(authCodeResponse.ok, '🚨 Auth code request should succeed').toBe(true)
108146

109-
const authResult = await authCodeResponse.json()
147+
const authResult = await authCodeResponse.json() as AuthResult
110148
expect(authResult.redirectTo, '🚨 Redirect URL should be returned').toBeTruthy()
111149

112150
// Step 5: Supplying the auth code (extract from redirect URL)
@@ -143,7 +181,7 @@ test('OAuth integration flow works end-to-end', async () => {
143181
}
144182

145183
expect(tokenResponse.ok, '🚨 Token exchange should succeed').toBe(true)
146-
const tokenResult = await tokenResponse.json()
184+
const tokenResult = await tokenResponse.json() as TokenResult
147185
expect(tokenResult.access_token, '🚨 Access token should be returned').toBeTruthy()
148186
expect(tokenResult.token_type?.toLowerCase(), '🚨 Token type should be Bearer').toBe('bearer')
149187

0 commit comments

Comments
 (0)