Skip to content

Commit c7f9e36

Browse files
committed
update tests
1 parent 9195587 commit c7f9e36

File tree

2 files changed

+58
-102
lines changed

2 files changed

+58
-102
lines changed

src/client/auth.test.ts

Lines changed: 50 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { mock, Mock } from 'node:test';
12
import { LATEST_PROTOCOL_VERSION } from '../types.js';
23
import {
34
discoverOAuthMetadata,
@@ -16,8 +17,25 @@ const mockFetch = jest.fn();
1617
global.fetch = mockFetch;
1718

1819
describe("OAuth Authorization", () => {
20+
let mockProvider: OAuthClientProvider;
21+
1922
beforeEach(() => {
2023
mockFetch.mockReset();
24+
mockProvider = {
25+
get redirectUrl() { return "http://localhost:3000/callback"; },
26+
get clientMetadata() {
27+
return {
28+
redirect_uris: ["http://localhost:3000/callback"],
29+
client_name: "Test Client",
30+
};
31+
},
32+
clientInformation: jest.fn(),
33+
tokens: jest.fn(),
34+
saveTokens: jest.fn(),
35+
redirectToAuthorization: jest.fn(),
36+
saveCodeVerifier: jest.fn(),
37+
codeVerifier() { return "verifier123"; },
38+
};
2139
});
2240

2341
describe("extractResourceMetadataUrl", () => {
@@ -462,9 +480,9 @@ describe("OAuth Authorization", () => {
462480
{
463481
metadata: undefined,
464482
clientInformation: validClientInfo,
465-
redirectUrl: "http://localhost:3000/callback",
466483
resource: new URL("https://api.example.com/mcp-server"),
467-
}
484+
},
485+
mockProvider
468486
);
469487

470488
expect(authorizationUrl.toString()).toMatch(
@@ -487,9 +505,9 @@ describe("OAuth Authorization", () => {
487505
"https://auth.example.com",
488506
{
489507
clientInformation: validClientInfo,
490-
redirectUrl: "http://localhost:3000/callback",
491508
scope: "read write profile",
492-
}
509+
},
510+
mockProvider
493511
);
494512

495513
expect(authorizationUrl.searchParams.get("scope")).toBe("read write profile");
@@ -500,8 +518,8 @@ describe("OAuth Authorization", () => {
500518
"https://auth.example.com",
501519
{
502520
clientInformation: validClientInfo,
503-
redirectUrl: "http://localhost:3000/callback",
504-
}
521+
},
522+
mockProvider
505523
);
506524

507525
expect(authorizationUrl.searchParams.has("scope")).toBe(false);
@@ -512,9 +530,9 @@ describe("OAuth Authorization", () => {
512530
"https://auth.example.com",
513531
{
514532
clientInformation: validClientInfo,
515-
redirectUrl: "http://localhost:3000/callback",
516533
state: "foobar",
517-
}
534+
},
535+
mockProvider
518536
);
519537

520538
expect(authorizationUrl.searchParams.get("state")).toBe("foobar");
@@ -525,8 +543,8 @@ describe("OAuth Authorization", () => {
525543
"https://auth.example.com",
526544
{
527545
clientInformation: validClientInfo,
528-
redirectUrl: "http://localhost:3000/callback",
529-
}
546+
},
547+
mockProvider
530548
);
531549

532550
expect(authorizationUrl.searchParams.has("state")).toBe(false);
@@ -538,8 +556,8 @@ describe("OAuth Authorization", () => {
538556
{
539557
metadata: validMetadata,
540558
clientInformation: validClientInfo,
541-
redirectUrl: "http://localhost:3000/callback",
542-
}
559+
},
560+
mockProvider
543561
);
544562

545563
expect(authorizationUrl.toString()).toMatch(
@@ -557,8 +575,7 @@ describe("OAuth Authorization", () => {
557575
startAuthorization("https://auth.example.com", {
558576
metadata,
559577
clientInformation: validClientInfo,
560-
redirectUrl: "http://localhost:3000/callback",
561-
})
578+
}, mockProvider)
562579
).rejects.toThrow(/does not support response type/);
563580
});
564581

@@ -573,29 +590,12 @@ describe("OAuth Authorization", () => {
573590
startAuthorization("https://auth.example.com", {
574591
metadata,
575592
clientInformation: validClientInfo,
576-
redirectUrl: "http://localhost:3000/callback",
577-
})
593+
}, mockProvider)
578594
).rejects.toThrow(/does not support code challenge method/);
579595
});
580596
});
581597

582598
describe("exchangeAuthorization", () => {
583-
const mockProvider: OAuthClientProvider = {
584-
get redirectUrl() { return "http://localhost:3000/callback"; },
585-
get clientMetadata() {
586-
return {
587-
redirect_uris: ["http://localhost:3000/callback"],
588-
client_name: "Test Client",
589-
};
590-
},
591-
clientInformation: jest.fn(),
592-
tokens: jest.fn(),
593-
saveTokens: jest.fn(),
594-
redirectToAuthorization: jest.fn(),
595-
saveCodeVerifier: jest.fn(),
596-
codeVerifier: jest.fn(),
597-
};
598-
599599
const validTokens = {
600600
access_token: "access123",
601601
token_type: "Bearer",
@@ -620,10 +620,8 @@ describe("OAuth Authorization", () => {
620620
const tokens = await exchangeAuthorization("https://auth.example.com", {
621621
clientInformation: validClientInfo,
622622
authorizationCode: "code123",
623-
codeVerifier: "verifier123",
624-
redirectUri: "http://localhost:3000/callback",
625623
resource: new URL("https://api.example.com/mcp-server"),
626-
});
624+
}, mockProvider);
627625

628626
expect(tokens).toEqual(validTokens);
629627
expect(mockFetch).toHaveBeenCalledWith(
@@ -632,11 +630,12 @@ describe("OAuth Authorization", () => {
632630
}),
633631
expect.objectContaining({
634632
method: "POST",
633+
headers: new Headers({
634+
"Content-Type": "application/x-www-form-urlencoded",
635+
}),
635636
})
636637
);
637638

638-
const headers = mockFetch.mock.calls[0][1].headers as Headers;
639-
expect(headers.get("Content-Type")).toBe("application/x-www-form-urlencoded");
640639
const body = mockFetch.mock.calls[0][1].body as URLSearchParams;
641640
expect(body.get("grant_type")).toBe("authorization_code");
642641
expect(body.get("code")).toBe("code123");
@@ -663,8 +662,6 @@ describe("OAuth Authorization", () => {
663662
const tokens = await exchangeAuthorization("https://auth.example.com", {
664663
clientInformation: validClientInfo,
665664
authorizationCode: "code123",
666-
codeVerifier: "verifier123",
667-
redirectUri: "http://localhost:3000/callback",
668665
}, mockProvider);
669666

670667
expect(tokens).toEqual(validTokens);
@@ -705,9 +702,7 @@ describe("OAuth Authorization", () => {
705702
exchangeAuthorization("https://auth.example.com", {
706703
clientInformation: validClientInfo,
707704
authorizationCode: "code123",
708-
codeVerifier: "verifier123",
709-
redirectUri: "http://localhost:3000/callback",
710-
})
705+
}, mockProvider)
711706
).rejects.toThrow();
712707
});
713708

@@ -721,30 +716,12 @@ describe("OAuth Authorization", () => {
721716
exchangeAuthorization("https://auth.example.com", {
722717
clientInformation: validClientInfo,
723718
authorizationCode: "code123",
724-
codeVerifier: "verifier123",
725-
redirectUri: "http://localhost:3000/callback",
726-
})
719+
}, mockProvider)
727720
).rejects.toThrow("Token exchange failed");
728721
});
729722
});
730723

731724
describe("refreshAuthorization", () => {
732-
const mockProvider: OAuthClientProvider = {
733-
get redirectUrl() { return "http://localhost:3000/callback"; },
734-
get clientMetadata() {
735-
return {
736-
redirect_uris: ["http://localhost:3000/callback"],
737-
client_name: "Test Client",
738-
};
739-
},
740-
clientInformation: jest.fn(),
741-
tokens: jest.fn(),
742-
saveTokens: jest.fn(),
743-
redirectToAuthorization: jest.fn(),
744-
saveCodeVerifier: jest.fn(),
745-
codeVerifier: jest.fn(),
746-
};
747-
748725
const validTokens = {
749726
access_token: "newaccess123",
750727
token_type: "Bearer",
@@ -773,7 +750,7 @@ describe("OAuth Authorization", () => {
773750
clientInformation: validClientInfo,
774751
refreshToken: "refresh123",
775752
resource: new URL("https://api.example.com/mcp-server"),
776-
});
753+
}, mockProvider);
777754

778755
expect(tokens).toEqual(validTokensWithNewRefreshToken);
779756
expect(mockFetch).toHaveBeenCalledWith(
@@ -785,8 +762,6 @@ describe("OAuth Authorization", () => {
785762
})
786763
);
787764

788-
const headers = mockFetch.mock.calls[0][1].headers as Headers;
789-
expect(headers.get("Content-Type")).toBe("application/x-www-form-urlencoded");
790765
const body = mockFetch.mock.calls[0][1].body as URLSearchParams;
791766
expect(body.get("grant_type")).toBe("refresh_token");
792767
expect(body.get("refresh_token")).toBe("refresh123");
@@ -846,7 +821,7 @@ describe("OAuth Authorization", () => {
846821
const tokens = await refreshAuthorization("https://auth.example.com", {
847822
clientInformation: validClientInfo,
848823
refreshToken,
849-
});
824+
}, mockProvider);
850825

851826
expect(tokens).toEqual({ refresh_token: refreshToken, ...validTokens });
852827
});
@@ -865,7 +840,7 @@ describe("OAuth Authorization", () => {
865840
refreshAuthorization("https://auth.example.com", {
866841
clientInformation: validClientInfo,
867842
refreshToken: "refresh123",
868-
})
843+
}, mockProvider)
869844
).rejects.toThrow();
870845
});
871846

@@ -879,7 +854,7 @@ describe("OAuth Authorization", () => {
879854
refreshAuthorization("https://auth.example.com", {
880855
clientInformation: validClientInfo,
881856
refreshToken: "refresh123",
882-
})
857+
}, mockProvider)
883858
).rejects.toThrow("Token refresh failed");
884859
});
885860
});
@@ -1624,9 +1599,7 @@ describe("OAuth Authorization", () => {
16241599
metadata: metadataWithBasicOnly,
16251600
clientInformation: validClientInfo,
16261601
authorizationCode: "code123",
1627-
codeVerifier: "verifier123",
1628-
redirectUri: "http://localhost:3000/callback",
1629-
});
1602+
}, mockProvider);
16301603

16311604
expect(tokens).toEqual(validTokens);
16321605
const request = mockFetch.mock.calls[0][1];
@@ -1652,9 +1625,7 @@ describe("OAuth Authorization", () => {
16521625
metadata: metadataWithPostOnly,
16531626
clientInformation: validClientInfo,
16541627
authorizationCode: "code123",
1655-
codeVerifier: "verifier123",
1656-
redirectUri: "http://localhost:3000/callback",
1657-
});
1628+
}, mockProvider);
16581629

16591630
expect(tokens).toEqual(validTokens);
16601631
const request = mockFetch.mock.calls[0][1];
@@ -1684,9 +1655,7 @@ describe("OAuth Authorization", () => {
16841655
metadata: metadataWithNoneOnly,
16851656
clientInformation: clientInfoWithoutSecret,
16861657
authorizationCode: "code123",
1687-
codeVerifier: "verifier123",
1688-
redirectUri: "http://localhost:3000/callback",
1689-
});
1658+
}, mockProvider);
16901659

16911660
expect(tokens).toEqual(validTokens);
16921661
const request = mockFetch.mock.calls[0][1];
@@ -1709,14 +1678,13 @@ describe("OAuth Authorization", () => {
17091678
const tokens = await exchangeAuthorization("https://auth.example.com", {
17101679
clientInformation: validClientInfo,
17111680
authorizationCode: "code123",
1712-
codeVerifier: "verifier123",
1713-
redirectUri: "http://localhost:3000/callback",
1714-
});
1681+
}, mockProvider);
17151682

17161683
expect(tokens).toEqual(validTokens);
17171684
const request = mockFetch.mock.calls[0][1];
17181685

1719-
// Check no Authorization header
1686+
// Check headers
1687+
expect(request.headers.get("Content-Type")).toBe("application/x-www-form-urlencoded");
17201688
expect(request.headers.get("Authorization")).toBeNull();
17211689

17221690
const body = request.body as URLSearchParams;
@@ -1764,7 +1732,7 @@ describe("OAuth Authorization", () => {
17641732
metadata: metadataWithBasicOnly,
17651733
clientInformation: validClientInfo,
17661734
refreshToken: "refresh123",
1767-
});
1735+
}, mockProvider);
17681736

17691737
expect(tokens).toEqual(validTokens);
17701738
const request = mockFetch.mock.calls[0][1];
@@ -1791,7 +1759,7 @@ describe("OAuth Authorization", () => {
17911759
metadata: metadataWithPostOnly,
17921760
clientInformation: validClientInfo,
17931761
refreshToken: "refresh123",
1794-
});
1762+
}, mockProvider);
17951763

17961764
expect(tokens).toEqual(validTokens);
17971765
const request = mockFetch.mock.calls[0][1];

0 commit comments

Comments
 (0)