view options menu now allows rearranging assignment columns

columns can be rearranged by name, due date or points

closes CNVS-36381

test plan:
* Create a course with at least two assignments and two students
  with the following criteria:
  - Assignments should have different names
  - Assignments should have different points possible
  - Assignments should have different due dates
* Open Gradezilla

* From the View menu, choose the first option in the "Arrange By"
  options group: (Assignment Name - A-Z).  This option should now
  get a checkmark against it.
* Reorder the columns by dragging them around
* Open the View menu again and notice the checkmark is gone from
  the "Assignment Name - A-Z" option.
* Reload Gradezilla and notice none of the "Arrange By" options
  are checked because the Gradebook is using a custom column
  order and not any of the pre-defined ones listed there.

* From the View menu, choose the first option in the "Arrange By"
  options group: (Assignment Name - A-Z)
* Verify that the assignment columns are sorted in alphabetical
  order.
* Open the View menu and verify there is a check mark next to the
  "Assignment Name - A-Z" option
* Reload the page and verify the columns' sort order persists

* Repeat the above with all the options in the "Arrange By"
  options group and verify the ordering of the assignment columns
  matches expectations.

Change-Id: I04d8e7b11e6381939eb2dd9472707dc3f0c9b1be
Reviewed-on: https://gerrit.instructure.com/108954
Tested-by: Jenkins
Reviewed-by: Keith T. Garner <kgarner@instructure.com>
QA-Review: Anju Reddy <areddy@instructure.com>
Product-Review: Christi Wruck
This commit is contained in:
Shahbaz Javeed 2017-04-18 14:04:41 -04:00
parent 3147ff25a8
commit 599df647fe
12 changed files with 1001 additions and 94 deletions

View File

@ -485,10 +485,9 @@ define [
makeColumnSortFn: (sortOrder) =>
fn = switch sortOrder.sortType
when 'assignment_group', 'alpha' then @compareAssignmentPositions
when 'due_date' then @compareAssignmentDueDates
when 'custom' then @makeCompareAssignmentCustomOrderFn(sortOrder)
else throw "unhandled column sort condition"
else @compareAssignmentPositions
@wrapColumnSortFn(fn)
compareAssignmentPositions: (a, b) ->

View File

@ -253,6 +253,7 @@ define [
dataLoader.gotAssignmentGroups.then () =>
@contentLoadStates.assignmentsLoaded = true
@renderViewOptionsMenu()
@updateColumnHeaders()
dataLoader.gotSubmissions.then () =>
@ -458,9 +459,13 @@ define [
columnOrderHasNotBeenSaved: =>
!@gradebookColumnOrderSettings
isDefaultSortOrder: (sortOrder) =>
not (['due_date', 'name', 'points', 'custom'].includes(sortOrder))
getStoredSortOrder: =>
if @isInvalidCustomSort() || @columnOrderHasNotBeenSaved()
{sortType: @defaultSortType}
sortType: @defaultSortType
direction: 'ascending'
else
@gradebookColumnOrderSettings
@ -486,6 +491,7 @@ define [
else
@storeCustomColumnOrder()
@renderViewOptionsMenu()
@updateColumnHeaders()
reorderCustomColumns: (ids) ->
@ -500,12 +506,7 @@ define [
newSortOrder.customOrder = _.pluck(scrollable_columns, 'id')
@setStoredSortOrder(newSortOrder)
setArrangementTogglersVisibility: (newSortOrder) =>
@$columnArrangementTogglers.each ->
$(this).closest('li').showIf $(this).data('arrangeColumnsBy') isnt newSortOrder.sortType
arrangeColumnsBy: (newSortOrder, isFirstArrangement) =>
@setArrangementTogglersVisibility(newSortOrder)
@setStoredSortOrder(newSortOrder) unless isFirstArrangement
columns = @grid.getColumns()
@ -514,14 +515,16 @@ define [
columns.splice(0, 0, frozen...)
@grid.setColumns(columns)
@renderViewOptionsMenu()
@updateColumnHeaders()
makeColumnSortFn: (sortOrder) =>
switch sortOrder.sortType
when 'assignment_group', 'alpha' then @wrapColumnSortFn(@compareAssignmentPositions)
when 'due_date' then @wrapColumnSortFn(@compareAssignmentDueDates)
when 'due_date' then @wrapColumnSortFn(@compareAssignmentDueDates, sortOrder.direction)
when 'name' then @wrapColumnSortFn(@compareAssignmentNames, sortOrder.direction)
when 'points' then @wrapColumnSortFn(@compareAssignmentPointsPossible, sortOrder.direction)
when 'custom' then @makeCompareAssignmentCustomOrderFn(sortOrder)
else throw "unhandled column sort condition"
else @wrapColumnSortFn(@compareAssignmentPositions, sortOrder.direction)
compareAssignmentPositions: (a, b) ->
diffOfAssignmentGroupPosition = a.object.assignment_group.position - b.object.assignment_group.position
@ -536,6 +539,12 @@ define [
secondAssignment = b.object
assignmentHelper.compareByDueDate(firstAssignment, secondAssignment)
compareAssignmentNames: (a, b) =>
@localeSort(a.object.name, b.object.name);
compareAssignmentPointsPossible: (a, b) ->
a.object.points_possible - b.object.points_possible
makeCompareAssignmentCustomOrderFn: (sortOrder) =>
sortMap = {}
indexCounter = 0
@ -561,7 +570,7 @@ define [
else
return @wrapColumnSortFn(@compareAssignmentPositions)(a, b)
wrapColumnSortFn: (wrappedFn) ->
wrapColumnSortFn: (wrappedFn, direction = 'ascending') ->
(a, b) ->
return -1 if b.type is 'total_grade'
return 1 if a.type is 'total_grade'
@ -569,7 +578,9 @@ define [
return 1 if a.type is 'assignment_group' and b.type isnt 'assignment_group'
if a.type is 'assignment_group' and b.type is 'assignment_group'
return a.object.position - b.object.position
return wrappedFn(a, b)
[a, b] = [b, a] if direction == 'descending'
wrappedFn(a, b)
rowFilter: (student) =>
matchingSection = !@sectionToShow || (@sectionToShow in student.sections)
@ -1116,10 +1127,6 @@ define [
if @hideAggregateColumns()
$settingsMenu.find('#include-ungraded-list-item').hide()
@$columnArrangementTogglers = $('#gradebook-toolbar [data-arrange-columns-by]').bind 'click', (event) =>
event.preventDefault()
newSortOrder = { sortType: $(event.currentTarget).data('arrangeColumnsBy') }
@arrangeColumnsBy(newSortOrder, false)
@arrangeColumnsBy(@getStoredSortOrder(), true)
$('#gradebook_settings').kyleMenu(returnFocusTo: $('#gradebook_settings'))
@ -1159,7 +1166,7 @@ define [
props.variant = mountPoint.getAttribute('data-variant')
renderComponent(GradebookMenu, mountPoint, props)
getViewOptionsMenuProps: ->
getTeacherNotesViewOptionsMenuProps: ->
teacherNotes = @options.teacher_notes
showingNotes = teacherNotes? and not teacherNotes.hidden
if showingNotes
@ -1168,10 +1175,39 @@ define [
onSelect = => @setTeacherNotesHidden(false)
else
onSelect = @createTeacherNotes
teacherNotes:
disabled: @contentLoadStates.teacherNotesColumnUpdating
onSelect: onSelect
selected: showingNotes
disabled: @contentLoadStates.teacherNotesColumnUpdating
onSelect: onSelect
selected: showingNotes
getColumnSortSettingsViewOptionsMenuProps: ->
storedSortOrder = @getStoredSortOrder()
criterion = if @isDefaultSortOrder(storedSortOrder.sortType)
'default'
else
storedSortOrder.sortType
criterion: criterion
direction: storedSortOrder.direction || 'ascending'
disabled: not @contentLoadStates.assignmentsLoaded
onSortByDefault: =>
@arrangeColumnsBy({ sortType: 'default', direction: 'ascending' }, false)
onSortByNameAscending: =>
@arrangeColumnsBy({ sortType: 'name', direction: 'ascending' }, false)
onSortByNameDescending: =>
@arrangeColumnsBy({ sortType: 'name', direction: 'descending' }, false)
onSortByDueDateAscending: =>
@arrangeColumnsBy({ sortType: 'due_date', direction: 'ascending' }, false)
onSortByDueDateDescending: =>
@arrangeColumnsBy({ sortType: 'due_date', direction: 'descending' }, false)
onSortByPointsAscending: =>
@arrangeColumnsBy({ sortType: 'points', direction: 'ascending' }, false)
onSortByPointsDescending: =>
@arrangeColumnsBy({ sortType: 'points', direction: 'descending' }, false)
getViewOptionsMenuProps: ->
teacherNotes: @getTeacherNotesViewOptionsMenuProps()
columnSortSettings: @getColumnSortSettingsViewOptionsMenuProps()
showUnpublishedAssignments: @showUnpublishedAssignments
onSelectShowUnpublishedAssignments: @toggleUnpublishedAssignments

View File

@ -24,7 +24,7 @@ import PopoverMenu from 'instructure-ui/lib/components/PopoverMenu';
import Typography from 'instructure-ui/lib/components/Typography';
import I18n from 'i18n!gradebook';
const { bool, func, shape } = React.PropTypes;
const { bool, func, shape, string } = React.PropTypes;
function renderTriggerButton () {
return (
@ -38,6 +38,18 @@ function renderTriggerButton () {
class ViewOptionsMenu extends React.Component {
static propTypes = {
columnSortSettings: shape({
criterion: string.isRequired,
direction: string.isRequired,
disabled: bool.isRequired,
onSortByDefault: func.isRequired,
onSortByNameAscending: func.isRequired,
onSortByNameDescending: func.isRequired,
onSortByDueDateAscending: func.isRequired,
onSortByDueDateDescending: func.isRequired,
onSortByPointsAscending: func.isRequired,
onSortByPointsDescending: func.isRequired
}).isRequired,
teacherNotes: shape({
disabled: bool.isRequired,
onSelect: func.isRequired,
@ -52,6 +64,17 @@ class ViewOptionsMenu extends React.Component {
this.bindMenuContent = (ref) => { this.menuContent = ref };
}
areColumnsOrderedBy (criterion, direction) {
const sortSettings = this.props.columnSortSettings;
const result = sortSettings.criterion === criterion;
if (direction === undefined) {
return result;
} else {
return result && sortSettings.direction === direction;
}
}
render () {
return (
<PopoverMenu
@ -59,16 +82,60 @@ class ViewOptionsMenu extends React.Component {
contentRef={this.bindMenuContent}
>
<MenuItemGroup label={I18n.t('Arrange By')}>
<MenuItem defaultSelected>
{ I18n.t('Assignment Name') }
<MenuItem
disabled={this.props.columnSortSettings.disabled}
selected={this.areColumnsOrderedBy('default')}
onSelect={this.props.columnSortSettings.onSortByDefault}
>
{ I18n.t('Default Order') }
</MenuItem>
<MenuItem>
{ I18n.t('Due Date') }
<MenuItem
disabled={this.props.columnSortSettings.disabled}
selected={this.areColumnsOrderedBy('name', 'ascending')}
onSelect={this.props.columnSortSettings.onSortByNameAscending}
>
{ I18n.t('Assignment Name - A-Z') }
</MenuItem>
<MenuItem>
{ I18n.t('Points') }
<MenuItem
disabled={this.props.columnSortSettings.disabled}
selected={this.areColumnsOrderedBy('name', 'descending')}
onSelect={this.props.columnSortSettings.onSortByNameDescending}
>
{ I18n.t('Assignment Name - Z-A') }
</MenuItem>
<MenuItem
disabled={this.props.columnSortSettings.disabled}
selected={this.areColumnsOrderedBy('due_date', 'ascending')}
onSelect={this.props.columnSortSettings.onSortByDueDateAscending}
>
{ I18n.t('Due Date - Oldest to Newest') }
</MenuItem>
<MenuItem
disabled={this.props.columnSortSettings.disabled}
selected={this.areColumnsOrderedBy('due_date', 'descending')}
onSelect={this.props.columnSortSettings.onSortByDueDateDescending}
>
{ I18n.t('Due Date - Newest to Oldest') }
</MenuItem>
<MenuItem
disabled={this.props.columnSortSettings.disabled}
selected={this.areColumnsOrderedBy('points', 'ascending')}
onSelect={this.props.columnSortSettings.onSortByPointsAscending}
>
{ I18n.t('Points - Lowest to Highest') }
</MenuItem>
<MenuItem
disabled={this.props.columnSortSettings.disabled}
selected={this.areColumnsOrderedBy('points', 'descending')}
onSelect={this.props.columnSortSettings.onSortByPointsDescending}
>
{ I18n.t('Points - Highest to Lowest') }
</MenuItem>
</MenuItemGroup>

View File

@ -152,6 +152,7 @@
<% end %>
<li><a class="student_names_toggle" href="#" role="button"><%= t('Hide Student Names') %></a></li>
<li><a data-arrange-columns-by="due_date" href="#"><label><%= t('Arrange columns by due date') %><input type="radio" name="arrange-columns-by" /></label></a></li>
<li><a data-arrange-columns-by="points" href="#"><label><%= t('Arrange columns by points') %><input type="radio" name="arrange-columns-by" /></label></a></li>
<li><a data-arrange-columns-by="assignment_group" href="#"><label><%= t('Arrange columns by assignment group') %><input type="radio" name="arrange-columns-by" /></label></a></li>
<li><a href="#"><label><%= t('Show Attendance Columns') %> <input type="checkbox" id="show_attendance" /></label></a></li>
<li id="include-ungraded-list-item"><a href="#"><label><%= t("Treat Ungraded as 0") %><input type="checkbox" id="include_ungraded_assignments" /></label></a></li>

View File

@ -91,8 +91,6 @@
</a></li>
<% end %>
<li><a class="student_names_toggle" href="#" role="button"><%= t('Hide Student Names') %></a></li>
<li><a data-arrange-columns-by="due_date" href="#"><label><%= t('Arrange columns by due date') %><input type="radio" name="arrange-columns-by" /></label></a></li>
<li><a data-arrange-columns-by="assignment_group" href="#"><label><%= t('Arrange columns by assignment group') %><input type="radio" name="arrange-columns-by" /></label></a></li>
<li><a href="#"><label><%= t('Show Attendance Columns') %> <input type="checkbox" id="show_attendance" /></label></a></li>
<li id="include-ungraded-list-item"><a href="#"><label><%= t("Treat Ungraded as 0") %><input type="checkbox" id="include_ungraded_assignments" /></label></a></li>
</ul>

View File

@ -510,6 +510,64 @@ test('returns false if "All Grading Periods" is selected and the grading period
notOk(this.hideAggregateColumns.call(self));
});
QUnit.module('Gradebook#makeColumnSortFn', {
sortOrder (sortType, direction) {
return {
sortType,
direction
}
},
setup () {
this.gradebook = createGradebook();
this.stub(this.gradebook, 'wrapColumnSortFn');
this.stub(this.gradebook, 'compareAssignmentPositions');
this.stub(this.gradebook, 'compareAssignmentDueDates');
this.stub(this.gradebook, 'compareAssignmentNames');
this.stub(this.gradebook, 'compareAssignmentPointsPossible');
}
});
test('wraps compareAssignmentPositions when called with a sortType of assignment_group', function () {
this.gradebook.makeColumnSortFn(this.sortOrder('assignment_group', 'ascending'));
const expectedArgs = [this.gradebook.compareAssignmentPositions, 'ascending'];
strictEqual(this.gradebook.wrapColumnSortFn.callCount, 1);
deepEqual(this.gradebook.wrapColumnSortFn.firstCall.args, expectedArgs);
});
test('wraps compareAssignmentPositions when called with a sortType of alpha', function () {
this.gradebook.makeColumnSortFn(this.sortOrder('alpha', 'descending'));
const expectedArgs = [this.gradebook.compareAssignmentPositions, 'descending'];
strictEqual(this.gradebook.wrapColumnSortFn.callCount, 1);
deepEqual(this.gradebook.wrapColumnSortFn.firstCall.args, expectedArgs);
});
test('wraps compareAssignmentNames when called with a sortType of name', function () {
this.gradebook.makeColumnSortFn(this.sortOrder('name', 'ascending'));
const expectedArgs = [this.gradebook.compareAssignmentNames, 'ascending'];
strictEqual(this.gradebook.wrapColumnSortFn.callCount, 1);
deepEqual(this.gradebook.wrapColumnSortFn.firstCall.args, expectedArgs);
});
test('wraps compareAssignmentDueDates when called with a sortType of due_date', function () {
this.gradebook.makeColumnSortFn(this.sortOrder('due_date', 'descending'));
const expectedArgs = [this.gradebook.compareAssignmentDueDates, 'descending'];
strictEqual(this.gradebook.wrapColumnSortFn.callCount, 1);
deepEqual(this.gradebook.wrapColumnSortFn.firstCall.args, expectedArgs);
});
test('wraps compareAssignmentPointsPossible when called with a sortType of points', function () {
this.gradebook.makeColumnSortFn(this.sortOrder('points', 'ascending'));
const expectedArgs = [this.gradebook.compareAssignmentPointsPossible, 'ascending'];
strictEqual(this.gradebook.wrapColumnSortFn.callCount, 1);
deepEqual(this.gradebook.wrapColumnSortFn.firstCall.args, expectedArgs);
});
QUnit.module('Gradebook#wrapColumnSortFn');
test('returns -1 if second argument is of type total_grade', function () {
@ -547,6 +605,45 @@ test('calls wrapped function when either column is not total_grade nor assignmen
ok(wrappedFn.called);
});
test('calls wrapped function with arguments in given order when no direction is given', function () {
const wrappedFn = this.stub();
const sortFn = createGradebook().wrapColumnSortFn(wrappedFn);
const first = { field: 1 };
const second = { field: 2 };
const expectedArgs = [first, second];
sortFn(first, second);
strictEqual(wrappedFn.callCount, 1);
deepEqual(wrappedFn.firstCall.args, expectedArgs);
});
test('calls wrapped function with arguments in given order when direction is ascending', function () {
const wrappedFn = this.stub();
const sortFn = createGradebook().wrapColumnSortFn(wrappedFn, 'ascending');
const first = { field: 1 };
const second = { field: 2 };
const expectedArgs = [first, second];
sortFn(first, second);
strictEqual(wrappedFn.callCount, 1);
deepEqual(wrappedFn.firstCall.args, expectedArgs);
});
test('calls wrapped function with arguments in reverse order when direction is descending', function () {
const wrappedFn = this.stub();
const sortFn = createGradebook().wrapColumnSortFn(wrappedFn, 'descending');
const first = { field: 1 };
const second = { field: 2 };
const expectedArgs = [second, first];
sortFn(first, second);
strictEqual(wrappedFn.callCount, 1);
deepEqual(wrappedFn.firstCall.args, expectedArgs);
});
QUnit.module('Gradebook#makeCompareAssignmentCustomOrderFn');
test('returns position difference if both are defined in the index', function () {
@ -605,6 +702,69 @@ test('falls back to object id for the indexes if field is not in the map', funct
equal(sortFn(a, b), -1);
});
QUnit.module('Gradebook#compareAssignmentNames', {
getRecord (name) {
return {
object: {
name
}
};
},
setup () {
this.gradebook = createGradebook();
this.firstRecord = this.getRecord('alpha');
this.secondRecord = this.getRecord('omega');
}
});
test('returns -1 if the name field comes first alphabetically in the first record', function () {
strictEqual(this.gradebook.compareAssignmentNames(this.firstRecord, this.secondRecord), -1);
});
test('returns 0 if the name field is the same in both records', function () {
strictEqual(this.gradebook.compareAssignmentNames(this.firstRecord, this.firstRecord), 0);
});
test('returns 1 if the name field comes later alphabetically in the first record', function () {
strictEqual(this.gradebook.compareAssignmentNames(this.secondRecord, this.firstRecord), 1);
});
test('comparison is case-insensitive', function () {
const thirdRecord = this.getRecord('Alpha');
strictEqual(this.gradebook.compareAssignmentNames(thirdRecord, this.firstRecord), 0);
});
QUnit.module('Gradebook#compareAssignmentPointsPossible', {
getRecord (pointsPossible) {
return {
object: {
points_possible: pointsPossible
}
};
},
setup () {
this.compareAssignmentPointsPossible = Gradebook.prototype.compareAssignmentPointsPossible;
this.firstRecord = this.getRecord(1);
this.secondRecord = this.getRecord(2);
}
});
test('returns a negative number if the points_possible field is smaller in the first record', function () {
strictEqual(this.compareAssignmentPointsPossible(this.firstRecord, this.secondRecord), -1);
});
test('returns 0 if the points_possible field is the same in both records', function () {
strictEqual(this.compareAssignmentPointsPossible(this.firstRecord, this.firstRecord), 0);
});
test('returns a positive number if the points_possible field is greater in the first record', function () {
strictEqual(this.compareAssignmentPointsPossible(this.secondRecord, this.firstRecord), 1);
});
QUnit.module('Gradebook#storeCustomColumnOrder');
test('stores the custom column order (ignoring frozen columns)', function () {
@ -629,6 +789,69 @@ test('stores the custom column order (ignoring frozen columns)', function () {
ok(gradeBook.setStoredSortOrder.calledWith(expectedSortOrder));
});
QUnit.module('Gradebook#getStoredSortOrder', {
setup () {
this.gradebookColumnOrderSettings = {
sortType: 'due_date',
direction: 'descending'
};
this.defaultColumnOrderSettings = {
sortType: 'assignment_group',
direction: 'ascending'
};
this.invalidColumnOrderSettings = {
sortType: 'custom'
};
this.gradebook = createGradebook({
gradebook_column_order_settings: this.gradebookColumnOrderSettings
});
}
});
test('returns the saved column order settings if they are valid', function () {
deepEqual(this.gradebook.getStoredSortOrder(), this.gradebookColumnOrderSettings);
});
test('returns the default column order settings if the stored settings are invalid', function () {
this.gradebook.gradebookColumnOrderSettings = this.invalidColumnOrderSettings;
deepEqual(this.gradebook.getStoredSortOrder(), this.defaultColumnOrderSettings);
});
test('returns the default column order settings if the column order has never been saved', function () {
this.gradebook.gradebookColumnOrderSettings = undefined
deepEqual(this.gradebook.getStoredSortOrder(), this.defaultColumnOrderSettings);
});
QUnit.module('Gradebook#isDefaultSortOrder', {
setup () {
this.isDefaultSortOrder = Gradebook.prototype.isDefaultSortOrder;
}
});
test('returns false if called with due_date', function () {
strictEqual(this.isDefaultSortOrder('due_date'), false);
});
test('returns false if called with name', function () {
strictEqual(this.isDefaultSortOrder('name'), false);
});
test('returns false if called with points', function () {
strictEqual(this.isDefaultSortOrder('points'), false);
});
test('returns false if called with points', function () {
strictEqual(this.isDefaultSortOrder('custom'), false);
});
test('returns true if called with anything else', function () {
strictEqual(this.isDefaultSortOrder('alpha'), true);
strictEqual(this.isDefaultSortOrder('assignment_group'), true);
});
QUnit.module('Gradebook#getVisibleGradeGridColumns', {
setup () {
this.getVisibleGradeGridColumns = Gradebook.prototype.getVisibleGradeGridColumns;
@ -709,7 +932,8 @@ test('falls back to the default sort type if the custom sort type does not have
this.makeCompareAssignmentCustomOrderFn = Gradebook.prototype.makeCompareAssignmentCustomOrderFn;
this.getVisibleGradeGridColumns();
ok(this.makeColumnSortFn.calledWith({
sortType: 'assignment_group'
sortType: 'assignment_group',
direction: 'ascending'
}));
});
@ -1170,49 +1394,49 @@ test('when editable, calls SubmissionDetailsDialog', function () {
deepEqual(this.submissionDialogArgs, expectedArguments);
});
QUnit.module('getViewOptionsMenuProps');
QUnit.module('Gradebook#getTeacherNotesViewOptionsMenuProps');
test('includes teacherNotes', function () {
const gradebook = createGradebook();
const props = gradebook.getViewOptionsMenuProps();
equal(typeof props.teacherNotes.disabled, 'boolean', 'props include "disabled"');
equal(typeof props.teacherNotes.onSelect, 'function', 'props include "onSelect"');
equal(typeof props.teacherNotes.selected, 'boolean', 'props include "selected"');
const props = gradebook.getTeacherNotesViewOptionsMenuProps();
equal(typeof props.disabled, 'boolean', 'props include "disabled"');
equal(typeof props.onSelect, 'function', 'props include "onSelect"');
equal(typeof props.selected, 'boolean', 'props include "selected"');
});
test('disabled defaults to false', function () {
const gradebook = createGradebook();
const props = gradebook.getViewOptionsMenuProps();
equal(props.teacherNotes.disabled, false);
const props = gradebook.getTeacherNotesViewOptionsMenuProps();
equal(props.disabled, false);
});
test('disabled is true if the teacher notes column is updating', function () {
const gradebook = createGradebook();
gradebook.setTeacherNotesColumnUpdating(true);
const props = gradebook.getViewOptionsMenuProps();
equal(props.teacherNotes.disabled, true);
const props = gradebook.getTeacherNotesViewOptionsMenuProps();
equal(props.disabled, true);
});
test('disabled is false if the teacher notes column is not updating', function () {
const gradebook = createGradebook();
gradebook.setTeacherNotesColumnUpdating(false);
const props = gradebook.getViewOptionsMenuProps();
equal(props.teacherNotes.disabled, false);
const props = gradebook.getTeacherNotesViewOptionsMenuProps();
equal(props.disabled, false);
});
test('onSelect calls createTeacherNotes if there are no teacher notes', function () {
const gradebook = createGradebook({ teacher_notes: null });
this.stub(gradebook, 'createTeacherNotes');
const props = gradebook.getViewOptionsMenuProps();
props.teacherNotes.onSelect();
const props = gradebook.getTeacherNotesViewOptionsMenuProps();
props.onSelect();
equal(gradebook.createTeacherNotes.callCount, 1);
});
test('onSelect calls setTeacherNotesHidden with false if teacher notes are hidden', function () {
const gradebook = createGradebook({ teacher_notes: { hidden: true } });
this.stub(gradebook, 'setTeacherNotesHidden');
const props = gradebook.getViewOptionsMenuProps();
props.teacherNotes.onSelect();
const props = gradebook.getTeacherNotesViewOptionsMenuProps();
props.onSelect();
equal(gradebook.setTeacherNotesHidden.callCount, 1);
equal(gradebook.setTeacherNotesHidden.getCall(0).args[0], false)
});
@ -1220,28 +1444,155 @@ test('onSelect calls setTeacherNotesHidden with false if teacher notes are hidde
test('onSelect calls setTeacherNotesHidden with true if teacher notes are visible', function () {
const gradebook = createGradebook({ teacher_notes: { hidden: false } });
this.stub(gradebook, 'setTeacherNotesHidden');
const props = gradebook.getViewOptionsMenuProps();
props.teacherNotes.onSelect();
const props = gradebook.getTeacherNotesViewOptionsMenuProps();
props.onSelect();
equal(gradebook.setTeacherNotesHidden.callCount, 1);
equal(gradebook.setTeacherNotesHidden.getCall(0).args[0], true)
});
test('selected is false if there are no teacher notes', function () {
const gradebook = createGradebook({ teacher_notes: null });
const props = gradebook.getViewOptionsMenuProps();
equal(props.teacherNotes.selected, false);
const props = gradebook.getTeacherNotesViewOptionsMenuProps();
equal(props.selected, false);
});
test('selected is false if teacher notes are hidden', function () {
const gradebook = createGradebook({ teacher_notes: { hidden: true } });
const props = gradebook.getViewOptionsMenuProps();
equal(props.teacherNotes.selected, false);
const props = gradebook.getTeacherNotesViewOptionsMenuProps();
equal(props.selected, false);
});
test('selected is true if teacher notes are visible', function () {
const gradebook = createGradebook({ teacher_notes: { hidden: false } });
const props = gradebook.getViewOptionsMenuProps();
equal(props.teacherNotes.selected, true);
const props = gradebook.getTeacherNotesViewOptionsMenuProps();
equal(props.selected, true);
});
QUnit.module('Gradebook#getColumnSortSettingsViewOptionsMenuProps', {
getProps (sortType = 'due_date', direction = 'ascending') {
const storedSortOrder = { sortType, direction };
this.stub(this.gradebook, 'getStoredSortOrder').returns(storedSortOrder);
const props = this.gradebook.getColumnSortSettingsViewOptionsMenuProps();
this.gradebook.getStoredSortOrder.restore();
return props;
},
expectedArgs (sortType, direction) {
return [
{ sortType, direction },
false
];
},
setup () {
this.gradebook = createGradebook();
this.stub(this.gradebook, 'arrangeColumnsBy');
}
});
test('includes all required properties', function () {
const props = this.getProps();
equal(typeof props.criterion, 'string', 'props include "criterion"');
equal(typeof props.direction, 'string', 'props include "direction"');
equal(typeof props.disabled, 'boolean', 'props include "disabled"');
equal(typeof props.onSortByDefault, 'function', 'props include "onSortByDefault"');
equal(typeof props.onSortByNameAscending, 'function', 'props include "onSortByNameAscending"');
equal(typeof props.onSortByNameDescending, 'function', 'props include "onSortByNameDescending"');
equal(typeof props.onSortByDueDateAscending, 'function', 'props include "onSortByDueDateAscending"');
equal(typeof props.onSortByDueDateDescending, 'function', 'props include "onSortByDueDateDescending"');
equal(typeof props.onSortByPointsAscending, 'function', 'props include "onSortByPointsAscending"');
equal(typeof props.onSortByPointsDescending, 'function', 'props include "onSortByPointsDescending"');
});
test('sets criterion to the sort field', function () {
strictEqual(this.getProps().criterion, 'due_date');
strictEqual(this.getProps('name').criterion, 'name');
});
test('sets criterion to "default" when isDefaultSortOrder returns true', function () {
strictEqual(this.getProps('assignment_group').criterion, 'default');
});
test('sets the direction', function () {
strictEqual(this.getProps(undefined, 'ascending').direction, 'ascending');
strictEqual(this.getProps(undefined, 'descending').direction, 'descending');
});
test('sets disabled to true when assignments have not been loaded yet', function () {
this.gradebook.setAssignmentsLoaded(false);
strictEqual(this.getProps().disabled, true);
});
test('sets disabled to false when assignments have been loaded', function () {
this.gradebook.setAssignmentsLoaded(true);
strictEqual(this.getProps().disabled, false);
});
test('sets onSortByNameAscending to a function that sorts columns by name ascending', function () {
this.getProps().onSortByNameAscending();
strictEqual(this.gradebook.arrangeColumnsBy.callCount, 1);
deepEqual(this.gradebook.arrangeColumnsBy.firstCall.args, this.expectedArgs('name', 'ascending'));
});
test('sets onSortByNameAscending to a function that sorts columns by name descending', function () {
this.getProps().onSortByNameDescending();
strictEqual(this.gradebook.arrangeColumnsBy.callCount, 1);
deepEqual(this.gradebook.arrangeColumnsBy.firstCall.args, this.expectedArgs('name', 'descending'));
});
test('sets onSortByDueDateAscending to a function that sorts columns by due date ascending', function () {
this.getProps().onSortByDueDateAscending();
strictEqual(this.gradebook.arrangeColumnsBy.callCount, 1);
deepEqual(this.gradebook.arrangeColumnsBy.firstCall.args, this.expectedArgs('due_date', 'ascending'));
});
test('sets onSortByDueDateAscending to a function that sorts columns by due date descending', function () {
this.getProps().onSortByDueDateDescending();
strictEqual(this.gradebook.arrangeColumnsBy.callCount, 1);
deepEqual(this.gradebook.arrangeColumnsBy.firstCall.args, this.expectedArgs('due_date', 'descending'));
});
test('sets onSortByPointsAscending to a function that sorts columns by points ascending', function () {
this.getProps().onSortByPointsAscending();
strictEqual(this.gradebook.arrangeColumnsBy.callCount, 1);
deepEqual(this.gradebook.arrangeColumnsBy.firstCall.args, this.expectedArgs('points', 'ascending'));
});
test('sets onSortByPointsAscending to a function that sorts columns by points descending', function () {
this.getProps().onSortByPointsDescending();
strictEqual(this.gradebook.arrangeColumnsBy.callCount, 1);
deepEqual(this.gradebook.arrangeColumnsBy.firstCall.args, this.expectedArgs('points', 'descending'));
});
QUnit.module('Gradebook#getViewOptionsMenuProps', {
setup () {
this.gradebook = createGradebook();
this.teacherNotesProps = { propsFor: 'teacherNotes' };
this.columnSortSettingProps = { propsFor: 'columnSortSettings' };
this.stub(this.gradebook, 'getTeacherNotesViewOptionsMenuProps').returns(this.teacherNotesProps);
this.stub(this.gradebook, 'getColumnSortSettingsViewOptionsMenuProps').returns(this.columnSortSettingProps);
this.props = this.gradebook.getViewOptionsMenuProps();
}
});
test('includes teacher notes properties', function () {
strictEqual(this.props.teacherNotes, this.teacherNotesProps);
});
test('includes column sort properties', function () {
strictEqual(this.props.columnSortSettings, this.columnSortSettingProps);
});
QUnit.module('Gradebook#createTeacherNotes', {
@ -4098,3 +4449,56 @@ test('sets the formatted grade on submission', function () {
this.gradebook.updateSubmission(this.submission);
equal(this.submission.grade, '123.45%');
});
QUnit.module('Gradebook#arrangeColumnsBy', {
setup () {
this.gradebook = createGradebook();
this.gradebook.parentColumns = [];
this.gradebook.customColumns = [];
this.gradebook.makeColumnSortFn = () => () => 1;
this.gradebook.grid = {
getColumns () { return []; },
setColumns () {}
}
}
});
test('renders the view options menu', function () {
this.stub(this.gradebook, 'renderViewOptionsMenu');
this.stub(this.gradebook, 'updateColumnHeaders');
this.stub(this.gradebook.grid, 'setColumns');
this.gradebook.arrangeColumnsBy({ sortBy: 'due_date', direction: 'ascending' }, false);
strictEqual(this.gradebook.renderViewOptionsMenu.callCount, 1);
});
QUnit.module('Gradebook#onColumnsReordered', {
setup () {
this.gradebook = createGradebook();
this.gradebook.customColumns = [];
this.gradebook.grid = {
getColumns () { return []; },
setColumns () {}
}
this.stub(this.gradebook, 'renderViewOptionsMenu');
this.stub(this.gradebook, 'updateColumnHeaders');
}
});
test('re-renders the View options menu', function () {
this.stub(this.gradebook, 'storeCustomColumnOrder');
this.gradebook.onColumnsReordered();
strictEqual(this.gradebook.renderViewOptionsMenu.callCount, 1);
});
test('re-renders all column headers', function () {
this.stub(this.gradebook, 'storeCustomColumnOrder');
this.gradebook.onColumnsReordered();
strictEqual(this.gradebook.updateColumnHeaders.callCount, 1);
});

View File

@ -29,6 +29,18 @@ function mountAndOpenOptions (props) {
QUnit.module('ViewOptionsMenu - notes', {
setup () {
this.props = {
columnSortSettings: {
criterion: 'due_date',
direction: 'ascending',
disabled: false,
onSortByDefault () {},
onSortByNameAscending () {},
onSortByNameDescending () {},
onSortByDueDateAscending () {},
onSortByDueDateDescending () {},
onSortByPointsAscending () {},
onSortByPointsDescending () {}
},
showUnpublishedAssignments: false,
onSelectShowUnpublishedAssignments: () => {},
teacherNotes: {
@ -103,6 +115,18 @@ QUnit.module('ViewOptionsMenu - unpublished assignments', {
onSelect: () => {},
selected: false
}}
columnSortSettings={{
criterion: 'due_date',
direction: 'ascending',
disabled: false,
onSortByDefault () {},
onSortByNameAscending () {},
onSortByNameDescending () {},
onSortByDueDateAscending () {},
onSortByDueDateDescending () {},
onSortByPointsAscending () {},
onSortByPointsDescending () {}
}}
/>
);
},
@ -114,6 +138,12 @@ QUnit.module('ViewOptionsMenu - unpublished assignments', {
.find('MenuItem')
.at(itemIndex);
},
teardown () {
if (this.wrapper) {
this.wrapper.unmount();
}
}
});
test('Unpublished Assignments is selected when showUnpublishedAssignments is true', function () {
@ -139,3 +169,292 @@ test('onSelectShowUnpublishedAssignment is called when selected', function () {
this.getMenuItemGroupAndMenuItem({ groupIndex: 1, itemIndex: 1 }).simulate('click');
strictEqual(onSelectShowUnpublishedAssignmentsStub.callCount, 1);
});
QUnit.module('ViewOptionsMenu - Column Sorting', {
getProps (criterion = 'due_date', direction = 'ascending', disabled = false) {
return {
columnSortSettings: {
criterion,
direction,
disabled,
onSortByDefault: this.stub(),
onSortByNameAscending: this.stub(),
onSortByNameDescending: this.stub(),
onSortByDueDateAscending: this.stub(),
onSortByDueDateDescending: this.stub(),
onSortByPointsAscending: this.stub(),
onSortByPointsDescending: this.stub()
},
showUnpublishedAssignments: false,
onSelectShowUnpublishedAssignments: () => {},
teacherNotes: {
disabled: false,
onSelect: () => {},
selected: true
}
};
},
getMenuContainer () {
return new ReactWrapper(this.wrapper.node.menuContent, this.wrapper.node);
},
getMenuItemGroup (name) {
let selectedMenuItemGroup;
const menuContainer = this.getMenuContainer();
const menuItemGroups = menuContainer.find('MenuItemGroup');
const menuItemGroupCount = menuItemGroups.length;
for (let groupIdx = 0; groupIdx < menuItemGroupCount; groupIdx++) {
const group = menuItemGroups.at(groupIdx);
if (group.props().label === name) {
selectedMenuItemGroup = group;
break;
}
}
return selectedMenuItemGroup;
},
getMenuItem (name, menuItemContainer) {
let selectedMenuItem;
const container = menuItemContainer || this.getMenuContainer();
const menuItems = container.find('MenuItem');
const menuItemCount = menuItems.length;
for (let menuItemIdx = 0; menuItemIdx < menuItemCount; menuItemIdx++) {
const menuItem = menuItems.at(menuItemIdx);
if (menuItem.text().trim() === name) {
selectedMenuItem = menuItem;
break;
}
}
return selectedMenuItem;
},
getMenuItems (filterProp, filterValue, menuItemContainer) {
const selectedMenuItems = [];
const container = menuItemContainer || this.getMenuContainer();
const menuItems = container.find('MenuItem');
const menuItemCount = menuItems.length;
for (let menuItemIdx = 0; menuItemIdx < menuItemCount; menuItemIdx++) {
const menuItem = menuItems.at(menuItemIdx);
if (filterProp === undefined || menuItem.props()[filterProp] === filterValue) {
selectedMenuItems.push(menuItem);
}
}
return selectedMenuItems;
},
teardown () {
if (this.wrapper) {
this.wrapper.unmount();
}
}
});
test('Default Order is selected when criterion is default and direction is ascending', function () {
const props = this.getProps('default', 'ascending');
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const selectedMenuItems = this.getMenuItems('selected', true, arrangeByMenuItemGroup);
strictEqual(selectedMenuItems.length, 1, 'only one menu item should be selected');
strictEqual(selectedMenuItems[0].text().trim(), 'Default Order');
});
test('Default Order is selected when criterion is default and direction is descending', function () {
const props = this.getProps('default', 'descending');
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const selectedMenuItems = this.getMenuItems('selected', true, arrangeByMenuItemGroup);
strictEqual(selectedMenuItems.length, 1, 'only one menu item should be selected');
strictEqual(selectedMenuItems[0].text().trim(), 'Default Order');
});
test('Assignment Name - A-Z is selected when criterion is name and direction is ascending', function () {
const props = this.getProps('name', 'ascending');
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const selectedMenuItems = this.getMenuItems('selected', true, arrangeByMenuItemGroup);
strictEqual(selectedMenuItems.length, 1, 'only one menu item should be selected');
strictEqual(selectedMenuItems[0].text().trim(), 'Assignment Name - A-Z');
});
test('Assignment Name - Z-A is selected when criterion is name and direction is ascending', function () {
const props = this.getProps('name', 'descending');
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const selectedMenuItems = this.getMenuItems('selected', true, arrangeByMenuItemGroup);
strictEqual(selectedMenuItems.length, 1, 'only one menu item should be selected');
strictEqual(selectedMenuItems[0].text().trim(), 'Assignment Name - Z-A');
});
test('Due Date - Oldest to Newest is selected when criterion is name and direction is ascending', function () {
const props = this.getProps('due_date', 'ascending');
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const selectedMenuItems = this.getMenuItems('selected', true, arrangeByMenuItemGroup);
strictEqual(selectedMenuItems.length, 1, 'only one menu item should be selected');
strictEqual(selectedMenuItems[0].text().trim(), 'Due Date - Oldest to Newest');
});
test('Due Date - Oldest to Newest is selected when criterion is name and direction is ascending', function () {
const props = this.getProps('due_date', 'descending');
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const selectedMenuItems = this.getMenuItems('selected', true, arrangeByMenuItemGroup);
strictEqual(selectedMenuItems.length, 1, 'only one menu item should be selected');
strictEqual(selectedMenuItems[0].text().trim(), 'Due Date - Newest to Oldest');
});
test('Points - Lowest to Highest is selected when criterion is name and direction is ascending', function () {
const props = this.getProps('points', 'ascending');
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const selectedMenuItems = this.getMenuItems('selected', true, arrangeByMenuItemGroup);
strictEqual(selectedMenuItems.length, 1, 'only one menu item should be selected');
strictEqual(selectedMenuItems[0].text().trim(), 'Points - Lowest to Highest');
});
test('Points - Lowest to Highest is selected when criterion is name and direction is ascending', function () {
const props = this.getProps('points', 'descending');
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const selectedMenuItems = this.getMenuItems('selected', true, arrangeByMenuItemGroup);
strictEqual(selectedMenuItems.length, 1, 'only one menu item should be selected');
strictEqual(selectedMenuItems[0].text().trim(), 'Points - Highest to Lowest');
});
test('all column ordering options are disabled when the column ordering settings are disabled', function () {
const props = this.getProps();
props.columnSortSettings.disabled = true;
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const disabledMenuItems = this.getMenuItems('disabled', true, arrangeByMenuItemGroup);
strictEqual(disabledMenuItems.length, 7, 'all column ordering menu items are disabled');
});
test('clicking on "Default Order" triggers onSortByDefault', function () {
const props = this.getProps();
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const specificMenuItem = this.getMenuItem('Default Order', arrangeByMenuItemGroup);
specificMenuItem.simulate('click');
strictEqual(props.columnSortSettings.onSortByDefault.callCount, 1);
});
test('clicking on "Assignments - A-Z" triggers onSortByNameAscending', function () {
const props = this.getProps();
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const specificMenuItem = this.getMenuItem('Assignment Name - A-Z', arrangeByMenuItemGroup);
specificMenuItem.simulate('click');
strictEqual(props.columnSortSettings.onSortByNameAscending.callCount, 1);
});
test('clicking on "Assignments - Z-A" triggers onSortByNameDescending', function () {
const props = this.getProps();
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const specificMenuItem = this.getMenuItem('Assignment Name - Z-A', arrangeByMenuItemGroup);
specificMenuItem.simulate('click');
strictEqual(props.columnSortSettings.onSortByNameDescending.callCount, 1);
});
test('clicking on "Due Date - Oldest to Newest" triggers onSortByDueDateAscending', function () {
const props = this.getProps();
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const specificMenuItem = this.getMenuItem('Due Date - Oldest to Newest', arrangeByMenuItemGroup);
specificMenuItem.simulate('click');
strictEqual(props.columnSortSettings.onSortByDueDateAscending.callCount, 1);
});
test('clicking on "Due Date - Newest to Oldest" triggers onSortByDueDateDescending', function () {
const props = this.getProps();
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const specificMenuItem = this.getMenuItem('Due Date - Newest to Oldest', arrangeByMenuItemGroup);
specificMenuItem.simulate('click');
strictEqual(props.columnSortSettings.onSortByDueDateDescending.callCount, 1);
});
test('clicking on "Points - Lowest to Highest" triggers onSortByPointsAscending', function () {
const props = this.getProps();
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const specificMenuItem = this.getMenuItem('Points - Lowest to Highest', arrangeByMenuItemGroup);
specificMenuItem.simulate('click');
strictEqual(props.columnSortSettings.onSortByPointsAscending.callCount, 1);
});
test('clicking on "Points - Highest to Lowest" triggers onSortByPointsDescending', function () {
const props = this.getProps();
this.wrapper = mountAndOpenOptions(props);
const arrangeByMenuItemGroup = this.getMenuItemGroup('Arrange By');
const specificMenuItem = this.getMenuItem('Points - Highest to Lowest', arrangeByMenuItemGroup);
specificMenuItem.simulate('click');
strictEqual(props.columnSortSettings.onSortByPointsDescending.callCount, 1);
});

View File

@ -53,16 +53,17 @@ describe "Gradezilla" do
end
context "return focus to settings menu when it closes" do
before { f('#gradebook_settings').click }
it "after hide/show student names is clicked", priority: "2", test_id: 720461 do
f('#gradebook_settings').click
f(".student_names_toggle").click
expect(active_element).to have_attribute('id', 'gradebook_settings')
end
it "after arrange columns is clicked", priority: "2", test_id: 720462 do
f("[data-arrange-columns-by='due_date']").click
expect(active_element).to have_attribute('id', 'gradebook_settings')
view_menu_trigger = gradezilla_page.gradebook_menu('View').find('button')
gradezilla_page.open_gradebook_menu('View')
gradezilla_page.select_gradebook_menu_option('Arrange By > Due Date - Oldest to Newest')
expect(active_element).to eq(view_menu_trigger)
end
end

View File

@ -25,27 +25,36 @@ describe "Gradezilla - arrange by assignment group" do
expect(first_row_cells[1]).to include_text @assignment_2_points
expect(first_row_cells[2]).to include_text "-"
arrange_settings = ff('input[name="arrange-columns-by"]')
f('#gradebook_settings').click
expect(arrange_settings.first.find_element(:xpath, '..')).to be_displayed
expect(arrange_settings.last.find_element(:xpath, '..')).not_to be_displayed
view_menu = gradezilla_page.open_gradebook_menu('View')
arrange_by_group = gradezilla_page.gradebook_menu_group('Arrange By', container: view_menu)
arrangement_menu_options = gradezilla_page.gradebook_menu_options(arrange_by_group)
selected_menu_options = arrangement_menu_options.select do |menu_item|
menu_item.attribute('aria-checked') == 'true'
end
expect(selected_menu_options.size).to eq(1)
expect(selected_menu_options[0].text.strip).to eq('Default Order')
end
it "should validate arrange columns by assignment group option", priority: "1", test_id: 220029 do
# since assignment group is the default, sort by due date, then assignment group again
arrange_settings = -> { ff('input[name="arrange-columns-by"]') }
f('#gradebook_settings').click
arrange_settings.call.first.find_element(:xpath, '..')
arrange_settings.call.last.find_element(:xpath, '..')
view_menu = gradezilla_page.open_gradebook_menu('View')
gradezilla_page.select_gradebook_menu_option('Default Order', container: view_menu)
first_row_cells = find_slick_cells(0, f('#gradebook_grid .container_1'))
expect(first_row_cells[0]).to include_text @assignment_1_points
expect(first_row_cells[1]).to include_text @assignment_2_points
expect(first_row_cells[2]).to include_text "-"
arrange_settings = -> { ff('input[name="arrange-columns-by"]') }
f('#gradebook_settings')
expect(arrange_settings.call.first.find_element(:xpath, '..')).to be_displayed
expect(arrange_settings.call.last.find_element(:xpath, '..')).not_to be_displayed
view_menu = gradezilla_page.open_gradebook_menu('View')
arrange_by_group = gradezilla_page.gradebook_menu_group('Arrange By', container: view_menu)
arrangement_menu_options = gradezilla_page.gradebook_menu_options(arrange_by_group)
selected_menu_options = arrangement_menu_options.select do |menu_item|
menu_item.attribute('aria-checked') == 'true'
end
expect(selected_menu_options.size).to eq(1)
expect(selected_menu_options[0].text.strip).to eq('Default Order')
# Setting should stick (not be messed up) after reload
gradezilla_page.visit(@course)
@ -55,9 +64,14 @@ describe "Gradezilla - arrange by assignment group" do
expect(first_row_cells[1]).to include_text @assignment_2_points
expect(first_row_cells[2]).to include_text "-"
arrange_settings = ff('input[name="arrange-columns-by"]')
f('#gradebook_settings').click
expect(arrange_settings.first.find_element(:xpath, '..')).to be_displayed
expect(arrange_settings.last.find_element(:xpath, '..')).not_to be_displayed
view_menu = gradezilla_page.open_gradebook_menu('View')
arrange_by_group = gradezilla_page.gradebook_menu_group('Arrange By', container: view_menu)
arrangement_menu_options = gradezilla_page.gradebook_menu_options(arrange_by_group)
selected_menu_options = arrangement_menu_options.select do |menu_item|
menu_item.attribute('aria-checked') == 'true'
end
expect(selected_menu_options.size).to eq(1)
expect(selected_menu_options[0].text.strip).to eq('Default Order')
end
end

View File

@ -21,14 +21,22 @@ describe "Gradezilla - arrange by due date" do
it "should validate arrange columns by due date option", priority: "1", test_id: 220027 do
expected_text = "-"
f('#gradebook_settings').click
arrange_settings = ff('input[name="arrange-columns-by"]')
arrange_settings.first.find_element(:xpath, '..').click
view_menu = gradezilla_page.open_gradebook_menu('View')
gradezilla_page.select_gradebook_menu_option('Arrange By > Due Date - Oldest to Newest', container: view_menu)
first_row_cells = find_slick_cells(0, f('#gradebook_grid .container_1'))
expect(first_row_cells[0]).to include_text expected_text
f('#gradebook_settings').click
expect(arrange_settings.first.find_element(:xpath, '..')).not_to be_displayed
expect(arrange_settings.last.find_element(:xpath, '..')).to be_displayed
view_menu = gradezilla_page.open_gradebook_menu('View')
arrange_by_group = gradezilla_page.gradebook_menu_group('Arrange By', container: view_menu)
arrangement_menu_options = gradezilla_page.gradebook_menu_options(arrange_by_group)
selected_menu_options = arrangement_menu_options.select do |menu_item|
menu_item.attribute('aria-checked') == 'true'
end
expect(selected_menu_options.size).to eq(1)
expect(selected_menu_options[0].text.strip).to eq('Due Date - Oldest to Newest')
# Setting should stick after reload
gradezilla_page.visit(@course)
@ -40,10 +48,15 @@ describe "Gradezilla - arrange by due date" do
expect(first_row_cells[1]).to include_text @assignment_1_points
expect(first_row_cells[2]).to include_text @assignment_2_points
f('#gradebook_settings').click
arrange_settings = ff('input[name="arrange-columns-by"]')
expect(arrange_settings.first.find_element(:xpath, '..')).not_to be_displayed
expect(arrange_settings.last.find_element(:xpath, '..')).to be_displayed
view_menu = gradezilla_page.open_gradebook_menu('View')
arrange_by_group = gradezilla_page.gradebook_menu_group('Arrange By', container: view_menu)
arrangement_menu_options = gradezilla_page.gradebook_menu_options(arrange_by_group)
selected_menu_options = arrangement_menu_options.select do |menu_item|
menu_item.attribute('aria-checked') == 'true'
end
expect(selected_menu_options.size).to eq(1)
expect(selected_menu_options[0].text.strip).to eq('Due Date - Oldest to Newest')
end
it "should put assignments with no due date last when sorting by due date and VDD", priority: "2", test_id: 251038 do
@ -55,8 +68,8 @@ describe "Gradezilla - arrange by due date" do
assignment2.update_attribute(:due_at, 3.days.from_now)
create_assignment_override(assignment2, @section_a, 2)
f('#gradebook_settings').click
f("a[data-arrange-columns-by='due_date']").click
view_menu = gradezilla_page.open_gradebook_menu('View')
gradezilla_page.select_gradebook_menu_option('Arrange By > Due Date - Oldest to Newest', container: view_menu)
# since due date changes in assignments don't reflect in column sorting without a refresh
gradezilla_page.visit(@course)
expect(f('#gradebook_grid .container_1 .slick-header-column:nth-child(1)')).to include_text(assignment3.title)
@ -76,8 +89,8 @@ describe "Gradezilla - arrange by due date" do
create_assignment_override(@assignment, @section_a, 5)
create_assignment_override(assignment3, @section_b, 4)
f('#gradebook_settings').click
f("a[data-arrange-columns-by='due_date']").click
view_menu = gradezilla_page.open_gradebook_menu('View')
gradezilla_page.select_gradebook_menu_option('Arrange By > Due Date - Oldest to Newest', container: view_menu)
expect(f('#gradebook_grid .container_1 .slick-header-column:nth-child(1)')).to include_text(assignment3.title)
expect(f('#gradebook_grid .container_1 .slick-header-column:nth-child(2)')).to include_text(@assignment.title)

View File

@ -57,11 +57,12 @@ describe "Gradezilla - assignment column headers" do
expect(first_row_cells[1]).to include_text @assignment_2_points
expect(first_row_cells[2]).to include_text @assignment_1_points
# both predefined short orders should be displayed since neither one is selected.
f('#gradebook_settings').click
arrange_settings = ff('input[name="arrange-columns-by"]')
expect(arrange_settings.first.find_element(:xpath, '..')).to be_displayed
expect(arrange_settings.last.find_element(:xpath, '..')).to be_displayed
# none of the predefined short orders should be selected.
view_menu = gradezilla_page.open_gradebook_menu('View')
arrange_by_group = gradezilla_page.gradebook_menu_group('Arrange By', container: view_menu)
arrangement_menu_options = gradezilla_page.gradebook_menu_options(arrange_by_group)
expect(arrangement_menu_options.all? { |menu_item| menu_item.attribute('aria-checked') == 'false'}).to be_truthy
end
it "should put new assignments at the end when columns have custom order", priority: "1", test_id: 220032 do

View File

@ -123,6 +123,60 @@ module Gradezilla
menu_item(name).click
end
# Semantic Methods for Gradebook Menus
def open_gradebook_menu(name)
trigger = f('button', gradebook_menu(name))
trigger.click
# return the id of the popover menu for use elsewhere if needed
menu_container(trigger.attribute('id'))
end
def select_gradebook_menu_option(name, container: nil)
gradebook_menu_option(name, container: container).click
end
def gradebook_menu_option(name = nil, container: nil)
menu_item_name = name
menu_container = container
if name =~ /(.+?) > (.+)/
menu_item_group_name, menu_item_name = Regexp.last_match[1], Regexp.last_match[2]
menu_container = gradebook_menu_group(menu_item_group_name, container: container)
end
gradebook_menu_options(menu_container).find { |el| el.text =~ /#{menu_item_name}/ }
end
# private
def gradebook_menu_options(container)
ff('[role*=menuitem]', container)
end
def gradebook_menu(name)
ff(".gradebook-menus [data-component]").find { |el| el.text.strip =~ /#{name}/ }
end
def menu_container(container_id)
selector = '[aria-expanded=true][role=menu]'
selector += "[aria-labelledby=#{container_id}]" if container_id
f(selector)
end
def gradebook_menu_group(name, container: nil)
menu_group = ff('[id*=MenuItemGroup]', container).find { |el| el.text.strip =~ /#{name}/ }
return unless menu_group
menu_group_id = menu_group.attribute('id')
f("[role=group][aria-labelledby=#{menu_group_id}]", container)
end
# End Methods for Gradebook Menus
private
def gp_dropdown() f(".grading-period-select-button") end