Compare commits
6 Commits
master
...
open-relea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ca7bc7d359 | ||
|
|
b41a336e11 | ||
|
|
b4032215c6 | ||
|
|
b20eb50699 | ||
|
|
5c021cdc80 | ||
|
|
fa826fe687 |
2
.env
2
.env
@@ -19,3 +19,5 @@ SEGMENT_KEY=''
|
|||||||
SITE_NAME=''
|
SITE_NAME=''
|
||||||
USER_INFO_COOKIE_NAME=''
|
USER_INFO_COOKIE_NAME=''
|
||||||
SCHEDULE_EMAIL_SECTION=''
|
SCHEDULE_EMAIL_SECTION=''
|
||||||
|
APP_ID=''
|
||||||
|
MFE_CONFIG_API_URL=''
|
||||||
|
|||||||
@@ -20,3 +20,5 @@ SEGMENT_KEY=''
|
|||||||
SITE_NAME=localhost
|
SITE_NAME=localhost
|
||||||
USER_INFO_COOKIE_NAME='edx-user-info'
|
USER_INFO_COOKIE_NAME='edx-user-info'
|
||||||
SCHEDULE_EMAIL_SECTION='true'
|
SCHEDULE_EMAIL_SECTION='true'
|
||||||
|
APP_ID=''
|
||||||
|
MFE_CONFIG_API_URL=''
|
||||||
|
|||||||
@@ -18,3 +18,5 @@ SEGMENT_KEY=''
|
|||||||
SITE_NAME=localhost
|
SITE_NAME=localhost
|
||||||
USER_INFO_COOKIE_NAME='edx-user-info'
|
USER_INFO_COOKIE_NAME='edx-user-info'
|
||||||
SCHEDULE_EMAIL_SECTION='true'
|
SCHEDULE_EMAIL_SECTION='true'
|
||||||
|
APP_ID=''
|
||||||
|
MFE_CONFIG_API_URL=''
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
/* eslint-disable import/no-extraneous-dependencies */
|
||||||
|
|
||||||
const { createConfig } = require('@edx/frontend-build');
|
const { createConfig } = require('@edx/frontend-build');
|
||||||
|
|
||||||
module.exports = createConfig('eslint');
|
module.exports = createConfig('eslint', {
|
||||||
|
rules: {
|
||||||
|
'react/function-component-definition': 'off',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@@ -9,18 +9,18 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node: [16]
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
- name: Setup Nodejs Env
|
||||||
|
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
|
||||||
- name: Setup Nodejs
|
- name: Setup Nodejs
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version: ${{ env.NODE_VER }}
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
- name: Validate package-lock.json changes
|
- name: Validate package-lock.json changes
|
||||||
|
|||||||
2
.github/workflows/lockfileversion-check.yml
vendored
2
.github/workflows/lockfileversion-check.yml
vendored
@@ -10,4 +10,4 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
version-check:
|
version-check:
|
||||||
uses: openedx/.github/.github/workflows/lockfileversion-check.yml@master
|
uses: openedx/.github/.github/workflows/lockfileversion-check-v3.yml@master
|
||||||
|
|||||||
28868
package-lock.json
generated
28868
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@@ -34,9 +34,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
|
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
|
||||||
"@edx/frontend-component-footer": "11.6.0",
|
"@edx/frontend-component-footer": "^12.0.0",
|
||||||
"@edx/frontend-component-header": "3.5.0",
|
"@edx/frontend-component-header": "^4.0.0",
|
||||||
"@edx/frontend-platform": "2.6.2",
|
"@edx/frontend-platform": "^4.0.1",
|
||||||
"@edx/paragon": "^20.20.0",
|
"@edx/paragon": "^20.20.0",
|
||||||
"@edx/tinymce-language-selector": "1.1.0",
|
"@edx/tinymce-language-selector": "1.1.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||||
@@ -53,6 +53,7 @@
|
|||||||
"prop-types": "15.8.1",
|
"prop-types": "15.8.1",
|
||||||
"react": "16.14.0",
|
"react": "16.14.0",
|
||||||
"react-dom": "16.14.0",
|
"react-dom": "16.14.0",
|
||||||
|
"react-helmet": "^6.1.0",
|
||||||
"react-redux": "7.2.9",
|
"react-redux": "7.2.9",
|
||||||
"react-router": "5.3.4",
|
"react-router": "5.3.4",
|
||||||
"react-router-dom": "5.3.4",
|
"react-router-dom": "5.3.4",
|
||||||
@@ -61,8 +62,8 @@
|
|||||||
"tinymce": "5.10.7"
|
"tinymce": "5.10.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@edx/browserslist-config": "^1.1.0",
|
"@edx/browserslist-config": "^1.2.0",
|
||||||
"@edx/frontend-build": "11.0.2",
|
"@edx/frontend-build": "^12.7.0",
|
||||||
"@edx/reactifex": "^2.1.1",
|
"@edx/reactifex": "^2.1.1",
|
||||||
"@testing-library/jest-dom": "5.16.5",
|
"@testing-library/jest-dom": "5.16.5",
|
||||||
"@testing-library/react": "12.1.5",
|
"@testing-library/react": "12.1.5",
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
<title>Communications | <%= process.env.SITE_NAME %></title>
|
<title>Communications | <%= process.env.SITE_NAME %></title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="shortcut icon" href="<%=htmlWebpackPlugin.options.FAVICON_URL%>" type="image/x-icon" />
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default function BulkEmailTool() {
|
|||||||
<NavigationTabs courseId={courseId} tabData={courseMetadata.tabs} />
|
<NavigationTabs courseId={courseId} tabData={courseMetadata.tabs} />
|
||||||
<BulkEmailProvider>
|
<BulkEmailProvider>
|
||||||
<Container size="md">
|
<Container size="md">
|
||||||
<BackToInstructor />
|
<BackToInstructor courseId={courseId} />
|
||||||
<div className="row pb-4.5">
|
<div className="row pb-4.5">
|
||||||
<h1 className="text-primary-500" id="main-content">
|
<h1 className="text-primary-500" id="main-content">
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable react/jsx-no-constructed-context-values */
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import useAsyncReducer, { combineReducers } from '../../../utils/useAsyncReducer';
|
import useAsyncReducer, { combineReducers } from '../../../utils/useAsyncReducer';
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable react/no-unstable-nested-components */
|
||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
// eslint-disable-next-line no-restricted-exports
|
||||||
export { default } from './BulkEmailRecipient';
|
export { default } from './BulkEmailRecipient';
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
// eslint-disable-next-line no-restricted-exports
|
||||||
export { default } from './BulkEmailForm';
|
export { default } from './BulkEmailForm';
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable react/no-unstable-nested-components */
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
@@ -131,6 +133,7 @@ function BulkEmailContentHistory({ intl }) {
|
|||||||
styling="card"
|
styling="card"
|
||||||
title={intl.formatMessage(messages.emailHistoryTableSectionButton)}
|
title={intl.formatMessage(messages.emailHistoryTableSectionButton)}
|
||||||
className="mb-3"
|
className="mb-3"
|
||||||
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
onOpen={fetchSentEmailHistoryData}
|
onOpen={fetchSentEmailHistoryData}
|
||||||
>
|
>
|
||||||
{showHistoricalEmailContentTable ? (
|
{showHistoricalEmailContentTable ? (
|
||||||
|
|||||||
@@ -71,12 +71,12 @@ export default function BulkEmailTaskManagerTable(props) {
|
|||||||
|
|
||||||
BulkEmailTaskManagerTable.propTypes = {
|
BulkEmailTaskManagerTable.propTypes = {
|
||||||
errorRetrievingData: PropTypes.bool.isRequired,
|
errorRetrievingData: PropTypes.bool.isRequired,
|
||||||
tableData: PropTypes.arrayOf(PropTypes.object),
|
tableData: PropTypes.arrayOf(PropTypes.shape({})),
|
||||||
tableDescription: PropTypes.string,
|
tableDescription: PropTypes.string,
|
||||||
alertWarningMessage: PropTypes.string.isRequired,
|
alertWarningMessage: PropTypes.string.isRequired,
|
||||||
alertErrorMessage: PropTypes.string.isRequired,
|
alertErrorMessage: PropTypes.string.isRequired,
|
||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
columns: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
|
||||||
additionalColumns: PropTypes.arrayOf(PropTypes.object),
|
additionalColumns: PropTypes.arrayOf(PropTypes.shape({})),
|
||||||
};
|
};
|
||||||
|
|
||||||
BulkEmailTaskManagerTable.defaultProps = {
|
BulkEmailTaskManagerTable.defaultProps = {
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
import { Hyperlink, Alert } from '@edx/paragon';
|
import { Hyperlink, Alert } from '@edx/paragon';
|
||||||
import { WarningFilled } from '@edx/paragon/icons';
|
import { WarningFilled } from '@edx/paragon/icons';
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
|
|
||||||
export default function BulkEmailPendingTasksAlert() {
|
export default function BulkEmailPendingTasksAlert(props) {
|
||||||
|
const { courseId } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<Alert variant="warning" icon={WarningFilled}>
|
<Alert variant="warning" icon={WarningFilled}>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="bulk.email.pending.tasks.description.one"
|
id="bulk.email.pending.tasks.description.one"
|
||||||
defaultMessage="To view all pending tasks, including email, visit "
|
defaultMessage="To view all pending tasks, including email, visit "
|
||||||
/>
|
/>
|
||||||
<Hyperlink
|
<Hyperlink
|
||||||
destination={`${getConfig().LMS_BASE_URL}/courses/${window.location.pathname.split('/')[2]}/instructor#view-course-info`}
|
destination={`${getConfig().LMS_BASE_URL}/courses/${courseId}/instructor#view-course-info`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
isInline
|
isInline
|
||||||
showLaunchIcon={false}
|
showLaunchIcon={false}
|
||||||
@@ -29,6 +31,10 @@ export default function BulkEmailPendingTasksAlert() {
|
|||||||
defaultMessage=" in the Instructor Dashboard."
|
defaultMessage=" in the Instructor Dashboard."
|
||||||
/>
|
/>
|
||||||
</Alert>
|
</Alert>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BulkEmailPendingTasksAlert.propTypes = {
|
||||||
|
courseId: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ function BulkEmailTaskHistory({ intl }) {
|
|||||||
<Collapsible
|
<Collapsible
|
||||||
styling="card"
|
styling="card"
|
||||||
title={intl.formatMessage(messages.emailTaskHistoryTableSectionButton)}
|
title={intl.formatMessage(messages.emailTaskHistoryTableSectionButton)}
|
||||||
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
onOpen={fetchEmailTaskHistoryData}
|
onOpen={fetchEmailTaskHistoryData}
|
||||||
>
|
>
|
||||||
{showHistoricalTaskContentTable ? (
|
{showHistoricalTaskContentTable ? (
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
@@ -8,7 +9,7 @@ import messages from './messages';
|
|||||||
import BulkEmailScheduledEmailsTable from './bulk-email-scheduled-emails-table';
|
import BulkEmailScheduledEmailsTable from './bulk-email-scheduled-emails-table';
|
||||||
import BulkEmailPendingTasksAlert from './BulkEmailPendingTasksAlert';
|
import BulkEmailPendingTasksAlert from './BulkEmailPendingTasksAlert';
|
||||||
|
|
||||||
function BulkEmailTaskManager({ intl }) {
|
function BulkEmailTaskManager({ intl, courseId }) {
|
||||||
return (
|
return (
|
||||||
<div className="w-100">
|
<div className="w-100">
|
||||||
{getConfig().SCHEDULE_EMAIL_SECTION && (
|
{getConfig().SCHEDULE_EMAIL_SECTION && (
|
||||||
@@ -26,7 +27,7 @@ function BulkEmailTaskManager({ intl }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="border-top border-primary-500 pt-4.5">
|
<div className="border-top border-primary-500 pt-4.5">
|
||||||
<h2 className="h3 mb-4 text-primary-500">{intl.formatMessage(messages.pendingTasksHeader)}</h2>
|
<h2 className="h3 mb-4 text-primary-500">{intl.formatMessage(messages.pendingTasksHeader)}</h2>
|
||||||
<BulkEmailPendingTasksAlert />
|
<BulkEmailPendingTasksAlert courseId={courseId} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -34,6 +35,7 @@ function BulkEmailTaskManager({ intl }) {
|
|||||||
|
|
||||||
BulkEmailTaskManager.propTypes = {
|
BulkEmailTaskManager.propTypes = {
|
||||||
intl: intlShape.isRequired,
|
intl: intlShape.isRequired,
|
||||||
|
courseId: PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default injectIntl(BulkEmailTaskManager);
|
export default injectIntl(BulkEmailTaskManager);
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
|
/* eslint-disable react/no-unstable-nested-components */
|
||||||
|
|
||||||
import React, {
|
import React, {
|
||||||
useCallback, useContext, useState, useEffect,
|
useCallback, useContext, useState, useEffect,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
// eslint-disable-next-line no-restricted-exports
|
||||||
export { default } from './BulkEmailScheduledEmailsTable';
|
export { default } from './BulkEmailScheduledEmailsTable';
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BulkEmailPendingTasksAlert from '../BulkEmailPendingTasksAlert';
|
||||||
|
import {
|
||||||
|
initializeMockApp, render, screen,
|
||||||
|
} from '../../../../setupTest';
|
||||||
|
|
||||||
|
describe('Testing BulkEmailPendingTasksAlert Component', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await initializeMockApp();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Render without Public path', async () => {
|
||||||
|
render(<BulkEmailPendingTasksAlert courseId="test-course-id" />);
|
||||||
|
|
||||||
|
const linkEl = await screen.findByText('Course Info');
|
||||||
|
expect(linkEl.href).toEqual('http://localhost:18000/courses/test-course-id/instructor#view-course-info');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Render with Public path', async () => {
|
||||||
|
Object.defineProperty(window, 'location', {
|
||||||
|
get() {
|
||||||
|
return { pathname: '/communications/courses/test-course-id/bulk-email' };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<BulkEmailPendingTasksAlert courseId="test-course-id" />);
|
||||||
|
|
||||||
|
const linkEl = await screen.findByText('Course Info');
|
||||||
|
expect(linkEl.href).toEqual('http://localhost:18000/courses/test-course-id/instructor#view-course-info');
|
||||||
|
expect(window.location.pathname).toEqual('/communications/courses/test-course-id/bulk-email');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1 +1,2 @@
|
|||||||
|
// eslint-disable-next-line no-restricted-exports
|
||||||
export { default } from './BulkEmailTool';
|
export { default } from './BulkEmailTool';
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ function TaskAlertModal(props) {
|
|||||||
// causing strange click event target issues in safari. To solve this, we want to
|
// causing strange click event target issues in safari. To solve this, we want to
|
||||||
// wrap the string in a fragment instead of a span, so that the whole button considered
|
// wrap the string in a fragment instead of a span, so that the whole button considered
|
||||||
// a "button" target, and not a "span inside a button"
|
// a "button" target, and not a "span inside a button"
|
||||||
|
// eslint-disable-next-line react/jsx-no-useless-fragment
|
||||||
msg => <>{msg}</>
|
msg => <>{msg}</>
|
||||||
}
|
}
|
||||||
</FormattedMessage>
|
</FormattedMessage>
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
// eslint-disable-next-line no-restricted-exports
|
||||||
export { default } from './TaskAlertModal';
|
export { default } from './TaskAlertModal';
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ export default function TextEditor(props) {
|
|||||||
block_unsupported_drop: false,
|
block_unsupported_drop: false,
|
||||||
image_advtab: true,
|
image_advtab: true,
|
||||||
name: 'emailBody',
|
name: 'emailBody',
|
||||||
|
relative_urls: false,
|
||||||
|
remove_script_host: false,
|
||||||
}}
|
}}
|
||||||
onEditorChange={onChange}
|
onEditorChange={onChange}
|
||||||
value={value}
|
value={value}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
// eslint-disable-next-line no-restricted-exports
|
||||||
export { default } from './TextEditor';
|
export { default } from './TextEditor';
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||||
import { Button, Icon } from '@edx/paragon';
|
import { Button, Icon } from '@edx/paragon';
|
||||||
import { ArrowBack } from '@edx/paragon/icons';
|
import { ArrowBack } from '@edx/paragon/icons';
|
||||||
|
|
||||||
export default function BackToInstructor() {
|
export default function BackToInstructor(props) {
|
||||||
|
const { courseId } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
variant="tertiary"
|
variant="tertiary"
|
||||||
className="mb-4.5 ml-n4.5 text-primary-500"
|
className="mb-4.5 ml-n4.5 text-primary-500"
|
||||||
href={`${getConfig().LMS_BASE_URL}/courses/${window.location.pathname.split('/')[2]}/instructor#view-course-info`}
|
href={`${getConfig().LMS_BASE_URL}/courses/${courseId}/instructor#view-course-info`}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
src={ArrowBack}
|
src={ArrowBack}
|
||||||
@@ -24,3 +27,7 @@ export default function BackToInstructor() {
|
|||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BackToInstructor.propTypes = {
|
||||||
|
courseId: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|||||||
33
src/components/navigation-tabs/BackToInstructor.test.jsx
Normal file
33
src/components/navigation-tabs/BackToInstructor.test.jsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BackToInstructor from './BackToInstructor';
|
||||||
|
import {
|
||||||
|
initializeMockApp, render, screen,
|
||||||
|
} from '../../setupTest';
|
||||||
|
|
||||||
|
describe('Testing BackToInstructor Component', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await initializeMockApp();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Render without Public path', async () => {
|
||||||
|
render(<BackToInstructor courseId="test-course-id" />);
|
||||||
|
|
||||||
|
const linkEl = await screen.findByText('Back to Instructor Dashboard');
|
||||||
|
expect(linkEl.href).toEqual('http://localhost:18000/courses/test-course-id/instructor#view-course-info');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Render with Public path', async () => {
|
||||||
|
Object.defineProperty(window, 'location', {
|
||||||
|
get() {
|
||||||
|
return { pathname: '/communications/courses/test-course-id/bulk-email' };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
render(<BackToInstructor courseId="test-course-id" />);
|
||||||
|
|
||||||
|
const linkEl = await screen.findByText('Back to Instructor Dashboard');
|
||||||
|
expect(linkEl.href).toEqual('http://localhost:18000/courses/test-course-id/instructor#view-course-info');
|
||||||
|
expect(window.location.pathname).toEqual('/communications/courses/test-course-id/bulk-email');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
|
import { camelCaseObject, getConfig } from '@edx/frontend-platform';
|
||||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||||
|
|
||||||
const courseHomeBaseUrl = `${getConfig().LMS_BASE_URL}/api/course_home/v1/course_metadata`;
|
export const getCourseHomeBaseUrl = () => `${getConfig().LMS_BASE_URL}/api/course_home/v1/course_metadata`;
|
||||||
|
|
||||||
export async function getCourseHomeCourseMetadata(courseId) {
|
export async function getCourseHomeCourseMetadata(courseId) {
|
||||||
const courseHomeMetadataUrl = `${courseHomeBaseUrl}/${courseId}`;
|
const courseHomeMetadataUrl = `${getCourseHomeBaseUrl()}/${courseId}`;
|
||||||
const { data } = await getAuthenticatedHttpClient().get(courseHomeMetadataUrl);
|
const { data } = await getAuthenticatedHttpClient().get(courseHomeMetadataUrl);
|
||||||
return camelCaseObject(data);
|
return camelCaseObject(data);
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/components/page-container/data/api.test.js
Normal file
24
src/components/page-container/data/api.test.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { Factory } from 'rosie'; // eslint-disable-line import/no-extraneous-dependencies
|
||||||
|
import { camelCaseObject } from '@edx/frontend-platform';
|
||||||
|
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||||
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
|
import { initializeMockApp } from '../../../setupTest';
|
||||||
|
import * as api from './api';
|
||||||
|
import './__factories__/courseMetadata.factory';
|
||||||
|
|
||||||
|
describe('api', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await initializeMockApp();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getCourseHomeCourseMetadata', async () => {
|
||||||
|
const axiosMock = new MockAdapter(getAuthenticatedHttpClient());
|
||||||
|
const courseMetadata = Factory.build('courseMetadata');
|
||||||
|
const { id: courseId } = courseMetadata;
|
||||||
|
axiosMock
|
||||||
|
.onGet(`${api.getCourseHomeBaseUrl()}/${courseId}`)
|
||||||
|
.reply(200, courseMetadata);
|
||||||
|
const data = await api.getCourseHomeCourseMetadata(courseId);
|
||||||
|
expect(data).toEqual(camelCaseObject(courseMetadata));
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,7 +2,7 @@ import 'core-js/stable';
|
|||||||
import 'regenerator-runtime/runtime';
|
import 'regenerator-runtime/runtime';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
APP_INIT_ERROR, APP_READY, subscribe, initialize, mergeConfig,
|
APP_INIT_ERROR, APP_READY, subscribe, initialize, mergeConfig, getConfig,
|
||||||
} from '@edx/frontend-platform';
|
} from '@edx/frontend-platform';
|
||||||
import { AppProvider, AuthenticatedPageRoute, ErrorPage } from '@edx/frontend-platform/react';
|
import { AppProvider, AuthenticatedPageRoute, ErrorPage } from '@edx/frontend-platform/react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
@@ -10,6 +10,7 @@ import ReactDOM from 'react-dom';
|
|||||||
import { messages as headerMessages } from '@edx/frontend-component-header';
|
import { messages as headerMessages } from '@edx/frontend-component-header';
|
||||||
import { messages as footerMessages } from '@edx/frontend-component-footer';
|
import { messages as footerMessages } from '@edx/frontend-component-footer';
|
||||||
import { messages as paragonMessages } from '@edx/paragon';
|
import { messages as paragonMessages } from '@edx/paragon';
|
||||||
|
import { Helmet } from 'react-helmet';
|
||||||
import { Switch } from 'react-router-dom';
|
import { Switch } from 'react-router-dom';
|
||||||
import appMessages from './i18n';
|
import appMessages from './i18n';
|
||||||
|
|
||||||
@@ -20,6 +21,9 @@ import PageContainer from './components/page-container/PageContainer';
|
|||||||
subscribe(APP_READY, () => {
|
subscribe(APP_READY, () => {
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<AppProvider>
|
<AppProvider>
|
||||||
|
<Helmet>
|
||||||
|
<link rel="shortcut icon" href={getConfig().FAVICON_URL} type="image/x-icon" />
|
||||||
|
</Helmet>
|
||||||
<div className="pb-3 container">
|
<div className="pb-3 container">
|
||||||
<Switch>
|
<Switch>
|
||||||
<AuthenticatedPageRoute path="/courses/:courseId/bulk_email">
|
<AuthenticatedPageRoute path="/courses/:courseId/bulk_email">
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import { getConfig, mergeConfig } from '@edx/frontend-platform';
|
|||||||
import { configure as configureAuth, MockAuthService } from '@edx/frontend-platform/auth';
|
import { configure as configureAuth, MockAuthService } from '@edx/frontend-platform/auth';
|
||||||
import appMessages from './i18n';
|
import appMessages from './i18n';
|
||||||
|
|
||||||
|
jest.mock('@edx/frontend-platform/react/hooks', () => ({
|
||||||
|
...jest.requireActual('@edx/frontend-platform/react/hooks'),
|
||||||
|
useTrackColorSchemeChoice: jest.fn(),
|
||||||
|
}));
|
||||||
Object.defineProperty(window, 'matchMedia', {
|
Object.defineProperty(window, 'matchMedia', {
|
||||||
writable: true,
|
writable: true,
|
||||||
value: jest.fn().mockImplementation((query) => ({
|
value: jest.fn().mockImplementation((query) => ({
|
||||||
|
|||||||
Reference in New Issue
Block a user