A2: teacher toolbox and code reorg
This is the first stab at implementing the teacher toolbox. It also moves code toward the desired organization and frameworks. closes ADMIN-1507 test plan: - assignments 2 teacher view shows data on the right side of the header -> "X" is used as a placeholder value for values we don't have yet - "X to grade" goes to the speedgrader for the assignment - clicking on "Published" toggle shows a placeholder alert for the action - clicking on "X unsubmitted" shows a placeholder alert for the action Change-Id: I45f51789e2c3722f14482ab57d8d12244cff31b4 Reviewed-on: https://gerrit.instructure.com/170766 Tested-by: Jenkins Reviewed-by: Ed Schiebel <eschiebel@instructure.com> QA-Review: Ed Schiebel <eschiebel@instructure.com> QA-Review: Anju Reddy <areddy@instructure.com> Product-Review: Jon Willesen <jonw+gerrit@instructure.com>
This commit is contained in:
parent
cc1aab6d53
commit
1898f2aa06
|
@ -1,29 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders normally 1`] = `
|
||||
<div>
|
||||
<h1>
|
||||
an assignment
|
||||
</h1>
|
||||
<div>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="medium"
|
||||
>
|
||||
Points Possible:
|
||||
42
|
||||
</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text
|
||||
as="span"
|
||||
letterSpacing="normal"
|
||||
size="medium"
|
||||
>
|
||||
Due:
|
||||
some time
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -1,63 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders 1`] = `
|
||||
<TabList
|
||||
defaultSelectedIndex={0}
|
||||
focus={false}
|
||||
variant="minimal"
|
||||
>
|
||||
<TabPanel
|
||||
id={null}
|
||||
labelledBy={null}
|
||||
padding="small"
|
||||
selected={false}
|
||||
tabRef={[Function]}
|
||||
title="Details"
|
||||
variant="simple"
|
||||
>
|
||||
<Details
|
||||
assignment={
|
||||
Object {
|
||||
"description": "<p>some assignment description</p>",
|
||||
"dueAt": "due",
|
||||
"name": "title",
|
||||
"pointsPossible": 42,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</TabPanel>
|
||||
<TabPanel
|
||||
id={null}
|
||||
labelledBy={null}
|
||||
padding="small"
|
||||
selected={false}
|
||||
tabRef={[Function]}
|
||||
title="Students"
|
||||
variant="simple"
|
||||
>
|
||||
Students
|
||||
</TabPanel>
|
||||
<TabPanel
|
||||
id={null}
|
||||
labelledBy={null}
|
||||
padding="small"
|
||||
selected={false}
|
||||
tabRef={[Function]}
|
||||
title="Rubric"
|
||||
variant="simple"
|
||||
>
|
||||
Rubric
|
||||
</TabPanel>
|
||||
<TabPanel
|
||||
id={null}
|
||||
labelledBy={null}
|
||||
padding="small"
|
||||
selected={false}
|
||||
tabRef={[Function]}
|
||||
title="Settings"
|
||||
variant="simple"
|
||||
>
|
||||
Settings
|
||||
</TabPanel>
|
||||
</TabList>
|
||||
`;
|
|
@ -1,11 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders and converts 1`] = `
|
||||
<div
|
||||
dangerouslySetInnerHTML={
|
||||
Object {
|
||||
"__html": "converted <p>some assignment description</p>",
|
||||
}
|
||||
}
|
||||
/>
|
||||
`;
|
|
@ -1,27 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders normally 1`] = `
|
||||
<div>
|
||||
Assignments 2 Teacher View
|
||||
<AssignmentHeader
|
||||
assignment={
|
||||
Object {
|
||||
"description": "an assignment",
|
||||
"dueAt": "The Future",
|
||||
"name": "What is the Answer?",
|
||||
"pointsPossible": 42,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<ContentTabs
|
||||
assignment={
|
||||
Object {
|
||||
"description": "an assignment",
|
||||
"dueAt": "The Future",
|
||||
"name": "What is the Answer?",
|
||||
"pointsPossible": 42,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
`;
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
import React from 'react'
|
||||
import TabList, {TabPanel} from '@instructure/ui-tabs/lib/components/TabList'
|
||||
import {AssignmentShape} from '../shared/shapes'
|
||||
import {AssignmentShape} from '../shapes'
|
||||
import Details from './Details'
|
||||
|
||||
ContentTabs.propTypes = {
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
import React from 'react'
|
||||
import apiUserContent from 'compiled/str/apiUserContent'
|
||||
import {AssignmentShape} from '../shared/shapes'
|
||||
import {AssignmentShape} from '../shapes'
|
||||
|
||||
Details.propTypes = {
|
||||
assignment: AssignmentShape.isRequired
|
||||
|
@ -31,6 +31,5 @@ export default function Details(props) {
|
|||
const convertedHtml = apiUserContent.convert(description)
|
||||
|
||||
// html is sanitized on the server side
|
||||
// eslint-disable-next-line react/no-danger
|
||||
return <div dangerouslySetInnerHTML={{__html: convertedHtml}} />
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* 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 {func} from 'prop-types'
|
||||
|
||||
import I18n from 'i18n!assignments_2'
|
||||
|
||||
import Flex, {FlexItem} from '@instructure/ui-layout/lib/components/Flex'
|
||||
import Text from '@instructure/ui-elements/lib/components/Text'
|
||||
|
||||
import {AssignmentShape} from '../shapes'
|
||||
import Toolbox from './Toolbox'
|
||||
|
||||
export default class Header extends React.Component {
|
||||
static propTypes = {
|
||||
assignment: AssignmentShape.isRequired,
|
||||
onUnsubmittedClick: func,
|
||||
onPublishChange: func
|
||||
}
|
||||
|
||||
renderPoints() {
|
||||
return (
|
||||
<span style={{lineHeight: '1'}}>
|
||||
<Text size="x-large">{this.props.assignment.pointsPossible}</Text>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
renderPointsLabel() {
|
||||
return <Text weight="bold">{I18n.t('Points')}</Text>
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Flex as="div" justifyItems="space-between">
|
||||
<FlexItem>
|
||||
<h1>{this.props.assignment.name}</h1>
|
||||
</FlexItem>
|
||||
<FlexItem>
|
||||
<Flex direction="column" textAlign="end">
|
||||
<FlexItem>
|
||||
<Toolbox {...this.props} />
|
||||
</FlexItem>
|
||||
<FlexItem padding="medium 0 0 0">{this.renderPoints()}</FlexItem>
|
||||
<FlexItem>{this.renderPointsLabel()}</FlexItem>
|
||||
</Flex>
|
||||
</FlexItem>
|
||||
</Flex>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 I18n from 'i18n!assignments_2'
|
||||
|
||||
import CloseButton from '@instructure/ui-buttons/lib/components/CloseButton'
|
||||
import Modal, {
|
||||
ModalHeader,
|
||||
ModalBody
|
||||
// ModalFooter
|
||||
} from '@instructure/ui-overlays/lib/components/Modal'
|
||||
|
||||
export default function MessageStudentsWho(props) {
|
||||
return (
|
||||
<Modal label={I18n.t('Message Students Who')} {...props}>
|
||||
<ModalHeader>
|
||||
<CloseButton placement="end" variant="icon" onClick={props.onDismiss}>
|
||||
{I18n.t('Close')}
|
||||
</CloseButton>
|
||||
</ModalHeader>
|
||||
<ModalBody>
|
||||
<div data-testid="message-students-who">Message Students Who</div>
|
||||
</ModalBody>
|
||||
</Modal>
|
||||
)
|
||||
}
|
|
@ -21,9 +21,10 @@ import {bool, shape, string} from 'prop-types'
|
|||
import {graphql} from 'react-apollo'
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
import {AssignmentShape} from '../shared/shapes'
|
||||
import AssignmentHeader from '../shared/AssignmentHeader'
|
||||
import {AssignmentShape} from '../shapes'
|
||||
import Header from './Header'
|
||||
import ContentTabs from './ContentTabs'
|
||||
import MessageStudentsWho from './MessageStudentsWho'
|
||||
|
||||
export class CoreTeacherView extends React.Component {
|
||||
static propTypes = {
|
||||
|
@ -34,8 +35,27 @@ export class CoreTeacherView extends React.Component {
|
|||
}).isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
messageStudentsWhoOpen: false
|
||||
}
|
||||
}
|
||||
|
||||
handlePublishChange = () => {
|
||||
alert('publish toggle clicked')
|
||||
}
|
||||
|
||||
handleUnsubmittedClick = () => {
|
||||
this.setState({messageStudentsWhoOpen: true})
|
||||
}
|
||||
|
||||
handleDismissMessageStudentsWho = () => {
|
||||
this.setState({messageStudentsWhoOpen: false})
|
||||
}
|
||||
|
||||
renderError(error) {
|
||||
return <div>Error: {error}</div>
|
||||
return <pre>Error: {JSON.stringify(error, null, 2)}</pre>
|
||||
}
|
||||
|
||||
renderLoading() {
|
||||
|
@ -51,9 +71,16 @@ export class CoreTeacherView extends React.Component {
|
|||
|
||||
return (
|
||||
<div>
|
||||
Assignments 2 Teacher View
|
||||
<AssignmentHeader assignment={assignment} />
|
||||
<Header
|
||||
assignment={assignment}
|
||||
onUnsubmittedClick={this.handleUnsubmittedClick}
|
||||
onPublishChange={this.handlePublishChange}
|
||||
/>
|
||||
<ContentTabs assignment={assignment} />
|
||||
<MessageStudentsWho
|
||||
open={this.state.messageStudentsWhoOpen}
|
||||
onDismiss={this.handleDismissMessageStudentsWho}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -61,14 +88,17 @@ export class CoreTeacherView extends React.Component {
|
|||
|
||||
const TeacherQuery = gql`
|
||||
query GetAssignment($assignmentLid: ID!) {
|
||||
assignment: legacyNode(type: Assignment, _id: $assignmentLid) {
|
||||
... on Assignment {
|
||||
assignment(id: $assignmentLid) {
|
||||
lid: _id
|
||||
gid: id
|
||||
name
|
||||
description
|
||||
dueAt
|
||||
pointsPossible
|
||||
state
|
||||
|
||||
course {
|
||||
lid: _id
|
||||
gid: id
|
||||
name
|
||||
description
|
||||
dueAt
|
||||
pointsPossible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,11 +112,9 @@ const TeacherView = graphql(TeacherQuery, {
|
|||
})
|
||||
})(CoreTeacherView)
|
||||
|
||||
TeacherView.propTypes = Object.assign(
|
||||
{
|
||||
assignmentLid: string.isRequired
|
||||
},
|
||||
TeacherView.propTypes
|
||||
)
|
||||
TeacherView.propTypes = {
|
||||
assignmentLid: string.isRequired,
|
||||
...TeacherView.propTypes
|
||||
}
|
||||
|
||||
export default TeacherView
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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 {func} from 'prop-types'
|
||||
|
||||
import I18n from 'i18n!assignments_2'
|
||||
|
||||
import Checkbox from '@instructure/ui-forms/lib/components/Checkbox'
|
||||
import Flex, {FlexItem} from '@instructure/ui-layout/lib/components/Flex'
|
||||
import Link from '@instructure/ui-elements/lib/components/Link'
|
||||
import Text from '@instructure/ui-elements/lib/components/Text'
|
||||
|
||||
import IconEmail from '@instructure/ui-icons/lib/Line/IconEmail'
|
||||
import IconSpeedGrader from '@instructure/ui-icons/lib/Line/IconSpeedGrader'
|
||||
|
||||
import {AssignmentShape} from '../shapes'
|
||||
|
||||
export default class Toolbox extends React.Component {
|
||||
static propTypes = {
|
||||
assignment: AssignmentShape.isRequired,
|
||||
onUnsubmittedClick: func,
|
||||
onPublishChange: func
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
onUnsubmittedClick: () => {},
|
||||
onPublishChange: () => {}
|
||||
}
|
||||
|
||||
renderPublished() {
|
||||
// TODO: put the label on the left side of the toggle when checkbox supports it
|
||||
return (
|
||||
<Checkbox
|
||||
label={I18n.t('Published')}
|
||||
variant="toggle"
|
||||
size="medium"
|
||||
checked={this.props.assignment.state === 'published'}
|
||||
onChange={this.props.onPublishChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
renderSpeedGraderLink() {
|
||||
const assignmentLid = this.props.assignment.lid
|
||||
const courseLid = this.props.assignment.course.lid
|
||||
const speedgraderLink = `/courses/${courseLid}/gradebook/speed_grader?assignment_id=${assignmentLid}`
|
||||
return (
|
||||
<Link href={speedgraderLink} icon={<IconSpeedGrader />} iconPlacement="end">
|
||||
<Text transform="uppercase" size="small" color="primary">
|
||||
{I18n.t('%{number} to grade', {number: 'X'})}
|
||||
</Text>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
renderUnsubmittedButton() {
|
||||
return (
|
||||
<Link icon={<IconEmail />} iconPlacement="end" onClick={this.props.onUnsubmittedClick}>
|
||||
<Text transform="uppercase" size="small" color="primary">
|
||||
{I18n.t('%{number} unsubmitted', {number: 'X'})}
|
||||
</Text>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div data-testid="teacher-toolbox">
|
||||
<Flex direction="column" textAlign="end">
|
||||
<FlexItem padding="0 0 medium 0">{this.renderPublished()}</FlexItem>
|
||||
<FlexItem>{this.renderSpeedGraderLink()}</FlexItem>
|
||||
<FlexItem>{this.renderUnsubmittedButton()}</FlexItem>
|
||||
</Flex>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
|
@ -17,15 +17,10 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {shallow} from 'enzyme'
|
||||
import {render} from 'react-testing-library'
|
||||
import {mockAssignment} from '../../test-utils'
|
||||
import ContentTabs from '../ContentTabs'
|
||||
|
||||
it('renders', () => {
|
||||
const assignment = {
|
||||
name: 'title',
|
||||
pointsPossible: 42,
|
||||
dueAt: 'due',
|
||||
description: '<p>some assignment description</p>'
|
||||
}
|
||||
expect(shallow(<ContentTabs assignment={assignment} />)).toMatchSnapshot()
|
||||
render(<ContentTabs assignment={mockAssignment()} />)
|
||||
})
|
|
@ -17,7 +17,8 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {shallow} from 'enzyme'
|
||||
import {render} from 'react-testing-library'
|
||||
import {mockAssignment} from '../../test-utils'
|
||||
import apiUserContent from 'compiled/str/apiUserContent'
|
||||
import Details from '../Details'
|
||||
|
||||
|
@ -25,13 +26,7 @@ jest.mock('compiled/str/apiUserContent')
|
|||
apiUserContent.convert = jest.fn(arg => `converted ${arg}`)
|
||||
|
||||
it('renders and converts', () => {
|
||||
const assignment = {
|
||||
name: 'title',
|
||||
pointsPossible: 42,
|
||||
dueAt: 'due',
|
||||
description: '<p>some assignment description</p>'
|
||||
}
|
||||
const wrapper = shallow(<Details assignment={assignment} />)
|
||||
// snapshot also tests that the content was converted
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
const assignment = mockAssignment()
|
||||
const {getByText} = render(<Details assignment={assignment} />)
|
||||
getByText(`converted ${assignment.description}`)
|
||||
})
|
|
@ -17,21 +17,14 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {shallow} from 'enzyme'
|
||||
import {CoreTeacherView} from '../TeacherView'
|
||||
import {render} from 'react-testing-library'
|
||||
import {mockAssignment} from '../../test-utils'
|
||||
import Header from '../Header'
|
||||
|
||||
it('renders normally', () => {
|
||||
const wrapper = shallow(
|
||||
<CoreTeacherView
|
||||
data={{
|
||||
assignment: {
|
||||
name: 'What is the Answer?',
|
||||
dueAt: 'The Future',
|
||||
pointsPossible: 42,
|
||||
description: 'an assignment'
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
it('renders basic assignment information', () => {
|
||||
const assignment = mockAssignment()
|
||||
const {container, getByTestId} = render(<Header assignment={mockAssignment()} />)
|
||||
expect(container).toHaveTextContent(assignment.name)
|
||||
expect(container).toHaveTextContent(assignment.pointsPossible.toString())
|
||||
expect(getByTestId('teacher-toolbox')).toBeInTheDocument()
|
||||
})
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 {render, fireEvent, wait} from 'react-testing-library'
|
||||
import {mockAssignment} from '../../test-utils'
|
||||
import {CoreTeacherView} from '../TeacherView'
|
||||
|
||||
it('shows the message students who dialog when the unsubmitted button is clicked', async () => {
|
||||
const {getByText} = render(<CoreTeacherView data={{assignment: mockAssignment()}} />)
|
||||
fireEvent.click(getByText(/unsubmitted/))
|
||||
// waitForElement would be much more convenient and less redundant, but it
|
||||
// doesn't work with the MutationObserver that Canvas installs in
|
||||
// jest-setup.js. Figure this out later.
|
||||
await wait(() => getByText('Message Students Who'))
|
||||
expect(getByText('Message Students Who')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
// tests to implement somewhere
|
||||
it.skip('renders a loading screen when waiting on the initial query', () => {})
|
||||
it.skip('renders a problem screen on a bad graphql query', () => {})
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 {render} from 'react-testing-library'
|
||||
import {closest, mockAssignment} from '../../test-utils'
|
||||
import Toolbox from '../Toolbox'
|
||||
|
||||
it('renders basic information', () => {
|
||||
const assignment = mockAssignment()
|
||||
const {getByText, getByLabelText} = render(<Toolbox assignment={assignment} />)
|
||||
expect(getByLabelText('Published').getAttribute('checked')).toBe('')
|
||||
const sgLink = closest(getByText('X to grade'), 'a')
|
||||
expect(sgLink).toBeTruthy()
|
||||
expect(sgLink.getAttribute('href')).toMatch(
|
||||
/\/courses\/course-lid\/gradebook\/speed_grader\?assignment_id=assignment-lid/
|
||||
)
|
||||
expect(closest(getByText('X unsubmitted'), 'button')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('renders unpublished value checkbox', () => {
|
||||
const {getByLabelText} = render(<Toolbox assignment={mockAssignment({state: 'unpublished'})} />)
|
||||
expect(getByLabelText('Published').getAttribute('checked')).toBeFalsy()
|
||||
})
|
|
@ -16,7 +16,7 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {bool, number, shape, string} from 'prop-types'
|
||||
import {bool, number, oneOf, shape, string} from 'prop-types'
|
||||
|
||||
// This ENV shape is for the controller's current show action. We'll have
|
||||
// something different when assignments are being created, which is a different
|
||||
|
@ -37,9 +37,15 @@ export const EnvShape = shape({
|
|||
}).isRequired
|
||||
})
|
||||
|
||||
export const CourseShape = shape({
|
||||
lid: string.isRequired
|
||||
})
|
||||
|
||||
export const AssignmentShape = shape({
|
||||
name: string.isRequired,
|
||||
pointsPossible: number.isRequired,
|
||||
dueAt: string.isRequired, // temporary
|
||||
description: string.isRequired
|
||||
description: string.isRequired,
|
||||
state: oneOf(['published', 'unpublished']).isRequired,
|
||||
course: CourseShape.isRequired
|
||||
})
|
|
@ -16,25 +16,30 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import Text from '@instructure/ui-elements/lib/components/Text'
|
||||
|
||||
import {AssignmentShape} from './shapes'
|
||||
|
||||
AssignmentHeader.propTypes = {
|
||||
assignment: AssignmentShape.isRequired
|
||||
// because our version of jsdom doesn't support elt.closest('a') yet. Should soon.
|
||||
export function closest(el, selector) {
|
||||
while (el && !el.matches(selector)) {
|
||||
el = el.parentElement
|
||||
}
|
||||
return el
|
||||
}
|
||||
|
||||
export default function AssignmentHeader(props) {
|
||||
return (
|
||||
<div>
|
||||
<h1>{props.assignment.name}</h1>
|
||||
<div>
|
||||
<Text>Points Possible: {props.assignment.pointsPossible}</Text>
|
||||
</div>
|
||||
<div>
|
||||
<Text>Due: {props.assignment.dueAt}</Text>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
export function mockCourse(overrides) {
|
||||
return {
|
||||
lid: 'course-lid',
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
export function mockAssignment(overrides) {
|
||||
return {
|
||||
name: 'assignment name',
|
||||
description: 'assignment description',
|
||||
lid: 'assignment-lid',
|
||||
dueAt: 'due-at',
|
||||
pointsPossible: 5,
|
||||
state: 'published',
|
||||
course: mockCourse(),
|
||||
...overrides
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ import ReactDOM from 'react-dom'
|
|||
import ApolloClient from 'apollo-boost'
|
||||
import {ApolloProvider} from 'react-apollo'
|
||||
|
||||
import TeacherView from './teacher/TeacherView'
|
||||
import TeacherView from './teacher/components/TeacherView'
|
||||
|
||||
const apolloClient = new ApolloClient({
|
||||
uri: '/api/graphql',
|
||||
|
|
|
@ -37,6 +37,7 @@ module.exports = {
|
|||
'jest-canvas-mock',
|
||||
'<rootDir>/jest/jest-setup.js'
|
||||
],
|
||||
setupTestFrameworkScriptFile: '<rootDir>/jest/jest-setup-framework.js',
|
||||
testMatch: [
|
||||
'**/__tests__/**/?(*.)(spec|test).js'
|
||||
],
|
||||
|
|
|
@ -16,17 +16,5 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {shallow} from 'enzyme'
|
||||
import AssignmentHeader from '../AssignmentHeader'
|
||||
|
||||
it('renders normally', () => {
|
||||
const assignment = {
|
||||
name: 'an assignment',
|
||||
pointsPossible: 42,
|
||||
dueAt: 'some time',
|
||||
description: 'an assignment'
|
||||
}
|
||||
const wrapper = shallow(<AssignmentHeader assignment={assignment} />)
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
})
|
||||
import 'jest-dom/extend-expect'
|
||||
import 'react-testing-library/cleanup-after-each'
|
|
@ -164,6 +164,7 @@
|
|||
"istanbul-merge": "^1.1.1",
|
||||
"jest": "^23",
|
||||
"jest-canvas-mock": "^1",
|
||||
"jest-dom": "^2",
|
||||
"jest-junit": "^5",
|
||||
"jest-localstorage-mock": "^2",
|
||||
"json-loader": "^0.5.7",
|
||||
|
@ -188,6 +189,7 @@
|
|||
"qunitjs": "^1.14.0",
|
||||
"raven-js": "^3.26.2",
|
||||
"react-test-renderer": "^16",
|
||||
"react-testing-library": "^5",
|
||||
"redux-logger": "2.6.1",
|
||||
"requirejs": "~2.2.0",
|
||||
"sass-direction": "^1",
|
||||
|
|
41
yarn.lock
41
yarn.lock
|
@ -930,6 +930,11 @@
|
|||
dependencies:
|
||||
"@sentry/cli" "^1.35.5"
|
||||
|
||||
"@sheerun/mutationobserver-shim@^0.3.2":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.2.tgz#8013f2af54a2b7d735f71560ff360d3a8176a87b"
|
||||
integrity sha512-vTCdPp/T/Q3oSqwHmZ5Kpa9oI7iLtGl3RQaA/NyLHikvcrPxACkkKVr/XzkSPJWXHRhKGzVvb0urJsbMlRxi1Q==
|
||||
|
||||
"@sinonjs/commons@^1.0.2":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.3.0.tgz#50a2754016b6f30a994ceda6d9a0a8c36adda849"
|
||||
|
@ -4903,7 +4908,7 @@ css-what@2.1:
|
|||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.2.tgz#c0876d9d0480927d7d4920dcd72af3595649554d"
|
||||
integrity sha512-wan8dMWQ0GUeF7DGEPVjhHemVW/vy6xUYmFzRY8RYqgA0JtXC9rJmbScBjqSu6dg9q0lwPQy6ZAmJVr3PPTvqQ==
|
||||
|
||||
css@2.X, css@^2.2.1:
|
||||
css@2.X, css@^2.2.1, css@^2.2.3:
|
||||
version "2.2.4"
|
||||
resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929"
|
||||
integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==
|
||||
|
@ -5551,6 +5556,15 @@ dom-serializer@0, dom-serializer@~0.1.0:
|
|||
domelementtype "~1.1.1"
|
||||
entities "~1.1.1"
|
||||
|
||||
dom-testing-library@^3.12.0:
|
||||
version "3.12.0"
|
||||
resolved "https://registry.yarnpkg.com/dom-testing-library/-/dom-testing-library-3.12.0.tgz#45c33124fe6a347410117802a367d3291514fe6f"
|
||||
integrity sha512-eWykEDuKmffXOUKvv4IK00krvC4m+V2/y137M1YccWanUlfUzqS1+3eqm3GMC9qMqCJugfHWn6OpIaQd9rwqcw==
|
||||
dependencies:
|
||||
"@sheerun/mutationobserver-shim" "^0.3.2"
|
||||
pretty-format "^23.6.0"
|
||||
wait-for-expect "^1.0.0"
|
||||
|
||||
domain-browser@^1.1.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
|
||||
|
@ -10216,6 +10230,19 @@ jest-docblock@^23.2.0:
|
|||
dependencies:
|
||||
detect-newline "^2.1.0"
|
||||
|
||||
jest-dom@^2:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jest-dom/-/jest-dom-2.1.1.tgz#c75515ef31147bd9684c860b0cba9605638fd4dd"
|
||||
integrity sha512-jE1LRnP/wVGdQy6sVJ+dPwMq6rXXuvYTnzWEb8hDwfxhQesoaaukJzZaZYi14JPpdmhrncdpUsZpagN7HjuTsw==
|
||||
dependencies:
|
||||
chalk "^2.4.1"
|
||||
css "^2.2.3"
|
||||
jest-diff "^23.6.0"
|
||||
jest-matcher-utils "^23.6.0"
|
||||
lodash "^4.17.11"
|
||||
pretty-format "^23.6.0"
|
||||
redent "^2.0.0"
|
||||
|
||||
jest-each@^23.6.0:
|
||||
version "23.6.0"
|
||||
resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-23.6.0.tgz#ba0c3a82a8054387016139c733a05242d3d71575"
|
||||
|
@ -14764,6 +14791,13 @@ react-test-renderer@^16, react-test-renderer@^16.0.0-0:
|
|||
react-is "^16.6.0"
|
||||
scheduler "^0.10.0"
|
||||
|
||||
react-testing-library@^5:
|
||||
version "5.2.3"
|
||||
resolved "https://registry.yarnpkg.com/react-testing-library/-/react-testing-library-5.2.3.tgz#c3be44bfa5eb1ba2acc1fb218785c40ebbdfe8ed"
|
||||
integrity sha512-Bw52++7uORuIQnL55lK/WQfppqAc9+8yFG4lWUp/kmSOvYDnt8J9oI5fNCfAGSQi9iIhAv9aNsI2G5rtid0nrA==
|
||||
dependencies:
|
||||
dom-testing-library "^3.12.0"
|
||||
|
||||
react-tinymce@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/react-tinymce/-/react-tinymce-0.7.0.tgz#4dc3f2511d8e33c7ef4511fa22732c497b2faab8"
|
||||
|
@ -18131,6 +18165,11 @@ w3c-hr-time@^1.0.1:
|
|||
dependencies:
|
||||
browser-process-hrtime "^0.1.2"
|
||||
|
||||
wait-for-expect@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-1.0.1.tgz#73ab346ed56ed2ef66c380a59fd623755ceac0ce"
|
||||
integrity sha512-TPZMSxGWUl2DWmqdspLDEy97/S1Mqq0pzbh2A7jTq0WbJurUb5GKli+bai6ayeYdeWTF0rQNWZmUvCVZ9gkrfA==
|
||||
|
||||
walker@~1.0.5:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb"
|
||||
|
|
Loading…
Reference in New Issue