Upgrade to Inst-UI 3.2

fixes GRADE-180

Test plan:
Smoke test all Canvas pages that use InstUI.

Change-Id: I9ca3dc199924ec3a26c21bcc47dacb51ed12df6a
Reviewed-on: https://gerrit.instructure.com/122611
Tested-by: Jenkins
Reviewed-by: Derek Bender <djbender@instructure.com>
Reviewed-by: Jeremy Neander <jneander@instructure.com>
QA-Review: KC Naegle <knaegle@instructure.com>
Product-Review: Neil Gupta <ngupta@instructure.com>
This commit is contained in:
Neil Gupta 2017-08-14 11:14:38 -05:00
parent e29b71e5cf
commit b9737cc05c
69 changed files with 1486 additions and 922 deletions

View File

@ -146,12 +146,13 @@ export default class ActAsModal extends React.Component {
return (
<span>
<Modal
onRequestClose={this.handleModalRequestClose}
onDismiss={this.handleModalRequestClose}
transition="fade"
size="fullscreen"
label={I18n.t('Act as User')}
closeButtonLabel={I18n.t('Close')}
isOpen
applicationElement={() => document.getElementById('application')}
open
>
<ModalHeader>
<Typography size="large">

View File

@ -98,17 +98,11 @@ import APIError from './api_error'
}
componentDidMount () {
this.manageFocus();
document.getElementById('application').setAttribute('aria-hidden', 'true')
}
componentWillReceiveProps (nextProps) {
if (nextProps.usersEnrolled) {
this.close();
}
if (nextProps.isOpen) {
document.getElementById('application').setAttribute('aria-hidden', 'true')
} else {
document.getElementById('application').removeAttribute('aria-hidden')
}
}
componentDidUpdate () {
this.manageFocus();
@ -295,13 +289,14 @@ import APIError from './api_error'
<Modal
closeButtonLabel={cancelLabel}
id="add_people_modal"
isOpen={this.props.isOpen}
open={this.props.isOpen}
label={I18n.t('Modal Dialog: Add People')}
onRequestClose={this.close}
applicationElement={() => document.getElementById('application')}
onDismiss={this.close}
ref={(node) => { this.node = node; }}
shouldCloseOnOverlayClick={false}
size="medium"
tabindex="-1"
tabIndex="-1"
>
<ModalHeader>
<Heading tabIndex="-1">{I18n.t('Add People')}</Heading>

View File

@ -39,8 +39,8 @@ import ScreenReaderContent from 'instructure-ui/lib/components/ScreenReaderConte
renderNotice () {
return (
this.props.nameList.length > 0
? <Alert variant="success" dismissable={false}>{I18n.t('The following users are ready to be added to the course.')}</Alert>
: <Alert variant="info" dismissable={false}>{I18n.t('No users were selected to add to the course')}</Alert>
? <Alert variant="success">{I18n.t('The following users are ready to be added to the course.')}</Alert>
: <Alert variant="info">{I18n.t('No users were selected to add to the course')}</Alert>
);
}
renderUserTable () {

View File

@ -93,7 +93,7 @@ import Alert from 'instructure-ui/lib/components/Alert'
}
return (
<div className="peopleValidationissues__duplicates">
<Alert variant="warning" dismissable={false}>
<Alert variant="warning">
{I18n.t('There were several possible matches with the import. Please resolve them below.')}
</Alert>
{duplicateAddresses.map((address) => {
@ -124,7 +124,7 @@ import Alert from 'instructure-ui/lib/components/Alert'
return (
<div className="peoplevalidationissues__missing">
<Alert variant="warning" dismissable={false}>{alertText}</Alert>
<Alert variant="warning">{alertText}</Alert>
<MissingPeopleSection
inviteUsersURL={this.props.inviteUsersURL}
missing={this.props.missing}

View File

@ -86,9 +86,10 @@ export default class BlueprintModal extends Component {
return (
<Modal
isOpen={this.props.isOpen}
onRequestClose={this.props.onCancel}
open={this.props.isOpen}
onDismiss={this.props.onCancel}
onClose={this.handleModalClose}
applicationElement={() => document.getElementById('application')}
transition="fade"
size="fullscreen"
label={this.props.title}
@ -114,6 +115,6 @@ export default class BlueprintModal extends Component {
)}
</ModalFooter>
</Modal>
)
);
}
}

View File

@ -49,11 +49,10 @@ export default class BlueprintCourseSidebar extends Component {
this.state = {
isOpen: false,
}
this.trayRef = null
}
handleOpen = () => {
this.props.onOpen(this.trayRef)
this.props.onOpen()
this.closeBtn.focus()
}
@ -74,7 +73,7 @@ export default class BlueprintCourseSidebar extends Component {
return (
<div className="bcs__wrapper">
<div className="bcs__trigger">
<Button ref={(c) => { this.openBtn = c }} variant="icon-inverse" onClick={this.open}>
<Button buttonRef={(c) => { this.openBtn = c }} variant="icon-inverse" onClick={this.open}>
<Typography color="primary-inverse" size="large">
<IconBlueprintSolid title={I18n.t('Open sidebar')} />
</Typography>
@ -82,18 +81,18 @@ export default class BlueprintCourseSidebar extends Component {
</div>
<Tray
label={I18n.t('Blueprint Settings')}
dismissable={false}
trapFocus
isOpen={this.state.isOpen}
shouldContainFocus
open={this.state.isOpen}
placement="end"
onEntering={this.handleOpen}
onEntered={this.handleOpen}
onExiting={this.handleClose}
contentRef={(el) => { this.trayRef = el }}
applicationElement={() => document.getElementById('application')}
contentRef={this.props.contentRef}
>
<div className="bcs__content" ref={this.props.contentRef}>
<div className="bcs__content">
<header className="bcs__header">
<div className="bcs__close-wrapper">
<Button variant="icon-inverse" onClick={this.close} ref={(c) => { this.closeBtn = c }}>
<Button variant="icon-inverse" onClick={this.close} buttonRef={(c) => { this.closeBtn = c }}>
<Typography color="primary-inverse" size="small">
<IconXSolid title={I18n.t('Close sidebar')} />
</Typography>
@ -110,6 +109,6 @@ export default class BlueprintCourseSidebar extends Component {
</Tray>
{this.props.detachedChildren}
</div>
)
);
}
}

View File

@ -91,24 +91,7 @@ export default class CourseSidebar extends Component {
}
}
componentWillUpdate (nextProps, nextState) {
if (this.state.isModalOpen !== nextState.isModalOpen) {
if (nextState.isModalOpen) {
document.getElementById('application').setAttribute('aria-hidden', 'true')
if (this.sidebarRef) {
this.sidebarRef.setAttribute('aria-hidden', 'true')
}
} else {
document.getElementById('application').removeAttribute('aria-hidden')
if (this.sidebarRef) {
this.sidebarRef.removeAttribute('aria-hidden')
}
}
}
}
onOpenSidebar = (trayRef) => {
this.sidebarRef = trayRef
onOpenSidebar = () => {
if (!this.props.hasLoadedAssociations) {
this.props.loadAssociations()
}
@ -117,11 +100,6 @@ export default class CourseSidebar extends Component {
}
}
onCloseSidebar = () => {
this.sidebarRef = null
}
sidebarRef = null
modals = {
associations: () => ({
props: {
@ -348,7 +326,6 @@ export default class CourseSidebar extends Component {
return (
<BlueprintSidebar
onOpen={this.onOpenSidebar}
onClose={this.onCloseSidebar}
contentRef={this.props.contentRef}
detachedChildren={this.renderModal()}
>

View File

@ -121,7 +121,7 @@ import Actions from 'jsx/calendar/scheduler/actions'
</div>
</Modal>
</div>
)
);
}
}

View File

@ -87,13 +87,11 @@ export default class BreakdownDetails extends React.Component {
return (
<Tray
isOpen={this.props.showDetails}
open={this.props.showDetails}
placement="end"
dismissable={false}
trapFocus
getDefaultFocusElement={() => this.closeButton}
onReady={() => document.getElementById('application').setAttribute('aria-hidden', true)}
onClose={() => document.getElementById('application').setAttribute('aria-hidden', false)}
shouldContainFocus
defaultFocusElement={() => this.closeButton}
applicationElement={() => document.getElementById('application')}
>
<div className="crs-breakdown-details">
<div className="crs-breakdown-details__content">
@ -128,6 +126,6 @@ export default class BreakdownDetails extends React.Component {
</div>
</div>
</Tray>
)
);
}
}

View File

@ -206,11 +206,11 @@ export default class StudentContextTray extends React.Component {
<Tray
label={I18n.t('Student Details')}
dismissable={!this.state.isLoading}
closeButtonLabel={I18n.t('Close')}
closeButtonLabel={!this.state.isLoading ? I18n.t('Close') : null}
closeButtonRef={this.getCloseButtonRef}
isOpen={this.state.isOpen}
onRequestClose={this.handleRequestClose}
applicationElement={() => document.getElementById('application')}
open={this.state.isOpen}
onDismiss={this.handleRequestClose}
placement='end'
zIndex='1000'
onClose={this.props.onClose}
@ -307,6 +307,6 @@ export default class StudentContextTray extends React.Component {
</aside>
</Tray>
</div>
)
);
}
}

View File

@ -52,7 +52,6 @@ class CourseHomeDialog extends React.Component {
constructor (props) {
super(props)
this.state = props.store.getState()
this.appElement = document.getElementById('application')
}
renderWikiLabelContent () {
@ -127,66 +126,68 @@ class CourseHomeDialog extends React.Component {
I18n.t('Before publishing your course, you must either publish a module in the Modules page, or choose a different home page.') :
I18n.t("Select what you'd like to display on the home page.")
return (<Modal
isOpen={this.props.open}
transition="fade"
label={I18n.t('Choose Course Home Page')}
closeButtonLabel={I18n.t("Close")}
onReady={this.onReady}
onRequestClose={this.props.onRequestClose}
onClose={this.onClose}
>
<ModalHeader>
<Heading tag="h2" level="h3">{I18n.t('Choose Home Page')}</Heading>
</ModalHeader>
<ModalBody>
<div className="content-box-mini" style={{marginTop: '0'}}>
<AccessibleContent>
<Typography weight="bold" size="small">
{instructions}
</Typography>
</AccessibleContent>
</div>
<RadioInputGroup
description={<ScreenReaderContent>{instructions}</ScreenReaderContent>}
name="course[default_view]"
onChange={this.onChange}
defaultValue={selectedDefaultView}
>
{inputs.map(input =>
<RadioInput
key={input.value}
checked={input.checked}
value={input.value}
label={input.label}
disabled={input.disabled}
/>)
return (
<Modal
open={this.props.open}
transition="fade"
label={I18n.t('Choose Course Home Page')}
closeButtonLabel={I18n.t('Close')}
applicationElement={() => document.getElementById('application')}
onDismiss={this.props.onRequestClose}
onClose={this.onClose}
>
<ModalHeader>
<Heading tag="h2" level="h3">{I18n.t('Choose Home Page')}</Heading>
</ModalHeader>
<ModalBody>
<div className="content-box-mini" style={{marginTop: '0'}}>
<AccessibleContent>
<Typography weight="bold" size="small">
{instructions}
</Typography>
</AccessibleContent>
</div>
<RadioInputGroup
description={<ScreenReaderContent>{instructions}</ScreenReaderContent>}
name="course[default_view]"
onChange={this.onChange}
defaultValue={selectedDefaultView}
>
{inputs.map(input =>
<RadioInput
key={input.value}
checked={input.checked}
value={input.value}
label={input.label}
disabled={input.disabled}
/>)
}
</RadioInputGroup>
{
wikiFrontPageTitle ? (
null
) : (
<div className="content-box-mini">
* <Link href={wikiUrl}>{I18n.t('Front page must be set first')}
</Link></div>
)
}
</RadioInputGroup>
{
wikiFrontPageTitle ? (
null
) : (
<div className="content-box-mini">
* <Link href={wikiUrl}>{I18n.t('Front page must be set first')}
</Link></div>
)
}
</ModalBody>
</ModalBody>
<ModalFooter>
<Button onClick={this.props.onRequestClose}>{I18n.t('Cancel')}</Button>&nbsp;
<Button
onClick={this.onSubmit}
disabled={this.props.isPublishing && this.state.selectedDefaultView === 'modules'}
variant="primary"
>{
this.props.isPublishing ? I18n.t('Choose and Publish') : I18n.t('Save')
}</Button>
</ModalFooter>
</Modal>)
<ModalFooter>
<Button onClick={this.props.onRequestClose}>{I18n.t('Cancel')}</Button>&nbsp;
<Button
onClick={this.onSubmit}
disabled={this.props.isPublishing && this.state.selectedDefaultView === 'modules'}
variant="primary"
>{
this.props.isPublishing ? I18n.t('Choose and Publish') : I18n.t('Save')
}</Button>
</ModalFooter>
</Modal>
);
}
componentDidMount () {
@ -197,13 +198,7 @@ class CourseHomeDialog extends React.Component {
this.props.store.removeChangeListener(this.onStoreChange)
}
onReady = () => {
this.appElement.setAttribute('aria-hidden', 'true')
}
onClose = () => {
this.appElement.removeAttribute('aria-hidden')
// this (unnecessary?) setTimeout fixes returning focus in ie11
window.setTimeout(() => {
const returnFocusTo = this.props.returnFocusTo

View File

@ -96,12 +96,13 @@ import Select from 'instructure-ui/lib/components/Select'
source: this.props.source.label
})
return (
<Modal ref='modal' isOpen={this.state.isOpen}
<Modal ref='modal' open={this.state.isOpen}
modalSize='small'
label={dialogLabel}
closeButtonLabel={I18n.t('Cancel')}
onReady={this.handleReady}
onRequestClose={this.handleRequestClose}
applicationElement={() => document.getElementById('application')}
onOpen={this.handleReady}
onDismiss={this.handleRequestClose}
onClose={this.handleClose}
>
<ModalHeader>
@ -115,7 +116,7 @@ import Select from 'instructure-ui/lib/components/Select'
<Button id='MoveToDialog__move' variant='primary' onClick={this.handleMove}>{I18n.t('Move')}</Button>
</ModalFooter>
</Modal>
)
);
}
});
export default MoveToDialog

View File

@ -269,6 +269,6 @@ export default React.createClass({
</Modal>
</div>
)
);
}
});

View File

@ -189,6 +189,6 @@ export default React.createClass({
</div>
</Modal>
</li>
)
);
}
});

View File

@ -124,7 +124,7 @@ export default React.createClass({
</div>
</Modal>
</li>
)
);
}
return false;
}

View File

@ -177,7 +177,7 @@ export default React.createClass({
</div>
</Modal>
</li>
)
);
}
return false;
}

View File

@ -66,7 +66,7 @@ export default React.createClass({
},
render() {
return(
return (
<Modal className="ReactModal__Content--canvas ReactModal__Content--mini-modal"
overlayClassName="ReactModal__Overlay--canvas"
isOpen={this.state.modalIsOpen}
@ -98,7 +98,7 @@ export default React.createClass({
</div>
</div>
</Modal>
)
);
}
});

View File

@ -116,7 +116,7 @@ class SearchFormComponent extends Component {
}
}
setSelectedFrom = (from) => {
setSelectedFrom = (_, from) => {
const startOfFrom = from ? moment(from).startOf('day').format() : '';
this.setState(prevState => ({
selected: {
@ -126,7 +126,7 @@ class SearchFormComponent extends Component {
}));
}
setSelectedTo = (to) => {
setSelectedTo = (_, to) => {
const endOfTo = to ? moment(to).endOf('day').format() : '';
this.setState(prevState => ({
selected: {

View File

@ -227,7 +227,7 @@ class AssignmentColumnHeader extends ColumnHeader {
return (
<PopoverMenu
contentRef={this.bindOptionsMenuContent}
focusTriggerOnClose={false}
shouldFocusTriggerOnClose={false}
trigger={this.renderTrigger()}
onToggle={this.onToggle}
onClose={this.props.onMenuClose}

View File

@ -93,7 +93,7 @@ class AssignmentGroupColumnHeader extends ColumnHeader {
<PopoverMenu
contentRef={this.bindOptionsMenuContent}
focusTriggerOnClose={false}
shouldFocusTriggerOnClose={false}
trigger={renderTrigger(this.props.assignmentGroup, menuShown, this.bindOptionsMenuTrigger)}
onToggle={this.onToggle}
onClose={this.props.onMenuClose}

View File

@ -125,11 +125,12 @@ class GradebookSettingsModal extends React.Component {
return (
<Modal
size="large"
isOpen={isOpen}
open={isOpen}
label={title}
closeButtonLabel={I18n.t('Close')}
onAfterOpen={this.fetchLatePolicy}
onRequestClose={this.close}
applicationElement={() => document.getElementById('application')}
onOpen={this.fetchLatePolicy}
onDismiss={this.close}
onExited={this.props.onClose}
>
<ModalHeader>

View File

@ -228,8 +228,7 @@ class LatePoliciesTabPanel extends React.Component {
<Alert
variant="warning"
closeButtonLabel={I18n.t('Close')}
dismissable
onClose={this.closeAlert}
onDismiss={this.closeAlert}
margin="small"
>
{I18n.t('Changing your policy now will affect previously graded submissions.')}

View File

@ -98,6 +98,7 @@ class StatusColorListItem extends React.Component {
show={isColorPickerShown}
onToggle={colorPickerOnToggle}
contentRef={colorPickerContentRef}
applicationElement={() => document.getElementById('application')}
>
<PopoverTrigger>

View File

@ -135,11 +135,12 @@ class StatusesModal extends React.Component {
return (
<Modal
isOpen={isOpen}
open={isOpen}
label={I18n.t('Statuses')}
closeButtonLabel={I18n.t('Close')}
closeButtonRef={bindCloseButton}
onRequestClose={close}
applicationElement={() => document.getElementById('application')}
onDismiss={close}
onExited={onClose}
contentRef={bindContentRef}
>

View File

@ -120,7 +120,7 @@ export default class StudentColumnHeader extends ColumnHeader {
<PopoverMenu
contentRef={this.bindOptionsMenuContent}
focusTriggerOnClose={false}
shouldFocusTriggerOnClose={false}
trigger={
<span ref={this.bindOptionsMenuTrigger} className={classes}>
<Typography weight="bold" fontStyle="normal" size="large" color="brand">

View File

@ -65,12 +65,12 @@ export default function SubmissionTray (props) {
<Tray
contentRef={props.contentRef}
label={I18n.t('Submission tray')}
isDismissable
closeButtonLabel={I18n.t('Close submission tray')}
isOpen={props.isOpen}
trapFocus
applicationElement={() => document.getElementById('application')}
open={props.isOpen}
shouldContainFocus
placement="end"
onRequestClose={props.onRequestClose}
onDismiss={props.onRequestClose}
onClose={props.onClose}
>
<div className="SubmissionTray__Container">

View File

@ -111,7 +111,7 @@ class TotalGradeColumnHeader extends ColumnHeader {
<PopoverMenu
ref={this.bindOptionsMenu}
contentRef={this.bindOptionsMenuContent}
focusTriggerOnClose={false}
shouldFocusTriggerOnClose={false}
trigger={renderTrigger(menuShown, this.bindOptionsMenuTrigger)}
onToggle={this.onToggle}
onClose={this.props.onMenuClose}

View File

@ -22,6 +22,10 @@ import PropTypes from 'prop-types'
import SVGWrapper from 'jsx/shared/SVGWrapper'
import PreventDefault from 'compiled/fn/preventDefault'
function readCookie(key) {
return (document.cookie.match('(^|; )' + encodeURIComponent(key) + '=([^;]*)') || 0)[2]
}
var ProfileTray = React.createClass({
propTypes: {
@ -66,7 +70,7 @@ import PreventDefault from 'compiled/fn/preventDefault'
>
<input name="utf8" value="✓" type="hidden"/>
<input name="_method" value="delete" type="hidden"/>
<input name="authenticity_token" value={$.cookie('_csrf_token')} type="hidden"/>
<input name="authenticity_token" value={readCookie('_csrf_token')} type="hidden"/>
<button
type="submit"
className="Button Button--small">

View File

@ -35,19 +35,6 @@ import axios from 'axios'
isOpen: false
}
constructor (props) {
super(props);
this.appElement = document.getElementById('application');
}
handleModalReady = () => {
this.appElement.setAttribute('aria-hidden', 'true');
}
handleModalClose = () => {
this.appElement.removeAttribute('aria-hidden');
}
handleOkayButtonClick = (e, onSuccessFunc = window.location.reload) => {
const API_URL = '/api/v1/users/self/features/flags/new_user_tutorial_on_off';
axios.put(API_URL, {
@ -62,13 +49,12 @@ import axios from 'axios'
render () {
return (
<Modal
isOpen={this.props.isOpen}
open={this.props.isOpen}
size="small"
onReady={this.handleModalReady}
onClose={this.handleModalClose}
onRequestClose={this.props.handleRequestClose}
onDismiss={this.props.handleRequestClose}
label={I18n.t('End Course Set-up Tutorial Dialog')}
closeButtonLabel={I18n.t('Close')}
applicationElement={() => document.getElementById('application')}
>
<ModalHeader>
<Heading>{I18n.t('End Course Set-up Tutorial')}</Heading>

View File

@ -91,14 +91,13 @@ class TutorialTray extends React.Component {
return (
<Tray
label={this.props.label}
isDismissable={false}
isOpen={!this.state.isCollapsed}
open={!this.state.isCollapsed}
placement="end"
zIndex="100"
onEntering={this.handleEntering}
onExiting={this.handleExiting}
onEntered={this.handleEntering}
trapFocus
shouldContainFocus
applicationElement={() => document.getElementById('application')}
>
<div className="NewUserTutorialTray">
<div className="NewUserTutorialTray__ButtonContainer">

View File

@ -37,17 +37,18 @@ export default React.createClass({
render: function () {
return (
<Modal
isOpen={this.state.isOpen}
open={this.state.isOpen}
shouldCloseOnOverlayClick={true}
onRequestClose={this.close}
onDismiss={this.close}
transition="fade"
size="auto"
label={I18n.t("Modal Dialog: Add to course")}
closeButtonLabel={I18n.t("Close")}
applicationElement={() => document.getElementById('application')}
ref={this._saveModal}
onEntering={this._fixFocus}
onClose={this.props.onClose}
onReady={this.props.onReady}
onOpen={this.props.onReady}
>
<ModalHeader>
<Heading>{I18n.t("Add to course...")}</Heading>

View File

@ -168,12 +168,11 @@ export default class FlashAlert extends React.Component {
<Alert
variant={this.props.variant}
closeButtonLabel={I18n.t('Close')}
onClose={this.closeAlert}
dismissable
onDismiss={this.closeAlert}
margin="small auto"
timeout={timeout}
liveRegion={this.getLiveRegion}
transitionType="fade"
transition="fade"
>
<div>
<p style={{margin: '0 -5px'}}>
@ -183,7 +182,7 @@ export default class FlashAlert extends React.Component {
</div>
</Alert>
</Transition>
)
);
}
}

View File

@ -216,13 +216,12 @@ import Alert from 'instructure-ui/lib/components/Alert'
<div className="MessageStudents__Alert">
<Alert variant={variant}
closeButtonLabel={I18n.t('Close')}
dismissable
onClose={this.handleAlertClose}
onDismiss={this.handleAlertClose}
>
{message}
</Alert>
</div>
)
);
} else { return null }
}
@ -244,11 +243,12 @@ import Alert from 'instructure-ui/lib/components/Alert'
return (
<div className="MessageStudents">
<Modal
isOpen={this.state.open}
open={this.state.open}
transition="fade"
label={this.props.title}
onRequestClose={this.props.onRequestClose}
onDismiss={this.props.onRequestClose}
closeButtonLabel={I18n.t('Close')}
applicationElement={() => document.getElementById('application')}
size='medium'
onExited={this.props.onExited}
>
@ -305,7 +305,7 @@ import Alert from 'instructure-ui/lib/components/Alert'
</ModalFooter>
</Modal>
</div>
)
);
}
}

View File

@ -137,6 +137,6 @@ export default React.createClass({
</ModalButtons>
</Modal>
</div>
)
);
}
})

View File

@ -139,6 +139,6 @@ export default React.createClass({
>
{this.modalContent()}
</Modal>
)
);
}
})

View File

@ -145,6 +145,9 @@ div.form-column-right, div.overrides-column-right {
margin: 15px 20px 0;
}
#discussion-edit-view {
@include readonly-input;
}
/* support for master class locked input fields */
#edit_assignment_form, #discussion-edit-view {
@ -152,8 +155,6 @@ div.form-column-right, div.overrides-column-right {
clear: both;
}
@include readonly-input;
.to .ic-Form-control.readonly,
.from .ic-Form-control.readonly { // locked availability dates
margin-bottom: 0; // removes white space at bottom of assign box

View File

@ -42,7 +42,6 @@
}
.bcs__content {
width: 270px;
border-bottom: 2px solid $ic-border-color;
.bcs__body {

View File

@ -68,7 +68,7 @@
"ic-ajax": "~2.0.1",
"ic-tabs": "0.1.3",
"imports-loader": "^0.7.0",
"instructure-ui": "2.5.0",
"instructure-ui": "3.2.0",
"istanbul-instrumenter-loader": "^3.0.0",
"jquery": "https://github.com/ryankshaw/jquery.git#1.7.2-with-AMD-and-CommonJS",
"jquery-getscrollbarwidth": "^1.0.0",

View File

@ -21,6 +21,7 @@
import $ from 'jquery'
import './vendor/jquery.scrollTo'
import './jquery.instructure_jquery_patches'
$.fn.scrollToVisible = function(obj) {
var options = {};

View File

@ -18,10 +18,9 @@
define([
'react',
'react-dom',
'react-addons-test-utils',
'enzyme',
'jsx/add_people/components/add_people',
], (React, ReactDOM, TestUtils, AddPeople) => {
], (React, enzyme, AddPeople) => {
QUnit.module('AddPeople');
const props = {
@ -39,17 +38,23 @@ define([
};
test('renders the component', () => {
const component = TestUtils.renderIntoDocument(
const container = document.createElement('div');
container.id = 'application';
document.body.appendChild(container);
const wrapper = enzyme.mount(
<AddPeople
validateUsers={() => {}}
enrollUsers={() => {}}
reset={() => {}}
{...props}
/>
/>,
{ attachTo: document.getElementById('fixtures') }
);
const addPeople = document.querySelectorAll('.addpeople');
equal(addPeople.length, 1, 'AddPeople component rendered.');
component.close();
ReactDOM.unmountComponentAtNode(component.node._overlay.parentElement);
ok(document.getElementById('add_people_modal'));
wrapper.unmount();
document.body.removeChild(container);
});
});

View File

@ -20,7 +20,17 @@ import React from 'react'
import * as enzyme from 'enzyme'
import BlueprintModal from 'jsx/blueprint_courses/components/BlueprintModal'
QUnit.module('BlueprintModal component')
QUnit.module('BlueprintModal component', {
setup () {
const appElement = document.createElement('div')
appElement.id = 'application'
document.getElementById('fixtures').appendChild(appElement)
},
teardown () {
document.getElementById('fixtures').innerHTML = ''
}
})
const defaultProps = () => ({
isOpen: true,

View File

@ -20,41 +20,41 @@ import React from 'react'
import * as enzyme from 'enzyme'
import BlueprintSidebar from 'jsx/blueprint_courses/components/BlueprintSidebar'
QUnit.module('BlueprintSidebar component')
QUnit.module('BlueprintSidebar', function (hooks) {
let clock
let wrapper
const defaultProps = () => ({
hooks.beforeEach(() => {
clock = sinon.useFakeTimers()
const appElement = document.createElement('div')
appElement.id = 'application'
document.getElementById('fixtures').appendChild(appElement)
})
})
test('renders the BlueprintSidebar component', () => {
const tree = enzyme.shallow(<BlueprintSidebar {...defaultProps()} />)
const node = tree.find('.bcs__wrapper')
ok(node.exists())
})
test('clicking open button sets isOpen to true', () => {
const props = defaultProps()
const tree = enzyme.mount(<BlueprintSidebar {...props} />)
const button = tree.find('.bcs__trigger button')
button.at(0).simulate('click')
const instance = tree.instance()
equal(instance.state.isOpen, true)
tree.unmount()
})
test('clicking close button sets isOpen to false', () => {
const props = defaultProps()
const tree = enzyme.mount(<BlueprintSidebar {...props} />)
const instance = tree.instance()
instance.setState({ isOpen: true })
const closeBtn = instance.closeBtn
const btnWrapper = new enzyme.ReactWrapper(closeBtn, closeBtn)
btnWrapper.at(0).simulate('click')
equal(instance.state.isOpen, false)
tree.unmount()
hooks.afterEach(() => {
wrapper.unmount()
document.getElementById('fixtures').innerHTML = ''
clock.restore()
})
test('renders the BlueprintSidebar component', () => {
wrapper = enzyme.shallow(<BlueprintSidebar />)
ok(wrapper.find('.bcs__wrapper').exists())
})
test('clicking open button sets isOpen to true', () => {
wrapper = enzyme.mount(<BlueprintSidebar />)
wrapper.find('.bcs__trigger button').at(0).simulate('click')
clock.tick(500)
strictEqual(wrapper.instance().state.isOpen, true)
})
test('clicking close button sets isOpen to false', () => {
wrapper = enzyme.mount(<BlueprintSidebar />)
wrapper.instance().open()
clock.tick(500)
wrapper.instance().closeBtn.click()
clock.tick(500)
strictEqual(wrapper.instance().state.isOpen, false)
})
})

View File

@ -26,6 +26,7 @@ import MigrationStates from 'jsx/blueprint_courses/migrationStates'
import sampleData from '../sampleData'
import mockStore from '../mockStore'
let clock
let sidebarContentRef = null
const initialState = {
@ -53,6 +54,10 @@ function connect (props = defaultProps(), storeState = initialState) {
QUnit.module('Course Sidebar component', {
setup () {
clock = sinon.useFakeTimers()
const appElement = document.createElement('div')
appElement.id = 'application'
document.getElementById('fixtures').appendChild(appElement)
sidebarContentRef = null
moxios.install()
moxios.stubRequest('/api/v1/courses/4/blueprint_templates/default/migrations', {
@ -62,6 +67,8 @@ QUnit.module('Course Sidebar component', {
},
teardown () {
moxios.uninstall()
document.getElementById('fixtures').innerHTML = ''
clock.restore()
}
})
@ -75,6 +82,7 @@ test('renders the closed CourseSidebar component', () => {
test('renders the open CourseSidebar component', () => {
const tree = enzyme.mount(connect())
tree.find('button').simulate('click')
clock.tick(500)
ok(sidebarContentRef, 'sidebar contents')
const sidebar = new enzyme.ReactWrapper(sidebarContentRef, sidebarContentRef)
@ -159,6 +167,7 @@ test('renders Sync button if has associations and sync is active and no unsyced
state.migrationStatus = MigrationStates.states.imports_queued
const tree = enzyme.mount(connect(props, state))
tree.find('button').simulate('click')
clock.tick(500)
ok(sidebarContentRef)
const sidebar = new enzyme.ReactWrapper(sidebarContentRef, sidebarContentRef)
@ -171,6 +180,7 @@ test('renders Sync button if has associations and has unsynced changes', () => {
const state = {...initialState}
const tree = enzyme.mount(connect(props, state))
tree.find('button').simulate('click')
clock.tick(500)
ok(sidebarContentRef)
const sidebar = new enzyme.ReactWrapper(sidebarContentRef, sidebarContentRef)

View File

@ -21,11 +21,24 @@ define([
'react-dom',
'jsx/conditional_release_stats/components/breakdown-details',
], (React, ReactDOM, BreakdownDetails) => {
const container = document.getElementById('fixtures')
let clock;
let container;
QUnit.module('Breakdown Details', {
setup () {
const applicationElement = document.createElement('div');
applicationElement.id = 'application';
document.getElementById('fixtures').appendChild(applicationElement);
container = document.createElement('div');
document.getElementById('fixtures').appendChild(container);
clock = sinon.useFakeTimers();
},
teardown() {
ReactDOM.unmountComponentAtNode(container);
document.getElementById('fixtures').innerHTML = '';
clock.restore();
}
})
@ -172,6 +185,7 @@ define([
test('renders component correctly', () => {
const component = renderComponent(defaultProps())
clock.tick(500);
const rendered = document.querySelectorAll('.crs-breakdown-details')
equal(rendered.length, 1)
@ -182,6 +196,7 @@ define([
props.selectedPath.student = 0
props.selectStudent = sinon.spy()
const component = renderComponent(props)
clock.tick(500);
const nextBtn = document.querySelector('.student-details__next-student')
nextBtn.click()
@ -194,6 +209,7 @@ define([
props.selectedPath.student = 1
props.selectStudent = sinon.spy()
const component = renderComponent(props)
clock.tick(500);
const nextBtn = document.querySelector('.student-details__next-student')
nextBtn.click()
@ -206,6 +222,7 @@ define([
props.selectedPath.student = 1
props.selectStudent = sinon.spy()
const component = renderComponent(props)
clock.tick(500);
const prevBtn = document.querySelector('.student-details__prev-student')
prevBtn.click()
@ -218,6 +235,7 @@ define([
props.selectedPath.student = 0
props.selectStudent = sinon.spy()
const component = renderComponent(props)
clock.tick(500);
const prevBtn = document.querySelector('.student-details__prev-student')
prevBtn.click()
@ -230,6 +248,7 @@ define([
props.selectedPath.student = 0
props.selectStudent = sinon.spy()
const component = renderComponent(props)
clock.tick(500);
const backBtn = document.querySelector('.crs-back-button')
backBtn.click()

View File

@ -24,6 +24,7 @@ QUnit.module('StudentContextCardTrigger', {
setup () {
$('#fixtures').append('<button class="student_context_card_trigger">Open</button>');
$('#fixtures').append('<div id="StudentTray__Container"></div>');
$('#fixtures').append('<div id="application"></div>');
window.ENV.STUDENT_CONTEXT_CARDS_ENABLED = true
moxios.install();
},

View File

@ -26,6 +26,9 @@ define([
'jsx/context_cards/StudentContextTray',
'jsx/context_cards/StudentCardStore'
], ($, React, ReactDOM, TestUtils, Avatar, Tray, StudentContextTray, StudentCardStore) => {
let fixtureElement
let applicationElement
QUnit.module('StudentContextTray', (hooks) => {
let store, subject
const courseId = '1'
@ -42,6 +45,11 @@ define([
returnFocusTo={() => {}}
/>
)
fixtureElement = document.createElement('div')
document.getElementById('fixtures').appendChild(fixtureElement)
applicationElement = document.createElement('div')
applicationElement.id = 'application'
document.getElementById('fixtures').appendChild(applicationElement)
})
hooks.afterEach(() => {
if (subject) {
@ -77,6 +85,7 @@ define([
})
test('tray should set focus to the close button when mounting', () => {
const clock = sinon.useFakeTimers()
store.state.loading = false
// eslint-disable-next-line react/no-render-return-value
const component = TestUtils.renderIntoDocument(
@ -86,11 +95,15 @@ define([
studentId={studentId}
returnFocusTo={() => {}}
/>,
document.getElementById('fixtures')
fixtureElement
)
component.onChange()
ok(component.closeButtonRef.focused)
clock.tick(1) // perform the setState timeout callback
equal(document.activeElement, component.closeButtonRef)
const componentNode = ReactDOM.findDOMNode(component)
ReactDOM.unmountComponentAtNode(componentNode.parentNode)
clock.restore()
})
test('tray should set focus back to the result of the returnFocusTo prop', () => {
@ -103,7 +116,7 @@ define([
studentId={studentId}
returnFocusTo={() => [$('#someButton')]}
/>,
document.getElementById('fixtures')
fixtureElement
)
const fakeEvent = {
@ -111,6 +124,8 @@ define([
}
component.handleRequestClose(fakeEvent)
ok(document.activeElement === document.getElementById('someButton'))
const componentNode = ReactDOM.findDOMNode(component)
ReactDOM.unmountComponentAtNode(componentNode.parentNode)
})
QUnit.module('analytics button', () => {

View File

@ -24,11 +24,9 @@ define([
'jsx/eportfolios/MoveToDialog',
'helpers/assertions'
], (React, ReactDOM, TestUtils, _, MoveToDialog, assertions) => {
const fixtures = document.getElementById('fixtures')
fixtures.innerHTML = '<div id="modalRoot"></div><div id="appRoot"></div>'
const root = document.getElementById('modalRoot')
const appRoot= document.getElementById('appRoot')
let root
let appRoot
let applicationElement
const mountDialog = (opts = {}) => {
opts = _.extend({}, {
@ -43,12 +41,20 @@ define([
}
QUnit.module('MoveToDialog', {
setup() {
setup () {
root = document.createElement('div')
appRoot = document.createElement('div')
applicationElement = document.createElement('div')
applicationElement.id = 'application'
document.getElementById('fixtures').appendChild(root)
document.getElementById('fixtures').appendChild(appRoot)
document.getElementById('fixtures').appendChild(applicationElement)
},
teardown() {
teardown () {
ReactDOM.unmountComponentAtNode(root)
appRoot.removeAttribute('aria-hidden')
document.getElementById('fixtures').innerHTML = ''
}
})
@ -103,21 +109,4 @@ define([
const button = document.getElementById('MoveToDialog__move')
TestUtils.Simulate.click(button)
})
test('handles aria-hides app element on open and close', (assert) => {
const done = assert.async()
notOk(appRoot.getAttribute('aria-hidden'))
mountDialog({
appElement: appRoot
})
setTimeout(() => {
ok(appRoot.getAttribute('aria-hidden'))
const button = document.getElementById('MoveToDialog__cancel')
TestUtils.Simulate.click(button)
notOk(appRoot.getAttribute('aria-hidden'))
done()
}, 1)
})
})

View File

@ -254,7 +254,11 @@ QUnit.module('SearchForm Autocomplete options', {
this.assignments = Fixtures.assignmentArray();
this.graders = Fixtures.userArray();
this.students = Fixtures.userArray();
this.wrapper = mount(<SearchFormComponent {...this.props} />);
this.wrapper = mount(<SearchFormComponent {...this.props} />, {attachTo: document.getElementById('fixtures')});
},
teardown () {
this.wrapper.unmount();
}
});

View File

@ -3104,6 +3104,7 @@ QUnit.module('Menus', {
this.gradebook.postGradesLtis = [];
this.gradebook.postGradesStore = {};
$fixtures.innerHTML = `
<div id="application"></div>
<span data-component="ViewOptionsMenu"></span>
<span data-component="ActionMenu"></span>
<span data-component="GradebookMenu" data-variant="DefaultGradebook"></span>
@ -3137,13 +3138,16 @@ test('GradebookMenu is rendered on renderGradebookMenu', function () {
});
test('StatusesModal is mounted on renderStatusesModal', function () {
const clock = sinon.useFakeTimers();
const statusModal = this.gradebook.renderStatusesModal();
statusModal.open();
clock.tick(500); // wait for Modal to transition open
const header = document.querySelector('h3');
equal(header.innerText, 'Statuses');
const statusesModalMountPoint = document.querySelector("[data-component='StatusesModal']");
ReactDOM.unmountComponentAtNode(statusesModalMountPoint);
clock.restore();
});
QUnit.module('setupGrading', {
@ -6059,13 +6063,12 @@ test('includes the column ids for related assignments when updating column heade
QUnit.module('Gradebook#renderSubmissionTray', {
setup () {
this.mountPointId = 'StudentTray__Container';
$fixtures.innerHTML = `<div id=${this.mountPointId}></div>`;
$fixtures.innerHTML = `<div id="${this.mountPointId}"></div><div id="application"></div>`;
this.gradebook = createGradebook();
this.gradebook.students = {
1101: {
id: '1101',
name: 'Adam Jones',
wtf: true,
assignment_2301: {
assignment_id: '2301', late: false, missing: false, excused: false, seconds_late: 0
}
@ -6093,22 +6096,31 @@ QUnit.module('Gradebook#renderSubmissionTray', {
});
test('shows a submission tray on the page when rendering an open tray', function () {
const clock = sinon.useFakeTimers();
this.gradebook.setSubmissionTrayState(true, '1101', '2301');
this.gradebook.renderSubmissionTray(this.gradebook.student('1101'));
ok(document.querySelector('div[aria-label="Submission tray"]'));
clock.tick(500); // wait for Tray to transition open
ok(document.querySelector('[aria-label="Submission tray"]'));
clock.restore();
});
test('does not show a submission tray on the page when rendering a closed tray', function () {
const clock = sinon.useFakeTimers();
this.gradebook.setSubmissionTrayState(false, '1101', '2301');
this.gradebook.renderSubmissionTray(this.gradebook.student('1101'));
notOk(document.querySelector('div[aria-label="Submission tray"]'));
clock.tick(500); // wait for Tray transition to ensure it has not opened
notOk(document.querySelector('[aria-label="Submission tray"]'));
clock.restore();
});
test('shows a submission tray when the related submission has not loaded for the student', function () {
const clock = sinon.useFakeTimers();
this.gradebook.setSubmissionTrayState(true, '1101', '2301');
this.gradebook.student('1101').assignment_2301 = undefined;
this.gradebook.renderSubmissionTray(this.gradebook.student('1101'));
ok(document.querySelector('div[aria-label="Submission tray"]'));
clock.tick(500); // wait for Tray to transition open
ok(document.querySelector('[aria-label="Submission tray"]'));
clock.restore();
});
QUnit.module('Gradebook#updateRowAndRenderSubmissionTray', {

View File

@ -16,11 +16,16 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { createGradebook } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import { createGradebook, setFixtureHtml } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import AssignmentRowCellPropFactory from 'jsx/gradezilla/default_gradebook/components/AssignmentRowCellPropFactory';
let fixture;
QUnit.module('AssignmentRowCellPropFactory#getProps', {
setup () {
fixture = document.createElement('div');
document.body.appendChild(fixture);
setFixtureHtml(fixture);
this.assignment = { id: '2301' };
this.gradebook = createGradebook({ context_id: '1201' });
this.gradebook.gridSupport = {
@ -31,6 +36,10 @@ QUnit.module('AssignmentRowCellPropFactory#getProps', {
};
this.factory = new AssignmentRowCellPropFactory(this.assignment, this.gradebook);
this.student = { id: '1101', isConcluded: false };
},
teardown () {
fixture.remove();
}
});

View File

@ -22,10 +22,16 @@ import GradebookSettingsModal from 'jsx/gradezilla/default_gradebook/components/
import GradebookSettingsModalApi from 'jsx/gradezilla/default_gradebook/apis/GradebookSettingsModalApi';
import { destroyContainer } from 'jsx/shared/FlashAlert';
let clock;
QUnit.module('GradebookSettingsModal', {
setup () {
clock = sinon.useFakeTimers();
this.qunitTimeout = QUnit.config.testTimeout;
QUnit.config.testTimeout = 1000;
const applicationElement = document.createElement('div');
applicationElement.id = 'application';
document.getElementById('fixtures').appendChild(applicationElement);
},
mountComponent (customProps = {}) {
@ -67,12 +73,14 @@ QUnit.module('GradebookSettingsModal', {
QUnit.config.testTimeout = this.qunitTimeout;
this.wrapper.unmount();
destroyContainer();
document.getElementById('fixtures').innerHTML = '';
clock.restore();
}
});
test('modal is initially closed', function () {
this.mountComponent();
equal(this.wrapper.find('Modal').prop('isOpen'), false);
equal(this.wrapper.find('Modal').prop('open'), false);
});
test('calling open causes the modal to be rendered', function () {
@ -80,7 +88,7 @@ test('calling open causes the modal to be rendered', function () {
const fetchLatePolicy = this.stubLatePolicyFetchSuccess(component);
component.open();
return fetchLatePolicy.then(() => {
equal(this.wrapper.find('Modal').prop('isOpen'), true);
equal(this.wrapper.find('Modal').prop('open'), true);
});
});
@ -89,9 +97,9 @@ test('calling close closes the modal', function () {
const fetchLatePolicy = this.stubLatePolicyFetchSuccess(component);
component.open();
return fetchLatePolicy.then(() => {
equal(this.wrapper.find('Modal').prop('isOpen'), true, 'modal is open');
equal(this.wrapper.find('Modal').prop('open'), true, 'modal is open');
component.close();
equal(this.wrapper.find('Modal').prop('isOpen'), false, 'modal is closed');
equal(this.wrapper.find('Modal').prop('open'), false, 'modal is closed');
});
});
@ -99,10 +107,11 @@ test('clicking cancel closes the modal', function () {
const component = this.mountComponent();
const fetchLatePolicy = this.stubLatePolicyFetchSuccess(component);
component.open();
clock.tick(50); // wait for Modal to transition open
return fetchLatePolicy.then(() => {
equal(this.wrapper.find('Modal').prop('isOpen'), true);
equal(this.wrapper.find('Modal').prop('open'), true);
document.getElementById('gradebook-settings-cancel-button').click();
equal(this.wrapper.find('Modal').prop('isOpen'), false);
equal(this.wrapper.find('Modal').prop('open'), false);
});
});
@ -110,6 +119,7 @@ test('the "Update" button is disabled when the modal opens', function () {
const component = this.mountComponent();
const fetchLatePolicy = this.stubLatePolicyFetchSuccess(component);
component.open();
clock.tick(50); // wait for Modal to transition open
return fetchLatePolicy.then(() => {
const updateButton = document.getElementById('gradebook-settings-update-button')
ok(updateButton.getAttribute('aria-disabled'));
@ -120,6 +130,7 @@ test('the "Update" button is enabled if a setting is changed', function () {
const component = this.mountComponent();
const fetchLatePolicy = this.stubLatePolicyFetchSuccess(component);
component.open();
clock.tick(50); // wait for Modal to transition open
return fetchLatePolicy.then(() => {
component.changeLatePolicy({ ...component.state.latePolicy, changes: { lateSubmissionDeductionEnabled: true } });
const updateButton = document.getElementById('gradebook-settings-update-button');
@ -131,6 +142,7 @@ test('the "Update" button is disabled if a setting is changed, but there are val
const component = this.mountComponent();
const fetchLatePolicy = this.stubLatePolicyFetchSuccess(component);
component.open();
clock.tick(50); // wait for Modal to transition open
return fetchLatePolicy.then(() => {
component.changeLatePolicy({
...component.state.latePolicy,
@ -147,6 +159,7 @@ test('clicking "Update" sends a request to update the late policy', function ()
const component = this.mountComponent();
const fetchLatePolicy = this.stubLatePolicyFetchSuccess(component);
component.open();
clock.tick(50); // wait for Modal to transition open
return fetchLatePolicy.then(() => {
const changes = { lateSubmissionDeductionEnabled: true };
component.changeLatePolicy({ ...component.state.latePolicy, changes });
@ -164,6 +177,7 @@ test('clicking "Update" sends a post request to create a late policy if one does
const component = this.mountComponent();
const fetchLatePolicy = this.stubLatePolicyFetchSuccess(component, { newRecord: true });
component.open();
clock.tick(50); // wait for Modal to transition open
return fetchLatePolicy.then(() => {
const changes = { lateSubmissionDeductionEnabled: true };

View File

@ -21,6 +21,8 @@ import { shallow, mount, ReactWrapper } from 'enzyme';
import StatusesModal from 'jsx/gradezilla/default_gradebook/components/StatusesModal';
import { statusColors } from 'jsx/gradezilla/default_gradebook/constants/colors';
let clock;
function defaultProps (props = {}) {
return {
colors: statusColors(),
@ -30,219 +32,238 @@ function defaultProps (props = {}) {
};
}
QUnit.module('StatusesModal', {
setup () {
this.wrapper = shallow(
<StatusesModal {...defaultProps()} />
);
},
QUnit.module('StatusesModal', function (suiteHooks) {
suiteHooks.beforeEach(function () {
const applicationElement = document.createElement('div');
applicationElement.id = 'application';
document.getElementById('fixtures').appendChild(applicationElement);
clock = sinon.useFakeTimers();
});
teardown () {
this.wrapper.unmount();
}
});
test('modal is initially closed', function () {
strictEqual(this.wrapper.find('Modal').prop('isOpen'), false);
});
test('modal has a label of "Statuses"', function () {
equal(this.wrapper.find('Modal').prop('label'), 'Statuses');
});
test('modal has a close button label of "Close"', function () {
equal(this.wrapper.find('Modal').prop('closeButtonLabel'), 'Close');
});
test('modal has an onRequestClose function', function () {
equal(typeof this.wrapper.find('Modal').prop('onRequestClose'), 'function');
});
test('modal has an onExited function', function () {
equal(typeof this.wrapper.find('Modal').prop('onRequestClose'), 'function');
});
test('modal has a "Statuses" header', function () {
equal(this.wrapper.find('Heading').children().text(), 'Statuses');
});
test('modal has a "Done" button', function () {
equal(this.wrapper.find('Button').children().text(), 'Done');
});
test('modal opens', function () {
this.wrapper.instance().open();
strictEqual(this.wrapper.find('Modal').prop('isOpen'), true);
});
test('modal closes', function () {
const statusModal = this.wrapper.instance();
statusModal.open();
statusModal.close();
strictEqual(this.wrapper.find('Modal').prop('isOpen'), false);
});
test('on close prop is passed to Modal onExit', function () {
const onClose = this.stub();
const wrapper = shallow(<StatusesModal {...defaultProps({ onClose })} />);
equal(wrapper.find('Modal').prop('onExited'), onClose);
});
QUnit.module('StatusesModal#isPopoverShown', {
setup () {
this.wrapper = shallow(<StatusesModal {...defaultProps()} />);
this.instance = this.wrapper.instance();
},
teardown () {
this.wrapper.unmount();
}
});
test('it is true when statuses matches openPopover', function () {
const status = 'late';
this.instance.handleOnToggle(status)(true);
strictEqual(this.instance.isPopoverShown(status), true);
});
test('it is when statuses does not match openPopover', function () {
this.instance.handleOnToggle('late')(true);
strictEqual(this.instance.isPopoverShown('missing'), false);
});
QUnit.module('StatusesModal#updateStatusColors');
test('it calls afterUpdateStatusColors', function () {
const afterUpdateStatusColors = this.stub();
const wrapper = shallow(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.updateStatusColors('late')('#000000');
strictEqual(afterUpdateStatusColors.callCount, 1);
wrapper.unmount();
});
test('it calls afterUpdateStatusColors with updated colors', function () {
const afterUpdateStatusColors = this.stub();
const color = '#000000';
const expectedColors = {
late: color,
missing: '#FFE8E5',
resubmitted: '#E5F7E5',
dropped: '#FEF0E5',
excused: '#FEF7E5'
};
const wrapper = shallow(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.updateStatusColors('late')(color);
deepEqual(afterUpdateStatusColors.firstCall.args[0], expectedColors);
wrapper.unmount();
});
test('it calls afterUpdateStatusColors with updated successFn', function () {
const successFn = this.stub();
function afterUpdateStatusColors (_color, fn) { fn(); }
const wrapper = shallow(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.updateStatusColors('late')('#000000', successFn);
strictEqual(successFn.calledOnce, true);
wrapper.unmount();
});
test('it calls afterUpdateStatusColors and sets openPopover to null', function () {
const successFn = this.stub();
function afterUpdateStatusColors (_color, fn) { fn(); }
const wrapper = shallow(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.updateStatusColors('late')('#000000', successFn);
strictEqual(instance.isPopoverShown(null), true);
wrapper.unmount();
});
test('it calls afterUpdateStatusColors with updated failureFn', function () {
const failureFn = this.stub();
function afterUpdateStatusColors (_color, _fn, fn) { fn(); }
const wrapper = shallow(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.updateStatusColors('late')('#000000', () => {}, failureFn);
strictEqual(failureFn.calledOnce, true);
wrapper.unmount();
});
QUnit.module('StatusesModal Behavior', {
setup () {
this.wrapper = shallow(<StatusesModal {...defaultProps()} />);
this.instance = this.wrapper.instance();
},
teardown () {
this.wrapper.unmount();
}
});
test('clicking Done closes the popover', function () {
const { wrapper, instance } = this;
instance.open();
wrapper.find('Button').simulate('click');
strictEqual(wrapper.find('Modal').prop('isOpen'), false);
});
test('renders five StatusColorListItems', function () {
const { wrapper, instance } = this;
instance.open();
strictEqual(wrapper.find('StatusColorListItem').length, 5);
});
QUnit.module('StatusesModal integration behavior with StatusColorListItem', {
setup () {
const afterUpdateStatusColors = (color, successFn) => successFn();
this.wrapper = mount(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
this.instance = this.wrapper.instance();
},
teardown () {
this.wrapper.unmount();
}
});
test('after clicking apply in the color picker, the color picker popover is closed', function () {
const { wrapper, instance } = this;
instance.open();
const modalContent = new ReactWrapper(wrapper.node.modalContentRef, wrapper.node);
modalContent.find('StatusColorListItem PopoverTrigger Button').at(0).simulate('click');
const colorPickerContent = new ReactWrapper(wrapper.node.colorPickerContents.late, wrapper.node);
const applyButton = colorPickerContent.find('button').findWhere(button => button.prop('children') === 'Apply');
applyButton.simulate('click');
strictEqual(modalContent.find('StatusColorListItem Popover').at(0).prop('show'), false);
});
test('after clicking cancel in the color picker, the color picker popover is closed', function () {
const { wrapper, instance } = this;
instance.open();
const modalContent = new ReactWrapper(wrapper.node.modalContentRef, wrapper.node);
modalContent.find('StatusColorListItem PopoverTrigger Button').at(0).simulate('click');
const colorPickerContent = new ReactWrapper(wrapper.node.colorPickerContents.late, wrapper.node);
const applyButton = colorPickerContent.find('button').findWhere(button => button.prop('children') === 'Cancel');
applyButton.simulate('click');
strictEqual(modalContent.find('StatusColorListItem Popover').at(0).prop('show'), false);
});
QUnit.module('StatusesModal integration behavior with StatusColorListItem');
test('selecting a color and clicking Apply in the color picker passes the ' +
'color to afterUpdateStatusColors', function () {
const afterUpdateStatusColors = this.stub();
const wrapper = mount(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.open();
const modalContent = new ReactWrapper(wrapper.node.modalContentRef, wrapper.node);
modalContent.find('StatusColorListItem PopoverTrigger Button').at(0).simulate('click');
const colorPickerContent = new ReactWrapper(wrapper.node.colorPickerContents.late, wrapper.node);
const whiteSwatch = colorPickerContent.find('button').findWhere(button => button.prop('title') === 'white (#FFFFFF)');
whiteSwatch.simulate('click');
const applyButton = colorPickerContent.find('button').findWhere(button => button.prop('children') === 'Apply');
applyButton.simulate('click');
strictEqual(afterUpdateStatusColors.firstCall.args[0].late, '#FFFFFF');
wrapper.unmount();
suiteHooks.afterEach(function () {
document.getElementById('fixtures').innerHTML = '';
clock.restore();
});
QUnit.module('StatusesModal', {
setup () {
this.wrapper = shallow(
<StatusesModal {...defaultProps()} />
);
},
teardown () {
this.wrapper.unmount();
document.getElementById('fixtures').innerHTML = '';
}
});
test('modal is initially closed', function () {
strictEqual(this.wrapper.find('Modal').prop('open'), false);
});
test('modal has a label of "Statuses"', function () {
equal(this.wrapper.find('Modal').prop('label'), 'Statuses');
});
test('modal has a close button label of "Close"', function () {
equal(this.wrapper.find('Modal').prop('closeButtonLabel'), 'Close');
});
test('modal has an onDismiss function', function () {
equal(typeof this.wrapper.find('Modal').prop('onDismiss'), 'function');
});
test('modal has an onExited function', function () {
equal(typeof this.wrapper.find('Modal').prop('onExited'), 'function');
});
test('modal has a "Statuses" header', function () {
equal(this.wrapper.find('Heading').children().text(), 'Statuses');
});
test('modal has a "Done" button', function () {
equal(this.wrapper.find('Button').children().text(), 'Done');
});
test('modal opens', function () {
this.wrapper.instance().open();
strictEqual(this.wrapper.find('Modal').prop('open'), true);
});
test('modal closes', function () {
const statusModal = this.wrapper.instance();
statusModal.open();
clock.tick(50); // wait for Modal to transition open
statusModal.close();
clock.tick(50); // wait for Modal to transition closed
strictEqual(this.wrapper.find('Modal').prop('open'), false);
});
test('on close prop is passed to Modal onExit', function () {
const onClose = this.stub();
const wrapper = shallow(<StatusesModal {...defaultProps({ onClose })} />);
equal(wrapper.find('Modal').prop('onExited'), onClose);
});
QUnit.module('StatusesModal#isPopoverShown', {
setup () {
this.wrapper = shallow(<StatusesModal {...defaultProps()} />);
this.instance = this.wrapper.instance();
},
teardown () {
this.wrapper.unmount();
}
});
test('it is true when statuses matches openPopover', function () {
const status = 'late';
this.instance.handleOnToggle(status)(true);
strictEqual(this.instance.isPopoverShown(status), true);
});
test('it is when statuses does not match openPopover', function () {
this.instance.handleOnToggle('late')(true);
strictEqual(this.instance.isPopoverShown('missing'), false);
});
QUnit.module('StatusesModal#updateStatusColors');
test('it calls afterUpdateStatusColors', function () {
const afterUpdateStatusColors = this.stub();
const wrapper = shallow(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.updateStatusColors('late')('#000000');
strictEqual(afterUpdateStatusColors.callCount, 1);
wrapper.unmount();
});
test('it calls afterUpdateStatusColors with updated colors', function () {
const afterUpdateStatusColors = this.stub();
const color = '#000000';
const expectedColors = {
late: color,
missing: '#FFE8E5',
resubmitted: '#E5F7E5',
dropped: '#FEF0E5',
excused: '#FEF7E5'
};
const wrapper = shallow(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.updateStatusColors('late')(color);
deepEqual(afterUpdateStatusColors.firstCall.args[0], expectedColors);
wrapper.unmount();
});
test('it calls afterUpdateStatusColors with updated successFn', function () {
const successFn = this.stub();
function afterUpdateStatusColors (_color, fn) { fn(); }
const wrapper = shallow(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.updateStatusColors('late')('#000000', successFn);
strictEqual(successFn.calledOnce, true);
wrapper.unmount();
});
test('it calls afterUpdateStatusColors and sets openPopover to null', function () {
const successFn = this.stub();
function afterUpdateStatusColors (_color, fn) { fn(); }
const wrapper = shallow(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.updateStatusColors('late')('#000000', successFn);
strictEqual(instance.isPopoverShown(null), true);
wrapper.unmount();
});
test('it calls afterUpdateStatusColors with updated failureFn', function () {
const failureFn = this.stub();
function afterUpdateStatusColors (_color, _fn, fn) { fn(); }
const wrapper = shallow(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.updateStatusColors('late')('#000000', () => {}, failureFn);
strictEqual(failureFn.calledOnce, true);
wrapper.unmount();
});
QUnit.module('StatusesModal Behavior', {
setup () {
this.wrapper = shallow(<StatusesModal {...defaultProps()} />);
this.instance = this.wrapper.instance();
},
teardown () {
this.wrapper.unmount();
}
});
test('clicking Done closes the popover', function () {
const { wrapper, instance } = this;
instance.open();
wrapper.find('Button').simulate('click');
strictEqual(wrapper.find('Modal').prop('open'), false);
});
test('renders five StatusColorListItems', function () {
const { wrapper, instance } = this;
instance.open();
strictEqual(wrapper.find('StatusColorListItem').length, 5);
});
QUnit.module('StatusesModal integration behavior with StatusColorListItem', {
setup () {
const afterUpdateStatusColors = (color, successFn) => successFn();
this.wrapper = mount(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
this.instance = this.wrapper.instance();
},
teardown () {
this.wrapper.unmount();
}
});
test('after clicking apply in the color picker, the color picker popover is closed', function () {
const { wrapper, instance } = this;
instance.open();
clock.tick(50); // wait for Modal to transition open
const modalContent = new ReactWrapper(wrapper.node.modalContentRef, wrapper.node);
modalContent.find('StatusColorListItem PopoverTrigger Button').at(0).simulate('click');
const colorPickerContent = new ReactWrapper(wrapper.node.colorPickerContents.late, wrapper.node);
const applyButton = colorPickerContent.find('button').findWhere(button => button.prop('children') === 'Apply');
applyButton.simulate('click');
strictEqual(modalContent.find('StatusColorListItem Popover').at(0).prop('show'), false);
});
test('after clicking cancel in the color picker, the color picker popover is closed', function () {
const { wrapper, instance } = this;
instance.open();
clock.tick(50); // wait for Modal to transition open
const modalContent = new ReactWrapper(wrapper.node.modalContentRef, wrapper.node);
modalContent.find('StatusColorListItem PopoverTrigger Button').at(0).simulate('click');
const colorPickerContent = new ReactWrapper(wrapper.node.colorPickerContents.late, wrapper.node);
const applyButton = colorPickerContent.find('button').findWhere(button => button.prop('children') === 'Cancel');
applyButton.simulate('click');
strictEqual(modalContent.find('StatusColorListItem Popover').at(0).prop('show'), false);
});
QUnit.module('StatusesModal integration behavior with StatusColorListItem');
test('selecting a color and clicking Apply in the color picker passes the ' +
'color to afterUpdateStatusColors', function () {
const afterUpdateStatusColors = this.stub();
const wrapper = mount(<StatusesModal {...defaultProps({ afterUpdateStatusColors })} />);
const instance = wrapper.instance();
instance.open();
clock.tick(50); // wait for Modal to transition open
const modalContent = new ReactWrapper(wrapper.node.modalContentRef, wrapper.node);
modalContent.find('StatusColorListItem PopoverTrigger Button').at(0).simulate('click');
const colorPickerContent = new ReactWrapper(wrapper.node.colorPickerContents.late, wrapper.node);
const whiteSwatch = colorPickerContent.find('button').findWhere(button => button.prop('title') === 'white (#FFFFFF)');
whiteSwatch.simulate('click');
const applyButton = colorPickerContent.find('button').findWhere(button => button.prop('children') === 'Apply');
applyButton.simulate('click');
strictEqual(afterUpdateStatusColors.firstCall.args[0].late, '#FFFFFF');
wrapper.unmount();
});
});

View File

@ -21,11 +21,21 @@ import { mount, ReactWrapper } from 'enzyme';
import SubmissionTray from 'jsx/gradezilla/default_gradebook/components/SubmissionTray';
QUnit.module('SubmissionTray', function (hooks) {
let clock;
let content;
let wrapper;
hooks.beforeEach(function () {
const applicationElement = document.createElement('div');
applicationElement.id = 'application';
document.getElementById('fixtures').appendChild(applicationElement);
clock = sinon.useFakeTimers();
});
hooks.afterEach(function () {
wrapper.unmount();
document.getElementById('fixtures').innerHTML = '';
clock.restore();
});
function mountComponent (props) {
@ -70,6 +80,7 @@ QUnit.module('SubmissionTray', function (hooks) {
selectPreviousAssignment: () => {}
};
wrapper = mount(<SubmissionTray {...defaultProps} {...props} />);
clock.tick(50); // wait for Tray to transition open
}
function avatarDiv () {

View File

@ -17,7 +17,7 @@
*/
import ReactDOM from 'react-dom';
import { createGradebook } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import { createGradebook, setFixtureHtml } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import AssignmentColumnHeaderRenderer
from 'jsx/gradezilla/default_gradebook/slick-grid/column-headers/AssignmentColumnHeaderRenderer';
@ -35,6 +35,8 @@ QUnit.module('AssignmentColumnHeaderRenderer', function (suiteHooks) {
suiteHooks.beforeEach(function () {
$container = document.createElement('div');
document.body.appendChild($container);
setFixtureHtml($container);
gradebook = createGradebook();
@ -58,6 +60,10 @@ QUnit.module('AssignmentColumnHeaderRenderer', function (suiteHooks) {
renderer = new AssignmentColumnHeaderRenderer(gradebook);
});
suiteHooks.afterEach(function() {
$container.remove();
});
QUnit.module('#render', function () {
test('renders the AssignmentColumnHeader to the given container node', function () {
render();

View File

@ -17,7 +17,7 @@
*/
import ReactDOM from 'react-dom';
import { createGradebook } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import { createGradebook, setFixtureHtml } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import AssignmentGroupColumnHeaderRenderer
from 'jsx/gradezilla/default_gradebook/slick-grid/column-headers/AssignmentGroupColumnHeaderRenderer';
@ -35,6 +35,8 @@ QUnit.module('AssignmentGroupColumnHeaderRenderer', function (suiteHooks) {
suiteHooks.beforeEach(function () {
$container = document.createElement('div');
document.body.appendChild($container);
setFixtureHtml($container);
gradebook = createGradebook();
@ -62,6 +64,10 @@ QUnit.module('AssignmentGroupColumnHeaderRenderer', function (suiteHooks) {
renderer = new AssignmentGroupColumnHeaderRenderer(gradebook);
});
suiteHooks.afterEach(function() {
$container.remove();
});
QUnit.module('#render', function () {
test('renders the AssignmentGroupColumnHeader to the given container node', function () {
render();

View File

@ -18,7 +18,7 @@
import I18n from 'i18n!gradebook';
import ReactDOM from 'react-dom';
import { createGradebook } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import { createGradebook, setFixtureHtml } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import CustomColumnHeaderRenderer
from 'jsx/gradezilla/default_gradebook/slick-grid/column-headers/CustomColumnHeaderRenderer';
@ -35,6 +35,8 @@ QUnit.module('CustomColumnHeaderRenderer', function (suiteHooks) {
suiteHooks.beforeEach(function () {
$container = document.createElement('div');
document.body.appendChild($container);
setFixtureHtml($container);
gradebook = createGradebook();
gradebook.gotCustomColumns([
@ -45,6 +47,10 @@ QUnit.module('CustomColumnHeaderRenderer', function (suiteHooks) {
renderer = new CustomColumnHeaderRenderer(gradebook);
});
suiteHooks.afterEach(function() {
$container.remove();
});
QUnit.module('#render', function () {
test('renders the CustomColumnHeader to the given container node', function () {
render();

View File

@ -17,7 +17,7 @@
*/
import ReactDOM from 'react-dom';
import { createGradebook } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import { createGradebook, setFixtureHtml } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import StudentColumnHeaderRenderer
from 'jsx/gradezilla/default_gradebook/slick-grid/column-headers/StudentColumnHeaderRenderer';
@ -33,6 +33,8 @@ QUnit.module('StudentColumnHeaderRenderer', function (suiteHooks) {
suiteHooks.beforeEach(function () {
$container = document.createElement('div');
document.body.appendChild($container);
setFixtureHtml($container);
gradebook = createGradebook({
login_handle_name: 'a_jones',
@ -41,6 +43,10 @@ QUnit.module('StudentColumnHeaderRenderer', function (suiteHooks) {
renderer = new StudentColumnHeaderRenderer(gradebook);
});
suiteHooks.afterEach(function() {
$container.remove();
});
QUnit.module('#render', function () {
test('renders the StudentColumnHeader to the given container node', function () {
render();

View File

@ -17,7 +17,7 @@
*/
import ReactDOM from 'react-dom';
import { createGradebook } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import { createGradebook, setFixtureHtml } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import TotalGradeColumnHeaderRenderer
from 'jsx/gradezilla/default_gradebook/slick-grid/column-headers/TotalGradeColumnHeaderRenderer';
@ -36,6 +36,8 @@ QUnit.module('TotalGradeColumnHeaderRenderer', function (suiteHooks) {
suiteHooks.beforeEach(function () {
$container = document.createElement('div');
document.body.appendChild($container);
setFixtureHtml($container);
gradebook = createGradebook();
columns = {
@ -55,6 +57,10 @@ QUnit.module('TotalGradeColumnHeaderRenderer', function (suiteHooks) {
renderer = new TotalGradeColumnHeaderRenderer(gradebook);
});
suiteHooks.afterEach(function() {
$container.remove();
});
QUnit.module('#render', function () {
test('renders the TotalGradeColumnHeader to the given container node', function () {
render();

View File

@ -16,7 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { createGradebook } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import { createGradebook, setFixtureHtml } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import AssignmentCellFormatter from 'jsx/gradezilla/default_gradebook/slick-grid/formatters/AssignmentCellFormatter';
QUnit.module('AssignmentCellFormatter', function (hooks) {
@ -30,6 +30,7 @@ QUnit.module('AssignmentCellFormatter', function (hooks) {
hooks.beforeEach(function () {
$fixture = document.createElement('div');
document.body.appendChild($fixture);
setFixtureHtml($fixture);
gradebook = createGradebook();
formatter = new AssignmentCellFormatter(gradebook);

View File

@ -16,7 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { createGradebook } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import { createGradebook, setFixtureHtml } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import AssignmentGroupCellFormatter from 'jsx/gradezilla/default_gradebook/slick-grid/formatters/AssignmentGroupCellFormatter';
QUnit.module('AssignmentGroupCellFormatter', function (hooks) {
@ -28,6 +28,7 @@ QUnit.module('AssignmentGroupCellFormatter', function (hooks) {
hooks.beforeEach(function () {
$fixture = document.createElement('div');
document.body.appendChild($fixture);
setFixtureHtml($fixture);
gradebook = createGradebook();
formatter = new AssignmentGroupCellFormatter(gradebook);

View File

@ -16,7 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { createGradebook } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import { createGradebook, setFixtureHtml } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import StudentCellFormatter from 'jsx/gradezilla/default_gradebook/slick-grid/formatters/StudentCellFormatter';
QUnit.module('StudentCellFormatter', function (hooks) {
@ -28,6 +28,7 @@ QUnit.module('StudentCellFormatter', function (hooks) {
hooks.beforeEach(function () {
$fixture = document.createElement('div');
document.body.appendChild($fixture);
setFixtureHtml($fixture);
gradebook = createGradebook({});
formatter = new StudentCellFormatter(gradebook);

View File

@ -16,7 +16,7 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { createGradebook } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import { createGradebook, setFixtureHtml } from 'spec/jsx/gradezilla/default_gradebook/GradebookSpecHelper';
import TotalGradeCellFormatter from 'jsx/gradezilla/default_gradebook/slick-grid/formatters/TotalGradeCellFormatter';
QUnit.module('TotalGradeCellFormatter', function (hooks) {
@ -28,6 +28,7 @@ QUnit.module('TotalGradeCellFormatter', function (hooks) {
hooks.beforeEach(function () {
$fixture = document.createElement('div');
document.body.appendChild($fixture);
setFixtureHtml($fixture);
gradebook = createGradebook({
grading_standard: [['A', 0.9], ['B', 0.8], ['C', 0.7], ['D', 0.6], ['F', 0.0]],

View File

@ -202,10 +202,11 @@ define([
});
});
test('starts polling for progress and returns a rejected promise on progress failure', function () {
test('starts polling for progress and returns a rejected promise on progress failure', function (assert) {
const done = assert.async();
const expectedMonitoringUrl = `${monitoringBase}/newProgressId`;
this.subject = new GradebookExportManager(exportingUrl, currentUserId);
this.subject = new GradebookExportManager(exportingUrl, currentUserId, null, 1);
moxios.stubRequest(expectedMonitoringUrl, {
status: 200,
@ -217,13 +218,15 @@ define([
return this.subject.startExport().catch((reason) => {
equal(reason, 'Error exporting gradebook: Arbitrary failure');
done();
});
});
test('starts polling for progress and returns a rejected promise on unknown progress status', function () {
test('starts polling for progress and returns a rejected promise on unknown progress status', function (assert) {
const done = assert.async();
const expectedMonitoringUrl = `${monitoringBase}/newProgressId`;
this.subject = new GradebookExportManager(exportingUrl, currentUserId);
this.subject = new GradebookExportManager(exportingUrl, currentUserId, null, 1);
moxios.stubRequest(expectedMonitoringUrl, {
status: 200,
@ -235,14 +238,16 @@ define([
return this.subject.startExport().catch((reason) => {
equal(reason, 'Error exporting gradebook: Pattern buffer degradation');
done();
});
});
test('starts polling for progress and returns a fulfilled promise on progress completion', function () {
test('starts polling for progress and returns a fulfilled promise on progress completion', function (assert) {
const done = assert.async();
const expectedMonitoringUrl = `${monitoringBase}/newProgressId`;
const expectedAttachmentUrl = `${attachmentBase}/newAttachmentId`;
this.subject = new GradebookExportManager(exportingUrl, currentUserId);
this.subject = new GradebookExportManager(exportingUrl, currentUserId, null, 1);
moxios.stubRequest(expectedMonitoringUrl, {
status: 200,
@ -267,6 +272,7 @@ define([
updatedAt: '2009-01-20T17:00:00Z'
};
deepEqual(resolution, expectedResolution);
done();
});
});
});

View File

@ -42,24 +42,6 @@ define([
handleRequestClose () {}
});
test('sets appElment to application div', () => {
const wrapper = shallow(<ConfirmEndTutorialDialog {...getDefaultProps()} />);
equal(wrapper.instance().appElement, $appElement[0]);
});
test('handleModalReady sets aria-hidden on appElement', () => {
const wrapper = shallow(<ConfirmEndTutorialDialog {...getDefaultProps()} />);
wrapper.instance().handleModalReady();
equal($appElement.attr('aria-hidden'), 'true');
});
test('handleModalClose removes aria-hidden from appElement', () => {
const wrapper = shallow(<ConfirmEndTutorialDialog {...getDefaultProps()} />);
$appElement.attr('aria-hidden', 'true')
wrapper.instance().handleModalClose()
ok(!$appElement.attr('aria-hidden'));
});
test('handleOkayButtonClick calls the proper api endpoint and data', () => {
const spy = sinon.spy(axios, 'put');
const wrapper = shallow(<ConfirmEndTutorialDialog {...getDefaultProps()} />);

View File

@ -22,9 +22,20 @@ import {shallow, mount} from 'enzyme';
import TutorialTray from 'jsx/new_user_tutorial/trays/TutorialTray';
import createTutorialStore from 'jsx/new_user_tutorial/utils/createTutorialStore'
QUnit.module('TutorialTray Spec');
QUnit.module('TutorialTray Spec', {
setup () {
const applicationElement = document.createElement('div');
applicationElement.id = 'application';
document.getElementById('fixtures').appendChild(applicationElement);
store = createTutorialStore();
},
const store = createTutorialStore();
teardown () {
document.getElementById('fixtures').innerHTML = '';
}
});
let store;
const getDefaultProps = overrides => (
Object.assign({}, {
@ -47,6 +58,7 @@ test('Renders', () => {
</TutorialTray>
);
ok(wrapper.exists());
wrapper.unmount()
});
test('handleEntering sets focus on the toggle button', () => {
@ -55,13 +67,11 @@ test('handleEntering sets focus on the toggle button', () => {
<div>Some Content</div>
</TutorialTray>
);
wrapper.setState({
isCollapsed: false
});
wrapper.instance().handleToggleClick();
wrapper.instance().handleEntering();
ok(wrapper.instance().toggleButton.button.focused);
wrapper.unmount()
});
test('handleExiting calls focus on the return value of the returnFocusToFunc', () => {
@ -76,6 +86,7 @@ test('handleExiting calls focus on the return value of the returnFocusToFunc', (
wrapper.instance().handleExiting();
ok(spy.called);
wrapper.unmount()
});
test('handleToggleClick toggles the isCollapsed state of the store', () => {
@ -88,6 +99,7 @@ test('handleToggleClick toggles the isCollapsed state of the store', () => {
wrapper.instance().handleToggleClick();
ok(store.getState().isCollapsed);
wrapper.unmount()
});
test('initial state sets endUserTutorialShown to false', () => {
@ -98,6 +110,7 @@ test('initial state sets endUserTutorialShown to false', () => {
);
equal(wrapper.state('endUserTutorialShown'), false);
wrapper.unmount()
});
test('handleEndTutorialClick sets endUserTutorialShown to true', () => {
@ -110,6 +123,7 @@ test('handleEndTutorialClick sets endUserTutorialShown to true', () => {
wrapper.instance().handleEndTutorialClick();
equal(wrapper.state('endUserTutorialShown'), true);
wrapper.unmount()
});
test('closeEndTutorialDialog sets endUserTutorialShown to false', () => {
@ -122,4 +136,5 @@ test('closeEndTutorialDialog sets endUserTutorialShown to false', () => {
wrapper.instance().closeEndTutorialDialog();
equal(wrapper.state('endUserTutorialShown'), false);
wrapper.unmount()
});

View File

@ -35,18 +35,27 @@ define([
{ default: Transition }
) => {
let $domNode, subject
let $domNode, subject, fixtures
const renderComponent = (props) => {
$domNode = $domNode || document.createElement('div')
$domNode = document.createElement('div')
fixtures.appendChild($domNode)
return ReactDOM.render(<MessageStudents { ...props } />, $domNode)
}
QUnit.module('MessageStudents', (hooks) => {
hooks.beforeEach(() => {
fixtures = document.getElementById('fixtures')
const appElement = document.createElement('div')
appElement.id = 'application'
fixtures.appendChild(appElement)
})
hooks.afterEach(() => {
ReactDOM.unmountComponentAtNode($domNode)
$domNode = null
subject= null
fixtures.innerHTML = ''
})
test('it renders', () => {

View File

@ -25,6 +25,10 @@ shared_context "blueprint lock context" do
f('.bpc-lock-toggle__label')
end
def blueprint_lock_icon_button
blueprint_lock_icon_label.find_element(:xpath, '../../parent::button')
end
def associated_index_lock_icon
f('#content-wrapper.ic-Layout-contentWrapper')
end
@ -59,12 +63,12 @@ shared_context "blueprint lock context" do
expect(element).not_to contain_css(@locked_button_css) # the item is now unlocked.
end
def verify_show_page_locked(element)
def verify_show_page_locked
element = blueprint_lock_icon_label
expect(element).to include_text("Locked") # verify item is locked
end
def verify_show_page_unlocked(element)
def verify_show_page_unlocked
element = blueprint_lock_icon_label
expect(element).to include_text("Blueprint") # verify the item is unlocked
end
@ -271,18 +275,15 @@ describe "master courses - locked items" do
@tag.update(restrictions: {content: true}) # lock the item. Does not require a migration.
get "/courses/#{@master.id}/assignments/#{@assignment.id}"
element = blueprint_lock_icon_label
verify_show_page_locked(element)
element.click
verify_show_page_locked
blueprint_lock_icon_button.click
refresh_page
element = blueprint_lock_icon_label
verify_show_page_unlocked(element)
element.click
verify_show_page_unlocked
blueprint_lock_icon_button.click
refresh_page
element = blueprint_lock_icon_label
verify_show_page_locked(element)
verify_show_page_locked
end
it "discussions show a lock icon on the show page", priority: "2", test_id: 3127582 do
@ -290,18 +291,15 @@ describe "master courses - locked items" do
@tag.update(restrictions: {content: true}) # lock the item. Does not require a migration.
get "/courses/#{@master.id}/discussion_topics/#{@discussion.id}"
element = blueprint_lock_icon_label
verify_show_page_locked(element)
element.click
verify_show_page_locked
blueprint_lock_icon_button.click
refresh_page
element = blueprint_lock_icon_label
verify_show_page_unlocked(element)
element.click
verify_show_page_unlocked
blueprint_lock_icon_button.click
refresh_page
element = blueprint_lock_icon_label
verify_show_page_locked(element)
verify_show_page_locked
end
it "pages show a lock icon on the show page", priority: "2", test_id: 3127583 do
@ -309,18 +307,15 @@ describe "master courses - locked items" do
@tag.update(restrictions: {content: true}) # lock the item. Does not require a migration.
get "/courses/#{@master.id}/pages/#{@page.id}"
element = blueprint_lock_icon_label
verify_show_page_locked(element)
element.click
verify_show_page_locked
blueprint_lock_icon_button.click
refresh_page
element = blueprint_lock_icon_label
verify_show_page_unlocked(element)
element.click
verify_show_page_unlocked
blueprint_lock_icon_button.click
refresh_page
element = blueprint_lock_icon_label
verify_show_page_locked(element)
verify_show_page_locked
end
it "quizzes show a lock icon on the show page", priority: "2", test_id: 3127584 do
@ -328,18 +323,15 @@ describe "master courses - locked items" do
@tag.update(restrictions: {content: true}) # lock the item. Does not require a migration.
get "/courses/#{@master.id}/quizzes/#{@quiz.id}"
element = blueprint_lock_icon_label
verify_show_page_locked(element)
element.click
verify_show_page_locked
blueprint_lock_icon_button.click
refresh_page
element = blueprint_lock_icon_label
verify_show_page_unlocked(element)
element.click
verify_show_page_unlocked
blueprint_lock_icon_button.click
refresh_page
element = blueprint_lock_icon_label
verify_show_page_locked(element)
verify_show_page_locked
end
end
end

View File

@ -29,7 +29,7 @@ shared_context "blueprint sidebar context" do
end
def blueprint_open_sidebar_button
f('.blueprint__root .bcs__wrapper .bcs__trigger')
f('.blueprint__root .bcs__wrapper .bcs__trigger button')
end
def sync_modal_send_notification_checkbox
@ -136,7 +136,7 @@ describe "master courses sidebar" do
get "/courses/#{@master.id}"
blueprint_open_sidebar_button.click
f('button#mcSyncHistoryBtn').click
expect(f('div[aria-label="Sync History"]')).to be_displayed
expect(f('span[aria-label="Sync History"]')).to be_displayed
expect(f('#application')).to have_attribute('aria-hidden', 'true')
end
@ -146,7 +146,7 @@ describe "master courses sidebar" do
wait_for_ajaximations
f('button#mcUnsyncedChangesBtn').click
wait_for_ajaximations
expect(f('div[aria-label="Unsynced Changes"]')).to be_displayed
expect(f('span[aria-label="Unsynced Changes"]')).to be_displayed
expect(f('#application')).to have_attribute('aria-hidden', 'true')
end
@ -177,7 +177,7 @@ describe "master courses sidebar" do
get "/courses/#{@master.id}"
blueprint_open_sidebar_button.click
f('button#mcSidebarAsscBtn').click
expect(f('div[aria-label="Associations"]')).to be_displayed
expect(f('span[aria-label="Associations"]')).to be_displayed
end
it "limits notification message to 140 characters", priority: "2", test_id: 3186725 do

1137
yarn.lock

File diff suppressed because it is too large Load Diff