Skip to content

Commit

Permalink
feat(settings): open links in foreground or background
Browse files Browse the repository at this point in the history
  • Loading branch information
setchy committed Jul 13, 2024
1 parent 7e39efc commit 92c0295
Show file tree
Hide file tree
Showing 22 changed files with 171 additions and 15 deletions.
2 changes: 2 additions & 0 deletions src/__mocks__/state-mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
type GitifyUser,
GroupBy,
type Hostname,
OpenPreference,
type SettingsState,
Theme,
type Token,
Expand Down Expand Up @@ -89,6 +90,7 @@ export const mockSettings: SettingsState = {
keyboardShortcut: true,
groupBy: GroupBy.REPOSITORY,
filterReasons: [],
openLinks: OpenPreference.FOREGROUND,
};

export const mockState: GitifyState = {
Expand Down
4 changes: 4 additions & 0 deletions src/components/AccountNotifications.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { AppContext } from '../context/App';
import { GroupBy } from '../types';
import { mockGitHubNotifications } from '../utils/api/__mocks__/response-mocks';
import * as links from '../utils/links';
import * as storage from '../utils/storage';
import { AccountNotifications } from './AccountNotifications';

jest.mock('./RepositoryNotifications', () => ({
Expand Down Expand Up @@ -61,6 +62,9 @@ describe('components/AccountNotifications.tsx', () => {
});

it('should open profile when clicked', async () => {
jest
.spyOn(storage, 'loadState')
.mockReturnValue({ settings: mockSettings });
const openAccountProfileMock = jest.spyOn(links, 'openAccountProfile');

const props = {
Expand Down
6 changes: 3 additions & 3 deletions src/components/NotificationRow.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ import type { UserType } from '../typesGitHub';
import { mockSingleNotification } from '../utils/api/__mocks__/response-mocks';
import * as comms from '../utils/comms';
import * as links from '../utils/links';
import * as storage from '../utils/storage';
import { NotificationRow } from './NotificationRow';

describe('components/NotificationRow.tsx', () => {
beforeEach(() => {
jest.spyOn(links, 'openNotification');
});
jest.spyOn(links, 'openNotification');
jest.spyOn(storage, 'loadState').mockReturnValue({ settings: mockSettings });

afterEach(() => {
jest.clearAllMocks();
Expand Down
4 changes: 3 additions & 1 deletion src/components/RepositoryNotifications.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { act, fireEvent, render, screen } from '@testing-library/react';
import { mockGitHubCloudAccount } from '../__mocks__/state-mocks';
import { mockGitHubCloudAccount, mockSettings } from '../__mocks__/state-mocks';
import { AppContext } from '../context/App';
import type { Link } from '../types';
import {
mockGitHubNotifications,
mockSingleNotification,
} from '../utils/api/__mocks__/response-mocks';
import * as comms from '../utils/comms';
import * as storage from '../utils/storage';
import { RepositoryNotifications } from './RepositoryNotifications';

jest.mock('./NotificationRow', () => ({
Expand All @@ -16,6 +17,7 @@ jest.mock('./NotificationRow', () => ({
describe('components/Repository.tsx', () => {
const markRepoNotificationsRead = jest.fn();
const markRepoNotificationsDone = jest.fn();
jest.spyOn(storage, 'loadState').mockReturnValue({ settings: mockSettings });

const props = {
account: mockGitHubCloudAccount,
Expand Down
2 changes: 2 additions & 0 deletions src/components/Sidebar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { mockSettings } from '../__mocks__/state-mocks';
import { AppContext } from '../context/App';
import { IconColor } from '../types';
import * as comms from '../utils/comms';
import * as storage from '../utils/storage';
import { Sidebar } from './Sidebar';

const mockNavigate = jest.fn();
Expand All @@ -15,6 +16,7 @@ jest.mock('react-router-dom', () => ({

describe('components/Sidebar.tsx', () => {
const fetchNotifications = jest.fn();
jest.spyOn(storage, 'loadState').mockReturnValue({ settings: mockSettings });

const openExternalLinkMock = jest.spyOn(comms, 'openExternalLink');

Expand Down
3 changes: 3 additions & 0 deletions src/components/buttons/Button.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { MarkGithubIcon } from '@primer/octicons-react';
import { fireEvent, render, screen } from '@testing-library/react';
import { shell } from 'electron';
import { mockSettings } from '../../__mocks__/state-mocks';
import type { Link } from '../../types';
import * as storage from '../../utils/storage';
import { Button, type IButton } from './Button';

describe('components/buttons/Button.tsx', () => {
const openExternalMock = jest.spyOn(shell, 'openExternal');
jest.spyOn(storage, 'loadState').mockReturnValue({ settings: mockSettings });

const props: IButton = {
label: 'button',
Expand Down
6 changes: 3 additions & 3 deletions src/components/notification/NotificationFooter.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import type { UserType } from '../../typesGitHub';
import { mockSingleNotification } from '../../utils/api/__mocks__/response-mocks';
import * as comms from '../../utils/comms';
import * as links from '../../utils/links';
import * as storage from '../../utils/storage';
import { NotificationFooter } from './NotificationFooter';

describe('components/notification/NotificationFooter.tsx', () => {
beforeEach(() => {
jest.spyOn(links, 'openNotification');
});
jest.spyOn(links, 'openNotification');
jest.spyOn(storage, 'loadState').mockReturnValue({ settings: mockSettings });

afterEach(() => {
jest.clearAllMocks();
Expand Down
3 changes: 3 additions & 0 deletions src/components/notification/NotificationHeader.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import { AppContext } from '../../context/App';
import { GroupBy } from '../../types';
import { mockSingleNotification } from '../../utils/api/__mocks__/response-mocks';
import * as comms from '../../utils/comms';
import * as storage from '../../utils/storage';
import { NotificationHeader } from './NotificationHeader';

describe('components/notification/NotificationHeader.tsx', () => {
jest.spyOn(storage, 'loadState').mockReturnValue({ settings: mockSettings });

it('should render itself & its children - group by repositories', async () => {
const props = {
notification: mockSingleNotification,
Expand Down
2 changes: 2 additions & 0 deletions src/components/settings/NotificationSettings.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { MemoryRouter } from 'react-router-dom';
import { mockAuth, mockSettings } from '../../__mocks__/state-mocks';
import { AppContext } from '../../context/App';
import * as comms from '../../utils/comms';
import * as storage from '../../utils/storage';
import { NotificationSettings } from './NotificationSettings';

describe('routes/components/settings/NotificationSettings.tsx', () => {
const updateSetting = jest.fn();
jest.spyOn(storage, 'loadState').mockReturnValue({ settings: mockSettings });

afterEach(() => {
jest.clearAllMocks();
Expand Down
3 changes: 3 additions & 0 deletions src/components/settings/SettingsFooter.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { MemoryRouter } from 'react-router-dom';
import { mockAuth, mockSettings } from '../../__mocks__/state-mocks';
import { AppContext } from '../../context/App';
import * as comms from '../../utils/comms';
import * as storage from '../../utils/storage';
import { SettingsFooter } from './SettingsFooter';

const mockNavigate = jest.fn();
Expand All @@ -14,6 +15,8 @@ jest.mock('react-router-dom', () => ({
global.ResizeObserver = require('resize-observer-polyfill');

describe('routes/components/settings/SettingsFooter.tsx', () => {
jest.spyOn(storage, 'loadState').mockReturnValue({ settings: mockSettings });

afterEach(() => {
jest.clearAllMocks();
process.env = originalEnv;
Expand Down
23 changes: 23 additions & 0 deletions src/components/settings/SystemSettings.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,29 @@ describe('routes/components/settings/SystemSettings.tsx', () => {
jest.clearAllMocks();
});

it('should change the open links radio group', async () => {
await act(async () => {
render(
<AppContext.Provider
value={{
auth: mockAuth,
settings: mockSettings,
updateSetting,
}}
>
<MemoryRouter>
<SystemSettings />
</MemoryRouter>
</AppContext.Provider>,
);
});

fireEvent.click(screen.getByLabelText('Background'));

expect(updateSetting).toHaveBeenCalledTimes(1);
expect(updateSetting).toHaveBeenCalledWith('openLinks', 'BACKGROUND');
});

it('should toggle the keyboardShortcut checkbox', async () => {
await act(async () => {
render(
Expand Down
14 changes: 14 additions & 0 deletions src/components/settings/SystemSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { DeviceDesktopIcon } from '@primer/octicons-react';
import { type FC, useContext } from 'react';
import { AppContext } from '../../context/App';
import type { OpenPreference } from '../../types';
import Constants from '../../utils/constants';
import { isLinux, isMacOS } from '../../utils/platform';
import { Checkbox } from '../fields/Checkbox';
import { RadioGroup } from '../fields/RadioGroup';
import { Legend } from './Legend';

export const SystemSettings: FC = () => {
Expand All @@ -12,6 +14,18 @@ export const SystemSettings: FC = () => {
return (
<fieldset>
<Legend icon={DeviceDesktopIcon}>System</Legend>
<RadioGroup
name="openLinks"
label="Open Links:"
value={settings.openLinks}
options={[
{ label: 'Foreground', value: 'FOREGROUND' },
{ label: 'Background', value: 'BACKGROUND' },
]}
onChange={(evt) => {
updateSetting('openLinks', evt.target.value as OpenPreference);
}}
/>
<Checkbox
name="kbdShortcutEnabled"
label="Enable keyboard shortcut"
Expand Down
2 changes: 2 additions & 0 deletions src/context/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,7 @@ describe('context/App.tsx', () => {
groupBy: 'REPOSITORY',
filterReasons: [],
zoomPercentage: 100,
openLinks: 'FOREGROUND',
} as SettingsState,
});
});
Expand Down Expand Up @@ -440,6 +441,7 @@ describe('context/App.tsx', () => {
groupBy: 'REPOSITORY',
filterReasons: [],
zoomPercentage: 100,
openLinks: 'FOREGROUND',
} as SettingsState,
});
});
Expand Down
2 changes: 2 additions & 0 deletions src/context/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
type AuthState,
type GitifyError,
GroupBy,
OpenPreference,
type SettingsState,
type SettingsValue,
type Status,
Expand Down Expand Up @@ -73,6 +74,7 @@ export const defaultSettings: SettingsState = {
showNumber: true,
keyboardShortcut: true,
groupBy: GroupBy.REPOSITORY,
openLinks: OpenPreference.FOREGROUND,
...defaultFilters,
};

Expand Down
3 changes: 3 additions & 0 deletions src/routes/Accounts.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { AppContext } from '../context/App';
import * as comms from '../utils/comms';
import * as links from '../utils/links';
import * as storage from '../utils/storage';

import { AccountsRoute } from './Accounts';

Expand All @@ -20,6 +21,8 @@ jest.mock('react-router-dom', () => ({
}));

describe('routes/Accounts.tsx', () => {
jest.spyOn(storage, 'loadState').mockReturnValue({ settings: mockSettings });

afterEach(() => {
jest.clearAllMocks();
});
Expand Down
3 changes: 3 additions & 0 deletions src/routes/LoginWithOAuthApp.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { shell } from 'electron';
import { MemoryRouter } from 'react-router-dom';
import { mockSettings } from '../__mocks__/state-mocks';
import { AppContext } from '../context/App';
import type { AuthState, ClientID, ClientSecret, Hostname } from '../types';
import * as storage from '../utils/storage';
import { LoginWithOAuthApp, validate } from './LoginWithOAuthApp';

const mockNavigate = jest.fn();
Expand All @@ -13,6 +15,7 @@ jest.mock('react-router-dom', () => ({

describe('routes/LoginWithOAuthApp.tsx', () => {
const openExternalMock = jest.spyOn(shell, 'openExternal');
jest.spyOn(storage, 'loadState').mockReturnValue({ settings: mockSettings });

const mockAuth: AuthState = {
accounts: [],
Expand Down
3 changes: 3 additions & 0 deletions src/routes/LoginWithPersonalAccessToken.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {
} from '@testing-library/react';
import { shell } from 'electron';
import { MemoryRouter } from 'react-router-dom';
import { mockSettings } from '../__mocks__/state-mocks';
import { AppContext } from '../context/App';
import * as storage from '../utils/storage';
import {
LoginWithPersonalAccessToken,
validate,
Expand All @@ -21,6 +23,7 @@ jest.mock('react-router-dom', () => ({

describe('routes/LoginWithPersonalAccessToken.tsx', () => {
const openExternalMock = jest.spyOn(shell, 'openExternal');
jest.spyOn(storage, 'loadState').mockReturnValue({ settings: mockSettings });

const mockValidateToken = jest.fn();

Expand Down
59 changes: 59 additions & 0 deletions src/routes/__snapshots__/Settings.test.tsx.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 92c0295

Please sign in to comment.