MDL-78217 grade: Refine front-end weight handling and add validation

In this commit, the front-end experience for grade item weights in the
gradebook setup page is refined, building upon the improvements made in
the previous commit.

Firstly, overridden weights are excluded from automatic adjustments.
This enhancement guarantees that user-specified weights remain unchanged
by front-end calculations, thereby preserving the flexibility of custom
weight assignments.

Additionally, front-end form validation has been introduced to enhance
the user experience. Now, users will see validation errors if they
submit invalid values, giving them the opportunity to correct the values
themselves. This ensures that weights are not automatically normalised
by the back-end code, preserving the values as entered by the user.
This commit is contained in:
Shamim Rezaie 2023-09-04 00:41:36 +10:00
parent 22a97437d1
commit 6aa05cfb9a
8 changed files with 134 additions and 108 deletions

View File

@ -1,4 +1,4 @@
define("core_grades/edittree_weights",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0;
define("core_grades/edittree_weights",["exports","core/str","core/prefetch"],(function(_exports,_str,_prefetch){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0;
/**
* This module provides functionality for managing weight calculations and adjustments for grade items.
*
@ -6,6 +6,6 @@ define("core_grades/edittree_weights",["exports"],(function(_exports){Object.def
* @copyright 2023 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
const selectors_weightOverrideCheckbox='input[type="checkbox"][name^="weightoverride_"]',selectors_weightOverrideInput='input[type="text"][name^="weight_"]',selectors_childrenByCategory=category=>'tr[data-parent-category="'.concat(category,'"]'),selectors_categoryByIdentifier=identifier=>'tr.category[data-category="'.concat(identifier,'"]'),grade_aggregation={sum:13};let decimalSeparator,oldExtraCreditCalculation;const formatWeight=weight=>weight.toFixed(3).replace(/0{0,2}$/,"").replace(".",decimalSeparator),parseWeight=weightString=>{const normalizedWeightString=weightString.replace(decimalSeparator,".");return isNaN(Number(normalizedWeightString))?0:parseFloat(normalizedWeightString||0)};_exports.init=(decSep,oldCalculation)=>{decimalSeparator=decSep,oldExtraCreditCalculation=oldCalculation,document.addEventListener("change",(e=>{if(e.target.matches(selectors_weightOverrideInput)||e.target.matches(selectors_weightOverrideCheckbox)){const gradeItemRow=e.target.closest("tr"),categoryElement=document.querySelector(selectors_categoryByIdentifier(gradeItemRow.dataset.parentCategory));if(parseInt(categoryElement.dataset.aggregation)===grade_aggregation.sum){const weightElement=gradeItemRow.querySelector(selectors_weightOverrideInput);weightElement.value=formatWeight(parseWeight(weightElement.value)),(categoryElement=>{const childElements=document.querySelectorAll(selectors_childrenByCategory(categoryElement.dataset.category));let totalGradeMax=0,totalOverriddenWeight=0,totalOverriddenGradeMax=0,automaticGradeItemsPresent=!1,requiresNormalising=!1;const overrideArray={};for(const childElement of childElements){const weightInput=childElement.querySelector(selectors_weightOverrideInput),weightCheckbox=childElement.querySelector(selectors_weightOverrideCheckbox);if(!weightInput)continue;const itemWeight=parseWeight(weightInput.value),itemAggregationCoefficient=parseInt(childElement.dataset.aggregationcoef),itemGradeMax=parseFloat(childElement.dataset.grademax);overrideArray[childElement.dataset.itemid]={extraCredit:itemAggregationCoefficient,weight:itemWeight,weightOverride:weightCheckbox.checked},weightCheckbox.checked||0!==itemAggregationCoefficient||(automaticGradeItemsPresent=!0),itemAggregationCoefficient>0||weightCheckbox.checked&&itemWeight<=0||(totalGradeMax+=itemGradeMax,weightCheckbox.checked&&(totalOverriddenWeight+=itemWeight,totalOverriddenGradeMax+=itemGradeMax))}let normaliseTotal=0,overriddenTotal=0;for(const gradeItemDetail of Object.values(overrideArray))gradeItemDetail.extraCredit||(normaliseTotal+=gradeItemDetail.weight),gradeItemDetail.weightOverride&&!gradeItemDetail.extraCredit&&gradeItemDetail.weight>0&&(overriddenTotal+=gradeItemDetail.weight);overriddenTotal>100&&(requiresNormalising=!0,normaliseTotal=overriddenTotal);const totalNonOverriddenGradeMax=totalGradeMax-totalOverriddenGradeMax;for(const childElement of childElements){const weightInput=childElement.querySelector(selectors_weightOverrideInput),weightCheckbox=childElement.querySelector(selectors_weightOverrideCheckbox),itemAggregationCoefficient=parseInt(childElement.dataset.aggregationcoef),itemGradeMax=parseFloat(childElement.dataset.grademax);weightInput&&(!oldExtraCreditCalculation&&itemAggregationCoefficient>0&&weightCheckbox.checked||(!oldExtraCreditCalculation&&itemAggregationCoefficient>0&&!weightCheckbox.checked?weightInput.value=totalGradeMax?formatWeight(100*itemGradeMax/totalGradeMax):0:weightCheckbox.checked?(!automaticGradeItemsPresent&&100!==normaliseTotal||requiresNormalising||overrideArray[childElement.dataset.itemid].weight<0)&&(0===normaliseTotal||overrideArray[childElement.dataset.itemid].weight<0?weightInput.value=formatWeight(0):weightInput.value=formatWeight(100*overrideArray[childElement.dataset.itemid].weight/normaliseTotal)):weightInput.value=formatWeight(totalOverriddenWeight>=100||0===totalNonOverriddenGradeMax||0===itemGradeMax?0:itemGradeMax/totalNonOverriddenGradeMax*(100-totalOverriddenWeight))))}})(categoryElement)}}}))}}));
const selectors_weightOverrideCheckbox='input[type="checkbox"][name^="weightoverride_"]',selectors_weightOverrideInput='input[type="text"][name^="weight_"]',selectors_childrenByCategory=category=>'tr[data-parent-category="'.concat(category,'"]'),selectors_categoryByIdentifier=identifier=>'tr.category[data-category="'.concat(identifier,'"]'),grade_aggregation={sum:13};let decimalSeparator,oldExtraCreditCalculation;const formatWeight=weight=>weight.toFixed(3).replace(/0{0,2}$/,"").replace(".",decimalSeparator),parseWeight=weightString=>{const normalizedWeightString=weightString.replace(decimalSeparator,".");return isNaN(Number(normalizedWeightString))?0:parseFloat(normalizedWeightString||0)};_exports.init=(decSep,oldCalculation)=>{decimalSeparator=decSep,oldExtraCreditCalculation=oldCalculation,(0,_prefetch.prefetchStrings)("core_grades",["erroroverweight","errorunderweight"]),document.addEventListener("change",(e=>{if(e.target.matches(selectors_weightOverrideInput)||e.target.matches(selectors_weightOverrideCheckbox)){const gradeItemRow=e.target.closest("tr"),categoryElement=document.querySelector(selectors_categoryByIdentifier(gradeItemRow.dataset.parentCategory));if(parseInt(categoryElement.dataset.aggregation)===grade_aggregation.sum){const weightElement=gradeItemRow.querySelector(selectors_weightOverrideInput);weightElement.value=formatWeight(parseWeight(weightElement.value)),(categoryElement=>{const childElements=document.querySelectorAll(selectors_childrenByCategory(categoryElement.dataset.category));let totalGradeMax=0,totalOverriddenWeight=0,totalOverriddenGradeMax=0,automaticGradeItemsPresent=!1,requiresNormalising=!1;const overrideArray={};for(const childElement of childElements){const weightInput=childElement.querySelector(selectors_weightOverrideInput),weightCheckbox=childElement.querySelector(selectors_weightOverrideCheckbox);if(!weightInput)continue;const itemWeight=parseWeight(weightInput.value),itemAggregationCoefficient=parseInt(childElement.dataset.aggregationcoef),itemGradeMax=parseFloat(childElement.dataset.grademax);overrideArray[childElement.dataset.itemid]={extraCredit:itemAggregationCoefficient,weight:itemWeight,weightOverride:weightCheckbox.checked},weightCheckbox.checked||0!==itemAggregationCoefficient||(automaticGradeItemsPresent=!0),itemAggregationCoefficient>0||weightCheckbox.checked&&itemWeight<=0||(totalGradeMax+=itemGradeMax,weightCheckbox.checked&&(totalOverriddenWeight+=itemWeight,totalOverriddenGradeMax+=itemGradeMax))}let normaliseTotal=0,overriddenTotal=0;for(const gradeItemDetail of Object.values(overrideArray))!gradeItemDetail.extraCredit&&gradeItemDetail.weight>0&&(normaliseTotal+=gradeItemDetail.weight),gradeItemDetail.weightOverride&&!gradeItemDetail.extraCredit&&gradeItemDetail.weight>0&&(overriddenTotal+=gradeItemDetail.weight);overriddenTotal>100&&(requiresNormalising=!0,normaliseTotal=overriddenTotal);const totalNonOverriddenGradeMax=totalGradeMax-totalOverriddenGradeMax;for(const childElement of childElements){const weightInput=childElement.querySelector(selectors_weightOverrideInput),weightCheckbox=childElement.querySelector(selectors_weightOverrideCheckbox),itemAggregationCoefficient=parseInt(childElement.dataset.aggregationcoef),itemGradeMax=parseFloat(childElement.dataset.grademax);if(!weightInput)continue;if(!oldExtraCreditCalculation&&itemAggregationCoefficient>0&&weightCheckbox.checked)continue;weightInput.classList.remove("is-invalid");const errorArea=weightInput.closest("td").querySelector(".invalid-feedback");if(errorArea.textContent="",!oldExtraCreditCalculation&&itemAggregationCoefficient>0&&!weightCheckbox.checked)weightInput.value=totalGradeMax?formatWeight(100*itemGradeMax/totalGradeMax):0;else if(weightCheckbox.checked){if(!automaticGradeItemsPresent&&100!==normaliseTotal||requiresNormalising||overrideArray[childElement.dataset.itemid].weight<0)if(overrideArray[childElement.dataset.itemid].weight<0)weightInput.value=formatWeight(0);else{const error=normaliseTotal>100?"erroroverweight":"errorunderweight";(0,_str.getString)(error,"core_grades").then((errorString=>{errorArea.textContent=errorString})),weightInput.classList.add("is-invalid")}}else weightInput.value=formatWeight(totalOverriddenWeight>=100||0===totalNonOverriddenGradeMax||0===itemGradeMax?0:itemGradeMax/totalNonOverriddenGradeMax*(100-totalOverriddenWeight))}})(categoryElement)}}})),document.addEventListener("submit",(e=>{if(e.target.matches("#gradetreeform")){const firstInvalidWeightInput=e.target.querySelector("input.is-invalid");if(firstInvalidWeightInput){const firstFocusableInvalidWeightInput=e.target.querySelector("input.is-invalid:enabled");firstFocusableInvalidWeightInput?firstFocusableInvalidWeightInput.focus():firstInvalidWeightInput.scrollIntoView({block:"center"}),e.preventDefault()}}}))}}));
//# sourceMappingURL=edittree_weights.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -21,6 +21,9 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import {getString} from 'core/str';
import {prefetchStrings} from 'core/prefetch';
/**
* Selectors.
*
@ -144,12 +147,11 @@ const recalculateNaturalWeights = (categoryElement) => {
let overriddenTotal = 0;
// Total up all the weights.
for (const gradeItemDetail of Object.values(overrideArray)) {
// If the grade item has extra credit, then don't add it to normaliseTotal.
if (!gradeItemDetail.extraCredit) {
// Exclude grade items with extra credit or negative weights (which will be set to zero later).
if (!gradeItemDetail.extraCredit && gradeItemDetail.weight > 0) {
normaliseTotal += gradeItemDetail.weight;
}
// The overridden total comprises items that are set as overridden, are not extra credit, and have a value
// greater than zero.
// The overridden total includes items that are marked as overridden, not extra credit, and have a positive weight.
if (gradeItemDetail.weightOverride && !gradeItemDetail.extraCredit && gradeItemDetail.weight > 0) {
// Add overridden weights up to see if they are greater than 1.
overriddenTotal += gradeItemDetail.weight;
@ -178,6 +180,11 @@ const recalculateNaturalWeights = (categoryElement) => {
continue;
}
// Remove any error messages and classes.
weightInput.classList.remove('is-invalid');
const errorArea = weightInput.closest('td').querySelector('.invalid-feedback');
errorArea.textContent = '';
if (!oldExtraCreditCalculation && itemAggregationCoefficient > 0 && !weightCheckbox.checked) {
// For an item with extra credit ignore other weights and overrides.
weightInput.value = totalGradeMax ? formatWeight(itemGradeMax * 100 / totalGradeMax) : 0;
@ -191,16 +198,17 @@ const recalculateNaturalWeights = (categoryElement) => {
// then convert it to a proportion of the available non-overridden weight.
weightInput.value = formatWeight((itemGradeMax / totalNonOverriddenGradeMax) * (100 - totalOverriddenWeight));
}
} else if ((!automaticGradeItemsPresent && normaliseTotal !== 100) || (requiresNormalising) ||
} else if ((!automaticGradeItemsPresent && normaliseTotal !== 100) || requiresNormalising ||
overrideArray[childElement.dataset.itemid].weight < 0) {
// Just divide the overridden weight for this item against the total weight override of all
// items in this category.
if (normaliseTotal === 0 || overrideArray[childElement.dataset.itemid].weight < 0) {
// If the normalised total equals zero, or the weight value is less than zero,
// set the weight for the grade item to zero.
if (overrideArray[childElement.dataset.itemid].weight < 0) {
weightInput.value = formatWeight(0);
} else {
weightInput.value = formatWeight(100 * overrideArray[childElement.dataset.itemid].weight / normaliseTotal);
const error = normaliseTotal > 100 ? 'erroroverweight' : 'errorunderweight';
// eslint-disable-next-line promise/always-return,promise/catch-or-return
getString(error, 'core_grades').then((errorString) => {
errorArea.textContent = errorString;
});
weightInput.classList.add('is-invalid');
}
}
}
@ -236,6 +244,7 @@ const parseWeight = (weightString) => {
export const init = (decSep, oldCalculation) => {
decimalSeparator = decSep;
oldExtraCreditCalculation = oldCalculation;
prefetchStrings('core_grades', ['erroroverweight', 'errorunderweight']);
document.addEventListener('change', e => {
// Update the weights of all grade items in the category when the weight of any grade item in the category is changed.
@ -253,4 +262,21 @@ export const init = (decSep, oldCalculation) => {
}
}
});
document.addEventListener('submit', e => {
// If the form is being submitted, then we need to ensure that the weight input fields are all set to
// a valid value.
if (e.target.matches('#gradetreeform')) {
const firstInvalidWeightInput = e.target.querySelector('input.is-invalid');
if (firstInvalidWeightInput) {
const firstFocusableInvalidWeightInput = e.target.querySelector('input.is-invalid:enabled');
if (firstFocusableInvalidWeightInput) {
firstFocusableInvalidWeightInput.focus();
} else {
firstInvalidWeightInput.scrollIntoView({block: 'center'});
}
e.preventDefault();
}
}
});
};

View File

@ -39,4 +39,5 @@
</label>
<input type="text" name="weight_{{id}}" id="weight_{{id}}" value="{{value}}" size="4" {{#disabled}}disabled{{/disabled}} class="form-control">
<span style="margin-left:5px">%</span>
<div class="form-control-feedback invalid-feedback ml-3" id="id_error_weight_{{id}}"></div>
</div>

View File

@ -453,40 +453,40 @@ Feature: We can use calculated grade totals
And I should see "270.00 (24.77 %)" in the ".course" "css_element"
Scenario: Natural aggregation from the setup screen
And I navigate to "Setup > Gradebook setup" in the course gradebook
When I navigate to "Setup > Gradebook setup" in the course gradebook
And I set the following settings for grade item "Course 1" of type "course" on "setup" page:
| Aggregation | Natural |
And I set the following settings for grade item "Sub category 1" of type "category" on "setup" page:
| Aggregation | Natural |
And I set the following settings for grade item "Sub category 2 &" of type "category" on "setup" page:
| Aggregation | Natural |
And I set the field "Override weight of Test assignment one &" to "1"
And the field "Weight of Test assignment one &" matches value "37.975"
And I set the field "Weight of Test assignment one &" to "10"
And I set the field "Override weight of Test assignment two" to "1"
And the field "Weight of Test assignment two" matches value "12.658"
And the field "Weight of Sub category 1" matches value "5.696"
And the field "Weight of Sub category 2" matches value "5.696"
And I set the field "Override weight of Test assignment one &" to "1"
And I set the field "Weight of Test assignment one &" to "10"
And the field "Weight of Test assignment two" matches value "18.367"
And the field "Weight of Sub category 1" matches value "8.265"
And the field "Weight of Sub category 2" matches value "8.265"
And I set the field "Override weight of Test assignment two" to "1"
And I set the field "Override weight of Test assignment two" to "0"
And I set the field "Override weight of Test assignment six" to "1"
And the field "Weight of Test assignment six" matches value "22.222"
And I set the field "Override weight of Test assignment six" to "1"
And I set the field "Weight of Test assignment six" to "50"
And I set the field "Override weight of Test assignment six" to "0"
And I set the field "Override weight of Test assignment ten" to "1"
And the field "Weight of Test assignment six" matches value "22.222"
And the field "Weight of Test assignment ten" matches value "33.333"
And I set the field "Override weight of Test assignment ten" to "1"
And I set the field "Weight of Test assignment ten" to "50"
And I set the field "Override weight of Sub category 1" to "1"
And the field "Weight of Sub category 1" matches value "5.696"
And I set the field "Weight of Sub category 1" to "15"
When I press "Save changes"
And I set the field "Override weight of Test assignment two" to "1"
And I set the field "Override weight of Test assignment six" to "1"
Then the field "Weight of Test assignment one &" matches value "10.0"
And the field "Weight of Test assignment two" matches value "16.854"
And the field "Weight of Test assignment six" matches value "22.222"
And the field "Weight of Test assignment ten" matches value "50.0"
And the field "Weight of Sub category 1" matches value "15.0"
And I press "Save changes"
Then the field "Weight of Test assignment one &" matches value "10.0"
And the field "Weight of Test assignment two" matches value "16.854"
And the field "Weight of Test assignment six" matches value "22.222"
@ -496,9 +496,9 @@ Feature: We can use calculated grade totals
And I set the field "Override weight of Test assignment two" to "0"
And I set the field "Override weight of Test assignment six" to "0"
And I set the field "Override weight of Sub category 1" to "0"
And the field "Weight of Test assignment one &" matches value "37.975"
And the field "Weight of Sub category 1" matches value "5.696"
And I press "Save changes"
And I set the field "Override weight of Test assignment one &" to "1"
And I set the field "Override weight of Sub category 1" to "1"
And the field "Weight of Test assignment one &" matches value "37.975"
And the field "Weight of Sub category 1" matches value "5.696"
And I reset weights for grade category "Sub category 2 &"

View File

@ -34,7 +34,6 @@ Feature: We can use natural aggregation and weights will be normalised to a tota
@javascript
Scenario: Setting all weights in a category to exactly one hundred in total.
And the field "Weight of Test assignment five" matches value "44.444"
And the field "Weight of Test assignment six" matches value "22.222"
And the field "Weight of Test assignment seven" matches value "33.333"
@ -45,57 +44,55 @@ Feature: We can use natural aggregation and weights will be normalised to a tota
And I set the field "Weight of Test assignment six" to "50"
And I set the field "Weight of Test assignment seven" to "20"
And I press "Save changes"
Then I should not see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "30.0"
And the field "Weight of Test assignment six" matches value "50.0"
And the field "Weight of Test assignment seven" matches value "20.0"
@javascript
Scenario: Setting all weights in a category to less than one hundred is normalised.
Scenario: Setting all weights in a category to less than one hundred is prevented.
When I set the field "Override weight of Test assignment five" to "1"
And I set the field "Override weight of Test assignment six" to "1"
And I set the field "Override weight of Test assignment seven" to "1"
And I set the field "Weight of Test assignment five" to "1"
And I set the field "Weight of Test assignment six" to "1"
And I set the field "Weight of Test assignment seven" to "2"
Then I should see "Weight total is less than 100%." in the "Test assignment five" "table_row"
And I should see "Weight total is less than 100%." in the "Test assignment six" "table_row"
And I should see "Weight total is less than 100%." in the "Test assignment seven" "table_row"
And I start watching to see if a new page loads
And I press "Save changes"
Then I should see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "25.0"
And the field "Weight of Test assignment six" matches value "25.0"
And the field "Weight of Test assignment seven" matches value "50.0"
And a new page should not have loaded since I started watching
@javascript
Scenario: Set one of the grade item weights to a figure over one hundred.
Scenario: Set one of the grade item weights to a figure over one hundred is prevented.
When I set the field "Override weight of Test assignment five" to "1"
And I set the field "Weight of Test assignment five" to "120"
And I press "Save changes"
Then I should see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "100.0"
Then I should see "Weight total exceeds 100%." in the "Test assignment five" "table_row"
And the field "Weight of Test assignment five" matches value "120.0"
And the field "Weight of Test assignment six" matches value "0.0"
And the field "Weight of Test assignment seven" matches value "0.0"
And I start watching to see if a new page loads
And I press "Save changes"
And a new page should not have loaded since I started watching
@javascript
Scenario: Setting several but not all grade item weights to over one hundred each.
Scenario: Setting several but not all grade item weights to over one hundred each is prevented.
When I set the field "Override weight of Test assignment five" to "1"
And I set the field "Override weight of Test assignment six" to "1"
And I set the field "Weight of Test assignment five" to "150"
And I set the field "Weight of Test assignment six" to "150"
And I press "Save changes"
Then I should see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "50.000"
And the field "Weight of Test assignment six" matches value "50.000"
Then I should see "Weight total exceeds 100%." in the "Test assignment five" "table_row"
And I should see "Weight total exceeds 100%." in the "Test assignment six" "table_row"
And the field "Weight of Test assignment five" matches value "150.0"
And the field "Weight of Test assignment six" matches value "150.0"
And the field "Weight of Test assignment seven" matches value "0.0"
And I start watching to see if a new page loads
And I press "Save changes"
And a new page should not have loaded since I started watching
@javascript
Scenario: Grade items weights are not normalised when all grade item weights are overridden (sum exactly 100). Extra credit is set respectful to number of items.
When I set the following settings for grade item "Test assignment seven" of type "gradeitem" on "setup" page:
| Extra credit | 1 |
And the field "Weight of Test assignment five" matches value "66.667"
@ -106,7 +103,6 @@ Feature: We can use natural aggregation and weights will be normalised to a tota
And I set the field "Weight of Test assignment five" to "60"
And I set the field "Weight of Test assignment six" to "40"
And I press "Save changes"
Then I should not see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "60.000"
And the field "Weight of Test assignment six" matches value "40.000"
@ -117,40 +113,42 @@ Feature: We can use natural aggregation and weights will be normalised to a tota
And the field "Weight of Test assignment seven" matches value "50.0"
@javascript
Scenario: Grade items weights are normalised when all grade item weights are overridden (sum over 100). Extra credit is set respectful to number of items.
Scenario: Setting grade items weights is prevented when all grade item weights are overridden (sum over 100). Extra credit is set respectful to number of items.
When I set the following settings for grade item "Test assignment seven" of type "gradeitem" on "setup" page:
| Extra credit | 1 |
And I set the field "Override weight of Test assignment five" to "1"
And I set the field "Override weight of Test assignment six" to "1"
And I set the field "Weight of Test assignment five" to "60"
And I set the field "Weight of Test assignment six" to "50"
And I press "Save changes"
Then I should see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "54.545"
And the field "Weight of Test assignment six" matches value "45.455"
Then I should see "Weight total exceeds 100%." in the "Test assignment five" "table_row"
And I should see "Weight total exceeds 100%." in the "Test assignment six" "table_row"
And the field "Weight of Test assignment five" matches value "60.0"
And the field "Weight of Test assignment six" matches value "50.0"
And the field "Weight of Test assignment seven" matches value "50.0"
And I start watching to see if a new page loads
And I press "Save changes"
And a new page should not have loaded since I started watching
And I reset weights for grade category "Sub category 1"
And the field "Weight of Test assignment five" matches value "66.667"
And the field "Weight of Test assignment six" matches value "33.333"
And the field "Weight of Test assignment seven" matches value "50.0"
@javascript
Scenario: Grade items weights are normalised when all grade item weights are overridden (sum under 100). Extra credit is set respectful to number of items.
Scenario: Setting grade items weights is prevented when all grade item weights are overridden (sum under 100). Extra credit is set respectful to number of items.
When I set the following settings for grade item "Test assignment seven" of type "gradeitem" on "setup" page:
| Extra credit | 1 |
And I set the field "Override weight of Test assignment five" to "1"
And I set the field "Override weight of Test assignment six" to "1"
And I set the field "Weight of Test assignment five" to "40"
And I set the field "Weight of Test assignment six" to "30"
And I press "Save changes"
Then I should see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "57.143"
And the field "Weight of Test assignment six" matches value "42.857"
Then I should see "Weight total is less than 100%." in the "Test assignment five" "table_row"
And I should see "Weight total is less than 100%." in the "Test assignment six" "table_row"
And the field "Weight of Test assignment five" matches value "40.0"
And the field "Weight of Test assignment six" matches value "30.0"
And the field "Weight of Test assignment seven" matches value "50.0"
And I start watching to see if a new page loads
And I press "Save changes"
And a new page should not have loaded since I started watching
And I reset weights for grade category "Sub category 1"
And the field "Weight of Test assignment five" matches value "66.667"
And the field "Weight of Test assignment six" matches value "33.333"
@ -158,13 +156,11 @@ Feature: We can use natural aggregation and weights will be normalised to a tota
@javascript
Scenario: Grade items weights are normalised when not all grade item weights are overridden. Extra credit is set respectful to number of items.
When I set the following settings for grade item "Test assignment seven" of type "gradeitem" on "setup" page:
| Extra credit | 1 |
And I set the field "Override weight of Test assignment five" to "1"
And I set the field "Weight of Test assignment five" to "40"
And I press "Save changes"
Then I should see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "40.00"
And the field "Weight of Test assignment six" matches value "60.000"
@ -175,9 +171,7 @@ Feature: We can use natural aggregation and weights will be normalised to a tota
And the field "Weight of Test assignment seven" matches value "50.0"
@javascript
Scenario: The extra credit grade item weight is overridden to a figure over one hundred and then
the grade item is set to normal.
Scenario: The extra credit grade item weight is overridden to a figure over one hundred and then the grade item is set to normal.
When I set the following settings for grade item "Test assignment seven" of type "gradeitem" on "setup" page:
| Extra credit | 1 |
And I set the field "Override weight of Test assignment seven" to "1"
@ -190,40 +184,37 @@ Feature: We can use natural aggregation and weights will be normalised to a tota
When I set the following settings for grade item "Test assignment seven" of type "gradeitem" on "setup" page:
| Extra credit | 0 |
And I should see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "0.0"
And the field "Weight of Test assignment six" matches value "0.0"
And the field "Weight of Test assignment seven" matches value "100.0"
@javascript
Scenario: The extra credit grade item weight is overridden to a figure over one hundred and then
the grade category is reset.
Scenario: The extra credit grade item weight is overridden to a figure over one hundred and then the grade category is reset.
When I set the following settings for grade item "Test assignment seven" of type "gradeitem" on "setup" page:
| Extra credit | 1 |
And I set the field "Override weight of Test assignment seven" to "1"
And I set the field "Weight of Test assignment seven" to "105"
And I press "Save changes"
And I reset weights for grade category "Sub category 1"
And the field "Weight of Test assignment five" matches value "66.667"
And the field "Weight of Test assignment six" matches value "33.333"
And the field "Weight of Test assignment seven" matches value "50.0"
@javascript
Scenario: Two out of three grade items weights are overridden and one is not.
The overridden grade item weights total over one hundred.
Scenario: Two out of three grade items weights are overridden and one is not. The overridden grade item weights total over one hundred.
Given I set the field "Override weight of Test assignment six" to "1"
And I set the field "Override weight of Test assignment seven" to "1"
And I set the field "Weight of Test assignment six" to "55"
And I set the field "Weight of Test assignment seven" to "65"
Then I should not see "Weight total exceeds 100%." in the "Test assignment five" "table_row"
And I should see "Weight total exceeds 100%." in the "Test assignment six" "table_row"
And I should see "Weight total exceeds 100%." in the "Test assignment seven" "table_row"
And the field "Weight of Test assignment five" matches value "0.0"
And the field "Weight of Test assignment six" matches value "55.0"
And the field "Weight of Test assignment seven" matches value "65.0"
And I start watching to see if a new page loads
And I press "Save changes"
And I should see "Your weights have been adjusted to total 100."
Then the field "Weight of Test assignment five" matches value "0.0"
And the field "Weight of Test assignment six" matches value "45.833"
And the field "Weight of Test assignment seven" matches value "54.167"
And a new page should not have loaded since I started watching
@javascript
Scenario: With one grade item set as extra credit, when I reset the weights for a category they return to the natural weights.
@ -249,7 +240,6 @@ Feature: We can use natural aggregation and weights will be normalised to a tota
And the field "Weight of Test assignment seven" matches value "60.0"
And I set the field "Override weight of Test assignment six" to "1"
And I set the field "Weight of Test assignment six" to "-25"
And I press "Save changes"
And the field "Weight of Test assignment six" matches value "0.0"
And the field "Weight of Test assignment seven" matches value "100.0"
And I reset weights for grade category "Sub category 1"
@ -257,7 +247,11 @@ Feature: We can use natural aggregation and weights will be normalised to a tota
And I set the field "Override weight of Test assignment six" to "1"
And I set the field "Weight of Test assignment five" to "-10"
And I set the field "Weight of Test assignment six" to "120"
And I press "Save changes"
And I should see "Weight total exceeds 100%." in the "Test assignment five" "table_row"
And I should see "Weight total exceeds 100%." in the "Test assignment six" "table_row"
And the field "Weight of Test assignment five" matches value "0.0"
And the field "Weight of Test assignment six" matches value "100.0"
And the field "Weight of Test assignment six" matches value "120.0"
And the field "Weight of Test assignment seven" matches value "0.0"
And I start watching to see if a new page loads
And I press "Save changes"
And a new page should not have loaded since I started watching

View File

@ -57,43 +57,47 @@ Feature: Gradebook calculations for natural weights normalisation before the fix
And the field "Weight of Test assignment seven" matches value "50.0"
@javascript
Scenario: Grade items weights are normalised when all grade item weights are overridden (sum over 100). Extra credit is set to zero (before the fix 20150619).
Scenario: Setting grade items weights is prevented when all grade item weights are overridden (sum over 100). Extra credit is set to zero (before the fix 20150619).
When I set the following settings for grade item "Test assignment seven" of type "gradeitem" on "setup" page:
| Extra credit | 1 |
And I set the field "Override weight of Test assignment five" to "1"
And I set the field "Override weight of Test assignment six" to "1"
And I set the field "Weight of Test assignment five" to "60"
And I set the field "Weight of Test assignment six" to "50"
And I press "Save changes"
Then I should see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "54.545"
And the field "Weight of Test assignment six" matches value "45.455"
Then I should see "Weight total exceeds 100%." in the "Test assignment five" "table_row"
And I should see "Weight total exceeds 100%." in the "Test assignment six" "table_row"
And the field "Weight of Test assignment five" matches value "60.0"
And the field "Weight of Test assignment six" matches value "50.0"
And the field "Weight of Test assignment seven" matches value "0.0"
# The weight of "seven" should be 15/30=50% (15 is the maxgrade for "seven" and 30 are max grades for this category (max grade of "five" plus max grade of "six")
And I start watching to see if a new page loads
And I press "Save changes"
And a new page should not have loaded since I started watching
And I reset weights for grade category "Sub category 1"
And the field "Weight of Test assignment five" matches value "66.667"
And the field "Weight of Test assignment six" matches value "33.333"
# The weight of "seven" should be 15/30=50% (15 is the maxgrade for "seven" and 30 are max grades for this category (max grade of "five" plus max grade of "six")
And the field "Weight of Test assignment seven" matches value "50.0"
@javascript
Scenario: Grade items weights are normalised when all grade item weights are overridden (sum under 100). Extra credit is set to zero (before the fix 20150619).
Scenario: Setting grade items weights is prevented when all grade item weights are overridden (sum under 100). Extra credit is set to zero (before the fix 20150619).
When I set the following settings for grade item "Test assignment seven" of type "gradeitem" on "setup" page:
| Extra credit | 1 |
And I set the field "Override weight of Test assignment five" to "1"
And I set the field "Override weight of Test assignment six" to "1"
And I set the field "Weight of Test assignment five" to "40"
And I set the field "Weight of Test assignment six" to "30"
And I press "Save changes"
Then I should see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "57.143"
And the field "Weight of Test assignment six" matches value "42.857"
Then I should see "Weight total is less than 100%." in the "Test assignment five" "table_row"
And I should see "Weight total is less than 100%." in the "Test assignment six" "table_row"
And the field "Weight of Test assignment five" matches value "40.0"
And the field "Weight of Test assignment six" matches value "30.0"
And the field "Weight of Test assignment seven" matches value "0.0"
# The weight of "seven" should be 15/30=50% (15 is the maxgrade for "seven" and 30 are max grades for this category (max grade of "five" plus max grade of "six")
And I start watching to see if a new page loads
And I press "Save changes"
And a new page should not have loaded since I started watching
And I reset weights for grade category "Sub category 1"
And the field "Weight of Test assignment five" matches value "66.667"
And the field "Weight of Test assignment six" matches value "33.333"
# The weight of "seven" should be 15/30=50% (15 is the maxgrade for "seven" and 30 are max grades for this category (max grade of "five" plus max grade of "six")
And the field "Weight of Test assignment seven" matches value "50.0"
@javascript
@ -103,7 +107,6 @@ Feature: Gradebook calculations for natural weights normalisation before the fix
And I set the field "Override weight of Test assignment five" to "1"
And I set the field "Weight of Test assignment five" to "40"
And I press "Save changes"
Then I should see "Your weights have been adjusted to total 100."
And the field "Weight of Test assignment five" matches value "40.00"
And the field "Weight of Test assignment six" matches value "60.000"

View File

@ -187,9 +187,11 @@ $string['errorgradevaluenonnumeric'] = 'Received non-numeric for low or high gra
$string['errornocalculationallowed'] = 'Calculations are not allowed for this item';
$string['errornocategorisedid'] = 'Could not get an uncategorised id!';
$string['errornocourse'] = 'Could not get course information';
$string['erroroverweight'] = 'Weight total exceeds 100%.';
$string['errorreprintheadersnonnumeric'] = 'Received non-numeric value for reprint-headers';
$string['errorsavegrade'] = 'Could not save grade, sorry.';
$string['errorsettinggrade'] = 'Error saving "{$a->itemname}" grade for userid {$a->userid}';
$string['errorunderweight'] = 'Weight total is less than 100%.';
$string['errorupdatinggradecategoryaggregateonlygraded'] = 'Error updating the "Aggregate only non-empty grades" setting of grade category ID {$a->id}';
$string['errorupdatinggradecategoryaggregateoutcomes'] = 'Error updating the "Include outcomes in aggregation" setting of grade category ID {$a->id}';
$string['errorupdatinggradecategoryaggregation'] = 'Error updating the aggregation type of grade category ID {$a->id}';