Skip to content

Commit 41af015

Browse files
authored
refactor: login methods and options (#1158)
* refactor: rename login methods and options * refactor: move to utils/auth package
1 parent f9daa15 commit 41af015

File tree

11 files changed

+394
-148
lines changed

11 files changed

+394
-148
lines changed

src/__mocks__/state-mocks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import {
22
type AuthState,
3-
type EnterpriseAccount,
43
type GitifyUser,
54
type SettingsState,
65
Theme,
76
} from '../types';
7+
import type { EnterpriseAccount } from '../utils/auth/types';
88

99
export const mockEnterpriseAccounts: EnterpriseAccount[] = [
1010
{

src/context/App.test.tsx

Lines changed: 91 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ describe('context/App.tsx', () => {
3535
jest.clearAllMocks();
3636
});
3737

38-
describe('api methods', () => {
39-
const apiRequestAuthMock = jest.spyOn(apiRequests, 'apiRequestAuth');
38+
describe('notification methods', () => {
4039
const getNotificationCountMock = jest.spyOn(
4140
notifications,
4241
'getNotificationCount',
@@ -269,18 +268,31 @@ describe('context/App.tsx', () => {
269268
'github.com',
270269
);
271270
});
271+
});
272+
describe('authentication methods', () => {
273+
const apiRequestAuthMock = jest.spyOn(apiRequests, 'apiRequestAuth');
274+
const fetchNotificationsMock = jest.fn();
272275

273-
it('should call validateToken', async () => {
276+
beforeEach(() => {
277+
(useNotifications as jest.Mock).mockReturnValue({
278+
fetchNotifications: fetchNotificationsMock,
279+
});
280+
});
281+
282+
it('should call loginWithPersonalAccessToken', async () => {
274283
apiRequestAuthMock.mockResolvedValueOnce(null);
275284

276285
const TestComponent = () => {
277-
const { validateToken } = useContext(AppContext);
286+
const { loginWithPersonalAccessToken } = useContext(AppContext);
278287

279288
return (
280289
<button
281290
type="button"
282291
onClick={() =>
283-
validateToken({ hostname: 'github.com', token: '123-456' })
292+
loginWithPersonalAccessToken({
293+
hostname: 'github.com',
294+
token: '123-456',
295+
})
284296
}
285297
>
286298
Test Case
@@ -332,90 +344,92 @@ describe('context/App.tsx', () => {
332344
expect(clearStateMock).toHaveBeenCalledTimes(1);
333345
});
334346

335-
it('should call updateSetting', async () => {
336-
const saveStateMock = jest
337-
.spyOn(storage, 'saveState')
338-
.mockImplementation(jest.fn());
347+
describe('settings methods', () => {
348+
it('should call updateSetting', async () => {
349+
const saveStateMock = jest
350+
.spyOn(storage, 'saveState')
351+
.mockImplementation(jest.fn());
339352

340-
const TestComponent = () => {
341-
const { updateSetting } = useContext(AppContext);
353+
const TestComponent = () => {
354+
const { updateSetting } = useContext(AppContext);
342355

343-
return (
344-
<button
345-
type="button"
346-
onClick={() => updateSetting('participating', true)}
347-
>
348-
Test Case
349-
</button>
350-
);
351-
};
356+
return (
357+
<button
358+
type="button"
359+
onClick={() => updateSetting('participating', true)}
360+
>
361+
Test Case
362+
</button>
363+
);
364+
};
352365

353-
const { getByText } = customRender(<TestComponent />);
366+
const { getByText } = customRender(<TestComponent />);
354367

355-
act(() => {
356-
fireEvent.click(getByText('Test Case'));
357-
});
368+
act(() => {
369+
fireEvent.click(getByText('Test Case'));
370+
});
358371

359-
expect(saveStateMock).toHaveBeenCalledWith({
360-
auth: { enterpriseAccounts: [], token: null, user: null },
361-
settings: {
362-
participating: true,
363-
playSound: true,
364-
showNotifications: true,
365-
showBots: true,
366-
showNotificationsCountInTray: false,
367-
openAtStartup: false,
368-
theme: 'SYSTEM',
369-
detailedNotifications: true,
370-
markAsDoneOnOpen: false,
371-
showAccountHostname: false,
372-
delayNotificationState: false,
373-
},
372+
expect(saveStateMock).toHaveBeenCalledWith({
373+
auth: { enterpriseAccounts: [], token: null, user: null },
374+
settings: {
375+
participating: true,
376+
playSound: true,
377+
showNotifications: true,
378+
showBots: true,
379+
showNotificationsCountInTray: false,
380+
openAtStartup: false,
381+
theme: 'SYSTEM',
382+
detailedNotifications: true,
383+
markAsDoneOnOpen: false,
384+
showAccountHostname: false,
385+
delayNotificationState: false,
386+
},
387+
});
374388
});
375-
});
376389

377-
it('should call updateSetting and set auto launch(openAtStartup)', async () => {
378-
const setAutoLaunchMock = jest.spyOn(comms, 'setAutoLaunch');
379-
const saveStateMock = jest
380-
.spyOn(storage, 'saveState')
381-
.mockImplementation(jest.fn());
390+
it('should call updateSetting and set auto launch(openAtStartup)', async () => {
391+
const setAutoLaunchMock = jest.spyOn(comms, 'setAutoLaunch');
392+
const saveStateMock = jest
393+
.spyOn(storage, 'saveState')
394+
.mockImplementation(jest.fn());
382395

383-
const TestComponent = () => {
384-
const { updateSetting } = useContext(AppContext);
396+
const TestComponent = () => {
397+
const { updateSetting } = useContext(AppContext);
385398

386-
return (
387-
<button
388-
type="button"
389-
onClick={() => updateSetting('openAtStartup', true)}
390-
>
391-
Test Case
392-
</button>
393-
);
394-
};
399+
return (
400+
<button
401+
type="button"
402+
onClick={() => updateSetting('openAtStartup', true)}
403+
>
404+
Test Case
405+
</button>
406+
);
407+
};
395408

396-
const { getByText } = customRender(<TestComponent />);
409+
const { getByText } = customRender(<TestComponent />);
397410

398-
act(() => {
399-
fireEvent.click(getByText('Test Case'));
400-
});
411+
act(() => {
412+
fireEvent.click(getByText('Test Case'));
413+
});
401414

402-
expect(setAutoLaunchMock).toHaveBeenCalledWith(true);
403-
404-
expect(saveStateMock).toHaveBeenCalledWith({
405-
auth: { enterpriseAccounts: [], token: null, user: null },
406-
settings: {
407-
participating: false,
408-
playSound: true,
409-
showNotifications: true,
410-
showBots: true,
411-
showNotificationsCountInTray: false,
412-
openAtStartup: true,
413-
theme: 'SYSTEM',
414-
detailedNotifications: true,
415-
markAsDoneOnOpen: false,
416-
showAccountHostname: false,
417-
delayNotificationState: false,
418-
},
415+
expect(setAutoLaunchMock).toHaveBeenCalledWith(true);
416+
417+
expect(saveStateMock).toHaveBeenCalledWith({
418+
auth: { enterpriseAccounts: [], token: null, user: null },
419+
settings: {
420+
participating: false,
421+
playSound: true,
422+
showNotifications: true,
423+
showBots: true,
424+
showNotificationsCountInTray: false,
425+
openAtStartup: true,
426+
theme: 'SYSTEM',
427+
detailedNotifications: true,
428+
markAsDoneOnOpen: false,
429+
showAccountHostname: false,
430+
delayNotificationState: false,
431+
},
432+
});
419433
});
420434
});
421435
});

src/context/App.tsx

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,23 @@ import { useInterval } from '../hooks/useInterval';
1010
import { useNotifications } from '../hooks/useNotifications';
1111
import {
1212
type AccountNotifications,
13-
type AuthOptions,
1413
type AuthState,
15-
type AuthTokenOptions,
1614
type GitifyError,
1715
type SettingsState,
1816
type Status,
1917
Theme,
2018
} from '../types';
2119
import { headNotifications } from '../utils/api/client';
22-
import { addAccount, authGitHub, getToken, getUserData } from '../utils/auth';
20+
import type {
21+
LoginOAuthAppOptions,
22+
LoginPersonalAccessTokenOptions,
23+
} from '../utils/auth/types';
24+
import {
25+
addAccount,
26+
authGitHub,
27+
getToken,
28+
getUserData,
29+
} from '../utils/auth/utils';
2330
import { setAutoLaunch, updateTrayTitle } from '../utils/comms';
2431
import Constants from '../utils/constants';
2532
import { getNotificationCount } from '../utils/notifications';
@@ -49,9 +56,9 @@ export const defaultSettings: SettingsState = {
4956
interface AppContextState {
5057
auth: AuthState;
5158
isLoggedIn: boolean;
52-
login: () => void;
53-
loginEnterprise: (data: AuthOptions) => void;
54-
validateToken: (data: AuthTokenOptions) => void;
59+
loginWithGitHubApp: () => void;
60+
loginWithOAuthApp: (data: LoginOAuthAppOptions) => void;
61+
loginWithPersonalAccessToken: (data: LoginPersonalAccessTokenOptions) => void;
5562
logout: () => void;
5663

5764
notifications: AccountNotifications[];
@@ -145,7 +152,7 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
145152
return !!auth.token || auth.enterpriseAccounts.length > 0;
146153
}, [auth]);
147154

148-
const login = useCallback(async () => {
155+
const loginWithGitHubApp = useCallback(async () => {
149156
const { authCode } = await authGitHub();
150157
const { token } = await getToken(authCode);
151158
const hostname = Constants.DEFAULT_AUTH_OPTIONS.hostname;
@@ -155,8 +162,8 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
155162
saveState({ auth: updatedAuth, settings });
156163
}, [auth, settings]);
157164

158-
const loginEnterprise = useCallback(
159-
async (data: AuthOptions) => {
165+
const loginWithOAuthApp = useCallback(
166+
async (data: LoginOAuthAppOptions) => {
160167
const { authOptions, authCode } = await authGitHub(data);
161168
const { token, hostname } = await getToken(authCode, authOptions);
162169
const updatedAuth = addAccount(auth, token, hostname);
@@ -166,14 +173,14 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
166173
[auth, settings],
167174
);
168175

169-
const validateToken = useCallback(
170-
async ({ token, hostname }: AuthTokenOptions) => {
176+
const loginWithPersonalAccessToken = useCallback(
177+
async ({ token, hostname }: LoginPersonalAccessTokenOptions) => {
171178
await headNotifications(hostname, token);
172179

173180
const user = await getUserData(token, hostname);
174-
const updatedAccounts = addAccount(auth, token, hostname, user);
175-
setAuth(updatedAccounts);
176-
saveState({ auth: updatedAccounts, settings });
181+
const updatedAuth = addAccount(auth, token, hostname, user);
182+
setAuth(updatedAuth);
183+
saveState({ auth: updatedAuth, settings });
177184
},
178185
[auth, settings],
179186
);
@@ -236,9 +243,9 @@ export const AppProvider = ({ children }: { children: ReactNode }) => {
236243
value={{
237244
auth,
238245
isLoggedIn,
239-
login,
240-
loginEnterprise,
241-
validateToken,
246+
loginWithGitHubApp,
247+
loginWithOAuthApp,
248+
loginWithPersonalAccessToken,
242249
logout,
243250

244251
notifications,

src/routes/LoginWithOAuthApp.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import { useNavigate } from 'react-router-dom';
1111
import { Button } from '../components/fields/Button';
1212
import { FieldInput } from '../components/fields/FieldInput';
1313
import { AppContext } from '../context/App';
14-
import type { AuthOptions } from '../types';
14+
import type { LoginOAuthAppOptions } from '../utils/auth/types';
1515
import {
1616
getNewOAuthAppURL,
1717
isValidClientId,
1818
isValidHostname,
1919
isValidToken,
20-
} from '../utils/auth';
20+
} from '../utils/auth/utils';
2121
import Constants from '../utils/constants';
2222

2323
interface IValues {
@@ -59,7 +59,7 @@ export const validate = (values: IValues): IFormErrors => {
5959
export const LoginWithOAuthApp: FC = () => {
6060
const {
6161
auth: { enterpriseAccounts },
62-
loginEnterprise,
62+
loginWithOAuthApp: loginEnterprise,
6363
} = useContext(AppContext);
6464
const navigate = useNavigate();
6565

@@ -129,7 +129,7 @@ export const LoginWithOAuthApp: FC = () => {
129129

130130
const login = useCallback(async (data: IValues) => {
131131
try {
132-
await loginEnterprise(data as AuthOptions);
132+
await loginEnterprise(data as LoginOAuthAppOptions);
133133
} catch (err) {
134134
// Skip
135135
}

0 commit comments

Comments
 (0)