MDL-76134 gradebook: Modify user story behat tests into passable runs

This commit is contained in:
Mathew May
2023-01-09 09:22:20 +08:00
parent 712f219c7c
commit bf783645e1
8 changed files with 285 additions and 188 deletions
+3 -3
View File
@@ -109,14 +109,14 @@ if (!empty($target) && !empty($action) && confirm_sesskey()) {
$reportname = get_string('pluginname', 'gradereport_grader');
// Do this check just before printing the grade header (and only do it once).
grade_regrade_final_grades_if_required($course);
//Initialise the grader report object that produces the table
//the class grade_report_grader_ajax was removed as part of MDL-21562
$report = new grade_report_grader($courseid, $gpr, $context, $page, $sortitemid);
$numusers = $report->get_numusers(true, true);
// Do this check just before printing the grade header (and only do it once).
grade_regrade_final_grades_if_required($course);
$actionbar = new \gradereport_grader\output\action_bar($context, $report, $numusers);
print_grade_page_head($COURSE->id, 'report', 'grader', $reportname, false, $buttons, true,
null, null, null, $actionbar);
@@ -1,4 +1,4 @@
@gradereport @gradereport_grader
@gradereport @gradereport_grader @javascript
Feature: Using the AJAX grading feature of Grader report to update grades and feedback
In order to use AJAX grading
As a teacher
@@ -7,10 +7,10 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
| Course 1 | C1 | 0 | 1 |
And the following "custom profile fields" exist:
| datatype | shortname | name |
| text | frog | Favourite frog |
| datatype | shortname | name |
| text | frog | Favourite frog |
And the following "users" exist:
| username | firstname | lastname | email | idnumber | profile_field_frog |
| teacher1 | Teacher | 1 | teacher1@example.com | t1 | |
@@ -18,11 +18,11 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
| student2 | Student | 2 | student2@example.com | s2 | prince frog |
| student3 | Student | 3 | student3@example.com | s3 | |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
And the following "scales" exist:
| name | scale |
| Test Scale | Disappointing,Good,Very good,Excellent |
@@ -50,7 +50,6 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
| grade_report_showaverages | 0 |
| grade_report_enableajax | 1 |
@javascript
Scenario: Use the grader report without editing, with AJAX on and quick feedback off
When the following config values are set as admin:
| grade_overridecat | 1 |
@@ -105,7 +104,6 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
| Student 2 | - | 33.00 | - | 33.00 |
| Student 3 | 80.00 | 50.00 | Very good | 133.00 |
@javascript
Scenario: Use the grader report without editing, with AJAX and quick feedback on
When the following config values are set as admin:
| grade_overridecat | 1 |
@@ -143,7 +141,6 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
And I click on student "Student 2" for grade item "Item SU"
And the field "ajaxfeedback" matches value "Student 2 SU feedback"
@javascript
Scenario: Use the grader report without editing, with AJAX and quick feedback on, without category override
When the following config values are set as admin:
| grade_overridecat | 0 |
@@ -164,7 +161,6 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
| -1- | -7- | -16- |
| Student 2 | 33.00 | 33.00 |
@javascript
Scenario: Use the grader report with editing, with AJAX and quick feedback on, with category override
When the following config values are set as admin:
| grade_overridecat | 1 |
@@ -195,7 +191,6 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
And I click on student "Student 2" for grade item "Item 1"
And the field "ajaxfeedback" matches value "Some feedback"
@javascript
Scenario: Use the grader report with editing, with AJAX and quick feedback on, without category override
When the following config values are set as admin:
| grade_overridecat | 0 |
@@ -243,7 +238,6 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
And I click on student "Student 2" for grade item "Item 1"
And the field "ajaxfeedback" matches value "Some feedback"
@javascript
Scenario: Teacher can see an error when an incorrect grade is given using the grader report with editing and AJAX on
Given I log in as "teacher1"
And I am on "Course 1" course homepage
@@ -258,7 +252,6 @@ Feature: Using the AJAX grading feature of Grader report to update grades and fe
And I should not see "The grade entered for Item VU for Student 2 is more than the maximum allowed"
And the grade for "Student 2" in grade item "Item VU" should match "66.00"
@javascript
Scenario: Teacher can see user custom filed columns as additional user identity
Given the following config values are set as admin:
| showuseridentity | email,profile_field_frog |
@@ -0,0 +1,165 @@
@core @javascript @gradereport_grader
Feature: Within the grader report, test that we can open our generic filter dropdown component
In order to filter down the users on the page
As a teacher
I need to be able to see the filter and select a combination of parameters
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email | idnumber |
| teacher1 | Teacher | 1 | teacher1@example.com | t1 |
| student1 | Student | 1 | student1@example.com | s1 |
| student2 | Dummy | User | student2@example.com | s2 |
| student3 | User | Example | student3@example.com | s3 |
| student4 | User | Test | student4@example.com | s4 |
| student5 | Turtle | Manatee | student5@example.com | s5 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
| student4 | C1 | student |
| student5 | C1 | student |
And the following "activities" exist:
| activity | course | idnumber | name |
| assign | C1 | a1 | Test assignment one |
And I am on the "Course 1" "Course" page logged in as "teacher1"
And I change window size to "large"
And I navigate to "View > Grader report" in the course gradebook
Scenario: A teacher can open the filter component
Given I should see "Filter by name"
When I press "Filter by name"
Then I should see "27" node occurrences of type "input" in the "First name" "core_grades > initials bar"
And I should see "27" node occurrences of type "input" in the "Surname" "core_grades > initials bar"
And "input[data-action=cancel]" "css_element" should exist
And "input[data-action=save]" "css_element" should exist
Scenario: A teacher can filter the grader report to limit users reported
Given I press "Filter by name"
And I wait until "input[data-action=save]" "css_element" exists
When I select "D" in the "First name" "core_grades > initials bar"
And I press "Apply"
And I wait to be redirected
# We should only have one user that matches the "D" first name
Then the following should exist in the "user-grades" table:
| -1- |
| Dummy User |
And the following should not exist in the "user-grades" table:
| -1- |
| Teacher 1 |
| Student 1 |
| User Example |
| User Test |
| Turtle Manatee |
# Test filtering on last name
# Business logic: If all is selected, we will not show it i.e. First (D) and NOT First (D) Last (All)
And I press "First (D)"
And I select "All" in the "First name" "core_grades > initials bar"
And I select "M" in the "Surname" "core_grades > initials bar"
And I press "Apply"
And I wait to be redirected
# We should only have one user that matches the "T" first name
And the following should exist in the "user-grades" table:
| -1- |
| Turtle Manatee |
And the following should not exist in the "user-grades" table:
| -1- |
| Teacher 1 |
| Student 1 |
| User Example |
| User Test |
| Dummy User |
# Test filtering on first && last name
And I press "Last (M)"
And I select "U" in the "First name" "core_grades > initials bar"
And I select "T" in the "Surname" "core_grades > initials bar"
And I press "Apply"
And I wait to be redirected
# We should only have one user that matches the "T" first name
And the following should exist in the "user-grades" table:
| -1- |
| User Test |
And the following should not exist in the "user-grades" table:
| -1- |
| Teacher 1 |
| Student 1 |
| User Example |
| Dummy User |
| Turtle Manatee |
# Final cheeky check to ensure our button matches.
And I press "First (U) Last (T)"
Scenario: A teacher can quickly tell that a filter is applied to the current table
Given I press "Filter by name"
And I wait until "input[data-action=save]" "css_element" exists
When I select "T" in the "First name" "core_grades > initials bar"
And I press "Apply"
And I wait to be redirected
Then I should see "First (T)"
# Check if removing the filter, removes the highlight and user notice of applied filters
And I press "First (T)"
And I wait until "input[data-action=save]" "css_element" exists
And I select "All" in the "First name" "core_grades > initials bar"
And I press "Apply"
And I wait to be redirected
# Check if the name button indicates if a filter is active
And I should see "Filter by name"
And I should not see "First (T)"
Scenario: A teacher can close the filter either by clicking close or clicking off the dropdown
Given I press "Filter by name"
And "input[data-action=save]" "css_element" should be visible
When I click on "input[data-action=cancel]" "css_element"
Then "input[data-action=save]" "css_element" should not be visible
# Click off the drop down
And I press "Filter by name"
And "input[data-action=save]" "css_element" should be visible
And I click on "First name" "link" in the "gradereport-grader-table" "table"
And "input[data-action=save]" "css_element" should not be visible
Scenario: A teacher using a language besides english can reset the initials bar
Given the following "language customisations" exist:
| component | stringid | value |
| core | all | すべて |
And I press "Filter by name"
And "input[data-action=save]" "css_element" should be visible
And I select "T" in the "First name" "core_grades > initials bar"
And I press "Apply"
And I wait to be redirected
And I press "First (T)"
And I wait until "input[data-action=save]" "css_element" exists
When I select "すべて" in the "First name" "core_grades > initials bar"
And I press "Apply"
And I wait to be redirected
Then I should not see "First (すべて) Last (すべて)"
And the following should exist in the "user-grades" table:
| -1- |
| Dummy User |
| Student 1 |
| User Example |
| User Test |
| Turtle Manatee |
# This can be expanded for left/right/home & end keys but will have to be done in conjunction with the non mini render.
@accessibility
Scenario: A teacher can set focus and navigate the filter with the keyboard
Given the page should meet accessibility standards
And the page should meet "wcag131, wcag141, wcag412" accessibility standards
And the page should meet accessibility standards with "wcag131, wcag141, wcag412" extra tests
And I press "Filter by name"
And "input[data-action=save]" "css_element" should be visible
And the focused element is "All" "button" in the "First name" "core_grades > initials bar"
When I press the tab key
Then the focused element is "input[value=A]" "css_element" in the "First name" "core_grades > initials bar"
And I press the tab key
And the focused element is "input[value=B]" "css_element" in the "First name" "core_grades > initials bar"
+58
View File
@@ -0,0 +1,58 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
require_once(__DIR__ . '/../../../lib/behat/behat_base.php');
/**
* Behat grade related steps definitions.
*
* @package core_grades
* @copyright 2022 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class behat_grades extends behat_base {
/**
* Return the list of partial named selectors.
*
* @return array
*/
public static function get_partial_named_selectors(): array {
return [
new behat_component_named_selector(
'initials bar',
[".//*[contains(concat(' ', @class, ' '), ' initialbar ')]//span[contains(., %locator%)]/parent::div"]
),
];
}
/**
* Select a given element within a specific container instance.
*
* @Given /^I select "(?P<input_value>(?:[^"]|\\")*)" in the "(?P<instance>(?:[^"]|\\")*)" "(?P<instance_type>(?:[^"]|\\")*)"$/
* @param string $value The Needle
* @param string $element The Haystack to select within
* @param string $selectortype What type of haystack we are looking in
*/
public function i_select_in_the($value, $element, $selectortype) {
// Getting the container where the text should be found.
$container = $this->get_selected_node($selectortype, $element);
$node = $this->find('xpath', './/input[@value="' . $value . '"]', false, $container);
$node->click();
}
}
+1 -2
View File
@@ -41,9 +41,8 @@ Feature: We can use calculated grade totals
| grade_aggregations_visible | Mean of grades,Weighted mean of grades,Simple weighted mean of grades,Mean of grades (with extra credits),Median of grades,Lowest grade,Highest grade,Mode of grades,Natural |
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I am on "Course 1" course homepage with editing mode on
And I navigate to "View > Grader report" in the course gradebook
And I turn editing mode on
And I change window size to "large"
And I give the grade "60.00" to the user "Student 1" for the grade item "Test assignment one &"
And I give the grade "20.00" to the user "Student 1" for the grade item "Test assignment two"
+16 -4
View File
@@ -119,6 +119,7 @@ Feature: Initials bar
And I should see "Bstudent Astudent"
And I should see "Cstudent Cstudent"
@javascript
Scenario: Filter users on view gradebook page
Given the following "activities" exist:
| activity | course | idnumber | name | intro | assignsubmission_onlinetext_enabled | assignsubmission_file_enabled |
@@ -126,6 +127,7 @@ Feature: Initials bar
And I am on the "assign1" "Activity" page logged in as "teacher"
When I follow "View all submissions"
And I select "View gradebook" from the "jump" singleselect
And I press "Filter by name"
And ".initialbarall.page-item.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element"
And ".initialbarall.page-item.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element"
And ".page-item.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element"
@@ -133,15 +135,19 @@ Feature: Initials bar
And I should see "Astudent Astudent"
And I should see "Bstudent Astudent"
And I should see "Cstudent Cstudent"
And I click on "A" "link" in the ".initialbar.lastinitial .page-item.A" "css_element"
And I select "A" in the "Surname" "core_grades > initials bar"
And ".initialbarall.page-item.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element"
And ".initialbarall.page-item.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element"
And ".page-item.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element"
And ".page-item.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element"
And I press "Apply"
And I should see "Astudent Astudent"
And I should see "Bstudent Astudent"
And I should not see "Cstudent Cstudent"
And I click on "B" "link" in the ".initialbar.firstinitial .page-item.B" "css_element"
And I press "Last (A)"
And I select "B" in the "First name" "core_grades > initials bar"
And I press "Apply"
And I wait until the page is ready
And ".initialbarall.page-item.active" "css_element" should not exist in the ".initialbar.firstinitial" "css_element"
And ".initialbarall.page-item.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element"
And ".page-item.active.B" "css_element" should exist in the ".initialbar.firstinitial" "css_element"
@@ -159,19 +165,25 @@ Feature: Initials bar
And I should not see "Astudent Astudent"
And I should see "Bstudent Astudent"
And I should not see "Cstudent Cstudent"
And I click on "All" "link" in the ".initialbar.firstinitial" "css_element"
And I press "First (B) Last (A)"
And I select "All" in the "First name" "core_grades > initials bar"
And ".initialbarall.page-item.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element"
And ".initialbarall.page-item.active" "css_element" should not exist in the ".initialbar.lastinitial" "css_element"
And ".page-item.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element"
And ".page-item.active.A" "css_element" should exist in the ".initialbar.lastinitial" "css_element"
And I press "Apply"
And I wait until the page is ready
And I should see "Astudent Astudent"
And I should see "Bstudent Astudent"
And I should not see "Cstudent Cstudent"
And I click on "All" "link" in the ".initialbar.lastinitial" "css_element"
And I press "Last (A)"
And I select "All" in the "Surname" "core_grades > initials bar"
And ".initialbarall.page-item.active" "css_element" should exist in the ".initialbar.firstinitial" "css_element"
And ".initialbarall.page-item.active" "css_element" should exist in the ".initialbar.lastinitial" "css_element"
And ".page-item.active.B" "css_element" should not exist in the ".initialbar.firstinitial" "css_element"
And ".page-item.active.A" "css_element" should not exist in the ".initialbar.lastinitial" "css_element"
And I press "Apply"
And I wait until the page is ready
And I should see "Astudent Astudent"
And I should see "Bstudent Astudent"
And I should see "Cstudent Cstudent"
+33
View File
@@ -2155,6 +2155,39 @@ EOF;
}
}
/**
* Checks, that the specified element contains the specified node type a certain amount of times.
* When running Javascript tests it also considers that texts may be hidden.
*
* @Then /^I should see "(?P<elementscount_number>\d+)" node occurrences of type "(?P<node_type>(?:[^"]|\\")*)" in the "(?P<element_string>(?:[^"]|\\")*)" "(?P<text_selector_string>[^"]*)"$/
* @throws ElementNotFoundException
* @throws ExpectationException
* @param int $elementscount How many occurrences of the element we look for.
* @param string $nodetype
* @param string $element Element we look in.
* @param string $selectortype The type of element where we are looking in.
*/
public function i_should_see_node_occurrences_of_type_in_element(int $elementscount, string $nodetype, string $element, string $selectortype) {
// Getting the container where the text should be found.
$container = $this->get_selected_node($selectortype, $element);
$xpath = "/descendant-or-self::$nodetype [count(descendant::$nodetype) = 0]";
$nodes = $this->find_all('xpath', $xpath, false, $container);
if ($this->running_javascript()) {
$nodes = array_filter($nodes, function($node) {
return $node->isVisible();
});
}
if ($elementscount != count($nodes)) {
throw new ExpectationException('Found '.count($nodes).' elements in column. Expected '.$elementscount,
$this->getSession());
}
}
/**
* Manually press enter key.
*
-163
View File
@@ -1,163 +0,0 @@
@core @javascript
Feature: Within the grader report, test that we can open our generic filter dropdown component
In order to filter down the users on the page
As a teacher
I need to be able to see the filter and select a combination of parameters
Background:
Given the following "courses" exist:
| fullname | shortname | category | groupmode |
| Course 1 | C1 | 0 | 1 |
And the following "users" exist:
| username | firstname | lastname | email | idnumber |
| teacher1 | Teacher | 1 | teacher1@example.com | t1 |
| student1 | Student | 1 | student1@example.com | s1 |
| student2 | Dummy | User | student2@example.com | s2 |
| student3 | User | Example | student3@example.com | s3 |
| student4 | User | Test | student4@example.com | s4 |
| student5 | Turtle | Manatee | student5@example.com | s5 |
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
| student2 | C1 | student |
| student3 | C1 | student |
| student4 | C1 | student |
| student5 | C1 | student |
And the following "activities" exist:
| activity | course | idnumber | name |
| assign | C1 | a1 | Test assignment one |
And I am on the "Course 1" "Course" page logged in as "teacher1"
And I change window size to "large"
And I navigate to "View > Grader report" in the course gradebook
Scenario: A teacher can open the filer component
Given I should see "Name" "button"
When I press "Name"
# Meeting outcome: We will use a placeholder pulse pattern.
# And I wait until "pulsing placholder" "css_element" exists
# And I wait until "Apply filter" "button" exists
# Meeting outcome: "All" option will still exist for the time being, with the followup of toggling active nodes to disable filter
# Meeting outcome: Deferred for later in the release after A+B testing done in-house.
And I should see "A loading spinner"
And I wait until "Apply filter" "button" exists
# https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/
Then I should see "27" occurrences of "Filter option" in the "First name" "Tool bar"
And I should see "27" occurrences of "Filter option" in the "Last name" "Tool bar"
# Meeting outcome: Upon selection, the table should update like the participants filter
# Given the above meeting outcome, This button will likely not need to exist
And I should see "Close" "button"
And I should see "Apply filter" "button"
# We need to decide if we want the page to reload or if the page content reloads like in the Course participants filters
Scenario: A teacher can filter the grader report to limit users reported
Given I press "Name"
And I wait until "Apply filter" "button" exists
When I select "D" in the "First name" "Toolbar"
And I press "Apply filter"
# Assuming we close the dropdown once filter is applied
And I wait until "Apply filter" "Button" does not exist
# We should only have one user that matches the "D" first name
Then the following should exist in the "user-grades" table:
| -1- |
| Dummy User |
# All other users should not be shown to the user based on filtering
And the following should not exist in the "user-grades" table:
| -1- |
| Teacher 1 |
| Student 1 |
| User Example |
| User Test |
| Turtle Manatee |
# Test filtering on last name
# Meeting outcome: Indication will be: First(T)
# Meeting outcome: If all is selected, we will not show it i.e. First (D) and NOT First (D) Last (All)
And I press "First (D)"
And I select "All" in the "First name" "Toolbar"
And I select "M" in the "Last name" "Toolbar"
And I press "Apply filter"
# Assuming we close the dropdown once filter is applied
And I wait until "Apply filter" "Button" does not exist
And I should see "First (U) Last(T)" "button"
# We should only have one user that matches the "T" first name
And the following should exist in the "user-grades" table:
| -1- |
| Turtle Manatee |
# All other users should not be shown to the user based on filtering
And the following should not exist in the "user-grades" table:
| -1- |
| Teacher 1 |
| Student 1 |
| User Example |
| User Test |
| Dummy User |
# Test filtering on first && last name
And I press "Name"
And I select "U" in the "First name" "Toolbar"
And I select "T" in the "Last name" "Toolbar"
And I press "Apply filter"
# Assuming we close the dropdown once filter is applied
And I wait until "Apply filter" "Button" does not exist
# We should only have one user that matches the "T" first name
And the following should exist in the "user-grades" table:
| -1- |
| User Test |
# All other users should not be shown to the user based on filtering
And the following should not exist in the "user-grades" table:
| -1- |
| Teacher 1 |
| Student 1 |
| User Example |
| Dummy User |
| Turtle Manatee |
Scenario: A teacher can quickly tell that a filter is applied to the current table
Given I press "Name"
And I wait until "Apply filter" "button" exists
When I select "T" in the "First name" "Toolbar"
And I press "Apply filter"
# Assuming we close the dropdown once filter is applied
And I wait until "Apply filter" "Button" does not exist
# Check if the name button indicates if a filter is active
Then I should see "First (T)"
# Meeting outcome: No decision yet if we alter the colors / active state / focus state
And I should see that "Name (T)" "button" is highlighted
# Check if removing the filter, removes the highlight and user notice of applied filters
And I press "First (T)"
And I wait until "Apply filter" "button" exists
And I select "All" in the "First name" "Toolbar"
And I press "Apply filter"
# Assuming we close the dropdown once filter is applied
And I wait until "Apply filter" "Button" does not exist
# Check if the name button indicates if a filter is active
And I should see "Name"
# Meeting outcome: We do not show First(All) Last(All)
And I should not see "First (T)"
And I should not see that "Name" "button" is highlighted
Scenario: A teacher can close the filter either by clicking close or clicking off the dropdown
# Meeting outcome: We would like this report to act like the participants filter page with the dynamic table
# Meeting outcome: Should we save state of user input when clicking off or click close?: - Maybe not needed? based on if we were to filter instantly on the user selection like we do in the participants page.
Given I press "Name"
And I wait until "Apply filter" "button" exists
When I press "Close"
Then I should not see "Apply filter"
# Click off the drop down
And I press "Name"
And I wait until "Apply filter" "button" exists
And I click on "First name" "link" in the "gradereport-grader-table" "table"
And I should not see "Apply filter"
# This can be expanded for left/right/up/down/home & end keys
Scenario: A teacher can set focus and navigate the filter with the keyboard
Given I press "Name"
And I wait until "Apply filter" "button" exists
And the focused element is "All" "button" in the "First name" "Toolbar"
When I press the right key
Then the focused element is "A" "button" in the "First name" "Toolbar"
And I press the tab key
And the focused element is "All" "button" in the "Last name" "Toolbar"