make student lmgb responsive
closes OUT-3544 flag=none Test plan: - Add outcomes, aligned rubrics and quizzes, and assess students. - Enable LMGB and sLMGB - View sLMGB from teacher view and student view at different resolutions - verify that adjustments match proposals in ticket - verify that adjustments are functional at various screen sizes (320x256 min, 992x700 desktop, etc.) Change-Id: Id8c4404843ccb80786e6d7286341f1ba5a3d51a4 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/242797 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Product-Review: Michael Brewer-Davis <mbd@instructure.com> Reviewed-by: Pat Renner <prenner@instructure.com> Reviewed-by: Augusto Callejas <acallejas@instructure.com> QA-Review: Brian Watson <bwatson@instructure.com>
This commit is contained in:
parent
98263403b3
commit
212aab602b
|
@ -23,12 +23,13 @@ import {Button} from '@instructure/ui-buttons'
|
|||
import {Flex} from '@instructure/ui-layout'
|
||||
import {PresentationContent, ScreenReaderContent} from '@instructure/ui-a11y'
|
||||
import {Text} from '@instructure/ui-elements'
|
||||
import WithBreakpoints, {breakpointsShape} from '../shared/WithBreakpoints'
|
||||
|
||||
import {showFlashError} from '../shared/FlashAlert'
|
||||
import I18n from 'i18n!grade_summary'
|
||||
import SelectMenu from './SelectMenu'
|
||||
|
||||
export default class SelectMenuGroup extends React.Component {
|
||||
class SelectMenuGroup extends React.Component {
|
||||
static propTypes = {
|
||||
assignmentSortOptions: PropTypes.arrayOf(PropTypes.array).isRequired,
|
||||
courses: PropTypes.arrayOf(
|
||||
|
@ -58,11 +59,13 @@ export default class SelectMenuGroup extends React.Component {
|
|||
id: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired
|
||||
})
|
||||
).isRequired
|
||||
).isRequired,
|
||||
breakpoints: breakpointsShape
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
selectedGradingPeriodID: null
|
||||
selectedGradingPeriodID: null,
|
||||
breakpoints: {}
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
|
@ -158,8 +161,14 @@ export default class SelectMenuGroup extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const isVertical = !this.props.breakpoints.miniTablet
|
||||
return (
|
||||
<Flex alignItems="end" wrapItems margin="0 0 small 0">
|
||||
<Flex
|
||||
alignItems={isVertical ? 'start' : 'end'}
|
||||
wrapItems
|
||||
margin="0 0 small 0"
|
||||
direction={isVertical ? 'column' : 'row'}
|
||||
>
|
||||
<Flex.Item>
|
||||
{this.props.students.length > 1 && (
|
||||
<SelectMenu
|
||||
|
@ -216,7 +225,7 @@ export default class SelectMenuGroup extends React.Component {
|
|||
/>
|
||||
</Flex.Item>
|
||||
|
||||
<Flex.Item margin="0 0 0 small">
|
||||
<Flex.Item margin={isVertical ? 'small 0 0 0' : '0 0 0 small'}>
|
||||
<Button
|
||||
disabled={this.state.processing || this.noSelectMenuChanged()}
|
||||
id="apply_select_menus"
|
||||
|
@ -237,3 +246,5 @@ export default class SelectMenuGroup extends React.Component {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default WithBreakpoints(SelectMenuGroup)
|
||||
|
|
|
@ -29,65 +29,39 @@ import UnassessedAssignment from './UnassessedAssignment'
|
|||
import OutcomePopover from './OutcomePopover'
|
||||
import {ScreenReaderContent, PresentationContent} from '@instructure/ui-a11y'
|
||||
import TruncateWithTooltip from '../../shared/components/TruncateWithTooltip'
|
||||
import WithBreakpoints, {breakpointsShape} from '../../shared/WithBreakpoints'
|
||||
import * as shapes from './shapes'
|
||||
|
||||
export default class Outcome extends React.Component {
|
||||
class Outcome extends React.Component {
|
||||
static propTypes = {
|
||||
outcome: shapes.outcomeShape.isRequired,
|
||||
expanded: PropTypes.bool.isRequired,
|
||||
onExpansionChange: PropTypes.func.isRequired,
|
||||
outcomeProficiency: shapes.outcomeProficiencyShape
|
||||
outcomeProficiency: shapes.outcomeProficiencyShape,
|
||||
breakpoints: breakpointsShape
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
outcomeProficiency: null
|
||||
outcomeProficiency: null,
|
||||
breakpoints: {}
|
||||
}
|
||||
|
||||
handleToggle = (_event, expanded) => {
|
||||
this.props.onExpansionChange('outcome', this.props.outcome.expansionId, expanded)
|
||||
}
|
||||
|
||||
renderHeader() {
|
||||
const {outcome, outcomeProficiency} = this.props
|
||||
const {assignments, display_name, mastered, title, score, points_possible, results} = outcome
|
||||
const numAlignments = assignments.length
|
||||
const pillAttributes = {margin: '0 0 0 x-small', text: I18n.t('Not mastered')}
|
||||
renderScoreAndPill() {
|
||||
const {outcome} = this.props
|
||||
const {mastered, score, points_possible, results} = outcome
|
||||
const pillAttributes = {text: I18n.t('Not mastered')}
|
||||
if (mastered) {
|
||||
Object.assign(pillAttributes, {text: I18n.t('Mastered'), variant: 'success'})
|
||||
}
|
||||
|
||||
return (
|
||||
<Flex direction="row" justifyItems="space-between" data-selenium="outcome">
|
||||
<Flex.Item shrink>
|
||||
<Flex direction="column">
|
||||
<Flex.Item>
|
||||
<Text size="medium">
|
||||
<Flex>
|
||||
<Flex.Item>
|
||||
<OutcomePopover outcome={outcome} outcomeProficiency={outcomeProficiency} />
|
||||
</Flex.Item>
|
||||
<Flex.Item shrink padding="0 x-small">
|
||||
<TruncateWithTooltip>{display_name || title}</TruncateWithTooltip>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Text>
|
||||
</Flex.Item>
|
||||
<Flex.Item>
|
||||
<Text size="small">
|
||||
{I18n.t(
|
||||
{
|
||||
zero: 'No alignments',
|
||||
one: '%{count} alignment',
|
||||
other: '%{count} alignments'
|
||||
},
|
||||
{count: I18n.n(numAlignments)}
|
||||
)}
|
||||
</Text>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Flex.Item>
|
||||
<Flex.Item>
|
||||
{_.isNumber(score) && !_.every(results, ['hide_points', true]) && (
|
||||
<Flex direction="row" justifyItems="start" padding="0 0 0 x-small">
|
||||
{_.isNumber(score) && !_.every(results, ['hide_points', true]) && (
|
||||
<Flex.Item padding="0 x-small 0 0">
|
||||
<span>
|
||||
<PresentationContent>
|
||||
<Text size="medium">
|
||||
|
@ -95,16 +69,64 @@ export default class Outcome extends React.Component {
|
|||
</Text>
|
||||
</PresentationContent>
|
||||
<ScreenReaderContent>
|
||||
{I18n.t('%{score} out of %{points_possible} points', {score, points_possible})}
|
||||
{I18n.t('%{score} out of %{points_possible} points', {
|
||||
score,
|
||||
points_possible
|
||||
})}
|
||||
</ScreenReaderContent>
|
||||
</span>
|
||||
)}
|
||||
</Flex.Item>
|
||||
)}
|
||||
<Flex.Item>
|
||||
<Pill {...pillAttributes} />
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
renderHeader() {
|
||||
const {outcome, outcomeProficiency, breakpoints} = this.props
|
||||
const {assignments, display_name, title} = outcome
|
||||
const numAlignments = assignments.length
|
||||
const verticalLayout = !breakpoints.tablet
|
||||
|
||||
return (
|
||||
<Flex
|
||||
direction={verticalLayout ? 'column' : 'row'}
|
||||
justifyItems={verticalLayout ? null : 'space-between'}
|
||||
alignItems={verticalLayout ? 'stretch' : null}
|
||||
data-selenium="outcome"
|
||||
>
|
||||
<Flex.Item grow as="div">
|
||||
<Text size="medium">
|
||||
<Flex>
|
||||
<Flex.Item>
|
||||
<OutcomePopover outcome={outcome} outcomeProficiency={outcomeProficiency} />
|
||||
</Flex.Item>
|
||||
<Flex.Item shrink>
|
||||
<TruncateWithTooltip>{display_name || title}</TruncateWithTooltip>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Text>
|
||||
{verticalLayout && this.renderScoreAndPill()}
|
||||
<View as="div" padding="0 0 0 x-small">
|
||||
<Text size="small">
|
||||
{I18n.t(
|
||||
{
|
||||
zero: 'No alignments',
|
||||
one: '%{count} alignment',
|
||||
other: '%{count} alignments'
|
||||
},
|
||||
{count: I18n.n(numAlignments)}
|
||||
)}
|
||||
</Text>
|
||||
</View>
|
||||
</Flex.Item>
|
||||
{!verticalLayout && <Flex.Item>{this.renderScoreAndPill()}</Flex.Item>}
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
|
||||
renderDetails() {
|
||||
const {outcome, outcomeProficiency} = this.props
|
||||
const {assignments, results} = outcome
|
||||
|
@ -168,3 +190,5 @@ export default class Outcome extends React.Component {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default WithBreakpoints(Outcome)
|
||||
|
|
|
@ -27,10 +27,15 @@ import natcompare from 'compiled/util/natcompare'
|
|||
import TruncateWithTooltip from '../../shared/components/TruncateWithTooltip'
|
||||
import Outcome from './Outcome'
|
||||
import * as shapes from './shapes'
|
||||
import WithBreakpoints, {breakpointsShape} from '../../shared/WithBreakpoints'
|
||||
|
||||
const outcomeGroupHeader = (outcomeGroup, numMastered, numGroup) => (
|
||||
<Flex justifyItems="space-between">
|
||||
<Flex.Item padding="0 x-small 0 0" size="0" grow>
|
||||
const outcomeGroupHeader = (outcomeGroup, numMastered, numGroup, isVertical) => (
|
||||
<Flex
|
||||
padding="0 0 0 xxx-small"
|
||||
justifyItems={isVertical ? null : 'space-between'}
|
||||
direction={isVertical ? 'column' : 'row'}
|
||||
>
|
||||
<Flex.Item padding="0 x-small 0 0" size={isVertical ? undefined : '0'} grow>
|
||||
<Text size="large" weight="bold">
|
||||
<TruncateWithTooltip>{outcomeGroup.title}</TruncateWithTooltip>
|
||||
</Text>
|
||||
|
@ -41,18 +46,20 @@ const outcomeGroupHeader = (outcomeGroup, numMastered, numGroup) => (
|
|||
</Flex>
|
||||
)
|
||||
|
||||
export default class OutcomeGroup extends React.Component {
|
||||
class OutcomeGroup extends React.Component {
|
||||
static propTypes = {
|
||||
outcomeGroup: shapes.outcomeGroupShape.isRequired,
|
||||
outcomes: PropTypes.arrayOf(shapes.outcomeShape).isRequired,
|
||||
expanded: PropTypes.bool.isRequired,
|
||||
expandedOutcomes: ImmutablePropTypes.set.isRequired,
|
||||
onExpansionChange: PropTypes.func.isRequired,
|
||||
outcomeProficiency: shapes.outcomeProficiencyShape
|
||||
outcomeProficiency: shapes.outcomeProficiencyShape,
|
||||
breakpoints: breakpointsShape
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
outcomeProficiency: null
|
||||
outcomeProficiency: null,
|
||||
breakpoints: {}
|
||||
}
|
||||
|
||||
handleToggle = (_event, expanded) => {
|
||||
|
@ -66,15 +73,17 @@ export default class OutcomeGroup extends React.Component {
|
|||
expanded,
|
||||
expandedOutcomes,
|
||||
onExpansionChange,
|
||||
outcomeProficiency
|
||||
outcomeProficiency,
|
||||
breakpoints
|
||||
} = this.props
|
||||
const numMastered = outcomes.filter(o => o.mastered).length
|
||||
const numGroup = outcomes.length
|
||||
const isVertical = !breakpoints.tablet
|
||||
|
||||
return (
|
||||
<View as="div" className="outcomeGroup">
|
||||
<ToggleGroup
|
||||
summary={outcomeGroupHeader(outcomeGroup, numMastered, numGroup)}
|
||||
summary={outcomeGroupHeader(outcomeGroup, numMastered, numGroup, isVertical)}
|
||||
toggleLabel={I18n.t('Toggle outcomes for %{title}', {title: outcomeGroup.title})}
|
||||
expanded={expanded}
|
||||
onToggle={this.handleToggle}
|
||||
|
@ -96,3 +105,5 @@ export default class OutcomeGroup extends React.Component {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default WithBreakpoints(OutcomeGroup)
|
||||
|
|
|
@ -21,23 +21,25 @@ import _ from 'lodash'
|
|||
import I18n from 'i18n!IndividualStudentMasteryOutcomePopover'
|
||||
import {View, Flex} from '@instructure/ui-layout'
|
||||
import {Text} from '@instructure/ui-elements'
|
||||
import {Link} from '@instructure/ui-link'
|
||||
import {ScreenReaderContent} from '@instructure/ui-a11y'
|
||||
import CalculationMethodContent from 'compiled/models/grade_summary/CalculationMethodContent'
|
||||
import {Popover} from '@instructure/ui-overlays'
|
||||
import {IconInfoLine} from '@instructure/ui-icons'
|
||||
import DatetimeDisplay from '../../shared/DatetimeDisplay'
|
||||
import {CloseButton} from '@instructure/ui-buttons'
|
||||
import {CloseButton, IconButton} from '@instructure/ui-buttons'
|
||||
import {Modal} from '@instructure/ui-modal'
|
||||
import WithBreakpoints, {breakpointsShape} from '../../shared/WithBreakpoints'
|
||||
import * as shapes from './shapes'
|
||||
|
||||
export default class OutcomePopover extends React.Component {
|
||||
class OutcomePopover extends React.Component {
|
||||
static propTypes = {
|
||||
outcome: shapes.outcomeShape.isRequired,
|
||||
outcomeProficiency: shapes.outcomeProficiencyShape
|
||||
outcomeProficiency: shapes.outcomeProficiencyShape,
|
||||
breakpoints: breakpointsShape
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
outcomeProficiency: null
|
||||
outcomeProficiency: null,
|
||||
breakpoints: {}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
|
@ -76,17 +78,31 @@ export default class OutcomePopover extends React.Component {
|
|||
latestTime() {
|
||||
const {outcome} = this.props
|
||||
if (outcome.results.length > 0) {
|
||||
return _.sortBy(outcome.results, r => r.submitted_or_assessed_at)[0].submitted_or_assessed_at
|
||||
return _.sortBy(outcome.results, r => -r.submitted_or_assessed_at)[0].submitted_or_assessed_at
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
renderPopoverContent() {
|
||||
renderSelectedRating() {
|
||||
const selectedRating = this.getSelectedRating()
|
||||
return (
|
||||
<Text size="small" weight="bold">
|
||||
<div>
|
||||
{selectedRating && (
|
||||
<div style={{color: `#${selectedRating.color}`}}>{selectedRating.description}</div>
|
||||
)}
|
||||
</div>
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
renderPopoverContent() {
|
||||
const latestTime = this.latestTime()
|
||||
const popoverContent = new CalculationMethodContent(this.props.outcome).present()
|
||||
const {method, exampleText, exampleScores, exampleResult} = popoverContent
|
||||
const {outcome} = this.props
|
||||
const {outcome, breakpoints} = this.props
|
||||
const isVertical = !breakpoints.miniTablet
|
||||
|
||||
return (
|
||||
<View as="div" padding="large" maxWidth="30rem">
|
||||
<CloseButton
|
||||
|
@ -103,7 +119,9 @@ export default class OutcomePopover extends React.Component {
|
|||
{outcome.title}
|
||||
</div>
|
||||
<div>
|
||||
{isVertical && <div>{this.renderSelectedRating()}</div>}
|
||||
{I18n.t('Last Assessment: ')}
|
||||
{isVertical && <br />}
|
||||
{latestTime ? (
|
||||
<DatetimeDisplay datetime={latestTime} format="%b %d, %l:%M %p" />
|
||||
) : (
|
||||
|
@ -111,17 +129,7 @@ export default class OutcomePopover extends React.Component {
|
|||
)}
|
||||
</div>
|
||||
</Flex.Item>
|
||||
<Flex.Item grow shrink align="stretch">
|
||||
<Text size="small" weight="bold">
|
||||
<div>
|
||||
{selectedRating && (
|
||||
<div style={{color: `#${selectedRating.color}`, textAlign: 'end'}}>
|
||||
{selectedRating.description}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Text>
|
||||
</Flex.Item>
|
||||
{!isVertical && <Flex.Item align="stretch">{this.renderSelectedRating()}</Flex.Item>}
|
||||
</Flex>
|
||||
<hr role="presentation" />
|
||||
<div>
|
||||
|
@ -143,8 +151,7 @@ export default class OutcomePopover extends React.Component {
|
|||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const popoverContent = this.renderPopoverContent()
|
||||
renderPopover() {
|
||||
return (
|
||||
<span>
|
||||
<Popover
|
||||
|
@ -155,26 +162,59 @@ export default class OutcomePopover extends React.Component {
|
|||
shouldContainFocus
|
||||
>
|
||||
<Popover.Trigger>
|
||||
<Link
|
||||
<IconButton
|
||||
size="small"
|
||||
margin="xx-small"
|
||||
withBackground={false}
|
||||
withBorder={false}
|
||||
screenReaderLabel={I18n.t('Click to expand outcome details')}
|
||||
renderIcon={IconInfoLine}
|
||||
onClick={() => this.setState(prevState => ({linkClicked: !prevState.linkClicked}))}
|
||||
onMouseEnter={() => this.setState({linkHover: true})}
|
||||
onMouseLeave={() => this.setState({linkHover: false})}
|
||||
>
|
||||
<span style={{color: 'black'}}>
|
||||
<IconInfoLine />
|
||||
</span>
|
||||
<span>
|
||||
{!this.state.linkClicked && (
|
||||
<ScreenReaderContent>
|
||||
{I18n.t('Click to expand outcome details')}
|
||||
</ScreenReaderContent>
|
||||
)}
|
||||
</span>
|
||||
</Link>
|
||||
/>
|
||||
</Popover.Trigger>
|
||||
<Popover.Content>{popoverContent}</Popover.Content>
|
||||
<Popover.Content>{this.renderPopoverContent()}</Popover.Content>
|
||||
</Popover>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
renderModal() {
|
||||
return (
|
||||
<span>
|
||||
<IconButton
|
||||
size="small"
|
||||
margin="xx-small"
|
||||
withBackground={false}
|
||||
withBorder={false}
|
||||
screenReaderLabel={I18n.t('Click to expand outcome details')}
|
||||
renderIcon={IconInfoLine}
|
||||
onClick={() => this.setState(prevState => ({linkClicked: !prevState.linkClicked}))}
|
||||
/>
|
||||
<Modal
|
||||
open={this.state.linkClicked}
|
||||
onDismiss={() =>
|
||||
this.setState(prevState => prevState.linkClicked && this.setState({linkClicked: false}))
|
||||
}
|
||||
size="fullscreen"
|
||||
label={I18n.t('Outcome Details')}
|
||||
>
|
||||
<Modal.Body>{this.renderPopoverContent()}</Modal.Body>
|
||||
</Modal>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {breakpoints} = this.props
|
||||
const modalLayout = !breakpoints.miniTablet
|
||||
if (modalLayout) {
|
||||
return this.renderModal()
|
||||
} else {
|
||||
return this.renderPopover()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default WithBreakpoints(OutcomePopover)
|
||||
|
|
|
@ -24,25 +24,22 @@ import {ApplyTheme} from '@instructure/ui-themeable'
|
|||
import {View} from '@instructure/ui-layout'
|
||||
import {Button} from '@instructure/ui-buttons'
|
||||
import {IconAssignmentLine, IconQuizLine} from '@instructure/ui-icons'
|
||||
import {List} from '@instructure/ui-elements'
|
||||
|
||||
const UnassessedAssignment = ({assignment}) => {
|
||||
const {id, url, submission_types, title} = assignment
|
||||
return (
|
||||
<List.Item key={id}>
|
||||
<View padding="small" display="block">
|
||||
<ApplyTheme theme={{[Button.theme]: {linkColor: '#68777D', fontWeight: '700'}}}>
|
||||
<Button
|
||||
href={url}
|
||||
variant="link"
|
||||
theme={{mediumPadding: '0', mediumHeight: 'normal'}}
|
||||
icon={_.includes(submission_types, 'online_quiz') ? IconQuizLine : IconAssignmentLine}
|
||||
>
|
||||
{title} ({I18n.t('Not yet assessed')})
|
||||
</Button>
|
||||
</ApplyTheme>
|
||||
</View>
|
||||
</List.Item>
|
||||
<View padding="small" display="block" key={id}>
|
||||
<ApplyTheme theme={{[Button.theme]: {linkColor: '#68777D', fontWeight: '700'}}}>
|
||||
<Button
|
||||
href={url}
|
||||
variant="link"
|
||||
theme={{mediumPadding: '0', mediumHeight: 'normal'}}
|
||||
icon={_.includes(submission_types, 'online_quiz') ? IconQuizLine : IconAssignmentLine}
|
||||
>
|
||||
{title} ({I18n.t('Not yet assessed')})
|
||||
</Button>
|
||||
</ApplyTheme>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {render, shallow} from 'enzyme'
|
||||
import {render, fireEvent, within} from '@testing-library/react'
|
||||
import Outcome from '../Outcome'
|
||||
|
||||
const result = (id = 1, date = new Date(), hidePoints = false) => ({
|
||||
const result = ({id = 1, date = new Date(), hide_points = false}, assignmentOverrides = {}) => ({
|
||||
id,
|
||||
percent: 0.1,
|
||||
assignment: {
|
||||
|
@ -28,9 +28,10 @@ const result = (id = 1, date = new Date(), hidePoints = false) => ({
|
|||
html_url: 'http://foo',
|
||||
name: 'My alignment',
|
||||
submission_types: '',
|
||||
score: 0
|
||||
score: 0,
|
||||
...assignmentOverrides
|
||||
},
|
||||
hide_points: hidePoints,
|
||||
hide_points,
|
||||
submitted_or_assessed_at: date.toISOString()
|
||||
})
|
||||
|
||||
|
@ -42,11 +43,11 @@ const defaultProps = (props = {}) => ({
|
|||
id: 1,
|
||||
assignments: [
|
||||
{
|
||||
assignment_id: 1,
|
||||
assignment_id: '1',
|
||||
learning_outcome_id: 1,
|
||||
submission_types: 'online_quiz',
|
||||
title: 'My assignment',
|
||||
url: 'www.example.com'
|
||||
name: 'My assignment',
|
||||
html_url: 'www.example.com'
|
||||
}
|
||||
],
|
||||
expansionId: 100,
|
||||
|
@ -76,6 +77,7 @@ const defaultProps = (props = {}) => ({
|
|||
assignment: {
|
||||
id: 'live_assessments/assessment_1',
|
||||
name: 'My assessment',
|
||||
html_url: 'http://bar',
|
||||
submission_types: 'magic_marker',
|
||||
score: 0
|
||||
},
|
||||
|
@ -90,93 +92,72 @@ const defaultProps = (props = {}) => ({
|
|||
...props
|
||||
})
|
||||
|
||||
it('renders the Outcome component', () => {
|
||||
const wrapper = shallow(<Outcome {...defaultProps()} />)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('renders correctly expanded', () => {
|
||||
const wrapper = shallow(<Outcome {...defaultProps()} expanded />)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
const {getByText, getByRole} = render(<Outcome {...defaultProps()} expanded />)
|
||||
expect(getByText('My outcome')).not.toBeNull()
|
||||
expect(getByRole('list')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('renders correctly expanded with no results', () => {
|
||||
const props = defaultProps()
|
||||
props.outcome.results = []
|
||||
const wrapper = shallow(<Outcome {...props} expanded />)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
const {getByText} = render(<Outcome {...props} expanded />)
|
||||
expect(getByText(/Not yet assessed/)).not.toBeNull()
|
||||
})
|
||||
|
||||
it('renders correctly expanded with no results or assignments', () => {
|
||||
const props = defaultProps()
|
||||
props.outcome.results = []
|
||||
props.outcome.assignments = []
|
||||
const wrapper = shallow(<Outcome {...props} expanded />)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
const {getByText} = render(<Outcome {...props} expanded />)
|
||||
expect(getByText(/No alignments are available/)).not.toBeNull()
|
||||
})
|
||||
|
||||
describe('header', () => {
|
||||
it('includes the outcome name', () => {
|
||||
const wrapper = shallow(<Outcome {...defaultProps()} />)
|
||||
const header = wrapper.find('ToggleGroup')
|
||||
const summary = render(header.prop('summary'))
|
||||
expect(summary.text()).toMatch('My outcome')
|
||||
})
|
||||
|
||||
it('includes the outcome friendly name', () => {
|
||||
const props = defaultProps()
|
||||
props.outcome.display_name = 'Friendly name'
|
||||
const wrapper = shallow(<Outcome {...props} />)
|
||||
const header = wrapper.find('ToggleGroup')
|
||||
const summary = render(header.prop('summary'))
|
||||
expect(summary.text()).toMatch('Friendly name')
|
||||
const {getByText} = render(<Outcome {...defaultProps()} />)
|
||||
expect(getByText('My outcome')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('includes mastery when mastered', () => {
|
||||
const props = defaultProps()
|
||||
props.outcome.mastered = true
|
||||
const wrapper = shallow(<Outcome {...props} />)
|
||||
const header = wrapper.find('ToggleGroup')
|
||||
const summary = render(header.prop('summary'))
|
||||
expect(summary.text()).toMatch('Mastered')
|
||||
const {getByText} = render(<Outcome {...props} />)
|
||||
expect(getByText('Mastered')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('includes non-mastery when not mastered', () => {
|
||||
const wrapper = shallow(<Outcome {...defaultProps()} />)
|
||||
const header = wrapper.find('ToggleGroup')
|
||||
const summary = render(header.prop('summary'))
|
||||
expect(summary.text()).toMatch('Not mastered')
|
||||
const {getByText} = render(<Outcome {...defaultProps()} />)
|
||||
expect(getByText('Not mastered')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('shows correct number of alignments', () => {
|
||||
const wrapper = shallow(<Outcome {...defaultProps()} />)
|
||||
const header = wrapper.find('ToggleGroup')
|
||||
const summary = render(header.prop('summary'))
|
||||
expect(summary.text()).toMatch('1 alignment')
|
||||
const {getByText} = render(<Outcome {...defaultProps()} />)
|
||||
expect(getByText('1 alignment')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('shows points if only some results have hide points enabled', () => {
|
||||
const props = defaultProps()
|
||||
props.outcome.results = [result(1, undefined, false), result(2, undefined, true)]
|
||||
const wrapper = shallow(<Outcome {...props} />)
|
||||
const header = wrapper.find('ToggleGroup')
|
||||
const summary = render(header.prop('summary'))
|
||||
expect(summary.text()).toMatch('1/5')
|
||||
props.outcome.results = [
|
||||
result({id: 1, hide_points: false}),
|
||||
result({id: 2, hide_points: true})
|
||||
]
|
||||
const {getByText} = render(<Outcome {...props} />)
|
||||
expect(getByText('1/5')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('does not show points if all results have hide points enabled', () => {
|
||||
const props = defaultProps()
|
||||
props.outcome.results = [result(1, undefined, true), result(2, undefined, true)]
|
||||
const wrapper = shallow(<Outcome {...props} />)
|
||||
const header = wrapper.find('ToggleGroup')
|
||||
const summary = render(header.prop('summary'))
|
||||
expect(summary.text()).not.toMatch('1/5')
|
||||
props.outcome.results = [result({id: 1, hide_points: true}), result({id: 2, hide_points: true})]
|
||||
const {queryByText} = render(<Outcome {...props} />)
|
||||
expect(queryByText('1/5')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
it('includes the individual results', () => {
|
||||
const wrapper = shallow(<Outcome {...defaultProps()} />)
|
||||
expect(wrapper.find('AssignmentResult')).toHaveLength(2)
|
||||
const {getAllByRole} = render(<Outcome {...defaultProps()} expanded />)
|
||||
const results = getAllByRole('listitem')
|
||||
expect(results).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('renders the results by most recent', () => {
|
||||
|
@ -186,19 +167,19 @@ it('renders the results by most recent', () => {
|
|||
const hourAgo = new Date(now - 3600000)
|
||||
const yearishAgo = new Date(now - 3600000 * 24 * 360)
|
||||
props.outcome.results = [
|
||||
result(1, hourAgo),
|
||||
result(2, now),
|
||||
result(3, minuteAgo),
|
||||
result(4, yearishAgo)
|
||||
result({id: 1, date: hourAgo}, {name: 'hour ago'}),
|
||||
result({id: 2, date: now}, {name: 'now'}),
|
||||
result({id: 3, date: minuteAgo}, {name: 'minute ago'}),
|
||||
result({id: 4, date: yearishAgo}, {name: 'year ago'})
|
||||
]
|
||||
|
||||
const wrapper = shallow(<Outcome {...props} />)
|
||||
const results = wrapper.find('AssignmentResult')
|
||||
const {getAllByRole} = render(<Outcome {...props} expanded />)
|
||||
const results = getAllByRole('listitem')
|
||||
expect(results).toHaveLength(4)
|
||||
expect(results.get(0).props.result.id).toEqual(2) // now
|
||||
expect(results.get(1).props.result.id).toEqual(3) // minuteAgo
|
||||
expect(results.get(2).props.result.id).toEqual(1) // hourAgo
|
||||
expect(results.get(3).props.result.id).toEqual(4) // yearishAgo
|
||||
expect(within(results[0]).getByText('now')).not.toBeNull()
|
||||
expect(within(results[1]).getByText('minute ago')).not.toBeNull()
|
||||
expect(within(results[2]).getByText('hour ago')).not.toBeNull()
|
||||
expect(within(results[3]).getByText('year ago')).not.toBeNull()
|
||||
})
|
||||
|
||||
describe('handleToggle()', () => {
|
||||
|
@ -206,8 +187,8 @@ describe('handleToggle()', () => {
|
|||
const props = defaultProps()
|
||||
props.onExpansionChange = jest.fn()
|
||||
|
||||
const wrapper = shallow(<Outcome {...props} />)
|
||||
wrapper.instance().handleToggle(null, true)
|
||||
const {getByText} = render(<Outcome {...props} />)
|
||||
fireEvent.click(getByText(/Toggle alignment details/)) // expand
|
||||
expect(props.onExpansionChange).toHaveBeenCalledWith('outcome', 100, true)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -17,14 +17,16 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {render, shallow} from 'enzyme'
|
||||
import {render, fireEvent, within} from '@testing-library/react'
|
||||
import {Set} from 'immutable'
|
||||
import OutcomeGroup from '../OutcomeGroup'
|
||||
|
||||
const outcome = (id, title) => ({
|
||||
id,
|
||||
title,
|
||||
assignments: [],
|
||||
assignments: [
|
||||
{html_url: 'http://foo', id: 'assignment_2', name: 'My alignment', submission_types: 'none'}
|
||||
],
|
||||
mastered: false,
|
||||
mastery_points: 3,
|
||||
points_possible: 5,
|
||||
|
@ -35,7 +37,7 @@ const outcome = (id, title) => ({
|
|||
id: 1,
|
||||
percent: 0.1,
|
||||
assignment: {
|
||||
id: 2,
|
||||
id: 'assignment_2',
|
||||
name: 'My alignment',
|
||||
html_url: 'http://foo',
|
||||
submission_types: ''
|
||||
|
@ -49,31 +51,7 @@ const defaultProps = (props = {}) => ({
|
|||
id: 10,
|
||||
title: 'My group'
|
||||
},
|
||||
outcomes: [
|
||||
{
|
||||
id: 1,
|
||||
expansionId: 100,
|
||||
mastered: false,
|
||||
mastery_points: 3,
|
||||
points_possible: 5,
|
||||
calculation_method: 'highest',
|
||||
ratings: [{description: 'My first rating'}, {description: 'My second rating'}],
|
||||
results: [
|
||||
{
|
||||
id: 1,
|
||||
score: 1,
|
||||
percent: 0.1,
|
||||
assignment: {
|
||||
id: 1,
|
||||
html_url: 'http://foo',
|
||||
name: 'My assignment',
|
||||
submission_types: 'online_quiz'
|
||||
}
|
||||
}
|
||||
],
|
||||
title: 'My outcome'
|
||||
}
|
||||
],
|
||||
outcomes: [outcome(1, 'My outcome')],
|
||||
expanded: false,
|
||||
expandedOutcomes: Set(),
|
||||
onExpansionChange: () => {},
|
||||
|
@ -81,27 +59,13 @@ const defaultProps = (props = {}) => ({
|
|||
})
|
||||
|
||||
it('renders the OutcomeGroup component', () => {
|
||||
const wrapper = shallow(<OutcomeGroup {...defaultProps()} />)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
})
|
||||
|
||||
describe('header', () => {
|
||||
it('includes the outcome group name', () => {
|
||||
const wrapper = shallow(<OutcomeGroup {...defaultProps()} />)
|
||||
const header = wrapper.find('ToggleGroup')
|
||||
const summary = render(header.prop('summary'))
|
||||
expect(summary.text()).toMatch('My group')
|
||||
})
|
||||
const {getByText} = render(<OutcomeGroup {...defaultProps()} />)
|
||||
expect(getByText('My group')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('includes the individual outcomes', () => {
|
||||
const wrapper = shallow(<OutcomeGroup {...defaultProps()} />)
|
||||
expect(wrapper.find('Outcome')).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('renders correctly expanded', () => {
|
||||
const wrapper = shallow(<OutcomeGroup {...defaultProps()} expanded />)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
const {getByText} = render(<OutcomeGroup {...defaultProps()} expanded />)
|
||||
expect(getByText('My outcome')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('renders outcomes in alphabetical order by title', () => {
|
||||
|
@ -113,21 +77,22 @@ it('renders outcomes in alphabetical order by title', () => {
|
|||
outcome(4, 'Aerosmith')
|
||||
]
|
||||
})
|
||||
const wrapper = shallow(<OutcomeGroup {...props} />)
|
||||
const outcomes = wrapper.find('Outcome')
|
||||
const {getAllByRole} = render(<OutcomeGroup {...props} expanded />)
|
||||
const outcomes = getAllByRole('listitem')
|
||||
expect(outcomes).toHaveLength(4)
|
||||
expect(outcomes.get(0).props.outcome.title).toEqual('Aardvark')
|
||||
expect(outcomes.get(1).props.outcome.title).toEqual('abba')
|
||||
expect(outcomes.get(2).props.outcome.title).toEqual('Aerosmith')
|
||||
expect(outcomes.get(3).props.outcome.title).toEqual('ZZ Top')
|
||||
expect(within(outcomes[0]).getByText('Aardvark')).not.toBeNull()
|
||||
expect(within(outcomes[1]).getByText('abba')).not.toBeNull()
|
||||
expect(within(outcomes[2]).getByText('Aerosmith')).not.toBeNull()
|
||||
expect(within(outcomes[3]).getByText('ZZ Top')).not.toBeNull()
|
||||
})
|
||||
|
||||
describe('handleToggle()', () => {
|
||||
it('calls the correct onExpansionChange callback', () => {
|
||||
const props = defaultProps()
|
||||
props.onExpansionChange = jest.fn()
|
||||
const wrapper = shallow(<OutcomeGroup {...props} />)
|
||||
wrapper.instance().handleToggle(null, true)
|
||||
const {getByRole} = render(<OutcomeGroup {...props} />)
|
||||
const button = getByRole('button')
|
||||
fireEvent.click(button)
|
||||
expect(props.onExpansionChange).toHaveBeenCalledWith('group', 10, true)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {shallow} from 'enzyme'
|
||||
import {render, fireEvent, within} from '@testing-library/react'
|
||||
import OutcomePopover from '../OutcomePopover'
|
||||
|
||||
const time1 = new Date(Date.UTC(2018, 1, 1, 7, 1, 0))
|
||||
const time2 = new Date(Date.UTC(2018, 1, 1, 8, 1, 0))
|
||||
const time1 = new Date('1995-12-17T03:24:00Z')
|
||||
const time2 = new Date('1999-03-11T12:20:00Z')
|
||||
|
||||
const defaultProps = (props = {}) => ({
|
||||
outcome: {
|
||||
|
@ -33,7 +33,10 @@ const defaultProps = (props = {}) => ({
|
|||
points_possible: 5,
|
||||
calculation_method: 'highest',
|
||||
score: 3,
|
||||
ratings: [{description: 'My first rating'}, {description: 'My second rating'}],
|
||||
ratings: [
|
||||
{description: 'My first rating', mastery: true},
|
||||
{description: 'My second rating', mastery: false}
|
||||
],
|
||||
results: [
|
||||
{
|
||||
id: 1,
|
||||
|
@ -66,69 +69,90 @@ const defaultProps = (props = {}) => ({
|
|||
},
|
||||
outcomeProficiency: {
|
||||
ratings: [
|
||||
{color: 'blue', description: 'I am blue', points: 10},
|
||||
{color: 'green', description: 'I am Groot', points: 5},
|
||||
{color: 'red', description: 'I am red', points: 0}
|
||||
{color: 'blue', description: 'I am blue', points: 10, mastery: false},
|
||||
{color: 'green', description: 'I am Groot', points: 5, mastery: true},
|
||||
{color: 'red', description: 'I am red', points: 0, mastery: false}
|
||||
]
|
||||
},
|
||||
...props
|
||||
})
|
||||
|
||||
it('renders the OutcomePopover component', () => {
|
||||
const wrapper = shallow(<OutcomePopover {...defaultProps()} />)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
const {getByText} = render(<OutcomePopover {...defaultProps()} />)
|
||||
expect(getByText(/Click to expand/)).not.toBeNull()
|
||||
})
|
||||
|
||||
it('renders correctly with no results', () => {
|
||||
const props = defaultProps()
|
||||
props.outcome.results = []
|
||||
const wrapper = shallow(<OutcomePopover {...props} />)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
describe('modal mode', () => {
|
||||
it('shows details on click', () => {
|
||||
const {baseElement, getByRole} = render(<OutcomePopover {...defaultProps()} />)
|
||||
const button = getByRole('button')
|
||||
fireEvent.click(button)
|
||||
expect(within(baseElement).getByText('Calculation Method')).not.toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
it('renders correctly with no custom outcomeProficiency', () => {
|
||||
const props = defaultProps()
|
||||
props.outcomeProficiency = null
|
||||
const wrapper = shallow(<OutcomePopover {...props} />)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('properly expands details for screenreader users', () => {
|
||||
const props = defaultProps()
|
||||
const wrapper = shallow(<OutcomePopover {...props} />)
|
||||
expect(wrapper.state('linkClicked')).toEqual(false)
|
||||
wrapper.find('Link').simulate('click')
|
||||
expect(wrapper.state('linkClicked')).toEqual(true)
|
||||
})
|
||||
|
||||
describe('latestTime', () => {
|
||||
it('properly returns the most recent submission time', () => {
|
||||
const props = defaultProps()
|
||||
const wrapper = shallow(<OutcomePopover {...props} />)
|
||||
expect(wrapper.instance().latestTime()).toEqual(time1)
|
||||
describe('popover mode', () => {
|
||||
it('shows details on click', () => {
|
||||
const {baseElement, getByRole} = render(
|
||||
<OutcomePopover {...defaultProps()} breakpoints={{miniTablet: true}} />
|
||||
)
|
||||
const button = getByRole('button')
|
||||
fireEvent.click(button)
|
||||
expect(within(baseElement).getByText('Calculation Method')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('properly returns nothing when there are no results', () => {
|
||||
it('shows details on hover', () => {
|
||||
const {baseElement, getByRole} = render(
|
||||
<OutcomePopover {...defaultProps()} breakpoints={{miniTablet: true}} />
|
||||
)
|
||||
const button = getByRole('button')
|
||||
fireEvent.mouseEnter(button)
|
||||
expect(within(baseElement).getByText('Calculation Method')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('removes details on leave', () => {
|
||||
const {baseElement, getByRole} = render(
|
||||
<OutcomePopover {...defaultProps()} breakpoints={{miniTablet: true}} />
|
||||
)
|
||||
const button = getByRole('button')
|
||||
fireEvent.mouseEnter(button)
|
||||
fireEvent.mouseLeave(button)
|
||||
expect(within(baseElement).queryByText('Calculation Method')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('latest time', () => {
|
||||
it('renders correctly with no results', () => {
|
||||
const props = defaultProps()
|
||||
props.outcome.results = []
|
||||
const wrapper = shallow(<OutcomePopover {...props} />)
|
||||
expect(wrapper.instance().latestTime()).toBeNull()
|
||||
const {baseElement, getByRole} = render(<OutcomePopover {...props} />)
|
||||
const button = getByRole('button')
|
||||
fireEvent.click(button)
|
||||
expect(within(baseElement).getByText('Last Assessment: No submissions')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('properly returns the most recent submission time', () => {
|
||||
const {baseElement, getByRole} = render(<OutcomePopover {...defaultProps()} />)
|
||||
const button = getByRole('button')
|
||||
fireEvent.click(button)
|
||||
expect(within(baseElement).getByText(/Mar 11/)).not.toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSelectedRating', () => {
|
||||
it('properly returns the custom proficiency level', () => {
|
||||
const props = defaultProps()
|
||||
const wrapper = shallow(<OutcomePopover {...props} />)
|
||||
const rating = wrapper.instance().getSelectedRating()
|
||||
expect(rating.description).toEqual('I am Groot')
|
||||
describe('selected rating', () => {
|
||||
it('renders custom outcomeProficiency', () => {
|
||||
const {baseElement, getByRole} = render(<OutcomePopover {...defaultProps()} />)
|
||||
const button = getByRole('button')
|
||||
fireEvent.click(button)
|
||||
expect(within(baseElement).getByText('I am Groot')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('properly returns the default proficiency level', () => {
|
||||
it('renders correct last assessment time with no custom outcomeProficiency', () => {
|
||||
const props = defaultProps()
|
||||
props.outcomeProficiency = null
|
||||
const wrapper = shallow(<OutcomePopover {...props} />)
|
||||
const rating = wrapper.instance().getSelectedRating()
|
||||
expect(rating.description).toEqual('Meets Mastery')
|
||||
const {baseElement, getByRole} = render(<OutcomePopover {...props} />)
|
||||
const button = getByRole('button')
|
||||
fireEvent.click(button)
|
||||
expect(within(baseElement).getByText('Meets Mastery')).not.toBeNull()
|
||||
})
|
||||
})
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,251 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders correctly expanded 1`] = `
|
||||
<View
|
||||
as="div"
|
||||
borderColor="default"
|
||||
className="outcomeGroup"
|
||||
debug={false}
|
||||
display="auto"
|
||||
focusColor="info"
|
||||
focusPosition="offset"
|
||||
focused={false}
|
||||
overflowX="visible"
|
||||
overflowY="visible"
|
||||
position="static"
|
||||
shouldAnimateFocus={true}
|
||||
>
|
||||
<ToggleGroup
|
||||
as="span"
|
||||
border={true}
|
||||
defaultExpanded={false}
|
||||
elementRef={[Function]}
|
||||
expanded={true}
|
||||
icon={[Function]}
|
||||
iconExpanded={[Function]}
|
||||
onToggle={[Function]}
|
||||
size="medium"
|
||||
summary={
|
||||
<Flex
|
||||
as="span"
|
||||
direction="row"
|
||||
elementRef={[Function]}
|
||||
inline={false}
|
||||
justifyItems="space-between"
|
||||
visualDebug={false}
|
||||
wrapItems={false}
|
||||
>
|
||||
<FlexItem
|
||||
as="span"
|
||||
elementRef={[Function]}
|
||||
grow={true}
|
||||
padding="0 x-small 0 0"
|
||||
shrink={false}
|
||||
size="0"
|
||||
>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="large"
|
||||
weight="bold"
|
||||
wrap="normal"
|
||||
>
|
||||
<TruncateWithTooltip>
|
||||
My group
|
||||
</TruncateWithTooltip>
|
||||
</Text>
|
||||
</FlexItem>
|
||||
<FlexItem
|
||||
as="span"
|
||||
elementRef={[Function]}
|
||||
grow={false}
|
||||
shrink={false}
|
||||
>
|
||||
<Pill
|
||||
text="0 of 1 Mastered"
|
||||
variant="default"
|
||||
/>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
}
|
||||
toggleLabel="Toggle outcomes for My group"
|
||||
transition={true}
|
||||
>
|
||||
<List
|
||||
as="ul"
|
||||
delimiter="solid"
|
||||
margin="none"
|
||||
size="medium"
|
||||
variant="unstyled"
|
||||
>
|
||||
<ListItem
|
||||
key="1"
|
||||
margin="0"
|
||||
>
|
||||
<Outcome
|
||||
expanded={false}
|
||||
onExpansionChange={[Function]}
|
||||
outcome={
|
||||
Object {
|
||||
"calculation_method": "highest",
|
||||
"expansionId": 100,
|
||||
"id": 1,
|
||||
"mastered": false,
|
||||
"mastery_points": 3,
|
||||
"points_possible": 5,
|
||||
"ratings": Array [
|
||||
Object {
|
||||
"description": "My first rating",
|
||||
},
|
||||
Object {
|
||||
"description": "My second rating",
|
||||
},
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"assignment": Object {
|
||||
"html_url": "http://foo",
|
||||
"id": 1,
|
||||
"name": "My assignment",
|
||||
"submission_types": "online_quiz",
|
||||
},
|
||||
"id": 1,
|
||||
"percent": 0.1,
|
||||
"score": 1,
|
||||
},
|
||||
],
|
||||
"title": "My outcome",
|
||||
}
|
||||
}
|
||||
outcomeProficiency={null}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</ToggleGroup>
|
||||
</View>
|
||||
`;
|
||||
|
||||
exports[`renders the OutcomeGroup component 1`] = `
|
||||
<View
|
||||
as="div"
|
||||
borderColor="default"
|
||||
className="outcomeGroup"
|
||||
debug={false}
|
||||
display="auto"
|
||||
focusColor="info"
|
||||
focusPosition="offset"
|
||||
focused={false}
|
||||
overflowX="visible"
|
||||
overflowY="visible"
|
||||
position="static"
|
||||
shouldAnimateFocus={true}
|
||||
>
|
||||
<ToggleGroup
|
||||
as="span"
|
||||
border={true}
|
||||
defaultExpanded={false}
|
||||
elementRef={[Function]}
|
||||
expanded={false}
|
||||
icon={[Function]}
|
||||
iconExpanded={[Function]}
|
||||
onToggle={[Function]}
|
||||
size="medium"
|
||||
summary={
|
||||
<Flex
|
||||
as="span"
|
||||
direction="row"
|
||||
elementRef={[Function]}
|
||||
inline={false}
|
||||
justifyItems="space-between"
|
||||
visualDebug={false}
|
||||
wrapItems={false}
|
||||
>
|
||||
<FlexItem
|
||||
as="span"
|
||||
elementRef={[Function]}
|
||||
grow={true}
|
||||
padding="0 x-small 0 0"
|
||||
shrink={false}
|
||||
size="0"
|
||||
>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="large"
|
||||
weight="bold"
|
||||
wrap="normal"
|
||||
>
|
||||
<TruncateWithTooltip>
|
||||
My group
|
||||
</TruncateWithTooltip>
|
||||
</Text>
|
||||
</FlexItem>
|
||||
<FlexItem
|
||||
as="span"
|
||||
elementRef={[Function]}
|
||||
grow={false}
|
||||
shrink={false}
|
||||
>
|
||||
<Pill
|
||||
text="0 of 1 Mastered"
|
||||
variant="default"
|
||||
/>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
}
|
||||
toggleLabel="Toggle outcomes for My group"
|
||||
transition={true}
|
||||
>
|
||||
<List
|
||||
as="ul"
|
||||
delimiter="solid"
|
||||
margin="none"
|
||||
size="medium"
|
||||
variant="unstyled"
|
||||
>
|
||||
<ListItem
|
||||
key="1"
|
||||
margin="0"
|
||||
>
|
||||
<Outcome
|
||||
expanded={false}
|
||||
onExpansionChange={[Function]}
|
||||
outcome={
|
||||
Object {
|
||||
"calculation_method": "highest",
|
||||
"expansionId": 100,
|
||||
"id": 1,
|
||||
"mastered": false,
|
||||
"mastery_points": 3,
|
||||
"points_possible": 5,
|
||||
"ratings": Array [
|
||||
Object {
|
||||
"description": "My first rating",
|
||||
},
|
||||
Object {
|
||||
"description": "My second rating",
|
||||
},
|
||||
],
|
||||
"results": Array [
|
||||
Object {
|
||||
"assignment": Object {
|
||||
"html_url": "http://foo",
|
||||
"id": 1,
|
||||
"name": "My assignment",
|
||||
"submission_types": "online_quiz",
|
||||
},
|
||||
"id": 1,
|
||||
"percent": 0.1,
|
||||
"score": 1,
|
||||
},
|
||||
],
|
||||
"title": "My outcome",
|
||||
}
|
||||
}
|
||||
outcomeProficiency={null}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</ToggleGroup>
|
||||
</View>
|
||||
`;
|
|
@ -1,655 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders correctly with no custom outcomeProficiency 1`] = `
|
||||
<span>
|
||||
<Popover
|
||||
alignArrow={false}
|
||||
constrain="window"
|
||||
contentRef={[Function]}
|
||||
defaultFocusElement={null}
|
||||
defaultShow={false}
|
||||
insertAt="bottom"
|
||||
label={null}
|
||||
liveRegion={null}
|
||||
mountNode={null}
|
||||
offsetX={0}
|
||||
offsetY={0}
|
||||
on={
|
||||
Array [
|
||||
"hover",
|
||||
"click",
|
||||
]
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onDismiss={[Function]}
|
||||
onFocus={[Function]}
|
||||
onMouseOut={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
onPositionChanged={[Function]}
|
||||
onPositioned={[Function]}
|
||||
onShow={[Function]}
|
||||
onToggle={[Function]}
|
||||
placement="bottom"
|
||||
positionTarget={null}
|
||||
shadow="resting"
|
||||
shouldCloseOnDocumentClick={true}
|
||||
shouldCloseOnEscape={true}
|
||||
shouldContainFocus={true}
|
||||
shouldFocusContentOnTriggerBlur={false}
|
||||
shouldRenderOffscreen={false}
|
||||
shouldReturnFocus={true}
|
||||
show={false}
|
||||
stacking="topmost"
|
||||
trackPosition={true}
|
||||
variant="default"
|
||||
withArrow={true}
|
||||
>
|
||||
<PopoverTrigger>
|
||||
<Link
|
||||
color="link"
|
||||
iconPlacement="start"
|
||||
isWithinText={true}
|
||||
onClick={[Function]}
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
>
|
||||
<span
|
||||
style={
|
||||
Object {
|
||||
"color": "black",
|
||||
}
|
||||
}
|
||||
>
|
||||
<IconInfoLine />
|
||||
</span>
|
||||
<span>
|
||||
<ScreenReaderContent
|
||||
as="span"
|
||||
>
|
||||
Click to expand outcome details
|
||||
</ScreenReaderContent>
|
||||
</span>
|
||||
</Link>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<View
|
||||
as="div"
|
||||
borderColor="default"
|
||||
debug={false}
|
||||
display="auto"
|
||||
focusColor="info"
|
||||
focusPosition="offset"
|
||||
focused={false}
|
||||
maxWidth="30rem"
|
||||
overflowX="visible"
|
||||
overflowY="visible"
|
||||
padding="large"
|
||||
position="static"
|
||||
shouldAnimateFocus={true}
|
||||
>
|
||||
<CloseButton
|
||||
as="button"
|
||||
cursor="pointer"
|
||||
margin="0"
|
||||
offset="x-small"
|
||||
onClick={[Function]}
|
||||
placement="end"
|
||||
size="small"
|
||||
type="button"
|
||||
>
|
||||
Click to close outcome details popover
|
||||
</CloseButton>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
wrap="normal"
|
||||
>
|
||||
<Flex
|
||||
alignItems="stretch"
|
||||
as="span"
|
||||
direction="row"
|
||||
elementRef={[Function]}
|
||||
inline={false}
|
||||
justifyItems="space-between"
|
||||
visualDebug={false}
|
||||
wrapItems={false}
|
||||
>
|
||||
<FlexItem
|
||||
as="span"
|
||||
elementRef={[Function]}
|
||||
grow={true}
|
||||
shrink={true}
|
||||
>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"overflowWrap": "break-word",
|
||||
"wordWrap": "break-word",
|
||||
}
|
||||
}
|
||||
>
|
||||
My outcome
|
||||
</div>
|
||||
<div>
|
||||
Last Assessment:
|
||||
<DatetimeDisplay
|
||||
datetime={2018-02-01T07:01:00.000Z}
|
||||
format="%b %d, %l:%M %p"
|
||||
/>
|
||||
</div>
|
||||
</FlexItem>
|
||||
<FlexItem
|
||||
align="stretch"
|
||||
as="span"
|
||||
elementRef={[Function]}
|
||||
grow={true}
|
||||
shrink={true}
|
||||
>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
weight="bold"
|
||||
wrap="normal"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"color": "#00AC18",
|
||||
"textAlign": "end",
|
||||
}
|
||||
}
|
||||
>
|
||||
Meets Mastery
|
||||
</div>
|
||||
</div>
|
||||
</Text>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
<hr
|
||||
role="presentation"
|
||||
/>
|
||||
<div>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
weight="bold"
|
||||
wrap="normal"
|
||||
>
|
||||
Calculation Method
|
||||
</Text>
|
||||
<div>
|
||||
Highest Score
|
||||
</div>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"padding": "0.5rem 0 0 0",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
weight="bold"
|
||||
wrap="normal"
|
||||
>
|
||||
Example
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
Mastery score reflects the highest score of a graded assignment or quiz.
|
||||
</div>
|
||||
<div>
|
||||
1- Item Scores: 1, 4, 2, 3
|
||||
</div>
|
||||
<div>
|
||||
2- Final Score: 4
|
||||
</div>
|
||||
</div>
|
||||
</Text>
|
||||
</View>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</span>
|
||||
`;
|
||||
|
||||
exports[`renders correctly with no results 1`] = `
|
||||
<span>
|
||||
<Popover
|
||||
alignArrow={false}
|
||||
constrain="window"
|
||||
contentRef={[Function]}
|
||||
defaultFocusElement={null}
|
||||
defaultShow={false}
|
||||
insertAt="bottom"
|
||||
label={null}
|
||||
liveRegion={null}
|
||||
mountNode={null}
|
||||
offsetX={0}
|
||||
offsetY={0}
|
||||
on={
|
||||
Array [
|
||||
"hover",
|
||||
"click",
|
||||
]
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onDismiss={[Function]}
|
||||
onFocus={[Function]}
|
||||
onMouseOut={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
onPositionChanged={[Function]}
|
||||
onPositioned={[Function]}
|
||||
onShow={[Function]}
|
||||
onToggle={[Function]}
|
||||
placement="bottom"
|
||||
positionTarget={null}
|
||||
shadow="resting"
|
||||
shouldCloseOnDocumentClick={true}
|
||||
shouldCloseOnEscape={true}
|
||||
shouldContainFocus={true}
|
||||
shouldFocusContentOnTriggerBlur={false}
|
||||
shouldRenderOffscreen={false}
|
||||
shouldReturnFocus={true}
|
||||
show={false}
|
||||
stacking="topmost"
|
||||
trackPosition={true}
|
||||
variant="default"
|
||||
withArrow={true}
|
||||
>
|
||||
<PopoverTrigger>
|
||||
<Link
|
||||
color="link"
|
||||
iconPlacement="start"
|
||||
isWithinText={true}
|
||||
onClick={[Function]}
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
>
|
||||
<span
|
||||
style={
|
||||
Object {
|
||||
"color": "black",
|
||||
}
|
||||
}
|
||||
>
|
||||
<IconInfoLine />
|
||||
</span>
|
||||
<span>
|
||||
<ScreenReaderContent
|
||||
as="span"
|
||||
>
|
||||
Click to expand outcome details
|
||||
</ScreenReaderContent>
|
||||
</span>
|
||||
</Link>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<View
|
||||
as="div"
|
||||
borderColor="default"
|
||||
debug={false}
|
||||
display="auto"
|
||||
focusColor="info"
|
||||
focusPosition="offset"
|
||||
focused={false}
|
||||
maxWidth="30rem"
|
||||
overflowX="visible"
|
||||
overflowY="visible"
|
||||
padding="large"
|
||||
position="static"
|
||||
shouldAnimateFocus={true}
|
||||
>
|
||||
<CloseButton
|
||||
as="button"
|
||||
cursor="pointer"
|
||||
margin="0"
|
||||
offset="x-small"
|
||||
onClick={[Function]}
|
||||
placement="end"
|
||||
size="small"
|
||||
type="button"
|
||||
>
|
||||
Click to close outcome details popover
|
||||
</CloseButton>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
wrap="normal"
|
||||
>
|
||||
<Flex
|
||||
alignItems="stretch"
|
||||
as="span"
|
||||
direction="row"
|
||||
elementRef={[Function]}
|
||||
inline={false}
|
||||
justifyItems="space-between"
|
||||
visualDebug={false}
|
||||
wrapItems={false}
|
||||
>
|
||||
<FlexItem
|
||||
as="span"
|
||||
elementRef={[Function]}
|
||||
grow={true}
|
||||
shrink={true}
|
||||
>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"overflowWrap": "break-word",
|
||||
"wordWrap": "break-word",
|
||||
}
|
||||
}
|
||||
>
|
||||
My outcome
|
||||
</div>
|
||||
<div>
|
||||
Last Assessment:
|
||||
No submissions
|
||||
</div>
|
||||
</FlexItem>
|
||||
<FlexItem
|
||||
align="stretch"
|
||||
as="span"
|
||||
elementRef={[Function]}
|
||||
grow={true}
|
||||
shrink={true}
|
||||
>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
weight="bold"
|
||||
wrap="normal"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"color": "#green",
|
||||
"textAlign": "end",
|
||||
}
|
||||
}
|
||||
>
|
||||
I am Groot
|
||||
</div>
|
||||
</div>
|
||||
</Text>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
<hr
|
||||
role="presentation"
|
||||
/>
|
||||
<div>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
weight="bold"
|
||||
wrap="normal"
|
||||
>
|
||||
Calculation Method
|
||||
</Text>
|
||||
<div>
|
||||
Highest Score
|
||||
</div>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"padding": "0.5rem 0 0 0",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
weight="bold"
|
||||
wrap="normal"
|
||||
>
|
||||
Example
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
Mastery score reflects the highest score of a graded assignment or quiz.
|
||||
</div>
|
||||
<div>
|
||||
1- Item Scores: 1, 4, 2, 3
|
||||
</div>
|
||||
<div>
|
||||
2- Final Score: 4
|
||||
</div>
|
||||
</div>
|
||||
</Text>
|
||||
</View>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</span>
|
||||
`;
|
||||
|
||||
exports[`renders the OutcomePopover component 1`] = `
|
||||
<span>
|
||||
<Popover
|
||||
alignArrow={false}
|
||||
constrain="window"
|
||||
contentRef={[Function]}
|
||||
defaultFocusElement={null}
|
||||
defaultShow={false}
|
||||
insertAt="bottom"
|
||||
label={null}
|
||||
liveRegion={null}
|
||||
mountNode={null}
|
||||
offsetX={0}
|
||||
offsetY={0}
|
||||
on={
|
||||
Array [
|
||||
"hover",
|
||||
"click",
|
||||
]
|
||||
}
|
||||
onBlur={[Function]}
|
||||
onClick={[Function]}
|
||||
onDismiss={[Function]}
|
||||
onFocus={[Function]}
|
||||
onMouseOut={[Function]}
|
||||
onMouseOver={[Function]}
|
||||
onPositionChanged={[Function]}
|
||||
onPositioned={[Function]}
|
||||
onShow={[Function]}
|
||||
onToggle={[Function]}
|
||||
placement="bottom"
|
||||
positionTarget={null}
|
||||
shadow="resting"
|
||||
shouldCloseOnDocumentClick={true}
|
||||
shouldCloseOnEscape={true}
|
||||
shouldContainFocus={true}
|
||||
shouldFocusContentOnTriggerBlur={false}
|
||||
shouldRenderOffscreen={false}
|
||||
shouldReturnFocus={true}
|
||||
show={false}
|
||||
stacking="topmost"
|
||||
trackPosition={true}
|
||||
variant="default"
|
||||
withArrow={true}
|
||||
>
|
||||
<PopoverTrigger>
|
||||
<Link
|
||||
color="link"
|
||||
iconPlacement="start"
|
||||
isWithinText={true}
|
||||
onClick={[Function]}
|
||||
onMouseEnter={[Function]}
|
||||
onMouseLeave={[Function]}
|
||||
>
|
||||
<span
|
||||
style={
|
||||
Object {
|
||||
"color": "black",
|
||||
}
|
||||
}
|
||||
>
|
||||
<IconInfoLine />
|
||||
</span>
|
||||
<span>
|
||||
<ScreenReaderContent
|
||||
as="span"
|
||||
>
|
||||
Click to expand outcome details
|
||||
</ScreenReaderContent>
|
||||
</span>
|
||||
</Link>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent>
|
||||
<View
|
||||
as="div"
|
||||
borderColor="default"
|
||||
debug={false}
|
||||
display="auto"
|
||||
focusColor="info"
|
||||
focusPosition="offset"
|
||||
focused={false}
|
||||
maxWidth="30rem"
|
||||
overflowX="visible"
|
||||
overflowY="visible"
|
||||
padding="large"
|
||||
position="static"
|
||||
shouldAnimateFocus={true}
|
||||
>
|
||||
<CloseButton
|
||||
as="button"
|
||||
cursor="pointer"
|
||||
margin="0"
|
||||
offset="x-small"
|
||||
onClick={[Function]}
|
||||
placement="end"
|
||||
size="small"
|
||||
type="button"
|
||||
>
|
||||
Click to close outcome details popover
|
||||
</CloseButton>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
wrap="normal"
|
||||
>
|
||||
<Flex
|
||||
alignItems="stretch"
|
||||
as="span"
|
||||
direction="row"
|
||||
elementRef={[Function]}
|
||||
inline={false}
|
||||
justifyItems="space-between"
|
||||
visualDebug={false}
|
||||
wrapItems={false}
|
||||
>
|
||||
<FlexItem
|
||||
as="span"
|
||||
elementRef={[Function]}
|
||||
grow={true}
|
||||
shrink={true}
|
||||
>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"overflowWrap": "break-word",
|
||||
"wordWrap": "break-word",
|
||||
}
|
||||
}
|
||||
>
|
||||
My outcome
|
||||
</div>
|
||||
<div>
|
||||
Last Assessment:
|
||||
<DatetimeDisplay
|
||||
datetime={2018-02-01T07:01:00.000Z}
|
||||
format="%b %d, %l:%M %p"
|
||||
/>
|
||||
</div>
|
||||
</FlexItem>
|
||||
<FlexItem
|
||||
align="stretch"
|
||||
as="span"
|
||||
elementRef={[Function]}
|
||||
grow={true}
|
||||
shrink={true}
|
||||
>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
weight="bold"
|
||||
wrap="normal"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"color": "#green",
|
||||
"textAlign": "end",
|
||||
}
|
||||
}
|
||||
>
|
||||
I am Groot
|
||||
</div>
|
||||
</div>
|
||||
</Text>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
<hr
|
||||
role="presentation"
|
||||
/>
|
||||
<div>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
weight="bold"
|
||||
wrap="normal"
|
||||
>
|
||||
Calculation Method
|
||||
</Text>
|
||||
<div>
|
||||
Highest Score
|
||||
</div>
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"padding": "0.5rem 0 0 0",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="small"
|
||||
weight="bold"
|
||||
wrap="normal"
|
||||
>
|
||||
Example
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
Mastery score reflects the highest score of a graded assignment or quiz.
|
||||
</div>
|
||||
<div>
|
||||
1- Item Scores: 1, 4, 2, 3
|
||||
</div>
|
||||
<div>
|
||||
2- Final Score: 4
|
||||
</div>
|
||||
</div>
|
||||
</Text>
|
||||
</View>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</span>
|
||||
`;
|
|
@ -1,59 +1,56 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`properly renders the UnassessedAssignment component 1`] = `
|
||||
<ListItem
|
||||
<View
|
||||
borderColor="default"
|
||||
debug={false}
|
||||
display="block"
|
||||
focusColor="info"
|
||||
focusPosition="offset"
|
||||
focused={false}
|
||||
key="1"
|
||||
overflowX="visible"
|
||||
overflowY="visible"
|
||||
padding="small"
|
||||
position="static"
|
||||
shouldAnimateFocus={true}
|
||||
>
|
||||
<View
|
||||
borderColor="default"
|
||||
debug={false}
|
||||
display="block"
|
||||
focusColor="info"
|
||||
focusPosition="offset"
|
||||
focused={false}
|
||||
overflowX="visible"
|
||||
overflowY="visible"
|
||||
padding="small"
|
||||
position="static"
|
||||
shouldAnimateFocus={true}
|
||||
<ApplyTheme
|
||||
immutable={false}
|
||||
theme={
|
||||
Object {
|
||||
Symbol(Button__MTEzMjky): Object {
|
||||
"fontWeight": "700",
|
||||
"linkColor": "#68777D",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<ApplyTheme
|
||||
immutable={false}
|
||||
<Button
|
||||
as="button"
|
||||
cursor="pointer"
|
||||
display="inline-block"
|
||||
elementRef={[Function]}
|
||||
href="www.example.com"
|
||||
icon={[Function]}
|
||||
margin="0"
|
||||
size="medium"
|
||||
textAlign="center"
|
||||
theme={
|
||||
Object {
|
||||
Symbol(Button__MTEzMjky): Object {
|
||||
"fontWeight": "700",
|
||||
"linkColor": "#68777D",
|
||||
},
|
||||
"mediumHeight": "normal",
|
||||
"mediumPadding": "0",
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
variant="link"
|
||||
withBackground={true}
|
||||
>
|
||||
<Button
|
||||
as="button"
|
||||
cursor="pointer"
|
||||
display="inline-block"
|
||||
elementRef={[Function]}
|
||||
href="www.example.com"
|
||||
icon={[Function]}
|
||||
margin="0"
|
||||
size="medium"
|
||||
textAlign="center"
|
||||
theme={
|
||||
Object {
|
||||
"mediumHeight": "normal",
|
||||
"mediumPadding": "0",
|
||||
}
|
||||
}
|
||||
type="button"
|
||||
variant="link"
|
||||
withBackground={true}
|
||||
>
|
||||
example
|
||||
(
|
||||
Not yet assessed
|
||||
)
|
||||
</Button>
|
||||
</ApplyTheme>
|
||||
</View>
|
||||
</ListItem>
|
||||
example
|
||||
(
|
||||
Not yet assessed
|
||||
)
|
||||
</Button>
|
||||
</ApplyTheme>
|
||||
</View>
|
||||
`;
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders the component 1`] = `
|
||||
<Flex
|
||||
alignItems="center"
|
||||
as="span"
|
||||
direction="row"
|
||||
elementRef={[Function]}
|
||||
inline={false}
|
||||
justifyItems="center"
|
||||
padding="medium"
|
||||
visualDebug={false}
|
||||
wrapItems={false}
|
||||
>
|
||||
<FlexItem
|
||||
as="span"
|
||||
elementRef={[Function]}
|
||||
grow={false}
|
||||
shrink={false}
|
||||
>
|
||||
<Spinner
|
||||
as="div"
|
||||
renderTitle="Loading outcome results"
|
||||
size="large"
|
||||
variant="default"
|
||||
/>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
`;
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
import React from 'react'
|
||||
import {mount, shallow} from 'enzyme'
|
||||
import {render, within} from '@testing-library/react'
|
||||
import {Set} from 'immutable'
|
||||
import IndividualStudentMastery from '../index'
|
||||
import fetchOutcomes from '../fetchOutcomes'
|
||||
|
@ -35,33 +36,25 @@ const props = {
|
|||
}
|
||||
|
||||
it('renders the component', () => {
|
||||
const wrapper = shallow(<IndividualStudentMastery {...props} />)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
const {getByText} = render(<IndividualStudentMastery {...props} />)
|
||||
expect(getByText('Loading outcome results')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('attempts to load when mounted', () => {
|
||||
mount(<IndividualStudentMastery {...props} />)
|
||||
render(<IndividualStudentMastery {...props} />)
|
||||
expect(fetchOutcomes).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('renders loading before promise resolves', () => {
|
||||
fetchOutcomes.mockImplementation(() => new Promise(() => {})) // unresolved promise
|
||||
const wrapper = mount(<IndividualStudentMastery {...props} />)
|
||||
expect(wrapper.find('Spinner')).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('renders error when error occurs during fetch', async () => {
|
||||
fetchOutcomes.mockImplementation(() => Promise.reject(new Error('foo')))
|
||||
const wrapper = mount(<IndividualStudentMastery {...props} />)
|
||||
await wrapper.instance().componentDidMount()
|
||||
expect(wrapper.text()).toMatch('An error occurred')
|
||||
const {findByText} = render(<IndividualStudentMastery {...props} />)
|
||||
expect(await findByText(/An error occurred/)).not.toBeNull()
|
||||
})
|
||||
|
||||
it('renders empty if no groups are returned', async () => {
|
||||
fetchOutcomes.mockImplementation(() => Promise.resolve({outcomeGroups: [], outcomes: []}))
|
||||
const wrapper = mount(<IndividualStudentMastery {...props} />)
|
||||
await wrapper.instance().componentDidMount()
|
||||
expect(wrapper.text()).toMatch('There are no outcomes in the course')
|
||||
const {findByText} = render(<IndividualStudentMastery {...props} />)
|
||||
expect(await findByText(/There are no outcomes in the course/)).not.toBeNull()
|
||||
})
|
||||
|
||||
it('renders outcome groups if they are returned', async () => {
|
||||
|
@ -71,9 +64,8 @@ it('renders outcome groups if they are returned', async () => {
|
|||
outcomes: []
|
||||
})
|
||||
)
|
||||
const wrapper = shallow(<IndividualStudentMastery {...props} />)
|
||||
await wrapper.instance().componentDidMount()
|
||||
expect(wrapper.update().find('OutcomeGroup')).toHaveLength(1)
|
||||
const {findByText} = render(<IndividualStudentMastery {...props} />)
|
||||
expect(await findByText('Group')).not.toBeNull()
|
||||
})
|
||||
|
||||
describe('expand and contract', () => {
|
||||
|
@ -100,6 +92,28 @@ describe('expand and contract', () => {
|
|||
)
|
||||
})
|
||||
|
||||
it('renders outcome groups in alphabetical order by title', async () => {
|
||||
fetchOutcomes.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
outcomeGroups: [
|
||||
{id: 1, title: 'ZZ Top Albums'},
|
||||
{id: 2, title: 'Aerosmith Albums'},
|
||||
{id: 3, title: 'Aardvark Albums'},
|
||||
{id: 4, title: 'abba Albums'}
|
||||
],
|
||||
outcomes: []
|
||||
})
|
||||
)
|
||||
const {findAllByRole} = render(<IndividualStudentMastery {...props} />)
|
||||
const groups = await findAllByRole('listitem')
|
||||
expect(groups).toHaveLength(4)
|
||||
expect(within(groups[0]).getByText('Aardvark Albums')).not.toBeNull()
|
||||
expect(within(groups[1]).getByText('abba Albums')).not.toBeNull()
|
||||
expect(within(groups[2]).getByText('Aerosmith Albums')).not.toBeNull()
|
||||
expect(within(groups[3]).getByText('ZZ Top Albums')).not.toBeNull()
|
||||
})
|
||||
|
||||
// legacy enzyme tests
|
||||
it('toggles elements to expanded when event fired', async () => {
|
||||
const wrapper = mount(<IndividualStudentMastery {...props} />)
|
||||
await wrapper.instance().componentDidMount()
|
||||
|
@ -147,25 +161,3 @@ describe('expand and contract', () => {
|
|||
expect(props.onExpansionChange).toHaveBeenLastCalledWith(false, true)
|
||||
})
|
||||
})
|
||||
|
||||
it('renders outcome groups in alphabetical order by title', async () => {
|
||||
fetchOutcomes.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
outcomeGroups: [
|
||||
{id: 1, title: 'ZZ Top Albums'},
|
||||
{id: 2, title: 'Aerosmith Albums'},
|
||||
{id: 3, title: 'Aardvark Albums'},
|
||||
{id: 4, title: 'abba Albums'}
|
||||
],
|
||||
outcomes: []
|
||||
})
|
||||
)
|
||||
const wrapper = shallow(<IndividualStudentMastery {...props} />)
|
||||
await wrapper.instance().componentDidMount()
|
||||
const groups = wrapper.find('OutcomeGroup')
|
||||
expect(groups).toHaveLength(4)
|
||||
expect(groups.get(0).props.outcomeGroup.title).toEqual('Aardvark Albums')
|
||||
expect(groups.get(1).props.outcomeGroup.title).toEqual('abba Albums')
|
||||
expect(groups.get(2).props.outcomeGroup.title).toEqual('Aerosmith Albums')
|
||||
expect(groups.get(3).props.outcomeGroup.title).toEqual('ZZ Top Albums')
|
||||
})
|
||||
|
|
|
@ -38,9 +38,18 @@ export const ratingShape = PropTypes.shape({
|
|||
description: PropTypes.string.isRequired
|
||||
})
|
||||
|
||||
export const alignmentShape = PropTypes.shape({
|
||||
assignment_id: PropTypes.string,
|
||||
learning_outcome_id: PropTypes.number,
|
||||
submission_types: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
|
||||
title: PropTypes.string,
|
||||
url: PropTypes.string
|
||||
})
|
||||
|
||||
export const outcomeShape = PropTypes.shape({
|
||||
id: PropTypes.number.isRequired,
|
||||
mastered: PropTypes.bool.isRequired,
|
||||
mastered: PropTypes.bool,
|
||||
assignments: PropTypes.arrayOf(alignmentShape),
|
||||
ratings: PropTypes.arrayOf(ratingShape).isRequired,
|
||||
results: PropTypes.arrayOf(outcomeResultShape).isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (C) 2020 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {Responsive} from '@instructure/ui-responsive'
|
||||
|
||||
// from _breakpoints.scss
|
||||
export const BREAKPOINTS = {
|
||||
miniTablet: {minWidth: '500px'},
|
||||
tablet: {minWidth: '768px'},
|
||||
desktop: {minWidth: '992px'},
|
||||
desktopNavOpen: {minWidth: '1140px'},
|
||||
desktopOnly: {minWidth: '768px'},
|
||||
mobileOnly: {maxWidth: '767px'}
|
||||
}
|
||||
|
||||
const convertMatchesToProp = matches => {
|
||||
const breakpoints = {}
|
||||
matches.forEach(match => (breakpoints[match] = true))
|
||||
return breakpoints
|
||||
}
|
||||
|
||||
const WithBreakpoints = Component => props => {
|
||||
if (window.matchMedia) {
|
||||
return (
|
||||
<Responsive
|
||||
match="media"
|
||||
query={BREAKPOINTS}
|
||||
render={(_addedProps, matches) => (
|
||||
<Component breakpoints={convertMatchesToProp(matches)} {...props} />
|
||||
)}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
return <Component breakpoints={{}} {...props} />
|
||||
}
|
||||
}
|
||||
|
||||
export const breakpointsShape = PropTypes.shape({
|
||||
miniTablet: PropTypes.bool,
|
||||
tablet: PropTypes.bool,
|
||||
desktop: PropTypes.bool,
|
||||
desktopNavOpen: PropTypes.bool,
|
||||
desktopOnly: PropTypes.bool,
|
||||
mobileOnly: PropTypes.bool
|
||||
})
|
||||
|
||||
export default WithBreakpoints
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (C) 2020 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {render} from '@testing-library/react'
|
||||
import WithBreakpoints from '../WithBreakpoints'
|
||||
|
||||
const testWidthQuery = (query, width) => {
|
||||
const minWidth = query.match(/min-width: ([0-9]+)px/)?.[1]
|
||||
const maxWidth = query.match(/max-width: ([0-9]+)px/)?.[1]
|
||||
if (minWidth && width > parseFloat(minWidth)) {
|
||||
return true
|
||||
}
|
||||
if (maxWidth && width < parseFloat(maxWidth)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
describe('WithBreakpoints', () => {
|
||||
const renderer = jest.fn(() => <div>Hello, world!</div>)
|
||||
const Wrapped = WithBreakpoints(renderer)
|
||||
|
||||
let matchMedia
|
||||
const mockWindowWidth = width => {
|
||||
if (window.matchMedia) {
|
||||
throw new Error('cannot mock when window.mediaQuery is defined')
|
||||
}
|
||||
matchMedia = query => ({
|
||||
matches: testWidthQuery(query, width),
|
||||
addListener: Function.prototype,
|
||||
removeListener: Function.prototype
|
||||
})
|
||||
window.matchMedia = matchMedia
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
renderer.mockClear()
|
||||
if (matchMedia) {
|
||||
delete window.matchMedia
|
||||
}
|
||||
})
|
||||
|
||||
describe('without matchMedia defined', () => {
|
||||
it('renders inner component', () => {
|
||||
const {getByText} = render(<Wrapped />)
|
||||
expect(getByText('Hello, world!')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('does not include any breakpoints', () => {
|
||||
render(<Wrapped />)
|
||||
const breakpoints = renderer.mock.calls[0][0].breakpoints
|
||||
expect(Object.keys(breakpoints)).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
describe('with matchMedia defined', () => {
|
||||
it('renders inner component', () => {
|
||||
mockWindowWidth(1)
|
||||
const {getByText} = render(<Wrapped />)
|
||||
expect(getByText('Hello, world!')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('calls inner component once', () => {
|
||||
mockWindowWidth(1)
|
||||
render(<Wrapped />)
|
||||
expect(renderer).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
describe('breakpoints prop', () => {
|
||||
it('includes breakpoints prop', () => {
|
||||
mockWindowWidth(1)
|
||||
render(<Wrapped />)
|
||||
expect(renderer.mock.calls[0][0]).toMatchObject({breakpoints: expect.any(Object)})
|
||||
})
|
||||
|
||||
it('includes correct breakpoints for small screen', () => {
|
||||
mockWindowWidth(1)
|
||||
render(<Wrapped />)
|
||||
const breakpoints = renderer.mock.calls[0][0].breakpoints
|
||||
expect(Object.keys(breakpoints)).toEqual(['mobileOnly'])
|
||||
})
|
||||
|
||||
it('includes miniTablet breakpoint for miniTablet screen', () => {
|
||||
mockWindowWidth(550)
|
||||
render(<Wrapped />)
|
||||
const breakpoints = renderer.mock.calls[0][0].breakpoints
|
||||
expect(Object.keys(breakpoints)).toEqual(['miniTablet', 'mobileOnly'])
|
||||
})
|
||||
|
||||
it('includes tablet breakpoints for tablet screen', () => {
|
||||
mockWindowWidth(800)
|
||||
render(<Wrapped />)
|
||||
const breakpoints = renderer.mock.calls[0][0].breakpoints
|
||||
expect(Object.keys(breakpoints)).toEqual(['miniTablet', 'tablet', 'desktopOnly'])
|
||||
})
|
||||
|
||||
it('includes desktop breakpoints for desktop screen', () => {
|
||||
mockWindowWidth(1000)
|
||||
render(<Wrapped />)
|
||||
const breakpoints = renderer.mock.calls[0][0].breakpoints
|
||||
expect(Object.keys(breakpoints)).toEqual(['miniTablet', 'tablet', 'desktop', 'desktopOnly'])
|
||||
})
|
||||
|
||||
it('includes desktopNavOpen breakpoints for large desktop screen', () => {
|
||||
mockWindowWidth(2000)
|
||||
render(<Wrapped />)
|
||||
const breakpoints = renderer.mock.calls[0][0].breakpoints
|
||||
expect(Object.keys(breakpoints)).toEqual([
|
||||
'miniTablet',
|
||||
'tablet',
|
||||
'desktop',
|
||||
'desktopNavOpen',
|
||||
'desktopOnly'
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
// print button for grades summary page
|
||||
.print-grades {
|
||||
float: direction(right);
|
||||
@media print {
|
||||
display: none;
|
||||
}
|
||||
|
@ -323,12 +322,19 @@ div.rubric-toggle {
|
|||
}
|
||||
|
||||
.outcome-toggles {
|
||||
float: direction(right);
|
||||
position: absolute;
|
||||
#{direction(right)}: 1em;
|
||||
margin-top: -2.3em;
|
||||
text-align: #{direction(right)};
|
||||
margin-top: 0.75rem;
|
||||
|
||||
@include breakpoint(mini-tablet) {
|
||||
float: direction(right);
|
||||
padding-top: 0;
|
||||
position: absolute;
|
||||
#{direction(right)}: 1em;
|
||||
margin-top: -2.3em;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin-#{direction(left)}: 0.5em;
|
||||
margin-#{direction(left)}: 0.75em;
|
||||
}
|
||||
a[class*=icon-]:before, a[class^=icon-]:before {
|
||||
margin: 0;
|
||||
|
|
|
@ -894,6 +894,9 @@ form.ic-Form-group { margin: 0; }
|
|||
.ic-Action-header {
|
||||
margin-bottom: $ic-sp*2;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: start;
|
||||
|
||||
&.ic-Action-header--before-item-groups {
|
||||
margin-bottom: 0;
|
||||
|
@ -902,9 +905,10 @@ form.ic-Form-group { margin: 0; }
|
|||
}
|
||||
|
||||
@include breakpoint(tablet) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
.ic-Action-header__Primary {
|
||||
flex-grow: 1;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {mount, shallow} from 'enzyme'
|
||||
import {mount} from 'enzyme'
|
||||
|
||||
import SelectMenuGroup from 'jsx/grade_summary/SelectMenuGroup'
|
||||
|
||||
|
@ -40,9 +40,15 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
{id: '60', nickname: 'Firebending', url: '/courses/60/grades', gradingPeriodSetId: '4'}
|
||||
]
|
||||
|
||||
const gradingPeriods = [{id: '9', title: 'Fall Semester'}, {id: '12', title: 'Spring Semester'}]
|
||||
const gradingPeriods = [
|
||||
{id: '9', title: 'Fall Semester'},
|
||||
{id: '12', title: 'Spring Semester'}
|
||||
]
|
||||
|
||||
const students = [{id: '7', name: 'Bob Smith'}, {id: '11', name: 'Jane Doe'}]
|
||||
const students = [
|
||||
{id: '7', name: 'Bob Smith'},
|
||||
{id: '11', name: 'Jane Doe'}
|
||||
]
|
||||
|
||||
props = {
|
||||
assignmentSortOptions,
|
||||
|
@ -66,12 +72,12 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
})
|
||||
|
||||
test('renders a student select menu if the students prop has more than 1 student', () => {
|
||||
wrapper = shallow(<SelectMenuGroup {...props} />)
|
||||
strictEqual(wrapper.find('#student_select_menu').length, 1)
|
||||
wrapper = mount(<SelectMenuGroup {...props} />)
|
||||
strictEqual(wrapper.find('SelectMenu#student_select_menu').length, 1)
|
||||
})
|
||||
|
||||
test('does not render a student select menu if the students prop has only 1 student', () => {
|
||||
wrapper = shallow(<SelectMenuGroup {...props} students={[{id: '11', name: 'Jane Doe'}]} />)
|
||||
wrapper = mount(<SelectMenuGroup {...props} students={[{id: '11', name: 'Jane Doe'}]} />)
|
||||
strictEqual(wrapper.find('#student_select_menu').length, 0)
|
||||
})
|
||||
|
||||
|
@ -89,8 +95,8 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
})
|
||||
|
||||
test('renders a grading period select menu if passed any grading periods', () => {
|
||||
wrapper = shallow(<SelectMenuGroup {...props} />)
|
||||
strictEqual(wrapper.find('#grading_period_select_menu').length, 1)
|
||||
wrapper = mount(<SelectMenuGroup {...props} />)
|
||||
strictEqual(wrapper.find('SelectMenu#grading_period_select_menu').length, 1)
|
||||
})
|
||||
|
||||
test('includes "All Grading Periods" as an option in the grading period select menu', () => {
|
||||
|
@ -105,7 +111,7 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
})
|
||||
|
||||
test('does not render a grading period select menu if passed no grading periods', () => {
|
||||
wrapper = shallow(<SelectMenuGroup {...props} gradingPeriods={[]} />)
|
||||
wrapper = mount(<SelectMenuGroup {...props} gradingPeriods={[]} />)
|
||||
strictEqual(wrapper.find('#grading_period_select_menu').length, 0)
|
||||
})
|
||||
|
||||
|
@ -116,12 +122,12 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
})
|
||||
|
||||
test('renders a course select menu if the courses prop has more than 1 course', () => {
|
||||
wrapper = shallow(<SelectMenuGroup {...props} />)
|
||||
strictEqual(wrapper.find('#course_select_menu').length, 1)
|
||||
wrapper = mount(<SelectMenuGroup {...props} />)
|
||||
strictEqual(wrapper.find('SelectMenu#course_select_menu').length, 1)
|
||||
})
|
||||
|
||||
test('does not render a course select menu if the courses prop has only 1 course', () => {
|
||||
wrapper = shallow(
|
||||
wrapper = mount(
|
||||
<SelectMenuGroup
|
||||
{...props}
|
||||
courses={[{id: '2', nickname: 'Autos', url: '/courses/2/grades'}]}
|
||||
|
@ -169,13 +175,13 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
})
|
||||
|
||||
test('renders a submit button', () => {
|
||||
wrapper = shallow(<SelectMenuGroup {...props} />)
|
||||
strictEqual(wrapper.find('#apply_select_menus').length, 1)
|
||||
wrapper = mount(<SelectMenuGroup {...props} />)
|
||||
strictEqual(wrapper.find('button#apply_select_menus').length, 1)
|
||||
})
|
||||
|
||||
test('disables the submit button if no select menu options have changed', () => {
|
||||
wrapper = mount(<SelectMenuGroup {...props} />)
|
||||
const submitButton = wrapper.find('Button[id="apply_select_menus"]')
|
||||
const submitButton = wrapper.find('button#apply_select_menus')
|
||||
strictEqual(submitButton.prop('disabled'), true)
|
||||
})
|
||||
|
||||
|
@ -185,7 +191,7 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
.find('#student_select_menu')
|
||||
.last()
|
||||
.simulate('change', {target: {value: '7'}})
|
||||
const submitButton = wrapper.find('Button[id="apply_select_menus"]')
|
||||
const submitButton = wrapper.find('button#apply_select_menus')
|
||||
strictEqual(submitButton.prop('disabled'), false)
|
||||
})
|
||||
|
||||
|
@ -195,20 +201,17 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
.find('#student_select_menu')
|
||||
.last()
|
||||
.simulate('change', {target: {value: '7'}})
|
||||
wrapper
|
||||
.find('Button[id="apply_select_menus"]')
|
||||
.find('button')
|
||||
.simulate('click')
|
||||
strictEqual(wrapper.find('Button[id="apply_select_menus"]').prop('disabled'), true)
|
||||
wrapper.find('button#apply_select_menus').simulate('click')
|
||||
strictEqual(wrapper.find('button#apply_select_menus').prop('disabled'), true)
|
||||
})
|
||||
|
||||
test('calls saveAssignmentOrder when the button is clicked, if assignment order has changed', () => {
|
||||
const stub = sinon.stub().resolves()
|
||||
wrapper = shallow(<SelectMenuGroup {...props} saveAssignmentOrder={stub} />)
|
||||
wrapper = mount(<SelectMenuGroup {...props} saveAssignmentOrder={stub} />)
|
||||
wrapper
|
||||
.find('#assignment_sort_order_select_menu')
|
||||
.find('select#assignment_sort_order_select_menu')
|
||||
.simulate('change', {target: {value: 'title'}})
|
||||
const submitButton = wrapper.find('#apply_select_menus')
|
||||
const submitButton = wrapper.find('button#apply_select_menus')
|
||||
submitButton.simulate('click')
|
||||
strictEqual(stub.callCount, 1)
|
||||
})
|
||||
|
@ -220,7 +223,7 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
.find('#student_select_menu')
|
||||
.last()
|
||||
.simulate('change', {target: {value: '7'}})
|
||||
const submitButton = wrapper.find('#apply_select_menus').last()
|
||||
const submitButton = wrapper.find('button#apply_select_menus').last()
|
||||
submitButton.simulate('click')
|
||||
strictEqual(props.saveAssignmentOrder.callCount, 0)
|
||||
})
|
||||
|
@ -239,7 +242,7 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
QUnit.module('when the student has changed', contextHooks => {
|
||||
contextHooks.beforeEach(() => {
|
||||
wrapper = mountComponent()
|
||||
submitButton = wrapper.find('#apply_select_menus').last()
|
||||
submitButton = wrapper.find('button#apply_select_menus').last()
|
||||
wrapper
|
||||
.find('#student_select_menu')
|
||||
.last()
|
||||
|
@ -261,7 +264,7 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
contextHooks.beforeEach(() => {
|
||||
props.selectedCourseID = '2'
|
||||
wrapper = mountComponent()
|
||||
submitButton = wrapper.find('#apply_select_menus').last()
|
||||
submitButton = wrapper.find('button#apply_select_menus').last()
|
||||
wrapper
|
||||
.find('#course_select_menu')
|
||||
.last()
|
||||
|
@ -282,7 +285,7 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
contextHooks.beforeEach(() => {
|
||||
props.selectedCourseID = '2'
|
||||
wrapper = mountComponent()
|
||||
submitButton = wrapper.find('#apply_select_menus').last()
|
||||
submitButton = wrapper.find('button#apply_select_menus').last()
|
||||
wrapper
|
||||
.find('#course_select_menu')
|
||||
.last()
|
||||
|
@ -305,7 +308,7 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
contextHooks.beforeEach(() => {
|
||||
props.selectedCourseID = '21'
|
||||
wrapper = mountComponent()
|
||||
submitButton = wrapper.find('#apply_select_menus').last()
|
||||
submitButton = wrapper.find('button#apply_select_menus').last()
|
||||
wrapper
|
||||
.find('#course_select_menu')
|
||||
.last()
|
||||
|
@ -326,7 +329,7 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
contextHooks.beforeEach(() => {
|
||||
props.selectedCourseID = '21'
|
||||
wrapper = mountComponent()
|
||||
submitButton = wrapper.find('#apply_select_menus').last()
|
||||
submitButton = wrapper.find('button#apply_select_menus').last()
|
||||
wrapper
|
||||
.find('#course_select_menu')
|
||||
.last()
|
||||
|
@ -347,7 +350,7 @@ QUnit.module('SelectMenuGroup', suiteHooks => {
|
|||
contextHooks.beforeEach(() => {
|
||||
props.selectedCourseID = '21'
|
||||
wrapper = mountComponent()
|
||||
submitButton = wrapper.find('#apply_select_menus').last()
|
||||
submitButton = wrapper.find('button#apply_select_menus').last()
|
||||
wrapper
|
||||
.find('#course_select_menu')
|
||||
.last()
|
||||
|
|
Loading…
Reference in New Issue