Merge branch 'develop' into feat/sla-3
This commit is contained in:
@@ -4,6 +4,9 @@ import AccountAPI from '../../api/account';
|
||||
import EnterpriseAccountAPI from '../../api/enterprise/account';
|
||||
import { throwErrorMessage } from '../utils/api';
|
||||
|
||||
const findRecordById = ($state, id) =>
|
||||
$state.records.find(record => record.id === Number(id)) || {};
|
||||
|
||||
const state = {
|
||||
records: [],
|
||||
uiFlags: {
|
||||
@@ -30,10 +33,15 @@ export const getters = {
|
||||
return true;
|
||||
}
|
||||
|
||||
const { features = {} } =
|
||||
$state.records.find(record => record.id === Number(id)) || {};
|
||||
const { features = {} } = findRecordById($state, id);
|
||||
|
||||
return features[featureName] || false;
|
||||
},
|
||||
// There are some features which can be enabled/disabled globally
|
||||
isFeatureEnabledGlobally: $state => (id, featureName) => {
|
||||
const { features = {} } = findRecordById($state, id);
|
||||
return features[featureName] || false;
|
||||
},
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
|
||||
@@ -181,6 +181,14 @@ export const actions = {
|
||||
// Ignore error
|
||||
}
|
||||
},
|
||||
|
||||
resendConfirmation: async () => {
|
||||
try {
|
||||
await authAPI.resendConfirmation();
|
||||
} catch (error) {
|
||||
// Ignore error
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// mutations
|
||||
|
||||
@@ -9,7 +9,7 @@ export const actions = {
|
||||
data: {
|
||||
data: { payload, meta },
|
||||
},
|
||||
} = await NotificationsAPI.get(page);
|
||||
} = await NotificationsAPI.get({ page });
|
||||
commit(types.CLEAR_NOTIFICATIONS);
|
||||
commit(types.SET_NOTIFICATIONS, payload);
|
||||
commit(types.SET_NOTIFICATIONS_META, meta);
|
||||
@@ -18,6 +18,29 @@ export const actions = {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isFetching: false });
|
||||
}
|
||||
},
|
||||
index: async ({ commit }, { page = 1, status, type, sortOrder } = {}) => {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isFetching: true });
|
||||
try {
|
||||
const {
|
||||
data: {
|
||||
data: { payload, meta },
|
||||
},
|
||||
} = await NotificationsAPI.get({
|
||||
page,
|
||||
status,
|
||||
type,
|
||||
sortOrder,
|
||||
});
|
||||
commit(types.SET_NOTIFICATIONS, payload);
|
||||
commit(types.SET_NOTIFICATIONS_META, meta);
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isFetching: false });
|
||||
if (payload.length < 15) {
|
||||
commit(types.SET_ALL_NOTIFICATIONS_LOADED);
|
||||
}
|
||||
} catch (error) {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isFetching: false });
|
||||
}
|
||||
},
|
||||
unReadCount: async ({ commit } = {}) => {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdatingUnreadCount: true });
|
||||
try {
|
||||
@@ -30,14 +53,26 @@ export const actions = {
|
||||
},
|
||||
read: async (
|
||||
{ commit },
|
||||
{ primaryActorType, primaryActorId, unreadCount }
|
||||
{ id, primaryActorType, primaryActorId, unreadCount }
|
||||
) => {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: true });
|
||||
try {
|
||||
await NotificationsAPI.read(primaryActorType, primaryActorId);
|
||||
commit(types.SET_NOTIFICATIONS_UNREAD_COUNT, unreadCount - 1);
|
||||
commit(types.UPDATE_NOTIFICATION, primaryActorId);
|
||||
commit(types.READ_NOTIFICATION, { id, read_at: new Date() });
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false });
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false });
|
||||
}
|
||||
},
|
||||
unread: async ({ commit }, { id }) => {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: true });
|
||||
try {
|
||||
await NotificationsAPI.unRead(id);
|
||||
commit(types.READ_NOTIFICATION, { id, read_at: null });
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false });
|
||||
} catch (error) {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false });
|
||||
}
|
||||
},
|
||||
readAll: async ({ commit }) => {
|
||||
@@ -53,10 +88,75 @@ export const actions = {
|
||||
}
|
||||
},
|
||||
|
||||
delete: async ({ commit }, { notification, count, unreadCount }) => {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true });
|
||||
try {
|
||||
await NotificationsAPI.delete(notification.id);
|
||||
commit(types.SET_NOTIFICATIONS_UNREAD_COUNT, unreadCount - 1);
|
||||
commit(types.DELETE_NOTIFICATION, { notification, count, unreadCount });
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false });
|
||||
} catch (error) {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false });
|
||||
}
|
||||
},
|
||||
|
||||
deleteAllRead: async ({ commit }) => {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true });
|
||||
try {
|
||||
await NotificationsAPI.deleteAll({
|
||||
type: 'read',
|
||||
});
|
||||
commit(types.DELETE_READ_NOTIFICATIONS);
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false });
|
||||
} catch (error) {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false });
|
||||
}
|
||||
},
|
||||
deleteAll: async ({ commit }) => {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true });
|
||||
try {
|
||||
await NotificationsAPI.deleteAll({
|
||||
type: 'all',
|
||||
});
|
||||
commit(types.DELETE_ALL_NOTIFICATIONS);
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false });
|
||||
} catch (error) {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false });
|
||||
}
|
||||
},
|
||||
|
||||
snooze: async ({ commit }, { id, snoozedUntil }) => {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: true });
|
||||
try {
|
||||
const response = await NotificationsAPI.snooze({
|
||||
id,
|
||||
snoozedUntil,
|
||||
});
|
||||
|
||||
const {
|
||||
data: { snoozed_until = null },
|
||||
} = response;
|
||||
commit(types.SNOOZE_NOTIFICATION, {
|
||||
id,
|
||||
snoozed_until,
|
||||
});
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false });
|
||||
} catch (error) {
|
||||
commit(types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false });
|
||||
}
|
||||
},
|
||||
|
||||
updateNotification: async ({ commit }, data) => {
|
||||
commit(types.UPDATE_NOTIFICATION, data);
|
||||
},
|
||||
|
||||
addNotification({ commit }, data) {
|
||||
commit(types.ADD_NOTIFICATION, data);
|
||||
},
|
||||
deleteNotification({ commit }, data) {
|
||||
commit(types.DELETE_NOTIFICATION, data);
|
||||
},
|
||||
clear({ commit }) {
|
||||
commit(types.CLEAR_NOTIFICATIONS);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
import { applyInboxPageFilters, sortComparator } from './helpers';
|
||||
|
||||
export const getters = {
|
||||
getNotifications($state) {
|
||||
return Object.values($state.records).sort((n1, n2) => n2.id - n1.id);
|
||||
},
|
||||
getFilteredNotifications: $state => filters => {
|
||||
const sortOrder = filters.sortOrder === 'desc' ? 'newest' : 'oldest';
|
||||
const filteredNotifications = Object.values($state.records).filter(
|
||||
notification => applyInboxPageFilters(notification, filters)
|
||||
);
|
||||
const sortedNotifications = filteredNotifications.sort((a, b) =>
|
||||
sortComparator(a, b, sortOrder)
|
||||
);
|
||||
return sortedNotifications;
|
||||
},
|
||||
getUIFlags($state) {
|
||||
return $state.uiFlags;
|
||||
},
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
export const filterByStatus = (snoozedUntil, filterStatus) =>
|
||||
filterStatus === 'snoozed' ? !!snoozedUntil : !snoozedUntil;
|
||||
|
||||
export const filterByType = (readAt, filterType) =>
|
||||
filterType === 'read' ? !!readAt : !readAt;
|
||||
|
||||
export const filterByTypeAndStatus = (
|
||||
readAt,
|
||||
snoozedUntil,
|
||||
filterType,
|
||||
filterStatus
|
||||
) => {
|
||||
const shouldFilterByStatus = filterByStatus(snoozedUntil, filterStatus);
|
||||
const shouldFilterByType = filterByType(readAt, filterType);
|
||||
return shouldFilterByStatus && shouldFilterByType;
|
||||
};
|
||||
|
||||
export const applyInboxPageFilters = (notification, filters) => {
|
||||
const { status, type } = filters;
|
||||
const { read_at: readAt, snoozed_until: snoozedUntil } = notification;
|
||||
|
||||
if (status && type)
|
||||
return filterByTypeAndStatus(readAt, snoozedUntil, type, status);
|
||||
if (status && !type) return filterByStatus(snoozedUntil, status);
|
||||
if (!status && type) return filterByType(readAt, type);
|
||||
return true;
|
||||
};
|
||||
|
||||
const INBOX_SORT_OPTIONS = {
|
||||
newest: 'desc',
|
||||
oldest: 'asc',
|
||||
};
|
||||
|
||||
const sortConfig = {
|
||||
newest: (a, b) => b.created_at - a.created_at,
|
||||
oldest: (a, b) => a.created_at - b.created_at,
|
||||
};
|
||||
|
||||
export const sortComparator = (a, b, sortOrder) => {
|
||||
const sortDirection = INBOX_SORT_OPTIONS[sortOrder];
|
||||
if (sortOrder === 'newest' || sortOrder === 'oldest') {
|
||||
return sortConfig[sortOrder](a, b, sortDirection);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
@@ -13,7 +13,9 @@ const state = {
|
||||
isFetching: false,
|
||||
isFetchingItem: false,
|
||||
isUpdating: false,
|
||||
isDeleting: false,
|
||||
isUpdatingUnreadCount: false,
|
||||
isAllNotificationsLoaded: false,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ export const mutations = {
|
||||
},
|
||||
[types.CLEAR_NOTIFICATIONS]: $state => {
|
||||
Vue.set($state, 'records', {});
|
||||
Vue.set($state.uiFlags, 'isAllNotificationsLoaded', false);
|
||||
},
|
||||
[types.SET_NOTIFICATIONS_META]: ($state, data) => {
|
||||
const {
|
||||
@@ -33,12 +34,8 @@ export const mutations = {
|
||||
});
|
||||
});
|
||||
},
|
||||
[types.UPDATE_NOTIFICATION]: ($state, primaryActorId) => {
|
||||
Object.values($state.records).forEach(item => {
|
||||
if (item.primary_actor_id === primaryActorId) {
|
||||
Vue.set($state.records[item.id], 'read_at', true);
|
||||
}
|
||||
});
|
||||
[types.READ_NOTIFICATION]: ($state, { id, read_at }) => {
|
||||
Vue.set($state.records[id], 'read_at', read_at);
|
||||
},
|
||||
[types.UPDATE_ALL_NOTIFICATIONS]: $state => {
|
||||
Object.values($state.records).forEach(item => {
|
||||
@@ -55,10 +52,37 @@ export const mutations = {
|
||||
Vue.set($state.meta, 'unreadCount', unreadCount);
|
||||
Vue.set($state.meta, 'count', count);
|
||||
},
|
||||
[types.UPDATE_NOTIFICATION]($state, data) {
|
||||
const { notification, unread_count: unreadCount, count } = data;
|
||||
Vue.set($state.records, notification.id, {
|
||||
...($state.records[notification.id] || {}),
|
||||
...notification,
|
||||
});
|
||||
Vue.set($state.meta, 'unreadCount', unreadCount);
|
||||
Vue.set($state.meta, 'count', count);
|
||||
},
|
||||
[types.DELETE_NOTIFICATION]($state, data) {
|
||||
const { notification, unread_count: unreadCount, count } = data;
|
||||
Vue.delete($state.records, notification.id);
|
||||
Vue.set($state.meta, 'unreadCount', unreadCount);
|
||||
Vue.set($state.meta, 'count', count);
|
||||
},
|
||||
[types.SET_ALL_NOTIFICATIONS_LOADED]: $state => {
|
||||
Vue.set($state.uiFlags, 'isAllNotificationsLoaded', true);
|
||||
},
|
||||
|
||||
[types.DELETE_READ_NOTIFICATIONS]: $state => {
|
||||
Object.values($state.records).forEach(item => {
|
||||
if (item.read_at) {
|
||||
Vue.delete($state.records, item.id);
|
||||
}
|
||||
});
|
||||
},
|
||||
[types.DELETE_ALL_NOTIFICATIONS]: $state => {
|
||||
Vue.set($state, 'records', {});
|
||||
},
|
||||
|
||||
[types.SNOOZE_NOTIFICATION]: ($state, { id, snoozed_until }) => {
|
||||
Vue.set($state.records[id], 'snoozed_until', snoozed_until);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -4,6 +4,10 @@ const accountData = {
|
||||
id: 1,
|
||||
name: 'Company one',
|
||||
locale: 'en',
|
||||
features: {
|
||||
auto_resolve_conversations: false,
|
||||
agent_management: false,
|
||||
},
|
||||
};
|
||||
|
||||
describe('#getters', () => {
|
||||
@@ -29,4 +33,32 @@ describe('#getters', () => {
|
||||
isDeleting: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('isFeatureEnabledonAccount', () => {
|
||||
const state = {
|
||||
records: [accountData],
|
||||
};
|
||||
const rootGetters = {
|
||||
getCurrentUser: {
|
||||
type: 'SuperAdmin',
|
||||
},
|
||||
};
|
||||
expect(
|
||||
getters.isFeatureEnabledonAccount(
|
||||
state,
|
||||
null,
|
||||
null,
|
||||
rootGetters
|
||||
)(1, 'auto_resolve_conversations')
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
it('isFeatureEnabledGlobally', () => {
|
||||
const state = {
|
||||
records: [accountData],
|
||||
};
|
||||
expect(
|
||||
getters.isFeatureEnabledGlobally(state)(1, 'auto_resolve_conversations')
|
||||
).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ jest.mock('../../../utils/api', () => ({
|
||||
getHeaderExpiry: jest.fn(),
|
||||
}));
|
||||
jest.mock('js-cookie', () => ({
|
||||
getJSON: jest.fn(),
|
||||
get: jest.fn(),
|
||||
}));
|
||||
|
||||
const commit = jest.fn();
|
||||
@@ -155,14 +155,14 @@ describe('#actions', () => {
|
||||
|
||||
describe('#setUser', () => {
|
||||
it('sends correct actions if user is logged in', async () => {
|
||||
Cookies.getJSON.mockImplementation(() => true);
|
||||
Cookies.get.mockImplementation(() => true);
|
||||
actions.setUser({ commit, dispatch });
|
||||
expect(commit.mock.calls).toEqual([]);
|
||||
expect(dispatch.mock.calls).toEqual([['validityCheck']]);
|
||||
});
|
||||
|
||||
it('sends correct actions if user is not logged in', async () => {
|
||||
Cookies.getJSON.mockImplementation(() => false);
|
||||
Cookies.get.mockImplementation(() => false);
|
||||
actions.setUser({ commit, dispatch });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.CLEAR_USER],
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import axios from 'axios';
|
||||
import { actions } from '../../notifications/actions';
|
||||
import types from '../../../mutation-types';
|
||||
|
||||
const commit = jest.fn();
|
||||
global.axios = axios;
|
||||
jest.mock('axios');
|
||||
@@ -39,6 +38,38 @@ describe('#actions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#index', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.get.mockResolvedValue({
|
||||
data: {
|
||||
data: {
|
||||
payload: [{ id: 1 }],
|
||||
meta: { count: 3, current_page: 1, unread_count: 2 },
|
||||
},
|
||||
},
|
||||
});
|
||||
await actions.index({ commit });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isFetching: true }],
|
||||
[types.SET_NOTIFICATIONS, [{ id: 1 }]],
|
||||
[
|
||||
types.SET_NOTIFICATIONS_META,
|
||||
{ count: 3, current_page: 1, unread_count: 2 },
|
||||
],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isFetching: false }],
|
||||
[types.SET_ALL_NOTIFICATIONS_LOADED],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.get.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await actions.index({ commit });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isFetching: true }],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isFetching: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#unReadCount', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.get.mockResolvedValue({ data: 1 });
|
||||
@@ -62,18 +93,91 @@ describe('#actions', () => {
|
||||
describe('#read', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.post.mockResolvedValue({});
|
||||
await actions.read({ commit }, { unreadCount: 2, primaryActorId: 1 });
|
||||
await actions.read(
|
||||
{ commit },
|
||||
{ id: 1, unreadCount: 2, primaryActorId: 1 }
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: true }],
|
||||
[types.SET_NOTIFICATIONS_UNREAD_COUNT, 1],
|
||||
[types.UPDATE_NOTIFICATION, 1],
|
||||
[types.READ_NOTIFICATION, { id: 1, read_at: expect.any(Date) }],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.post.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(actions.read({ commit })).rejects.toThrow(Error);
|
||||
await actions.read(
|
||||
{ commit },
|
||||
{ id: 1, unreadCount: 2, primaryActorId: 1 }
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: true }],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#unread', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.post.mockResolvedValue({});
|
||||
await actions.unread({ commit }, { id: 1 });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
['SET_NOTIFICATIONS_UI_FLAG', { isUpdating: true }],
|
||||
['READ_NOTIFICATION', { id: 1, read_at: null }],
|
||||
['SET_NOTIFICATIONS_UI_FLAG', { isUpdating: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.post.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(actions.unread({ commit })).rejects.toThrow(Error);
|
||||
await actions.unread({ commit }, { id: 1 });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: true }],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#delete', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.delete.mockResolvedValue({});
|
||||
await actions.delete(
|
||||
{ commit },
|
||||
{
|
||||
notification: { id: 1 },
|
||||
count: 2,
|
||||
unreadCount: 1,
|
||||
}
|
||||
);
|
||||
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true }],
|
||||
[types.SET_NOTIFICATIONS_UNREAD_COUNT, 0],
|
||||
[
|
||||
types.DELETE_NOTIFICATION,
|
||||
{ notification: { id: 1 }, count: 2, unreadCount: 1 },
|
||||
],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.delete.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await expect(actions.delete({ commit })).rejects.toThrow(Error);
|
||||
await actions.delete(
|
||||
{ commit },
|
||||
{
|
||||
notification: { id: 1 },
|
||||
count: 2,
|
||||
unreadCount: 1,
|
||||
}
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true }],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
describe('#readAll', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.post.mockResolvedValue({ data: 1 });
|
||||
@@ -107,4 +211,76 @@ describe('#actions', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('clear', () => {
|
||||
it('sends correct actions', async () => {
|
||||
await actions.clear({ commit });
|
||||
expect(commit.mock.calls).toEqual([[types.CLEAR_NOTIFICATIONS]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteAllRead', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.delete.mockResolvedValue({});
|
||||
await actions.deleteAllRead({ commit });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true }],
|
||||
[types.DELETE_READ_NOTIFICATIONS],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.delete.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await actions.deleteAllRead({ commit });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true }],
|
||||
[types.DELETE_READ_NOTIFICATIONS],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteAll', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.delete.mockResolvedValue({});
|
||||
await actions.deleteAll({ commit });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true }],
|
||||
[types.DELETE_ALL_NOTIFICATIONS],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.delete.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await actions.deleteAll({ commit });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: true }],
|
||||
[types.DELETE_ALL_NOTIFICATIONS],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isDeleting: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('snooze', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.post.mockResolvedValue({
|
||||
data: { snoozed_until: '20 Jan, 5.04pm' },
|
||||
});
|
||||
await actions.snooze({ commit }, { id: 1, snoozedUntil: 1703057715 });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: true }],
|
||||
[types.SNOOZE_NOTIFICATION, { id: 1, snoozed_until: '20 Jan, 5.04pm' }],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false }],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.post.mockRejectedValue({ message: 'Incorrect header' });
|
||||
await actions.snooze({ commit }, { id: 1, snoozedUntil: 1703057715 });
|
||||
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: true }],
|
||||
[types.SET_NOTIFICATIONS_UI_FLAG, { isUpdating: false }],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,6 +16,32 @@ describe('#getters', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('getFilteredNotifications', () => {
|
||||
const state = {
|
||||
records: {
|
||||
1: { id: 1, read_at: '2024-02-07T11:42:39.988Z', snoozed_until: null },
|
||||
2: { id: 2, read_at: null, snoozed_until: null },
|
||||
3: {
|
||||
id: 3,
|
||||
read_at: '2024-02-07T11:42:39.988Z',
|
||||
snoozed_until: '2024-02-07T11:42:39.988Z',
|
||||
},
|
||||
},
|
||||
};
|
||||
const filters = {
|
||||
type: 'read',
|
||||
status: 'snoozed',
|
||||
sortOrder: 'desc',
|
||||
};
|
||||
expect(getters.getFilteredNotifications(state)(filters)).toEqual([
|
||||
{
|
||||
id: 3,
|
||||
read_at: '2024-02-07T11:42:39.988Z',
|
||||
snoozed_until: '2024-02-07T11:42:39.988Z',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('getUIFlags', () => {
|
||||
const state = {
|
||||
uiFlags: {
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
import {
|
||||
filterByStatus,
|
||||
filterByType,
|
||||
filterByTypeAndStatus,
|
||||
applyInboxPageFilters,
|
||||
sortComparator,
|
||||
} from '../../notifications/helpers';
|
||||
|
||||
const notifications = [
|
||||
{
|
||||
id: 1,
|
||||
read_at: '2024-02-07T11:42:39.988Z',
|
||||
snoozed_until: null,
|
||||
created_at: 1707328400,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
read_at: null,
|
||||
snoozed_until: null,
|
||||
created_at: 1707233688,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
read_at: '2024-01-07T11:42:39.988Z',
|
||||
snoozed_until: null,
|
||||
created_at: 1707233672,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
read_at: null,
|
||||
snoozed_until: '2024-02-08T03:30:00.000Z',
|
||||
created_at: 1707233667,
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
read_at: '2024-02-07T10:42:39.988Z',
|
||||
snoozed_until: '2024-02-08T03:30:00.000Z',
|
||||
created_at: 1707233662,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
read_at: null,
|
||||
snoozed_until: '2024-02-08T03:30:00.000Z',
|
||||
created_at: 1707233561,
|
||||
},
|
||||
];
|
||||
|
||||
describe('#filterByStatus', () => {
|
||||
it('returns the notifications with snoozed status', () => {
|
||||
const filters = { status: 'snoozed' };
|
||||
notifications.forEach(notification => {
|
||||
expect(
|
||||
filterByStatus(notification.snoozed_until, filters.status)
|
||||
).toEqual(notification.snoozed_until !== null);
|
||||
});
|
||||
});
|
||||
it('returns true if the notification is snoozed', () => {
|
||||
const filters = { status: 'snoozed' };
|
||||
expect(
|
||||
filterByStatus(notifications[3].snoozed_until, filters.status)
|
||||
).toEqual(true);
|
||||
});
|
||||
it('returns false if the notification is not snoozed', () => {
|
||||
const filters = { status: 'snoozed' };
|
||||
expect(
|
||||
filterByStatus(notifications[2].snoozed_until, filters.status)
|
||||
).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#filterByType', () => {
|
||||
it('returns the notifications with read status', () => {
|
||||
const filters = { type: 'read' };
|
||||
notifications.forEach(notification => {
|
||||
expect(filterByType(notification.read_at, filters.type)).toEqual(
|
||||
notification.read_at !== null
|
||||
);
|
||||
});
|
||||
});
|
||||
it('returns true if the notification is read', () => {
|
||||
const filters = { type: 'read' };
|
||||
expect(filterByType(notifications[0].read_at, filters.type)).toEqual(true);
|
||||
});
|
||||
it('returns false if the notification is not read', () => {
|
||||
const filters = { type: 'read' };
|
||||
expect(filterByType(notifications[1].read_at, filters.type)).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#filterByTypeAndStatus', () => {
|
||||
it('returns the notifications with type and status', () => {
|
||||
const filters = { type: 'read', status: 'snoozed' };
|
||||
notifications.forEach(notification => {
|
||||
expect(
|
||||
filterByTypeAndStatus(
|
||||
notification.read_at,
|
||||
notification.snoozed_until,
|
||||
filters.type,
|
||||
filters.status
|
||||
)
|
||||
).toEqual(
|
||||
notification.read_at !== null && notification.snoozed_until !== null
|
||||
);
|
||||
});
|
||||
});
|
||||
it('returns true if the notification is read and snoozed', () => {
|
||||
const filters = { type: 'read', status: 'snoozed' };
|
||||
expect(
|
||||
filterByTypeAndStatus(
|
||||
notifications[4].read_at,
|
||||
notifications[4].snoozed_until,
|
||||
filters.type,
|
||||
filters.status
|
||||
)
|
||||
).toEqual(true);
|
||||
});
|
||||
it('returns false if the notification is not read and snoozed', () => {
|
||||
const filters = { type: 'read', status: 'snoozed' };
|
||||
expect(
|
||||
filterByTypeAndStatus(
|
||||
notifications[3].read_at,
|
||||
notifications[3].snoozed_until,
|
||||
filters.type,
|
||||
filters.status
|
||||
)
|
||||
).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#applyInboxPageFilters', () => {
|
||||
it('returns the notifications with type and status', () => {
|
||||
const filters = { type: 'read', status: 'snoozed' };
|
||||
notifications.forEach(notification => {
|
||||
expect(applyInboxPageFilters(notification, filters)).toEqual(
|
||||
filterByTypeAndStatus(
|
||||
notification.read_at,
|
||||
notification.snoozed_until,
|
||||
filters.type,
|
||||
filters.status
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
it('returns the notifications with type only', () => {
|
||||
const filters = { type: 'read', status: null };
|
||||
notifications.forEach(notification => {
|
||||
expect(applyInboxPageFilters(notification, filters)).toEqual(
|
||||
filterByType(notification.read_at, filters.type)
|
||||
);
|
||||
});
|
||||
});
|
||||
it('returns the notifications with status only', () => {
|
||||
const filters = { type: null, status: 'snoozed' };
|
||||
notifications.forEach(notification => {
|
||||
expect(applyInboxPageFilters(notification, filters)).toEqual(
|
||||
filterByStatus(notification.snoozed_until, filters.status)
|
||||
);
|
||||
});
|
||||
});
|
||||
it('returns true if there are no filters', () => {
|
||||
const filters = { type: null, status: null };
|
||||
notifications.forEach(notification => {
|
||||
expect(applyInboxPageFilters(notification, filters)).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#sortComparator', () => {
|
||||
it('returns the notifications sorted by newest', () => {
|
||||
const sortOrder = 'newest';
|
||||
const sortedNotifications = [...notifications].sort((a, b) =>
|
||||
sortComparator(a, b, sortOrder)
|
||||
);
|
||||
const expectedOrder = [
|
||||
notifications[0],
|
||||
notifications[1],
|
||||
notifications[2],
|
||||
notifications[3],
|
||||
notifications[4],
|
||||
notifications[5],
|
||||
].sort((a, b) => b.created_at - a.created_at);
|
||||
expect(sortedNotifications).toEqual(expectedOrder);
|
||||
});
|
||||
|
||||
it('returns the notifications sorted by oldest', () => {
|
||||
const sortOrder = 'oldest';
|
||||
const sortedNotifications = [...notifications].sort((a, b) =>
|
||||
sortComparator(a, b, sortOrder)
|
||||
);
|
||||
const expectedOrder = [
|
||||
notifications[0],
|
||||
notifications[1],
|
||||
notifications[2],
|
||||
notifications[3],
|
||||
notifications[4],
|
||||
notifications[5],
|
||||
].sort((a, b) => a.created_at - b.created_at);
|
||||
expect(sortedNotifications).toEqual(expectedOrder);
|
||||
});
|
||||
});
|
||||
@@ -12,7 +12,10 @@ describe('#mutations', () => {
|
||||
|
||||
describe('#CLEAR_NOTIFICATIONS', () => {
|
||||
it('clear notifications', () => {
|
||||
const state = { records: { 1: { id: 1 } } };
|
||||
const state = {
|
||||
records: { 1: { id: 1 } },
|
||||
uiFlags: { isAllNotificationsLoaded: true },
|
||||
};
|
||||
mutations[types.CLEAR_NOTIFICATIONS](state);
|
||||
expect(state.records).toEqual({});
|
||||
});
|
||||
@@ -72,7 +75,10 @@ describe('#mutations', () => {
|
||||
1: { id: 1, primary_actor_id: 1 },
|
||||
},
|
||||
};
|
||||
mutations[types.UPDATE_NOTIFICATION](state, 1);
|
||||
mutations[types.READ_NOTIFICATION](state, {
|
||||
id: 1,
|
||||
read_at: true,
|
||||
});
|
||||
expect(state.records).toEqual({
|
||||
1: { id: 1, primary_actor_id: 1, read_at: true },
|
||||
});
|
||||
@@ -141,4 +147,40 @@ describe('#mutations', () => {
|
||||
expect(state.meta.count).toEqual(232);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_ALL_NOTIFICATIONS_LOADED', () => {
|
||||
it('set all notifications loaded', () => {
|
||||
const state = { uiFlags: { isAllNotificationsLoaded: false } };
|
||||
mutations[types.SET_ALL_NOTIFICATIONS_LOADED](state);
|
||||
expect(state.uiFlags).toEqual({ isAllNotificationsLoaded: true });
|
||||
});
|
||||
});
|
||||
|
||||
describe('#DELETE_READ_NOTIFICATIONS', () => {
|
||||
it('delete read notifications', () => {
|
||||
const state = {
|
||||
records: {
|
||||
1: { id: 1, primary_actor_id: 1, read_at: true },
|
||||
2: { id: 2, primary_actor_id: 2 },
|
||||
},
|
||||
};
|
||||
mutations[types.DELETE_READ_NOTIFICATIONS](state);
|
||||
expect(state.records).toEqual({
|
||||
2: { id: 2, primary_actor_id: 2 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#DELETE_ALL_NOTIFICATIONS', () => {
|
||||
it('delete all notifications', () => {
|
||||
const state = {
|
||||
records: {
|
||||
1: { id: 1, primary_actor_id: 1, read_at: true },
|
||||
2: { id: 2, primary_actor_id: 2 },
|
||||
},
|
||||
};
|
||||
mutations[types.DELETE_ALL_NOTIFICATIONS](state);
|
||||
expect(state.records).toEqual({});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user