Skip to content

Commit

Permalink
test: added test cases for UI components
Browse files Browse the repository at this point in the history
  • Loading branch information
SundasNoreen committed Jun 26, 2023
1 parent 45a1da9 commit 0e6a272
Show file tree
Hide file tree
Showing 9 changed files with 418 additions and 9 deletions.
18 changes: 13 additions & 5 deletions src/Notifications/NotificationRowItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,35 @@ const NotificationRowItem = ({
className="d-flex mb-2 align-items-center text-decoration-none"
to={contentUrl}
onClick={handleMarkAsRead}
data-testid={`notification-${id}`}
>
<Icon src={iconComponent} className={`${iconClass} mr-4 notification-icon`} />
<div className="d-flex w-100">
<Icon
src={iconComponent}
className={`${iconClass} mr-4 notification-icon`}
data-testid={`notification-icon-${id}`}
/>
<div className="d-flex w-100" data-testid="notification-contents">
<div className="d-flex align-items-center w-100">
<div className="py-10px w-100 px-0 cursor-pointer">
<span
className="line-height-24 text-gray-700 mb-2 notification-item-content overflow-hidden content"
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: content }}
data-testid={`notification-content-${id}`}
/>
<div className="py-0 d-flex">
<span className="font-size-12 text-gray-500 line-height-20">
<span>{courseName}</span>
<span data-testid={`notification-course-${id}`}>{courseName}
</span>
<span className="text-light-700 px-1.5">{intl.formatMessage(messages.fullStop)}</span>
<span>{timeago.format(createdAt, 'time-locale')}</span>
<span data-testid={`notification-created-date-${id}`}> {timeago.format(createdAt, 'time-locale')}
</span>
</span>
</div>
</div>
{!lastRead && (
<div className="d-flex py-1.5 px-1.5 ml-2 cursor-pointer">
<span className="bg-brand-500 rounded unread" />
<span className="bg-brand-500 rounded unread" data-testid={`unread-${id}`} />
</div>
)}
</div>
Expand Down
5 changes: 3 additions & 2 deletions src/Notifications/NotificationSections.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const NotificationSections = () => {
variant="link"
className="text-info-500 font-size-14 line-height-10 text-decoration-none p-0 border-0"
onClick={handleMarkAllAsRead}
data-testid="mark-all-read"
>
{intl.formatMessage(messages.notificationMarkAsRead)}
</Button>
Expand All @@ -66,11 +67,11 @@ const NotificationSections = () => {
};

return (
<div className="mt-4 px-4">
<div className="mt-4 px-4" data-testid="notification-tray-section">
{renderNotificationSection('today', today)}
{renderNotificationSection('earlier', earlier)}
{currentPage < numPages && (
<Button variant="primary" className="w-100 bg-primary-500" onClick={updatePagination}>
<Button variant="primary" className="w-100 bg-primary-500" onClick={updatePagination} data-testid="load-more">
{intl.formatMessage(messages.loadMoreNotifications)}
</Button>
)}
Expand Down
1 change: 1 addition & 0 deletions src/Notifications/NotificationTabs.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const NotificationTabs = () => {
title={appName}
notification={notificationUnseenCounts[appName]}
tabClassName="pt-0 pb-10px px-2.5 d-flex border-top-0 mb-0 align-items-center line-height-24 text-capitalize"
data-testid={`notification-tab-${appName}`}
>
{appName === selectedAppName && (<NotificationSections />)}
</Tab>
Expand Down
6 changes: 4 additions & 2 deletions src/Notifications/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const Notifications = () => {
overlay={(
<Popover
id="notificationTray"
data-testid="notificationTray"
data-testid="notification-tray"
className={classNames('overflow-auto rounded-0 border-0', {
'w-100': !isOnMediumScreen && !isOnLargeScreen,
'medium-screen': isOnMediumScreen,
Expand All @@ -64,7 +64,7 @@ const Notifications = () => {
<div ref={popoverRef}>
<Popover.Title as="h2" className="d-flex justify-content-between p-0 m-4 border-0 text-primary-500 font-size-18 line-height-24">
{intl.formatMessage(messages.notificationTitle)}
<Icon src={Settings} className="icon-size-20" />
<Icon src={Settings} className="icon-size-20" data-testid="setting-icon" />
</Popover.Title>
<Popover.Content className="notification-content p-0">
<NotificationTabs />
Expand All @@ -83,12 +83,14 @@ const Notifications = () => {
variant="light"
iconClassNames="text-primary-500"
className="ml-4 mr-1 my-3 notification-button"
data-testid="notification-bell-icon"
/>
{notificationCounts?.count > 0 && (
<Badge
pill
variant="danger"
className="font-weight-normal px-1 notification-badge"
data-testid="notification-count"
>
{notificationCounts.count}
</Badge>
Expand Down
84 changes: 84 additions & 0 deletions src/Notifications/index.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React from 'react';

import {
act, fireEvent, render, screen, waitFor,
} from '@testing-library/react';
import MockAdapter from 'axios-mock-adapter';
import { Context as ResponsiveContext } from 'react-responsive';
import { Factory } from 'rosie';

import { initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { AppContext, AppProvider } from '@edx/frontend-platform/react';

import AuthenticatedUserDropdown from '../learning-header/AuthenticatedUserDropdown';
import { initializeStore } from '../store';
import executeThunk from '../test-utils';
import { getNotificationsCountApiUrl } from './data/api';
import { fetchAppsNotificationCount } from './data/thunks';

import './data/__factories__';

const notificationCountsApiUrl = getNotificationsCountApiUrl();

let axiosMock;
let store;

async function renderComponent() {
await render(
<ResponsiveContext.Provider>
<IntlProvider locale="en" messages={{}}>
<AppProvider store={store}>
<AppContext.Provider>
<AuthenticatedUserDropdown />
</AppContext.Provider>
</AppProvider>
</IntlProvider>
</ResponsiveContext.Provider>,
);
}

describe('Notification test cases.', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: '123abc',
username: 'testuser',
administrator: false,
roles: [],
},
});

axiosMock = new MockAdapter(getAuthenticatedHttpClient());
Factory.resetAll();
store = initializeStore();

axiosMock.onGet(notificationCountsApiUrl).reply(200, (Factory.build('notificationsCount')));
await executeThunk(fetchAppsNotificationCount(), store.dispatch, store.getState);
});

it('successfully showed bell icon and unseen count on it if unseen count is greater then 0.', async () => {
await renderComponent();

const bellIcon = screen.queryByTestId('notification-bell-icon');
const notificationCount = screen.queryByTestId('notification-count');

expect(bellIcon).toBeInTheDocument();
expect(notificationCount).toBeInTheDocument();
expect(screen.queryByText(45)).toBeInTheDocument();
});

it('successfully show/hide notification tray by clicking on the bell icon and setting icon.', async () => {
await renderComponent();

const bellIcon = screen.queryByTestId('notification-bell-icon');

await act(async () => { fireEvent.click(bellIcon); });
expect(screen.queryByTestId('notification-tray')).toBeInTheDocument();
expect(screen.queryByTestId('setting-icon')).toBeInTheDocument();

await act(async () => { fireEvent.click(bellIcon); });
await waitFor(() => expect(screen.queryByTestId('notification-tray')).not.toBeInTheDocument());
});
});
87 changes: 87 additions & 0 deletions src/Notifications/notificationRowItem.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';

import {
act, fireEvent, render, screen,
} from '@testing-library/react';
import MockAdapter from 'axios-mock-adapter';
import { Context as ResponsiveContext } from 'react-responsive';
import { Factory } from 'rosie';

import { initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { AppContext, AppProvider } from '@edx/frontend-platform/react';

import AuthenticatedUserDropdown from '../learning-header/AuthenticatedUserDropdown';
import { initializeStore } from '../store';
import { markNotificationAsReadApiUrl } from './data/api';
import setupLearnerMockResponse from './test-utils';

import './data/__factories__';

const markedNotificationAsReadApiUrl = markNotificationAsReadApiUrl();

let axiosMock;
let store;

async function renderComponent() {
await render(
<ResponsiveContext.Provider>
<IntlProvider locale="en" messages={{}}>
<AppProvider store={store}>
<AppContext.Provider>
<AuthenticatedUserDropdown />
</AppContext.Provider>
</AppProvider>
</IntlProvider>
</ResponsiveContext.Provider>,
);
}

describe('Notification row item test cases.', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});

axiosMock = new MockAdapter(getAuthenticatedHttpClient());
Factory.resetAll();
store = initializeStore();

({ store, axiosMock } = await setupLearnerMockResponse());
});

it(
'Successfully viewed notification icon, notification context, unread , course name and notification time.',
async () => {
await renderComponent();

const bellIcon = screen.queryByTestId('notification-bell-icon');
await act(async () => { fireEvent.click(bellIcon); });

expect(screen.queryByTestId('notification-icon-1')).toBeInTheDocument();
expect(screen.queryByTestId('notification-content-1')).toBeInTheDocument();
expect(screen.queryByTestId('notification-course-1')).toBeInTheDocument();
expect(screen.queryByTestId('notification-created-date-1')).toBeInTheDocument();
expect(screen.queryByTestId('unread-1')).toBeInTheDocument();
},
);

it('Successfully marked notification as read.', async () => {
axiosMock.onPut(markedNotificationAsReadApiUrl).reply(200, { message: 'Notification marked read.' });
await renderComponent();

const bellIcon = screen.queryByTestId('notification-bell-icon');
await act(async () => { fireEvent.click(bellIcon); });

const notification = screen.queryByTestId('notification-1');
await act(async () => { fireEvent.click(notification); });

expect(screen.queryByTestId('unread-1')).not.toBeInTheDocument();
});
});
101 changes: 101 additions & 0 deletions src/Notifications/notificationSections.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from 'react';

import {
act, fireEvent, render, screen, within,
} from '@testing-library/react';
import MockAdapter from 'axios-mock-adapter';
import { Context as ResponsiveContext } from 'react-responsive';
import { Factory } from 'rosie';

import { initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { AppContext, AppProvider } from '@edx/frontend-platform/react';

import AuthenticatedUserDropdown from '../learning-header/AuthenticatedUserDropdown';
import { initializeStore } from '../store';
import { markNotificationAsReadApiUrl } from './data/api';
import setupLearnerMockResponse from './test-utils';

import './data/__factories__';

const markedAllNotificationsAsReadApiUrl = markNotificationAsReadApiUrl();

let axiosMock;
let store;

async function renderComponent() {
await render(
<ResponsiveContext.Provider>
<IntlProvider locale="en" messages={{}}>
<AppProvider store={store}>
<AppContext.Provider>
<AuthenticatedUserDropdown />
</AppContext.Provider>
</AppProvider>
</IntlProvider>
</ResponsiveContext.Provider>,
);
}

describe('Notification sections test cases.', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});

axiosMock = new MockAdapter(getAuthenticatedHttpClient());
Factory.resetAll();
store = initializeStore();

({ store, axiosMock } = await setupLearnerMockResponse());
});

it('Successfully viewed last 24 hours and earlier section along with nark all as read label.', async () => {
await renderComponent();

const bellIcon = screen.queryByTestId('notification-bell-icon');
await act(async () => { fireEvent.click(bellIcon); });
const notificationTraySection = screen.queryByTestId('notification-tray-section');

expect(within(notificationTraySection).queryByText('Last 24 hours')).toBeInTheDocument();
expect(within(notificationTraySection).queryByText('Earlier')).toBeInTheDocument();
expect(within(notificationTraySection).queryByText('Mark all as read')).toBeInTheDocument();
});

it(
'Successfully clicks on the mark all as read, the unread status disappeared across all the notifications',
async () => {
axiosMock.onPut(markedAllNotificationsAsReadApiUrl).reply(200, { message: 'Notifications marked read.' });
await renderComponent();

const bellIcon = screen.queryByTestId('notification-bell-icon');
await act(async () => { fireEvent.click(bellIcon); });
const markAllReadButton = screen.queryByTestId('mark-all-read');

expect(screen.queryByTestId('unread-1')).toBeInTheDocument();
await act(async () => { fireEvent.click(markAllReadButton); });

expect(screen.queryByTestId('unread-1')).not.toBeInTheDocument();
},
);

it('Successfully load more notifications by clicking on load more notification button.', async () => {
await renderComponent();

const bellIcon = screen.queryByTestId('notification-bell-icon');
await act(async () => { fireEvent.click(bellIcon); });

const loadMoreButton = screen.queryByTestId('load-more');

expect(screen.queryAllByTestId('notification-contents')).toHaveLength(10);
await act(async () => { fireEvent.click(loadMoreButton); });

expect(screen.queryAllByTestId('notification-contents')).toHaveLength(16);
});
});
Loading

0 comments on commit 0e6a272

Please sign in to comment.