Skip to content
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
1 change: 0 additions & 1 deletion .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ ENABLE_ACCESSIBILITY_PAGE=false
ENABLE_PROGRESS_GRAPH_SETTINGS=false
ENABLE_TEAM_TYPE_SETTING=false
ENABLE_NEW_EDITOR_PAGES=true
ENABLE_NEW_HOME_PAGE = false
ENABLE_NEW_COURSE_OUTLINE_PAGE = false
ENABLE_NEW_VIDEO_UPLOAD_PAGE = false
ENABLE_NEW_GRADING_PAGE = false
Expand Down
18 changes: 18 additions & 0 deletions src/AppFooter.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Footer } from '@edx/frontend-lib-content-components';

const AppFooter = () => (
<div className="mt-6">
<Footer
marketingBaseUrl={process.env.MARKETING_SITE_BASE_URL}
termsOfServiceUrl={process.env.TERMS_OF_SERVICE_URL}
privacyPolicyUrl={process.env.PRIVACY_POLICY_URL}
supportEmail={process.env.SUPPORT_EMAIL}
platformName={process.env.SITE_NAME}
lmsBaseUrl={process.env.LMS_BASE_URL}
studioBaseUrl={process.env.STUDIO_BASE_URL}
showAccessibilityPage={process.env.ENABLE_ACCESSIBILITY_PAGE === 'true'}
/>
</div>
);

export default AppFooter;
17 changes: 17 additions & 0 deletions src/AppFooter.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { render } from '@testing-library/react';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import AppFooter from './AppFooter';

describe('<AppFooter />', () => {
const RootWrapper = () => (
<IntlProvider locale="en">
<AppFooter />
</IntlProvider>
);
it('should render the footer successfully', () => {
const { getByText } = render(<RootWrapper />);
expect(getByText('Looking for help with Studio?')).toBeInTheDocument();
expect(getByText('LMS')).toHaveAttribute('href', process.env.LMS_BASE_URL);
});
});
17 changes: 1 addition & 16 deletions src/CourseAuthoringPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { useDispatch, useSelector } from 'react-redux';
import {
useLocation,
} from 'react-router-dom';
import { Footer } from '@edx/frontend-lib-content-components';
import Header from './studio-header/Header';
import { fetchCourseDetail } from './data/thunks';
import { useModel } from './generic/model-store';
import PermissionDeniedAlert from './generic/PermissionDeniedAlert';
import { getCourseAppsApiStatus } from './pages-and-resources/data/selectors';
import { RequestStatus } from './data/constants';
import Loading from './generic/Loading';
import AppFooter from './AppFooter';

const AppHeader = ({
courseNumber, courseOrg, courseTitle, courseId,
Expand All @@ -37,21 +37,6 @@ AppHeader.defaultProps = {
courseOrg: null,
};

const AppFooter = () => (
<div className="mt-6">
<Footer
marketingBaseUrl={process.env.MARKETING_SITE_BASE_URL}
termsOfServiceUrl={process.env.TERMS_OF_SERVICE_URL}
privacyPolicyUrl={process.env.PRIVACY_POLICY_URL}
supportEmail={process.env.SUPPORT_EMAIL}
platformName={process.env.SITE_NAME}
lmsBaseUrl={process.env.LMS_BASE_URL}
studioBaseUrl={process.env.STUDIO_BASE_URL}
showAccessibilityPage={process.env.ENABLE_ACCESSIBILITY_PAGE === 'true'}
/>
</div>
);

const CourseAuthoringPage = ({ courseId, children }) => {
const dispatch = useDispatch();

Expand Down
8 changes: 2 additions & 6 deletions src/CourseAuthoringRoutes.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,7 @@ describe('<CourseAuthoringRoutes>', () => {
store = initializeStore();
});

// TODO: This test needs to be corrected.
// The problem arose after moving new commits (https://github.com/raccoongang/frontend-app-course-authoring/pull/25)
it.skip('renders the PagesAndResources component when the pages and resources route is active', () => {
it('renders the PagesAndResources component when the pages and resources route is active', () => {
render(
<AppProvider store={store}>
<MemoryRouter initialEntries={[`/course/${courseId}/pages-and-resources`]}>
Expand All @@ -85,9 +83,7 @@ describe('<CourseAuthoringRoutes>', () => {
);
});

// TODO: This test needs to be corrected.
// The problem arose after moving new commits (https://github.com/raccoongang/frontend-app-course-authoring/pull/25)
it.skip('renders the ProctoredExamSettings component when the proctored exam settings route is active', () => {
it('renders the ProctoredExamSettings component when the proctored exam settings route is active', () => {
render(
<AppProvider store={store}>
<MemoryRouter initialEntries={[`/course/${courseId}/proctored-exam-settings`]}>
Expand Down
2 changes: 1 addition & 1 deletion src/advanced-settings/settings-sidebar/SettingsSidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
} from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';

import HelpSidebar from '../../generic/help-sidebar';
import { HelpSidebar } from '../../generic/help-sidebar';
import messages from './messages';

const SettingsSidebar = ({ intl, courseId, proctoredExamSettingsUrl }) => (
Expand Down
11 changes: 11 additions & 0 deletions src/assets/scss/_form.scss
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,14 @@
color: $black;
}
}

.dropdown-group-wrapper {
position: relative;
z-index: $zindex-dropdown;
margin-left: auto;

.dropdown-container {
position: absolute;
width: 100%;
}
}
11 changes: 10 additions & 1 deletion src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ export const DATE_TIME_FORMAT = 'YYYY-MM-DDTHH:mm:ss\\Z';
export const COMMA_SEPARATED_DATE_FORMAT = 'MMMM D, YYYY';
export const DEFAULT_EMPTY_WYSIWYG_VALUE = '<p>&nbsp;</p>';
export const STATEFUL_BUTTON_STATES = {
pending: 'pending',
default: 'default',
pending: 'pending',
error: 'error',
};

export const USER_ROLES = {
Expand All @@ -25,3 +26,11 @@ export const NOTIFICATION_MESSAGES = {
};

export const DEFAULT_TIME_STAMP = '00:00';

export const COURSE_CREATOR_STATES = {
unrequested: 'unrequested',
pending: 'pending',
granted: 'granted',
denied: 'denied',
disallowedForThisSite: 'disallowed_for_this_site',
};
93 changes: 93 additions & 0 deletions src/course-rerun/CourseRerun.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { history, initializeMockApp } from '@edx/frontend-platform';
import { IntlProvider, injectIntl } from '@edx/frontend-platform/i18n';
import { AppProvider } from '@edx/frontend-platform/react';
import {
act, fireEvent, render, waitFor,
} from '@testing-library/react';
import MockAdapter from 'axios-mock-adapter';

import initializeStore from '../store';
import { studioHomeMock } from '../studio-home/__mocks__';
import { getStudioHomeApiUrl } from '../studio-home/data/api';
import { RequestStatus } from '../data/constants';
import messages from './messages';
import CourseRerun from '.';

let axiosMock;
let store;
const mockPathname = '/foo-bar';

jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useSelector: jest.fn(),
}));

jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: () => ({
pathname: mockPathname,
}),
}));

const RootWrapper = () => (
<MemoryRouter>
<AppProvider store={store}>
<IntlProvider locale="en">
<CourseRerun intl={injectIntl} />
</IntlProvider>
</AppProvider>
</MemoryRouter>
);

describe('<CourseRerun />', () => {
beforeEach(() => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});
store = initializeStore();
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(getStudioHomeApiUrl()).reply(200, studioHomeMock);
useSelector.mockReturnValue(studioHomeMock);
});

it('should render successfully', () => {
const { getByText, getAllByRole } = render(<RootWrapper />);
expect(getByText(messages.rerunTitle.defaultMessage));
expect(getAllByRole('button', { name: messages.cancelButton.defaultMessage }).length).toBe(2);
});

it('should navigate to /home on cancel button click', () => {
const { getAllByRole } = render(<RootWrapper />);
const cancelButton = getAllByRole('button', { name: messages.cancelButton.defaultMessage })[0];

fireEvent.click(cancelButton);
waitFor(() => {
expect(history.location.pathname).toBe('/home');
});
});

it('shows the spinner before the query is complete', async () => {
useSelector.mockReturnValue({ organizationLoadingStatus: RequestStatus.IN_PROGRESS });

await act(async () => {
const { getByRole } = render(<RootWrapper />);
const spinner = getByRole('status');
expect(spinner.textContent).toEqual('Loading...');
});
});

it('should show footer', () => {
const { getByText } = render(<RootWrapper />);
expect(getByText('Looking for help with Studio?')).toBeInTheDocument();
expect(getByText('LMS')).toHaveAttribute('href', process.env.LMS_BASE_URL);
});
});
58 changes: 58 additions & 0 deletions src/course-rerun/course-rerun-form/CourseRerunForm.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { render } from '@testing-library/react';
import { initializeMockApp } from '@edx/frontend-platform';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { AppProvider } from '@edx/frontend-platform/react';

import { studioHomeMock } from '../../studio-home/__mocks__';
import initializeStore from '../../store';
import CourseRerunForm from '.';

jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useSelector: jest.fn(),
}));

let store;

const onClickCancelMock = jest.fn();

const RootWrapper = (props) => (
<IntlProvider locale="en">
<AppProvider store={store}>
<CourseRerunForm {...props} />
</AppProvider>
</IntlProvider>
);

const props = {
initialFormValues: {
displayName: '',
org: '',
number: '',
run: '',
},
onClickCancel: onClickCancelMock,
};

describe('<CourseRerunForm />', () => {
beforeEach(() => {
initializeMockApp({
authenticatedUser: {
userId: 3,
username: 'abc123',
administrator: true,
roles: [],
},
});

store = initializeStore();
useSelector.mockReturnValue(studioHomeMock);
});

it('renders description successfully', () => {
const { getByText } = render(<RootWrapper {...props} />);
expect(getByText('Provide identifying information for this re-run of the course. The original course is not affected in any way by a re-run', { exact: false })).toBeInTheDocument();
});
});
36 changes: 36 additions & 0 deletions src/course-rerun/course-rerun-form/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useIntl } from '@edx/frontend-platform/i18n';

import { CreateOrRerunCourseForm } from '../../generic/create-or-rerun-course';
import messages from './messages';

const CourseRerunForm = ({ initialFormValues, onClickCancel }) => {
const intl = useIntl();
return (
<div className="mb-4.5">
<div className="my-2.5">{intl.formatMessage(messages.rerunCourseDescription, {
strong: (
<strong>{intl.formatMessage(messages.rerunCourseDescriptionStrong)}</strong>
),
})}
</div>
<CreateOrRerunCourseForm
initialValues={initialFormValues}
onClickCancel={onClickCancel}
/>
</div>
);
};

CourseRerunForm.propTypes = {
initialFormValues: PropTypes.shape({
displayName: PropTypes.string.isRequired,
org: PropTypes.string.isRequired,
number: PropTypes.string.isRequired,
run: PropTypes.string,
}).isRequired,
onClickCancel: PropTypes.func.isRequired,
};

export default CourseRerunForm;
14 changes: 14 additions & 0 deletions src/course-rerun/course-rerun-form/messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { defineMessages } from '@edx/frontend-platform/i18n';

const messages = defineMessages({
rerunCourseDescription: {
id: 'course-authoring.course-rerun.form.description',
defaultMessage: 'Provide identifying information for this re-run of the course. The original course is not affected in any way by a re-run. {strong}',
},
rerunCourseDescriptionStrong: {
id: 'course-authoring.course-rerun.form.description.strong',
defaultMessage: 'Note: Together, the organization, course number, and course run must uniquely identify this new course instance.',
},
});

export default messages;
Loading