diff --git a/.vdiff.json b/.vdiff.json index 5c085fcd..0587e7ab 100644 --- a/.vdiff.json +++ b/.vdiff.json @@ -2,7 +2,7 @@ "browsers": [ { "name": "Chromium", - "version": 133 + "version": 134 } ], "system": { diff --git a/demo/components/grade-result/index.html b/demo/components/grade-result/index.html new file mode 100644 index 00000000..72c724e1 --- /dev/null +++ b/demo/components/grade-result/index.html @@ -0,0 +1,534 @@ + + + + + + d2l-grade-result + + + + + + + + + + +
+

Write Permissions Enabled

+ +
number grade, no icons
+ + + + +
number grade with decimal, no icons
+ + + + +
number grade, icons
+ + + + +
number grade, icons, tooltips
+ + + + +
letter grade, no icons
+ + + + +
letter grade, icons
+ + + + +
letter grade, icons, tooltips
+ + + +
+ + + +
+

Write Permissions Disabled

+ +
number grade, no icons
+ + + + +
number grade with decimals, no icons
+ + + + +
number grade, icons
+ + + + +
number grade, icons, tooltips
+ + + + +
letter grade, no icons
+ + + + +
letter grade, icons
+ + + + +
letter grade, icons, tooltips
+ + + +
+ + + +
+

Autograde Provided with Write Permissions

+ +
number grade, no icons, clear manual override option
+ + + + +
number grade, icons, clear manual override option
+ + + + +
number grade, icons, tooltips, clear manual override option
+ + + + + +
letter grade, no icons, clear manual override option
+ + + + +
letter grade, icons, clear manual override option
+ + + + +
letter grade, icons, tooltips, clear manual override option
+ + + + +
+ +
+ +
Custom manual override clear text
+ + + + +
+ +
+ +
Show grade calculation method
+ + + + + +
+ +
+ +
Dynamic Width
+ + + + +
+ +
+

Negative Marking

+ +
Negative marking enabled (for question scores)
+ + + + +
Floored negative score hint (for attempt scores)
+ + + + +
Floored negative score hint, icons (for attempt scores on quizzes with grade items)
+ + + + +
Floored negative score hint, read-only
+ + + + +
Floored negative score hint, read-only, icons
+ + + +
+ +
+

validation errors

+ +
Required validation error
+ + + + +
Number range validation error
+ + + + +
+ +
+ +

Student Grade Preview

+ +
None
+ + + + +
No Display
+ + + + +
Select Box Symbol
+ + + + +
Percentage Symbol
+ + + + +
Score and Symbol Only
+ + + + +
Score and Colour Only
+ + + + +
Symbol and Colour Only
+ + + + +
Score Only
+ + + + +
Symbol Only
+ + + + +
Colour Only
+ + + + +
Null Values
+ + + + +
Hide Label
+ + + + +
+ +
+ + diff --git a/package-lock.json b/package-lock.json index 003765cb..fe67a51f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -297,9 +297,9 @@ } }, "node_modules/@brightspace-ui/core": { - "version": "3.91.0", - "resolved": "https://registry.npmjs.org/@brightspace-ui/core/-/core-3.91.0.tgz", - "integrity": "sha512-DHSfgdzdzRPnBflG8xydeDTremXP+c8BnhxFdelDiuOFiL4zIfh61EvHEDi1AQGVBFJIx3axuTCISCvoNvmt4g==", + "version": "3.92.0", + "resolved": "https://registry.npmjs.org/@brightspace-ui/core/-/core-3.92.0.tgz", + "integrity": "sha512-A+EXVMYmKdTMOgTJ7eXMOGFefG68lBWNkkw6d0u5ceK6Y6KUijkw2ZLX6u1Pxb77FF5R1SqXMRaNoWNDTDF6wQ==", "license": "Apache-2.0", "dependencies": { "@brightspace-ui/intl": "^3", diff --git a/src/components/grade-result/README.md b/src/components/grade-result/README.md new file mode 100644 index 00000000..f9ab1bb9 --- /dev/null +++ b/src/components/grade-result/README.md @@ -0,0 +1,85 @@ +# @d2l/labs-grade-result + +A web component used for rendering grades in Brightspace + +## Properties + +#### d2l-labs-d2l-grade-result + +| Property | Type | Default | Description | +| ----------------------------------| --------- | ------- | ------------------------------------------------------------ | +| `href` | `string` | `''` | The Hypermedia route to power the component. This component runs off of the /grade route or an activity. | +| `token` | `string` | `''` | For authentication | +| `disableAutoSave` | `boolean` | `false` | Prevent the component from automatically saving the grade to the API when the grade is changed. | +| `_hideTitle` | `boolean` | `false` | This property will hide the "Overall Grade" title above the component. | +| `customManualOverrideText` | `string` | `undefined` | This properly will substitute the stock text on the "Manual Override" button. | +| `customManualOverrideClearText` | `string` | `undefined` | This properly will substitute the stock text on the "Clear Manual Override" button. | + +##### Public Methods + +| Method | Description | +| ------------------------------ | ------------------------------------------------------------ | +| `saveGrade(): void` | This is the method used to manually save the grade to the server when `disableAutoSave = true`. This method will emit `@d2l-grade-result-grade-saved-success` or `@d2l-grade-result-grade-saved-error`. | +| `hasUnsavedChanges(): boolean` | Determines whether the grade has been changed by the user and has not been saved to the server yet. | + +If you are only interested in rendering the presentational layer of the component, you can simply use the `d2l-grade-result-presentational` component. + +#### d2l-labs-d2l-grade-result-presentational + +| Property | GradeType | Type | Default | Description | +| ----------------------------------| -------------- | --------------------------- | ----------- | ------------------------------------------------------------ | +| `gradeType` | All | `string ('Numeric' or 'LetterGrade')` | `'Numeric'` | Specifies the type of grade that the component is meant to render. | +| `labelText` | All | `string` | `''` | The text that appears above the component. | +| `scoreNumerator` | Numeric | `number` | `0` | The numerator of the numeric score that is given. | +| `scoreDenominator` | Numeric | `number` | `0` | The denominator of the numeric score that is given. | +| `selectedLetterGrade` | LetterGrade | `string` | `''` | The current selected letter grade of the options given. | +| `letterGradeOptions` | LetterGrade | `Object` | `null` | A dictionary where the key is a unique id and the value is an object containing the LetterGrade text and the PercentStart. | +| `includeGradeButton` | All | `boolean` | `false` | Determines whether the grades icon button is rendered. | +| `includeReportsButton` | All | `boolean` | `false` | Determines whether the reports icon button is rendered. | +| `gradeButtonTooltip` | All | `string` | `''` | The text that is inside of the tooltip when hovering over the grades button. | +| `reportsButtonTooltip` | All | `string` | `''` | The text that is inside of the tooltip when hovering over the reports button. | +| `readOnly` | All | `boolean` | `false` | Set to `true` if the user does not have permissions to edit the grade. | +| `isManualOverrideActive` | All | `boolean` | `false` | Set to `true` if the user is currently manually overriding the grade. This will display the button to 'Clear Manual Override'. | +| `hideTitle` | All | `boolean` | `false` | This property will hide the "Overall Grade" title above the component. | +| `customManualOverrideClearText` | All | `string` | `undefined` | This property will substitute the stock text on the "Clear Manual Override" button. | +| `subtitleText` | All | `string` | `undefined` | This property will show the given text under the title. | +| `required` | Numeric | `Boolean` | `false` | Set to `true` if an undefined/blank grade is not considered valid | +| `inputLabelText` | Numeric | `string` | `''` | This property sets the label that will be used inside the aria-label and validation error tool-tips | +| `allowNegativeScore` | Numeric | `boolean` | `'false'` | Set to `true` if negative scores can be entered | +| `showFlooredScoreWarning` | Numeric | `boolean` | `'false'` | Set to `true` if displaying a negative grade that has been floored at 0 | + +## Events + +#### d2l-labs-d2l-grade-result + +| Event | Description | +| ----------------------------------------------- | ------------------------------------------------------------ | +| `@d2l-grade-result-initialized-success` | This event is fired when the component is successfully initialized and a grade is loaded from the API. | +| `@d2l-grade-result-initialized-error` | This event is fired when there is an error initializing the component. This is usually caused by an invalid `href` or `token`. | +| `@d2l-grade-result-grade-updated-success` | This event is fired when the grade is successfully updated on the frontend. | +| `@d2l-grade-result-grade-updated-error` | This event is fired when there is an error updating the grade on the frontend. | +| `@d2l-grade-result-grade-saved-success` | This event is fired when the grade is successfully saved to the server. | +| `@d2l-grade-result-grade-saved-error` | This event is fired when there is an error while saving the grade to the server. | +| `@d2l-grade-result-grade-button-click` | This event is fired when the grades button is clicked. | +| `@d2l-grade-result-reports-button-click` | This event is fired when the reports button is clicked. | +| `@d2l-grade-result-manual-override-clear-click` | This event is fired when the manual override clear is clicked. | + +#### d2l-labs-d2l-grade-result-presentational + +| Event | Description | +| ----------------------------------------------- | ------------------------------------------------------------ | +| `@d2l-grade-result-grade-button-click` | This event is fired when the grades button is clicked. | +| `@d2l-grade-result-reports-button-click` | This event is fired when the reports button is clicked. | +| `@d2l-grade-result-grade-change` | This event is fired on the change of the grade for a `gradeType="Numeric"` grade. | +| `@d2l-grade-result-letter-score-selected` | This event is fired on the change of the grade for a `gradeType="LetterGrade"` grade. | +| `@d2l-grade-result-manual-override-clear-click` | This event is fired when the manual override clear is clicked. | + + +## Usage + +```html + +My element +``` \ No newline at end of file diff --git a/src/components/grade-result/grade-result-icon-button.js b/src/components/grade-result/grade-result-icon-button.js new file mode 100644 index 00000000..b7cbcb87 --- /dev/null +++ b/src/components/grade-result/grade-result-icon-button.js @@ -0,0 +1,38 @@ +import '@brightspace-ui/core/components/button/button-icon.js'; +import { html, LitElement } from 'lit'; +import { getUniqueId } from '@brightspace-ui/core/helpers/uniqueId.js'; + +export class D2LGradeResultIconButton extends LitElement { + static get properties() { + return { + text: { type: String }, + icon: { type: String }, + _id: { type: String }, + }; + } + + constructor() { + super(); + this._id = getUniqueId(); + } + + render() { + return html` + + `; + } + + _onClick() { + this.dispatchEvent(new CustomEvent('d2l-grade-result-icon-button-click', { + bubbles: true, + composed: true, + })); + } + +} +customElements.define('d2l-grade-result-icon-button', D2LGradeResultIconButton); diff --git a/src/components/grade-result/grade-result-letter-score.js b/src/components/grade-result/grade-result-letter-score.js new file mode 100644 index 00000000..019cea1e --- /dev/null +++ b/src/components/grade-result/grade-result-letter-score.js @@ -0,0 +1,91 @@ +import { css, html, LitElement } from 'lit'; +import { bodyStandardStyles } from '@brightspace-ui/core/components/typography/styles.js'; +import { LocalizeLabsElement } from '../localize-labs-element.js'; +import { selectStyles } from '@brightspace-ui/core/components/inputs/input-select-styles.js'; + +export class D2LGradeResultLetterScore extends LocalizeLabsElement(LitElement) { + + static get properties() { + return { + availableOptions: { type: Object }, + label: { type: String }, + selectedOption: { type: String }, + readOnly: { type: Boolean } + }; + } + + static get styles() { + return [selectStyles, bodyStandardStyles, css` + .d2l-grade-result-letter-score-container { + width: 8rem; + } + .d2l-grade-result-letter-score-select { + width: 100%; + } + .d2l-grade-result-letter-score-score-read-only { + height: calc(2rem + 2px); + line-height: calc(2rem + 2px); + } + `]; + } + + constructor() { + super(); + this.availableOptions = null; + this.selectedOption = ''; + } + + render() { + if (!this.readOnly) { + return html` +
+ +
+ `; + } else { + return html` +
+ ${this._selectedOptionText()} +
+ `; + } + } + + _onOptionSelected(e) { + this.dispatchEvent(new CustomEvent('d2l-grade-result-letter-score-selected', { + composed: true, + bubbles: true, + detail: { + value: e.target.value + } + })); + } + + _renderOptions() { + const itemTemplate = []; + for (const [id, option] of Object.entries(this.availableOptions)) { + if (this.selectedOption === id) { + itemTemplate.push(html``); + } else { + itemTemplate.push(html``); + } + } + return itemTemplate; + } + + _selectedOptionText() { + if (this.availableOptions[this.selectedOption]) { + return this.availableOptions[this.selectedOption].LetterGrade; + } + } + +} + +customElements.define('d2l-grade-result-letter-score', D2LGradeResultLetterScore); diff --git a/src/components/grade-result/grade-result-numeric-score.js b/src/components/grade-result/grade-result-numeric-score.js new file mode 100644 index 00000000..5b67b8d0 --- /dev/null +++ b/src/components/grade-result/grade-result-numeric-score.js @@ -0,0 +1,108 @@ +import '@brightspace-ui/core/components/inputs/input-number.js'; +import '@brightspace-ui/core/components/offscreen/offscreen.js'; +import { bodyCompactStyles, bodyStandardStyles } from '@brightspace-ui/core/components/typography/styles.js'; +import { css, html, LitElement, nothing } from 'lit'; +import { LocalizeLabsElement } from '../localize-labs-element.js'; + +const numberConverter = { + fromAttribute: (attr) => { return !attr ? undefined : Number(attr); }, + toAttribute: (prop) => { return String(prop); } +}; + +const EXTRA_SPACE = 2.5; +const MIN_WIDTH = 5.5; +const MIN_NEGATIVE_GRADE = -9999999999; +const MIN_POSITIVE_GRADE = 0; + +export class D2LGradeResultNumericScore extends LocalizeLabsElement(LitElement) { + static get properties() { + return { + label: { type: String }, + scoreNumerator: { type: Number, converter: numberConverter }, + scoreDenominator: { type: Number }, + readOnly: { type: Boolean }, + required: { type: Boolean }, + allowNegativeScore: { type: Boolean }, + showFlooredScoreWarning: { type: Boolean }, + }; + } + + static get styles() { + return [bodyCompactStyles, bodyStandardStyles, css` + .d2l-grade-result-numeric-score-container { + align-items: center; + display: flex; + flex-direction: row; + } + .d2l-grade-result-numeric-score-score-read-only { + height: calc(2rem + 2px); + line-height: calc(2rem + 2px); + max-width: 5.25rem; + } + .d2l-grade-result-numeric-score-hint { + margin: 0 0.3rem; + } + `]; + } + + render() { + const roundedNumerator = isNaN(this.scoreNumerator) ? '' : Math.round((this.scoreNumerator + Number.EPSILON) * 100) / 100; + + const denominatorLength = isNaN(this.scoreDenominator) ? 0 : this.scoreDenominator.toString().length; + const numeratorLength = roundedNumerator.toString().length; + const dynamicWidth = numeratorLength <= denominatorLength ? denominatorLength + EXTRA_SPACE : (numeratorLength * 0.5) + (denominatorLength * 0.5) + EXTRA_SPACE; + + return html` +
+ ${!this.readOnly ? html` +
+ + + +
+ ` : html` + + ${this.localize('components:gradeResult:numeratorOutOfDenominator', { numerator: roundedNumerator, denominator: this.scoreDenominator })} + `} + ${this.showFlooredScoreWarning ? html` +
+ ${this.localize('components:gradeResult:cannotBeNegative')} +
+ ` : nothing} +
+ `; + } + + _onGradeChange(e) { + const newScore = e.target.value; + this.dispatchEvent(new CustomEvent('d2l-grade-result-grade-change', { + bubbles: true, + composed: true, + detail: { + value: newScore + } + })); + } + +} + +customElements.define('d2l-grade-result-numeric-score', D2LGradeResultNumericScore); diff --git a/src/components/grade-result/grade-result-presentational.js b/src/components/grade-result/grade-result-presentational.js new file mode 100644 index 00000000..876a972e --- /dev/null +++ b/src/components/grade-result/grade-result-presentational.js @@ -0,0 +1,253 @@ +import './grade-result-icon-button.js'; +import './grade-result-numeric-score.js'; +import './grade-result-letter-score.js'; +import './grade-result-student-grade-preview.js'; +import '@brightspace-ui/core/components/button/button-subtle.js'; +import { bodySmallStyles, labelStyles } from '@brightspace-ui/core/components/typography/styles.js'; +import { css, html, LitElement, nothing } from 'lit'; +import { GradeType } from '../../controllers/grade-result/Grade.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { LocalizeLabsElement } from '../localize-labs-element.js'; + +const numberConverter = { + fromAttribute: (attr) => { return !attr ? undefined : Number(attr); }, + toAttribute: (prop) => { return String(prop); } +}; + +export class D2LGradeResultPresentational extends LocalizeLabsElement(LitElement) { + static get properties() { + return { + allowNegativeScore: { type: Boolean }, + customManualOverrideClearText: { type: String }, + displayStudentGradePreview: { type: Boolean, attribute: 'display-student-grade-preview' }, + gradeButtonTooltip: { type: String }, + gradeType: { type: String }, + hideTitle: { type: Boolean }, + includeGradeButton: { type: Boolean }, + includeReportsButton: { type: Boolean }, + inputLabelText: { type: String }, + isManualOverrideActive: { type: Boolean }, + labelHeadingLevel: { type: Number }, + labelText: { type: String }, + letterGradeOptions: { type: Object }, + readOnly: { type: Boolean }, + reportsButtonTooltip: { type: String }, + required: { type: Boolean }, + scoreDenominator: { type: Number }, + scoreNumerator: { type: Number, converter: numberConverter }, + selectedLetterGrade: { type: String }, + showFlooredScoreWarning: { type: Boolean }, + subtitleText: { type: String }, + studentGradePreview: { type: Object, attribute: 'student-grade-preview' }, + }; + } + + static get styles() { + return [ bodySmallStyles, labelStyles, css` + .d2l-grade-result-presentational-container { + display: flex; + flex-wrap: wrap; + gap: 0 0.9rem; + } + .d2l-grade-result-presentational-score-container { + display: flex; + flex-wrap: wrap; + gap: 0.3rem; + } + .d2l-grade-result-manual-override-clear { + margin-top: 0.3rem; + } + .d2l-label-text { + line-height: 1.6rem; + margin-bottom: 0.4rem; + } + .d2l-grade-result-presentational-subtitle { + font-weight: bold; + margin-top: -4px; + } + `]; + } + + constructor() { + super(); + this.allowNegativeScore = false; + this.customManualOverrideClearText = undefined; + this.hideTitle = false; + this.includeGradeButton = false; + this.includeReportsButton = false; + this.isManualOverrideActive = false; + this.labelHeadingLevel = undefined; + this.readOnly = false; + this.selectedLetterGrade = ''; + this.showFlooredScoreWarning = false; + this.subtitleText = undefined; + } + + render() { + return html` +
+
+ ${this._renderScoreLabel()} + ${this._renderScoreSubtitle()} +
+ ${this._renderScoreComponent()} + ${this._renderGradeIconButton()} + ${this._renderGradeReportIconButton()} +
+
+ ${this._renderStudentGradePreview()} +
+ ${this._renderManualOverrideButtonComponent()} + `; + } + + _isReadOnly() { + return Boolean(this.readOnly); + } + + _onGradeButtonClick() { + this.dispatchEvent(new CustomEvent('d2l-grade-result-grade-button-click', { + bubbles: true, + composed: true, + })); + } + + _onManualOverrideClearClick() { + this.dispatchEvent(new CustomEvent('d2l-grade-result-manual-override-clear-click', { + bubbles: true, + composed: true + })); + } + + _onReportsButtonClick() { + this.dispatchEvent(new CustomEvent('d2l-grade-result-reports-button-click', { + bubbles: true, + composed: true, + })); + } + + _renderGradeIconButton() { + if (!this.includeGradeButton) { + return nothing; + } + + return html` + + `; + } + + _renderGradeReportIconButton() { + if (!this.includeReportsButton) { + return nothing; + } + + return html` + + `; + } + + _renderLetterScoreComponent() { + return html` + + `; + } + + _renderManualOverrideButtonComponent() { + if (!this.isManualOverrideActive) { + return nothing; + } + + const text = this.customManualOverrideClearText ? this.customManualOverrideClearText : this.localize('components:gradeResult:clearManualOverride'); + + return html` + + `; + } + + _renderNumericScoreComponent() { + return html` + + `; + } + + _renderScoreComponent() { + if (this.gradeType === GradeType.Number) { + return this._renderNumericScoreComponent(); + } else if (this.gradeType === GradeType.Letter) { + return this._renderLetterScoreComponent(); + } else { + throw new Error('INVALID GRADE TYPE PROVIDED'); + } + } + + _renderScoreLabel() { + if (this.hideTitle || !this.labelText) { + return nothing; + } + + return html` + + `; + } + + _renderScoreSubtitle() { + if (!this.subtitleText) { + return nothing; + } + + return html` +
+ ${this.subtitleText} +
+ `; + } + + _renderStudentGradePreview() { + if (!this.studentGradePreview) { + return nothing; + } + + return html` + + `; + } + +} + +customElements.define('d2l-labs-d2l-grade-result-presentational', D2LGradeResultPresentational); diff --git a/src/components/grade-result/grade-result-student-grade-preview.js b/src/components/grade-result/grade-result-student-grade-preview.js new file mode 100644 index 00000000..640c52c8 --- /dev/null +++ b/src/components/grade-result/grade-result-student-grade-preview.js @@ -0,0 +1,139 @@ +import '@brightspace-ui/core/components/offscreen/offscreen.js'; +import { bodyCompactStyles, bodySmallStyles, labelStyles } from '@brightspace-ui/core/components/typography/styles.js'; +import { css, html, LitElement, nothing } from 'lit'; +import { formatNumber } from '@brightspace-ui/intl/lib/number.js'; +import { LocalizeLabsElement } from '../localize-labs-element.js'; + +const previewOptions = { + colour: 'colour', + score: 'score', + symbol: 'symbol' +}; + +export class D2LGradeResultStudentGradePreview extends LocalizeLabsElement(LitElement) { + + static get properties() { + return { + hideLabel: { + type: Boolean, + attribute: 'hide-label' + }, + outOf: { + type: Number, + attribute: 'out-of' + }, + studentGradePreview: { + type: Object, + attribute: 'student-grade-preview' + } + }; + } + + static get styles() { + return [bodySmallStyles, bodyCompactStyles, labelStyles, css` + :host { + display: inline-block; + } + :host([hidden]) { + display: none; + } + .d2l-grade-result-student-grade-preview-container { + align-items: center; + display: flex; + flex-direction: row; + gap: 0.5rem; + min-height: calc(2rem + 2px); + } + .d2l-grade-result-student-grade-preview-colour { + border-radius: 6px; + height: 0.9rem; + width: 0.9rem; + } + .d2l-label-text { + line-height: 1.6rem; + margin-bottom: 0.4rem; + } + `]; + } + + constructor() { + super(); + this.hideLabel = false; + } + + render() { + if (!this.studentGradePreview) { + return nothing; + } + + let label = nothing; + if (!this.hideLabel) { + label = html` + + `; + } + + const shouldDisplayAny = Object.values(previewOptions).some(option => this._shouldDisplay(option)); + if (!shouldDisplayAny) { + return html` + ${label} +
+ ${this.localize('components:gradeResult:studentGradePreviewNotShown')} +
+ `; + } + + return html` + ${label} +
+ ${this._renderColour()} + ${this._renderScoreAndSymbol()} +
+ `; + } + + _renderColour() { + if (!this._shouldDisplay(previewOptions.colour) || !this.studentGradePreview.colour) { + return nothing; + } + + return html` +
+
+ `; + } + + _renderScoreAndSymbol() { + if (!this._shouldDisplay(previewOptions.score) && !this._shouldDisplay(previewOptions.symbol)) { + return nothing; + } + + const score = this._shouldDisplay(previewOptions.score) + ? `${this.studentGradePreview?.score && typeof this.studentGradePreview?.score === 'number' ? formatNumber(this.studentGradePreview?.score) : ''} / ${this.outOf && typeof this.outOf === 'number' ? formatNumber(this.outOf) : 0}` + : ''; + const accessibleScore = this._shouldDisplay(previewOptions.score) ? this.localize('components:gradeResult:numeratorOutOfDenominator', { numerator: this.studentGradePreview?.score, denominator: this.outOf }) : ''; + + const symbol = this._shouldDisplay(previewOptions.symbol) ? this.studentGradePreview?.symbol : ''; + + const separator = score && symbol ? ' - ' : ''; + + return html` + + + ${`${accessibleScore}${separator}${symbol}`} + + `; + } + + _shouldDisplay(property) { + return Object.prototype.hasOwnProperty.call(this.studentGradePreview, property); + } + +} + +customElements.define('d2l-grade-result-student-grade-preview', D2LGradeResultStudentGradePreview); diff --git a/src/controllers/grade-result/Grade.js b/src/controllers/grade-result/Grade.js new file mode 100644 index 00000000..9b43b93d --- /dev/null +++ b/src/controllers/grade-result/Grade.js @@ -0,0 +1,175 @@ + +export const GradeType = { + Letter: 'LetterGrade', + Number: 'Numeric' +}; + +export const GradeErrors = { + GET_LETTER_GRADE_FROM_NUMERIC_SCORE: 'Grade must be of type LetterGrade to get the letter grade', + GET_ASSIGNED_VALUE_FROM_NUMERIC_SCORE: 'Grade must be of type LetterGrade to get the assigned value', + INVALID_SCORE_TYPE: 'Invalid scoreType provided', + INVALID_SCORE: 'Invalid score provided', + INVALID_OUT_OF: 'Invalid outOf provided', + INVALID_LETTER_GRADE: 'Invalid letterGrade provided', + INVALID_LETTER_GRADE_ID: 'Invalid letterGradeId provided', + INVALID_LETTER_GRADE_OPTIONS: 'Invalid letterGradeOptions provided', + LETTER_GRADE_NOT_IN_OPTIONS: 'letterGrade must be one of the letterGradeOptions provided', + LETTER_GRADE_ID_NO_ASSIGNED_VALUE: 'LetterGradeId does not have a corresponding AssignedValue', +}; + +export class Grade { + + constructor(scoreType, score, outOf, letterGrade, letterGradeOptions, entity, calculatedScore = null, aggregatedScore = null, display = null) { + this.entity = entity; + this.isManuallyOverridden = false; + this.calculatedScore = calculatedScore; + this.aggregatedScore = aggregatedScore; + this.display = display; + this.outOf = outOf; + this.scoreType = this._parseScoreType(scoreType); + if (this.isNumberGrade()) { + this._parseNumberGrade(score); + } else { + const letterGradeId = this._getLetterGradeIdFromLetterGrade(letterGrade, letterGradeOptions); + this._parseLetterGrade(letterGradeId, letterGradeOptions); + } + } + + getDisplay() { + return this.display; + } + + getEntity() { + return this.entity; + } + + getLetterGrade() { + if (this.isNumberGrade()) { + throw new Error(GradeErrors.GET_LETTER_GRADE_FROM_NUMERIC_SCORE); + } + return this.letterGrade; + } + + getLetterGradeAssignedValue() { + if (this.isNumberGrade()) { + throw new Error(GradeErrors.GET_LETTER_GRADE_FROM_NUMERIC_SCORE); + } + + const letterGradeOption = this.letterGradeOptions[this.letterGradeId]; + + if (!letterGradeOption || (typeof letterGradeOption.AssignedValue !== 'number' && letterGradeOption.AssignedValue !== null)) { + throw new Error(GradeErrors.LETTER_GRADE_ID_NO_ASSIGNED_VALUE); + } + + return letterGradeOption.AssignedValue; + } + + getLetterGradeOptions() { + return this.letterGradeOptions; + } + + getOutOf() { + return this.outOf; + } + + getScore() { + return this.isNumberGrade() ? this.score : this.letterGradeId; + } + + getScoreType() { + return this.scoreType; + } + + isLetterGrade() { + return this.scoreType === GradeType.Letter; + } + + isNumberGrade() { + return this.scoreType === GradeType.Number; + } + + setScore(score) { + if (this.isNumberGrade()) { + this._parseNumberGrade(score, this.outOf); + } else { + this._parseLetterGrade(score, this.letterGradeOptions); + } + } + + _getLetterGradeIdFromLetterGrade(letterGrade, letterGradeOptions) { + if ((!letterGrade || typeof letterGrade !== 'string') && letterGrade !== null && letterGrade !== '') { + throw new Error(GradeErrors.INVALID_LETTER_GRADE); + } + if (!letterGradeOptions || typeof letterGradeOptions !== 'object' || Object.keys(letterGradeOptions).length === 0) { + throw new Error(GradeErrors.INVALID_LETTER_GRADE_OPTIONS); + } + + let letterGradeId; + + // this is the "None" case which has the id 0 + if (letterGrade === '' || letterGrade === null) { + letterGradeId = '0'; + } else { + letterGradeId = Object.keys(letterGradeOptions).find(key => + letterGradeOptions[key].LetterGrade === letterGrade + ); + } + + if (letterGradeId === undefined) { + throw new Error(GradeErrors.LETTER_GRADE_NOT_IN_OPTIONS); + } + + return letterGradeId; + } + + _parseLetterGrade(letterGradeId, letterGradeOptions) { + if (!letterGradeId && letterGradeId !== 0) { + throw new Error(GradeErrors.INVALID_LETTER_GRADE_ID); + } + + if (!letterGradeOptions || Object.keys(letterGradeOptions).length === 0) { + throw new Error(GradeErrors.INVALID_LETTER_GRADE_OPTIONS); + } + + this.score = null; + this.letterGradeId = letterGradeId; + this.letterGrade = letterGradeOptions[letterGradeId].LetterGrade; + this.letterGradeOptions = letterGradeOptions; + } + + _parseNumberGrade(score) { + if (score === undefined) { + score = ''; + } else if (isNaN(score)) { + throw new Error(GradeErrors.INVALID_SCORE); + } else if (typeof score === 'string') { + score = Number(score); + } + + if (this.calculatedScore !== null) { + this.isManuallyOverridden = score !== this.calculatedScore; + } + + this.score = score; + this.letterGradeId = null; + this.letterGrade = null; + this.letterGradeOptions = null; + } + + _parseScoreType(scoreType) { + const invalidScoreError = new Error(GradeErrors.INVALID_SCORE_TYPE); + + if (!scoreType || typeof scoreType !== 'string') { + throw invalidScoreError; + } + + if (scoreType.toLowerCase() === GradeType.Number.toLowerCase()) { + return GradeType.Number; + } else if (scoreType.toLowerCase() === GradeType.Letter.toLowerCase()) { + return GradeType.Letter; + } else { + throw invalidScoreError; + } + } + +} diff --git a/test/.eslintrc.json b/test/.eslintrc.json deleted file mode 100644 index 4a3c6eb6..00000000 --- a/test/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "brightspace/testing-config" -} \ No newline at end of file diff --git a/test/components/grade-result/d2l-grade-result-autograde-provided.vdiff.js b/test/components/grade-result/d2l-grade-result-autograde-provided.vdiff.js new file mode 100644 index 00000000..b5261883 --- /dev/null +++ b/test/components/grade-result/d2l-grade-result-autograde-provided.vdiff.js @@ -0,0 +1,117 @@ +import '../../../src/components/grade-result/grade-result-presentational.js'; +import { fixture, html } from '@brightspace-ui/testing'; +import { testDiff } from './vdiff-utils.js'; + +describe('autograde provided visual diff tests', () => { + + const tests = [ + { + name: 'autograde-provided-number-grade-no-icons-clear-manual-override-option', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20 + }, + { + name: 'autograde-provided-number-grade-icons-clear-manual-override-option', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20, + includeGradeButton: true, + includeReportsButton: true + }, + { + name: 'autograde-provided-number-grade-icons-tooltips-clear-manual-override-option-grades', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20, + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusGradesButton: true + }, + { + name: 'autograde-provided-number-grade-icons-tooltips-clear-manual-override-option-reports', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20, + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusReportsButton: true + }, + { + name: 'autograde-provided-letter-grade-no-icons-clear-manual-override-option', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + selectedLetterGrade: '2' + }, + { + name: 'autograde-provided-letter-grade-icons-clear-manual-override-option', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + selectedLetterGrade: '2', + includeGradeButton: true, + includeReportsButton: true + }, + { + name: 'autograde-provided-letter-grade-icons-tooltips-clear-manual-override-option-grades', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + selectedLetterGrade: '2', + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusGradesButton: true + }, + { + name: 'autograde-provided-letter-grade-icons-tooltips-clear-manual-override-option-reports', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + selectedLetterGrade: '2', + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusReportsButton: true + } + ]; + + tests.forEach((test) => { + it(`${test.name}`, async() => { + const fixtureElement = await fixture( + html` +
+ +
`, + { pagePadding: false } + ); + + await testDiff(fixtureElement, test.focusGradesButton, test.focusReportsButton); + }); + }); + +}); diff --git a/test/components/grade-result/d2l-grade-result-custom-manual-override-text.vdiff.js b/test/components/grade-result/d2l-grade-result-custom-manual-override-text.vdiff.js new file mode 100644 index 00000000..70b507c3 --- /dev/null +++ b/test/components/grade-result/d2l-grade-result-custom-manual-override-text.vdiff.js @@ -0,0 +1,27 @@ +import '../../../src/components/grade-result/grade-result-presentational.js'; +import { fixture, html } from '@brightspace-ui/testing'; +import { testDiff } from './vdiff-utils.js'; + +describe('optional override text substitution visual diff tests', () => { + + it('custom-manual-override-clear-text', async() => { + const fixtureElement = await fixture( + html` +
+ +
`, + { pagePadding: false } + ); + + await testDiff(fixtureElement); + }); + +}); diff --git a/test/components/grade-result/d2l-grade-result-presentational.test.js b/test/components/grade-result/d2l-grade-result-presentational.test.js new file mode 100644 index 00000000..c0015b08 --- /dev/null +++ b/test/components/grade-result/d2l-grade-result-presentational.test.js @@ -0,0 +1,140 @@ +import '../../../src/components/grade-result/grade-result-presentational.js'; +import { clickElem, fixture, html } from '@brightspace-ui/testing'; +import { getGradesButton, getLetterScore, getLetterScoreSelect, getManualOverrideButton, getNumericScore, getNumericScoreInput, getReportsButton } from './utils.js'; + +const letterGradeOptions = { + 0: { 'LetterGrade': 'None', 'PercentStart': null }, + 1: { 'LetterGrade': 'A', 'PercentStart': '80' }, + 2: { 'LetterGrade': 'B', 'PercentStart': '65' }, + 3: { 'LetterGrade': 'C', 'PercentStart': '50' }, +}; + +const componentManualOverride = html` + +`; + +const componentManualOverrideClear = html` + +`; + +const componentNumericScore = html` + +`; + +const componentLetterScore = html` + +`; + +const eventTimeoutMS = 10000; + +describe('d2l-grade-result-presentational', () => { + + it('click grade button event', async() => { + return new Promise((resolve, reject) => { + fixture(componentManualOverride).then(el => { + const event = 'd2l-grade-result-grade-button-click'; + el.addEventListener(event, resolve); + clickElem(getGradesButton(el)); + setTimeout(() => reject(`timeout waiting for ${event} event`), eventTimeoutMS); + }); + }); + }); + + it('click reports button event', async() => { + return new Promise((resolve, reject) => { + fixture(componentManualOverride).then(el => { + const event = 'd2l-grade-result-reports-button-click'; + el.addEventListener(event, resolve); + clickElem(getReportsButton(el)); + setTimeout(() => reject(`timeout waiting for ${event} event`), eventTimeoutMS); + }); + }); + }); + + it('click manual override clear button event', async() => { + return new Promise((resolve, reject) => { + fixture(componentManualOverrideClear).then(el => { + const event = 'd2l-grade-result-manual-override-clear-click'; + el.addEventListener(event, resolve); + clickElem(getManualOverrideButton(el)); + setTimeout(() => reject(`timeout waiting for ${event} event`), eventTimeoutMS); + }); + }); + }); + + // this test fails after adding localization to d2l-grade-result-numeric-score but the component still works + it.skip('number grade changed', async() => { + return new Promise((resolve, reject) => { + fixture(componentNumericScore).then(el => { + const event = 'd2l-grade-result-grade-change'; + const value = 10; + el.addEventListener(event, (e) => { + const input = getNumericScoreInput(e.target); + if (Number(input.value) === value) { + resolve(); + } else { + reject(`Expecting value to equal ${value}`); + } + }); + const score = getNumericScore(el); + const input = getNumericScoreInput(el); + input.setAttribute('value', value); + score._onGradeChange({ target: input }); + setTimeout(() => reject(`timeout waiting for ${event} event`), eventTimeoutMS); + }); + }); + }); + + it('letter score changed', async() => { + return new Promise((resolve, reject) => { + fixture(componentLetterScore).then(el => { + const event = 'd2l-grade-result-letter-score-selected'; + const value = '2'; + el.addEventListener(event, (e) => { + const score = getLetterScoreSelect(e.target); + if (score.value === value) { + resolve(); + } else { + reject(`Expecting value to equal ${value}`); + } + }); + const score = getLetterScore(el); + const select = getLetterScoreSelect(el); + select.value = value; + score._onOptionSelected({ target: select }); + setTimeout(() => reject(`timeout waiting for ${event} event`), eventTimeoutMS); + }); + }); + }); +}); diff --git a/test/components/grade-result/d2l-grade-result-read-only.vdiff.js b/test/components/grade-result/d2l-grade-result-read-only.vdiff.js new file mode 100644 index 00000000..0bac8bca --- /dev/null +++ b/test/components/grade-result/d2l-grade-result-read-only.vdiff.js @@ -0,0 +1,157 @@ +import '../../../src/components/grade-result/grade-result-presentational.js'; +import { fixture, html } from '@brightspace-ui/testing'; +import { testDiff } from './vdiff-utils.js'; + +describe('read only visual diff tests', () => { + + const tests = [ + { + name: 'read-only-number-grade-no-icons', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20 + }, + { + name: 'read-only-number-decimal-grade-no-icons', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 1.55555, + scoreDenominator: 20 + }, + { + name: 'read-only-negative-grade-no-icons', + gradeType: 'Numeric', + labelText: 'Attempt Grade', + scoreNumerator: 0, + scoreDenominator: 20, + showFlooredScoreWarning: true + }, + { + name: 'read-only-number-grade-icons', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20, + includeGradeButton: true, + includeReportsButton: true + }, + { + name: 'read-only-number-grade-icons-tooltips-grades', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20, + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusGradesButton: true + }, + { + name: 'read-only-number-grade-icons-tooltips-reports', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20, + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusReportsButton: true + }, + { + name: 'read-only-negative-grade-icons', + gradeType: 'Numeric', + labelText: 'Attempt Grade', + scoreNumerator: 5, + scoreDenominator: 20, + showFlooredScoreWarning: true, + includeGradeButton: true, + includeReportsButton: true + }, + { + name: 'read-only-number-grade-empty-numerator', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreDenominator: 20 + }, + { + name: 'read-only-letter-grade-no-icons', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + selectedLetterGrade: '2' + }, + { + name: 'read-only-letter-grade-icons', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + selectedLetterGrade: '2', + includeGradeButton: true, + includeReportsButton: true + }, + { + name: 'read-only-letter-grade-icons-tooltips-grades', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + selectedLetterGrade: '2', + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusGradesButton: true + }, + { + name: 'read-only-letter-grade-icons-tooltips-reports', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + selectedLetterGrade: '2', + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusReportsButton: true + }, + { + name: 'd2l-labs-d2l-grade-result-with-subtitle', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20, + subtitleText: 'Average grade post' + } + ]; + + tests.forEach((test) => { + it(`${test.name}`, async() => { + const fixtureElement = await fixture( + html` +
+ +
`, + { pagePadding: false } + ); + + await testDiff(fixtureElement, test.focusGradesButton, test.focusReportsButton); + }); + }); + +}); diff --git a/test/components/grade-result/d2l-grade-result-student-grade-preview.vdiff.js b/test/components/grade-result/d2l-grade-result-student-grade-preview.vdiff.js new file mode 100644 index 00000000..4e374c20 --- /dev/null +++ b/test/components/grade-result/d2l-grade-result-student-grade-preview.vdiff.js @@ -0,0 +1,268 @@ +import '../../../src/components/grade-result/grade-result-student-grade-preview.js'; +import '../../../src/components/grade-result/grade-result-presentational.js'; +import { expect, fixture, html } from '@brightspace-ui/testing'; + +describe('student-grade-preview', () => { + + const tests = [ + { + name: 'none', + outOf: 10 + }, + { + name: 'no-display-options', + outOf: 10, + displayStudentGradePreview: true, + studentGradePreview: '{}' + }, + { + name: 'select-box-symbol', + outOf: 10, + displayStudentGradePreview: true, + studentGradePreview: '{"score":10, "symbol":"Very Good", "colour":"#00FFFF"}' + }, + { + name: 'percentage-symbol', + outOf: 10, + displayStudentGradePreview: true, + studentGradePreview: '{"score":9, "symbol":"90 %", "colour":"#AAAAFF"}' + }, + { + name: 'score-and-symbol-only', + outOf: 10, + displayStudentGradePreview: true, + studentGradePreview: '{"score":2, "symbol":"Bad"}' + }, + { + name: 'score-and-colour-only', + outOf: 10, + displayStudentGradePreview: true, + studentGradePreview: '{"score":10, "colour":"#11FF11"}' + }, + { + name: 'symbol-and-colour-only', + outOf: 10, + displayStudentGradePreview: true, + studentGradePreview: '{"symbol":"11 %", "colour":"#666666"}' + }, + { + name: 'score-only', + outOf: 10, + displayStudentGradePreview: true, + studentGradePreview: '{"score":7}' + }, + { + name: 'symbol-only', + outOf: 10, + displayStudentGradePreview: true, + studentGradePreview: '{"symbol":"A+"}' + }, + { + name: 'colour-only', + outOf: 10, + displayStudentGradePreview: true, + studentGradePreview: '{"colour":"#FFAAAA"}' + }, + { + name: 'null-values', + outOf: 10, + displayStudentGradePreview: true, + studentGradePreview: '{"score":null, "symbol":"-%", "colour":""}' + }, + { + name: 'hide-label', + hideLabel: true, + outOf: 10, + displayStudentGradePreview: true, + studentGradePreview: '{"score":9, "symbol":"90 %", "colour":"#AAAAFF"}' + }, + { + name: 'hide-student-grade-preview', + hideLabel: false, + outOf: 10, + displayStudentGradePreview: false, + studentGradePreview: '{"score":9, "symbol":"90 %", "colour":"#AAAAFF"}' + }, + ]; + + tests.forEach((test) => { + it(`${test.name}`, async() => { + const el = await fixture( + html` + + ` + ); + + await expect(el).to.be.golden(); + }); + }); + +}); + +describe('presentational-with-grade-preview', () => { + + const tests = [ + { + name: 'write-numeric', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: '5', + scoreDenominator: '20', + includeGradeButton: true, + includeReportsButton: true, + readOnly: false, + displayStudentGradePreview: true, + studentGradePreview: '{"score":5, "symbol":"Fine", "colour":"#FFCC00"}' + }, + { + name: 'write-letter', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: '{ "0": { "LetterGrade": "None", "PercentStart": null}, "1": { "LetterGrade": "A", "PercentStart": "75"}, "2": { "LetterGrade": "B", "PercentStart": "50"}}', + selectedLetterGrade: '2', + scoreDenominator: '5', + includeGradeButton: true, + includeReportsButton: true, + readOnly: false, + displayStudentGradePreview: true, + studentGradePreview: '{"score":5, "symbol":"B", "colour":"#00FF00"}' + }, + { + name: 'readonly-numeric', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: '5', + scoreDenominator: '20', + includeGradeButton: true, + includeReportsButton: true, + readOnly: true, + displayStudentGradePreview: true, + studentGradePreview: '{"score":5, "symbol":"Fine", "colour":"#FFCC00"}' + }, + { + name: 'readonly-letter', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: '{ "0": { "LetterGrade": "None", "PercentStart": null}, "1": { "LetterGrade": "A", "PercentStart": "75"}, "2": { "LetterGrade": "B", "PercentStart": "50"}}', + selectedLetterGrade: '2', + scoreDenominator: '5', + includeGradeButton: true, + includeReportsButton: true, + readOnly: true, + displayStudentGradePreview: true, + studentGradePreview: '{"score":5, "symbol":"B", "colour":"#00FF00"}' + }, + { + name: 'readonly-letter-long-letter', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: '{ "0": { "LetterGrade": "None", "PercentStart": null}, "1": { "LetterGrade": "A", "PercentStart": "75"}, "2": { "LetterGrade": "This is a really really really really really long letter grade", "PercentStart": "50"}}', + selectedLetterGrade: '2', + scoreDenominator: '5', + includeGradeButton: true, + includeReportsButton: true, + readOnly: true, + displayStudentGradePreview: true, + studentGradePreview: '{"score":5, "symbol":"B", "colour":"#00FF00"}' + }, + { + name: 'manual-override', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: '5', + scoreDenominator: '20', + isGradeAutoCompleted: true, + isManualOverrideActive: true, + includeGradeButton: true, + includeReportsButton: true, + readOnly: false, + displayStudentGradePreview: true, + studentGradePreview: '{"score":5, "symbol":"Fine", "colour":"#FFCC00"}' + }, + { + name: 'grade-calculation', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: '5', + scoreDenominator: '20', + isGradeAutoCompleted: false, + isManualOverrideActive: false, + includeGradeButton: true, + includeReportsButton: true, + readOnly: true, + subtitleText: 'Average post score', + displayStudentGradePreview: true, + studentGradePreview: '{"score":5, "symbol":"Fine", "colour":"#FFCC00"}' + }, + { + name: 'negative-score-hint', + gradeType: 'Numeric', + labelText: 'Attempt Grade', + scoreNumerator: '0', + scoreDenominator: '20', + showFlooredScoreWarning: true, + isGradeAutoCompleted: false, + isManualOverrideActive: false, + includeGradeButton: true, + includeReportsButton: true, + readOnly: false, + displayStudentGradePreview: true, + studentGradePreview: '{"score":5, "symbol":"Fine", "colour":"#FFCC00"}' + }, + { + name: 'grade-not-shown-to-learners', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: '5', + scoreDenominator: '20', + includeGradeButton: true, + includeReportsButton: true, + readOnly: false, + displayStudentGradePreview: true, + studentGradePreview: '{}' + }, + ]; + + const screenSizeCategories = [ + { name: 'desktop', viewport: { height: 800, width: 700 } }, + { name: 'mobile', viewport: { height: 800, width: 400 } } + ]; + + screenSizeCategories.forEach((screenSizeCategory) => { + describe(screenSizeCategory.name, () => { + tests.forEach((test) => { + it(`${test.name}`, async() => { + const el = await fixture( + html` + + `, { viewport: screenSizeCategory.viewport } + ); + + await expect(el).to.be.golden(); + }); + }); + }); + }); + +}); diff --git a/test/components/grade-result/d2l-grade-result-write-enabled.vdiff.js b/test/components/grade-result/d2l-grade-result-write-enabled.vdiff.js new file mode 100644 index 00000000..25a9f237 --- /dev/null +++ b/test/components/grade-result/d2l-grade-result-write-enabled.vdiff.js @@ -0,0 +1,171 @@ +import '../../../src/components/grade-result/grade-result-presentational.js'; +import { fixture, html } from '@brightspace-ui/testing'; +import { testDiff } from './vdiff-utils.js'; + +describe('write enabled visual diff tests', () => { + + const tests = [ + { + name: 'write-enabled-number-grade-no-icons', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20 + }, + { + name: 'write-enabled-number-decimal-grade-no-icons', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 1.55555, + scoreDenominator: 20 + }, + { + name: 'write-enabled-number-grade-icons', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20, + includeGradeButton: true, + includeReportsButton: true + }, + { + name: 'write-enabled-number-grade-icons-tooltips-grade', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20, + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusGradesButton: true + }, + { + name: 'write-enabled-number-grade-icons-tooltips-reports', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 5, + scoreDenominator: 20, + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusReportsButton: true + }, + { + name: 'write-enabled-number-range-validation-error', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: -2, + scoreDenominator: 20 + }, + { + name: 'write-enabled-number-range-validation-error-tooltip', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: -2, + scoreDenominator: 20, + focusInputBox: true + }, + { + name: 'write-enabled-number-negative-marking-enabled', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: -2, + scoreDenominator: 20, + allowNegativeScore: true + }, + { + name: 'write-enabled-negative-grade-warning', + gradeType: 'Numeric', + labelText: 'Attempt Grade', + scoreNumerator: 0, + scoreDenominator: 20, + showFlooredScoreWarning: true, + focusInputBox: true + }, + { + name: 'write-enabled-negative-grade-warning-icons', + gradeType: 'Numeric', + labelText: 'Attempt Grade', + scoreNumerator: 0, + scoreDenominator: 20, + includeGradeButton: true, + includeReportsButton: true, + showFlooredScoreWarning: true, + focusInputBox: true + }, + { + name: 'write-enabled-number-dynamic-width', + gradeType: 'Numeric', + labelText: 'Overall Grade', + scoreNumerator: 33333333, + scoreDenominator: 33333333 + }, + { + name: 'write-enabled-letter-grade-no-icons', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + selectedLetterGrade: '2' + }, + { + name: 'write-enabled-letter-grade-icons', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + includeGradeButton: true, + includeReportsButton: true + }, + { + name: 'write-enabled-letter-grade-icons-tooltips-grades', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusGradesButton: true + }, + { + name: 'write-enabled-letter-grade-icons-tooltips-reports', + gradeType: 'LetterGrade', + labelText: 'Overall Grade', + letterGradeOptions: { '0': { 'LetterGrade': 'None', 'PercentStart': null }, '1': { 'LetterGrade': 'A', 'PercentStart': '75' }, '2': { 'LetterGrade': 'B', 'PercentStart': '50' } }, + gradeButtonTooltip: 'Assignment 1 Grade Item Attached', + reportsButtonTooltip: 'Class and user statistics', + includeGradeButton: true, + includeReportsButton: true, + focusReportsButton: true + } + ]; + + tests.forEach((test) => { + it(`${test.name}`, async() => { + const fixtureElement = await fixture( + html` +
+ +
`, + { pagePadding: false } + ); + + await testDiff(fixtureElement, test.focusGradesButton, test.focusReportsButton, test.focusInputBox); + }); + }); + +}); diff --git a/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-icons-clear-manual-override-option.png b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-icons-clear-manual-override-option.png new file mode 100644 index 00000000..527a84ca Binary files /dev/null and b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-icons-clear-manual-override-option.png differ diff --git a/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-icons-tooltips-clear-manual-override-option-grades.png b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-icons-tooltips-clear-manual-override-option-grades.png new file mode 100644 index 00000000..0428a02f Binary files /dev/null and b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-icons-tooltips-clear-manual-override-option-grades.png differ diff --git a/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-icons-tooltips-clear-manual-override-option-reports.png b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-icons-tooltips-clear-manual-override-option-reports.png new file mode 100644 index 00000000..6e43cd04 Binary files /dev/null and b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-icons-tooltips-clear-manual-override-option-reports.png differ diff --git a/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-no-icons-clear-manual-override-option.png b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-no-icons-clear-manual-override-option.png new file mode 100644 index 00000000..2835cb83 Binary files /dev/null and b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-letter-grade-no-icons-clear-manual-override-option.png differ diff --git a/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-icons-clear-manual-override-option.png b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-icons-clear-manual-override-option.png new file mode 100644 index 00000000..84cc074f Binary files /dev/null and b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-icons-clear-manual-override-option.png differ diff --git a/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-icons-tooltips-clear-manual-override-option-grades.png b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-icons-tooltips-clear-manual-override-option-grades.png new file mode 100644 index 00000000..540a7600 Binary files /dev/null and b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-icons-tooltips-clear-manual-override-option-grades.png differ diff --git a/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-icons-tooltips-clear-manual-override-option-reports.png b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-icons-tooltips-clear-manual-override-option-reports.png new file mode 100644 index 00000000..ddc906e6 Binary files /dev/null and b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-icons-tooltips-clear-manual-override-option-reports.png differ diff --git a/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-no-icons-clear-manual-override-option.png b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-no-icons-clear-manual-override-option.png new file mode 100644 index 00000000..bdccba4b Binary files /dev/null and b/test/components/grade-result/golden/autograde/chromium/provided-visual-diff-tests-autograde-provided-number-grade-no-icons-clear-manual-override-option.png differ diff --git a/test/components/grade-result/golden/optional/chromium/override-text-substitution-visual-diff-tests-custom-manual-override-clear-text.png b/test/components/grade-result/golden/optional/chromium/override-text-substitution-visual-diff-tests-custom-manual-override-clear-text.png new file mode 100644 index 00000000..e0490f24 Binary files /dev/null and b/test/components/grade-result/golden/optional/chromium/override-text-substitution-visual-diff-tests-custom-manual-override-clear-text.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-grade-calculation.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-grade-calculation.png new file mode 100644 index 00000000..36c69cba Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-grade-calculation.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-grade-not-shown-to-learners.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-grade-not-shown-to-learners.png new file mode 100644 index 00000000..a258ace1 Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-grade-not-shown-to-learners.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-manual-override.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-manual-override.png new file mode 100644 index 00000000..9f8a1d4f Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-manual-override.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-negative-score-hint.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-negative-score-hint.png new file mode 100644 index 00000000..da186aab Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-negative-score-hint.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-readonly-letter-long-letter.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-readonly-letter-long-letter.png new file mode 100644 index 00000000..229da2ea Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-readonly-letter-long-letter.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-readonly-letter.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-readonly-letter.png new file mode 100644 index 00000000..fce3cd47 Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-readonly-letter.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-readonly-numeric.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-readonly-numeric.png new file mode 100644 index 00000000..19b21edb Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-readonly-numeric.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-write-letter.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-write-letter.png new file mode 100644 index 00000000..b3aa1b29 Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-write-letter.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-write-numeric.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-write-numeric.png new file mode 100644 index 00000000..38b86638 Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/desktop-write-numeric.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-grade-calculation.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-grade-calculation.png new file mode 100644 index 00000000..68977199 Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-grade-calculation.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-grade-not-shown-to-learners.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-grade-not-shown-to-learners.png new file mode 100644 index 00000000..de51c2d4 Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-grade-not-shown-to-learners.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-manual-override.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-manual-override.png new file mode 100644 index 00000000..c4df3da9 Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-manual-override.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-negative-score-hint.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-negative-score-hint.png new file mode 100644 index 00000000..191f948d Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-negative-score-hint.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-readonly-letter-long-letter.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-readonly-letter-long-letter.png new file mode 100644 index 00000000..e4351187 Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-readonly-letter-long-letter.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-readonly-letter.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-readonly-letter.png new file mode 100644 index 00000000..9454c8a8 Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-readonly-letter.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-readonly-numeric.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-readonly-numeric.png new file mode 100644 index 00000000..8d6de8a3 Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-readonly-numeric.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-write-letter.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-write-letter.png new file mode 100644 index 00000000..b30a3a6c Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-write-letter.png differ diff --git a/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-write-numeric.png b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-write-numeric.png new file mode 100644 index 00000000..8e4c67a7 Binary files /dev/null and b/test/components/grade-result/golden/presentational-with-grade-preview/chromium/mobile-write-numeric.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-d2l-labs-d2l-grade-result-with-subtitle.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-d2l-labs-d2l-grade-result-with-subtitle.png new file mode 100644 index 00000000..491a363f Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-d2l-labs-d2l-grade-result-with-subtitle.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-icons-tooltips-grades.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-icons-tooltips-grades.png new file mode 100644 index 00000000..9c353f81 Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-icons-tooltips-grades.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-icons-tooltips-reports.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-icons-tooltips-reports.png new file mode 100644 index 00000000..c37fa774 Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-icons-tooltips-reports.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-icons.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-icons.png new file mode 100644 index 00000000..1ec15fa1 Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-icons.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-no-icons.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-no-icons.png new file mode 100644 index 00000000..7a3c4f7e Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-letter-grade-no-icons.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-negative-grade-icons.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-negative-grade-icons.png new file mode 100644 index 00000000..50770a8b Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-negative-grade-icons.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-negative-grade-no-icons.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-negative-grade-no-icons.png new file mode 100644 index 00000000..831c60de Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-negative-grade-no-icons.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-decimal-grade-no-icons.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-decimal-grade-no-icons.png new file mode 100644 index 00000000..846f4a41 Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-decimal-grade-no-icons.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-empty-numerator.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-empty-numerator.png new file mode 100644 index 00000000..872b0119 Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-empty-numerator.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-icons-tooltips-grades.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-icons-tooltips-grades.png new file mode 100644 index 00000000..5486ac39 Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-icons-tooltips-grades.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-icons-tooltips-reports.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-icons-tooltips-reports.png new file mode 100644 index 00000000..b86fe7c8 Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-icons-tooltips-reports.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-icons.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-icons.png new file mode 100644 index 00000000..2dd88715 Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-icons.png differ diff --git a/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-no-icons.png b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-no-icons.png new file mode 100644 index 00000000..15fd3af9 Binary files /dev/null and b/test/components/grade-result/golden/read/chromium/only-visual-diff-tests-read-only-number-grade-no-icons.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/colour-only.png b/test/components/grade-result/golden/student-grade-preview/chromium/colour-only.png new file mode 100644 index 00000000..b079db1c Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/colour-only.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/hide-label.png b/test/components/grade-result/golden/student-grade-preview/chromium/hide-label.png new file mode 100644 index 00000000..0c13153e Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/hide-label.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/hide-student-grade-preview.png b/test/components/grade-result/golden/student-grade-preview/chromium/hide-student-grade-preview.png new file mode 100644 index 00000000..78019f8c Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/hide-student-grade-preview.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/no-display-options.png b/test/components/grade-result/golden/student-grade-preview/chromium/no-display-options.png new file mode 100644 index 00000000..1aff716a Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/no-display-options.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/none.png b/test/components/grade-result/golden/student-grade-preview/chromium/none.png new file mode 100644 index 00000000..78019f8c Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/none.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/null-values.png b/test/components/grade-result/golden/student-grade-preview/chromium/null-values.png new file mode 100644 index 00000000..d9fe2531 Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/null-values.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/percentage-symbol.png b/test/components/grade-result/golden/student-grade-preview/chromium/percentage-symbol.png new file mode 100644 index 00000000..7599f395 Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/percentage-symbol.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/score-and-colour-only.png b/test/components/grade-result/golden/student-grade-preview/chromium/score-and-colour-only.png new file mode 100644 index 00000000..6287c528 Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/score-and-colour-only.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/score-and-symbol-only.png b/test/components/grade-result/golden/student-grade-preview/chromium/score-and-symbol-only.png new file mode 100644 index 00000000..17476db9 Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/score-and-symbol-only.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/score-only.png b/test/components/grade-result/golden/student-grade-preview/chromium/score-only.png new file mode 100644 index 00000000..aebef4b3 Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/score-only.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/select-box-symbol.png b/test/components/grade-result/golden/student-grade-preview/chromium/select-box-symbol.png new file mode 100644 index 00000000..c6e8be97 Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/select-box-symbol.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/symbol-and-colour-only.png b/test/components/grade-result/golden/student-grade-preview/chromium/symbol-and-colour-only.png new file mode 100644 index 00000000..2df9bf15 Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/symbol-and-colour-only.png differ diff --git a/test/components/grade-result/golden/student-grade-preview/chromium/symbol-only.png b/test/components/grade-result/golden/student-grade-preview/chromium/symbol-only.png new file mode 100644 index 00000000..58f54a29 Binary files /dev/null and b/test/components/grade-result/golden/student-grade-preview/chromium/symbol-only.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-icons-tooltips-grades.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-icons-tooltips-grades.png new file mode 100644 index 00000000..66f78327 Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-icons-tooltips-grades.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-icons-tooltips-reports.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-icons-tooltips-reports.png new file mode 100644 index 00000000..a8fa69c2 Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-icons-tooltips-reports.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-icons.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-icons.png new file mode 100644 index 00000000..446f8735 Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-icons.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-no-icons.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-no-icons.png new file mode 100644 index 00000000..dba08f96 Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-letter-grade-no-icons.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-negative-grade-warning-icons.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-negative-grade-warning-icons.png new file mode 100644 index 00000000..f7aa4a9e Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-negative-grade-warning-icons.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-negative-grade-warning.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-negative-grade-warning.png new file mode 100644 index 00000000..8f08a014 Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-negative-grade-warning.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-decimal-grade-no-icons.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-decimal-grade-no-icons.png new file mode 100644 index 00000000..1e0f1e01 Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-decimal-grade-no-icons.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-dynamic-width.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-dynamic-width.png new file mode 100644 index 00000000..c6c08a19 Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-dynamic-width.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-icons-tooltips-grade.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-icons-tooltips-grade.png new file mode 100644 index 00000000..929375a0 Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-icons-tooltips-grade.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-icons-tooltips-reports.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-icons-tooltips-reports.png new file mode 100644 index 00000000..70a247fe Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-icons-tooltips-reports.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-icons.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-icons.png new file mode 100644 index 00000000..8f10297a Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-icons.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-no-icons.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-no-icons.png new file mode 100644 index 00000000..815bcc77 Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-grade-no-icons.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-negative-marking-enabled.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-negative-marking-enabled.png new file mode 100644 index 00000000..af4e0ee2 Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-negative-marking-enabled.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-range-validation-error-tooltip.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-range-validation-error-tooltip.png new file mode 100644 index 00000000..fd449807 Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-range-validation-error-tooltip.png differ diff --git a/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-range-validation-error.png b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-range-validation-error.png new file mode 100644 index 00000000..acf9463e Binary files /dev/null and b/test/components/grade-result/golden/write/chromium/enabled-visual-diff-tests-write-enabled-number-range-validation-error.png differ diff --git a/test/components/grade-result/utils.js b/test/components/grade-result/utils.js new file mode 100644 index 00000000..a8cb94ef --- /dev/null +++ b/test/components/grade-result/utils.js @@ -0,0 +1,35 @@ +export const getPresentationalComponent = (el) => { + return el.shadowRoot.querySelector('d2l-labs-d2l-grade-result-presentational'); +}; + +export const getGradesButton = (el) => { + return el + .shadowRoot.querySelector('d2l-grade-result-icon-button') + .shadowRoot.querySelector('d2l-button-icon'); +}; + +export const getReportsButton = (el) => { + return el + .shadowRoot.querySelectorAll('d2l-grade-result-icon-button')[1] + .shadowRoot.querySelector('d2l-button-icon'); +}; + +export const getManualOverrideButton = (el) => { + return el.shadowRoot.querySelector('d2l-button-subtle'); +}; + +export const getNumericScore = (el) => { + return el.shadowRoot.querySelector('d2l-grade-result-numeric-score'); +}; + +export const getNumericScoreInput = (el) => { + return getNumericScore(el).shadowRoot.querySelector('d2l-input-number'); +}; + +export const getLetterScore = (el) => { + return el.shadowRoot.querySelector('d2l-grade-result-letter-score'); +}; + +export const getLetterScoreSelect = (el) => { + return getLetterScore(el).shadowRoot.querySelector('select'); +}; diff --git a/test/components/grade-result/vdiff-utils.js b/test/components/grade-result/vdiff-utils.js new file mode 100644 index 00000000..947a61d3 --- /dev/null +++ b/test/components/grade-result/vdiff-utils.js @@ -0,0 +1,42 @@ +import { expect, focusElem } from '@brightspace-ui/testing'; + +async function focusGradesButton(fixtureElement) { + const gradeButtonElement = fixtureElement + .querySelector('d2l-labs-d2l-grade-result-presentational') + .shadowRoot.querySelector('d2l-grade-result-icon-button') + .shadowRoot.querySelector('d2l-button-icon'); + + await focusElem(gradeButtonElement); +} + +async function focusReportsButton(fixtureElement) { + const reportsButtonElement = fixtureElement + .querySelector('d2l-labs-d2l-grade-result-presentational') + .shadowRoot.querySelectorAll('d2l-grade-result-icon-button')[1] + .shadowRoot.querySelector('d2l-button-icon'); + + await focusElem(reportsButtonElement); +} + +async function focusInputBox(fixtureElement) { + const inputBoxElement = fixtureElement + .querySelector('d2l-labs-d2l-grade-result-presentational') + .shadowRoot.querySelector('d2l-grade-result-numeric-score') + .shadowRoot.querySelector('d2l-input-number') + .shadowRoot.querySelector('d2l-input-text') + .shadowRoot.querySelector('input'); + + await focusElem(inputBoxElement); +} + +export async function testDiff(fixtureElement, focusGrades, focusReports, focusInput) { + if (focusGrades) { + await focusGradesButton(fixtureElement); + } else if (focusReports) { + await focusReportsButton(fixtureElement); + } else if (focusInput) { + await focusInputBox(fixtureElement); + } + + await expect(fixtureElement).to.be.golden(); +} diff --git a/test/controllers/grade-result/Grade.test.js b/test/controllers/grade-result/Grade.test.js new file mode 100644 index 00000000..e4738cd9 --- /dev/null +++ b/test/controllers/grade-result/Grade.test.js @@ -0,0 +1,368 @@ +import { Grade, GradeErrors, GradeType } from '../../../src/controllers/grade-result/Grade.js'; +import { assert } from '@brightspace-ui/testing'; + +const letterGradeOptions = { + 0: { 'LetterGrade': 'None', 'PercentStart': null, 'AssignedValue': null }, + 1: { 'LetterGrade': 'A', 'PercentStart': 80, 'AssignedValue': 80 }, + 2: { 'LetterGrade': 'B', 'PercentStart': 65, 'AssignedValue': 65 }, + 3: { 'LetterGrade': 'C', 'PercentStart': 50, 'AssignedValue': 50 }, +}; + +describe('Grade tests', () => { + describe('properly calling constructor', () => { + it('initializes properly for a numeric score', () => { + const grade = new Grade(GradeType.Number, 10, 50, null, null); + assert.equal(grade.isLetterGrade(), false); + assert.equal(grade.isNumberGrade(), true); + assert.equal(grade.getScoreType(), GradeType.Number); + assert.equal(grade.getScore(), 10); + assert.equal(grade.getOutOf(), 50); + }); + + it('initializes properly for a numeric score (not overridden)', () => { + const grade = new Grade(GradeType.Number, 10, 50, null, null, null, 10); + assert.equal(grade.isLetterGrade(), false); + assert.equal(grade.isNumberGrade(), true); + assert.equal(grade.getScoreType(), GradeType.Number); + assert.equal(grade.getScore(), 10); + assert.equal(grade.getOutOf(), 50); + assert.equal(grade.getLetterGradeOptions(), undefined); + assert.equal(grade.isManuallyOverridden, false); + }); + + it('initializes properly for a numeric score (overridden)', () => { + const grade = new Grade(GradeType.Number, 10, 50, null, null, null, 15); + assert.equal(grade.isLetterGrade(), false); + assert.equal(grade.isNumberGrade(), true); + assert.equal(grade.getScoreType(), GradeType.Number); + assert.equal(grade.getScore(), 10); + assert.equal(grade.getOutOf(), 50); + assert.equal(grade.getLetterGradeOptions(), undefined); + assert.equal(grade.isManuallyOverridden, true); + }); + + it('initializes properly for a letter score', () => { + const grade = new Grade(GradeType.Letter, null, null, 'A', letterGradeOptions); + assert.equal(grade.isLetterGrade(), true); + assert.equal(grade.isNumberGrade(), false); + assert.equal(grade.getScoreType(), GradeType.Letter); + assert.equal(grade.getScore(), '1'); + assert.equal(grade.getOutOf(), null); + assert.deepEqual(grade.getLetterGradeOptions(), letterGradeOptions); + }); + + it('initializes properly for a letter score with null grade', () => { + const grade = new Grade(GradeType.Letter, null, null, null, letterGradeOptions); + assert.equal(grade.isLetterGrade(), true); + assert.equal(grade.isNumberGrade(), false); + assert.equal(grade.getScoreType(), GradeType.Letter); + assert.equal(grade.getScore(), '0'); + assert.equal(grade.getOutOf(), null); + assert.deepEqual(grade.getLetterGradeOptions(), letterGradeOptions); + }); + + it('initializes properly for a letter score with an out of', () => { + const grade = new Grade(GradeType.Letter, null, 50, 'A', letterGradeOptions); + assert.equal(grade.isLetterGrade(), true); + assert.equal(grade.isNumberGrade(), false); + assert.equal(grade.getScoreType(), GradeType.Letter); + assert.equal(grade.getScore(), '1'); + assert.equal(grade.getOutOf(), 50); + assert.deepEqual(grade.getLetterGradeOptions(), letterGradeOptions); + }); + }); + + describe('throws an error if improper scoreType given in constructor', () => { + it('given invalid string', () => { + assert.throws(() => { + new Grade('not valid', 10, 50, null, null); + }, GradeErrors.INVALID_SCORE_TYPE); + }); + + it('given undefined', () => { + assert.throws(() => { + new Grade(undefined, 10, 50, null, null); + }, GradeErrors.INVALID_SCORE_TYPE); + }); + + it('given number', () => { + assert.throws(() => { + new Grade(5, 10, 50, null, null); + }, GradeErrors.INVALID_SCORE_TYPE); + }); + + it('given array', () => { + assert.throws(() => { + new Grade([], 10, 50, null, null); + }, GradeErrors.INVALID_SCORE_TYPE); + }); + }); + + describe('ensures that the gradeType is case insensitive and isLetterGrade and isNumberGrade still work', () => { + it('can handle numeric', () => { + assert.doesNotThrow(() => { + const grade = new Grade('numeric', 10, 50, null, null); + assert.isFalse(grade.isLetterGrade()); + assert.isTrue(grade.isNumberGrade()); + }); + }); + + it('can handle lettergrade', () => { + assert.doesNotThrow(() => { + const grade = new Grade('lettergrade', null, null, 'A', letterGradeOptions); + assert.isTrue(grade.isLetterGrade()); + assert.isFalse(grade.isNumberGrade()); + }); + }); + }); + + describe('throws an error if improper score are provided for numeric scores', () => { + it('score as null', () => { + assert.doesNotThrow(() => { + new Grade(GradeType.Number, null, 10, null, null); + }); + }); + + it('score as string', () => { + assert.throws(() => { + new Grade(GradeType.Number, 'A', 10, null, null); + }, GradeErrors.INVALID_SCORE); + }); + + it('score as array of strings', () => { + assert.throws(() => { + new Grade(GradeType.Number, ['A'], 10, null, null); + }, GradeErrors.INVALID_SCORE); + }); + }); + + describe('throws an error if improper score/outOf are provided for letter scores', () => { + it('lettergrade as null', () => { + assert.doesNotThrow(() => { + new Grade(GradeType.Letter, null, null, null, letterGradeOptions); + }); + }); + + it('lettergrade as number', () => { + assert.throws(() => { + new Grade(GradeType.Letter, null, null, 10, letterGradeOptions); + }, GradeErrors.INVALID_LETTER_GRADE); + }); + + it('lettergrade as array of strings', () => { + assert.throws(() => { + new Grade(GradeType.Letter, null, null, ['A', 'B'], letterGradeOptions); + }, GradeErrors.INVALID_LETTER_GRADE); + }); + + it('lettergradeOptions as null', () => { + assert.throws(() => { + new Grade(GradeType.Letter, null, null, 'A', null); + }, GradeErrors.INVALID_LETTER_GRADE_OPTIONS); + }); + + it('lettergradeOptions as number', () => { + assert.throws(() => { + new Grade(GradeType.Letter, null, null, 'A', 50); + }, GradeErrors.INVALID_LETTER_GRADE_OPTIONS); + }); + + it('lettergradeOptions as string', () => { + assert.throws(() => { + new Grade(GradeType.Letter, null, null, 'A', '50'); + }, GradeErrors.INVALID_LETTER_GRADE_OPTIONS); + }); + + it('lettergradeOptions as empty array', () => { + assert.throws(() => { + new Grade(GradeType.Letter, null, null, 'A', []); + }, GradeErrors.INVALID_LETTER_GRADE_OPTIONS); + }); + + }); + + describe('getScore, getOutOf, and getLetterGradeOptions work properly', () => { + it('getScore works properly for numeric scores', () => { + const grade = new Grade(GradeType.Number, 5, 10, null, null); + assert.equal(grade.getScore(), 5); + }); + + it('getScore works properly for letter scores', () => { + const grade = new Grade(GradeType.Letter, null, null, 'A', letterGradeOptions); + assert.equal(grade.getScore(), 1); + }); + + it('getOutOf works properly for numeric scores', () => { + const grade = new Grade(GradeType.Number, 5, 10, null, null); + assert.equal(grade.getOutOf(), 10); + }); + + it('getLetterGradeOptions works properly for letter scores', () => { + const grade = new Grade(GradeType.Letter, null, null, 'A', letterGradeOptions); + assert.deepEqual(grade.getLetterGradeOptions(), letterGradeOptions); + }); + }); + + describe('getLetterGrade works properly', () => { + it('getLetterGrade throws an error if the grade is numeric', () => { + const grade = new Grade(GradeType.Number, 5, 10, null, null); + assert.throws(() => { + grade.getLetterGrade(); + }, GradeErrors.GET_LETTER_GRADE_FROM_NUMERIC_SCORE); + }); + + it('getLetterGrade returns the letter grade properly', () => { + const letterGrade = 'A'; + const grade = new Grade(GradeType.Letter, null, null, letterGrade, letterGradeOptions); + assert.equal(grade.getLetterGrade(), letterGrade); + }); + }); + + it('ensures that the letterGrade is one of the LetterGradeOptions', () => { + assert.throws(() => { + new Grade(GradeType.Letter, null, null, 'D', letterGradeOptions); + }, GradeErrors.LETTER_GRADE_NOT_IN_OPTIONS); + }); + + it('allows score and outOf to be 0', () => { + assert.doesNotThrow(() => { + new Grade(GradeType.Number, 0, 0, null, null); + }); + }); + + describe('getLetterGradeAssignedValue works properly', () => { + it('getLetterGradeAssignedValue throws an error if the grade is numeric', () => { + const grade = new Grade(GradeType.Number, 5, 10, null, null); + assert.throws(() => { + grade.getLetterGradeAssignedValue(); + }, GradeErrors.GET_LETTER_GRADE_FROM_NUMERIC_SCORE); + }); + + it('getLetterGradeAssignedValue throws an error if the letterGradeId has no corresponding assigned value', () => { + const letterGrade = 'A'; + const badLetterGradeOptions = { + 0: { 'LetterGrade': 'None', 'PercentStart': null, 'AssignedValue': null }, + 1: { 'LetterGrade': 'A', 'PercentStart': '80' }, + 2: { 'LetterGrade': 'B', 'PercentStart': '65', 'AssignedValue': '65' }, + 3: { 'LetterGrade': 'C', 'PercentStart': '50', 'AssignedValue': '50' }, + }; + const grade = new Grade(GradeType.Letter, null, null, letterGrade, badLetterGradeOptions); + assert.throws(() => { + grade.getLetterGradeAssignedValue(); + }, GradeErrors.LETTER_GRADE_ID_NO_ASSIGNED_VALUE); + }); + + it('getLetterGradeAssignedValue throws an error if the letterGradeId has an assigned value that is not a number', () => { + const letterGrade = 'A'; + const badLetterGradeOptions = { + 0: { 'LetterGrade': 'None', 'PercentStart': null, 'AssignedValue': null }, + 1: { 'LetterGrade': 'A', 'PercentStart': '80', 'AssignedValue': 'A' }, + 2: { 'LetterGrade': 'B', 'PercentStart': '65', 'AssignedValue': '65' }, + 3: { 'LetterGrade': 'C', 'PercentStart': '50', 'AssignedValue': '50' }, + }; + const grade = new Grade(GradeType.Letter, null, null, letterGrade, badLetterGradeOptions); + assert.throws(() => { + grade.getLetterGradeAssignedValue(); + }, GradeErrors.LETTER_GRADE_ID_NO_ASSIGNED_VALUE); + }); + + it('getLetterGradeAssignedValue returns assigned value', () => { + const letterGrade = 'A'; + const grade = new Grade(GradeType.Letter, null, null, letterGrade, letterGradeOptions); + assert.equal(grade.getLetterGradeAssignedValue(), 80); + }); + }); + + describe('properly updates a score of a number grade', () => { + const grade = new Grade(GradeType.Number, 0, 0, null, null); + + it('sets number grade score properly', () => { + assert.doesNotThrow(() => { + grade.setScore(10); + assert.equal(grade.getScore(), 10); + }); + }); + + it('returns empty string for undefined score', () => { + assert.doesNotThrow(() => { + grade.setScore(undefined); + assert.equal(grade.getScore(), ''); + }); + }); + + it('does not throw for null score', () => { + assert.doesNotThrow(() => { + grade.setScore(null); + }); + }); + + it('throws error for string score', () => { + assert.throws(() => { + grade.setScore('A'); + }, GradeErrors.INVALID_SCORE); + }); + + it('throws error for array of strings score', () => { + assert.throws(() => { + grade.setScore(['A']); + }, GradeErrors.INVALID_SCORE); + }); + }); + + describe('properly updates a letter grade', () => { + const grade = new Grade(GradeType.Letter, null, null, 'A', letterGradeOptions); + + it('sets the letter grade properly', () => { + assert.doesNotThrow(() => { + const letterGradeId = grade._getLetterGradeIdFromLetterGrade('B', letterGradeOptions); + grade.setScore(letterGradeId); + assert.equal(grade.getScore(), 2); + }); + }); + + it('throws error for null score', () => { + assert.throws(() => { + grade.setScore(null); + }, GradeErrors.INVALID_LETTER_GRADE_ID); + }); + + it('throws error for undefined score', () => { + assert.throws(() => { + grade.setScore(); + }, GradeErrors.INVALID_LETTER_GRADE_ID); + }); + + it('throws error for new score not in letter grade options', () => { + assert.throws(() => { + grade._getLetterGradeIdFromLetterGrade('D', letterGradeOptions); + }, GradeErrors.LETTER_GRADE_NOT_IN_OPTIONS); + }); + + }); + + it('is able to store and retrieve an entity associated with the grade', () => { + const entity = { some: 'entity' }; + const grade = new Grade(GradeType.Number, 10, 11, null, null, entity); + assert.equal(grade.getEntity(), entity); + }); + + describe('can handle when scores have not yet been set', () => { + it('can handle score as null', () => { + assert.doesNotThrow(() => { + new Grade(GradeType.Number, null, 10, null, null); + }); + }); + + it('can handle letterGrade as null', () => { + assert.doesNotThrow(() => { + new Grade(GradeType.Letter, null, null, null, letterGradeOptions); + }); + }); + }); + + it('getDisplay works properly', () => { + const display = { some: 'display property' }; + const grade = new Grade(GradeType.Number, 10, 11, null, null, null, null, null, display); + assert.equal(grade.getDisplay(), display); + }); +});