Skip to content
Closed
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
16 changes: 0 additions & 16 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,4 @@ const config = createConfig('jest', {

// delete config.testURL;

config.reporters = [...(config.reporters || []), ["jest-console-group-reporter", {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add some context as to why we are removing this?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After regenerating package-lock.json, the dependency updates caused the jest-console-group-reporter to fail with a TypeError: Cannot read properties of undefined (reading 'isSet') during the test run.
Since this is just a reporter utility for grouping console logs and its failure was blocking the test suite execution, I removed it to restore stability to the CI pipeline.

// change this setting if need to see less details for each test
// reportType: "summary" | "details",
// enable: true | false,
afterEachTest: {
enable: true,
filePaths: false,
reportType: "details",
},
afterAllTests: {
reportType: "summary",
enable: true,
filePaths: true,
},
}]];

module.exports = config;
12,548 changes: 7,846 additions & 4,702 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@
"eslint-import-resolver-webpack": "^0.13.9",
"jest-console-group-reporter": "^1.1.1",
"jest-when": "^3.6.0",
"rosie": "2.1.1"
"rosie": "2.1.1",
"ts-jest": "^29.4.6"
},
"bundlewatch": {
"files": [
Expand Down
7 changes: 7 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { breakpoints } from '@openedx/paragon';

export const DECODE_ROUTES = {
ACCESS_DENIED: '/course/:courseId/access-denied',
HOME: '/course/:courseId/home',
Expand Down Expand Up @@ -72,3 +74,8 @@ export const LOADED = 'loaded';
export const FAILED = 'failed';
export const DENIED = 'denied';
export type StatusValue = typeof LOADING | typeof LOADED | typeof FAILED | typeof DENIED;

export const BREAKPOINTS = {
LARGE: breakpoints.large.minWidth ?? 992,
MEDIUM: breakpoints.medium.minWidth ?? 768,
} as const;
11 changes: 5 additions & 6 deletions src/courseware/course/Course.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ describe('Course', () => {
it('handles click to open/close discussions sidebar', async () => {
await setupDiscussionSidebar();

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

Expand Down Expand Up @@ -295,7 +295,7 @@ describe('Course', () => {
sequenceId: sequenceBlocks[0].id,
};
render(<Course {...testData} />, { store: testStore, wrapWithRouter: true });
waitFor(() => expect(screen.findByText('Some random banner text to display.')).toBeInTheDocument());
await waitFor(() => expect(screen.getByText('Some random banner text to display.')).toBeInTheDocument());
});

it('renders Entrance Exam alert with passing score', async () => {
Expand Down Expand Up @@ -329,7 +329,7 @@ describe('Course', () => {
sequenceId: sequenceBlocks[0].id,
};
render(<Course {...testData} />, { store: testStore, wrapWithRouter: true });
waitFor(() => expect(screen.findByText('Your score is 100%. You have passed the entrance exam.')).toBeInTheDocument());
await waitFor(() => expect(screen.getByText('Your score is 100%. You have passed the entrance exam.')).toBeInTheDocument());
});

it('renders Entrance Exam alert with non-passing score', async () => {
Expand Down Expand Up @@ -363,7 +363,7 @@ describe('Course', () => {
sequenceId: sequenceBlocks[0].id,
};
render(<Course {...testData} />, { store: testStore, wrapWithRouter: true });
waitFor(() => expect(screen.findByText('To access course materials, you must score 70% or higher on this exam. Your current score is 30%.')).toBeInTheDocument());
await waitFor(() => expect(screen.getByText('To access course materials, you must score 70% or higher on this exam. Your current score is 30%.')).toBeInTheDocument());
});
});

Expand All @@ -381,8 +381,7 @@ describe('Course', () => {
unitId: Object.values(models.units)[0].id,
};
render(<Course {...testData} />, { store: testStore, wrapWithRouter: true });
const learnerTools = screen.queryByTestId(mockLearnerToolsTestId);
await waitFor(() => expect(learnerTools).toBeInTheDocument());
await waitFor(() => expect(screen.queryByTestId(mockLearnerToolsTestId)).toBeInTheDocument());
});

it('does not display learner tools when screen is too narrow (mobile)', async () => {
Expand Down
51 changes: 51 additions & 0 deletions src/courseware/course/sequence/Unit/ContentIFrame.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,57 @@ jest.mock('@edx/frontend-platform/react', () => ({ ErrorPage: () => <div>ErrorPa

jest.mock('@src/generic/PageLoading', () => jest.fn(() => <div>PageLoading</div>));

jest.mock('@openedx/paragon', () => {
const actual = jest.requireActual('@openedx/paragon');
const PropTypes = jest.requireActual('prop-types');

const MockModalDialog = ({ children, isOpen, onClose }) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[important]: Is it possible to abandon the mock of this Paragon component?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this mock resolve third issue about Paragon modal issues in tests in this ticket

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this mock simulates the behavior of a modal window with data-testid="modal-backdrop". However, is it now clear why we’re getting the error TestingLibraryElementError: Unable to find an element by: [data-testid="modal-backdrop"]?

if (!isOpen) { return null; }

return (
<div role="dialog" aria-modal="true" className="mock-modal">
<button
type="button"
data-testid="modal-backdrop"
onClick={onClose}
aria-label="Close"
>
</button>
<div className="mock-modal-content">
{children}
</div>
</div>
);
};

MockModalDialog.propTypes = {
children: PropTypes.node,
isOpen: PropTypes.bool,
onClose: PropTypes.func,
};

const createSubComponent = (baseClass) => {
const Component = ({ children, className }) => (
<div className={`${baseClass} ${className || ''}`}>{children}</div>
);
Component.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
};
return Component;
};

MockModalDialog.Body = createSubComponent('mock-modal-body');
MockModalDialog.Header = createSubComponent('mock-modal-header');
MockModalDialog.Footer = createSubComponent('mock-modal-footer');

return {
...actual,
ModalDialog: MockModalDialog,
};
});

jest.mock('./hooks', () => ({
useIFrameBehavior: jest.fn(),
useModalIFrameData: jest.fn(),
Expand Down
8 changes: 2 additions & 6 deletions src/plugin-slots/LearnerToolsSlot/index.test.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import React from 'react';
import { render } from '@testing-library/react';

jest.mock('@openedx/frontend-plugin-framework', () => ({
PluginSlot: jest.fn(() => <div data-testid="plugin-slot">Plugin Slot</div>),
}));

jest.mock('@edx/frontend-platform/auth', () => ({
getAuthenticatedUser: jest.fn(),
}));
Expand Down Expand Up @@ -103,7 +99,7 @@ describe('LearnerToolsSlot', () => {

render(<LearnerToolsSlot {...defaultProps} />);

// The portal should render to document.body
expect(document.body.querySelector('[data-testid="plugin-slot"]')).toBeInTheDocument();
// The portal should render to document.body with the id as testid
expect(document.body.querySelector('[data-testid="org.openedx.frontend.learning.learner_tools.v1"]')).toBeInTheDocument();
});
});
17 changes: 17 additions & 0 deletions src/product-tours/ProductTours.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ import { buildOutlineFromBlocks } from '../courseware/data/__factories__/learnin

import { UserMessagesProvider } from '../generic/user-messages';
import { DECODE_ROUTES } from '../constants';
import {
DismissButtonFormattedMessage,
NextButtonFormattedMessage,
OkayButtonFormattedMessage,
} from './GenericTourFormattedMessages';

initializeMockApp();
jest.mock('@edx/frontend-platform/analytics');
Expand Down Expand Up @@ -158,6 +163,18 @@ describe('Course Home Tours', () => {
expect(await screen.queryByRole('dialog')).not.toBeInTheDocument();
},
);

describe('GenericTourFormattedMessages', () => {
it('renders all formatted message components to satisfy coverage', () => {
render(<DismissButtonFormattedMessage />);
render(<NextButtonFormattedMessage />);
render(<OkayButtonFormattedMessage />);

expect(screen.getByText('Dismiss')).toBeInTheDocument();
expect(screen.getByText('Next')).toBeInTheDocument();
expect(screen.getByText('Okay')).toBeInTheDocument();
});
});
});

jest.mock(
Expand Down
6 changes: 2 additions & 4 deletions src/setupTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,11 @@ import buildSimpleCourseAndSequenceMetadata from './courseware/data/__factories_
import { buildOutlineFromBlocks } from './courseware/data/__factories__/learningSequencesOutline.factory';

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

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

Expand Down
4 changes: 2 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export const executeThunk = async (thunk, dispatch, getState = undefined) => {
*/
export const appendBrowserTimezoneToUrl = (url: string) => {
const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const urlObject = new URL(url);
const urlObject = new URL(url, url.startsWith('http') ? undefined : 'http://localhost');
if (browserTimezone) {
urlObject.searchParams.append('browser_timezone', browserTimezone);
}
return urlObject.href;
return url.startsWith('http') ? urlObject.href : `${urlObject.pathname}${urlObject.search}`;
};
9 changes: 9 additions & 0 deletions webpack.dev.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,13 @@ config.resolve.alias = {
'@src': path.resolve(__dirname, 'src'),
};

// Fix for react-focus-on webpack 5 compatibility issue
// The package has ES modules without file extensions in imports
config.module.rules.push({
test: /\.m?js$/,
resolve: {
fullySpecified: false,
},
});

module.exports = config;
9 changes: 9 additions & 0 deletions webpack.prod.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,13 @@ config.resolve.alias = {
'@src': path.resolve(__dirname, 'src'),
};

// Fix for react-focus-on webpack 5 compatibility issue
// The package has ES modules without file extensions in imports
config.module.rules.push({
test: /\.m?js$/,
resolve: {
fullySpecified: false,
},
});

module.exports = config;
Loading