flash error when students fail to load

refs GRADE-877

test plan:
 1. Setup a course with AMM and a moderated assignment
 2. Edit the first line of the students endpoint to fail

    app/controllers/submissions_api_controller.rb

    def gradeable_students
      fail "totes broken somehow"
      ...
    end

 3. Log in or act as the moderator
 4. Visit the moderation page for the assignment
 5. Verify a flash error appears
 6. Verify the flash error mentions loading students
 7. Remove the edit to the controller
 8. Refresh the moderation page
 9. Verify no flash error appears

Change-Id: I069f71641ed643860e27a56e615abeb643c7361c
Reviewed-on: https://gerrit.instructure.com/151601
Tested-by: Jenkins
Reviewed-by: Keith T. Garner <kgarner@instructure.com>
Reviewed-by: Adrian Packel <apackel@instructure.com>
QA-Review: Anju Reddy <areddy@instructure.com>
Product-Review: Sidharth Oberoi <soberoi@instructure.com>
This commit is contained in:
Jeremy Neander 2018-05-25 12:33:49 -05:00
parent 0a0ae68561
commit 3238926671
5 changed files with 144 additions and 1 deletions

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2018 - 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 {Component} from 'react'
import {string} from 'prop-types'
import {connect} from 'react-redux'
import I18n from 'i18n!assignment_grade_summary'
import {showFlashAlert} from '../../../shared/FlashAlert'
import * as StudentActions from '../students/StudentActions'
class FlashMessageHolder extends Component {
static propTypes = {
loadStudentsStatus: string
}
static defaultProps = {
loadStudentsStatus: null
}
componentWillReceiveProps(nextProps) {
if (nextProps.loadStudentsStatus !== this.props.loadStudentsStatus) {
if (nextProps.loadStudentsStatus === StudentActions.FAILURE) {
showFlashAlert({
message: I18n.t('There was a problem loading students.'),
type: 'error'
})
}
}
}
render() {
return null
}
}
function mapStateToProps(state) {
return {
loadStudentsStatus: state.students.loadStudentsStatus
}
}
export default connect(mapStateToProps)(FlashMessageHolder)

View File

@ -26,6 +26,7 @@ import I18n from 'i18n!assignment_grade_summary'
import '../../../context_cards/StudentContextCardTrigger'
import {loadStudents} from '../students/StudentActions'
import FlashMessageHolder from './FlashMessageHolder'
import GradesGrid from './GradesGrid'
import Header from './Header'
@ -73,6 +74,8 @@ class Layout extends Component {
return (
<div>
<FlashMessageHolder />
<Header assignment={this.props.assignment} />
<View as="div" margin="large 0 0 0">

View File

@ -63,7 +63,6 @@ function getAllStudentsPages(url, callbacks) {
})
.catch(response => {
callbacks.onFailure(response)
return Promise.reject(response) // allow for shared error handling
})
}

View File

@ -91,6 +91,7 @@ export default class FlashAlert extends React.Component {
if (!liveRegion) {
liveRegion = document.createElement('div')
liveRegion.id = screenreaderMessageHolderId
liveRegion.setAttribute('role', 'alert')
document.body.appendChild(liveRegion)
}
return liveRegion

View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2018 - 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 {mount} from 'enzyme'
import {Provider} from 'react-redux'
import * as FlashAlert from 'jsx/shared/FlashAlert'
import * as StudentActions from 'jsx/assignments/GradeSummary/students/StudentActions'
import FlashMessageHolder from 'jsx/assignments/GradeSummary/components/FlashMessageHolder'
import configureStore from 'jsx/assignments/GradeSummary/configureStore'
QUnit.module('GradeSummary FlashMessageHolder', suiteHooks => {
let storeEnv
let store
let wrapper
suiteHooks.beforeEach(() => {
storeEnv = {
assignment: {
courseId: '1201',
id: '2301',
title: 'Example Assignment'
},
graders: [
{graderId: '1101', graderName: 'Miss Frizzle'},
{graderId: '1102', graderName: 'Mr. Keating'}
]
}
sinon.stub(FlashAlert, 'showFlashAlert')
})
suiteHooks.afterEach(() => {
FlashAlert.showFlashAlert.restore()
wrapper.unmount()
})
function mountComponent() {
store = configureStore(storeEnv)
wrapper = mount(
<Provider store={store}>
<FlashMessageHolder />
</Provider>
)
}
QUnit.module('when students fail to load', hooks => {
hooks.beforeEach(() => {
mountComponent()
store.dispatch(StudentActions.setLoadStudentsStatus(StudentActions.FAILURE))
})
test('displays a flash alert', () => {
strictEqual(FlashAlert.showFlashAlert.callCount, 1)
})
test('uses the error type', () => {
const {type} = FlashAlert.showFlashAlert.lastCall.args[0]
equal(type, 'error')
})
test('includes a message about loading students', () => {
const {message} = FlashAlert.showFlashAlert.lastCall.args[0]
ok(message.includes('loading students'))
})
})
})