@@ -209,13 +209,73 @@ describe('AuthLogin', () => {
209209 expect ( server . close ) . toHaveBeenCalledTimes ( 1 ) ;
210210 } ) ;
211211
212- it ( 'rejects when the callback omits the authorization code ' , async ( ) => {
212+ it ( 'rejects with guidance when callback returns already_logged_in ' , async ( ) => {
213213 const command = createCommand ( basePort + 3 ) ;
214214 const pendingCode = (
215215 command as unknown as { startServerAndAwaitCode : ( url : string , state : string ) => Promise < string > }
216216 ) . startServerAndAwaitCode ( authUrl , 'expected-state' ) ;
217217 const server = getLatestServer ( ) ;
218218
219+ await flushAsync ( ) ;
220+ const response = sendCallbackThroughStub ( { error : 'already_logged_in' , state : 'expected-state' } ) ;
221+
222+ expect ( response . writeHead ) . toHaveBeenCalledWith ( 400 , { 'Content-Type' : 'text/plain' } ) ;
223+ expect ( response . end ) . toHaveBeenCalledWith (
224+ "You're already signed in. We'll continue for you. Return to the terminal." ,
225+ ) ;
226+ await expect ( pendingCode ) . rejects . toThrow ( `You're already signed in. Run "hd auth login" again to continue.` ) ;
227+ expect ( server . close ) . toHaveBeenCalledTimes ( 1 ) ;
228+ } ) ;
229+
230+ it ( 'rejects when callback returns a generic OAuth error' , async ( ) => {
231+ const command = createCommand ( basePort + 4 ) ;
232+ const pendingCode = (
233+ command as unknown as { startServerAndAwaitCode : ( url : string , state : string ) => Promise < string > }
234+ ) . startServerAndAwaitCode ( authUrl , 'expected-state' ) ;
235+ const server = getLatestServer ( ) ;
236+
237+ await flushAsync ( ) ;
238+ const response = sendCallbackThroughStub ( {
239+ error : 'access_denied' ,
240+ error_description : 'User denied access' ,
241+ state : 'expected-state' ,
242+ } ) ;
243+
244+ expect ( response . writeHead ) . toHaveBeenCalledWith ( 400 , { 'Content-Type' : 'text/plain' } ) ;
245+ expect ( response . end ) . toHaveBeenCalledWith ( "We couldn't complete sign-in. Return to the terminal and try again." ) ;
246+ await expect ( pendingCode ) . rejects . toThrow ( `We couldn't complete sign-in. Please run "hd auth login" again.` ) ;
247+ expect ( server . close ) . toHaveBeenCalledTimes ( 1 ) ;
248+ } ) ;
249+
250+ it ( 'rejects with guidance when callback returns different_user_authenticated' , async ( ) => {
251+ const command = createCommand ( basePort + 5 ) ;
252+ const pendingCode = (
253+ command as unknown as { startServerAndAwaitCode : ( url : string , state : string ) => Promise < string > }
254+ ) . startServerAndAwaitCode ( authUrl , 'expected-state' ) ;
255+ const server = getLatestServer ( ) ;
256+
257+ await flushAsync ( ) ;
258+ const response = sendCallbackThroughStub ( { error : 'different_user_authenticated' , state : 'expected-state' } ) ;
259+
260+ expect ( response . writeHead ) . toHaveBeenCalledWith ( 400 , { 'Content-Type' : 'text/plain' } ) ;
261+ expect ( response . end ) . toHaveBeenCalledWith (
262+ "You're signed in with a different account than this sign-in attempt. Return to the terminal." ,
263+ ) ;
264+ await expect ( pendingCode ) . rejects . toThrow (
265+ `You're signed in with a different account than this sign-in attempt. ` +
266+ `Choose another account, or reset this sign-in session and try again. ` +
267+ `If needed, run "hd auth logout" and then "hd auth login".` ,
268+ ) ;
269+ expect ( server . close ) . toHaveBeenCalledTimes ( 1 ) ;
270+ } ) ;
271+
272+ it ( 'rejects when the callback omits the authorization code' , async ( ) => {
273+ const command = createCommand ( basePort + 6 ) ;
274+ const pendingCode = (
275+ command as unknown as { startServerAndAwaitCode : ( url : string , state : string ) => Promise < string > }
276+ ) . startServerAndAwaitCode ( authUrl , 'expected-state' ) ;
277+ const server = getLatestServer ( ) ;
278+
219279 await flushAsync ( ) ;
220280 sendCallbackThroughStub ( { state : 'expected-state' } ) ;
221281
@@ -224,7 +284,7 @@ describe('AuthLogin', () => {
224284 } ) ;
225285
226286 it ( 'rejects when the callback URL is invalid' , async ( ) => {
227- const command = createCommand ( basePort + 4 ) ;
287+ const command = createCommand ( basePort + 7 ) ;
228288 const pendingCode = (
229289 command as unknown as { startServerAndAwaitCode : ( url : string , state : string ) => Promise < string > }
230290 ) . startServerAndAwaitCode ( authUrl , 'expected-state' ) ;
@@ -240,7 +300,7 @@ describe('AuthLogin', () => {
240300 } ) ;
241301
242302 it ( 'returns a 400 response when the incoming request is missing a URL' , async ( ) => {
243- const command = createCommand ( basePort + 4 ) ;
303+ const command = createCommand ( basePort + 8 ) ;
244304 const pendingCode = (
245305 command as unknown as { startServerAndAwaitCode : ( url : string , state : string ) => Promise < string > }
246306 ) . startServerAndAwaitCode ( authUrl , 'expected-state' ) ;
@@ -259,7 +319,7 @@ describe('AuthLogin', () => {
259319 } ) ;
260320
261321 it ( 'responds with not found for unrelated paths' , async ( ) => {
262- const command = createCommand ( basePort + 5 ) ;
322+ const command = createCommand ( basePort + 9 ) ;
263323 const pendingCode = (
264324 command as unknown as { startServerAndAwaitCode : ( url : string , state : string ) => Promise < string > }
265325 ) . startServerAndAwaitCode ( authUrl , 'expected-state' ) ;
@@ -278,7 +338,7 @@ describe('AuthLogin', () => {
278338 } ) ;
279339
280340 it ( 'rejects when the local HTTP server emits an error' , async ( ) => {
281- const command = createCommand ( basePort + 6 ) ;
341+ const command = createCommand ( basePort + 10 ) ;
282342 const pendingCode = (
283343 command as unknown as { startServerAndAwaitCode : ( url : string , state : string ) => Promise < string > }
284344 ) . startServerAndAwaitCode ( authUrl , 'expected-state' ) ;
@@ -294,7 +354,7 @@ describe('AuthLogin', () => {
294354
295355 it ( 'warns and allows manual navigation when browser launch fails' , async ( ) => {
296356 openMock . mockRejectedValueOnce ( new Error ( 'browser unavailable' ) ) ;
297- const command = createCommand ( basePort + 7 ) ;
357+ const command = createCommand ( basePort + 11 ) ;
298358 const warnSpy = vi
299359 . spyOn ( command as unknown as { warn : ( ...args : unknown [ ] ) => unknown } , 'warn' )
300360 . mockImplementation ( ( ) => { } ) ;
@@ -319,7 +379,7 @@ describe('AuthLogin', () => {
319379 } ) ;
320380
321381 it ( 'deduplicates shutdown when callback success and server error race' , async ( ) => {
322- const command = createCommand ( basePort + 8 ) ;
382+ const command = createCommand ( basePort + 12 ) ;
323383 const state = 'expected-state' ;
324384 const pendingCode = (
325385 command as unknown as { startServerAndAwaitCode : ( url : string , state : string ) => Promise < string > }
0 commit comments