import { GitHubProvider } from "../src/providers/GitHubProvider"; import { GoogleProvider } from "../src/providers/GoogleProvider"; import { getProvider } from "../src/providers/ProviderRegistry"; describe("OAuth Providers", () => { describe("GitHubProvider", () => { let provider: GitHubProvider; beforeEach(() => { provider = new GitHubProvider({ clientId: "test-github-client-id", clientSecret: "test-github-client-secret", callbackUrl: "https://myapp.com/oauth/github/callback", }); }); it("should generate correct authorization URL", () => { const url = provider.getAuthorizationUrl({ state: "random-state-123", redirectUri: "https://myapp.com/oauth/github/callback", scope: ["user:email"], }); expect(url).toContain("https://github.com/login/oauth/authorize"); expect(url).toContain("client_id=test-github-client-id"); expect(url).toContain("redirect_uri=https%3A%2F%2Fmyapp.com%2Foauth%2Fgithub%2Fcallback"); expect(url).toContain("state=random-state-123"); expect(url).toContain("scope=user%3Aemail"); }); it("should use default scopes when none provided", () => { const url = provider.getAuthorizationUrl({ state: "random-state-123", redirectUri: "https://myapp.com/oauth/github/callback", scope: [], }); expect(url).toContain("scope=user%3Aemail"); }); it("should exchange code for token", async () => { const mockResponse = { access_token: "gho_test_access_token", token_type: "bearer", scope: "user:email", }; spyOn(provider, "makeHttpRequest").and.returnValue(Promise.resolve(mockResponse)); const tokens = await provider.exchangeCodeForToken({ code: "auth-code-123", redirectUri: "https://myapp.com/oauth/github/callback", }); expect(tokens.accessToken).toBe("gho_test_access_token"); expect(tokens.scope).toBe("user:email"); }); it("should fetch user profile", async () => { const mockProfile = { id: 123456, login: "testuser", email: "test@example.com", name: "Test User", avatar_url: "https://avatars.githubusercontent.com/u/123456", }; spyOn(provider, "makeHttpRequest").and.returnValue(Promise.resolve(mockProfile)); const profile = await provider.getUserProfile("gho_test_access_token"); expect(profile.id).toBe("123456"); expect(profile.email).toBe("test@example.com"); expect(profile.name).toBe("Test User"); expect(profile.avatarUrl).toBe("https://avatars.githubusercontent.com/u/123456"); expect(profile.raw).toBeDefined(); }); }); describe("GoogleProvider", () => { let provider: GoogleProvider; beforeEach(() => { provider = new GoogleProvider({ clientId: "test-google-client-id", clientSecret: "test-google-client-secret", callbackUrl: "https://myapp.com/oauth/google/callback", }); }); it("should generate correct authorization URL", () => { const url = provider.getAuthorizationUrl({ state: "random-state-456", redirectUri: "https://myapp.com/oauth/google/callback", scope: ["openid", "email", "profile"], }); expect(url).toContain("https://accounts.google.com/o/oauth2/v2/auth"); expect(url).toContain("client_id=test-google-client-id"); expect(url).toContain("redirect_uri=https%3A%2F%2Fmyapp.com%2Foauth%2Fgoogle%2Fcallback"); expect(url).toContain("state=random-state-456"); expect(url).toContain("scope=openid%20email%20profile"); expect(url).toContain("response_type=code"); }); it("should exchange code for token", async () => { const mockResponse = { access_token: "ya29.test_access_token", token_type: "Bearer", expires_in: 3600, scope: "openid email profile", }; spyOn(provider, "makeHttpRequest").and.returnValue(Promise.resolve(mockResponse)); const tokens = await provider.exchangeCodeForToken({ code: "auth-code-456", redirectUri: "https://myapp.com/oauth/google/callback", }); expect(tokens.accessToken).toBe("ya29.test_access_token"); expect(tokens.expiresIn).toBe(3600); expect(tokens.scope).toBe("openid email profile"); }); it("should fetch user profile", async () => { const mockProfile = { id: "123456789", email: "test@gmail.com", verified_email: true, name: "Test Google User", picture: "https://lh3.googleusercontent.com/a/test", }; spyOn(provider, "makeHttpRequest").and.returnValue(Promise.resolve(mockProfile)); const profile = await provider.getUserProfile("ya29.test_access_token"); expect(profile.id).toBe("123456789"); expect(profile.email).toBe("test@gmail.com"); expect(profile.name).toBe("Test Google User"); expect(profile.avatarUrl).toBe("https://lh3.googleusercontent.com/a/test"); expect(profile.raw).toBeDefined(); }); }); describe("ProviderRegistry", () => { it("should return GitHubProvider for github", () => { const provider = getProvider("github", { clientId: "test-id", clientSecret: "test-secret", callbackUrl: "https://myapp.com/oauth/github/callback", }); expect(provider).toBeInstanceOf(GitHubProvider); }); it("should return GoogleProvider for google", () => { const provider = getProvider("google", { clientId: "test-id", clientSecret: "test-secret", callbackUrl: "https://myapp.com/oauth/google/callback", }); expect(provider).toBeInstanceOf(GoogleProvider); }); it("should throw error for unsupported provider", () => { expect(() => { getProvider("facebook" as any, { clientId: "test-id", clientSecret: "test-secret", callbackUrl: "https://myapp.com/oauth/facebook/callback", }); }).toThrowError("Unsupported OAuth provider: facebook"); }); }); });