@dataroadinc/setup-auth
Version:
CLI tool and programmatic API for automated OAuth setup across cloud platforms
256 lines (218 loc) • 7.2 kB
text/typescript
/**
* Tests for the setup-auth programmatic API
*/
import { describe, it, expect, vi, beforeEach } from "vitest"
import {
SetupAuthAPI,
registerCallbackUrls,
updateCallbackUrls,
type CallbackUrlConfig,
} from "./index.js"
// Mock the GCP dependencies
vi.mock("../providers/gcp/oauth/client.js", () => ({
GcpOAuthWebClientManager: vi.fn().mockImplementation(() => ({
createClient: vi.fn().mockResolvedValue({
clientId: "test-client-id",
clientSecret: "test-client-secret",
}),
updateRedirectUris: vi.fn().mockResolvedValue(undefined),
})),
}))
vi.mock("../providers/gcp/creds/identity.js", () => ({
GcpIdentityFactory: {
createIdentity: vi.fn().mockResolvedValue({}),
},
}))
vi.mock("../utils/redirect-urls.js", () => ({
buildRedirectUriList: vi
.fn()
.mockReturnValue([
"https://test-app.vercel.app/api/auth/callback/gcp",
"https://test-app.com/api/auth/callback/gcp",
]),
}))
describe("SetupAuthAPI", () => {
let api: SetupAuthAPI
beforeEach(() => {
// Reset the singleton instance
;(SetupAuthAPI as unknown as { instance: SetupAuthAPI | null }).instance =
null
api = SetupAuthAPI.getInstance()
})
describe("getInstance", () => {
it("should return the same instance on multiple calls", () => {
const instance1 = SetupAuthAPI.getInstance()
const instance2 = SetupAuthAPI.getInstance()
expect(instance1).toBe(instance2)
})
})
describe("validateCallbackUrlConfig", () => {
it("should validate a valid GCP configuration", async () => {
const config: CallbackUrlConfig = {
provider: "gcp",
platform: "vercel",
projectConfig: {
gcpProjectId: "test-project-id",
},
}
// This should not throw
await expect(api.registerCallbackUrls(config)).resolves.toBeDefined()
})
it("should reject configuration without provider", async () => {
const config = {
platform: "vercel",
projectConfig: {
gcpProjectId: "test-project-id",
},
} as CallbackUrlConfig
const result = await api.registerCallbackUrls(config)
expect(result.success).toBe(false)
expect(result.error).toContain("OAuth provider is required")
})
it("should reject configuration without platform", async () => {
const config = {
provider: "gcp",
projectConfig: {
gcpProjectId: "test-project-id",
},
} as CallbackUrlConfig
const result = await api.registerCallbackUrls(config)
expect(result.success).toBe(false)
expect(result.error).toContain("Platform is required")
})
it("should reject GCP configuration without project ID", async () => {
const config: CallbackUrlConfig = {
provider: "gcp",
platform: "vercel",
projectConfig: {},
}
const result = await api.registerCallbackUrls(config)
expect(result.success).toBe(false)
expect(result.error).toContain(
"GCP project ID is required for GCP provider"
)
})
})
describe("registerCallbackUrls", () => {
it("should register GCP callback URLs successfully", async () => {
const config: CallbackUrlConfig = {
provider: "gcp",
platform: "vercel",
deploymentUrl: "https://test-app.vercel.app",
callbackPath: "/api/auth/callback/gcp",
projectConfig: {
gcpProjectId: "test-project-id",
},
}
const result = await api.registerCallbackUrls(config)
expect(result.success).toBe(true)
expect(result.registeredUrls).toBeDefined()
expect(result.clientId).toBe("test-client-id")
expect(result.providerDetails).toBeDefined()
})
it("should handle GitHub provider (not implemented)", async () => {
const config: CallbackUrlConfig = {
provider: "github",
platform: "vercel",
projectConfig: {
githubAppName: "test-app",
},
}
const result = await api.registerCallbackUrls(config)
expect(result.success).toBe(false)
expect(result.error).toContain(
"GitHub OAuth app creation not yet implemented"
)
})
it("should handle Azure provider (not implemented)", async () => {
const config: CallbackUrlConfig = {
provider: "azure",
platform: "vercel",
projectConfig: {
azureTenantId: "test-tenant-id",
},
}
const result = await api.registerCallbackUrls(config)
expect(result.success).toBe(false)
expect(result.error).toContain(
"Azure AD app registration not yet implemented"
)
})
it("should handle LinkedIn provider (not implemented)", async () => {
const config: CallbackUrlConfig = {
provider: "linkedin",
platform: "vercel",
projectConfig: {},
}
const result = await api.registerCallbackUrls(config)
expect(result.success).toBe(false)
expect(result.error).toContain(
"LinkedIn OAuth app creation not yet implemented"
)
})
})
describe("updateCallbackUrls", () => {
beforeEach(() => {
// Mock environment variable
process.env.GCP_OAUTH_CLIENT_ID =
"test-client-id.apps.googleusercontent.com"
})
it("should update GCP callback URLs successfully", async () => {
const config: CallbackUrlConfig = {
provider: "gcp",
platform: "vercel",
deploymentUrl: "https://test-app.vercel.app",
projectConfig: {
gcpProjectId: "test-project-id",
},
}
const result = await api.updateCallbackUrls(config)
expect(result.success).toBe(true)
expect(result.redirectUris).toBeDefined()
})
it("should fail when GCP client ID is not found", async () => {
delete process.env.GCP_OAUTH_CLIENT_ID
const config: CallbackUrlConfig = {
provider: "gcp",
platform: "vercel",
projectConfig: {
gcpProjectId: "test-project-id",
},
}
const result = await api.updateCallbackUrls(config)
expect(result.success).toBe(false)
expect(result.error).toContain("GCP OAuth client ID not found")
})
})
})
describe("Convenience functions", () => {
beforeEach(() => {
// Reset the singleton instance
;(SetupAuthAPI as unknown as { instance: SetupAuthAPI | null }).instance =
null
})
it("should export registerCallbackUrls function", async () => {
const config: CallbackUrlConfig = {
provider: "gcp",
platform: "vercel",
projectConfig: {
gcpProjectId: "test-project-id",
},
}
const result = await registerCallbackUrls(config)
expect(result.success).toBe(true)
})
it("should export updateCallbackUrls function", async () => {
process.env.GCP_OAUTH_CLIENT_ID =
"test-client-id.apps.googleusercontent.com"
const config: CallbackUrlConfig = {
provider: "gcp",
platform: "vercel",
projectConfig: {
gcpProjectId: "test-project-id",
},
}
const result = await updateCallbackUrls(config)
expect(result.success).toBe(true)
})
})