@@ -20,7 +20,6 @@ import { RequestError } from '@octokit/request-error';
2020
2121import type { MockedFunction } from 'vitest' ;
2222
23- import { simulateDeviceFlow } from '../../__helpers__/auth-helpers' ;
2423import { mockGitHubCloudAccount } from '../../__mocks__/account-mocks' ;
2524import { mockAuth } from '../../__mocks__/state-mocks' ;
2625import { mockRawUser } from '../api/__mocks__/response-mocks' ;
@@ -81,127 +80,91 @@ describe('renderer/utils/auth/utils.ts', () => {
8180 vi . clearAllMocks ( ) ;
8281 } ) ;
8382
84- describe ( 'device OAuth orchestration (test helper)' , ( ) => {
85- it ( 'should authenticate using device flow for GitHub app' , async ( ) => {
86- createDeviceCodeMock . mockResolvedValueOnce ( {
87- data : {
88- device_code : 'device-code' ,
89- user_code : 'user-code' ,
90- verification_uri : 'https://github.com/login/device' ,
91- expires_in : 900 ,
92- interval : 5 ,
93- } ,
94- } as unknown as Awaited < ReturnType < typeof createDeviceCode > > ) ;
95-
96- exchangeDeviceCodeMock . mockResolvedValueOnce ( {
97- authentication : {
98- token : 'device-token' ,
99- } ,
100- } as unknown as Awaited < ReturnType < typeof exchangeDeviceCode > > ) ;
101-
102- const token = await simulateDeviceFlow ( ) ;
103-
104- expect ( createDeviceCodeMock ) . toHaveBeenCalledWith ( {
105- clientType : 'oauth-app' ,
106- clientId : 'FAKE_CLIENT_ID_123' ,
107- scopes : getRecommendedScopeNames ( ) ,
108- request : expect . any ( Function ) ,
109- } ) ;
83+ describe ( 'Gitify GitHub OAuth - Device Code Flow' , ( ) => {
84+ describe ( 'startGitHubDeviceFlow' , ( ) => {
85+ it ( 'should request a device code and return a session' , async ( ) => {
86+ createDeviceCodeMock . mockResolvedValueOnce ( {
87+ data : {
88+ device_code : 'device-code-xyz' ,
89+ user_code : 'user-code-xyz' ,
90+ verification_uri : 'https://github.com/login/device' ,
91+ expires_in : 600 ,
92+ interval : 5 ,
93+ } ,
94+ } as unknown as Awaited < ReturnType < typeof createDeviceCode > > ) ;
11095
111- expect ( exchangeDeviceCodeMock ) . toHaveBeenCalledWith ( {
112- clientType : 'oauth-app' ,
113- clientId : 'FAKE_CLIENT_ID_123' ,
114- code : 'device-code' ,
115- request : expect . any ( Function ) ,
116- } ) ;
96+ const session = await authUtils . startGitHubDeviceFlow ( ) ;
11797
118- expect ( token ) . toBe ( 'device-token' ) ;
119- } ) ;
120- } ) ;
98+ expect ( createDeviceCodeMock ) . toHaveBeenCalledWith ( {
99+ clientType : 'oauth-app' ,
100+ clientId : 'FAKE_CLIENT_ID_123' ,
101+ scopes : getRecommendedScopeNames ( ) ,
102+ request : expect . any ( Function ) ,
103+ } ) ;
121104
122- describe ( 'startGitHubDeviceFlow' , ( ) => {
123- it ( 'should request a device code and return a session' , async ( ) => {
124- createDeviceCodeMock . mockResolvedValueOnce ( {
125- data : {
126- device_code : 'device-code-xyz' ,
127- user_code : 'user-code-xyz' ,
128- verification_uri : 'https://github.com/login/device' ,
129- expires_in : 600 ,
130- interval : 5 ,
131- } ,
132- } as unknown as Awaited < ReturnType < typeof createDeviceCode > > ) ;
133-
134- const session = await authUtils . startGitHubDeviceFlow ( ) ;
135-
136- expect ( createDeviceCodeMock ) . toHaveBeenCalledWith ( {
137- clientType : 'oauth-app' ,
138- clientId : 'FAKE_CLIENT_ID_123' ,
139- scopes : getRecommendedScopeNames ( ) ,
140- request : expect . any ( Function ) ,
105+ expect ( session . deviceCode ) . toBe ( 'device-code-xyz' ) ;
106+ expect ( session . userCode ) . toBe ( 'user-code-xyz' ) ;
107+ expect ( session . verificationUri ) . toBe ( 'https://github.com/login/device' ) ;
108+ expect ( session . intervalSeconds ) . toBe ( 5 ) ;
109+ expect ( session . expiresAt ) . toBeGreaterThan ( Date . now ( ) ) ;
141110 } ) ;
142-
143- expect ( session . deviceCode ) . toBe ( 'device-code-xyz' ) ;
144- expect ( session . userCode ) . toBe ( 'user-code-xyz' ) ;
145- expect ( session . verificationUri ) . toBe ( 'https://github.com/login/device' ) ;
146- expect ( session . intervalSeconds ) . toBe ( 5 ) ;
147- expect ( session . expiresAt ) . toBeGreaterThan ( Date . now ( ) ) ;
148111 } ) ;
149- } ) ;
150-
151- describe ( 'pollGitHubDeviceFlow' , ( ) => {
152- const baseSession = {
153- hostname : 'github.com' ,
154- clientId : 'FAKE_CLIENT_ID_123' ,
155- deviceCode : 'device-code' ,
156- userCode : 'user-code' ,
157- verificationUri : 'https://github.com/login/device' ,
158- intervalSeconds : 5 ,
159- expiresAt : Date . now ( ) + 10000 ,
160- } as const ;
161-
162- it ( 'returns token on successful exchange' , async ( ) => {
163- exchangeDeviceCodeMock . mockResolvedValueOnce ( {
164- authentication : { token : 'device-token-xyz' } ,
165- } as unknown as Awaited < ReturnType < typeof exchangeDeviceCode > > ) ;
166-
167- const token = await authUtils . pollGitHubDeviceFlow (
168- baseSession as DeviceFlowSession ,
169- ) ;
170112
171- expect ( exchangeDeviceCodeMock ) . toHaveBeenCalledWith ( {
172- clientType : 'oauth-app' ,
113+ describe ( 'pollGitHubDeviceFlow' , ( ) => {
114+ const baseSession = {
115+ hostname : 'github.com' ,
173116 clientId : 'FAKE_CLIENT_ID_123' ,
174- code : 'device-code' ,
175- request : expect . any ( Function ) ,
176- } ) ;
117+ deviceCode : 'device-code' ,
118+ userCode : 'user-code' ,
119+ verificationUri : 'https://github.com/login/device' ,
120+ intervalSeconds : 5 ,
121+ expiresAt : Date . now ( ) + 10000 ,
122+ } as const ;
123+
124+ it ( 'returns token on successful exchange' , async ( ) => {
125+ exchangeDeviceCodeMock . mockResolvedValueOnce ( {
126+ authentication : { token : 'device-token-xyz' } ,
127+ } as unknown as Awaited < ReturnType < typeof exchangeDeviceCode > > ) ;
128+
129+ const token = await authUtils . pollGitHubDeviceFlow (
130+ baseSession as DeviceFlowSession ,
131+ ) ;
177132
178- expect ( token ) . toBe ( 'device-token-xyz' ) ;
179- } ) ;
133+ expect ( exchangeDeviceCodeMock ) . toHaveBeenCalledWith ( {
134+ clientType : 'oauth-app' ,
135+ clientId : 'FAKE_CLIENT_ID_123' ,
136+ code : 'device-code' ,
137+ request : expect . any ( Function ) ,
138+ } ) ;
180139
181- it ( 'returns null when authorization is pending or slow_down' , async ( ) => {
182- const pendingErr = Object . create ( RequestError . prototype ) ;
183- pendingErr . response = { data : { error : 'authorization_pending' } } ;
140+ expect ( token ) . toBe ( 'device-token-xyz' ) ;
141+ } ) ;
184142
185- exchangeDeviceCodeMock . mockRejectedValueOnce ( pendingErr ) ;
143+ it ( 'returns null when authorization is pending or slow_down' , async ( ) => {
144+ const pendingErr = Object . create ( RequestError . prototype ) ;
145+ pendingErr . response = { data : { error : 'authorization_pending' } } ;
186146
187- const token = await authUtils . pollGitHubDeviceFlow (
188- baseSession as DeviceFlowSession ,
189- ) ;
147+ exchangeDeviceCodeMock . mockRejectedValueOnce ( pendingErr ) ;
190148
191- expect ( token ) . toBeNull ( ) ;
192- } ) ;
149+ const token = await authUtils . pollGitHubDeviceFlow (
150+ baseSession as DeviceFlowSession ,
151+ ) ;
193152
194- it ( 'throws on other errors' , async ( ) => {
195- const otherErr = new Error ( 'boom' ) ;
153+ expect ( token ) . toBeNull ( ) ;
154+ } ) ;
196155
197- exchangeDeviceCodeMock . mockRejectedValueOnce ( otherErr ) ;
156+ it ( 'throws on other errors' , async ( ) => {
157+ const otherErr = new Error ( 'boom' ) ;
198158
199- await expect (
200- async ( ) =>
201- await authUtils . pollGitHubDeviceFlow (
202- baseSession as DeviceFlowSession ,
203- ) ,
204- ) . rejects . toThrow ( 'boom' ) ;
159+ exchangeDeviceCodeMock . mockRejectedValueOnce ( otherErr ) ;
160+
161+ await expect (
162+ async ( ) =>
163+ await authUtils . pollGitHubDeviceFlow (
164+ baseSession as DeviceFlowSession ,
165+ ) ,
166+ ) . rejects . toThrow ( 'boom' ) ;
167+ } ) ;
205168 } ) ;
206169 } ) ;
207170
0 commit comments