Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: added test cases for UI components #360

Merged
merged 3 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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-notification-${id}`} />
</div>
)}
</div>
Expand Down
10 changes: 8 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,16 @@ 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-notifications"
>
{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
109 changes: 109 additions & 0 deletions src/Notifications/index.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
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;

function renderComponent() {
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();
});

async function setupMockNotificationCountResponse(count = 45, showNotificationsTray = true) {
axiosMock.onGet(notificationCountsApiUrl)
.reply(200, (Factory.build('notificationsCount', { count, showNotificationsTray })));
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 setupMockNotificationCountResponse();
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 showed bell icon and hide unseen count tag when unseen count is zero.', async () => {
await setupMockNotificationCountResponse(0);
renderComponent();

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

expect(bellIcon).toBeInTheDocument();
expect(notificationCount).not.toBeInTheDocument();
});

it('Successfully hides bell icon when showNotificationsTray is false.', async () => {
await setupMockNotificationCountResponse(45, false);
renderComponent();

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

expect(bellIcon).not.toBeInTheDocument();
});

it('Successfully viewed setting icon and show/hide notification tray by clicking on the bell icon .', async () => {
await setupMockNotificationCountResponse();
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 mockNotificationsResponse from './test-utils';

import './data/__factories__';

const markedNotificationAsReadApiUrl = markNotificationAsReadApiUrl();

let axiosMock;
let store;

function renderComponent() {
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 mockNotificationsResponse());
});

it(
'Successfully viewed notification icon, notification context, unread , course name and notification time.',
async () => {
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-notification-1')).toBeInTheDocument();
},
);

it('Successfully marked notification as read.', async () => {
axiosMock.onPut(markedNotificationAsReadApiUrl).reply(200, { message: 'Notification marked read.' });
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-notification-1')).not.toBeInTheDocument();
});
});
Loading