@@ -34,6 +34,24 @@ const encodeOrg = Schema.encodeSync(Org)
3434
3535const org = ( id : string , name : string ) => encodeOrg ( new Org ( { id : OrgID . make ( id ) , name } ) )
3636
37+ const login = ( ) =>
38+ new Login ( {
39+ code : DeviceCode . make ( "device-code" ) ,
40+ user : UserCode . make ( "user-code" ) ,
41+ url : "https://one.example.com/verify" ,
42+ server : "https://one.example.com" ,
43+ expiry : Duration . seconds ( 600 ) ,
44+ interval : Duration . seconds ( 5 ) ,
45+ } )
46+
47+ const deviceTokenClient = ( body : unknown , status = 400 ) =>
48+ HttpClient . make ( ( req ) =>
49+ Effect . succeed ( req . url === "https://one.example.com/auth/device/token" ? json ( req , body , status ) : json ( req , { } , 404 ) ) ,
50+ )
51+
52+ const poll = ( body : unknown , status = 400 ) =>
53+ AccountEffect . Service . use ( ( s ) => s . poll ( login ( ) ) ) . pipe ( Effect . provide ( live ( deviceTokenClient ( body , status ) ) ) )
54+
3755it . effect ( "orgsByAccount groups orgs per account" , ( ) =>
3856 Effect . gen ( function * ( ) {
3957 yield * AccountRepo . use ( ( r ) =>
@@ -172,15 +190,6 @@ it.effect("config sends the selected org header", () =>
172190
173191it . effect ( "poll stores the account and first org on success" , ( ) =>
174192 Effect . gen ( function * ( ) {
175- const login = new Login ( {
176- code : DeviceCode . make ( "device-code" ) ,
177- user : UserCode . make ( "user-code" ) ,
178- url : "https://one.example.com/verify" ,
179- server : "https://one.example.com" ,
180- expiry : Duration . seconds ( 600 ) ,
181- interval : Duration . seconds ( 5 ) ,
182- } )
183-
184193 const client = HttpClient . make ( ( req ) =>
185194 Effect . succeed (
186195 req . url === "https://one.example.com/auth/device/token"
@@ -198,7 +207,7 @@ it.effect("poll stores the account and first org on success", () =>
198207 ) ,
199208 )
200209
201- const res = yield * AccountEffect . Service . use ( ( s ) => s . poll ( login ) ) . pipe ( Effect . provide ( live ( client ) ) )
210+ const res = yield * AccountEffect . Service . use ( ( s ) => s . poll ( login ( ) ) ) . pipe ( Effect . provide ( live ( client ) ) )
202211
203212 expect ( res . _tag ) . toBe ( "PollSuccess" )
204213 if ( res . _tag === "PollSuccess" ) {
@@ -215,3 +224,59 @@ it.effect("poll stores the account and first org on success", () =>
215224 )
216225 } ) ,
217226)
227+
228+ for ( const [ name , body , expectedTag ] of [
229+ [
230+ "pending" ,
231+ {
232+ error : "authorization_pending" ,
233+ error_description : "The authorization request is still pending" ,
234+ } ,
235+ "PollPending" ,
236+ ] ,
237+ [
238+ "slow" ,
239+ {
240+ error : "slow_down" ,
241+ error_description : "Polling too frequently, please slow down" ,
242+ } ,
243+ "PollSlow" ,
244+ ] ,
245+ [
246+ "denied" ,
247+ {
248+ error : "access_denied" ,
249+ error_description : "The authorization request was denied" ,
250+ } ,
251+ "PollDenied" ,
252+ ] ,
253+ [
254+ "expired" ,
255+ {
256+ error : "expired_token" ,
257+ error_description : "The device code has expired" ,
258+ } ,
259+ "PollExpired" ,
260+ ] ,
261+ ] as const ) {
262+ it . effect ( `poll returns ${ name } for ${ body . error } ` , ( ) =>
263+ Effect . gen ( function * ( ) {
264+ const result = yield * poll ( body )
265+ expect ( result . _tag ) . toBe ( expectedTag )
266+ } ) ,
267+ )
268+ }
269+
270+ it . effect ( "poll returns poll error for other OAuth errors" , ( ) =>
271+ Effect . gen ( function * ( ) {
272+ const result = yield * poll ( {
273+ error : "server_error" ,
274+ error_description : "An unexpected error occurred" ,
275+ } )
276+
277+ expect ( result . _tag ) . toBe ( "PollError" )
278+ if ( result . _tag === "PollError" ) {
279+ expect ( String ( result . cause ) ) . toContain ( "server_error" )
280+ }
281+ } ) ,
282+ )
0 commit comments