diff --git a/desktop/src/components/settings/ChatGPTOfficialLogin.test.tsx b/desktop/src/components/settings/ChatGPTOfficialLogin.test.tsx index 48f7b93b..d568f080 100644 --- a/desktop/src/components/settings/ChatGPTOfficialLogin.test.tsx +++ b/desktop/src/components/settings/ChatGPTOfficialLogin.test.tsx @@ -90,7 +90,34 @@ describe('ChatGPTOfficialLogin', () => { }) expect(copyTextToClipboardMock).toHaveBeenCalledWith(authorizeUrl) + expect(useHahaOpenAIOAuthStore.getState().error).toBeNull() expect(useHahaOpenAIOAuthStore.getState().isPolling).toBe(true) - consoleErrorSpy.mockRestore() + expect(screen.queryByText(/Unable to open browser/)).not.toBeInTheDocument() + expect(screen.queryByRole('button', { name: 'Copy authorization link' })).not.toBeInTheDocument() + }) + + it('keeps the authorization link available when copy fails', async () => { + const authorizeUrl = 'https://chatgpt.com/oauth/authorize?state=openai-state' + statusMock.mockResolvedValue({ loggedIn: false }) + startMock.mockResolvedValue({ authorizeUrl, state: 'openai-state' }) + shellOpenMock.mockRejectedValue(new Error('shell unavailable')) + copyTextToClipboardMock.mockResolvedValue(false) + vi.spyOn(console, 'error').mockImplementation(() => {}) + + render() + + await screen.findByRole('button', { name: 'Sign in with ChatGPT' }) + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: 'Sign in with ChatGPT' })) + }) + + await act(async () => { + fireEvent.click(screen.getByRole('button', { name: 'Copy authorization link' })) + }) + + expect(copyTextToClipboardMock).toHaveBeenCalledWith(authorizeUrl) + expect(useHahaOpenAIOAuthStore.getState().isPolling).toBe(false) + expect(screen.getByText(/Unable to copy authorization link/)).toBeInTheDocument() + expect(screen.getByRole('button', { name: 'Copy authorization link' })).toBeInTheDocument() }) }) diff --git a/desktop/src/components/settings/ChatGPTOfficialLogin.tsx b/desktop/src/components/settings/ChatGPTOfficialLogin.tsx index c973254f..087596b3 100644 --- a/desktop/src/components/settings/ChatGPTOfficialLogin.tsx +++ b/desktop/src/components/settings/ChatGPTOfficialLogin.tsx @@ -26,7 +26,14 @@ export function ChatGPTOfficialLogin() { return () => stopPolling() }, [fetchStatus, stopPolling]) + useEffect(() => { + if (status?.loggedIn) { + setManualAuthorizeUrl(null) + } + }, [status?.loggedIn]) + const handleLogin = async () => { + setManualAuthorizeUrl(null) try { const { authorizeUrl } = await login() setManualAuthorizeUrl(authorizeUrl) @@ -49,6 +56,7 @@ export function ChatGPTOfficialLogin() { if (!manualAuthorizeUrl) return const copied = await copyTextToClipboard(manualAuthorizeUrl) if (copied) { + setManualAuthorizeUrl(null) useHahaOpenAIOAuthStore.setState({ error: null }) startPolling() return