rm loading, prm test

This commit is contained in:
Paul Carleton 2025-05-29 14:10:32 +01:00
commit 03bb303bf9
No known key found for this signature in database
4 changed files with 131 additions and 22 deletions

View file

@ -329,8 +329,6 @@ const App = () => {
}
} catch (error) {
console.error("Error loading OAuth tokens:", error);
} finally {
updateAuthState({ loading: false });
}
};

View file

@ -60,23 +60,23 @@ const AuthDebugger = ({
authState,
updateAuthState,
}: AuthDebuggerProps) => {
// Initialize loading state
// Check for existing tokens on mount
useEffect(() => {
if (authState.loading && serverUrl) {
// Check if we have existing tokens
if (serverUrl && !authState.oauthTokens) {
const checkTokens = async () => {
const provider = new DebugInspectorOAuthClientProvider(serverUrl);
const existingTokens = await provider.tokens();
updateAuthState({
loading: false,
oauthTokens: existingTokens || null,
});
if (existingTokens) {
updateAuthState({
oauthTokens: existingTokens,
oauthStep: "complete",
});
}
};
checkTokens();
}
}, [serverUrl, authState.loading, updateAuthState]);
}, [serverUrl]); // Only run when serverUrl changes
const startOAuthFlow = useCallback(() => {
if (!serverUrl) {
updateAuthState({
@ -241,10 +241,7 @@ const AuthDebugger = ({
<StatusMessage message={authState.statusMessage} />
)}
{authState.loading ? (
<p>Loading authentication status...</p>
) : (
<div className="space-y-4">
<div className="space-y-4">
{authState.oauthTokens && (
<div className="space-y-2">
<p className="text-sm font-medium">Access Token:</p>
@ -286,7 +283,6 @@ const AuthDebugger = ({
the standard automatic flow.
</p>
</div>
)}
</div>
<OAuthFlowProgress

View file

@ -106,7 +106,9 @@ describe("AuthDebugger", () => {
mockDiscoverOAuthMetadata.mockResolvedValue(mockOAuthMetadata);
mockRegisterClient.mockResolvedValue(mockOAuthClientInfo);
mockDiscoverOAuthProtectedResourceMetadata.mockResolvedValue(null);
mockDiscoverOAuthProtectedResourceMetadata.mockRejectedValue(
new Error("No protected resource metadata found")
);
mockStartAuthorization.mockImplementation(async (_sseUrl, options) => {
const authUrl = new URL("https://oauth.example.com/authorize");
@ -448,7 +450,7 @@ describe("AuthDebugger", () => {
await act(async () => {
renderAuthDebugger({
updateAuthState,
authState: { ...defaultAuthState, loading: false },
authState: { ...defaultAuthState },
});
});
@ -471,7 +473,7 @@ describe("AuthDebugger", () => {
).mock.calls.find((call) => call[0] === SESSION_KEYS.AUTH_DEBUGGER_STATE);
expect(storedStateCall).toBeDefined();
const storedState = JSON.parse(storedStateCall![1]);
const storedState = JSON.parse(storedStateCall![1] as string);
expect(storedState).toMatchObject({
oauthStep: "authorization_code",
@ -487,4 +489,119 @@ describe("AuthDebugger", () => {
});
});
});
describe("OAuth Protected Resource Metadata", () => {
it("should successfully fetch and display protected resource metadata", async () => {
const updateAuthState = jest.fn();
const mockResourceMetadata = {
resource: "https://example.com/api",
authorization_servers: ["https://custom-auth.example.com"],
bearer_methods_supported: ["header", "body"],
resource_documentation: "https://example.com/api/docs",
resource_policy_uri: "https://example.com/api/policy",
};
// Mock successful metadata discovery
mockDiscoverOAuthProtectedResourceMetadata.mockResolvedValue(
mockResourceMetadata
);
mockDiscoverOAuthMetadata.mockResolvedValue(mockOAuthMetadata);
await act(async () => {
renderAuthDebugger({
updateAuthState,
authState: { ...defaultAuthState },
});
});
// Click Guided OAuth Flow to start the process
await act(async () => {
fireEvent.click(screen.getByText("Guided OAuth Flow"));
});
// Verify that the flow started with metadata discovery
expect(updateAuthState).toHaveBeenCalledWith({
oauthStep: "metadata_discovery",
authorizationUrl: null,
statusMessage: null,
latestError: null,
});
// Click Continue to trigger metadata discovery
const continueButton = await screen.findByText("Continue");
await act(async () => {
fireEvent.click(continueButton);
});
// Wait for the metadata to be fetched
await waitFor(() => {
expect(mockDiscoverOAuthProtectedResourceMetadata).toHaveBeenCalledWith(
"https://example.com"
);
});
// Verify the state was updated with the resource metadata
await waitFor(() => {
expect(updateAuthState).toHaveBeenCalledWith(
expect.objectContaining({
resourceMetadata: mockResourceMetadata,
authServerUrl: new URL("https://custom-auth.example.com"),
oauthStep: "client_registration",
})
);
});
});
it("should handle protected resource metadata fetch failure gracefully", async () => {
const updateAuthState = jest.fn();
const mockError = new Error("Failed to fetch resource metadata");
// Mock failed metadata discovery
mockDiscoverOAuthProtectedResourceMetadata.mockRejectedValue(mockError);
// But OAuth metadata should still work with the original URL
mockDiscoverOAuthMetadata.mockResolvedValue(mockOAuthMetadata);
await act(async () => {
renderAuthDebugger({
updateAuthState,
authState: { ...defaultAuthState },
});
});
// Click Guided OAuth Flow
await act(async () => {
fireEvent.click(screen.getByText("Guided OAuth Flow"));
});
// Click Continue to trigger metadata discovery
const continueButton = await screen.findByText("Continue");
await act(async () => {
fireEvent.click(continueButton);
});
// Wait for the metadata fetch to fail
await waitFor(() => {
expect(mockDiscoverOAuthProtectedResourceMetadata).toHaveBeenCalledWith(
"https://example.com"
);
});
// Verify the flow continues despite the error
await waitFor(() => {
expect(updateAuthState).toHaveBeenCalledWith(
expect.objectContaining({
resourceMetadataError: mockError,
// Should use the original server URL as fallback
authServerUrl: new URL("https://example.com"),
oauthStep: "client_registration",
})
);
});
// Verify that regular OAuth metadata discovery was still called
expect(mockDiscoverOAuthMetadata).toHaveBeenCalledWith(
new URL("https://example.com")
);
});
});
});

View file

@ -27,7 +27,6 @@ export interface StatusMessage {
export interface AuthDebuggerState {
isInitiatingAuth: boolean;
oauthTokens: OAuthTokens | null;
loading: boolean;
oauthStep: OAuthStep;
resourceMetadata: OAuthProtectedResourceMetadata | null;
resourceMetadataError:
@ -47,7 +46,6 @@ export interface AuthDebuggerState {
export const EMPTY_DEBUGGER_STATE: AuthDebuggerState = {
isInitiatingAuth: false,
oauthTokens: null,
loading: true,
oauthStep: "metadata_discovery",
oauthMetadata: null,
resourceMetadata: null,