@@ -122,6 +122,46 @@ describe('kimi login', () => {
122122 expect ( exitSpy ) . toHaveBeenCalledWith ( 0 ) ;
123123 } ) ;
124124
125+ it ( 'still prints device code prompt when opening the browser fails' , async ( ) => {
126+ vi . mocked ( openUrl ) . mockImplementation ( ( ) => {
127+ throw new Error ( 'no browser' ) ;
128+ } ) ;
129+ mockLogin . mockImplementation (
130+ async (
131+ _providerName : string | undefined ,
132+ options : {
133+ onDeviceCode ?: ( data : {
134+ userCode : string ;
135+ verificationUri : string ;
136+ verificationUriComplete : string ;
137+ expiresIn : number | null ;
138+ } ) => void | Promise < void > ;
139+ } ,
140+ ) => {
141+ await options . onDeviceCode ?.( {
142+ userCode : 'ABCD-EFGH' ,
143+ verificationUri : 'https://example.com/v' ,
144+ verificationUriComplete : 'https://example.com/v?code=ABCD-EFGH' ,
145+ expiresIn : 600 ,
146+ } ) ;
147+ return { providerName : 'kimi-code' , ok : true } ;
148+ } ,
149+ ) ;
150+
151+ const program = new Command ( 'kimi' ) . exitOverride ( ) ;
152+ registerLoginCommand ( program ) ;
153+
154+ await expect ( program . parseAsync ( [ 'node' , 'kimi' , 'login' ] ) ) . rejects . toThrow ( ExitCalled ) ;
155+
156+ const writtenChunks = stderrSpy . mock . calls . map ( ( call : unknown [ ] ) => String ( call [ 0 ] ) ) ;
157+ expect ( writtenChunks . some ( ( chunk : string ) => chunk . includes ( 'ABCD-EFGH' ) ) ) . toBe ( true ) ;
158+ expect ( writtenChunks . some ( ( chunk : string ) => chunk . includes ( 'https://example.com/v' ) ) ) . toBe (
159+ true ,
160+ ) ;
161+ expect ( openUrl ) . toHaveBeenCalledWith ( 'https://example.com/v?code=ABCD-EFGH' ) ;
162+ expect ( exitSpy ) . toHaveBeenCalledWith ( 0 ) ;
163+ } ) ;
164+
125165 it ( 'exits 1 when auth.login throws' , async ( ) => {
126166 mockLogin . mockRejectedValue ( new Error ( 'boom' ) ) ;
127167
0 commit comments