test: added redux, selector and api cases

This commit is contained in:
SundasNoreen
2023-06-15 13:57:23 +05:00
parent c3541a3d79
commit 6efa31092d
6 changed files with 97 additions and 52 deletions

57
package-lock.json generated
View File

@@ -16,6 +16,7 @@
"@fortawesome/free-solid-svg-icons": "6.3.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"@reduxjs/toolkit": "1.9.5",
"axios-mock-adapter": "1.21.4",
"babel-polyfill": "6.26.0",
"classnames": "2.3.2",
"lodash": "4.17.21",
@@ -23,6 +24,7 @@
"react-responsive": "8.2.0",
"react-router-dom": "5.3.4",
"react-transition-group": "4.4.5",
"rosie": "2.1.0",
"timeago.js": "4.0.2"
},
"devDependencies": {
@@ -7709,8 +7711,7 @@
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"dev": true
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/at-least-node": {
"version": "1.0.0",
@@ -7799,7 +7800,6 @@
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
"dev": true,
"dependencies": {
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
@@ -7819,6 +7819,40 @@
"url": "https://github.com/ArthurFiorette/axios-cache-interceptor?sponsor=1"
}
},
"node_modules/axios-mock-adapter": {
"version": "1.21.4",
"resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.21.4.tgz",
"integrity": "sha512-ztnENm28ONAKeRXC/6SUW6pcsaXbThKq93MRDRAA47LYTzrGSDoO/DCr1NHz7jApEl95DrBoGPvZ0r9xtSbjqw==",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"is-buffer": "^2.0.5"
},
"peerDependencies": {
"axios": ">= 0.17.0"
}
},
"node_modules/axios-mock-adapter/node_modules/is-buffer": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"engines": {
"node": ">=4"
}
},
"node_modules/axobject-query": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
@@ -9166,7 +9200,6 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dev": true,
"dependencies": {
"delayed-stream": "~1.0.0"
},
@@ -9896,7 +9929,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
@@ -11774,8 +11806,7 @@
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/fast-defer": {
"version": "1.1.7",
@@ -12052,7 +12083,6 @@
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"dev": true,
"funding": [
{
"type": "individual",
@@ -12283,7 +12313,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dev": true,
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
@@ -19203,7 +19232,6 @@
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"engines": {
"node": ">= 0.6"
}
@@ -19212,7 +19240,6 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"dependencies": {
"mime-db": "1.52.0"
},
@@ -22628,6 +22655,14 @@
"rimraf": "bin.js"
}
},
"node_modules/rosie": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/rosie/-/rosie-2.1.0.tgz",
"integrity": "sha512-Dbzdc+prLXZuB/suRptDnBUY29SdGvND3bLg6cll8n7PNqzuyCxSlRfrkn8PqjS9n4QVsiM7RCvxCkKAkTQRjA==",
"engines": {
"node": ">=10"
}
},
"node_modules/rst-selector-parser": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz",

View File

@@ -62,14 +62,16 @@
"@fortawesome/free-solid-svg-icons": "6.3.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"@reduxjs/toolkit": "1.9.5",
"axios-mock-adapter": "1.21.4",
"babel-polyfill": "6.26.0",
"classnames": "2.3.2",
"lodash": "4.17.21",
"react-redux": "7.2.9",
"react-responsive": "8.2.0",
"react-router-dom": "5.3.4",
"react-transition-group": "4.4.5",
"timeago.js": "4.0.2",
"react-router-dom": "5.3.4"
"rosie": "2.1.0",
"timeago.js": "4.0.2"
},
"peerDependencies": {
"@edx/frontend-platform": "^4.0.0",

View File

@@ -1,8 +1,15 @@
import { camelCaseObject } from '@edx/frontend-platform';
import notificationsList from './notifications.json';
import { camelCaseObject, getConfig, snakeCaseObject } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
export const getNotificationsCountApiUrl = () => `${getConfig().LMS_BASE_URL}/api/notifications/count/`;
export const getNotificationsApiUrl = () => `${getConfig().LMS_BASE_URL}/api/notifications/`;
export const markNotificationsSeenApiUrl = (appName) => `${getConfig().LMS_BASE_URL}/api/notifications/mark-notifications-unseen/${appName}/`;
export const markAllNotificationsAsReadpiUrl = (appName, id) => `${getConfig().LMS_BASE_URL}/api/notifications/mark-notifications-read/${appName}/${id}`;
export async function getNotifications(appName, page, pageSize) {
const { data } = notificationsList;
const params = snakeCaseObject({ page, pageSize });
const { data } = await getAuthenticatedHttpClient().get(getNotificationsApiUrl(), { params });
const startIndex = (page - 1) * pageSize;
const endIndex = startIndex + pageSize;
@@ -11,30 +18,25 @@ export async function getNotifications(appName, page, pageSize) {
}
export async function getNotificationCounts() {
const data = {
count: 45,
count_by_app_name: {
reminders: 10,
discussions: 20,
grades: 10,
authoring: 5,
},
show_notification_tray: false,
};
const { data } = await getAuthenticatedHttpClient().get(getNotificationsCountApiUrl());
return camelCaseObject(data);
}
export async function markNotificationSeen() {
const data = [];
export async function markNotificationSeen(appName) {
const { data } = await getAuthenticatedHttpClient().put(`${markNotificationsSeenApiUrl(appName)}`);
return camelCaseObject(data);
}
export async function markAllNotificationRead() {
const { data } = camelCaseObject(notificationsList);
return data;
export async function markAllNotificationRead(appName) {
const { data } = await getAuthenticatedHttpClient().put(`${markAllNotificationsAsReadpiUrl(appName)}`);
return camelCaseObject(data);
}
export async function markNotificationRead(notificationId) {
const { data } = camelCaseObject(notificationsList);
return { data, id: notificationId };
export async function markNotificationRead(appName, notificationId) {
const { data } = await getAuthenticatedHttpClient().put(`${markAllNotificationsAsReadpiUrl(appName, notificationId)}`);
return camelCaseObject({ data, id: notificationId });
}

View File

@@ -40,7 +40,10 @@ describe('Notification Redux', () => {
store = initializeStore();
axiosMock.onGet(notificationCountsApiUrl).reply(200, (Factory.build('notificationsCount')));
axiosMock.onGet(notificationsApiUrl).reply(200, (Factory.buildList('notification', 2, null)));
axiosMock.onGet(notificationsApiUrl).reply(
200,
(Factory.buildList('notification', 2, null, { createdDate: new Date().toISOString() })),
);
await executeThunk(fetchAppsNotificationCount(), store.dispatch, store.getState);
await executeThunk(fetchNotificationList({ page: 1, pageSize: 10 }), store.dispatch, store.getState);
});
@@ -68,9 +71,9 @@ describe('Notification Redux', () => {
});
it('successfully loaded notifications list in the redux.', async () => {
const state = store.getState();
const { notifications: { notifications } } = store.getState();
expect(Object.keys(state.notifications.notifications)).toHaveLength(2);
expect(Object.keys(notifications)).toHaveLength(2);
});
it('successfully loaded notification counts in the redux.', async () => {
@@ -84,9 +87,9 @@ describe('Notification Redux', () => {
});
it('successfully loaded showNotificationTray status in the redux based on api.', async () => {
const state = store.getState();
const { notifications: { showNotificationTray } } = store.getState();
expect(state.notifications.showNotificationTray).toEqual(true);
expect(showNotificationTray).toEqual(true);
});
it('successfully store the count, numPages, currentPage, and nextPage data in redux.', async () => {
@@ -98,15 +101,15 @@ describe('Notification Redux', () => {
});
it('successfully updated the selected app name in redux.', async () => {
const state = store.getState();
const { notifications: { appName } } = store.getState();
expect(state.notifications.appName).toEqual('discussions');
expect(appName).toEqual('discussions');
});
it('successfully store notification ids in the selected app in apps.', async () => {
const state = store.getState();
const { notifications: { apps } } = store.getState();
expect(state.notifications.apps.discussions).toHaveLength(2);
expect(apps.discussions).toHaveLength(2);
});
it('successfully marked all notifications as seen for selected app.', async () => {
@@ -120,10 +123,10 @@ describe('Notification Redux', () => {
axiosMock.onPut(markedAllNotificationsAsReadApiUrl).reply(200);
await executeThunk(markAllNotificationsAsRead('discussions'), store.dispatch, store.getState);
const { notifications } = store.getState();
const firstNotification = Object.values(notifications.notifications)[0];
const { notifications: { notificationStatus, notifications } } = store.getState();
const firstNotification = Object.values(notifications)[0];
expect(notifications.notificationStatus).toEqual('successful');
expect(notificationStatus).toEqual('successful');
expect(firstNotification.lastRead).not.toBeNull();
});
@@ -131,10 +134,10 @@ describe('Notification Redux', () => {
axiosMock.onPut(markedNotificationAsReadApiUrl).reply(200);
await executeThunk(markNotificationsAsRead('discussions', 1), store.dispatch, store.getState);
const { notifications } = store.getState();
const firstNotification = Object.values(notifications.notifications)[0];
const { notifications: { notificationStatus, notifications } } = store.getState();
const firstNotification = Object.values(notifications)[0];
expect(notifications.notificationStatus).toEqual('successful');
expect(notificationStatus).toEqual('successful');
expect(firstNotification.lastRead).not.toBeNull();
});
});

View File

@@ -43,7 +43,10 @@ describe('Notification Selectors', () => {
store = initializeStore();
axiosMock.onGet(notificationCountsApiUrl).reply(200, (Factory.build('notificationsCount')));
axiosMock.onGet(notificationsApiUrl).reply(200, (Factory.buildList('notification', 2, null)));
axiosMock.onGet(notificationsApiUrl).reply(
200,
(Factory.buildList('notification', 2, null, { createdDate: new Date().toISOString() })),
);
await executeThunk(fetchAppsNotificationCount(), store.dispatch, store.getState);
await executeThunk(fetchNotificationList({ page: 1, pageSize: 10 }), store.dispatch, store.getState);
});

View File

@@ -97,11 +97,11 @@ export const markAllNotificationsAsRead = (appName) => (
}
);
export const markNotificationsAsRead = (notificationId) => (
export const markNotificationsAsRead = (appName, notificationId) => (
async (dispatch) => {
try {
dispatch(markNotificationsAsReadRequest({ notificationId }));
const data = await markNotificationRead(notificationId);
const data = await markNotificationRead(appName, notificationId);
dispatch(markNotificationsAsReadSuccess(data));
} catch (error) {
if (getHttpErrorStatus(error) === 403) {