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:
Jon Willesen 2018-11-01 15:02:46 -06:00 committed by Jon Willesen
parent cc1aab6d53
commit 1898f2aa06
22 changed files with 421 additions and 222 deletions

View File

@ -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>
`;

View File

@ -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>
`;

View File

@ -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>",
}
}
/>
`;

View File

@ -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>
`;

View File

@ -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 = {

View File

@ -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}} />
}

View File

@ -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>
)
}
}

View File

@ -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>
)
}

View File

@ -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

View File

@ -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>
)
}
}

View File

@ -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()} />)
})

View File

@ -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}`)
})

View File

@ -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()
})

View File

@ -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', () => {})

View File

@ -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()
})

View File

@ -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
})

View File

@ -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
}
}

View File

@ -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',

View File

@ -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'
],

View File

@ -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'

View File

@ -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",

View File

@ -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"