Fix page buttons (#188)
* add prev/next grades selectors * fix PageButtons props
This commit is contained in:
@@ -208,7 +208,7 @@ export default class Gradebook extends React.Component {
|
||||
<BulkManagementControls courseId={this.props.courseId} />
|
||||
</div>
|
||||
<GradebookTable setGradebookState={this.safeSetState} />
|
||||
{PageButtons(this.props)}
|
||||
<PageButtons {...this.props} />
|
||||
<p>* available for learners in the Master's track only</p>
|
||||
<EditModal
|
||||
assignmentName={this.state.assignmentName}
|
||||
|
||||
@@ -1,36 +1,112 @@
|
||||
import renderer from 'react-test-renderer';
|
||||
import PageButtons from '.';
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
const createInput = function createInput(prevPage, nextPage) {
|
||||
return {
|
||||
prevPage,
|
||||
nextPage,
|
||||
selectedTrack: 't',
|
||||
selectedCohort: 'c',
|
||||
getPrevNextGrades() {},
|
||||
};
|
||||
};
|
||||
import selectors from 'data/selectors';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
describe('PageButtons', () => {
|
||||
const assertPageButtonsSnapshot = function assertPageButtonsSnapshot(input) {
|
||||
const pb = renderer.create(PageButtons(input));
|
||||
const tree = pb.toJSON();
|
||||
expect(tree).toMatchSnapshot();
|
||||
};
|
||||
import { PageButtons, mapStateToProps, mapDispatchToProps } from '.';
|
||||
|
||||
it('prev null, next null', () => {
|
||||
assertPageButtonsSnapshot(createInput(null, null));
|
||||
jest.mock('@edx/paragon', () => ({
|
||||
Button: () => 'Button',
|
||||
}));
|
||||
jest.mock('data/selectors', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
grades: {
|
||||
nextPage: jest.fn(state => ({ nextPage: state })),
|
||||
prevPage: jest.fn(state => ({ prevPage: state })),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('data/thunkActions', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
grades: {
|
||||
fetchPrevNextGrades: jest.fn(),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
let props;
|
||||
let el;
|
||||
describe('PageButtons component', () => {
|
||||
beforeEach(() => {
|
||||
props = {
|
||||
match: { params: { courseId: 'hogwarts-minerva-txmog101' } },
|
||||
selectedAssignmentType: 'Transmogrification Exams',
|
||||
selectedCohort: { name: 'Slytherin' },
|
||||
selectedTrack: { name: 'Death Eater' },
|
||||
getPrevNextGrades: jest.fn(),
|
||||
nextPage: 'NEXT PAGE',
|
||||
prevPage: 'prev PAGE',
|
||||
};
|
||||
});
|
||||
|
||||
it('prev null, next not null', () => {
|
||||
assertPageButtonsSnapshot(createInput(null, 'np'));
|
||||
describe('snapshots', () => {
|
||||
beforeEach(() => {
|
||||
el = shallow(<PageButtons {...props} />);
|
||||
el.instance.fetchNextGrades = jest.fn().mockName('fetchNextGrades');
|
||||
el.instance.fetchPrevGrades = jest.fn().mockName('fetchPrevGrades');
|
||||
});
|
||||
test('buttons enabled with both endpoints provided', () => {
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
test('nextPage disabled if not provided', () => {
|
||||
el.setProps({ nextPage: undefined });
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
test('prevPage disabled if not provided', () => {
|
||||
el.setProps({ prevPage: undefined });
|
||||
expect(el.instance().render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
it('prev not null, next null', () => {
|
||||
assertPageButtonsSnapshot(createInput('pp', null));
|
||||
describe('behavior', () => {
|
||||
beforeEach(() => {
|
||||
el = shallow(<PageButtons {...props} />);
|
||||
});
|
||||
describe('getPrevGrades', () => {
|
||||
it('calls props.getPrevNextGrades with props.prevPage', () => {
|
||||
el.instance().getPrevGrades();
|
||||
expect(props.getPrevNextGrades).toHaveBeenCalledWith(
|
||||
props.prevPage,
|
||||
props.match.params.courseId,
|
||||
props.selectedCohort,
|
||||
props.selectedTrack,
|
||||
props.selectedAssignmentType,
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('getNextGrades', () => {
|
||||
it('calls props.getPrevNextGrades with props.nextPage', () => {
|
||||
el.instance().getNextGrades();
|
||||
expect(props.getPrevNextGrades).toHaveBeenCalledWith(
|
||||
props.nextPage,
|
||||
props.match.params.courseId,
|
||||
props.selectedCohort,
|
||||
props.selectedTrack,
|
||||
props.selectedAssignmentType,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('prev not null, next not null', () => {
|
||||
assertPageButtonsSnapshot(createInput('pp', 'np'));
|
||||
describe('mapStateToProps', () => {
|
||||
const testState = { l: 'eeeerroooooy', j: 'jjjjeeeeeeenkins' };
|
||||
let mapped;
|
||||
beforeEach(() => {
|
||||
mapped = mapStateToProps(testState);
|
||||
});
|
||||
test('nextPage from grades.nextPage', () => {
|
||||
expect(mapped.nextPage).toEqual(selectors.grades.nextPage(testState));
|
||||
});
|
||||
test('prevPage from grades.prevPage', () => {
|
||||
expect(mapped.prevPage).toEqual(selectors.grades.prevPage(testState));
|
||||
});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
test('getPrevNextGrades from thunkActions.grades.fetchPrevNextGrades', () => {
|
||||
expect(
|
||||
mapDispatchToProps.getPrevNextGrades,
|
||||
).toEqual(thunkActions.grades.fetchPrevNextGrades);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PageButtons prev not null, next not null 1`] = `
|
||||
exports[`PageButtons component snapshots buttons enabled with both endpoints provided 1`] = `
|
||||
<div
|
||||
className="d-flex justify-content-center"
|
||||
style={
|
||||
@@ -9,8 +9,7 @@ exports[`PageButtons prev not null, next not null 1`] = `
|
||||
}
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="btn btn-outline-primary"
|
||||
<Button
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
@@ -18,12 +17,11 @@ exports[`PageButtons prev not null, next not null 1`] = `
|
||||
"margin": "20px",
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
variant="outline-primary"
|
||||
>
|
||||
Previous Page
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-outline-primary"
|
||||
</Button>
|
||||
<Button
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
@@ -31,14 +29,14 @@ exports[`PageButtons prev not null, next not null 1`] = `
|
||||
"margin": "20px",
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
variant="outline-primary"
|
||||
>
|
||||
Next Page
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`PageButtons prev not null, next null 1`] = `
|
||||
exports[`PageButtons component snapshots nextPage disabled if not provided 1`] = `
|
||||
<div
|
||||
className="d-flex justify-content-center"
|
||||
style={
|
||||
@@ -47,8 +45,7 @@ exports[`PageButtons prev not null, next null 1`] = `
|
||||
}
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="btn btn-outline-primary"
|
||||
<Button
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
@@ -56,12 +53,11 @@ exports[`PageButtons prev not null, next null 1`] = `
|
||||
"margin": "20px",
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
variant="outline-primary"
|
||||
>
|
||||
Previous Page
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-outline-primary"
|
||||
</Button>
|
||||
<Button
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
@@ -69,14 +65,14 @@ exports[`PageButtons prev not null, next null 1`] = `
|
||||
"margin": "20px",
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
variant="outline-primary"
|
||||
>
|
||||
Next Page
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`PageButtons prev null, next not null 1`] = `
|
||||
exports[`PageButtons component snapshots prevPage disabled if not provided 1`] = `
|
||||
<div
|
||||
className="d-flex justify-content-center"
|
||||
style={
|
||||
@@ -85,8 +81,7 @@ exports[`PageButtons prev null, next not null 1`] = `
|
||||
}
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="btn btn-outline-primary"
|
||||
<Button
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
@@ -94,12 +89,11 @@ exports[`PageButtons prev null, next not null 1`] = `
|
||||
"margin": "20px",
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
variant="outline-primary"
|
||||
>
|
||||
Previous Page
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-outline-primary"
|
||||
</Button>
|
||||
<Button
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
@@ -107,47 +101,9 @@ exports[`PageButtons prev null, next not null 1`] = `
|
||||
"margin": "20px",
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
variant="outline-primary"
|
||||
>
|
||||
Next Page
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`PageButtons prev null, next null 1`] = `
|
||||
<div
|
||||
className="d-flex justify-content-center"
|
||||
style={
|
||||
Object {
|
||||
"paddingBottom": "20px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="btn btn-outline-primary"
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"margin": "20px",
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
Previous Page
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-outline-primary"
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
style={
|
||||
Object {
|
||||
"margin": "20px",
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
Next Page
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -1,75 +1,99 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { Button } from '@edx/paragon';
|
||||
|
||||
export default function PageButtons({
|
||||
prevPage, nextPage, selectedTrack, selectedCohort, selectedAssignmentType,
|
||||
getPrevNextGrades, match,
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className="d-flex justify-content-center"
|
||||
style={{ paddingBottom: '20px' }}
|
||||
>
|
||||
<Button
|
||||
style={{ margin: '20px' }}
|
||||
variant="outline-primary"
|
||||
disabled={!prevPage}
|
||||
onClick={() => getPrevNextGrades(
|
||||
prevPage,
|
||||
match.params.courseId,
|
||||
selectedCohort,
|
||||
selectedTrack,
|
||||
selectedAssignmentType,
|
||||
)}
|
||||
import selectors from 'data/selectors';
|
||||
import thunkActions from 'data/thunkActions';
|
||||
|
||||
export class PageButtons extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.getPrevGrades = this.getPrevGrades.bind(this);
|
||||
this.getNextGrades = this.getNextGrades.bind(this);
|
||||
}
|
||||
|
||||
getPrevGrades() {
|
||||
this.props.getPrevNextGrades(
|
||||
this.props.prevPage,
|
||||
this.props.match.params.courseId,
|
||||
this.props.selectedCohort,
|
||||
this.props.selectedTrack,
|
||||
this.props.selectedAssignmentType,
|
||||
);
|
||||
}
|
||||
|
||||
getNextGrades() {
|
||||
this.props.getPrevNextGrades(
|
||||
this.props.nextPage,
|
||||
this.props.match.params.courseId,
|
||||
this.props.selectedCohort,
|
||||
this.props.selectedTrack,
|
||||
this.props.selectedAssignmentType,
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
className="d-flex justify-content-center"
|
||||
style={{ paddingBottom: '20px' }}
|
||||
>
|
||||
Previous Page
|
||||
</Button>
|
||||
<Button
|
||||
style={{ margin: '20px' }}
|
||||
variant="outline-primary"
|
||||
disabled={!nextPage}
|
||||
onClick={() => getPrevNextGrades(
|
||||
nextPage,
|
||||
match.params.courseId,
|
||||
selectedCohort,
|
||||
selectedTrack,
|
||||
selectedAssignmentType,
|
||||
)}
|
||||
>
|
||||
Next Page
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
<Button
|
||||
style={{ margin: '20px' }}
|
||||
variant="outline-primary"
|
||||
disabled={!this.props.prevPage}
|
||||
onClick={this.getPrevGrades}
|
||||
>
|
||||
Previous Page
|
||||
</Button>
|
||||
<Button
|
||||
style={{ margin: '20px' }}
|
||||
variant="outline-primary"
|
||||
disabled={!this.props.nextPage}
|
||||
onClick={this.getNextGrades}
|
||||
>
|
||||
Next Page
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
PageButtons.defaultProps = {
|
||||
match: {
|
||||
params: {
|
||||
courseId: '',
|
||||
},
|
||||
params: { courseId: '' },
|
||||
},
|
||||
nextPage: '',
|
||||
prevPage: '',
|
||||
selectedAssignmentType: null,
|
||||
selectedCohort: null,
|
||||
selectedTrack: null,
|
||||
selectedAssignmentType: null,
|
||||
nextPage: '',
|
||||
prevPage: '',
|
||||
};
|
||||
|
||||
PageButtons.propTypes = {
|
||||
getPrevNextGrades: PropTypes.func.isRequired,
|
||||
match: PropTypes.shape({
|
||||
params: PropTypes.shape({
|
||||
courseId: PropTypes.string,
|
||||
}),
|
||||
}),
|
||||
selectedAssignmentType: PropTypes.string,
|
||||
selectedCohort: PropTypes.shape({ name: PropTypes.string }),
|
||||
selectedTrack: PropTypes.shape({ name: PropTypes.string }),
|
||||
// redux
|
||||
getPrevNextGrades: PropTypes.func.isRequired,
|
||||
nextPage: PropTypes.string,
|
||||
prevPage: PropTypes.string,
|
||||
selectedAssignmentType: PropTypes.string,
|
||||
selectedCohort: PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
}),
|
||||
selectedTrack: PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
}),
|
||||
};
|
||||
|
||||
export const mapStateToProps = (state) => ({
|
||||
nextPage: selectors.grades.nextPage(state),
|
||||
prevPage: selectors.grades.prevPage(state),
|
||||
});
|
||||
|
||||
export const mapDispatchToProps = {
|
||||
getPrevNextGrades: thunkActions.grades.fetchPrevNextGrades,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(PageButtons);
|
||||
|
||||
@@ -205,6 +205,8 @@ const simpleSelectors = simpleSelectorFactory(
|
||||
'filteredUsersCount',
|
||||
'totalUsersCount',
|
||||
'gradeFormat',
|
||||
'nextPage',
|
||||
'prevPage',
|
||||
'showSpinner',
|
||||
'gradeOverrideCurrentEarnedGradedOverride',
|
||||
'gradeOverrideHistoryError',
|
||||
|
||||
@@ -287,6 +287,8 @@ describe('grades selectors', () => {
|
||||
testSimpleSelector('filteredUsersCount');
|
||||
testSimpleSelector('totalUsersCount');
|
||||
testSimpleSelector('gradeFormat');
|
||||
testSimpleSelector('nextPage');
|
||||
testSimpleSelector('prevPage');
|
||||
testSimpleSelector('showSpinner');
|
||||
testSimpleSelector('gradeOverrideCurrentEarnedGradedOverride');
|
||||
testSimpleSelector('gradeOverrideHistoryError');
|
||||
|
||||
Reference in New Issue
Block a user