UNPKG

@rsweeten/dropbox-sync

Version:

Reusable Dropbox synchronization module with framework adapters

180 lines (179 loc) 7.88 kB
import { useNextDropboxSync, getCredentialsFromCookies, handleOAuthCallback, createNextDropboxApiHandlers, } from '../next'; import { createDropboxSyncClient } from '../../core/client'; import { cookies } from 'next/headers'; import { NextResponse } from 'next/server'; // Mock dependencies jest.mock('../../core/client'); jest.mock('next/headers'); jest.mock('next/server'); describe('Next.js adapter', () => { beforeEach(() => { jest.clearAllMocks(); // Mock process.env process.env.DROPBOX_APP_KEY = 'test-app-key'; process.env.DROPBOX_APP_SECRET = 'test-app-secret'; process.env.NEXT_PUBLIC_APP_URL = 'https://example.com'; }); describe('useNextDropboxSync', () => { it('should create a Dropbox sync client with provided credentials', () => { const mockCredentials = { clientId: 'custom-client-id', clientSecret: 'custom-client-secret', }; createDropboxSyncClient.mockReturnValue({ mock: 'client', }); const result = useNextDropboxSync(mockCredentials); expect(createDropboxSyncClient).toHaveBeenCalledWith(mockCredentials); expect(result).toEqual({ mock: 'client' }); }); }); describe('getCredentialsFromCookies', () => { it('should get credentials from cookies', async () => { const mockCookieStore = { get: jest.fn((name) => { if (name === 'dropbox_access_token') return { value: 'test-access-token' }; if (name === 'dropbox_refresh_token') return { value: 'test-refresh-token' }; return null; }), }; cookies.mockResolvedValue(mockCookieStore); const credentials = await getCredentialsFromCookies(); expect(cookies).toHaveBeenCalled(); expect(credentials).toEqual({ clientId: 'test-app-key', clientSecret: 'test-app-secret', accessToken: 'test-access-token', refreshToken: 'test-refresh-token', }); }); it('should handle missing cookie values', async () => { const mockCookieStore = { get: jest.fn().mockReturnValue(null), }; cookies.mockResolvedValue(mockCookieStore); const credentials = await getCredentialsFromCookies(); expect(credentials).toEqual({ clientId: 'test-app-key', clientSecret: 'test-app-secret', accessToken: undefined, refreshToken: undefined, }); }); }); describe('handleOAuthCallback', () => { it('should handle successful OAuth callback', async () => { // Mock URL with auth code const mockRequest = { url: 'https://example.com/callback?code=test-auth-code', }; global.URL = jest.fn().mockImplementation(() => { return { searchParams: { get: jest.fn().mockReturnValue('test-auth-code'), }, }; }); // Mock Dropbox client const mockClient = { auth: { exchangeCodeForToken: jest.fn().mockResolvedValue({ accessToken: 'new-access-token', refreshToken: 'new-refresh-token', expiresAt: Date.now() + 14400 * 1000, }), }, }; createDropboxSyncClient.mockReturnValue(mockClient); // Mock NextResponse const mockResponseCookies = { set: jest.fn(), }; const mockResponse = { cookies: mockResponseCookies, }; NextResponse.redirect.mockReturnValue(mockResponse); await handleOAuthCallback(mockRequest); expect(createDropboxSyncClient).toHaveBeenCalled(); expect(mockClient.auth.exchangeCodeForToken).toHaveBeenCalledWith('test-auth-code', expect.any(String)); expect(NextResponse.redirect).toHaveBeenCalled(); expect(mockResponseCookies.set).toHaveBeenCalledTimes(3); // Access, refresh, and connected cookies }); it('should redirect to error page if code is missing', async () => { const mockRequest = { url: 'https://example.com/callback', }; global.URL = jest.fn().mockImplementation(() => { return { searchParams: { get: jest.fn().mockReturnValue(null), }, }; }); // Create a proper URL string for the mock response const errorUrl = 'https://example.com/auth/error'; NextResponse.redirect.mockReturnValue({ url: errorUrl, }); const result = await handleOAuthCallback(mockRequest); // Now we'll check that the redirect was called, and the result contains our URL expect(NextResponse.redirect).toHaveBeenCalled(); expect(result.url).toBe(errorUrl); }); }); describe('createNextDropboxApiHandlers', () => { it('should create API handlers with necessary methods', () => { const handlers = createNextDropboxApiHandlers(); expect(handlers).toHaveProperty('status'); expect(handlers).toHaveProperty('oauthStart'); expect(handlers).toHaveProperty('logout'); }); it('should check status from cookies', async () => { const mockCookieStore = { get: jest.fn().mockReturnValue({ value: 'test-token' }), }; cookies.mockResolvedValue(mockCookieStore); NextResponse.json.mockReturnValue({ json: 'response', }); const handlers = createNextDropboxApiHandlers(); const response = await handlers.status(); expect(cookies).toHaveBeenCalled(); expect(mockCookieStore.get).toHaveBeenCalledWith('dropbox_access_token'); expect(NextResponse.json).toHaveBeenCalledWith({ connected: true }); }); it('should start OAuth flow', async () => { const mockClient = { auth: { getAuthUrl: jest .fn() .mockResolvedValue('https://dropbox.com/oauth'), }, }; createDropboxSyncClient.mockReturnValue(mockClient); NextResponse.redirect.mockReturnValue({ redirect: 'response', }); const handlers = createNextDropboxApiHandlers(); const response = await handlers.oauthStart(); expect(createDropboxSyncClient).toHaveBeenCalled(); expect(mockClient.auth.getAuthUrl).toHaveBeenCalled(); expect(NextResponse.redirect).toHaveBeenCalledWith('https://dropbox.com/oauth'); }); it('should handle logout', async () => { const mockResponseCookies = { delete: jest.fn(), }; const mockResponse = { cookies: mockResponseCookies, }; NextResponse.json.mockReturnValue(mockResponse); const handlers = createNextDropboxApiHandlers(); const response = await handlers.logout(); expect(NextResponse.json).toHaveBeenCalledWith({ success: true }); expect(mockResponseCookies.delete).toHaveBeenCalledTimes(3); // Should delete three cookies }); }); });