components unit test (#23)
Co-authored-by: Ben Warzeski <bwarzeski@edx.org>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { hooks } from 'data/redux';
|
||||
import BeginCourseButton from './BeginCourseButton';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCardCourseRunData: jest.fn(),
|
||||
useCardEnrollmentData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('BeginCourseButton', () => {
|
||||
const props = {
|
||||
cardId: 'cardId',
|
||||
};
|
||||
hooks.useCardCourseRunData.mockReturnValue({
|
||||
homeUrl: 'homeUrl',
|
||||
});
|
||||
describe('snapshot', () => {
|
||||
test('renders default button when learner has access to the course', () => {
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({
|
||||
hasAccess: true,
|
||||
});
|
||||
const wrapper = shallow(<BeginCourseButton {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('renders disabled button when learner does not have access to the course', () => {
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({
|
||||
hasAccess: false,
|
||||
});
|
||||
const wrapper = shallow(<BeginCourseButton {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { hooks } from 'data/redux';
|
||||
import ResumeButton from './ResumeButton';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCardCourseRunData: jest.fn(),
|
||||
useCardEnrollmentData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('ResumeButton', () => {
|
||||
const props = {
|
||||
cardId: 'cardId',
|
||||
};
|
||||
hooks.useCardCourseRunData.mockReturnValue({
|
||||
resumeUrl: 'resumeUrl',
|
||||
});
|
||||
describe('snapshot', () => {
|
||||
test('renders default button when learner has access to the course', () => {
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({
|
||||
hasAccess: true,
|
||||
});
|
||||
const wrapper = shallow(<ResumeButton {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('renders disabled button when learner does not have access to the course', () => {
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({
|
||||
hasAccess: false,
|
||||
});
|
||||
const wrapper = shallow(<ResumeButton {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('behavior', () => {
|
||||
it('renders disabled button when audit access expired', () => {
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({
|
||||
hasAccess: true,
|
||||
isAudit: true,
|
||||
isAuditAccessExpired: true,
|
||||
});
|
||||
const wrapper = shallow(<ResumeButton {...props} />);
|
||||
expect(wrapper.prop('disabled')).toEqual(true);
|
||||
});
|
||||
it('renders enabled button when audit access not expired', () => {
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({
|
||||
hasAccess: true,
|
||||
isAudit: true,
|
||||
isAuditAccessExpired: false,
|
||||
});
|
||||
const wrapper = shallow(<ResumeButton {...props} />);
|
||||
expect(wrapper.prop('disabled')).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { hooks } from 'data/redux';
|
||||
import SelectSessionButton from './SelectSessionButton';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCardCourseRunData: jest.fn(),
|
||||
useCardEnrollmentData: jest.fn(),
|
||||
useCardEntitlementData: jest.fn(),
|
||||
useUpdateSelectSessionModalCallback: () => jest.fn().mockName('mockOpenSessionModal'),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('SelectSessionButton', () => {
|
||||
const props = {
|
||||
cardId: 'cardId',
|
||||
};
|
||||
hooks.useCardCourseRunData.mockReturnValue({
|
||||
resumeUrl: 'resumeUrl',
|
||||
});
|
||||
const createWrapper = ({ hasAccess, canChange, hasSessions }) => {
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({
|
||||
hasAccess,
|
||||
});
|
||||
hooks.useCardEntitlementData.mockReturnValueOnce({
|
||||
canChange,
|
||||
hasSessions,
|
||||
});
|
||||
return shallow(<SelectSessionButton {...props} />);
|
||||
};
|
||||
describe('snapshot', () => {
|
||||
test('renders default button', () => {
|
||||
const wrapper = createWrapper({ hasAccess: true, canChange: true, hasSessions: true });
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
it('renders disabled button when user does not have access to the course', () => {
|
||||
const wrapper = createWrapper({ hasAccess: false, canChange: true, hasSessions: true });
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('behavior', () => {
|
||||
it('default render', () => {
|
||||
const wrapper = createWrapper({ hasAccess: true, canChange: true, hasSessions: true });
|
||||
expect(wrapper.prop('disabled')).toEqual(false);
|
||||
expect(wrapper.prop('href')).toEqual('resumeUrl');
|
||||
expect(wrapper.prop('onClick').getMockName())
|
||||
.toEqual(hooks.useUpdateSelectSessionModalCallback().getMockName());
|
||||
});
|
||||
it('disabled if learner doesn\'t have access, cannot change sessions, or does not have sessions', () => {
|
||||
const noAccess = createWrapper({ hasAccess: false, canChange: true, hasSessions: true });
|
||||
expect(noAccess.prop('disabled')).toEqual(true);
|
||||
|
||||
const cannotChange = createWrapper({ hasAccess: true, canChange: false, hasSessions: true });
|
||||
expect(cannotChange.prop('disabled')).toEqual(true);
|
||||
|
||||
const noSessions = createWrapper({ hasAccess: true, canChange: true, hasSessions: false });
|
||||
expect(noSessions.prop('disabled')).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { hooks } from 'data/redux';
|
||||
import UpgradeButton from './UpgradeButton';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCardCourseRunData: jest.fn(),
|
||||
useCardEnrollmentData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('UpgradeButton', () => {
|
||||
const props = {
|
||||
cardId: 'cardId',
|
||||
};
|
||||
const upgradeUrl = 'upgradeUrl';
|
||||
hooks.useCardCourseRunData.mockReturnValue({ upgradeUrl });
|
||||
describe('snapshot', () => {
|
||||
test('can upgrade', () => {
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({ canUpgrade: true });
|
||||
const wrapper = shallow(<UpgradeButton {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('cannot upgrade', () => {
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({ canUpgrade: false });
|
||||
const wrapper = shallow(<UpgradeButton {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { hooks } from 'data/redux';
|
||||
import ViewCourseButton from './ViewCourseButton';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCardCourseRunData: jest.fn(),
|
||||
useCardEnrollmentData: jest.fn(),
|
||||
useCardEntitlementData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('ViewCourseButton', () => {
|
||||
const props = {
|
||||
cardId: 'cardId',
|
||||
};
|
||||
const marketingUrl = 'marketingUrl';
|
||||
hooks.useCardCourseRunData.mockReturnValue({ marketingUrl });
|
||||
const createWrapper = ({ hasAccess, isEntitlement, isExpired }) => {
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({ hasAccess });
|
||||
hooks.useCardEntitlementData.mockReturnValueOnce({ isEntitlement, isExpired });
|
||||
return shallow(<ViewCourseButton {...props} />);
|
||||
};
|
||||
describe('snapshot', () => {
|
||||
test('default button', () => {
|
||||
const wrapper = createWrapper({ hasAccess: true, isEntitlement: false, isExpired: false });
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('disabled button', () => {
|
||||
const wrapper = createWrapper({ hasAccess: false, isEntitlement: false, isExpired: false });
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('behavior', () => {
|
||||
it('disabled button without access', () => {
|
||||
const wrapper = createWrapper({ hasAccess: false, isEntitlement: false, isExpired: false });
|
||||
expect(wrapper.prop('disabled')).toEqual(true);
|
||||
});
|
||||
it('disabled button with access', () => {
|
||||
const wrapper = createWrapper({ hasAccess: true, isEntitlement: true, isExpired: true });
|
||||
expect(wrapper.prop('disabled')).toEqual(true);
|
||||
});
|
||||
it('enabled button', () => {
|
||||
const wrapper = createWrapper({ hasAccess: true, isEntitlement: false, isExpired: false });
|
||||
expect(wrapper.prop('disabled')).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`BeginCourseButton snapshot renders default button when learner has access to the course 1`] = `
|
||||
<Button
|
||||
as="a"
|
||||
disabled={false}
|
||||
href="homeUrl"
|
||||
>
|
||||
Begin Course
|
||||
</Button>
|
||||
`;
|
||||
|
||||
exports[`BeginCourseButton snapshot renders disabled button when learner does not have access to the course 1`] = `
|
||||
<Button
|
||||
as="a"
|
||||
disabled={true}
|
||||
href="homeUrl"
|
||||
>
|
||||
Begin Course
|
||||
</Button>
|
||||
`;
|
||||
@@ -0,0 +1,20 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ResumeButton snapshot renders default button when learner has access to the course 1`] = `
|
||||
<Button
|
||||
as="a"
|
||||
href="resumeUrl"
|
||||
>
|
||||
Resume
|
||||
</Button>
|
||||
`;
|
||||
|
||||
exports[`ResumeButton snapshot renders disabled button when learner does not have access to the course 1`] = `
|
||||
<Button
|
||||
as="a"
|
||||
disabled={true}
|
||||
href="resumeUrl"
|
||||
>
|
||||
Resume
|
||||
</Button>
|
||||
`;
|
||||
@@ -0,0 +1,23 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SelectSessionButton snapshot renders default button 1`] = `
|
||||
<Button
|
||||
as="a"
|
||||
disabled={false}
|
||||
href="resumeUrl"
|
||||
onClick={[MockFunction mockOpenSessionModal]}
|
||||
>
|
||||
Resume
|
||||
</Button>
|
||||
`;
|
||||
|
||||
exports[`SelectSessionButton snapshot renders disabled button when user does not have access to the course 1`] = `
|
||||
<Button
|
||||
as="a"
|
||||
disabled={true}
|
||||
href="resumeUrl"
|
||||
onClick={[MockFunction mockOpenSessionModal]}
|
||||
>
|
||||
Resume
|
||||
</Button>
|
||||
`;
|
||||
@@ -0,0 +1,25 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`UpgradeButton snapshot can upgrade 1`] = `
|
||||
<Button
|
||||
as="a"
|
||||
disabled={false}
|
||||
href="upgradeUrl"
|
||||
iconBefore={[MockFunction icons.Locked]}
|
||||
variant="outline-primary"
|
||||
>
|
||||
Upgrade
|
||||
</Button>
|
||||
`;
|
||||
|
||||
exports[`UpgradeButton snapshot cannot upgrade 1`] = `
|
||||
<Button
|
||||
as="a"
|
||||
disabled={true}
|
||||
href="upgradeUrl"
|
||||
iconBefore={[MockFunction icons.Locked]}
|
||||
variant="outline-primary"
|
||||
>
|
||||
Upgrade
|
||||
</Button>
|
||||
`;
|
||||
@@ -0,0 +1,21 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ViewCourseButton snapshot default button 1`] = `
|
||||
<Button
|
||||
as="a"
|
||||
disabled={false}
|
||||
href="marketingUrl"
|
||||
>
|
||||
View Course
|
||||
</Button>
|
||||
`;
|
||||
|
||||
exports[`ViewCourseButton snapshot disabled button 1`] = `
|
||||
<Button
|
||||
as="a"
|
||||
disabled={true}
|
||||
href="marketingUrl"
|
||||
>
|
||||
View Course
|
||||
</Button>
|
||||
`;
|
||||
@@ -1,36 +1,54 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CourseCard Actions component does not render secondary button if null is returned for secondary props 1`] = `
|
||||
exports[`CourseCardActions snapshot show begin course button when verified and not entitlement and has started 1`] = `
|
||||
<ActionRow
|
||||
data-test-id="CourseCardActions"
|
||||
>
|
||||
<Button
|
||||
cardId="test-course-number"
|
||||
prop1="primary-prop1"
|
||||
prop2="primary-prop2"
|
||||
>
|
||||
primary-children
|
||||
</Button>
|
||||
<BeginCourseButton
|
||||
cardId="cardId"
|
||||
/>
|
||||
</ActionRow>
|
||||
`;
|
||||
|
||||
exports[`CourseCard Actions component loads primary and secondary button props from hook 1`] = `
|
||||
exports[`CourseCardActions snapshot show resume button when verified and not entitlement and has started 1`] = `
|
||||
<ActionRow
|
||||
data-test-id="CourseCardActions"
|
||||
>
|
||||
<Button
|
||||
cardId="test-course-number"
|
||||
prop1="primary-prop1"
|
||||
prop2="primary-prop2"
|
||||
>
|
||||
primary-children
|
||||
</Button>
|
||||
<Button
|
||||
cardId="test-course-number"
|
||||
prop1="primary-prop1"
|
||||
prop2="primary-prop2"
|
||||
>
|
||||
primary-children
|
||||
</Button>
|
||||
<ResumeButton
|
||||
cardId="cardId"
|
||||
/>
|
||||
</ActionRow>
|
||||
`;
|
||||
|
||||
exports[`CourseCardActions snapshot show select session button when not verified and entitlement 1`] = `
|
||||
<ActionRow
|
||||
data-test-id="CourseCardActions"
|
||||
>
|
||||
<SelectSessionButton
|
||||
cardId="cardId"
|
||||
/>
|
||||
</ActionRow>
|
||||
`;
|
||||
|
||||
exports[`CourseCardActions snapshot show upgrade button when not verified and not entitlement 1`] = `
|
||||
<ActionRow
|
||||
data-test-id="CourseCardActions"
|
||||
>
|
||||
<UpgradeButton
|
||||
cardId="cardId"
|
||||
/>
|
||||
<BeginCourseButton
|
||||
cardId="cardId"
|
||||
/>
|
||||
</ActionRow>
|
||||
`;
|
||||
|
||||
exports[`CourseCardActions snapshot show view course button when not verified and entitlement and fulfilled 1`] = `
|
||||
<ActionRow
|
||||
data-test-id="CourseCardActions"
|
||||
>
|
||||
<ViewCourseButton
|
||||
cardId="cardId"
|
||||
/>
|
||||
</ActionRow>
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { hooks } from 'data/redux';
|
||||
import CourseCardActions from '.';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCardCourseRunData: jest.fn(),
|
||||
useCardEnrollmentData: jest.fn(),
|
||||
useCardEntitlementData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('./UpgradeButton', () => 'UpgradeButton');
|
||||
jest.mock('./SelectSessionButton', () => 'SelectSessionButton');
|
||||
jest.mock('./ViewCourseButton', () => 'ViewCourseButton');
|
||||
jest.mock('./BeginCourseButton', () => 'BeginCourseButton');
|
||||
jest.mock('./ResumeButton', () => 'ResumeButton');
|
||||
|
||||
describe('CourseCardActions', () => {
|
||||
const props = {
|
||||
cardId: 'cardId',
|
||||
};
|
||||
const createWrapper = ({
|
||||
isEntitlement, isFulfilled, isArchived, isVerified, hasStarted,
|
||||
}) => {
|
||||
hooks.useCardEntitlementData.mockReturnValueOnce({ isEntitlement, isFulfilled });
|
||||
hooks.useCardCourseRunData.mockReturnValueOnce({ isArchived });
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({ isVerified, hasStarted });
|
||||
return shallow(<CourseCardActions {...props} />);
|
||||
};
|
||||
describe('snapshot', () => {
|
||||
test('show upgrade button when not verified and not entitlement', () => {
|
||||
const wrapper = createWrapper({
|
||||
isEntitlement: false, isFulfilled: false, isArchived: false, isVerified: false, hasStarted: false,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('show select session button when not verified and entitlement', () => {
|
||||
const wrapper = createWrapper({
|
||||
isEntitlement: true, isFulfilled: false, isArchived: false, isVerified: false, hasStarted: false,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('show begin course button when verified and not entitlement and has started', () => {
|
||||
const wrapper = createWrapper({
|
||||
isEntitlement: false, isFulfilled: false, isArchived: false, isVerified: true, hasStarted: false,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('show resume button when verified and not entitlement and has started', () => {
|
||||
const wrapper = createWrapper({
|
||||
isEntitlement: false, isFulfilled: false, isArchived: false, isVerified: true, hasStarted: true,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('show view course button when not verified and entitlement and fulfilled', () => {
|
||||
const wrapper = createWrapper({
|
||||
isEntitlement: true, isFulfilled: true, isArchived: false, isVerified: false, hasStarted: false,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('behavior', () => {
|
||||
it('show upgrade button when not verified and not entitlement', () => {
|
||||
const wrapper = createWrapper({
|
||||
isEntitlement: false, isFulfilled: false, isArchived: false, isVerified: false, hasStarted: false,
|
||||
});
|
||||
expect(wrapper.find('UpgradeButton')).toHaveLength(1);
|
||||
});
|
||||
it('show select session button when not verified and entitlement', () => {
|
||||
const wrapper = createWrapper({
|
||||
isEntitlement: true, isFulfilled: false, isArchived: false, isVerified: false, hasStarted: false,
|
||||
});
|
||||
expect(wrapper.find('SelectSessionButton')).toHaveLength(1);
|
||||
});
|
||||
it('show begin course button when verified and not entitlement and has started', () => {
|
||||
const wrapper = createWrapper({
|
||||
isEntitlement: false, isFulfilled: false, isArchived: false, isVerified: true, hasStarted: false,
|
||||
});
|
||||
expect(wrapper.find('BeginCourseButton')).toHaveLength(1);
|
||||
});
|
||||
it('show resume button when verified and not entitlement and has started', () => {
|
||||
const wrapper = createWrapper({
|
||||
isEntitlement: false, isFulfilled: false, isArchived: false, isVerified: true, hasStarted: true,
|
||||
});
|
||||
expect(wrapper.find('ResumeButton')).toHaveLength(1);
|
||||
});
|
||||
it('show view course button when not verified and entitlement and fulfilled', () => {
|
||||
const wrapper = createWrapper({
|
||||
isEntitlement: true, isFulfilled: true, isArchived: false, isVerified: false, hasStarted: false,
|
||||
});
|
||||
expect(wrapper.find('ViewCourseButton')).toHaveLength(1);
|
||||
});
|
||||
it('show view course button when not verified and entitlement and fulfilled and archived', () => {
|
||||
const wrapper = createWrapper({
|
||||
isEntitlement: true, isFulfilled: true, isArchived: true, isVerified: false, hasStarted: false,
|
||||
});
|
||||
expect(wrapper.find('ViewCourseButton')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,151 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { hooks } from 'data/redux';
|
||||
import CertificateBanner from './CertificateBanner';
|
||||
import messages from './messages';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCardCertificateData: jest.fn(),
|
||||
useCardEnrollmentData: jest.fn(),
|
||||
useCardGradeData: jest.fn(),
|
||||
useCardCourseRunData: jest.fn(),
|
||||
usePlatformSettingsData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('Components/Banner', () => 'Banner');
|
||||
|
||||
describe('CertificateBanner', () => {
|
||||
const props = {
|
||||
cardId: 'cardId',
|
||||
};
|
||||
hooks.usePlatformSettingsData.mockReturnValue({
|
||||
supportEmail: 'suport@email',
|
||||
billingEmail: 'billing@email',
|
||||
});
|
||||
hooks.useCardCourseRunData.mockReturnValue({
|
||||
minPassingGrade: 0.8,
|
||||
progressUrl: 'progressUrl',
|
||||
});
|
||||
|
||||
const defaultCertificate = {
|
||||
isRestricted: false,
|
||||
isDownloadable: false,
|
||||
isEarnedButUnavailable: false,
|
||||
};
|
||||
const defaultEnrollment = {
|
||||
isAudit: false,
|
||||
isVerified: false,
|
||||
hasFinished: false,
|
||||
};
|
||||
const defaultGrade = {
|
||||
isPassing: false,
|
||||
};
|
||||
const createWrapper = ({
|
||||
certificate = {},
|
||||
enrollment = {},
|
||||
grade = {},
|
||||
}) => {
|
||||
hooks.useCardGradeData.mockReturnValueOnce({ ...defaultGrade, ...grade });
|
||||
hooks.useCardCertificateData.mockReturnValueOnce({ ...defaultCertificate, ...certificate });
|
||||
hooks.useCardEnrollmentData.mockReturnValueOnce({ ...defaultEnrollment, ...enrollment });
|
||||
return shallow(<CertificateBanner {...props} />);
|
||||
};
|
||||
describe('snapshot', () => {
|
||||
test('is restricted', () => {
|
||||
const wrapper = createWrapper({
|
||||
certificate: {
|
||||
isRestricted: true,
|
||||
},
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('is restricted and verified', () => {
|
||||
const wrapper = createWrapper({
|
||||
certificate: {
|
||||
isRestricted: true,
|
||||
},
|
||||
enrollment: {
|
||||
isVerified: true,
|
||||
},
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('not passing and audit', () => {
|
||||
const wrapper = createWrapper({
|
||||
enrollment: {
|
||||
isAudit: true,
|
||||
},
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('not passing and has finished', () => {
|
||||
const wrapper = createWrapper({
|
||||
enrollment: {
|
||||
hasFinished: true,
|
||||
},
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('not passing and not audit and not finished', () => {
|
||||
const wrapper = createWrapper({});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('is passing and is downloadable', () => {
|
||||
const wrapper = createWrapper({
|
||||
grade: {
|
||||
isPassing: true,
|
||||
},
|
||||
certificate: {
|
||||
isDownloadable: true,
|
||||
},
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('is passing and is earned but unavailable', () => {
|
||||
const wrapper = createWrapper({
|
||||
grade: {
|
||||
isPassing: true,
|
||||
},
|
||||
certificate: {
|
||||
isEarnedButUnavailable: true,
|
||||
},
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('is passing and not downloadable render empty', () => {
|
||||
const wrapper = createWrapper({
|
||||
grade: {
|
||||
isPassing: true,
|
||||
},
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('behavior', () => {
|
||||
it('is restricted', () => {
|
||||
const wrapper = createWrapper({
|
||||
certificate: {
|
||||
isRestricted: true,
|
||||
},
|
||||
});
|
||||
const bannerMessage = wrapper.find('format-message-function').map(el => el.prop('message').defaultMessage).join('\n');
|
||||
expect(bannerMessage).toEqual(messages.certRestricted.defaultMessage);
|
||||
expect(bannerMessage).toContain(messages.certRestricted.defaultMessage);
|
||||
});
|
||||
it('is restricted and verified', () => {
|
||||
const wrapper = createWrapper({
|
||||
certificate: {
|
||||
isRestricted: true,
|
||||
},
|
||||
enrollment: {
|
||||
isVerified: true,
|
||||
},
|
||||
});
|
||||
const bannerMessage = wrapper.find('format-message-function').map(el => el.prop('message').defaultMessage).join('\n');
|
||||
expect(bannerMessage).toContain(messages.certRestricted.defaultMessage);
|
||||
expect(bannerMessage).toContain(messages.certRefundContactBilling.defaultMessage);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -61,7 +61,7 @@ const render = (overrides = {}) => {
|
||||
};
|
||||
|
||||
describe('CourseBanner', () => {
|
||||
it('initializes data with course number from enrollment, course and course run data', () => {
|
||||
test('initializes data with course number from enrollment, course and course run data', () => {
|
||||
render();
|
||||
expect(appHooks.useCardCourseData).toHaveBeenCalledWith(cardId);
|
||||
expect(appHooks.useCardCourseRunData).toHaveBeenCalledWith(cardId);
|
||||
@@ -145,9 +145,6 @@ describe('CourseBanner', () => {
|
||||
test('snapshot: isStaff', () => {
|
||||
expect(el).toMatchSnapshot();
|
||||
});
|
||||
test('messages: staffAccessOnly', () => {
|
||||
expect(el.text()).toContain(messages.staffAccessOnly.defaultMessage);
|
||||
});
|
||||
});
|
||||
test('snapshot: stacking banners', () => {
|
||||
render({
|
||||
|
||||
@@ -39,7 +39,7 @@ const render = (overrides = {}) => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
describe('EntitlementBanner', () => {
|
||||
it('initializes data with course number from entitlement', () => {
|
||||
test('initializes data with course number from entitlement', () => {
|
||||
render();
|
||||
expect(appHooks.useCardEntitlementData).toHaveBeenCalledWith(cardId);
|
||||
expect(appHooks.useUpdateSelectSessionModalCallback).toHaveBeenCalledWith(dispatch, cardId);
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CertificateBanner snapshot is passing and is downloadable 1`] = `
|
||||
<Banner
|
||||
icon={[MockFunction icons.CheckCircle]}
|
||||
variant="success"
|
||||
>
|
||||
Congratulations. Your certificate is ready.
|
||||
|
||||
<Hyperlink>
|
||||
View Certificate.
|
||||
</Hyperlink>
|
||||
</Banner>
|
||||
`;
|
||||
|
||||
exports[`CertificateBanner snapshot is passing and is earned but unavailable 1`] = `
|
||||
<Banner>
|
||||
Your grade and certificate will be ready after Invalid Date.
|
||||
</Banner>
|
||||
`;
|
||||
|
||||
exports[`CertificateBanner snapshot is passing and not downloadable render empty 1`] = `""`;
|
||||
|
||||
exports[`CertificateBanner snapshot is restricted 1`] = `
|
||||
<Banner
|
||||
variant="danger"
|
||||
>
|
||||
<format-message-function
|
||||
message={
|
||||
Object {
|
||||
"defaultMessage": "Your Certificate of Achievement is being held pending confirmation that the issuance of your Certificate is in compliance with strict U.S. embargoes on Iran, Cuba, Syria, and Sudan. If you think our system has mistakenly identified you as being connected with one of those countries, please let us know by contacting {supportEmail}.",
|
||||
"description": "Restricted certificate warning message",
|
||||
"id": "learner-dash.courseCard.banners.certificateRestricted",
|
||||
}
|
||||
}
|
||||
values={
|
||||
Object {
|
||||
"supportEmail": <MailtoLink
|
||||
to="suport@email"
|
||||
>
|
||||
suport@email
|
||||
</MailtoLink>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Banner>
|
||||
`;
|
||||
|
||||
exports[`CertificateBanner snapshot is restricted and verified 1`] = `
|
||||
<Banner
|
||||
variant="danger"
|
||||
>
|
||||
<format-message-function
|
||||
message={
|
||||
Object {
|
||||
"defaultMessage": "Your Certificate of Achievement is being held pending confirmation that the issuance of your Certificate is in compliance with strict U.S. embargoes on Iran, Cuba, Syria, and Sudan. If you think our system has mistakenly identified you as being connected with one of those countries, please let us know by contacting {supportEmail}.",
|
||||
"description": "Restricted certificate warning message",
|
||||
"id": "learner-dash.courseCard.banners.certificateRestricted",
|
||||
}
|
||||
}
|
||||
values={
|
||||
Object {
|
||||
"supportEmail": <MailtoLink
|
||||
to="suport@email"
|
||||
>
|
||||
suport@email
|
||||
</MailtoLink>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
|
||||
<format-message-function
|
||||
message={
|
||||
Object {
|
||||
"defaultMessage": "If you would like a refund on your Certificate of Achievement, please contact our billing address {billingEmail}",
|
||||
"description": "Message to learners to contact billing for certificate refunds",
|
||||
"id": "learner-dash.courseCard.banners.certificateRefundContactBilling",
|
||||
}
|
||||
}
|
||||
values={
|
||||
Object {
|
||||
"billingEmail": <MailtoLink
|
||||
to="billing@email"
|
||||
>
|
||||
billing@email
|
||||
</MailtoLink>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</Banner>
|
||||
`;
|
||||
|
||||
exports[`CertificateBanner snapshot not passing and audit 1`] = `
|
||||
<Banner>
|
||||
Grade required to pass the course: 0.8
|
||||
</Banner>
|
||||
`;
|
||||
|
||||
exports[`CertificateBanner snapshot not passing and has finished 1`] = `
|
||||
<Banner
|
||||
variant="warning"
|
||||
>
|
||||
You are not eligible for a certificate.
|
||||
.
|
||||
|
||||
<Hyperlink
|
||||
destination="progressUrl"
|
||||
>
|
||||
View grades.
|
||||
</Hyperlink>
|
||||
</Banner>
|
||||
`;
|
||||
|
||||
exports[`CertificateBanner snapshot not passing and not audit and not finished 1`] = `
|
||||
<Banner
|
||||
variant="warning"
|
||||
>
|
||||
Grade required for a certificate: 0.8
|
||||
</Banner>
|
||||
`;
|
||||
@@ -38,27 +38,9 @@ exports[`CourseBanner course run active and cannot upgrade snapshot: (upgradseDe
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`CourseBanner snapshot: stacking banners 1`] = `
|
||||
<Fragment>
|
||||
<Banner>
|
||||
You can't access this course just yet because the course hasn't started yet. The course will start on 11/11/3030.
|
||||
</Banner>
|
||||
<Banner>
|
||||
You can't access this course just yet because you have not met the pre-requisites.
|
||||
</Banner>
|
||||
<Banner>
|
||||
Staff access only.
|
||||
</Banner>
|
||||
</Fragment>
|
||||
`;
|
||||
exports[`CourseBanner snapshot: stacking banners 1`] = `<Fragment />`;
|
||||
|
||||
exports[`CourseBanner staff snapshot: isStaff 1`] = `
|
||||
<Fragment>
|
||||
<Banner>
|
||||
Staff access only.
|
||||
</Banner>
|
||||
</Fragment>
|
||||
`;
|
||||
exports[`CourseBanner staff snapshot: isStaff 1`] = `<Fragment />`;
|
||||
|
||||
exports[`CourseBanner too early snapshot: tooEarly 1`] = `
|
||||
<Fragment>
|
||||
|
||||
@@ -9,11 +9,11 @@ import { hooks as appHooks } from 'data/redux';
|
||||
|
||||
import RelatedProgramsBadge from './RelatedProgramsBadge';
|
||||
import CourseCardMenu from './CourseCardMenu';
|
||||
|
||||
import messages from '../messages';
|
||||
import CourseCardActions from './CourseCardActions';
|
||||
import CourseCardDetails from './CourseCardDetails';
|
||||
|
||||
import messages from '../messages';
|
||||
|
||||
export const CourseCardContent = ({ cardId, orientation }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const { courseName, bannerImgSrc } = appHooks.useCardCourseData(cardId);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { hooks } from 'data/redux';
|
||||
import CourseCardContent from './CourseCardContent';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCardCourseData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('./CourseCardActions', () => 'CourseCardActions');
|
||||
jest.mock('./CourseCardDetails', () => 'CourseCardDetails');
|
||||
jest.mock('./RelatedProgramsBadge', () => 'RelatedProgramsBadge');
|
||||
jest.mock('./CourseCardMenu', () => 'CourseCardMenu');
|
||||
|
||||
describe('CourseCardContent', () => {
|
||||
const props = {
|
||||
cardId: 'test-card-id',
|
||||
orientation: 'vertical',
|
||||
};
|
||||
hooks.useCardCourseData.mockReturnValue({
|
||||
courseName: 'test-course-name',
|
||||
bannerImgSrc: 'test-banner-img-src',
|
||||
});
|
||||
describe('snapshot', () => {
|
||||
test('orientation vertical', () => {
|
||||
const wrapper = shallow(<CourseCardContent {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('orientation horizontal', () => {
|
||||
const wrapper = shallow(<CourseCardContent {...props} orientation="horizontal" />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -15,7 +15,7 @@ jest.mock('./hooks', () => ({
|
||||
const cardId = 'test-card-id';
|
||||
|
||||
describe('CourseCard Details component', () => {
|
||||
it('has change session button on entitlement course', () => {
|
||||
test('has change session button on entitlement course', () => {
|
||||
const mockHook = (args) => () => ({
|
||||
providerName: 'provider-name',
|
||||
accessMessage: 'access-message',
|
||||
@@ -34,7 +34,7 @@ describe('CourseCard Details component', () => {
|
||||
expect(el.text().match(/•/g)).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('does not have change session button on regular course', () => {
|
||||
test('does not have change session button on regular course', () => {
|
||||
const mockHook = (args) => () => ({
|
||||
providerName: 'provider-name',
|
||||
accessMessage: 'acess-message',
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import CourseCardLayout from './CourseCardLayout';
|
||||
import { useIsCollapsed } from '../hooks';
|
||||
|
||||
jest.mock('../hooks', () => ({
|
||||
useIsCollapsed: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('./CourseCardBanners', () => 'CourseCardBanners');
|
||||
jest.mock('./CourseCardContent', () => 'CourseCardContent');
|
||||
|
||||
describe('CourseCardLayout', () => {
|
||||
const props = {
|
||||
cardId: 'test-card-id',
|
||||
};
|
||||
describe('snapshot', () => {
|
||||
test('is collapsed', () => {
|
||||
useIsCollapsed.mockReturnValue(true);
|
||||
const wrapper = shallow(<CourseCardLayout {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('is not collapsed', () => {
|
||||
useIsCollapsed.mockReturnValue(false);
|
||||
const wrapper = shallow(<CourseCardLayout {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CourseCardMenu snapshot 1`] = `
|
||||
<Fragment>
|
||||
<Dropdown>
|
||||
<Dropdown.Toggle
|
||||
alt="Actions dropdown"
|
||||
as="IconButton"
|
||||
iconAs="Icon"
|
||||
id="dropdown-toggle-with-iconbutton"
|
||||
src={[MockFunction icons.MoreVert]}
|
||||
variant="primary"
|
||||
/>
|
||||
<Dropdown.Menu>
|
||||
<Dropdown.Item
|
||||
onClick={[MockFunction unenrollShow]}
|
||||
>
|
||||
Unenroll
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
onClick={[MockFunction emailSettingShow]}
|
||||
>
|
||||
Email Settings
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="#/action-3"
|
||||
>
|
||||
Share to Facebook
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="#/action-3"
|
||||
>
|
||||
Share to Twitter
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
<UnenrollConfirmModal
|
||||
cardId="test-card-id"
|
||||
closeModal={[MockFunction unenrollHide]}
|
||||
show={false}
|
||||
/>
|
||||
<EmailSettingsModal
|
||||
cardId="test-card-id"
|
||||
closeModal={[MockFunction emailSettingHide]}
|
||||
show={false}
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -0,0 +1,58 @@
|
||||
import { MockUseState } from 'testUtils';
|
||||
|
||||
import * as hooks from './hooks';
|
||||
|
||||
const state = new MockUseState(hooks);
|
||||
|
||||
describe('CourseCardMenu hooks', () => {
|
||||
describe('state values', () => {
|
||||
state.testGetter(state.keys.isUnenrollConfirmVisible);
|
||||
state.testGetter(state.keys.isEmailSettingsVisible);
|
||||
});
|
||||
|
||||
describe('useUnenrollData', () => {
|
||||
let out;
|
||||
beforeEach(() => {
|
||||
state.mock();
|
||||
out = hooks.useUnenrollData();
|
||||
});
|
||||
afterEach(state.restore);
|
||||
|
||||
test('default state', () => {
|
||||
expect(out.isVisible).toEqual(state.stateVals.isUnenrollConfirmVisible);
|
||||
});
|
||||
|
||||
test('show', () => {
|
||||
out.show();
|
||||
state.expectSetStateCalledWith(state.keys.isUnenrollConfirmVisible, true);
|
||||
});
|
||||
|
||||
test('hide', () => {
|
||||
out.hide();
|
||||
state.expectSetStateCalledWith(state.keys.isUnenrollConfirmVisible, false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useEmailSettings', () => {
|
||||
let out;
|
||||
beforeEach(() => {
|
||||
state.mock();
|
||||
out = hooks.useEmailSettings();
|
||||
});
|
||||
afterEach(state.restore);
|
||||
|
||||
test('default state', () => {
|
||||
expect(out.isVisible).toEqual(state.stateVals.isEmailSettingsVisible);
|
||||
});
|
||||
|
||||
test('show', () => {
|
||||
out.show();
|
||||
state.expectSetStateCalledWith(state.keys.isEmailSettingsVisible, true);
|
||||
});
|
||||
|
||||
test('hide', () => {
|
||||
out.hide();
|
||||
state.expectSetStateCalledWith(state.keys.isEmailSettingsVisible, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import CourseCardMenu from '.';
|
||||
import useCourseCardMenuData from './hooks';
|
||||
|
||||
jest.mock('./hooks', () => jest.fn());
|
||||
|
||||
describe('CourseCardMenu', () => {
|
||||
const props = {
|
||||
cardId: 'test-card-id',
|
||||
};
|
||||
const defaultEmailSettingsModal = {
|
||||
isVisible: false,
|
||||
show: jest.fn().mockName('emailSettingShow'),
|
||||
hide: jest.fn().mockName('emailSettingHide'),
|
||||
};
|
||||
const defaultUnenrollModal = {
|
||||
isVisible: false,
|
||||
show: jest.fn().mockName('unenrollShow'),
|
||||
hide: jest.fn().mockName('unenrollHide'),
|
||||
};
|
||||
|
||||
test('snapshot', () => {
|
||||
useCourseCardMenuData.mockReturnValue({
|
||||
emailSettingsModal: defaultEmailSettingsModal,
|
||||
unenrollModal: defaultUnenrollModal,
|
||||
});
|
||||
const wrapper = shallow(<CourseCardMenu {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,87 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CourseCardContent snapshot orientation horizontal 1`] = `
|
||||
<Fragment>
|
||||
<Card.ImageCap
|
||||
src="test-banner-img-src"
|
||||
srcAlt="Course thumbnail"
|
||||
/>
|
||||
<Card.Body>
|
||||
<Card.Header
|
||||
actions={
|
||||
<CourseCardMenu
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<span
|
||||
data-testid="CourseCardTitle"
|
||||
>
|
||||
test-course-name
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
<Card.Section
|
||||
className="pt-0"
|
||||
>
|
||||
<CourseCardDetails
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
</Card.Section>
|
||||
<Card.Footer
|
||||
orientation="vertical"
|
||||
textElement={
|
||||
<RelatedProgramsBadge
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
}
|
||||
>
|
||||
<CourseCardActions
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
</Card.Footer>
|
||||
</Card.Body>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`CourseCardContent snapshot orientation vertical 1`] = `
|
||||
<Fragment>
|
||||
<Card.ImageCap
|
||||
src="test-banner-img-src"
|
||||
srcAlt="Course thumbnail"
|
||||
/>
|
||||
<Card.Body>
|
||||
<Card.Header
|
||||
actions={
|
||||
<CourseCardMenu
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
}
|
||||
title={
|
||||
<span
|
||||
data-testid="CourseCardTitle"
|
||||
>
|
||||
test-course-name
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
<Card.Section
|
||||
className="pt-0"
|
||||
>
|
||||
<CourseCardDetails
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
</Card.Section>
|
||||
<RelatedProgramsBadge
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
<Card.Footer
|
||||
orientation="horizontal"
|
||||
>
|
||||
<CourseCardActions
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
</Card.Footer>
|
||||
</Card.Body>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -0,0 +1,63 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CourseCardLayout snapshot is collapsed 1`] = `
|
||||
<div
|
||||
className="mb-4.5 course-card"
|
||||
data-testid="CourseCard"
|
||||
>
|
||||
<Card
|
||||
orientation="vertical"
|
||||
>
|
||||
<div
|
||||
className="d-flex flex-column w-100"
|
||||
>
|
||||
<div
|
||||
className="d-flex"
|
||||
>
|
||||
<CourseCardContent
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="course-card-banners"
|
||||
data-testid="CourseCardBanners"
|
||||
>
|
||||
<CourseCardBanners
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`CourseCardLayout snapshot is not collapsed 1`] = `
|
||||
<div
|
||||
className="mb-4.5 course-card"
|
||||
data-testid="CourseCard"
|
||||
>
|
||||
<Card
|
||||
orientation="horizontal"
|
||||
>
|
||||
<div
|
||||
className="d-flex flex-column w-100"
|
||||
>
|
||||
<div
|
||||
className="d-flex"
|
||||
>
|
||||
<CourseCardContent
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="course-card-banners"
|
||||
data-testid="CourseCardBanners"
|
||||
>
|
||||
<CourseCardBanners
|
||||
cardId="test-card-id"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,21 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { FilterKeys } from 'data/constants/app';
|
||||
import ActiveCourseFilters from './ActiveCourseFilters';
|
||||
|
||||
describe('ActiveCourseFilters', () => {
|
||||
const props = {
|
||||
filters: Object.values(FilterKeys),
|
||||
setFilters: {
|
||||
remove: jest.fn().mockName('setFilters.remove'),
|
||||
clear: jest.fn().mockName('setFilters.clear'),
|
||||
},
|
||||
handleRemoveFilter: jest.fn().mockName('handleRemoveFilter'),
|
||||
};
|
||||
describe('snapshot', () => {
|
||||
test('renders', () => {
|
||||
const wrapper = shallow(<ActiveCourseFilters {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { breakpoints, useWindowSize } from '@edx/paragon';
|
||||
import CourseFilterControls from './CourseFilterControls';
|
||||
import useCourseFilterControlsData from './hooks';
|
||||
|
||||
jest.mock('./hooks', () => jest.fn().mockName('useCourseFilterControlsData'));
|
||||
|
||||
jest.mock('./components/FilterForm', () => 'FilterForm');
|
||||
jest.mock('./components/SortForm', () => 'SortForm');
|
||||
|
||||
describe('CourseFilterControls', () => {
|
||||
const props = {
|
||||
sortBy: 'test-sort-by',
|
||||
setSortBy: jest.fn().mockName('setSortBy'),
|
||||
filters: ['test-filter'],
|
||||
setFilters: {
|
||||
add: jest.fn().mockName('setFilters.add'),
|
||||
remove: jest.fn().mockName('setFilters.remove'),
|
||||
},
|
||||
};
|
||||
|
||||
useCourseFilterControlsData.mockReturnValue({
|
||||
isOpen: false,
|
||||
open: jest.fn().mockName('open'),
|
||||
close: jest.fn().mockName('close'),
|
||||
target: 'test-target',
|
||||
setTarget: jest.fn().mockName('setTarget'),
|
||||
handleFilterChange: jest.fn().mockName('handleFilterChange'),
|
||||
handleSortChange: jest.fn().mockName('handleSortChange'),
|
||||
});
|
||||
|
||||
describe('snapshot', () => {
|
||||
test('is mobile', () => {
|
||||
useWindowSize.mockReturnValueOnce({ width: breakpoints.small.minWidth - 1 });
|
||||
const wrapper = shallow(<CourseFilterControls {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('is not mobile', () => {
|
||||
useWindowSize.mockReturnValueOnce({ width: breakpoints.small.minWidth });
|
||||
const wrapper = shallow(<CourseFilterControls {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ActiveCourseFilters snapshot renders 1`] = `
|
||||
<div
|
||||
id="course-list-active-filters"
|
||||
>
|
||||
<Chip
|
||||
key="inProgress"
|
||||
variant="primary"
|
||||
>
|
||||
In-Progress
|
||||
</Chip>
|
||||
<Chip
|
||||
key="notStarted"
|
||||
variant="primary"
|
||||
>
|
||||
Not Started
|
||||
</Chip>
|
||||
<Chip
|
||||
key="done"
|
||||
variant="primary"
|
||||
>
|
||||
Done
|
||||
</Chip>
|
||||
<Chip
|
||||
key="notEnrolled"
|
||||
variant="primary"
|
||||
>
|
||||
Not Enrolled
|
||||
</Chip>
|
||||
<Chip
|
||||
key="upgraded"
|
||||
variant="primary"
|
||||
>
|
||||
Upgraded
|
||||
</Chip>
|
||||
<Button
|
||||
onClick={[MockFunction setFilters.clear]}
|
||||
variant="link"
|
||||
>
|
||||
Clear all
|
||||
</Button>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,115 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CourseFilterControls snapshot is mobile 1`] = `
|
||||
<div
|
||||
id="course-filter-controls"
|
||||
>
|
||||
<Button
|
||||
iconBefore={[MockFunction icons.Tune]}
|
||||
onClick={[MockFunction open]}
|
||||
variant="outline-primary"
|
||||
>
|
||||
Refine
|
||||
</Button>
|
||||
<Form>
|
||||
<Sheet
|
||||
className="w-75"
|
||||
onClose={[MockFunction close]}
|
||||
position="left"
|
||||
show={false}
|
||||
>
|
||||
<div
|
||||
className="p-1 mr-3"
|
||||
>
|
||||
<b>
|
||||
Refine
|
||||
</b>
|
||||
</div>
|
||||
<hr />
|
||||
<div
|
||||
className="filter-form-row"
|
||||
>
|
||||
<FilterForm
|
||||
filters={
|
||||
Array [
|
||||
"test-filter",
|
||||
]
|
||||
}
|
||||
handleFilterChange={[MockFunction handleFilterChange]}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="filter-form-row text-left m-1"
|
||||
>
|
||||
<SortForm
|
||||
handleSortChange={[MockFunction handleSortChange]}
|
||||
sortBy="test-sort-by"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="pgn__modal-close-container"
|
||||
>
|
||||
<ModalCloseButton
|
||||
onClick={[MockFunction close]}
|
||||
variant="tertiary"
|
||||
>
|
||||
<Icon
|
||||
src={[MockFunction icons.Close]}
|
||||
/>
|
||||
</ModalCloseButton>
|
||||
</div>
|
||||
</Sheet>
|
||||
</Form>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`CourseFilterControls snapshot is not mobile 1`] = `
|
||||
<div
|
||||
id="course-filter-controls"
|
||||
>
|
||||
<Button
|
||||
iconBefore={[MockFunction icons.Tune]}
|
||||
onClick={[MockFunction open]}
|
||||
variant="outline-primary"
|
||||
>
|
||||
Refine
|
||||
</Button>
|
||||
<Form>
|
||||
<ModalPopup
|
||||
isOpen={false}
|
||||
onClose={[MockFunction close]}
|
||||
placement="bottom-end"
|
||||
positionRef="test-target"
|
||||
>
|
||||
<div
|
||||
className="bg-white p-3 rounded shadow d-flex flex-row"
|
||||
id="course-filter-controls-card"
|
||||
>
|
||||
<div
|
||||
className="filter-form-col"
|
||||
>
|
||||
<FilterForm
|
||||
filters={
|
||||
Array [
|
||||
"test-filter",
|
||||
]
|
||||
}
|
||||
handleFilterChange={[MockFunction handleFilterChange]}
|
||||
/>
|
||||
</div>
|
||||
<hr
|
||||
className="h-100 bg-primary-200 m-1"
|
||||
/>
|
||||
<div
|
||||
className="filter-form-col text-left m-1"
|
||||
>
|
||||
<SortForm
|
||||
handleSortChange={[MockFunction handleSortChange]}
|
||||
sortBy="test-sort-by"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</ModalPopup>
|
||||
</Form>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,15 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { FilterKeys } from 'data/constants/app';
|
||||
import Checkbox from './Checkbox';
|
||||
|
||||
describe('Checkbox', () => {
|
||||
describe('snapshot', () => {
|
||||
Object.keys(FilterKeys).forEach((filterKey) => {
|
||||
it(`renders ${filterKey}`, () => {
|
||||
const wrapper = shallow(<Checkbox filterKey={filterKey} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { FilterKeys } from 'data/constants/app';
|
||||
import FilterForm, { filterOrder } from './FilterForm';
|
||||
|
||||
jest.mock('./Checkbox', () => 'Checkbox');
|
||||
|
||||
describe('FilterForm', () => {
|
||||
const props = {
|
||||
filters: ['test-filter'],
|
||||
handleFilterChange: jest.fn().mockName('handleFilterChange'),
|
||||
};
|
||||
describe('snapshot', () => {
|
||||
test('renders', () => {
|
||||
const wrapper = shallow(<FilterForm {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
test('filterOrder', () => {
|
||||
expect(filterOrder).toEqual([
|
||||
FilterKeys.inProgress,
|
||||
FilterKeys.notStarted,
|
||||
FilterKeys.done,
|
||||
FilterKeys.notEnrolled,
|
||||
FilterKeys.upgraded,
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { SortKeys } from 'data/constants/app';
|
||||
import SortForm from './SortForm';
|
||||
|
||||
jest.mock('./Checkbox', () => 'Checkbox');
|
||||
|
||||
describe('SortForm', () => {
|
||||
const props = {
|
||||
handleSortChange: jest.fn().mockName('handleSortChange'),
|
||||
sortBy: SortKeys.enrolled,
|
||||
};
|
||||
describe('snapshot', () => {
|
||||
test('renders', () => {
|
||||
const wrapper = shallow(<SortForm {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Checkbox snapshot renders done 1`] = `
|
||||
<Form.Checkbox
|
||||
className="py-2"
|
||||
value="done"
|
||||
>
|
||||
Done
|
||||
</Form.Checkbox>
|
||||
`;
|
||||
|
||||
exports[`Checkbox snapshot renders inProgress 1`] = `
|
||||
<Form.Checkbox
|
||||
className="py-2"
|
||||
value="inProgress"
|
||||
>
|
||||
In-Progress
|
||||
</Form.Checkbox>
|
||||
`;
|
||||
|
||||
exports[`Checkbox snapshot renders notEnrolled 1`] = `
|
||||
<Form.Checkbox
|
||||
className="py-2"
|
||||
value="notEnrolled"
|
||||
>
|
||||
Not Enrolled
|
||||
</Form.Checkbox>
|
||||
`;
|
||||
|
||||
exports[`Checkbox snapshot renders notStarted 1`] = `
|
||||
<Form.Checkbox
|
||||
className="py-2"
|
||||
value="notStarted"
|
||||
>
|
||||
Not Started
|
||||
</Form.Checkbox>
|
||||
`;
|
||||
|
||||
exports[`Checkbox snapshot renders upgraded 1`] = `
|
||||
<Form.Checkbox
|
||||
className="py-2"
|
||||
value="upgraded"
|
||||
>
|
||||
Upgraded
|
||||
</Form.Checkbox>
|
||||
`;
|
||||
@@ -0,0 +1,41 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`FilterForm snapshot renders 1`] = `
|
||||
<Form.Group>
|
||||
<div
|
||||
className="filter-form-heading mb-1"
|
||||
>
|
||||
Course Status
|
||||
</div>
|
||||
<Form.CheckboxSet
|
||||
name="course-status-filters"
|
||||
onChange={[MockFunction handleFilterChange]}
|
||||
value={
|
||||
Array [
|
||||
"test-filter",
|
||||
]
|
||||
}
|
||||
>
|
||||
<Checkbox
|
||||
filterKey="inProgress"
|
||||
key="inProgress"
|
||||
/>
|
||||
<Checkbox
|
||||
filterKey="notStarted"
|
||||
key="notStarted"
|
||||
/>
|
||||
<Checkbox
|
||||
filterKey="done"
|
||||
key="done"
|
||||
/>
|
||||
<Checkbox
|
||||
filterKey="notEnrolled"
|
||||
key="notEnrolled"
|
||||
/>
|
||||
<Checkbox
|
||||
filterKey="upgraded"
|
||||
key="upgraded"
|
||||
/>
|
||||
</Form.CheckboxSet>
|
||||
</Form.Group>
|
||||
`;
|
||||
@@ -0,0 +1,29 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SortForm snapshot renders 1`] = `
|
||||
<Fragment>
|
||||
<div
|
||||
className="filter-form-heading mb-1"
|
||||
>
|
||||
Sort
|
||||
</div>
|
||||
<Form.RadioSet
|
||||
name="sort"
|
||||
onChange={[MockFunction handleSortChange]}
|
||||
value="enrolled"
|
||||
>
|
||||
<Form.Radio
|
||||
className="py-2"
|
||||
value="enrolled"
|
||||
>
|
||||
Last enrolled
|
||||
</Form.Radio>
|
||||
<Form.Radio
|
||||
className="py-2"
|
||||
value="title"
|
||||
>
|
||||
Title (A-Z)
|
||||
</Form.Radio>
|
||||
</Form.RadioSet>
|
||||
</Fragment>
|
||||
`;
|
||||
@@ -1,13 +1,20 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useToggle } from '@edx/paragon';
|
||||
|
||||
import { StrictDict } from 'utils';
|
||||
|
||||
import * as module from './hooks';
|
||||
|
||||
export const state = StrictDict({
|
||||
target: (val) => React.useState(val), // eslint-disable-line
|
||||
});
|
||||
|
||||
export const useCourseFilterControlsData = ({
|
||||
setFilters,
|
||||
setSortBy,
|
||||
}) => {
|
||||
const [isOpen, open, close] = useToggle(false);
|
||||
const [target, setTarget] = React.useState(null);
|
||||
const [target, setTarget] = module.state.target(null);
|
||||
const handleFilterChange = ({ target: { checked, value } }) => {
|
||||
const update = checked ? setFilters.add : setFilters.remove;
|
||||
update(value);
|
||||
|
||||
82
src/containers/CourseFilterControls/hooks.test.js
Normal file
82
src/containers/CourseFilterControls/hooks.test.js
Normal file
@@ -0,0 +1,82 @@
|
||||
import { useToggle } from '@edx/paragon';
|
||||
|
||||
import { MockUseState } from 'testUtils';
|
||||
|
||||
import * as hooks from './hooks';
|
||||
|
||||
const state = new MockUseState(hooks);
|
||||
|
||||
describe('CourseFilterControls hooks', () => {
|
||||
let out;
|
||||
const setSortBy = jest.fn();
|
||||
const setFilters = {
|
||||
add: jest.fn(),
|
||||
remove: jest.fn(),
|
||||
};
|
||||
const toggleOpen = jest.fn();
|
||||
const toggleClose = jest.fn();
|
||||
describe('state values', () => {
|
||||
state.testGetter(state.keys.target);
|
||||
});
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('useCourseFilterControlsData', () => {
|
||||
beforeEach(() => {
|
||||
useToggle.mockReturnValueOnce([false, toggleOpen, toggleClose]);
|
||||
state.mock();
|
||||
out = hooks.useCourseFilterControlsData({
|
||||
setFilters,
|
||||
setSortBy,
|
||||
});
|
||||
});
|
||||
afterEach(state.restore);
|
||||
|
||||
test('default state', () => {
|
||||
expect(out.isOpen).toEqual(false);
|
||||
expect(out.open).toEqual(toggleOpen);
|
||||
expect(out.close).toEqual(toggleClose);
|
||||
expect(out.target).toEqual(state.stateVals.target);
|
||||
});
|
||||
|
||||
test('isOpen is true when target is set', () => {
|
||||
useToggle.mockReturnValueOnce([true, toggleOpen, toggleClose]);
|
||||
expect(out.target).toEqual(null);
|
||||
state.mockVal(state.keys.target, 'foo');
|
||||
out = hooks.useCourseFilterControlsData({
|
||||
setFilters,
|
||||
setSortBy,
|
||||
});
|
||||
expect(out.isOpen).toEqual(true);
|
||||
expect(out.target).toEqual('foo');
|
||||
});
|
||||
|
||||
test('handle filter change', () => {
|
||||
const value = 'a';
|
||||
out.handleFilterChange({
|
||||
target: {
|
||||
checked: true,
|
||||
value,
|
||||
},
|
||||
});
|
||||
expect(setFilters.add).toHaveBeenCalledWith(value);
|
||||
out.handleFilterChange({
|
||||
target: {
|
||||
checked: false,
|
||||
value,
|
||||
},
|
||||
});
|
||||
expect(setFilters.remove).toHaveBeenCalledWith(value);
|
||||
});
|
||||
test('handle sort change', () => {
|
||||
const value = 'a';
|
||||
out.handleSortChange({
|
||||
target: {
|
||||
value,
|
||||
},
|
||||
});
|
||||
expect(setSortBy).toHaveBeenCalledWith(value);
|
||||
});
|
||||
});
|
||||
});
|
||||
118
src/containers/CourseList/__snapshots__/index.test.jsx.snap
Normal file
118
src/containers/CourseList/__snapshots__/index.test.jsx.snap
Normal file
@@ -0,0 +1,118 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`CourseList snapshots with filters 1`] = `
|
||||
<div
|
||||
className="course-list-container"
|
||||
>
|
||||
<div
|
||||
id="course-list-heading-container"
|
||||
>
|
||||
<h2
|
||||
className="my-2"
|
||||
>
|
||||
My Courses
|
||||
</h2>
|
||||
<div
|
||||
className="text-right"
|
||||
id="course-filter-controls-container"
|
||||
>
|
||||
<CourseFilterControls
|
||||
abitary="filter"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="course-list-active-filters-container"
|
||||
>
|
||||
<ActiveCourseFilters
|
||||
abitary="filter"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="d-flex flex-column flex-grow-1"
|
||||
>
|
||||
<Pagination
|
||||
onPageSelect={[MockFunction setPageNumber]}
|
||||
pageCount={1}
|
||||
paginationLabel="Course List"
|
||||
variant="secondary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`CourseList snapshots with multiple courses and pages 1`] = `
|
||||
<div
|
||||
className="course-list-container"
|
||||
>
|
||||
<div
|
||||
id="course-list-heading-container"
|
||||
>
|
||||
<h2
|
||||
className="my-2"
|
||||
>
|
||||
My Courses
|
||||
</h2>
|
||||
<div
|
||||
className="text-right"
|
||||
id="course-filter-controls-container"
|
||||
>
|
||||
<CourseFilterControls />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="d-flex flex-column flex-grow-1"
|
||||
>
|
||||
<CourseCard
|
||||
cardId="foo"
|
||||
key="foo"
|
||||
/>
|
||||
<CourseCard
|
||||
cardId="bar"
|
||||
key="bar"
|
||||
/>
|
||||
<CourseCard
|
||||
cardId="baz"
|
||||
key="baz"
|
||||
/>
|
||||
<Pagination
|
||||
onPageSelect={[MockFunction setPageNumber]}
|
||||
pageCount={3}
|
||||
paginationLabel="Course List"
|
||||
variant="secondary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`CourseList snapshots with no filters 1`] = `
|
||||
<div
|
||||
className="course-list-container"
|
||||
>
|
||||
<div
|
||||
id="course-list-heading-container"
|
||||
>
|
||||
<h2
|
||||
className="my-2"
|
||||
>
|
||||
My Courses
|
||||
</h2>
|
||||
<div
|
||||
className="text-right"
|
||||
id="course-filter-controls-container"
|
||||
>
|
||||
<CourseFilterControls />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="d-flex flex-column flex-grow-1"
|
||||
>
|
||||
<Pagination
|
||||
onPageSelect={[MockFunction setPageNumber]}
|
||||
pageCount={1}
|
||||
paginationLabel="Course List"
|
||||
variant="secondary"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
43
src/containers/CourseList/hooks.js
Normal file
43
src/containers/CourseList/hooks.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useCheckboxSetValues } from '@edx/paragon';
|
||||
|
||||
import { StrictDict } from 'utils';
|
||||
import { hooks as appHooks } from 'data/redux';
|
||||
import { ListPageSize, SortKeys } from 'data/constants/app';
|
||||
|
||||
import * as module from './hooks';
|
||||
|
||||
export const state = StrictDict({
|
||||
pageNumber: (val) => React.useState(val), // eslint-disable-line
|
||||
sortBy: (val) => React.useState(val), // eslint-disable-line
|
||||
});
|
||||
|
||||
export const useCourseListData = () => {
|
||||
const [pageNumber, setPageNumber] = module.state.pageNumber(1);
|
||||
const [sortBy, setSortBy] = module.state.sortBy(SortKeys.title);
|
||||
const [filters, setFilters] = useCheckboxSetValues([]);
|
||||
const { numPages, visible } = appHooks.useCurrentCourseList({
|
||||
sortBy,
|
||||
isAscending: true,
|
||||
filters,
|
||||
pageNumber,
|
||||
pageSize: ListPageSize,
|
||||
});
|
||||
const handleRemoveFilter = (filter) => () => setFilters.remove(filter);
|
||||
return {
|
||||
numPages,
|
||||
setPageNumber,
|
||||
visibleList: visible,
|
||||
filterOptions: {
|
||||
sortBy,
|
||||
setSortBy,
|
||||
filters,
|
||||
setFilters,
|
||||
handleRemoveFilter,
|
||||
},
|
||||
showFilters: filters.length > 0,
|
||||
};
|
||||
};
|
||||
|
||||
export default useCourseListData;
|
||||
55
src/containers/CourseList/hooks.test.js
Normal file
55
src/containers/CourseList/hooks.test.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { MockUseState } from 'testUtils';
|
||||
|
||||
import { hooks as appHooks } from 'data/redux';
|
||||
import * as hooks from './hooks';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useCurrentCourseList: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const state = new MockUseState(hooks);
|
||||
|
||||
describe('CourseList hooks', () => {
|
||||
let out;
|
||||
describe('state values', () => {
|
||||
state.testGetter(state.keys.pageNumber);
|
||||
state.testGetter(state.keys.sortBy);
|
||||
});
|
||||
|
||||
describe('useCourseListData', () => {
|
||||
beforeEach(() => state.mock());
|
||||
afterEach(state.restore);
|
||||
|
||||
test('empty initializes', () => {
|
||||
appHooks.useCurrentCourseList.mockReturnValueOnce({
|
||||
numPages: 1,
|
||||
visible: [],
|
||||
});
|
||||
out = hooks.useCourseListData();
|
||||
expect(out.numPages).toEqual(1);
|
||||
expect(out.visibleList).toEqual([]);
|
||||
});
|
||||
|
||||
test('page count and visble list', () => {
|
||||
const result = {
|
||||
numPages: 2,
|
||||
visible: ['a', 'b'],
|
||||
};
|
||||
appHooks.useCurrentCourseList.mockReturnValueOnce(result);
|
||||
out = hooks.useCourseListData();
|
||||
expect(out.numPages).toEqual(result.numPages);
|
||||
expect(out.visibleList).toEqual(result.visible);
|
||||
});
|
||||
test('handle remove filter', () => {
|
||||
appHooks.useCurrentCourseList.mockReturnValueOnce({
|
||||
numPages: 1,
|
||||
visible: [],
|
||||
});
|
||||
out = hooks.useCourseListData();
|
||||
out.filterOptions.handleRemoveFilter('a')();
|
||||
expect(out.filterOptions.setFilters.remove).toHaveBeenCalledWith('a');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,48 +1,19 @@
|
||||
import React from 'react';
|
||||
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import {
|
||||
Pagination,
|
||||
useCheckboxSetValues,
|
||||
} from '@edx/paragon';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Pagination } from '@edx/paragon';
|
||||
|
||||
import { hooks as appHooks } from 'data/redux';
|
||||
import { ListPageSize, SortKeys } from 'data/constants/app';
|
||||
import { ActiveCourseFilters, CourseFilterControls } from 'containers/CourseFilterControls';
|
||||
import CourseCard from 'containers/CourseCard';
|
||||
|
||||
import { useCourseListData } from './hooks';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
export const useCourseListData = () => {
|
||||
const [pageNumber, setPageNumber] = React.useState(1);
|
||||
const [sortBy, setSortBy] = React.useState(SortKeys.title);
|
||||
const [filters, setFilters] = useCheckboxSetValues([]);
|
||||
const { numPages, visible } = appHooks.useCurrentCourseList({
|
||||
sortBy,
|
||||
isAscending: true,
|
||||
filters,
|
||||
pageNumber,
|
||||
pageSize: ListPageSize,
|
||||
});
|
||||
const handleRemoveFilter = (filter) => () => setFilters.remove(filter);
|
||||
return {
|
||||
numPages,
|
||||
setPageNumber,
|
||||
visibleList: visible,
|
||||
filterOptions: {
|
||||
sortBy,
|
||||
setSortBy,
|
||||
filters,
|
||||
setFilters,
|
||||
handleRemoveFilter,
|
||||
},
|
||||
showFilters: filters.length > 0,
|
||||
};
|
||||
};
|
||||
|
||||
export const CourseList = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
const {
|
||||
filterOptions,
|
||||
setPageNumber,
|
||||
@@ -53,8 +24,8 @@ export const CourseList = () => {
|
||||
return (
|
||||
<div className="course-list-container">
|
||||
<div id="course-list-heading-container">
|
||||
<h2 className="my-3">
|
||||
<FormattedMessage {...messages.myCourses} />
|
||||
<h2 className="my-2">
|
||||
{formatMessage(messages.myCourses)}
|
||||
</h2>
|
||||
<div
|
||||
id="course-filter-controls-container"
|
||||
|
||||
54
src/containers/CourseList/index.test.jsx
Normal file
54
src/containers/CourseList/index.test.jsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import CourseList from '.';
|
||||
import { useCourseListData } from './hooks';
|
||||
|
||||
jest.mock('./hooks', () => ({
|
||||
useCourseListData: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('containers/CourseCard', () => 'CourseCard');
|
||||
jest.mock('containers/CourseFilterControls', () => ({
|
||||
ActiveCourseFilters: 'ActiveCourseFilters',
|
||||
CourseFilterControls: 'CourseFilterControls',
|
||||
}));
|
||||
|
||||
describe('CourseList', () => {
|
||||
const defaultCourseListData = {
|
||||
filterOptions: {},
|
||||
numPages: 1,
|
||||
setPageNumber: jest.fn().mockName('setPageNumber'),
|
||||
showFilters: false,
|
||||
visibleList: [],
|
||||
};
|
||||
const createWrapper = (courseListData) => {
|
||||
useCourseListData.mockReturnValueOnce({
|
||||
...defaultCourseListData,
|
||||
...courseListData,
|
||||
});
|
||||
return shallow(<CourseList />);
|
||||
};
|
||||
|
||||
describe('snapshots', () => {
|
||||
test('with no filters', () => {
|
||||
const wrapper = createWrapper();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('with filters', () => {
|
||||
const wrapper = createWrapper({
|
||||
filterOptions: {
|
||||
abitary: 'filter',
|
||||
},
|
||||
showFilters: true,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('with multiple courses and pages', () => {
|
||||
const wrapper = createWrapper({
|
||||
visibleList: [{ cardId: 'foo' }, { cardId: 'bar' }, { cardId: 'baz' }],
|
||||
numPages: 3,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
86
src/containers/Dashboard/__snapshots__/index.test.jsx.snap
Normal file
86
src/containers/Dashboard/__snapshots__/index.test.jsx.snap
Normal file
@@ -0,0 +1,86 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Dashboard snapshots there are available dashboards 1`] = `
|
||||
<div
|
||||
className="d-flex flex-column p-2"
|
||||
id="dashboard-container"
|
||||
>
|
||||
<EnterpriseDashboardModal />
|
||||
<EmptyCourse />
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Dashboard snapshots there are courses 1`] = `
|
||||
<div
|
||||
className="d-flex flex-column p-2"
|
||||
id="dashboard-container"
|
||||
>
|
||||
<Container
|
||||
fluid={true}
|
||||
size="xl"
|
||||
>
|
||||
<Row>
|
||||
<Col
|
||||
className="p-0 px-4"
|
||||
lg={
|
||||
Object {
|
||||
"offset": 1,
|
||||
"span": 10,
|
||||
}
|
||||
}
|
||||
md={
|
||||
Object {
|
||||
"offset": 0,
|
||||
"span": 12,
|
||||
}
|
||||
}
|
||||
sm={
|
||||
Object {
|
||||
"offset": 2,
|
||||
"span": 8,
|
||||
}
|
||||
}
|
||||
xl={
|
||||
Object {
|
||||
"offset": 0,
|
||||
"span": 8,
|
||||
}
|
||||
}
|
||||
xs={
|
||||
Object {
|
||||
"offset": 0,
|
||||
"span": 12,
|
||||
}
|
||||
}
|
||||
>
|
||||
<CourseList />
|
||||
</Col>
|
||||
<Col
|
||||
className="p-0 pr-4 pl-1"
|
||||
md={12}
|
||||
xl={4}
|
||||
>
|
||||
<WidgetSidebar />
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Dashboard snapshots there are no courses 1`] = `
|
||||
<div
|
||||
className="d-flex flex-column p-2"
|
||||
id="dashboard-container"
|
||||
>
|
||||
<EmptyCourse />
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Dashboard snapshots there is a select session modal 1`] = `
|
||||
<div
|
||||
className="d-flex flex-column p-2"
|
||||
id="dashboard-container"
|
||||
>
|
||||
<EmptyCourse />
|
||||
</div>
|
||||
`;
|
||||
120
src/containers/Dashboard/index.test.jsx
Normal file
120
src/containers/Dashboard/index.test.jsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { hooks } from 'data/redux';
|
||||
|
||||
import CourseList from 'containers/CourseList';
|
||||
import WidgetSidebar from 'containers/WidgetSidebar';
|
||||
import EmptyCourse from 'containers/EmptyCourse';
|
||||
import SelectSessionModal from 'containers/SelectSessionModal';
|
||||
import EnterpriseDashboardModal from 'containers/EnterpriseDashboardModal';
|
||||
|
||||
import Dashboard from '.';
|
||||
|
||||
jest.mock('data/redux', () => ({
|
||||
thunkActions: {
|
||||
app: {
|
||||
initialize: jest.fn(),
|
||||
},
|
||||
},
|
||||
hooks: {
|
||||
useHasCourses: jest.fn(),
|
||||
useHasAvailableDashboards: jest.fn(),
|
||||
useShowSelectSessionModal: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('containers/CourseList', () => 'CourseList');
|
||||
jest.mock('containers/WidgetSidebar', () => 'WidgetSidebar');
|
||||
jest.mock('containers/EmptyCourse', () => 'EmptyCourse');
|
||||
jest.mock('containers/SelectSessionModal', () => 'SelectSessionModal');
|
||||
jest.mock('containers/EnterpriseDashboardModal', () => 'EnterpriseDashboardModal');
|
||||
|
||||
describe('Dashboard', () => {
|
||||
const createWrapper = ({
|
||||
hasCourses,
|
||||
hasAvailableDashboards,
|
||||
showSelectSessionModal,
|
||||
}) => {
|
||||
hooks.useHasCourses.mockReturnValueOnce(hasCourses);
|
||||
hooks.useHasAvailableDashboards.mockReturnValueOnce(hasAvailableDashboards);
|
||||
hooks.useShowSelectSessionModal.mockReturnValueOnce(showSelectSessionModal);
|
||||
return shallow(<Dashboard />);
|
||||
};
|
||||
|
||||
describe('snapshots', () => {
|
||||
test('there are courses', () => {
|
||||
const wrapper = createWrapper({
|
||||
hasCourses: true,
|
||||
hasAvailableDashboards: false,
|
||||
showSelectSessionModal: false,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('there are no courses', () => {
|
||||
const wrapper = createWrapper({
|
||||
hasCourses: false,
|
||||
hasAvailableDashboards: false,
|
||||
showSelectSessionModal: false,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('there are available dashboards', () => {
|
||||
const wrapper = createWrapper({
|
||||
hasCourses: false,
|
||||
hasAvailableDashboards: true,
|
||||
showSelectSessionModal: false,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('there is a select session modal', () => {
|
||||
const wrapper = createWrapper({
|
||||
hasCourses: false,
|
||||
hasAvailableDashboards: false,
|
||||
showSelectSessionModal: true,
|
||||
});
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('behavior', () => {
|
||||
it('initializes the app without courses', () => {
|
||||
const wrapper = createWrapper({
|
||||
hasCourses: false,
|
||||
hasAvailableDashboards: false,
|
||||
showSelectSessionModal: false,
|
||||
});
|
||||
expect(wrapper.find(EmptyCourse).length).toEqual(1);
|
||||
expect(wrapper.find(CourseList).length).toEqual(0);
|
||||
expect(wrapper.find(WidgetSidebar).length).toEqual(0);
|
||||
expect(wrapper.find(SelectSessionModal).length).toEqual(0);
|
||||
expect(wrapper.find(EnterpriseDashboardModal).length).toEqual(0);
|
||||
});
|
||||
it('initializes the app with courses, dashboard and select', () => {
|
||||
const wrapper = createWrapper({
|
||||
hasCourses: true,
|
||||
hasAvailableDashboards: true,
|
||||
showSelectSessionModal: true,
|
||||
});
|
||||
expect(wrapper.find(EmptyCourse).length).toEqual(0);
|
||||
expect(wrapper.find(CourseList).length).toEqual(1);
|
||||
expect(wrapper.find(WidgetSidebar).length).toEqual(1);
|
||||
expect(wrapper.find(SelectSessionModal).length).toEqual(1);
|
||||
expect(wrapper.find(EnterpriseDashboardModal).length).toEqual(1);
|
||||
});
|
||||
it('initializes the app with courses, dashboard and no select', () => {
|
||||
const wrapper = createWrapper({
|
||||
hasCourses: true,
|
||||
hasAvailableDashboards: true,
|
||||
showSelectSessionModal: false,
|
||||
});
|
||||
expect(wrapper.find(EmptyCourse).length).toEqual(0);
|
||||
expect(wrapper.find(CourseList).length).toEqual(1);
|
||||
expect(wrapper.find(WidgetSidebar).length).toEqual(1);
|
||||
expect(wrapper.find(SelectSessionModal).length).toEqual(0);
|
||||
expect(wrapper.find(EnterpriseDashboardModal).length).toEqual(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { hooks as appHooks } from 'data/redux';
|
||||
import { AuthenticatedUserDropdown } from './AuthenticatedUserDropdown';
|
||||
import { useIsCollapsed } from './hooks';
|
||||
|
||||
jest.mock('@edx/frontend-platform/react', () => ({
|
||||
AppContext: {
|
||||
authenticatedUser: {
|
||||
profileImage: 'profileImage',
|
||||
},
|
||||
},
|
||||
}));
|
||||
jest.mock('data/redux', () => ({
|
||||
hooks: {
|
||||
useEnterpriseDashboardData: jest.fn(),
|
||||
},
|
||||
}));
|
||||
jest.mock('containers/LearnerDashboardHeader/hooks', () => ({
|
||||
useIsCollapsed: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('AuthenticatedUserDropdown', () => {
|
||||
const props = {
|
||||
username: 'username',
|
||||
};
|
||||
const defaultDashboardData = {
|
||||
label: 'label',
|
||||
url: 'url',
|
||||
};
|
||||
|
||||
describe('snapshots', () => {
|
||||
test('with enterprise dashboard', () => {
|
||||
appHooks.useEnterpriseDashboardData.mockReturnValueOnce(defaultDashboardData);
|
||||
useIsCollapsed.mockReturnValueOnce(true);
|
||||
const wrapper = shallow(<AuthenticatedUserDropdown {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('without enterprise dashboard and expanded', () => {
|
||||
appHooks.useEnterpriseDashboardData.mockReturnValueOnce(null);
|
||||
useIsCollapsed.mockReturnValueOnce(false);
|
||||
const wrapper = shallow(<AuthenticatedUserDropdown {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,12 +3,14 @@ import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Image } from '@edx/paragon';
|
||||
|
||||
import messages from './messages';
|
||||
|
||||
export const GreetingBanner = ({ size }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
let greetMessage;
|
||||
const hour = new Date().getHours();
|
||||
|
||||
@@ -39,11 +41,11 @@ export const GreetingBanner = ({ size }) => {
|
||||
{isSmall
|
||||
? (
|
||||
<h5 className="text-center text-accent-b">
|
||||
<FormattedMessage {...greetMessage} />
|
||||
{formatMessage(greetMessage)}
|
||||
</h5>
|
||||
) : (
|
||||
<h1 className="text-center text-accent-b">
|
||||
<FormattedMessage {...greetMessage} />
|
||||
{formatMessage(greetMessage)}
|
||||
</h1>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { GreetingBanner } from './GreetingBanner';
|
||||
|
||||
describe('GreetingBanner', () => {
|
||||
const morning = new Date('2021-01-01T11:59:59.999');
|
||||
const afternoon = new Date('2021-01-01T16:59:59.999');
|
||||
const evening = new Date('2021-01-01T18:00:00');
|
||||
afterAll(() => jest.useRealTimers());
|
||||
describe('snapshots', () => {
|
||||
['small', 'large'].forEach((size) => {
|
||||
test(`with size ${size} and morning`, () => {
|
||||
jest.useFakeTimers('modern').setSystemTime(morning);
|
||||
const wrapper = shallow(<GreetingBanner size={size} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test(`with size ${size} and afternoon`, () => {
|
||||
jest.useFakeTimers('modern').setSystemTime(afternoon);
|
||||
const wrapper = shallow(<GreetingBanner size={size} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test(`with size ${size} and evening`, () => {
|
||||
jest.useFakeTimers('modern').setSystemTime(evening);
|
||||
const wrapper = shallow(<GreetingBanner size={size} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,121 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AuthenticatedUserDropdown snapshots with enterprise dashboard 1`] = `
|
||||
<Dropdown
|
||||
className="user-dropdown"
|
||||
>
|
||||
<Dropdown.Toggle
|
||||
id="user"
|
||||
src="profileImage"
|
||||
variant="primary"
|
||||
>
|
||||
<span
|
||||
className="d-none d-md-inline"
|
||||
data-hj-suppress={true}
|
||||
>
|
||||
username
|
||||
</span>
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu
|
||||
className="dropdown-menu-right"
|
||||
>
|
||||
<Dropdown.Header>
|
||||
SWITCH DASHBOARD
|
||||
</Dropdown.Header>
|
||||
<Dropdown.Item
|
||||
as="a"
|
||||
className="active"
|
||||
href="/edx-dashboard"
|
||||
>
|
||||
Personal
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
as="a"
|
||||
href="url"
|
||||
key="label"
|
||||
>
|
||||
label
|
||||
|
||||
Dashboard
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Divider />
|
||||
<Dropdown.Item
|
||||
href="http://localhost:18000/u/username"
|
||||
>
|
||||
Profile
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="http://localhost:18000/u/username"
|
||||
>
|
||||
View Programs
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="http://localhost:18000/account/settings"
|
||||
>
|
||||
Account
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item>
|
||||
Help
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Divider />
|
||||
<Dropdown.Item
|
||||
href="http://localhost:18000/logout"
|
||||
>
|
||||
Sign Out
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
`;
|
||||
|
||||
exports[`AuthenticatedUserDropdown snapshots without enterprise dashboard and expanded 1`] = `
|
||||
<Dropdown
|
||||
className="user-dropdown"
|
||||
>
|
||||
<Dropdown.Toggle
|
||||
id="user"
|
||||
src="profileImage"
|
||||
variant="primary"
|
||||
>
|
||||
<span
|
||||
className="d-none d-md-inline"
|
||||
data-hj-suppress={true}
|
||||
>
|
||||
username
|
||||
</span>
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu
|
||||
className="dropdown-menu-right"
|
||||
>
|
||||
<Dropdown.Header>
|
||||
SWITCH DASHBOARD
|
||||
</Dropdown.Header>
|
||||
<Dropdown.Item
|
||||
as="a"
|
||||
className="active"
|
||||
href="/edx-dashboard"
|
||||
>
|
||||
Personal
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Divider />
|
||||
<Dropdown.Item
|
||||
href="http://localhost:18000/u/username"
|
||||
>
|
||||
Profile
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item
|
||||
href="http://localhost:18000/account/settings"
|
||||
>
|
||||
Account
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item>
|
||||
Help
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Divider />
|
||||
<Dropdown.Item
|
||||
href="http://localhost:18000/logout"
|
||||
>
|
||||
Sign Out
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
`;
|
||||
@@ -0,0 +1,151 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`GreetingBanner snapshots with size large and afternoon 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center p-5"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "148px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
className="greetings-slash-container-large bg-brand-500"
|
||||
/>
|
||||
<h1
|
||||
className="text-center text-accent-b"
|
||||
>
|
||||
Good Afternoon!
|
||||
</h1>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`GreetingBanner snapshots with size large and evening 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center p-5"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "148px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
className="greetings-slash-container-large bg-brand-500"
|
||||
/>
|
||||
<h1
|
||||
className="text-center text-accent-b"
|
||||
>
|
||||
Good Evening!
|
||||
</h1>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`GreetingBanner snapshots with size large and morning 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center p-5"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "148px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
className="greetings-slash-container-large bg-brand-500"
|
||||
/>
|
||||
<h1
|
||||
className="text-center text-accent-b"
|
||||
>
|
||||
Good Morning!
|
||||
</h1>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`GreetingBanner snapshots with size small and afternoon 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center p-3.5"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "46px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
className="greetings-slash-container-small bg-brand-500"
|
||||
/>
|
||||
<h5
|
||||
className="text-center text-accent-b"
|
||||
>
|
||||
Good Afternoon!
|
||||
</h5>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`GreetingBanner snapshots with size small and evening 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center p-3.5"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "46px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
className="greetings-slash-container-small bg-brand-500"
|
||||
/>
|
||||
<h5
|
||||
className="text-center text-accent-b"
|
||||
>
|
||||
Good Evening!
|
||||
</h5>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`GreetingBanner snapshots with size small and morning 1`] = `
|
||||
<div
|
||||
className="d-flex align-items-center justify-content-center p-3.5"
|
||||
>
|
||||
<Image
|
||||
alt="localhost"
|
||||
className="d-block"
|
||||
src="https://edx-cdn.org/v3/default/logo-white.svg"
|
||||
style={
|
||||
Object {
|
||||
"width": "46px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<div
|
||||
className="greetings-slash-container-small bg-brand-500"
|
||||
/>
|
||||
<h5
|
||||
className="text-center text-accent-b"
|
||||
>
|
||||
Good Morning!
|
||||
</h5>
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1,74 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LearnerDashboardHeader UserMenu snapshots with authenticated user 1`] = `
|
||||
<AuthenticatedUserDropdown
|
||||
username="test-username"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`LearnerDashboardHeader UserMenu snapshots without authenticated user 1`] = `""`;
|
||||
|
||||
exports[`LearnerDashboardHeader snapshots with collapsed 1`] = `
|
||||
<Fragment>
|
||||
<ConfirmEmailBanner />
|
||||
<div
|
||||
className="flex-column bg-primary"
|
||||
>
|
||||
<header
|
||||
className="learner-dashboard-header"
|
||||
>
|
||||
<div
|
||||
className="d-flex"
|
||||
>
|
||||
<div
|
||||
className="flex-grow-1"
|
||||
>
|
||||
<GreetingBanner
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="my-auto ml-1"
|
||||
>
|
||||
<UserMenu />
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</div>
|
||||
<MasqueradeBar />
|
||||
<hr />
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`LearnerDashboardHeader snapshots without collapsed 1`] = `
|
||||
<Fragment>
|
||||
<ConfirmEmailBanner />
|
||||
<div
|
||||
className="flex-column bg-primary"
|
||||
>
|
||||
<header
|
||||
className="learner-dashboard-header"
|
||||
>
|
||||
<div
|
||||
className="d-flex"
|
||||
>
|
||||
<Button
|
||||
iconBefore={[MockFunction icons.Program]}
|
||||
variant="inverse-tertiary"
|
||||
>
|
||||
Switch to Programs
|
||||
</Button>
|
||||
<div
|
||||
className="flex-grow-1"
|
||||
/>
|
||||
<UserMenu />
|
||||
</div>
|
||||
</header>
|
||||
<GreetingBanner
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<MasqueradeBar />
|
||||
<hr />
|
||||
</Fragment>
|
||||
`;
|
||||
15
src/containers/LearnerDashboardHeader/hooks.test.js
Normal file
15
src/containers/LearnerDashboardHeader/hooks.test.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { useWindowSize, breakpoints } from '@edx/paragon';
|
||||
import { useIsCollapsed } from './hooks';
|
||||
|
||||
describe('LearnerDashboardHeader hooks', () => {
|
||||
describe('useIsCollapsed', () => {
|
||||
test('large screen is not collapsed', () => {
|
||||
useWindowSize.mockReturnValueOnce({ width: breakpoints.large.maxWidth + 1 });
|
||||
expect(useIsCollapsed()).toEqual(false);
|
||||
});
|
||||
test('small screen is collapsed', () => {
|
||||
useWindowSize.mockReturnValueOnce({ width: breakpoints.large.maxWidth - 1 });
|
||||
expect(useIsCollapsed()).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -6,10 +6,11 @@ import { Program } from '@edx/paragon/icons';
|
||||
import { Button } from '@edx/paragon';
|
||||
|
||||
import MasqueradeBar from 'containers/MasqueradeBar';
|
||||
import AuthenticatedUserDropdown from './AuthenticatedUserDropdown';
|
||||
|
||||
import AuthenticatedUserDropdown from './AuthenticatedUserDropdown';
|
||||
import GreetingBanner from './GreetingBanner';
|
||||
import ConfirmEmailBanner from './ConfirmEmailBanner';
|
||||
|
||||
import { useIsCollapsed } from './hooks';
|
||||
import messages from './messages';
|
||||
import './index.scss';
|
||||
|
||||
51
src/containers/LearnerDashboardHeader/index.test.jsx
Normal file
51
src/containers/LearnerDashboardHeader/index.test.jsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { shallow } from 'enzyme';
|
||||
import { AppContext } from '@edx/frontend-platform/react';
|
||||
|
||||
import LearnerDashboardHeader, { UserMenu } from '.';
|
||||
|
||||
import { useIsCollapsed } from './hooks';
|
||||
|
||||
jest.mock('@edx/frontend-platform/react', () => ({
|
||||
AppContext: {
|
||||
authenticatedUser: {
|
||||
username: 'test-username',
|
||||
},
|
||||
},
|
||||
}));
|
||||
jest.mock('./hooks', () => ({
|
||||
useIsCollapsed: jest.fn(),
|
||||
}));
|
||||
jest.mock('containers/MasqueradeBar', () => 'MasqueradeBar');
|
||||
|
||||
jest.mock('./ConfirmEmailBanner', () => 'ConfirmEmailBanner');
|
||||
jest.mock('./AuthenticatedUserDropdown', () => 'AuthenticatedUserDropdown');
|
||||
jest.mock('./GreetingBanner', () => 'GreetingBanner');
|
||||
|
||||
describe('LearnerDashboardHeader', () => {
|
||||
describe('snapshots', () => {
|
||||
test('with collapsed', () => {
|
||||
useIsCollapsed.mockReturnValueOnce(true);
|
||||
const wrapper = shallow(<LearnerDashboardHeader />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('without collapsed', () => {
|
||||
useIsCollapsed.mockReturnValueOnce(false);
|
||||
const wrapper = shallow(<LearnerDashboardHeader />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('UserMenu', () => {
|
||||
describe('snapshots', () => {
|
||||
test('with authenticated user', () => {
|
||||
const wrapper = shallow(<UserMenu />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
test('without authenticated user', () => {
|
||||
AppContext.authenticatedUser = null;
|
||||
const wrapper = shallow(<UserMenu />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`WidgetSidebar snapshots default 1`] = `
|
||||
<div
|
||||
className="widget-sidebar"
|
||||
>
|
||||
<div
|
||||
className="d-flex"
|
||||
>
|
||||
<Card
|
||||
orientation="horizontal"
|
||||
>
|
||||
<Card.ImageCap
|
||||
src="icon/mock/path"
|
||||
srcAlt="course side widget"
|
||||
/>
|
||||
<Card.Body
|
||||
className="m-auto pr-2"
|
||||
>
|
||||
<h4>
|
||||
Looking for a new challenge?
|
||||
</h4>
|
||||
<Hyperlink
|
||||
destination="#"
|
||||
variant="brand"
|
||||
>
|
||||
Explore courses
|
||||
</Hyperlink>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { useIntl } from '@edx/frontend-platform/i18n';
|
||||
import { Hyperlink, Card } from '@edx/paragon';
|
||||
|
||||
import moreCoursesSVG from 'assets/more-courses-sidewidget.svg';
|
||||
@@ -8,25 +8,28 @@ import messages from './messages';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
export const WidgetSidebar = () => (
|
||||
<div className="widget-sidebar px-2 mt-5 pt-3">
|
||||
<div className="d-flex">
|
||||
<Card orientation="horizontal">
|
||||
<Card.ImageCap
|
||||
src={moreCoursesSVG}
|
||||
srcAlt="course side widget"
|
||||
/>
|
||||
<Card.Body className="m-auto pr-2">
|
||||
<h4>
|
||||
<FormattedMessage {...messages.lookingForChallengePrompt} />
|
||||
</h4>
|
||||
<Hyperlink variant="brand" destination="#">
|
||||
<FormattedMessage {...messages.findCoursesButton} />
|
||||
</Hyperlink>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
export const WidgetSidebar = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
return (
|
||||
<div className="widget-sidebar">
|
||||
<div className="d-flex">
|
||||
<Card orientation="horizontal">
|
||||
<Card.ImageCap
|
||||
src={moreCoursesSVG}
|
||||
srcAlt="course side widget"
|
||||
/>
|
||||
<Card.Body className="m-auto pr-2">
|
||||
<h4>
|
||||
{formatMessage(messages.lookingForChallengePrompt)}
|
||||
</h4>
|
||||
<Hyperlink variant="brand" destination="#">
|
||||
{formatMessage(messages.findCoursesButton)}
|
||||
</Hyperlink>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export default WidgetSidebar;
|
||||
|
||||
12
src/containers/WidgetSidebar/index.test.jsx
Normal file
12
src/containers/WidgetSidebar/index.test.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import WidgetSidebar from '.';
|
||||
|
||||
describe('WidgetSidebar', () => {
|
||||
describe('snapshots', () => {
|
||||
test('default', () => {
|
||||
const wrapper = shallow(<WidgetSidebar />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user