Skip to content
2 changes: 1 addition & 1 deletion src/js/__mocks__/mockedData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ export const mockedEnterpriseNotifications = [
} as Notification,
];

export const mockedNotificationsRecuderData = [
export const mockedNotificationsReducerData = [
{
hostname: 'github.com',
notifications: mockedGithubNotifications,
Expand Down
29 changes: 24 additions & 5 deletions src/js/components/sidebar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,39 @@ describe('components/Sidebar.tsx', () => {
clock.clearAllTimers();
});

it('should test the mapStateToProps method', () => {
describe('mapStateToProps', () => {
const state = {
auth: {
token: '12345',
enterpriseAccounts: mockedEnterpriseAccounts,
} as AuthState,
notifications: {
response: [],
response: [{ hostname: 'Dolores', notifications: [{}, {}] }],
},
} as AppState;

const mappedProps = mapStateToProps(state);

expect(mappedProps.isEitherLoggedIn).toBeTruthy();
it('should accept a provided token', () => {
const mappedProps = mapStateToProps(state);
expect(mappedProps.isEitherLoggedIn).toBeTruthy();
expect(mappedProps.connectedAccounts).toBe(2);
});

it('should count notification lengths', () => {
const mappedProps = mapStateToProps(state);
expect(mappedProps.notificationsCount).toBe(2);
});

it('should accept a null token', () => {
const mappedProps = mapStateToProps({
...state,
auth: {
...state.auth,
token: null,
},
});
expect(mappedProps.isEitherLoggedIn).toBeTruthy();
expect(mappedProps.connectedAccounts).toBe(1);
});
});

it('should render itself & its children (logged in)', () => {
Expand Down
76 changes: 59 additions & 17 deletions src/js/middleware/notifications.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import * as actions from '../actions';
import * as comms from '../utils/comms';
import {
mockedGithubNotifications,
mockedNotificationsRecuderData,
mockedNotificationsReducerData,
} from '../__mocks__/mockedData';
import notificationsMiddleware from './notifications';
import NativeNotifications from '../utils/notifications';

// Keep 3 notifications
// Ps. To receive 4 on actions.NOTIFICATIONS.SUCCESS,
const mockedNotifications = mockedNotificationsRecuderData.map(
const mockedNotifications = mockedNotificationsReducerData.map(
(account, accountIndex) => {
if (accountIndex === 0) {
return {
Expand All @@ -22,25 +22,27 @@ const mockedNotifications = mockedNotificationsRecuderData.map(
}
);

const createFakeStore = () => ({
const DEFAULT_STORE = {
notifications: {
response: mockedNotifications,
},
settings: {
playSound: false,
showNotifications: false,
},
};

const createFakeStore = (storeData) => ({
getState() {
return {
notifications: {
response: mockedNotifications,
},
settings: {
playSound: false,
showNotifications: false,
},
};
return storeData;
},
});

const dispatchWithStoreOf = (_, action) => {
const dispatchWithStoreOf = (storeData, action) => {
let dispatched = null;
const dispatch = notificationsMiddleware(createFakeStore())(
(actionAttempt) => (dispatched = actionAttempt)
);
const dispatch = notificationsMiddleware(
createFakeStore({ ...DEFAULT_STORE, ...storeData })
)((actionAttempt) => (dispatched = actionAttempt));
dispatch(action);
return dispatched;
};
Expand All @@ -54,7 +56,7 @@ describe('middleware/notifications.js', () => {
it('should raise notifications (native & sound, update tray icon, set badge)', () => {
const action = {
type: actions.NOTIFICATIONS.SUCCESS,
payload: mockedNotificationsRecuderData,
payload: mockedNotificationsReducerData,
};

expect(dispatchWithStoreOf({}, action)).toEqual(action);
Expand Down Expand Up @@ -93,4 +95,44 @@ describe('middleware/notifications.js', () => {
expect(comms.updateTrayIcon).toHaveBeenCalledTimes(1);
expect(comms.updateTrayIcon).toHaveBeenCalledWith(2);
});

it('should update tray icon with no notifications', () => {
const noNewNotifications = mockedNotificationsReducerData.map((host) => ({
...host,
notifications: [],
}));
const action = {
type: actions.NOTIFICATIONS.SUCCESS,
payload: noNewNotifications,
};
dispatchWithStoreOf(
{
...DEFAULT_STORE,
notifications: {
response: noNewNotifications,
},
},
action
);
expect(comms.updateTrayIcon).toHaveBeenCalledTimes(1);
expect(comms.updateTrayIcon).toHaveBeenCalledWith(0);
});

it('should show 0 notifications if no accounts logged in', () => {
const action = {
type: actions.NOTIFICATIONS.SUCCESS,
payload: mockedNotificationsReducerData,
};
dispatchWithStoreOf(
{
...DEFAULT_STORE,
notifications: {
response: [],
},
},
action
);
expect(comms.updateTrayIcon).toHaveBeenCalledTimes(1);
expect(comms.updateTrayIcon).toHaveBeenCalledWith(4);
});
});
14 changes: 14 additions & 0 deletions src/js/routes/enterprise-login.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe('routes/enterprise-login.js', () => {
new BrowserWindow().loadURL.mockReset();
spyOn(ipcRenderer, 'send');
props.dispatch.mockReset();
props.history.goBack = jest.fn();
});

it('should test the mapStateToProps method', () => {
Expand Down Expand Up @@ -57,6 +58,19 @@ describe('routes/enterprise-login.js', () => {
expect(tree).toMatchSnapshot();
});

it('let us go back', () => {
props.history.goBack = jest.fn();
const { getByLabelText } = render(
<Provider store={createStore(() => {})}>
<MemoryRouter>
<EnterpriseLogin {...props} />
</MemoryRouter>
</Provider>
);
fireEvent.click(getByLabelText('Go Back'));
expect(props.history.goBack).toHaveBeenCalledTimes(1);
});

it('should validate the form values', () => {
let values;
const emptyValues = {
Expand Down
8 changes: 4 additions & 4 deletions src/js/routes/notifications.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';
import * as TestRenderer from 'react-test-renderer';

import { AppState, NotificationsState } from '../../types/reducers';
import { mockedNotificationsRecuderData } from '../__mocks__/mockedData';
import { mockedNotificationsReducerData } from '../__mocks__/mockedData';
import { NotificationsRoute, mapStateToProps } from './notifications';

jest.mock('../components/account-notifications', () => ({
Expand All @@ -20,7 +20,7 @@ jest.mock('../components/oops', () => ({
describe('routes/notifications.ts', () => {
const props = {
failed: false,
accountNotifications: mockedNotificationsRecuderData,
accountNotifications: mockedNotificationsReducerData,
notificationsCount: 4,
hasMultipleAccounts: true,
hasNotifications: true,
Expand All @@ -29,7 +29,7 @@ describe('routes/notifications.ts', () => {
it('should test the mapStateToProps method', () => {
const state = {
notifications: {
response: mockedNotificationsRecuderData,
response: mockedNotificationsReducerData,
failed: false,
} as NotificationsState,
} as AppState;
Expand All @@ -38,7 +38,7 @@ describe('routes/notifications.ts', () => {

expect(mappedProps.failed).toBeFalsy();
expect(mappedProps.accountNotifications).toEqual(
mockedNotificationsRecuderData
mockedNotificationsReducerData
);
expect(mappedProps.hasNotifications).toBeTruthy();
expect(mappedProps.notificationsCount).toBe(4);
Expand Down
21 changes: 17 additions & 4 deletions src/js/routes/settings.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ describe('routes/settings.tsx', () => {
props.history.replace.mockReset();
});

it('should test the mapStateToProps method', () => {
describe('mapStateToProps', () => {
const state = {
auth: {
token: '123-456',
Expand All @@ -52,11 +52,24 @@ describe('routes/settings.tsx', () => {
participating: false,
} as SettingsState,
} as AppState;
it('should test the method', () => {
const mappedProps = mapStateToProps(state);

const mappedProps = mapStateToProps(state);
expect(mappedProps.hasMultipleAccounts).toBeTruthy();
expect(mappedProps.settings.participating).toBeFalsy();
});

it('should recognize when only one account logged in', () => {
const mappedProps = mapStateToProps({
...state,
auth: {
...state.auth,
token: null,
},
});

expect(mappedProps.hasMultipleAccounts).toBeTruthy();
expect(mappedProps.settings.participating).toBeFalsy();
expect(mappedProps.hasMultipleAccounts).toBeFalsy();
});
});

it('should render itself & its children', () => {
Expand Down
1 change: 1 addition & 0 deletions src/js/store/configureStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default function configureStore() {
storageMiddleware,
];

/* istanbul ignore next */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might not be related to this PR - but shall we remove this block completely (along with the isDev variable)? I guess we can also remove redux-logger from package.json.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Even better 😎, I'll make this change.

I didn't want to overstep and really tried to avoid changing non-test files, but if you'd be okay with refactors, I'd be happy to go deeper and propose some cleanup changes.

if (isDev) {
const { createLogger } = require('redux-logger');
const logger = createLogger({ collapsed: true });
Expand Down
7 changes: 7 additions & 0 deletions src/js/utils/__snapshots__/github-api.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ Object {
`;

exports[`./utils/github-api.ts should format the notification reason 12`] = `
Object {
"description": undefined,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realised that this is broken in the source file - shall we update the actual file https://github.com/manosim/gitify/blob/master/src/js/utils/github-api.ts#L48 to use DESCRIPTIONS['CI_ACTIVITY'] which will remove that undefined.

"type": "Workflow Run",
}
`;

exports[`./utils/github-api.ts should format the notification reason 13`] = `
Object {
"description": "The reason for this notification is not supported by the app.",
"type": "Unknown",
Expand Down
7 changes: 7 additions & 0 deletions src/js/utils/comms.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
reOpenWindow,
openExternalLink,
setAutoLaunch,
restoreSetting,
} from './comms';

const { ipcRenderer, remote, shell } = require('electron');
Expand Down Expand Up @@ -32,6 +33,12 @@ describe('utils/comms.ts', () => {
expect(ipcRenderer.send).toHaveBeenCalledWith('reopen-window');
});

it('should restore a setting', () => {
restoreSetting('foo', 'bar');
expect(ipcRenderer.send).toHaveBeenCalledTimes(1);
expect(ipcRenderer.send).toHaveBeenCalledWith('foo', 'bar');
});

it('should open an external link', () => {
openExternalLink('http://www.gitify.io/');
expect(shell.openExternal).toHaveBeenCalledTimes(1);
Expand Down
2 changes: 2 additions & 0 deletions src/js/utils/github-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ describe('./utils/github-api.ts', () => {
expect(formatReason('state_change')).toMatchSnapshot();
expect(formatReason('subscribed')).toMatchSnapshot();
expect(formatReason('team_mention')).toMatchSnapshot();
expect(formatReason('ci_activity')).toMatchSnapshot();
expect(formatReason('something_else_unknown' as Reason)).toMatchSnapshot();
});

Expand All @@ -25,6 +26,7 @@ describe('./utils/github-api.ts', () => {
expect(getNotificationTypeIcon('RepositoryVulnerabilityAlert')).toBe(
'alert'
);
expect(getNotificationTypeIcon('CheckSuite')).toBe('sync');
expect(getNotificationTypeIcon('Unknown' as SubjectType)).toBe('question');
});
});