Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fe7c2e1
chore: Remove redux and start migrating to context
manosim Dec 15, 2020
54b47d8
chore: Display notifications successfully
manosim Dec 15, 2020
289c41c
chore: Fix a few tests
manosim Dec 15, 2020
e5eb6f2
chore: Move more files
manosim Dec 16, 2020
48a8b53
chore: Restore Settings on launch
manosim Dec 16, 2020
14ad4fd
chore: Use hook - useInterval
manosim Dec 20, 2020
9feb5d0
chore: Simpler logic for native notifiactions
manosim Dec 20, 2020
6431e8d
chore: Store correct settings when updating settings
manosim Dec 20, 2020
d8e6d79
chore: Restore appearance on load
manosim Dec 20, 2020
270eee3
chore: Move files to src/
manosim Dec 20, 2020
4848c0d
fix: Correct imports
manosim Dec 20, 2020
be91f70
feat: Mark notification as read
manosim Dec 20, 2020
c066a75
feat: Unsubscribe from notification
manosim Dec 20, 2020
89ac3ff
feat: Mark repo notifications as read
manosim Dec 20, 2020
6c5c6f4
chore: Rename Constants file to constants
manosim Dec 20, 2020
b7b07fa
feat: Implement Login with Enterprise & fix more tests
manosim Dec 21, 2020
5248d4c
fix: Fix more tests
manosim Dec 21, 2020
8681ede
chore: Fix imports
manosim Dec 21, 2020
f28bce3
chore: Test useNotifications hook
manosim Dec 23, 2020
50e0d81
fix: Fix app context - callback dependencies
manosim Dec 23, 2020
c157f5c
chore: Update dependencies
manosim Dec 23, 2020
8768689
chore: Move auth hook to utils
manosim Dec 24, 2020
45a8859
chore: Tests for App context
manosim Dec 24, 2020
4dc6059
chore: Clean Up
manosim Dec 24, 2020
49fef73
chore: Rename Notification component to NotificationRow
manosim Dec 24, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Run Tests

on: [push, pull_request]
on: [push]

jobs:
run-unit-tests:
Expand All @@ -26,7 +26,10 @@ jobs:
- name: Run Prettier (Check)
run: yarn prettier:check

- name: Run Typechecking
run: yarn tsc --noEmit

- name: Run Jest
run: yarn test --coverage --runInBand
run: yarn test --coverage --runInBand --verbose

- uses: codecov/codecov-action@v1
48 changes: 20 additions & 28 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@
"contributors": [
{
"name": "Emmanouil Konstantinidis",
"url": "https://githib.com/manosim"
"url": "https://github.com/manosim"
},
{
"name": "Jake 'Sid' Smith",
"url": "https://githib.com/JakeSidSmith"
"url": "https://github.com/JakeSidSmith"
}
],
"license": "MIT",
Expand All @@ -52,7 +52,7 @@
"jest": {
"preset": "ts-jest/presets/js-with-ts",
"setupFiles": [
"<rootDir>/src/js/__helpers__/setupEnvVars.js"
"<rootDir>/src/__helpers__/setupEnvVars.js"
],
"testEnvironment": "jsdom",
"coverageThreshold": {
Expand Down Expand Up @@ -106,12 +106,12 @@
"afterSign": "scripts/notarize.js"
},
"dependencies": {
"@primer/octicons-react": "^11.1.0",
"@primer/octicons-react": "^11.2.0",
"autoprefixer": "^10.1.0",
"axios": "=0.21.0",
"axios": "=0.21.1",
"date-fns": "^2.16.1",
"electron-updater": "^4.3.5",
"final-form": "^4.19.1",
"final-form": "^4.20.1",
"lodash": "^4.17.20",
"menubar": "^9.0.1",
"nprogress": "=0.2.0",
Expand All @@ -120,43 +120,35 @@
"react-dom": "=16.13.1",
"react-emojione": "=5.0.1",
"react-final-form": "^6.4.0",
"react-is": "^16.13.1",
"react-redux": "=7.2.0",
"react-router-dom": "^5.1.2",
"react-transition-group": "^4.3.0",
"react-router-dom": "^5.2.0",
"react-transition-group": "^4.4.1",
"react-typist": "^2.0.5",
"redux": "=4.0.5",
"redux-storage": "=4.1.2",
"redux-storage-decorator-filter": "=1.1.8",
"redux-storage-engine-localstorage": "=1.1.4",
"redux-thunk": "=2.3.0",
"tailwindcss": "^2.0.2",
"ts-loader": "^8.0.11",
"typescript": "^4.1.2"
"ts-loader": "^8.0.12",
"typescript": "^4.1.3"
},
"devDependencies": {
"@testing-library/react": "^10.0.2",
"@types/jest": "^26.0.15",
"@testing-library/react": "^11.2.2",
"@testing-library/react-hooks": "^3.7.0",
"@types/jest": "^26.0.19",
"@types/lodash": "^4.14.165",
"@types/node": "^14.14.9",
"@types/node": "^14.14.14",
"@types/react": "^16.9.32",
"@types/react-redux": "^7.1.7",
"@types/react-transition-group": "^4.2.4",
"@types/styled-components": "^5.0.1",
"@types/react-router-dom": "^5.1.6",
"@types/react-transition-group": "^4.4.0",
"css-loader": "^5.0.1",
"electron": "^11.1.0",
"electron-builder": "^22.9.1",
"electron-notarize": "^1.0.0",
"jest": "^26.6.3",
"nock": "^12.0.3",
"nock": "^13.0.5",
"postcss-loader": "^4.1.0",
"prettier": "=2.2.0",
"prettier": "=2.2.1",
"react-test-renderer": "=16.13.1",
"redux-mock-store": "=1.5.4",
"style-loader": "^2.0.0",
"ts-jest": "^26.4.4",
"webpack": "^5.6.0",
"webpack": "^5.11.0",
"webpack-cli": "^4.2.0",
"webpack-merge": "^5.4.0"
"webpack-merge": "^5.7.3"
}
}
File renamed without changes.
File renamed without changes.
20 changes: 20 additions & 0 deletions src/__mocks__/mock-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Appearance, AuthState, SettingsState } from '../types';

export const mockAccounts: AuthState = {
token: 'token-123-456',
enterpriseAccounts: [
{
token: 'token-gitify-123-456',
hostname: 'github.gitify.io',
},
],
};

export const mockSettings: SettingsState = {
participating: false,
playSound: true,
showNotifications: true,
markOnClick: false,
openAtStartup: false,
appearance: Appearance.SYSTEM,
};
13 changes: 10 additions & 3 deletions src/js/__mocks__/mockedData.ts → src/__mocks__/mockedData.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Notification, Repository } from '../../types/github';
import { EnterpriseAccount } from '../../types/reducers';
import { AccountNotifications, EnterpriseAccount } from '../types';
import { Notification, Repository } from '../typesGithub';

export const mockedEnterpriseAccounts: EnterpriseAccount[] = [
{
Expand Down Expand Up @@ -251,7 +251,7 @@ export const mockedEnterpriseNotifications = [
} as Notification,
];

export const mockedNotificationsReducerData = [
export const mockedAccountNotifications: AccountNotifications[] = [
{
hostname: 'github.com',
notifications: mockedGithubNotifications,
Expand All @@ -261,3 +261,10 @@ export const mockedNotificationsReducerData = [
notifications: mockedEnterpriseNotifications,
},
];

export const mockedSingleAccountNotifications: AccountNotifications[] = [
{
hostname: 'github.com',
notifications: [mockedSingleNotification],
},
];
34 changes: 13 additions & 21 deletions src/js/app.tsx → src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,27 @@
import * as React from 'react';
import React, { useContext } from 'react';
import {
Redirect,
HashRouter as Router,
Route,
Switch,
} from 'react-router-dom';
import { Provider } from 'react-redux';

import configureStore from './store/configureStore';
import Loading from './components/loading';
import Sidebar from './components/sidebar';

import EnterpriseLoginRoute from './routes/enterprise-login';
import LoginRoute from './routes/login';
import NotificationsRoute from './routes/notifications';
import SettingsRoute from './routes/settings';

// Store
export const store = configureStore();
import { AppContext, AppProvider } from './context/App';
import { Loading } from './components/Loading';
import { LoginEnterpriseRoute } from './routes/LoginEnterprise';
import { LoginRoute } from './routes/Login';
import { NotificationsRoute } from './routes/Notifications';
import { SettingsRoute } from './routes/Settings';
import { Sidebar } from './components/Sidebar';

export const PrivateRoute = ({ component: Component, ...rest }) => {
// @ts-ignore
const authReducer = store.getState().auth;
const isAuthenticated =
authReducer.token !== null || authReducer.enterpriseAccounts.length > 0;
const { isLoggedIn } = useContext(AppContext);

return (
<Route
{...rest}
render={(props) =>
isAuthenticated ? (
isLoggedIn ? (
<Component {...props} />
) : (
<Redirect
Expand All @@ -43,7 +35,7 @@ export const PrivateRoute = ({ component: Component, ...rest }) => {

export const App = () => {
return (
<Provider store={store}>
<AppProvider>
<Router>
<div className="flex flex-col pl-14 h-full">
<Loading />
Expand All @@ -53,10 +45,10 @@ export const App = () => {
<PrivateRoute path="/" exact component={NotificationsRoute} />
<PrivateRoute path="/settings" exact component={SettingsRoute} />
<Route path="/login" component={LoginRoute} />
<Route path="/enterpriselogin" component={EnterpriseLoginRoute} />
<Route path="/enterpriselogin" component={LoginEnterpriseRoute} />
</Switch>
</div>
</Router>
</Provider>
</AppProvider>
);
};
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import * as React from 'react';
import * as TestRendener from 'react-test-renderer';
import React from 'react';
import TestRendener from 'react-test-renderer';

import { AccountNotifications } from './account-notifications';
import { AccountNotifications } from './AccountNotifications';
import { mockedGithubNotifications } from '../__mocks__/mockedData';

jest.mock('./repository');
jest.mock('./Repository', () => ({
RepositoryNotifications: () => <div>Repository</div>,
}));

describe('components/account-notifications.tsx', () => {
describe('components/AccountNotifications.tsx', () => {
it('should render itself (github.com with notifications)', () => {
const props = {
hostname: 'github.com',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as React from 'react';
import * as _ from 'lodash';
import React from 'react';
import _ from 'lodash';
import { ChevronDownIcon, ChevronLeftIcon } from '@primer/octicons-react';

import { Notification } from '../../types/github';
import RepositoryNotifications from './repository';
import { Notification } from '../typesGithub';
import { RepositoryNotifications } from './Repository';

interface IProps {
hostname: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from 'react';
import * as TestRenderer from 'react-test-renderer';
import { Constants } from '../utils/constants';

import Constants from '../utils/constants';
import { AllRead } from './all-read';
import { AllRead } from './AllRead';

jest.mock('react-typist');

Expand Down
10 changes: 5 additions & 5 deletions src/js/components/all-read.tsx → src/components/AllRead.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ import * as React from 'react';
import Typist from 'react-typist';
import { emojify } from 'react-emojione';

import constants from '../utils/constants';
import { Constants } from '../utils/constants';

export const AllRead = () => {
const message = React.useMemo(
() =>
constants.ALLREAD_MESSAGES[
Math.floor(Math.random() * constants.ALLREAD_MESSAGES.length)
Constants.ALLREAD_MESSAGES[
Math.floor(Math.random() * Constants.ALLREAD_MESSAGES.length)
],
[]
);

const emoji = React.useMemo(
() =>
constants.ALLREAD_EMOJIS[
Math.floor(Math.random() * constants.ALLREAD_EMOJIS.length)
Constants.ALLREAD_EMOJIS[
Math.floor(Math.random() * Constants.ALLREAD_EMOJIS.length)
],
[]
);
Expand Down
59 changes: 59 additions & 0 deletions src/components/Loading.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from 'react';
import { render } from '@testing-library/react';
import NProgress from 'nprogress';

import { AppContext } from '../context/App';
import { Loading } from './Loading';

jest.mock('nprogress', () => {
return {
configure: jest.fn(),
start: jest.fn(),
done: jest.fn(),
remove: jest.fn(),
};
});

describe('components/Loading.js', () => {
beforeEach(() => {
NProgress.configure.mockReset();
NProgress.start.mockReset();
NProgress.done.mockReset();
NProgress.remove.mockReset();
});

it('should check that NProgress is getting called in when isFetching changes (loading)', () => {
const { container } = render(
<AppContext.Provider value={{ isFetching: true }}>
<Loading />
</AppContext.Provider>
);

expect(container.innerHTML).toBe('');
expect(NProgress.configure).toHaveBeenCalledTimes(1);
expect(NProgress.start).toHaveBeenCalledTimes(1);
});

it('should check that NProgress is getting called in when isFetching changes (not loading)', () => {
const { container } = render(
<AppContext.Provider value={{ isFetching: false }}>
<Loading />
</AppContext.Provider>
);

expect(container.innerHTML).toBe('');
expect(NProgress.configure).toHaveBeenCalledTimes(1);
expect(NProgress.done).toHaveBeenCalledTimes(1);
});

it('should remove NProgress on unmount', () => {
const { unmount } = render(
<AppContext.Provider value={{ isFetching: true }}>
<Loading />
</AppContext.Provider>
);
expect(NProgress.remove).toHaveBeenCalledTimes(0);
unmount();
expect(NProgress.remove).toHaveBeenCalledTimes(1);
});
});
28 changes: 28 additions & 0 deletions src/components/Loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useContext, useEffect } from 'react';
import NProgress from 'nprogress';

import { AppContext } from '../context/App';

export const Loading = () => {
const { isFetching } = useContext(AppContext);

useEffect(() => {
NProgress.configure({
showSpinner: false,
});

return () => {
NProgress.remove();
};
}, []);

useEffect(() => {
if (isFetching) {
NProgress.start();
} else {
NProgress.done();
}
}, [isFetching]);

return null;
};
Loading