Files
smoothschedule/frontend/src/hooks/__tests__/usePlatformOAuth.test.ts
poduck 8dc2248f1f feat: Add comprehensive test suite and misc improvements
- Add frontend unit tests with Vitest for components, hooks, pages, and utilities
- Add backend tests for webhooks, notifications, middleware, and edge cases
- Add ForgotPassword, NotFound, and ResetPassword pages
- Add migration for orphaned staff resources conversion
- Add coverage directory to gitignore (generated reports)
- Various bug fixes and improvements from previous work

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-08 02:36:46 -05:00

1562 lines
42 KiB
TypeScript

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { renderHook, waitFor, act } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import React from 'react';
// Mock the platformOAuth API
vi.mock('../../api/platformOAuth', () => ({
getPlatformOAuthSettings: vi.fn(),
updatePlatformOAuthSettings: vi.fn(),
}));
import {
usePlatformOAuthSettings,
useUpdatePlatformOAuthSettings,
} from '../usePlatformOAuth';
import * as platformOAuthApi from '../../api/platformOAuth';
// Create wrapper for React Query
const createWrapper = () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false },
},
});
return function Wrapper({ children }: { children: React.ReactNode }) {
return React.createElement(QueryClientProvider, { client: queryClient }, children);
};
};
describe('usePlatformOAuth hooks', () => {
beforeEach(() => {
vi.clearAllMocks();
});
// ============================================================================
// usePlatformOAuthSettings Query Hook
// ============================================================================
describe('usePlatformOAuthSettings', () => {
it('fetches platform OAuth settings successfully', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: true,
client_id: 'google-client-id',
client_secret: 'google-secret',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: true,
client_id: 'facebook-client-id',
client_secret: 'facebook-secret',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: true,
client_id: 'microsoft-client-id',
client_secret: 'microsoft-secret',
tenant_id: 'microsoft-tenant-id',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.getPlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => usePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
// Initially loading
expect(result.current.isLoading).toBe(true);
// Wait for success
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
expect(platformOAuthApi.getPlatformOAuthSettings).toHaveBeenCalledTimes(1);
expect(result.current.data).toEqual(mockResponse);
expect(result.current.data?.oauth_allow_registration).toBe(true);
expect(result.current.data?.google.enabled).toBe(true);
expect(result.current.data?.facebook.enabled).toBe(true);
expect(result.current.data?.microsoft.enabled).toBe(true);
});
it('handles all providers disabled', async () => {
const mockResponse = {
oauth_allow_registration: false,
google: {
enabled: false,
client_id: '',
client_secret: '',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.getPlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => usePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
expect(result.current.data?.oauth_allow_registration).toBe(false);
expect(result.current.data?.google.enabled).toBe(false);
expect(result.current.data?.apple.enabled).toBe(false);
expect(result.current.data?.facebook.enabled).toBe(false);
expect(result.current.data?.linkedin.enabled).toBe(false);
expect(result.current.data?.microsoft.enabled).toBe(false);
expect(result.current.data?.twitter.enabled).toBe(false);
expect(result.current.data?.twitch.enabled).toBe(false);
});
it('handles all providers enabled with credentials', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: true,
client_id: 'google-id',
client_secret: 'google-secret',
},
apple: {
enabled: true,
client_id: 'apple-id',
client_secret: 'apple-secret',
team_id: 'apple-team',
key_id: 'apple-key',
},
facebook: {
enabled: true,
client_id: 'fb-id',
client_secret: 'fb-secret',
},
linkedin: {
enabled: true,
client_id: 'linkedin-id',
client_secret: 'linkedin-secret',
},
microsoft: {
enabled: true,
client_id: 'ms-id',
client_secret: 'ms-secret',
tenant_id: 'ms-tenant',
},
twitter: {
enabled: true,
client_id: 'twitter-id',
client_secret: 'twitter-secret',
},
twitch: {
enabled: true,
client_id: 'twitch-id',
client_secret: 'twitch-secret',
},
};
vi.mocked(platformOAuthApi.getPlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => usePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
expect(result.current.data?.google.enabled).toBe(true);
expect(result.current.data?.apple.enabled).toBe(true);
expect(result.current.data?.apple.team_id).toBe('apple-team');
expect(result.current.data?.apple.key_id).toBe('apple-key');
expect(result.current.data?.facebook.enabled).toBe(true);
expect(result.current.data?.linkedin.enabled).toBe(true);
expect(result.current.data?.microsoft.enabled).toBe(true);
expect(result.current.data?.microsoft.tenant_id).toBe('ms-tenant');
expect(result.current.data?.twitter.enabled).toBe(true);
expect(result.current.data?.twitch.enabled).toBe(true);
});
it('handles API error gracefully', async () => {
const mockError = new Error('Failed to fetch OAuth settings');
vi.mocked(platformOAuthApi.getPlatformOAuthSettings).mockRejectedValue(mockError);
const { result } = renderHook(() => usePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await waitFor(() => {
expect(result.current.isError).toBe(true);
});
expect(result.current.error).toEqual(mockError);
expect(result.current.data).toBeUndefined();
});
it('does not retry on failure', async () => {
vi.mocked(platformOAuthApi.getPlatformOAuthSettings).mockRejectedValue(
new Error('401 Unauthorized')
);
const { result } = renderHook(() => usePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await waitFor(() => {
expect(result.current.isError).toBe(true);
});
// Should be called only once (no retries)
expect(platformOAuthApi.getPlatformOAuthSettings).toHaveBeenCalledTimes(1);
});
it('caches data with 5 minute stale time', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: true,
client_id: 'google-id',
client_secret: 'google-secret',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.getPlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result, rerender } = renderHook(() => usePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
// Rerender should use cached data (within stale time)
rerender();
// Should still only be called once
expect(platformOAuthApi.getPlatformOAuthSettings).toHaveBeenCalledTimes(1);
});
it('handles partial provider configuration', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: true,
client_id: 'google-id',
client_secret: '',
},
apple: {
enabled: true,
client_id: 'apple-id',
client_secret: 'apple-secret',
team_id: '',
key_id: 'apple-key',
},
facebook: {
enabled: false,
client_id: 'fb-id',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.getPlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => usePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
expect(result.current.data?.google.client_id).toBe('google-id');
expect(result.current.data?.google.client_secret).toBe('');
expect(result.current.data?.apple.team_id).toBe('');
expect(result.current.data?.apple.key_id).toBe('apple-key');
});
});
// ============================================================================
// useUpdatePlatformOAuthSettings Mutation Hook
// ============================================================================
describe('useUpdatePlatformOAuthSettings', () => {
it('updates global oauth_allow_registration flag', async () => {
const mockResponse = {
oauth_allow_registration: false,
google: {
enabled: true,
client_id: 'google-id',
client_secret: 'google-secret',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await act(async () => {
await result.current.mutateAsync({
oauth_allow_registration: false,
});
});
expect(platformOAuthApi.updatePlatformOAuthSettings).toHaveBeenCalledWith(
{
oauth_allow_registration: false,
},
expect.anything()
);
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
});
it('updates Google OAuth settings', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: true,
client_id: 'new-google-id',
client_secret: 'new-google-secret',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await act(async () => {
await result.current.mutateAsync({
oauth_google_enabled: true,
oauth_google_client_id: 'new-google-id',
oauth_google_client_secret: 'new-google-secret',
});
});
expect(platformOAuthApi.updatePlatformOAuthSettings).toHaveBeenCalledWith(
{
oauth_google_enabled: true,
oauth_google_client_id: 'new-google-id',
oauth_google_client_secret: 'new-google-secret',
},
expect.anything()
);
});
it('updates Apple OAuth settings with all fields', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: false,
client_id: '',
client_secret: '',
},
apple: {
enabled: true,
client_id: 'apple-id',
client_secret: 'apple-secret',
team_id: 'apple-team',
key_id: 'apple-key',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await act(async () => {
await result.current.mutateAsync({
oauth_apple_enabled: true,
oauth_apple_client_id: 'apple-id',
oauth_apple_client_secret: 'apple-secret',
oauth_apple_team_id: 'apple-team',
oauth_apple_key_id: 'apple-key',
});
});
expect(platformOAuthApi.updatePlatformOAuthSettings).toHaveBeenCalledWith(
{
oauth_apple_enabled: true,
oauth_apple_client_id: 'apple-id',
oauth_apple_client_secret: 'apple-secret',
oauth_apple_team_id: 'apple-team',
oauth_apple_key_id: 'apple-key',
},
expect.anything()
);
});
it('updates Microsoft OAuth settings with tenant_id', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: false,
client_id: '',
client_secret: '',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: true,
client_id: 'ms-id',
client_secret: 'ms-secret',
tenant_id: 'ms-tenant-123',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await act(async () => {
await result.current.mutateAsync({
oauth_microsoft_enabled: true,
oauth_microsoft_client_id: 'ms-id',
oauth_microsoft_client_secret: 'ms-secret',
oauth_microsoft_tenant_id: 'ms-tenant-123',
});
});
expect(platformOAuthApi.updatePlatformOAuthSettings).toHaveBeenCalledWith(
{
oauth_microsoft_enabled: true,
oauth_microsoft_client_id: 'ms-id',
oauth_microsoft_client_secret: 'ms-secret',
oauth_microsoft_tenant_id: 'ms-tenant-123',
},
expect.anything()
);
});
it('updates Facebook OAuth settings', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: false,
client_id: '',
client_secret: '',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: true,
client_id: 'fb-id',
client_secret: 'fb-secret',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await act(async () => {
await result.current.mutateAsync({
oauth_facebook_enabled: true,
oauth_facebook_client_id: 'fb-id',
oauth_facebook_client_secret: 'fb-secret',
});
});
expect(platformOAuthApi.updatePlatformOAuthSettings).toHaveBeenCalledWith(
{
oauth_facebook_enabled: true,
oauth_facebook_client_id: 'fb-id',
oauth_facebook_client_secret: 'fb-secret',
},
expect.anything()
);
});
it('updates LinkedIn OAuth settings', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: false,
client_id: '',
client_secret: '',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: true,
client_id: 'linkedin-id',
client_secret: 'linkedin-secret',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await act(async () => {
await result.current.mutateAsync({
oauth_linkedin_enabled: true,
oauth_linkedin_client_id: 'linkedin-id',
oauth_linkedin_client_secret: 'linkedin-secret',
});
});
expect(platformOAuthApi.updatePlatformOAuthSettings).toHaveBeenCalledWith(
{
oauth_linkedin_enabled: true,
oauth_linkedin_client_id: 'linkedin-id',
oauth_linkedin_client_secret: 'linkedin-secret',
},
expect.anything()
);
});
it('updates Twitter OAuth settings', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: false,
client_id: '',
client_secret: '',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: true,
client_id: 'twitter-id',
client_secret: 'twitter-secret',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await act(async () => {
await result.current.mutateAsync({
oauth_twitter_enabled: true,
oauth_twitter_client_id: 'twitter-id',
oauth_twitter_client_secret: 'twitter-secret',
});
});
expect(platformOAuthApi.updatePlatformOAuthSettings).toHaveBeenCalledWith(
{
oauth_twitter_enabled: true,
oauth_twitter_client_id: 'twitter-id',
oauth_twitter_client_secret: 'twitter-secret',
},
expect.anything()
);
});
it('updates Twitch OAuth settings', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: false,
client_id: '',
client_secret: '',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: true,
client_id: 'twitch-id',
client_secret: 'twitch-secret',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await act(async () => {
await result.current.mutateAsync({
oauth_twitch_enabled: true,
oauth_twitch_client_id: 'twitch-id',
oauth_twitch_client_secret: 'twitch-secret',
});
});
expect(platformOAuthApi.updatePlatformOAuthSettings).toHaveBeenCalledWith(
{
oauth_twitch_enabled: true,
oauth_twitch_client_id: 'twitch-id',
oauth_twitch_client_secret: 'twitch-secret',
},
expect.anything()
);
});
it('updates multiple provider settings at once', async () => {
const mockResponse = {
oauth_allow_registration: false,
google: {
enabled: true,
client_id: 'google-id',
client_secret: 'google-secret',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: true,
client_id: 'fb-id',
client_secret: 'fb-secret',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: true,
client_id: 'ms-id',
client_secret: 'ms-secret',
tenant_id: 'ms-tenant',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await act(async () => {
await result.current.mutateAsync({
oauth_allow_registration: false,
oauth_google_enabled: true,
oauth_google_client_id: 'google-id',
oauth_google_client_secret: 'google-secret',
oauth_facebook_enabled: true,
oauth_facebook_client_id: 'fb-id',
oauth_facebook_client_secret: 'fb-secret',
oauth_microsoft_enabled: true,
oauth_microsoft_client_id: 'ms-id',
oauth_microsoft_client_secret: 'ms-secret',
oauth_microsoft_tenant_id: 'ms-tenant',
});
});
expect(platformOAuthApi.updatePlatformOAuthSettings).toHaveBeenCalledWith(
{
oauth_allow_registration: false,
oauth_google_enabled: true,
oauth_google_client_id: 'google-id',
oauth_google_client_secret: 'google-secret',
oauth_facebook_enabled: true,
oauth_facebook_client_id: 'fb-id',
oauth_facebook_client_secret: 'fb-secret',
oauth_microsoft_enabled: true,
oauth_microsoft_client_id: 'ms-id',
oauth_microsoft_client_secret: 'ms-secret',
oauth_microsoft_tenant_id: 'ms-tenant',
},
expect.anything()
);
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
});
it('disables a provider by setting enabled to false', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: false,
client_id: 'google-id',
client_secret: 'google-secret',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await act(async () => {
await result.current.mutateAsync({
oauth_google_enabled: false,
});
});
expect(platformOAuthApi.updatePlatformOAuthSettings).toHaveBeenCalledWith(
{
oauth_google_enabled: false,
},
expect.anything()
);
});
it('updates query cache on success', async () => {
const mockResponse = {
oauth_allow_registration: true,
google: {
enabled: true,
client_id: 'updated-google-id',
client_secret: 'updated-google-secret',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const queryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false },
},
});
const wrapper = ({ children }: { children: React.ReactNode }) =>
React.createElement(QueryClientProvider, { client: queryClient }, children);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper,
});
await act(async () => {
await result.current.mutateAsync({
oauth_google_enabled: true,
oauth_google_client_id: 'updated-google-id',
oauth_google_client_secret: 'updated-google-secret',
});
});
// Verify cache was updated
const cachedData = queryClient.getQueryData(['platformOAuthSettings']);
expect(cachedData).toEqual(mockResponse);
});
it('handles update error gracefully', async () => {
const mockError = new Error('Failed to update settings');
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockRejectedValue(mockError);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
let caughtError: any = null;
await act(async () => {
try {
await result.current.mutateAsync({
oauth_google_enabled: true,
});
} catch (error) {
caughtError = error;
}
});
expect(caughtError).toEqual(mockError);
await waitFor(() => {
expect(result.current.isError).toBe(true);
});
expect(result.current.error).toEqual(mockError);
});
it('handles validation error from backend', async () => {
const mockError = new Error('Invalid client_id format');
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockRejectedValue(mockError);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
let caughtError: any = null;
await act(async () => {
try {
await result.current.mutateAsync({
oauth_google_client_id: 'invalid-format',
});
} catch (error) {
caughtError = error;
}
});
expect(caughtError).toEqual(mockError);
});
it('handles partial update with only one field', async () => {
const mockResponse = {
oauth_allow_registration: false,
google: {
enabled: true,
client_id: 'google-id',
client_secret: 'google-secret',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(mockResponse);
const { result } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper: createWrapper(),
});
await act(async () => {
await result.current.mutateAsync({
oauth_allow_registration: false,
});
});
expect(platformOAuthApi.updatePlatformOAuthSettings).toHaveBeenCalledWith(
{
oauth_allow_registration: false,
},
expect.anything()
);
await waitFor(() => {
expect(result.current.isSuccess).toBe(true);
});
expect(result.current.data?.oauth_allow_registration).toBe(false);
});
});
// ============================================================================
// Integration Tests
// ============================================================================
describe('integration tests', () => {
it('fetches settings then updates them', async () => {
const initialResponse = {
oauth_allow_registration: true,
google: {
enabled: false,
client_id: '',
client_secret: '',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
const updatedResponse = {
oauth_allow_registration: true,
google: {
enabled: true,
client_id: 'new-google-id',
client_secret: 'new-google-secret',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: true,
client_id: 'new-fb-id',
client_secret: 'new-fb-secret',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
vi.mocked(platformOAuthApi.getPlatformOAuthSettings).mockResolvedValue(initialResponse);
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(updatedResponse);
const queryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false },
},
});
const wrapper = ({ children }: { children: React.ReactNode }) =>
React.createElement(QueryClientProvider, { client: queryClient }, children);
// Fetch initial settings
const { result: fetchResult } = renderHook(() => usePlatformOAuthSettings(), {
wrapper,
});
await waitFor(() => {
expect(fetchResult.current.isSuccess).toBe(true);
});
expect(fetchResult.current.data?.google.enabled).toBe(false);
expect(fetchResult.current.data?.facebook.enabled).toBe(false);
// Update settings
const { result: updateResult } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper,
});
await act(async () => {
await updateResult.current.mutateAsync({
oauth_google_enabled: true,
oauth_google_client_id: 'new-google-id',
oauth_google_client_secret: 'new-google-secret',
oauth_facebook_enabled: true,
oauth_facebook_client_id: 'new-fb-id',
oauth_facebook_client_secret: 'new-fb-secret',
});
});
// Verify cache was updated
const cachedData = queryClient.getQueryData(['platformOAuthSettings']);
expect(cachedData).toEqual(updatedResponse);
});
it('enables all providers in sequence', async () => {
const initialResponse = {
oauth_allow_registration: true,
google: {
enabled: false,
client_id: '',
client_secret: '',
},
apple: {
enabled: false,
client_id: '',
client_secret: '',
team_id: '',
key_id: '',
},
facebook: {
enabled: false,
client_id: '',
client_secret: '',
},
linkedin: {
enabled: false,
client_id: '',
client_secret: '',
},
microsoft: {
enabled: false,
client_id: '',
client_secret: '',
tenant_id: '',
},
twitter: {
enabled: false,
client_id: '',
client_secret: '',
},
twitch: {
enabled: false,
client_id: '',
client_secret: '',
},
};
const allEnabledResponse = {
oauth_allow_registration: true,
google: {
enabled: true,
client_id: 'google-id',
client_secret: 'google-secret',
},
apple: {
enabled: true,
client_id: 'apple-id',
client_secret: 'apple-secret',
team_id: 'apple-team',
key_id: 'apple-key',
},
facebook: {
enabled: true,
client_id: 'fb-id',
client_secret: 'fb-secret',
},
linkedin: {
enabled: true,
client_id: 'linkedin-id',
client_secret: 'linkedin-secret',
},
microsoft: {
enabled: true,
client_id: 'ms-id',
client_secret: 'ms-secret',
tenant_id: 'ms-tenant',
},
twitter: {
enabled: true,
client_id: 'twitter-id',
client_secret: 'twitter-secret',
},
twitch: {
enabled: true,
client_id: 'twitch-id',
client_secret: 'twitch-secret',
},
};
vi.mocked(platformOAuthApi.getPlatformOAuthSettings).mockResolvedValue(initialResponse);
vi.mocked(platformOAuthApi.updatePlatformOAuthSettings).mockResolvedValue(allEnabledResponse);
const queryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false },
},
});
const wrapper = ({ children }: { children: React.ReactNode }) =>
React.createElement(QueryClientProvider, { client: queryClient }, children);
// Fetch initial settings
const { result: fetchResult } = renderHook(() => usePlatformOAuthSettings(), {
wrapper,
});
await waitFor(() => {
expect(fetchResult.current.isSuccess).toBe(true);
});
// Update all providers
const { result: updateResult } = renderHook(() => useUpdatePlatformOAuthSettings(), {
wrapper,
});
await act(async () => {
await updateResult.current.mutateAsync({
oauth_google_enabled: true,
oauth_google_client_id: 'google-id',
oauth_google_client_secret: 'google-secret',
oauth_apple_enabled: true,
oauth_apple_client_id: 'apple-id',
oauth_apple_client_secret: 'apple-secret',
oauth_apple_team_id: 'apple-team',
oauth_apple_key_id: 'apple-key',
oauth_facebook_enabled: true,
oauth_facebook_client_id: 'fb-id',
oauth_facebook_client_secret: 'fb-secret',
oauth_linkedin_enabled: true,
oauth_linkedin_client_id: 'linkedin-id',
oauth_linkedin_client_secret: 'linkedin-secret',
oauth_microsoft_enabled: true,
oauth_microsoft_client_id: 'ms-id',
oauth_microsoft_client_secret: 'ms-secret',
oauth_microsoft_tenant_id: 'ms-tenant',
oauth_twitter_enabled: true,
oauth_twitter_client_id: 'twitter-id',
oauth_twitter_client_secret: 'twitter-secret',
oauth_twitch_enabled: true,
oauth_twitch_client_id: 'twitch-id',
oauth_twitch_client_secret: 'twitch-secret',
});
});
// Verify cache reflects all enabled
const cachedData = queryClient.getQueryData(['platformOAuthSettings']);
expect(cachedData).toEqual(allEnabledResponse);
});
});
});