/** * YouTube OAuth Scopes Unit Tests * * Verifies that all required OAuth scopes are present in the YouTube OAuth configuration, * including upload and analytics scopes needed for the YouTube Operations Hub. */ import { describe, it, expect, vi } from 'vitest' vi.mock('googleapis', () => { class MockOAuth2 { generateAuthUrl({ scope }: { scope: string[] }): string { return `https://accounts.google.com/o/oauth2/v2/auth?scope=${encodeURIComponent(scope.join(' '))}` } } return { google: { auth: { OAuth2: MockOAuth2, }, }, } }) vi.stubEnv('YOUTUBE_CLIENT_ID', 'test-client-id') vi.stubEnv('YOUTUBE_CLIENT_SECRET', 'test-client-secret') vi.stubEnv('YOUTUBE_REDIRECT_URI', 'https://test.example.com/api/youtube/callback') describe('YouTube OAuth Scopes', () => { it('should include youtube.readonly scope', async () => { vi.resetModules() const { getAuthUrl } = await import('@/lib/integrations/youtube/oauth') const url = getAuthUrl() expect(url).toContain('youtube.readonly') }) it('should include youtube.force-ssl scope', async () => { vi.resetModules() const { getAuthUrl } = await import('@/lib/integrations/youtube/oauth') const url = getAuthUrl() expect(url).toContain('youtube.force-ssl') }) it('should include youtube scope (full access)', async () => { vi.resetModules() const { getAuthUrl } = await import('@/lib/integrations/youtube/oauth') const url = getAuthUrl() expect(url).toContain('auth%2Fyoutube') }) it('should include youtube.upload scope', async () => { vi.resetModules() const { getAuthUrl } = await import('@/lib/integrations/youtube/oauth') const url = getAuthUrl() expect(url).toContain('youtube.upload') }) it('should include yt-analytics.readonly scope', async () => { vi.resetModules() const { getAuthUrl } = await import('@/lib/integrations/youtube/oauth') const url = getAuthUrl() expect(url).toContain('yt-analytics.readonly') }) it('should contain exactly 5 scopes', async () => { vi.resetModules() const { getAuthUrl } = await import('@/lib/integrations/youtube/oauth') const url = getAuthUrl() const decodedUrl = decodeURIComponent(url) const scopeParam = decodedUrl.split('scope=')[1] const scopes = scopeParam.split(' ') expect(scopes).toHaveLength(5) }) })