diff --git a/src/components/Gradebook/filters/AssignmentFilters/__snapshots__/AssignmentFilter.test.jsx.snap b/src/components/Gradebook/GradebookFilters/AssignmentFilter/__snapshots__/test.jsx.snap similarity index 100% rename from src/components/Gradebook/filters/AssignmentFilters/__snapshots__/AssignmentFilter.test.jsx.snap rename to src/components/Gradebook/GradebookFilters/AssignmentFilter/__snapshots__/test.jsx.snap diff --git a/src/components/Gradebook/filters/AssignmentFilters/AssignmentFilter.jsx b/src/components/Gradebook/GradebookFilters/AssignmentFilter/index.jsx similarity index 100% rename from src/components/Gradebook/filters/AssignmentFilters/AssignmentFilter.jsx rename to src/components/Gradebook/GradebookFilters/AssignmentFilter/index.jsx diff --git a/src/components/Gradebook/filters/AssignmentFilters/AssignmentFilter.test.jsx b/src/components/Gradebook/GradebookFilters/AssignmentFilter/test.jsx similarity index 94% rename from src/components/Gradebook/filters/AssignmentFilters/AssignmentFilter.test.jsx rename to src/components/Gradebook/GradebookFilters/AssignmentFilter/test.jsx index 162a43d..2d16e19 100644 --- a/src/components/Gradebook/filters/AssignmentFilters/AssignmentFilter.test.jsx +++ b/src/components/Gradebook/GradebookFilters/AssignmentFilter/test.jsx @@ -7,7 +7,7 @@ import { AssignmentFilter, mapStateToProps, mapDispatchToProps, -} from './AssignmentFilter'; +} from '.'; jest.mock('data/selectors/filters', () => ({ /** Mocking to use passed state for validation purposes */ @@ -43,11 +43,9 @@ describe('AssignmentFilter', () => { beforeEach(() => { props = { ...props, - updateQueryParams: jest.fn().mockName('updateQueryParams'), - updateGradesIfAssignmentGradeFiltersSet: jest.fn().mockName( - 'updateGradesIfAssignmentGradeFiltersSet', - ), - updateAssignmentFilter: jest.fn().mockName('updateAssignmentFilter'), + updateQueryParams: jest.fn(), + updateGradesIfAssignmentGradeFiltersSet: jest.fn(), + updateAssignmentFilter: jest.fn(), }; }); diff --git a/src/components/Gradebook/filters/AssignmentFilters/__snapshots__/AssignmentGradeFilter.test.jsx.snap b/src/components/Gradebook/GradebookFilters/AssignmentGradeFilter/__snapshots__/test.jsx.snap similarity index 100% rename from src/components/Gradebook/filters/AssignmentFilters/__snapshots__/AssignmentGradeFilter.test.jsx.snap rename to src/components/Gradebook/GradebookFilters/AssignmentGradeFilter/__snapshots__/test.jsx.snap diff --git a/src/components/Gradebook/filters/AssignmentFilters/AssignmentGradeFilter.jsx b/src/components/Gradebook/GradebookFilters/AssignmentGradeFilter/index.jsx similarity index 85% rename from src/components/Gradebook/filters/AssignmentFilters/AssignmentGradeFilter.jsx rename to src/components/Gradebook/GradebookFilters/AssignmentGradeFilter/index.jsx index 8d97ede..c1aa92d 100644 --- a/src/components/Gradebook/filters/AssignmentFilters/AssignmentGradeFilter.jsx +++ b/src/components/Gradebook/GradebookFilters/AssignmentGradeFilter/index.jsx @@ -22,7 +22,7 @@ export class AssignmentGradeFilter extends React.Component { const { assignmentGradeMin, assignmentGradeMax, - } = this.props; + } = this.props.filterValues; this.props.updateAssignmentLimits( assignmentGradeMin, @@ -41,11 +41,11 @@ export class AssignmentGradeFilter extends React.Component { } handleSetMax(event) { - this.props.setAssignmentGradeMax(event.target.value); + this.props.setFilters({ assignmentGradeMax: event.target.value }); } handleSetMin(event) { - this.props.setAssignmentGradeMin(event.target.value); + this.props.setFilters({ assignmentGradeMin: event.target.value }); } render() { @@ -54,14 +54,14 @@ export class AssignmentGradeFilter extends React.Component { @@ -89,11 +89,12 @@ AssignmentGradeFilter.defaultProps = { }; AssignmentGradeFilter.propTypes = { - assignmentGradeMin: PropTypes.string.isRequired, - assignmentGradeMax: PropTypes.string.isRequired, courseId: PropTypes.string.isRequired, - setAssignmentGradeMin: PropTypes.func.isRequired, - setAssignmentGradeMax: PropTypes.func.isRequired, + filterValues: PropTypes.shape({ + assignmentGradeMin: PropTypes.string.isRequired, + assignmentGradeMax: PropTypes.string.isRequired, + }).isRequired, + setFilters: PropTypes.func.isRequired, updateQueryParams: PropTypes.func.isRequired, // redux diff --git a/src/components/Gradebook/filters/AssignmentFilters/AssignmentGradeFilter.test.jsx b/src/components/Gradebook/GradebookFilters/AssignmentGradeFilter/test.jsx similarity index 78% rename from src/components/Gradebook/filters/AssignmentFilters/AssignmentGradeFilter.test.jsx rename to src/components/Gradebook/GradebookFilters/AssignmentGradeFilter/test.jsx index e8378a9..7dc21ce 100644 --- a/src/components/Gradebook/filters/AssignmentFilters/AssignmentGradeFilter.test.jsx +++ b/src/components/Gradebook/GradebookFilters/AssignmentGradeFilter/test.jsx @@ -8,12 +8,14 @@ import { AssignmentGradeFilter, mapStateToProps, mapDispatchToProps, -} from './AssignmentGradeFilter'; +} from '.'; describe('AssignmentGradeFilter', () => { let props = { - assignmentGradeMin: '1', - assignmentGradeMax: '100', + filterValues: { + assignmentGradeMin: '1', + assignmentGradeMax: '100', + }, courseId: '12345', selectedAssignmentType: 'assgnFilterLabel1', @@ -25,8 +27,7 @@ describe('AssignmentGradeFilter', () => { beforeEach(() => { props = { ...props, - setAssignmentGradeMin: jest.fn(), - setAssignmentGradeMax: jest.fn(), + setFilters: jest.fn(), updateQueryParams: jest.fn(), getUserGrades: jest.fn(), updateAssignmentLimits: jest.fn(), @@ -45,8 +46,8 @@ describe('AssignmentGradeFilter', () => { }); it('calls props.updateAssignmentLimits with min and max', () => { expect(props.updateAssignmentLimits).toHaveBeenCalledWith( - props.assignmentGradeMin, - props.assignmentGradeMax, + props.filterValues.assignmentGradeMin, + props.filterValues.assignmentGradeMax, ); }); it('calls getUserGrades w/ selection', () => { @@ -59,8 +60,28 @@ describe('AssignmentGradeFilter', () => { }); it('updates queryParams with assignment grade min and max', () => { expect(props.updateQueryParams).toHaveBeenCalledWith({ - assignmentGradeMin: props.assignmentGradeMin, - assignmentGradeMax: props.assignmentGradeMax, + assignmentGradeMin: props.filterValues.assignmentGradeMin, + assignmentGradeMax: props.filterValues.assignmentGradeMax, + }); + }); + }); + describe('handleSetMin', () => { + it('calls setFilters for assignmentGradeMin', () => { + const testVal = 23; + const el = mount(); + el.instance().handleSetMin({ target: { value: testVal } }); + expect(props.setFilters).toHaveBeenCalledWith({ + assignmentGradeMin: testVal, + }); + }); + }); + describe('handleSetMax', () => { + it('calls setFilters for assignmentGradeMax', () => { + const testVal = 92; + const el = mount(); + el.instance().handleSetMax({ target: { value: testVal } }); + expect(props.setFilters).toHaveBeenCalledWith({ + assignmentGradeMax: testVal, }); }); }); diff --git a/src/components/Gradebook/filters/AssignmentFilters/__snapshots__/AssignmentTypeFilter.test.jsx.snap b/src/components/Gradebook/GradebookFilters/AssignmentTypeFilter/__snapshots__/test.jsx.snap similarity index 100% rename from src/components/Gradebook/filters/AssignmentFilters/__snapshots__/AssignmentTypeFilter.test.jsx.snap rename to src/components/Gradebook/GradebookFilters/AssignmentTypeFilter/__snapshots__/test.jsx.snap diff --git a/src/components/Gradebook/filters/AssignmentFilters/AssignmentTypeFilter.jsx b/src/components/Gradebook/GradebookFilters/AssignmentTypeFilter/index.jsx similarity index 100% rename from src/components/Gradebook/filters/AssignmentFilters/AssignmentTypeFilter.jsx rename to src/components/Gradebook/GradebookFilters/AssignmentTypeFilter/index.jsx diff --git a/src/components/Gradebook/filters/AssignmentFilters/AssignmentTypeFilter.test.jsx b/src/components/Gradebook/GradebookFilters/AssignmentTypeFilter/test.jsx similarity index 99% rename from src/components/Gradebook/filters/AssignmentFilters/AssignmentTypeFilter.test.jsx rename to src/components/Gradebook/GradebookFilters/AssignmentTypeFilter/test.jsx index 6f92f67..d250465 100644 --- a/src/components/Gradebook/filters/AssignmentFilters/AssignmentTypeFilter.test.jsx +++ b/src/components/Gradebook/GradebookFilters/AssignmentTypeFilter/test.jsx @@ -7,7 +7,7 @@ import { AssignmentTypeFilter, mapStateToProps, mapDispatchToProps, -} from './AssignmentTypeFilter'; +} from '.'; jest.mock('data/selectors/filters', () => ({ /** Mocking to use passed state for validation purposes */ diff --git a/src/components/Gradebook/filters/CourseGradeFilters/__snapshots__/test.jsx.snap b/src/components/Gradebook/GradebookFilters/CourseGradeFilter/__snapshots__/test.jsx.snap similarity index 77% rename from src/components/Gradebook/filters/CourseGradeFilters/__snapshots__/test.jsx.snap rename to src/components/Gradebook/GradebookFilters/CourseGradeFilter/__snapshots__/test.jsx.snap index 7df9b32..9fcc591 100644 --- a/src/components/Gradebook/filters/CourseGradeFilters/__snapshots__/test.jsx.snap +++ b/src/components/Gradebook/GradebookFilters/CourseGradeFilter/__snapshots__/test.jsx.snap @@ -1,11 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`CourseGradeFilters Component snapshots basic snapshot 1`] = ` - +exports[`CourseGradeFilter Component snapshots basic snapshot 1`] = ` + @@ -34,5 +30,5 @@ exports[`CourseGradeFilters Component snapshots basic snapshot 1`] = ` Apply - + `; diff --git a/src/components/Gradebook/filters/CourseGradeFilters/index.jsx b/src/components/Gradebook/GradebookFilters/CourseGradeFilter/index.jsx similarity index 70% rename from src/components/Gradebook/filters/CourseGradeFilters/index.jsx rename to src/components/Gradebook/GradebookFilters/CourseGradeFilter/index.jsx index 851fb3b..db566d7 100644 --- a/src/components/Gradebook/filters/CourseGradeFilters/index.jsx +++ b/src/components/Gradebook/GradebookFilters/CourseGradeFilter/index.jsx @@ -4,14 +4,13 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import { Button, - Collapsible, } from '@edx/paragon'; import { updateCourseGradeFilter } from 'data/actions/filters'; import { fetchGrades } from 'data/actions/grades'; import PercentGroup from '../PercentGroup'; -export class CourseGradeFilters extends React.Component { +export class CourseGradeFilter extends React.Component { constructor(props) { super(props); this.handleApplyClick = this.handleApplyClick.bind(this); @@ -21,11 +20,14 @@ export class CourseGradeFilters extends React.Component { } handleApplyClick() { - const isMinValid = this.isGradeFilterValueInRange(this.props.courseGradeMin); - const isMaxValid = this.isGradeFilterValueInRange(this.props.courseGradeMax); + const { courseGradeMin, courseGradeMax } = this.props.filterValues; + const isMinValid = this.isGradeFilterValueInRange(courseGradeMin); + const isMaxValid = this.isGradeFilterValueInRange(courseGradeMax); - this.props.setIsMinCourseGradeFilterValid(isMinValid); - this.props.setIsMaxCourseGradeFilterValid(isMaxValid); + this.props.setFilters({ + isMinCourseGradeFilterValid: isMinValid, + isMaxCourseGradeFilterValid: isMaxValid, + }); if (isMinValid && isMaxValid) { this.updateAPI(); @@ -33,7 +35,7 @@ export class CourseGradeFilters extends React.Component { } updateAPI() { - const { courseGradeMin, courseGradeMax } = this.props; + const { courseGradeMin, courseGradeMax } = this.props.filterValues; this.props.updateFilter( courseGradeMin, courseGradeMax, @@ -50,11 +52,11 @@ export class CourseGradeFilters extends React.Component { } handleUpdateMin(event) { - this.props.setCourseGradeMin(event.target.value); + this.props.setFilters({ courseGradeMin: event.target.value }); } handleUpdateMax(event) { - this.props.setCourseGradeMax(event.target.value); + this.props.setFilters({ courseGradeMax: event.target.value }); } isGradeFilterValueInRange = (value) => { @@ -64,18 +66,18 @@ export class CourseGradeFilters extends React.Component { render() { return ( - + <> @@ -87,27 +89,27 @@ export class CourseGradeFilters extends React.Component { Apply - + > ); } } -CourseGradeFilters.defaultProps = { +CourseGradeFilter.defaultProps = { courseId: '', selectedAssignmentType: '', selectedCohort: null, selectedTrack: null, }; -CourseGradeFilters.propTypes = { - courseGradeMin: PropTypes.string.isRequired, - courseGradeMax: PropTypes.string.isRequired, +CourseGradeFilter.propTypes = { courseId: PropTypes.string, - setCourseGradeMin: PropTypes.func.isRequired, - setCourseGradeMax: PropTypes.func.isRequired, - setIsMaxCourseGradeFilterValid: PropTypes.func.isRequired, - setIsMinCourseGradeFilterValid: PropTypes.func.isRequired, + filterValues: PropTypes.shape({ + courseGradeMin: PropTypes.string.isRequired, + courseGradeMax: PropTypes.string.isRequired, + }).isRequired, + setFilters: PropTypes.func.isRequired, updateQueryParams: PropTypes.func.isRequired, + // Redux getUserGrades: PropTypes.func.isRequired, selectedAssignmentType: PropTypes.string, @@ -127,4 +129,4 @@ export const mapDispatchToProps = { getUserGrades: fetchGrades, }; -export default connect(mapStateToProps, mapDispatchToProps)(CourseGradeFilters); +export default connect(mapStateToProps, mapDispatchToProps)(CourseGradeFilter); diff --git a/src/components/Gradebook/filters/CourseGradeFilters/test.jsx b/src/components/Gradebook/GradebookFilters/CourseGradeFilter/test.jsx similarity index 69% rename from src/components/Gradebook/filters/CourseGradeFilters/test.jsx rename to src/components/Gradebook/GradebookFilters/CourseGradeFilter/test.jsx index b72ab57..84229bc 100644 --- a/src/components/Gradebook/filters/CourseGradeFilters/test.jsx +++ b/src/components/Gradebook/GradebookFilters/CourseGradeFilter/test.jsx @@ -6,7 +6,7 @@ import { shallow } from 'enzyme'; import { updateCourseGradeFilter } from 'data/actions/filters'; import { fetchGrades } from 'data/actions/grades'; import { - CourseGradeFilters, + CourseGradeFilter, mapStateToProps, mapDispatchToProps, } from '.'; @@ -16,10 +16,12 @@ jest.mock('@edx/paragon', () => ({ Collapsible: 'Collapsible', })); -describe('CourseGradeFilters', () => { +describe('CourseGradeFilter', () => { let props = { - courseGradeMin: '5', - courseGradeMax: '92', + filterValues: { + courseGradeMin: '5', + courseGradeMax: '92', + }, courseId: '12345', selectedAssignmentType: 'assignMent type 1', selectedCohort: 'COHort', @@ -30,10 +32,7 @@ describe('CourseGradeFilters', () => { props = { ...props, getUserGrades: jest.fn(), - setCourseGradeMin: jest.fn(), - setCourseGradeMax: jest.fn(), - setIsMinCourseGradeFilterValid: jest.fn(), - setIsMaxCourseGradeFilterValid: jest.fn(), + setFilters: jest.fn(), updateQueryParams: jest.fn(), updateFilter: jest.fn(), }; @@ -42,7 +41,7 @@ describe('CourseGradeFilters', () => { describe('Component', () => { describe('snapshots', () => { test('basic snapshot', () => { - const el = shallow(); + const el = shallow(); el.instance().handleUpdateMin = jest.fn().mockName( 'handleUpdateMin', ); @@ -60,9 +59,32 @@ describe('CourseGradeFilters', () => { let el; const testVal = 'TESTvalue'; beforeEach(() => { - el = shallow(); + el = shallow(); }); describe('handleApplyClick', () => { + beforeEach(() => { + el.instance().updateAPI = jest.fn(); + }); + it('calls setFilters for isMin(Max)CourseGradeFilterValid', () => { + el.instance().isGradeFilterValueInRange = jest.fn().mockImplementation(v => v >= 50); + el.instance().handleApplyClick(); + expect(props.setFilters).toHaveBeenCalledWith({ + isMinCourseGradeFilterValid: false, + isMaxCourseGradeFilterValid: true, + }); + }); + it('calls updateAPI only if both min and max are valid', () => { + const isValid = jest.fn().mockImplementation(v => v >= 50); + el.instance().isGradeFilterValueInRange = isValid; + el.instance().handleApplyClick(); + expect(el.instance().updateAPI).not.toHaveBeenCalled(); + isValid.mockImplementation(v => v <= 50); + el.instance().handleApplyClick(); + expect(el.instance().updateAPI).not.toHaveBeenCalled(); + isValid.mockImplementation(v => v >= 0); + el.instance().handleApplyClick(); + expect(el.instance().updateAPI).toHaveBeenCalled(); + }); }); describe('updateAPI', () => { beforeEach(() => { @@ -70,8 +92,8 @@ describe('CourseGradeFilters', () => { }); it('calls props.updateFilter with selection', () => { expect(props.updateFilter).toHaveBeenCalledWith( - props.courseGradeMin, - props.courseGradeMax, + props.filterValues.courseGradeMin, + props.filterValues.courseGradeMax, props.courseId, ); }); @@ -82,15 +104,15 @@ describe('CourseGradeFilters', () => { props.selectedTrack, props.selectedAssignmentType, { - courseGradeMin: props.courseGradeMin, - courseGradeMax: props.courseGradeMax, + courseGradeMin: props.filterValues.courseGradeMin, + courseGradeMax: props.filterValues.courseGradeMax, }, ); }); it('updates query params with courseGradeMin and courseGradeMax', () => { expect(props.updateQueryParams).toHaveBeenCalledWith({ - courseGradeMin: props.courseGradeMin, - courseGradeMax: props.courseGradeMax, + courseGradeMin: props.filterValues.courseGradeMin, + courseGradeMax: props.filterValues.courseGradeMax, }); }); }); @@ -99,7 +121,9 @@ describe('CourseGradeFilters', () => { el.instance().handleUpdateMin( { target: { value: testVal } }, ); - expect(props.setCourseGradeMin).toHaveBeenCalledWith(testVal); + expect(props.setFilters).toHaveBeenCalledWith({ + courseGradeMin: testVal, + }); }); }); describe('handleUpdateMax', () => { @@ -107,7 +131,9 @@ describe('CourseGradeFilters', () => { el.instance().handleUpdateMax( { target: { value: testVal } }, ); - expect(props.setCourseGradeMax).toHaveBeenCalledWith(testVal); + expect(props.setFilters).toHaveBeenCalledWith({ + courseGradeMax: testVal, + }); }); }); describe('isFilterValueInRange', () => { diff --git a/src/components/Gradebook/filters/PercentGroup.jsx b/src/components/Gradebook/GradebookFilters/PercentGroup.jsx similarity index 100% rename from src/components/Gradebook/filters/PercentGroup.jsx rename to src/components/Gradebook/GradebookFilters/PercentGroup.jsx diff --git a/src/components/Gradebook/filters/PercentGroup.test.jsx b/src/components/Gradebook/GradebookFilters/PercentGroup.test.jsx similarity index 100% rename from src/components/Gradebook/filters/PercentGroup.test.jsx rename to src/components/Gradebook/GradebookFilters/PercentGroup.test.jsx diff --git a/src/components/Gradebook/filters/SelectGroup.jsx b/src/components/Gradebook/GradebookFilters/SelectGroup.jsx similarity index 100% rename from src/components/Gradebook/filters/SelectGroup.jsx rename to src/components/Gradebook/GradebookFilters/SelectGroup.jsx diff --git a/src/components/Gradebook/filters/SelectGroup.test.jsx b/src/components/Gradebook/GradebookFilters/SelectGroup.test.jsx similarity index 100% rename from src/components/Gradebook/filters/SelectGroup.test.jsx rename to src/components/Gradebook/GradebookFilters/SelectGroup.test.jsx diff --git a/src/components/Gradebook/filters/StudentGroupsFilters/__snapshots__/test.jsx.snap b/src/components/Gradebook/GradebookFilters/StudentGroupsFilter/__snapshots__/test.jsx.snap similarity index 79% rename from src/components/Gradebook/filters/StudentGroupsFilters/__snapshots__/test.jsx.snap rename to src/components/Gradebook/GradebookFilters/StudentGroupsFilter/__snapshots__/test.jsx.snap index 8e49656..6ca66a8 100644 --- a/src/components/Gradebook/filters/StudentGroupsFilters/__snapshots__/test.jsx.snap +++ b/src/components/Gradebook/GradebookFilters/StudentGroupsFilter/__snapshots__/test.jsx.snap @@ -1,11 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`StudentGroupsFilters Component snapshots basic snapshot 1`] = ` - +exports[`StudentGroupsFilter Component snapshots basic snapshot 1`] = ` + - + `; -exports[`StudentGroupsFilters Component snapshots mapCohortsEntries cohort options: [Cohort-All, <{slug, name}...>] 1`] = ` +exports[`StudentGroupsFilter Component snapshots mapCohortsEntries cohort options: [Cohort-All, <{slug, name}...>] 1`] = ` Array [ ] 1`] = ` +exports[`StudentGroupsFilter Component snapshots mapTracksEntries cohort options: [Track-All, <{id, name}...>] 1`] = ` Array [ + <> - + > ); } } -StudentGroupsFilters.defaultProps = { +StudentGroupsFilter.defaultProps = { /** testing cohorts: [ { name: 'Fake Cohort 1', id: 'fake_cohort_1' }, @@ -134,7 +126,7 @@ StudentGroupsFilters.defaultProps = { tracks: [], }; -StudentGroupsFilters.propTypes = { +StudentGroupsFilter.propTypes = { courseId: PropTypes.string, updateQueryParams: PropTypes.func.isRequired, @@ -165,4 +157,4 @@ export const mapDispatchToProps = { getUserGrades: fetchGrades, }; -export default connect(mapStateToProps, mapDispatchToProps)(StudentGroupsFilters); +export default connect(mapStateToProps, mapDispatchToProps)(StudentGroupsFilter); diff --git a/src/components/Gradebook/filters/StudentGroupsFilters/test.jsx b/src/components/Gradebook/GradebookFilters/StudentGroupsFilter/test.jsx similarity index 95% rename from src/components/Gradebook/filters/StudentGroupsFilters/test.jsx rename to src/components/Gradebook/GradebookFilters/StudentGroupsFilter/test.jsx index 3f69559..594717e 100644 --- a/src/components/Gradebook/filters/StudentGroupsFilters/test.jsx +++ b/src/components/Gradebook/GradebookFilters/StudentGroupsFilter/test.jsx @@ -5,7 +5,7 @@ import { shallow } from 'enzyme'; import { fetchGrades } from 'data/actions/grades'; import { - StudentGroupsFilters, + StudentGroupsFilter, mapStateToProps, mapDispatchToProps, } from '.'; @@ -14,7 +14,7 @@ jest.mock('@edx/paragon', () => ({ Collapsible: 'Collapsible', })); -describe('StudentGroupsFilters', () => { +describe('StudentGroupsFilter', () => { let props = { courseId: '12345', cohorts: [ @@ -44,7 +44,7 @@ describe('StudentGroupsFilters', () => { describe('snapshots', () => { let el; beforeEach(() => { - el = shallow(); + el = shallow(); }); test('basic snapshot', () => { el.instance().updateTracks = jest.fn().mockName( @@ -70,7 +70,7 @@ describe('StudentGroupsFilters', () => { describe('behavior', () => { let el; beforeEach(() => { - el = shallow(); + el = shallow(); }); describe('mapSelectedCohortEntry', () => { it('returns the name of the cohort with the same numerical id', () => { @@ -135,7 +135,7 @@ describe('StudentGroupsFilters', () => { describe('updateTracks', () => { const selectedSlug = 'SLUG'; beforeEach(() => { - el = shallow(); + el = shallow(); jest.spyOn( el.instance(), 'selectedTrackSlugFromEvent', @@ -159,7 +159,7 @@ describe('StudentGroupsFilters', () => { describe('updateCohorts', () => { const selectedId = 23; beforeEach(() => { - el = shallow(); + el = shallow(); jest.spyOn( el.instance(), 'selectedCohortIdFromEvent', diff --git a/src/components/Gradebook/filters/__snapshots__/PercentGroup.test.jsx.snap b/src/components/Gradebook/GradebookFilters/__snapshots__/PercentGroup.test.jsx.snap similarity index 100% rename from src/components/Gradebook/filters/__snapshots__/PercentGroup.test.jsx.snap rename to src/components/Gradebook/GradebookFilters/__snapshots__/PercentGroup.test.jsx.snap diff --git a/src/components/Gradebook/filters/__snapshots__/SelectGroup.test.jsx.snap b/src/components/Gradebook/GradebookFilters/__snapshots__/SelectGroup.test.jsx.snap similarity index 100% rename from src/components/Gradebook/filters/__snapshots__/SelectGroup.test.jsx.snap rename to src/components/Gradebook/GradebookFilters/__snapshots__/SelectGroup.test.jsx.snap diff --git a/src/components/Gradebook/GradebookFilters/__snapshots__/test.jsx.snap b/src/components/Gradebook/GradebookFilters/__snapshots__/test.jsx.snap new file mode 100644 index 0000000..31194a0 --- /dev/null +++ b/src/components/Gradebook/GradebookFilters/__snapshots__/test.jsx.snap @@ -0,0 +1,135 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`GradebookFilters Component snapshots basic snapshot 1`] = ` + + + } + iconWhenOpen={ + + } + styling="card" + title="Assignments" + > + + + + + + + + } + iconWhenOpen={ + + } + styling="card" + title="Overall Grade" + > + + + + } + iconWhenOpen={ + + } + styling="card" + title="Student Groups" + > + + + + } + iconWhenOpen={ + + } + styling="card" + title="Include Course Team Members" + > + + Include Course Team Members + + + +`; diff --git a/src/components/Gradebook/GradebookFilters/index.jsx b/src/components/Gradebook/GradebookFilters/index.jsx new file mode 100644 index 0000000..722ef10 --- /dev/null +++ b/src/components/Gradebook/GradebookFilters/index.jsx @@ -0,0 +1,115 @@ +/* eslint-disable react/sort-comp, import/no-named-as-default */ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; + +import { Collapsible, Form } from '@edx/paragon'; + +import * as filterActions from 'data/actions/filters'; + +import AssignmentTypeFilter from './AssignmentTypeFilter'; +import AssignmentFilter from './AssignmentFilter'; +import AssignmentGradeFilter from './AssignmentGradeFilter'; +import CourseGradeFilter from './CourseGradeFilter'; +import StudentGroupsFilter from './StudentGroupsFilter'; + +export class GradebookFilters extends React.Component { + constructor(props) { + super(props); + this.state = { + includeCourseRoleMembers: this.props.includeCourseRoleMembers, + }; + this.handleIncludeTeamMembersChange = this.handleIncludeTeamMembersChange.bind(this); + } + + handleIncludeTeamMembersChange(includeCourseRoleMembers) { + this.setState({ includeCourseRoleMembers }); + this.props.updateIncludeCourseRoleMembers(includeCourseRoleMembers); + this.props.updateQueryParams({ includeCourseRoleMembers }); + } + + collapsibleGroup = (title, content) => ( + + {content} + + ); + + render() { + const { + courseId, + filterValues, + setFilters, + updateQueryParams, + } = this.props; + return ( + <> + {this.collapsibleGroup('Assignments', ( + + + + + + ))} + {this.collapsibleGroup('Overall Grade', ( + + ))} + {this.collapsibleGroup('Student Groups', ( + + ))} + {this.collapsibleGroup('Include Course Team Members', ( + + Include Course Team Members + + ))} + > + ); + } +} +GradebookFilters.propTypes = { + courseId: PropTypes.string.isRequired, + filterValues: PropTypes.shape({ + assignmentGradeMin: PropTypes.string, + assignmentGradeMax: PropTypes.string, + courseGradeMin: PropTypes.string, + courseGradeMax: PropTypes.string, + }).isRequired, + setFilters: PropTypes.func.isRequired, + includeCourseRoleMembers: PropTypes.bool.isRequired, + updateIncludeCourseRoleMembers: PropTypes.func.isRequired, + updateQueryParams: PropTypes.func.isRequired, +}; + +export const mapStateToProps = (state) => ({ + includeCourseRoleMembers: state.filters.includeCourseRoleMembers, +}); + +export const mapDispatchToProps = { + updateIncludeCourseRoleMembers: filterActions.updateIncludeCourseRoleMembers, +}; + +export default connect(mapStateToProps, mapDispatchToProps)(GradebookFilters); diff --git a/src/components/Gradebook/GradebookFilters/test.jsx b/src/components/Gradebook/GradebookFilters/test.jsx new file mode 100644 index 0000000..99eb0c0 --- /dev/null +++ b/src/components/Gradebook/GradebookFilters/test.jsx @@ -0,0 +1,85 @@ +import React from 'react'; +import { shallow } from 'enzyme'; + +import { updateIncludeCourseRoleMembers } from 'data/actions/filters'; + +import { + GradebookFilters, + mapStateToProps, + mapDispatchToProps, +} from '.'; + +describe('GradebookFilters', () => { + let props = { + courseId: '12345', + filterValues: { + assignmentGradeMin: '10', + assignmentGradeMax: '90', + courseGradeMin: '20', + courseGradeMax: '80', + }, + includeCourseRoleMembers: true, + }; + + beforeEach(() => { + props = { + ...props, + updateQueryParams: jest.fn(), + updateIncludeCourseRoleMembers: jest.fn(), + setFilters: jest.fn(), + }; + }); + + describe('Component', () => { + describe('behavior', () => { + describe('handleIncludeTeamMembersChange', () => { + let el; + beforeEach(() => { + el = shallow(); + }); + it('calls props.updateIncludeCourseRoleMembers with newVal', () => { + el.instance().handleIncludeTeamMembersChange(false); + expect( + props.updateIncludeCourseRoleMembers, + ).toHaveBeenCalledWith(false); + }); + it('calls props.updateIncludeCourseRoleMembers with newVal', () => { + el.instance().handleIncludeTeamMembersChange(true); + expect( + props.updateQueryParams, + ).toHaveBeenCalledWith({ includeCourseRoleMembers: true }); + }); + }); + }); + describe('snapshots', () => { + test('basic snapshot', () => { + const el = shallow(); + el.instance().handleIncludeTeamMembersChange = jest.fn().mockName( + 'handleIncludeTeamMembersChange', + ); + expect(el.instance().render()).toMatchSnapshot(); + }); + }); + }); + describe('mapStateToProps', () => { + const state = { + filters: { + includeCourseRoleMembers: 'plz do', + }, + }; + describe('includeCourseRoleMembers', () => { + it('is drawn from filters.includeCourseRoleMembers', () => { + expect(mapStateToProps(state).includeCourseRoleMembers).toEqual( + state.filters.includeCourseRoleMembers, + ); + }); + }); + }); + describe('mapDispatchToProps', () => { + test('updateIncludeCourseRoleMembers', () => { + expect(mapDispatchToProps.updateIncludeCourseRoleMembers).toEqual( + updateIncludeCourseRoleMembers, + ); + }); + }); +}); diff --git a/src/components/Gradebook/filters/AssignmentFilters/__snapshots__/test.jsx.snap b/src/components/Gradebook/filters/AssignmentFilters/__snapshots__/test.jsx.snap deleted file mode 100644 index 7564596..0000000 --- a/src/components/Gradebook/filters/AssignmentFilters/__snapshots__/test.jsx.snap +++ /dev/null @@ -1,27 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Assignments Component snapshots basic snapshot 1`] = ` - - - - - - - -`; diff --git a/src/components/Gradebook/filters/AssignmentFilters/index.jsx b/src/components/Gradebook/filters/AssignmentFilters/index.jsx deleted file mode 100644 index e179a74..0000000 --- a/src/components/Gradebook/filters/AssignmentFilters/index.jsx +++ /dev/null @@ -1,49 +0,0 @@ -/* eslint-disable react/sort-comp, import/no-named-as-default */ -import React from 'react'; -import PropTypes from 'prop-types'; - -import { Collapsible } from '@edx/paragon'; - -import AssignmentTypeFilter from './AssignmentTypeFilter'; -import AssignmentFilter from './AssignmentFilter'; -import AssignmentGradeFilter from './AssignmentGradeFilter'; - -export const AssignmentFilters = ({ - courseId, - assignmentGradeMax, - assignmentGradeMin, - setAssignmentGradeMax, - setAssignmentGradeMin, - updateQueryParams, -}) => ( - - - - - - - -); - -AssignmentFilters.propTypes = { - assignmentGradeMin: PropTypes.string.isRequired, - assignmentGradeMax: PropTypes.string.isRequired, - courseId: PropTypes.string.isRequired, - setAssignmentGradeMin: PropTypes.func.isRequired, - setAssignmentGradeMax: PropTypes.func.isRequired, - updateQueryParams: PropTypes.func.isRequired, -}; - -export default AssignmentFilters; diff --git a/src/components/Gradebook/filters/AssignmentFilters/test.jsx b/src/components/Gradebook/filters/AssignmentFilters/test.jsx deleted file mode 100644 index b5bf7e6..0000000 --- a/src/components/Gradebook/filters/AssignmentFilters/test.jsx +++ /dev/null @@ -1,36 +0,0 @@ -/* eslint-disable import/no-named-as-default */ - -import React from 'react'; -import { shallow } from 'enzyme'; - -import AssignmentFilters from '.'; - -jest.mock('@edx/paragon', () => ({ - Collapsible: 'Collapsible', -})); - -describe('Assignments', () => { - const props = { - assignmentGradeMin: '5', - assignmentGradeMax: '92', - courseId: '12345', - setAssignmentGradeMin: jest.fn().mockName('setAssignmentGradeMin'), - setAssignmentGradeMax: jest.fn().mockName('setAssignmentGradeMax'), - updateQueryParams: jest.fn().mockName('updateQueryParams'), - }; - - describe('Component', () => { - describe('snapshots', () => { - test('basic snapshot', () => { - const el = shallow(); - expect(el).toMatchSnapshot(); - }); - }); - }); - describe('mapStateToProps', () => { - - }); - describe('mapDispatchToProps', () => { - - }); -}); diff --git a/src/components/Gradebook/index.jsx b/src/components/Gradebook/index.jsx index 0930fd7..289045e 100644 --- a/src/components/Gradebook/index.jsx +++ b/src/components/Gradebook/index.jsx @@ -3,8 +3,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Button, - Collapsible, - CheckBox, Icon, InputSelect, SearchField, @@ -26,9 +24,7 @@ import BulkManagementControls from './BulkManagementControls'; import EditModal from './EditModal'; import GradebookTable from './GradebookTable'; import SearchControls from './SearchControls'; -import AssignmentFilters from './filters/AssignmentFilters'; -import CourseGradeFilters from './filters/CourseGradeFilters'; -import StudentGroupsFilters from './filters/StudentGroupsFilters'; +import GradebookFilters from './GradebookFilters'; export default class Gradebook extends React.Component { constructor(props) { @@ -241,11 +237,6 @@ export default class Gradebook extends React.Component { ); } - handleIncludeTeamMembersChange = (includeCourseRoleMembers) => { - this.props.updateIncludeCourseRoleMembers(includeCourseRoleMembers); - this.updateQueryParams({ includeCourseRoleMembers }); - }; - createStateFieldSetter = (key) => (value) => this.setState({ [key]: value }); createStateFieldOnChange = (key) => ({ target }) => this.setState({ [key]: target.value }); @@ -270,6 +261,22 @@ export default class Gradebook extends React.Component { 'updateUserName', ); + setFilters = this.createLimitedSetter( + 'assignmentGradeMin', + 'assignmentGradeMax', + 'courseGradeMin', + 'courseGradeMax', + 'isMinCourseGradeFilterValid', + 'isMaxCourseGradeFilterValid', + ); + + filterValues = () => ({ + assignmentGradeMin: this.state.assignmentGradeMin, + assignmentGradeMax: this.state.assignmentGradeMax, + courseGradeMin: this.state.courseGradeMin, + courseGradeMax: this.state.courseGradeMax, + }); + render() { return ( )} > - - - - - - ); } @@ -452,7 +432,6 @@ Gradebook.defaultProps = { showBulkManagement: false, showSpinner: false, totalUsersCount: null, - includeCourseRoleMembers: false, tracks: [ { name: 'Fake Track 1', id: 'fake_track_1' }, { name: 'Fake Track 2', id: 'fake_track_2' }, @@ -493,6 +472,4 @@ Gradebook.propTypes = { name: PropTypes.string, })), updateCourseGradeFilter: PropTypes.func.isRequired, - includeCourseRoleMembers: PropTypes.bool, - updateIncludeCourseRoleMembers: PropTypes.func.isRequired, }; diff --git a/src/containers/GradebookPage/index.jsx b/src/containers/GradebookPage/index.jsx index 5a78db9..164cbd3 100644 --- a/src/containers/GradebookPage/index.jsx +++ b/src/containers/GradebookPage/index.jsx @@ -20,7 +20,6 @@ import { updateAssignmentFilter, updateAssignmentLimits, updateCourseGradeFilter, - updateIncludeCourseRoleMembers, } from '../../data/actions/filters'; import stateHasMastersTrack from '../../data/selectors/tracks'; import { @@ -113,7 +112,6 @@ const mapStateToProps = (state, ownProps) => ( tracks: state.tracks.results, uploadSuccess: !!(state.grades.bulkManagement && state.grades.bulkManagement.uploadSuccess), - includeCourseRoleMembers: state.filters.includeCourseRoleMembers, } ); @@ -136,7 +134,6 @@ const mapDispatchToProps = { updateAssignmentFilter, updateAssignmentLimits, updateCourseGradeFilter, - updateIncludeCourseRoleMembers, }; const GradebookPage = connect(