diff --git a/.all-contributorsrc b/.all-contributorsrc index 65a773e9e..5a0868aba 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -552,7 +552,8 @@ "avatar_url": "https://avatars1.githubusercontent.com/u/40802?v=4", "profile": "http://jamesmglover.com", "contributions": [ - "code" + "code", + "test" ] }, { diff --git a/.eslintrc b/.eslintrc index 1d221241c..b1fd74bab 100644 --- a/.eslintrc +++ b/.eslintrc @@ -37,6 +37,7 @@ "repository": "repository", "search": "search", "testData": "./__tests__/data", + "user": "user", "utils": "utils" } } diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 5b560dab8..eb5a88de7 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -13,5 +13,5 @@ Thank you to all the people who have already contributed to GitPoint! | [
Vitaliy Kanev](https://github.com/vitalkanev)
[πŸ“–](https://github.com/gitpoint/git-point/commits?author=vitalkanev "Documentation") | [
Peter Dave Hello](https://www.peterdavehello.org/)
[πŸ“–](https://github.com/gitpoint/git-point/commits?author=PeterDaveHello "Documentation") [πŸ”§](#tool-PeterDaveHello "Tools") | [
Ernoff](https://github.com/Ernoff)
[πŸ’»](https://github.com/gitpoint/git-point/commits?author=Ernoff "Code") [πŸ›](https://github.com/gitpoint/git-point/issues?q=author%3AErnoff "Bug reports") | [
Matthew Brandly](http://words.brandly.me/about/)
[πŸ’»](https://github.com/gitpoint/git-point/commits?author=brandly "Code") | [
JoΓ£o Fonseca](https://github.com/Jpfonseca)
[🌍](#translation-Jpfonseca "Translation") | [
Arjun Curat](https://github.com/acurat)
[πŸ“–](https://github.com/gitpoint/git-point/commits?author=acurat "Documentation") | | [
siderio2](https://github.com/siderio2)
[🌍](#translation-siderio2 "Translation") | [
Kodo Verkisto](https://github.com/kodisto)
[🌍](#translation-kodisto "Translation") | [
Sarah Vessels](http://sarahvessels.com/)
[πŸ“–](https://github.com/gitpoint/git-point/commits?author=cheshire137 "Documentation") | [
Thales Sousa](https://github.com/tminussi)
[🌍](#translation-tminussi "Translation") | [
Aseem Sood](https://github.com/asood123)
[πŸ“–](https://github.com/gitpoint/git-point/commits?author=asood123 "Documentation") | [
Eliott hauteclair](https://eliott.be)
[🌍](#translation-Eliottiosdevs "Translation") | | [
Peter Blazejewicz](http://www.linkedin.com/in/peterblazejewicz)
[🌍](#translation-peterblazejewicz "Translation") | [
Eric Adamski](https://github.com/ericadamski)
[πŸ›](https://github.com/gitpoint/git-point/issues?q=author%3Aericadamski "Bug reports") | [
Jouderian Nobre Junior](https://github.com/jouderianjr)
[πŸ’»](https://github.com/gitpoint/git-point/commits?author=jouderianjr "Code") | [
Phi Dong](http://www.phidong.com)
[πŸ’»](https://github.com/gitpoint/git-point/commits?author=pdong "Code") | [
John Patrick Salcedo](https://github.com/jpls93)
[πŸ’»](https://github.com/gitpoint/git-point/commits?author=jpls93 "Code") | [
Γ“scar Carretero](https://github.com/ocarreterom)
[πŸ’»](https://github.com/gitpoint/git-point/commits?author=ocarreterom "Code") | -| [
Dyesse YUMBA](https://github.com/dyesseyumba)
[πŸ”§](#tool-dyesseyumba "Tools") | [
Bink](https://binkpitch.me/)
[πŸ’»](https://github.com/gitpoint/git-point/commits?author=binkpitch "Code") | [
khvilaboa](https://github.com/khvilaboa)
[🌍](#translation-khvilaboa "Translation") | [
James Glover](http://jamesmglover.com)
[πŸ’»](https://github.com/gitpoint/git-point/commits?author=jglover "Code") | [
Jose Luis Naranjo](https://co.linkedin.com/in/josenaranjo/en)
| +| [
Dyesse YUMBA](https://github.com/dyesseyumba)
[πŸ”§](#tool-dyesseyumba "Tools") | [
Bink](https://binkpitch.me/)
[πŸ’»](https://github.com/gitpoint/git-point/commits?author=binkpitch "Code") | [
khvilaboa](https://github.com/khvilaboa)
[🌍](#translation-khvilaboa "Translation") | [
James Glover](http://jamesmglover.com)
[πŸ’»](https://github.com/gitpoint/git-point/commits?author=jglover "Code") [⚠️](https://github.com/gitpoint/git-point/commits?author=jglover "Tests") | [
Jose Luis Naranjo](https://co.linkedin.com/in/josenaranjo/en)
| diff --git a/__tests__/data/issue.js b/__tests__/data/api/issue.js similarity index 100% rename from __tests__/data/issue.js rename to __tests__/data/api/issue.js diff --git a/__tests__/data/api/notification.js b/__tests__/data/api/notification.js new file mode 100644 index 000000000..1cc1be0a5 --- /dev/null +++ b/__tests__/data/api/notification.js @@ -0,0 +1,47 @@ +export const notification = { + id: '1', + repository: { + id: 1296269, + owner: { + login: 'octocat', + id: 1, + avatar_url: 'https://github.com/images/error/octocat_happy.gif', + gravatar_id: '', + url: 'https://api.github.com/users/octocat', + html_url: 'https://github.com/octocat', + followers_url: 'https://api.github.com/users/octocat/followers', + following_url: + 'https://api.github.com/users/octocat/following{/other_user}', + gists_url: 'https://api.github.com/users/octocat/gists{/gist_id}', + starred_url: + 'https://api.github.com/users/octocat/starred{/owner}{/repo}', + subscriptions_url: 'https://api.github.com/users/octocat/subscriptions', + organizations_url: 'https://api.github.com/users/octocat/orgs', + repos_url: 'https://api.github.com/users/octocat/repos', + events_url: 'https://api.github.com/users/octocat/events{/privacy}', + received_events_url: + 'https://api.github.com/users/octocat/received_events', + type: 'User', + site_admin: false, + }, + name: 'Hello-World', + full_name: 'octocat/Hello-World', + description: 'This your first repo!', + private: false, + fork: false, + url: 'https://api.github.com/repos/octocat/Hello-World', + html_url: 'https://github.com/octocat/Hello-World', + }, + subject: { + title: 'Greetings', + url: 'https://api.github.com/repos/octokit/octokit.rb/issues/123', + latest_comment_url: + 'https://api.github.com/repos/octokit/octokit.rb/issues/comments/123', + type: 'Issue', + }, + reason: 'subscribed', + unread: true, + updated_at: '2014-11-07T22:01:45Z', + last_read_at: '2014-11-07T22:01:45Z', + url: 'https://api.github.com/notifications/threads/1', +}; diff --git a/__tests__/data/organization.js b/__tests__/data/api/organization.js similarity index 100% rename from __tests__/data/organization.js rename to __tests__/data/api/organization.js diff --git a/__tests__/data/pull-request.js b/__tests__/data/api/pull-request.js similarity index 100% rename from __tests__/data/pull-request.js rename to __tests__/data/api/pull-request.js diff --git a/__tests__/data/user.js b/__tests__/data/api/user.js similarity index 100% rename from __tests__/data/user.js rename to __tests__/data/api/user.js diff --git a/__tests__/data/label.js b/__tests__/data/label.js index 84ae6f55e..4981ec1ef 100644 --- a/__tests__/data/label.js +++ b/__tests__/data/label.js @@ -1,4 +1,4 @@ export default { - name: 'test tag', + name: 'test label text', color: 'c3c3c3', }; diff --git a/__tests__/tests/components/EntityInfo.js b/__tests__/tests/components/EntityInfo.js index 5d7d4dc25..6d2c822cf 100644 --- a/__tests__/tests/components/EntityInfo.js +++ b/__tests__/tests/components/EntityInfo.js @@ -1,8 +1,8 @@ import React from 'react'; import { shallow } from 'enzyme'; -import organization from '../../data/organization'; -import user from '../../data/user'; +import organization from 'testData/api/organization'; +import user from 'testData/api/user'; import { EntityInfo } from 'components'; diff --git a/__tests__/tests/components/LabelButton.js b/__tests__/tests/components/LabelButton.js index 972cade49..ea5850f50 100644 --- a/__tests__/tests/components/LabelButton.js +++ b/__tests__/tests/components/LabelButton.js @@ -1,7 +1,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import label from '../../data/label'; +import label from 'testData/label'; import { LabelButton } from 'components'; @@ -9,7 +9,7 @@ describe('', () => { it('correctly renders small style', () => { const wrapper = shallow(); - expect(wrapper.prop('title')).toEqual('test tag'); + expect(wrapper.prop('title')).toEqual(label.name); expect(wrapper.prop('fontSize')).toEqual(12); expect(wrapper.prop('color')).toEqual('#000000'); expect(wrapper.prop('backgroundColor')).toEqual('#c3c3c3'); @@ -19,7 +19,7 @@ describe('', () => { it('correctly renders large style', () => { const wrapper = shallow(); - expect(wrapper.prop('title')).toEqual('test tag'); + expect(wrapper.prop('title')).toEqual(label.name); expect(wrapper.prop('fontSize')).toEqual(13); expect(wrapper.prop('color')).toEqual('#000000'); expect(wrapper.prop('backgroundColor')).toEqual('#c3c3c3'); diff --git a/__tests__/tests/components/StateBadge.js b/__tests__/tests/components/StateBadge.js index 89440d9b4..7a80a92d5 100644 --- a/__tests__/tests/components/StateBadge.js +++ b/__tests__/tests/components/StateBadge.js @@ -1,12 +1,12 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { closed as closedIssue, open as openIssue } from '../../data/issue'; +import { closed as closedIssue, open as openIssue } from 'testData/api/issue'; import { closed as closedPr, open as openPr, merged as mergedPr, -} from '../../data/pull-request'; +} from 'testData/api/pull-request'; import { colors } from 'config'; import { StateBadge } from 'components'; diff --git a/__tests__/tests/reducers/notifications.reducer.js b/__tests__/tests/reducers/notifications.reducer.js new file mode 100644 index 000000000..bbf29337c --- /dev/null +++ b/__tests__/tests/reducers/notifications.reducer.js @@ -0,0 +1,479 @@ +import React from 'react'; +import { + notificationsReducer, + initialState, +} from 'notifications/notifications.reducer'; +import { + GET_UNREAD_NOTIFICATIONS, + GET_PARTICIPATING_NOTIFICATIONS, + GET_ALL_NOTIFICATIONS, + MARK_NOTIFICATION_AS_READ, + MARK_ALL_NOTIFICATIONS_AS_READ, + GET_NOTIFICATIONS_COUNT, + MARK_REPO_AS_READ, +} from 'notifications/notifications.type'; +import { notification } from 'testData/api/notification'; +import { authError } from 'testData/api/error'; + +describe('Notifications Reducer', () => { + it('should return the initial state', () => { + expect(notificationsReducer(undefined, {})).toEqual(initialState); + }); + + it('should set notifications count from GET_NOTIFICATIONS_COUNT.SUCCESS action', () => { + const expectedState = { + ...initialState, + notificationsCount: 1, + }; + const getNotificationsCountSuccessAction = { + type: GET_NOTIFICATIONS_COUNT.SUCCESS, + payload: 1, + }; + + expect( + notificationsReducer(initialState, getNotificationsCountSuccessAction) + ).toEqual(expectedState); + }); + + it('should set an error from GET_NOTIFICATIONS_COUNT.ERROR action', () => { + const expectedState = { + ...initialState, + error: authError, + }; + const getNotificationsCountErrorAction = { + type: GET_NOTIFICATIONS_COUNT.ERROR, + payload: authError, + }; + + expect( + notificationsReducer(initialState, getNotificationsCountErrorAction) + ).toEqual(expectedState); + }); + + /** + * Unread notifications. + */ + it('should set isPendingUnread to true when GET_UNREAD_NOTIFICATIONS.PENDING action is dispatched', () => { + const expectedState = { + ...initialState, + isPendingUnread: true, + }; + const getUnreadNotificationsAction = { + type: GET_UNREAD_NOTIFICATIONS.PENDING, + }; + + expect( + notificationsReducer(initialState, getUnreadNotificationsAction) + ).toEqual(expectedState); + }); + + it('should set unread notifications from GET_UNREAD_NOTIFICATIONS.SUCCESS action', () => { + const expectedState = { + ...initialState, + unread: [notification], + isPendingUnread: false, + }; + const getUnreadNotificationsSuccessAction = { + type: GET_UNREAD_NOTIFICATIONS.SUCCESS, + payload: [notification], + }; + + expect( + notificationsReducer(initialState, getUnreadNotificationsSuccessAction) + ).toEqual(expectedState); + }); + + it('should set an error from GET_UNREAD_NOTIFICATIONS.ERROR action', () => { + const expectedState = { + ...initialState, + error: authError, + isPendingUnread: false, + }; + const getUnreadNotificationsErrorAction = { + type: GET_UNREAD_NOTIFICATIONS.ERROR, + payload: authError, + }; + + expect( + notificationsReducer(initialState, getUnreadNotificationsErrorAction) + ).toEqual(expectedState); + }); + + /** + * Participating notifications. + */ + it('should set isPendingParticipating to true when GET_PARTICIPATING_NOTIFICATIONS.PENDING action is dispatched', () => { + const expectedState = { + ...initialState, + isPendingParticipating: true, + }; + const getParticipatingNotificationsAction = { + type: GET_PARTICIPATING_NOTIFICATIONS.PENDING, + }; + + expect( + notificationsReducer(initialState, getParticipatingNotificationsAction) + ).toEqual(expectedState); + }); + + it('should set unread notifications from GET_PARTICIPATING_NOTIFICATIONS.SUCCESS action', () => { + const expectedState = { + ...initialState, + participating: [notification], + isPendingParticipating: false, + }; + const getParticipatingNotificationsSuccessAction = { + type: GET_PARTICIPATING_NOTIFICATIONS.SUCCESS, + payload: [notification], + }; + + expect( + notificationsReducer( + initialState, + getParticipatingNotificationsSuccessAction + ) + ).toEqual(expectedState); + }); + + it('should set an error from GET_PARTICIPATING_NOTIFICATIONS.ERROR action', () => { + const expectedState = { + ...initialState, + error: authError, + isPendingParticipating: false, + }; + const getParticipatingNotificationsErrorAction = { + type: GET_PARTICIPATING_NOTIFICATIONS.ERROR, + payload: authError, + }; + + expect( + notificationsReducer( + initialState, + getParticipatingNotificationsErrorAction + ) + ).toEqual(expectedState); + }); + + /** + * Fetching all notifications. + */ + it('should set isPendingAll to true when GET_ALL_NOTIFICATIONS.PENDING action is dispatched', () => { + const expectedState = { + ...initialState, + isPendingAll: true, + }; + const getPendingNotificationsAction = { + type: GET_ALL_NOTIFICATIONS.PENDING, + }; + + expect( + notificationsReducer(initialState, getPendingNotificationsAction) + ).toEqual(expectedState); + }); + + it('should set pending notifications from GET_ALL_NOTIFICATIONS.SUCCESS action', () => { + const expectedState = { + ...initialState, + all: [notification, notification], + isPendingAll: false, + }; + const getPendingNotificationsSuccessAction = { + type: GET_ALL_NOTIFICATIONS.SUCCESS, + payload: [notification, notification], + }; + + expect( + notificationsReducer(initialState, getPendingNotificationsSuccessAction) + ).toEqual(expectedState); + }); + + it('should set an error from GET_ALL_NOTIFICATIONS.ERROR action', () => { + const expectedState = { + ...initialState, + error: authError, + isPendingAll: false, + }; + const getPendingNotificationsErrorAction = { + type: GET_ALL_NOTIFICATIONS.ERROR, + payload: authError, + }; + + expect( + notificationsReducer(initialState, getPendingNotificationsErrorAction) + ).toEqual(expectedState); + }); + + /** + * Mark individual notifications as read. + */ + it('should set isPendingMarkNotificationAsRead to true when MARK_NOTIFICATION_AS_READ.PENDING action is dispatched', () => { + const expectedState = { + ...initialState, + isPendingMarkNotificationAsRead: true, + }; + const markNotificationsReadAction = { + type: MARK_NOTIFICATION_AS_READ.PENDING, + }; + + expect( + notificationsReducer(initialState, markNotificationsReadAction) + ).toEqual(expectedState); + }); + + it('should filter out the unread notification from returned notifications and update the notification count given a notification id', () => { + const state = { + ...initialState, + unread: [notification], + notificationsCount: 1, + isPendingMarkNotificationAsRead: true, + }; + + const expectedState = { + ...initialState, + unread: [], + isPendingMarkNotificationAsRead: false, + notificationsCount: 0, + }; + + const markNotificationsReadSuccessAction = { + type: MARK_NOTIFICATION_AS_READ.SUCCESS, + notificationID: '1', + }; + + expect( + notificationsReducer(state, markNotificationsReadSuccessAction) + ).toEqual(expectedState); + }); + + it('should filter out the participating notification from returned notifications and update the notification count given a notification id', () => { + const state = { + ...initialState, + participating: [notification], + notificationsCount: 1, + isPendingMarkNotificationAsRead: true, + }; + + const expectedState = { + ...initialState, + participating: [], + isPendingMarkNotificationAsRead: false, + notificationsCount: 0, + }; + + const markNotificationsReadSuccessAction = { + type: MARK_NOTIFICATION_AS_READ.SUCCESS, + notificationID: '1', + }; + + expect( + notificationsReducer(state, markNotificationsReadSuccessAction) + ).toEqual(expectedState); + }); + + it("should set the value of the unread property to false for a single notification in 'all' update the notification count given a notification id", () => { + const state = { + ...initialState, + all: [notification], + isPendingMarkNotificationAsRead: true, + notificationsCount: 1, + }; + const readNotification = { + ...notification, + unread: false, + }; + const expectedState = { + ...initialState, + all: [readNotification], + isPendingMarkNotificationAsRead: false, + notificationsCount: 0, + }; + const markNotificationsReadSuccessAction = { + type: MARK_NOTIFICATION_AS_READ.SUCCESS, + notificationID: '1', + }; + + expect( + notificationsReducer(state, markNotificationsReadSuccessAction) + ).toEqual(expectedState); + }); + + it('should set an error from MARK_NOTIFICATION_AS_READ.ERROR action', () => { + const expectedState = { + ...initialState, + error: authError, + isPendingMarkNotificationAsRead: false, + }; + const markNotificationsReadErrorAction = { + type: MARK_NOTIFICATION_AS_READ.ERROR, + payload: authError, + }; + + expect( + notificationsReducer(initialState, markNotificationsReadErrorAction) + ).toEqual(expectedState); + }); + + /** + * Mark all notifications as read. + */ + it('should set isPendingMarkAllNotificationsAsRead to true when MARK_ALL_NOTIFICATIONS_AS_READ.PENDING action is dispatched', () => { + const expectedState = { + ...initialState, + isPendingMarkAllNotificationsAsRead: true, + }; + const markAllNotificationsReadAction = { + type: MARK_ALL_NOTIFICATIONS_AS_READ.PENDING, + }; + + expect( + notificationsReducer(initialState, markAllNotificationsReadAction) + ).toEqual(expectedState); + }); + + it('should set isPendingMarkAllNotificationsAsRead to false when MARK_ALL_NOTIFICATIONS_AS_READ.SUCCESS action is dispatched', () => { + const state = { + ...initialState, + isPendingMarkAllNotificationsAsRead: true, + }; + const expectedState = { + ...initialState, + isPendingMarkAllNotificationsAsRead: false, + }; + const markAllNotificationsReadSuccessAction = { + type: MARK_ALL_NOTIFICATIONS_AS_READ.SUCCESS, + }; + + expect( + notificationsReducer(state, markAllNotificationsReadSuccessAction) + ).toEqual(expectedState); + }); + + it('should set an error from MARK_ALL_NOTIFICATIONS_AS_READ.ERROR action', () => { + const expectedState = { + ...initialState, + error: authError, + isPendingMarkNotificationAsRead: false, + }; + const markAllNotificationsReadErrorAction = { + type: MARK_ALL_NOTIFICATIONS_AS_READ.ERROR, + payload: authError, + }; + + expect( + notificationsReducer(initialState, markAllNotificationsReadErrorAction) + ).toEqual(expectedState); + }); + + /** + * Mark repository notifications as read. + */ + it('should set isPendingMarkNotificationAsRead to true when MARK_REPO_AS_READ.PENDING action is dispatched', () => { + const expectedState = { + ...initialState, + isPendingRepoMarkAsRead: true, + }; + const markRepoAsReadAction = { + type: MARK_REPO_AS_READ.PENDING, + }; + + expect(notificationsReducer(initialState, markRepoAsReadAction)).toEqual( + expectedState + ); + }); + + it('should filter out the repo notification from returned unread notifications and update the notification count given a repo name', () => { + const state = { + ...initialState, + unread: [notification], + notificationsCount: 1, + isPendingRepoMarkAsRead: true, + }; + + const expectedState = { + ...initialState, + unread: [], + isPendingRepoMarkAsRead: false, + notificationsCount: 0, + }; + + const markRepoNotificationsReadSuccessAction = { + type: MARK_REPO_AS_READ.SUCCESS, + repoFullName: notification.repository.full_name, + repoNotificationsCount: 1, + }; + + expect( + notificationsReducer(state, markRepoNotificationsReadSuccessAction) + ).toEqual(expectedState); + }); + + it('should filter out the repo notification from returned participating notifications and update the notification count given a repo name', () => { + const state = { + ...initialState, + participating: [notification], + notificationsCount: 1, + isPendingRepoMarkAsRead: true, + }; + + const expectedState = { + ...initialState, + participating: [], + isPendingRepoMarkAsRead: false, + notificationsCount: 0, + }; + + const markRepoNotificationsReadSuccessAction = { + type: MARK_REPO_AS_READ.SUCCESS, + repoFullName: notification.repository.full_name, + repoNotificationsCount: 1, + }; + + expect( + notificationsReducer(state, markRepoNotificationsReadSuccessAction) + ).toEqual(expectedState); + }); + + it("should set the value of the unread property to false for a single notification in 'all' and update the notification count given a repo name", () => { + const state = { + ...initialState, + all: [notification], + isPendingRepoMarkAsRead: true, + notificationsCount: 1, + }; + const readNotification = { + ...notification, + unread: false, + }; + const expectedState = { + ...initialState, + all: [readNotification], + isPendingRepoMarkAsRead: false, + notificationsCount: 0, + }; + const markRepoNotificationsReadSuccessAction = { + type: MARK_REPO_AS_READ.SUCCESS, + repoFullName: notification.repository.full_name, + repoNotificationsCount: 1, + }; + + expect( + notificationsReducer(state, markRepoNotificationsReadSuccessAction) + ).toEqual(expectedState); + }); + + it('should set an error from the MARK_REPO_AS_READ.ERROR action', () => { + const expectedState = { + ...initialState, + error: authError, + isPendingRepoMarkAsRead: false, + }; + const markRepoNotificationsReadErrorAction = { + type: MARK_REPO_AS_READ.ERROR, + payload: authError, + }; + + expect( + notificationsReducer(initialState, markRepoNotificationsReadErrorAction) + ).toEqual(expectedState); + }); +}); diff --git a/src/notifications/notifications.reducer.js b/src/notifications/notifications.reducer.js index 10181079f..6648ba0ba 100644 --- a/src/notifications/notifications.reducer.js +++ b/src/notifications/notifications.reducer.js @@ -8,7 +8,7 @@ import { MARK_ALL_NOTIFICATIONS_AS_READ, } from './notifications.type'; -const initialState = { +export const initialState = { unread: [], participating: [], all: [],