Skip to content
Open
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
4,708 changes: 2,637 additions & 2,071 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
"@fortawesome/free-regular-svg-icons": "5.15.4",
"@fortawesome/free-solid-svg-icons": "5.15.4",
"@fortawesome/react-fontawesome": "^0.1.4",
"@openedx/frontend-build": "^14.6.2",
"@openedx/frontend-plugin-framework": "^1.7.0",
"@openedx/paragon": "^23.4.5",
"@popperjs/core": "2.11.8",
Expand Down Expand Up @@ -74,14 +73,14 @@
"truncate-html": "1.0.4"
},
"devDependencies": {
"@openedx/frontend-build": "^14.6.2",
"@pact-foundation/pact": "^13.0.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"@testing-library/user-event": "14.6.1",
"axios-mock-adapter": "2.1.0",
"bundlewatch": "^0.4.0",
"eslint-import-resolver-webpack": "^0.13.9",
"jest": "^29.7.0",
"jest-console-group-reporter": "^1.1.1",
"jest-when": "^3.6.0",
"rosie": "2.1.1"
Expand Down
21 changes: 10 additions & 11 deletions src/courseware/course/Course.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,23 +191,22 @@ describe('Course', () => {
const { rerender } = render(<Course {...testData} />, { store: testStore });
loadUnit();

waitFor(() => {
expect(screen.findByTestId('sidebar-DISCUSSIONS')).toBeInTheDocument();
expect(screen.findByTestId('sidebar-DISCUSSIONS')).not.toHaveClass('d-none');
});
const sidebar = await screen.findByTestId('sidebar-DISCUSSIONS');
expect(sidebar).toBeInTheDocument();
expect(sidebar).not.toHaveClass('d-none');

rerender(null);
});

it('handles click to open/close notification tray', async () => {
await setupDiscussionSidebar();
waitFor(() => {
const notificationShowButton = screen.findByRole('button', { name: /Show notification tray/i });
expect(screen.queryByRole('region', { name: /notification tray/i })).not.toBeInTheDocument();
fireEvent.click(notificationShowButton);
expect(screen.queryByRole('region', { name: /notification tray/i })).toBeInTheDocument();
expect(screen.queryByRole('region', { name: /notification tray/i })).not.toHaveClass('d-none');
});
const notificationShowButton = await screen.findByRole('button', { name: /Show notification tray/i });
expect(screen.queryByRole('region', { name: /notification tray/i })).not.toBeInTheDocument();
fireEvent.click(notificationShowButton);

const notificationTray = await screen.findByRole('region', { name: /notification tray/i });
expect(notificationTray).toBeInTheDocument();
expect(notificationTray).not.toHaveClass('d-none');
});

it('doesn\'t renders course breadcrumbs by default', async () => {
Expand Down
4 changes: 2 additions & 2 deletions src/courseware/course/new-sidebar/SidebarContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ const SidebarProvider: React.FC<Props> = ({
const { verifiedMode } = useModel('courseHomeMeta', courseId);
const topic = useModel('discussionTopics', unitId);
const windowWidth = useWindowSize().width ?? window.innerWidth;
const shouldDisplayFullScreen = windowWidth < breakpoints.large.minWidth;
const shouldDisplaySidebarOpen = windowWidth > breakpoints.medium.minWidth;
const shouldDisplayFullScreen = windowWidth < breakpoints.large.minWidth!;
const shouldDisplaySidebarOpen = windowWidth > breakpoints.medium.minWidth!;
const query = new URLSearchParams(window.location.search);
const isInitiallySidebarOpen = shouldDisplaySidebarOpen || query.get('sidebar') === 'true';
const sidebarKey = `sidebar.${courseId}`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('NotificationsWidget', () => {
}

beforeEach(async () => {
global.innerWidth = breakpoints.large.minWidth;
global.innerWidth = breakpoints.large.minWidth!;
store = initializeStore();
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(courseMetadataUrl).reply(200, defaultMetadata);
Expand Down
28 changes: 17 additions & 11 deletions src/courseware/course/sequence/Unit/ContentIFrame.test.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { render, screen } from '@testing-library/react';
import { IntlProvider } from '@edx/frontend-platform/i18n';

import * as hooks from './hooks';
import ContentIFrame, { IFRAME_FEATURE_POLICY } from './ContentIFrame';

// eslint-disable-next-line react/prop-types
const IntlWrapper = ({ children }) => (
<IntlProvider locale="en">{children}</IntlProvider>
);

jest.mock('@edx/frontend-platform/react', () => ({ ErrorPage: () => <div>ErrorPage</div> }));

jest.mock('@src/generic/PageLoading', () => jest.fn(() => <div>PageLoading</div>));
Expand Down Expand Up @@ -59,7 +65,7 @@ describe('ContentIFrame Component', () => {
});
describe('behavior', () => {
beforeEach(() => {
render(<ContentIFrame {...props} />);
render(<ContentIFrame {...props} />, { wrapper: IntlWrapper });
});
it('initializes iframe behavior hook', () => {
expect(hooks.useIFrameBehavior).toHaveBeenCalledWith({
Expand All @@ -78,28 +84,28 @@ describe('ContentIFrame Component', () => {
describe('if not hasLoaded', () => {
it('displays errorPage if showError', () => {
hooks.useIFrameBehavior.mockReturnValueOnce({ ...iframeBehavior, showError: true });
render(<ContentIFrame {...props} />);
render(<ContentIFrame {...props} />, { wrapper: IntlWrapper });
const errorPage = screen.getByText('ErrorPage');
expect(errorPage).toBeInTheDocument();
});
it('displays PageLoading component if not showError', () => {
render(<ContentIFrame {...props} />);
render(<ContentIFrame {...props} />, { wrapper: IntlWrapper });
const pageLoading = screen.getByText('PageLoading');
expect(pageLoading).toBeInTheDocument();
});
});
describe('hasLoaded', () => {
it('does not display PageLoading or ErrorPage', () => {
hooks.useIFrameBehavior.mockReturnValueOnce({ ...iframeBehavior, hasLoaded: true });
render(<ContentIFrame {...props} />);
render(<ContentIFrame {...props} />, { wrapper: IntlWrapper });
const pageLoading = screen.queryByText('PageLoading');
expect(pageLoading).toBeNull();
const errorPage = screen.queryByText('ErrorPage');
expect(errorPage).toBeNull();
});
});
it('display iframe with props from hooks', () => {
render(<ContentIFrame {...props} />);
render(<ContentIFrame {...props} />, { wrapper: IntlWrapper });
const iframe = screen.getByTitle(props.title);
expect(iframe).toBeInTheDocument();
expect(iframe).toHaveAttribute('id', props.elementId);
Expand All @@ -112,14 +118,14 @@ describe('ContentIFrame Component', () => {
});
describe('if not shouldShowContent', () => {
it('does not show PageLoading, ErrorPage, or unit-iframe-wrapper', () => {
render(<ContentIFrame {...{ ...props, shouldShowContent: false }} />);
render(<ContentIFrame {...{ ...props, shouldShowContent: false }} />, { wrapper: IntlWrapper });
expect(screen.queryByText('PageLoading')).toBeNull();
expect(screen.queryByText('ErrorPage')).toBeNull();
expect(screen.queryByTitle(props.title)).toBeNull();
});
});
it('does not display modal if modalOptions returns isOpen: false', () => {
render(<ContentIFrame {...props} />);
render(<ContentIFrame {...props} />, { wrapper: IntlWrapper });
const modal = screen.queryByRole('dialog');
expect(modal).toBeNull();
});
Expand All @@ -138,7 +144,7 @@ describe('ContentIFrame Component', () => {
...modalIFrameData,
modalOptions: { ...modalOptions.withBody, isFullscreen: true },
});
render(<ContentIFrame {...props} />);
render(<ContentIFrame {...props} />, { wrapper: IntlWrapper });
});
it('displays Modal with div wrapping provided body content if modal.body is provided', () => {
const dialog = screen.getByRole('dialog');
Expand All @@ -155,7 +161,7 @@ describe('ContentIFrame Component', () => {
...modalIFrameData,
modalOptions: { ...modalOptions.withUrl, isFullscreen: true },
});
render(<ContentIFrame {...props} />);
render(<ContentIFrame {...props} />, { wrapper: IntlWrapper });
});
it('displays Modal with iframe to provided url if modal.body is not provided', () => {
const iframe = screen.getByTitle(modalOptions.withUrl.title);
Expand All @@ -169,7 +175,7 @@ describe('ContentIFrame Component', () => {
describe('body modal', () => {
beforeEach(() => {
hooks.useModalIFrameData.mockReturnValueOnce({ ...modalIFrameData, modalOptions: modalOptions.withBody });
render(<ContentIFrame {...props} />);
render(<ContentIFrame {...props} />, { wrapper: IntlWrapper });
});
it('displays Modal with div wrapping provided body content if modal.body is provided', () => {
const dialog = screen.getByRole('dialog');
Expand All @@ -182,7 +188,7 @@ describe('ContentIFrame Component', () => {
describe('url modal', () => {
beforeEach(() => {
hooks.useModalIFrameData.mockReturnValueOnce({ ...modalIFrameData, modalOptions: modalOptions.withUrl });
render(<ContentIFrame {...props} />);
render(<ContentIFrame {...props} />, { wrapper: IntlWrapper });
});
it('displays Modal with iframe to provided url if modal.body is not provided', () => {
const iframe = screen.getByTitle(modalOptions.withUrl.title);
Expand Down
15 changes: 10 additions & 5 deletions src/plugin-slots/LearnerToolsSlot/index.test.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import React from 'react';
import { render } from '@testing-library/react';
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import * as auth from '@edx/frontend-platform/auth';

import { LearnerToolsSlot } from './index';

jest.mock('@openedx/frontend-plugin-framework', () => ({
PluginSlot: jest.fn(() => <div data-testid="plugin-slot">Plugin Slot</div>),
Expand All @@ -14,17 +10,26 @@ jest.mock('@edx/frontend-platform/auth', () => ({
}));

describe('LearnerToolsSlot', () => {
let auth;
let PluginSlot;
let LearnerToolsSlot;

const defaultProps = {
courseId: 'course-v1:edX+DemoX+Demo_Course',
unitId: 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@unit1',
isStaff: false,
enrollmentMode: 'verified',
};

beforeEach(() => {
beforeEach(async () => {
jest.resetModules();
jest.clearAllMocks();
// Mock document.body for createPortal
document.body.innerHTML = '<div id="root"></div>';

auth = await import('@edx/frontend-platform/auth');
({ PluginSlot } = await import('@openedx/frontend-plugin-framework'));
({ LearnerToolsSlot } = await import('./index'));
});

it('renders PluginSlot with correct props when user is authenticated', () => {
Expand Down
16 changes: 10 additions & 6 deletions src/setupTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ import { getCourseOutlineStructure } from './courseware/data/thunks';
import { appendBrowserTimezoneToUrl, executeThunk } from './utils';
import buildSimpleCourseAndSequenceMetadata from './courseware/data/__factories__/sequenceMetadata.factory';
import { buildOutlineFromBlocks } from './courseware/data/__factories__/learningSequencesOutline.factory';
import MockedPluginSlot from './tests/MockedPluginSlot';

jest.mock('@openedx/frontend-plugin-framework', () => ({
...jest.requireActual('@openedx/frontend-plugin-framework'),
Plugin: () => 'Plugin',
PluginSlot: MockedPluginSlot,
}));
jest.mock('@openedx/frontend-plugin-framework', () => {
// eslint-disable-next-line global-require
const MockedPluginSlot = require('./tests/MockedPluginSlot').default;

return {
...jest.requireActual('@openedx/frontend-plugin-framework'),
Plugin: () => 'Plugin',
PluginSlot: MockedPluginSlot,
};
});

jest.mock('@src/generic/plugin-store', () => ({
...jest.requireActual('@src/generic/plugin-store'),
Expand Down