@@ -71,6 +71,8 @@ describe('login (device code flow)', () => {
7171 deviceCode : 'a' . repeat ( 64 ) ,
7272 userCode : 'BCDF-GHJK' ,
7373 verificationUri : 'https://app.test/auth/device' ,
74+ verificationUriComplete :
75+ 'https://app.test/auth/device?user_code=BCDF-GHJK' ,
7476 expiresIn : 900 ,
7577 interval : 0 ,
7678 } ) ;
@@ -112,6 +114,8 @@ describe('login (device code flow)', () => {
112114 deviceCode : 'a' . repeat ( 64 ) ,
113115 userCode : 'BCDF-GHJK' ,
114116 verificationUri : 'https://app.test/auth/device' ,
117+ verificationUriComplete :
118+ 'https://app.test/auth/device?user_code=BCDF-GHJK' ,
115119 expiresIn : 0 ,
116120 interval : 0 ,
117121 } ) ;
@@ -142,6 +146,8 @@ describe('login (device code flow)', () => {
142146 deviceCode : 'a' . repeat ( 64 ) ,
143147 userCode : 'BCDF-GHJK' ,
144148 verificationUri : 'https://app.test/auth/device' ,
149+ verificationUriComplete :
150+ 'https://app.test/auth/device?user_code=BCDF-GHJK' ,
145151 expiresIn : 900 ,
146152 interval : 0 ,
147153 } ) ;
@@ -178,6 +184,8 @@ describe('login (device code flow)', () => {
178184 deviceCode : 'a' . repeat ( 64 ) ,
179185 userCode : 'BCDF-GHJK' ,
180186 verificationUri : 'https://app.test/auth/device' ,
187+ verificationUriComplete :
188+ 'https://app.test/auth/device?user_code=BCDF-GHJK' ,
181189 expiresIn : 900 ,
182190 interval : 0 ,
183191 } ) ;
@@ -207,4 +215,72 @@ describe('login (device code flow)', () => {
207215 expect ( result . success ) . toBe ( false ) ;
208216 expect ( result . error ) . toContain ( 'Failed to request device code' ) ;
209217 } ) ;
218+
219+ it ( 'opens verificationUriComplete in browser when available' , async ( ) => {
220+ let openedUrl = '' ;
221+ const captureOpen = async ( url : string ) => {
222+ openedUrl = url ;
223+ } ;
224+
225+ const mockFetch = createMockFetch ( ( url ) => {
226+ if ( url . includes ( '/api/auth/device/code' ) ) {
227+ return fakeResponse ( {
228+ deviceCode : 'a' . repeat ( 64 ) ,
229+ userCode : 'BCDF-GHJK' ,
230+ verificationUri : 'https://app.test/auth/device' ,
231+ verificationUriComplete :
232+ 'https://app.test/auth/device?user_code=BCDF-GHJK' ,
233+ expiresIn : 900 ,
234+ interval : 0 ,
235+ } ) ;
236+ }
237+
238+ return fakeResponse ( {
239+ token : 'sk-walkeros-' + 'd' . repeat ( 64 ) ,
240+ email : 'url@example.com' ,
241+ userId : 'user_789' ,
242+ } ) ;
243+ } ) ;
244+
245+ await login ( {
246+ openUrl : captureOpen ,
247+ fetch : mockFetch ,
248+ maxPollAttempts : 10 ,
249+ } ) ;
250+
251+ expect ( openedUrl ) . toBe ( 'https://app.test/auth/device?user_code=BCDF-GHJK' ) ;
252+ } ) ;
253+
254+ it ( 'falls back to verificationUri when verificationUriComplete is missing' , async ( ) => {
255+ let openedUrl = '' ;
256+ const captureOpen = async ( url : string ) => {
257+ openedUrl = url ;
258+ } ;
259+
260+ const mockFetch = createMockFetch ( ( url ) => {
261+ if ( url . includes ( '/api/auth/device/code' ) ) {
262+ return fakeResponse ( {
263+ deviceCode : 'a' . repeat ( 64 ) ,
264+ userCode : 'BCDF-GHJK' ,
265+ verificationUri : 'https://app.test/auth/device' ,
266+ expiresIn : 900 ,
267+ interval : 0 ,
268+ } ) ;
269+ }
270+
271+ return fakeResponse ( {
272+ token : 'sk-walkeros-' + 'e' . repeat ( 64 ) ,
273+ email : 'fallback@example.com' ,
274+ userId : 'user_101' ,
275+ } ) ;
276+ } ) ;
277+
278+ await login ( {
279+ openUrl : captureOpen ,
280+ fetch : mockFetch ,
281+ maxPollAttempts : 10 ,
282+ } ) ;
283+
284+ expect ( openedUrl ) . toBe ( 'https://app.test/auth/device' ) ;
285+ } ) ;
210286} ) ;
0 commit comments