Remove enzyme mount from shared tests
refs LF-1439 flag=none Test Plan: - TermsOfServiceModal.test.jsx - passed - AnnouncementRow.test.jsx - passed - CourseItemRow.test.jsx - passed - ToggleIcon.test.jsx - passed - TruncateWithTooltip.test.jsx - passed - UnreadBadge.test.jsx - passed Change-Id: I0e1c93008ec49a1efc4d9462df9a571a44c2efbd Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/346597 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Eric Saupe <eric.saupe@instructure.com> QA-Review: Eric Saupe <eric.saupe@instructure.com> Product-Review: Árpád Kozma <arpad.kozma@instructure.com>
This commit is contained in:
parent
c677a896aa
commit
f98b461976
|
@ -1,205 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {mount} from 'enzyme'
|
||||
import merge from 'lodash/merge'
|
||||
import AnnouncementRow from '@canvas/announcements/react/components/AnnouncementRow'
|
||||
|
||||
QUnit.module('AnnouncementRow component')
|
||||
|
||||
const makeProps = (props = {}) =>
|
||||
merge(
|
||||
{
|
||||
announcement: {
|
||||
id: '1',
|
||||
position: 1,
|
||||
published: true,
|
||||
title: 'Hello World',
|
||||
message: 'Foo bar bar baz boop beep bop Foo',
|
||||
posted_at: 'January 10, 2019 at 10:00 AM',
|
||||
author: {
|
||||
id: '5',
|
||||
display_name: 'John Smith',
|
||||
html_url: '',
|
||||
avatar_image_url: null,
|
||||
},
|
||||
read_state: 'unread',
|
||||
unread_count: 0,
|
||||
discussion_subentry_count: 5,
|
||||
locked: false,
|
||||
html_url: '',
|
||||
user_count: 10,
|
||||
permissions: {
|
||||
reply: true,
|
||||
},
|
||||
},
|
||||
canManage: false,
|
||||
masterCourseData: {},
|
||||
},
|
||||
props
|
||||
)
|
||||
|
||||
test('renders the AnnouncementRow component', () => {
|
||||
const tree = mount(<AnnouncementRow {...makeProps()} />)
|
||||
ok(tree.exists())
|
||||
})
|
||||
|
||||
test('renders a checkbox if canManage: true', () => {
|
||||
const tree = mount(<AnnouncementRow {...makeProps({canManage: true})} />)
|
||||
const node = tree.find('Checkbox')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders no checkbox if canManage: false', () => {
|
||||
const tree = mount(<AnnouncementRow {...makeProps({canManage: false})} />)
|
||||
const node = tree.find('Checkbox')
|
||||
notOk(node.exists())
|
||||
})
|
||||
|
||||
test('renders UnreadBadge if announcement has replies > 0', () => {
|
||||
const announcement = {discussion_subentry_count: 5}
|
||||
const tree = mount(<AnnouncementRow {...makeProps({announcement})} />)
|
||||
const node = tree.find('UnreadBadge')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders UnreadBadge if announcement has replies == 0', () => {
|
||||
const announcement = {discussion_subentry_count: 0}
|
||||
const tree = mount(<AnnouncementRow {...makeProps({announcement})} />)
|
||||
const node = tree.find('UnreadBadge')
|
||||
notOk(node.exists())
|
||||
})
|
||||
|
||||
test('renders "Delayed" date label if announcement is delayed', () => {
|
||||
const delayedDate = new Date().toString()
|
||||
const announcement = {delayed_post_at: delayedDate}
|
||||
const tree = mount(<AnnouncementRow {...makeProps({announcement})} />)
|
||||
const node = tree.find('.ic-item-row__meta-content-timestamp')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders "Posted on" date label if announcement is not delayed', () => {
|
||||
const test_date = '1/24/2018'
|
||||
const announcement = {delayed_post_at: null, posted_at: test_date}
|
||||
const tree = mount(<AnnouncementRow {...makeProps({announcement})} />)
|
||||
const node = tree.find('.ic-item-row__meta-content-timestamp Text')
|
||||
ok(node.first().text().includes('Jan 24, 2018'))
|
||||
})
|
||||
|
||||
test('renders the SectionsTooltip component if canHaveSections: true', () => {
|
||||
const announcement = {user_count: 200}
|
||||
const tree = mount(<AnnouncementRow {...makeProps({announcement, canHaveSections: true})} />)
|
||||
equal(tree.find('SectionsTooltip Text').at(0).text(), 'All Sections')
|
||||
})
|
||||
|
||||
test('does not render the SectionsTooltip component if canHaveSections: false', () => {
|
||||
const announcement = {user_count: 200, canHaveSections: false}
|
||||
const tree = mount(<AnnouncementRow {...makeProps({announcement})} />)
|
||||
notOk(tree.find('SectionsTooltip').exists())
|
||||
})
|
||||
|
||||
test('renders the SectionsTooltip component with sections', () => {
|
||||
const announcement = {
|
||||
sections: [
|
||||
{id: 6, course_id: 1, name: 'section 4', user_count: 2},
|
||||
{id: 5, course_id: 1, name: 'section 2', user_count: 1},
|
||||
],
|
||||
}
|
||||
const tree = mount(<AnnouncementRow {...makeProps({announcement, canHaveSections: true})} />)
|
||||
equal(tree.find('SectionsTooltip Text').at(0).text(), '2 Sectionssection 4section 2')
|
||||
})
|
||||
|
||||
test('does not render master course lock icon if masterCourseData is not provided', assert => {
|
||||
const done = assert.async()
|
||||
const masterCourseData = null
|
||||
const rowRef = row => {
|
||||
notOk(row.masterCourseLock)
|
||||
done()
|
||||
}
|
||||
mount(<AnnouncementRow {...makeProps({masterCourseData, rowRef})} />)
|
||||
})
|
||||
|
||||
test('renders master course lock icon if masterCourseData is provided', assert => {
|
||||
const done = assert.async()
|
||||
const masterCourseData = {isMasterCourse: true, masterCourse: {id: '1'}}
|
||||
const rowRef = row => {
|
||||
ok(row.masterCourseLock)
|
||||
done()
|
||||
}
|
||||
mount(<AnnouncementRow {...makeProps({masterCourseData, rowRef})} />)
|
||||
})
|
||||
|
||||
test('renders reply button icon if user has reply permission', () => {
|
||||
const tree = mount(
|
||||
<AnnouncementRow {...makeProps({announcement: {permissions: {reply: true}}})} />
|
||||
)
|
||||
const node = tree.find('IconReplyLine')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('does not render reply button icon if user does not have reply permission', () => {
|
||||
const tree = mount(
|
||||
<AnnouncementRow {...makeProps({announcement: {permissions: {reply: false}}})} />
|
||||
)
|
||||
const node = tree.find('IconReply')
|
||||
notOk(node.exists())
|
||||
})
|
||||
|
||||
test('removes non-text content from announcement message', () => {
|
||||
const messageHtml = `
|
||||
<p>Hello World!</p>
|
||||
<img src="/images/stuff/things.png" />
|
||||
<p>foo bar</p>
|
||||
`
|
||||
const tree = mount(<AnnouncementRow {...makeProps({announcement: {message: messageHtml}})} />)
|
||||
const node = tree.find('.ic-announcement-row__content').instance()
|
||||
equal(node.childNodes.length, 1)
|
||||
equal(node.childNodes[0].nodeType, 3) // nodeType === 3 is text node type
|
||||
ok(node.textContent.includes('Hello World!'))
|
||||
ok(node.textContent.includes('foo bar'))
|
||||
})
|
||||
|
||||
test('does not render manage menu if canManage is false', () => {
|
||||
const tree = mount(<AnnouncementRow {...makeProps({canManage: false})} />)
|
||||
const menu = tree.find('.ic-item-row__manage-menu')
|
||||
notOk(menu.exists())
|
||||
})
|
||||
|
||||
test('renders manage menu if canManage is true', () => {
|
||||
const tree = mount(<AnnouncementRow {...makeProps({canManage: true})} />)
|
||||
const menu = tree.find('.ic-item-row__manage-menu')
|
||||
ok(menu.exists())
|
||||
})
|
||||
|
||||
test('does not render Allow Comments menu item if announcements are globally locked', () => {
|
||||
const tree = mount(
|
||||
<AnnouncementRow
|
||||
{...makeProps({canManage: true, canDelete: true, announcementsLocked: true})}
|
||||
/>
|
||||
)
|
||||
|
||||
// If we click the menu, it does not actually pop up the new menu in this tree,
|
||||
// it pops it up in another tree in the dom which afaict can't be tested here.
|
||||
// This is a way to get around that.
|
||||
const courseItemRow = tree.find('CourseItemRow')
|
||||
ok(courseItemRow.exists())
|
||||
const menuItems = courseItemRow.props().manageMenuOptions()
|
||||
strictEqual(menuItems.length, 1)
|
||||
strictEqual(menuItems[0].key, 'delete')
|
||||
})
|
|
@ -1,246 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2017 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {mount} from 'enzyme'
|
||||
import CourseItemRow from '@canvas/announcements/react/components/CourseItemRow'
|
||||
import AnnouncementModel from '@canvas/discussions/backbone/models/Announcement'
|
||||
import {IconAssignmentLine} from '@instructure/ui-icons'
|
||||
|
||||
QUnit.module('CourseItemRow component')
|
||||
|
||||
const props = {
|
||||
title: <p>Hello World</p>,
|
||||
body: <p>Hello World</p>,
|
||||
actionsContent: null,
|
||||
metaContent: null,
|
||||
author: {
|
||||
id: '5',
|
||||
display_name: 'John Smith',
|
||||
html_url: '',
|
||||
avatar_image_url: null,
|
||||
},
|
||||
className: '',
|
||||
id: '5',
|
||||
itemUrl: '',
|
||||
selectable: false,
|
||||
defaultSelected: false,
|
||||
isRead: false,
|
||||
showAvatar: true,
|
||||
onSelectedChanged: () => {},
|
||||
}
|
||||
|
||||
test('renders the CourseItemRow component', () => {
|
||||
const tree = mount(<CourseItemRow {...props} />)
|
||||
ok(tree.exists())
|
||||
})
|
||||
|
||||
test("renders the CourseItemRow component when author doesn't exist", () => {
|
||||
const tree = mount(<CourseItemRow {...props} author={null} />)
|
||||
ok(tree.exists())
|
||||
})
|
||||
|
||||
test('renders children inside content column', () => {
|
||||
const tree = mount(
|
||||
<CourseItemRow
|
||||
{...props}
|
||||
title={<span className="find-me" />}
|
||||
body={<span className="find-me2" />}
|
||||
sectionToolTip={<span className="find-me3" />}
|
||||
replyButton={<span className="find-me4" />}
|
||||
/>
|
||||
)
|
||||
ok(tree.find('.ic-item-row__content-col .find-me').exists())
|
||||
ok(tree.find('.ic-item-row__content-col .find-me2').exists())
|
||||
ok(tree.find('.ic-item-row__content-col .find-me3').exists())
|
||||
ok(tree.find('.ic-item-row__content-col .find-me4').exists())
|
||||
})
|
||||
|
||||
test('renders clickable children inside content link', () => {
|
||||
const tree = mount(
|
||||
<CourseItemRow
|
||||
{...props}
|
||||
itemUrl="/foo"
|
||||
title={<span className="find-me" />}
|
||||
body={<span className="find-me2" />}
|
||||
sectionToolTip={<span className="find-me3" />}
|
||||
replyButton={<span className="find-me4" />}
|
||||
/>
|
||||
)
|
||||
ok(tree.find('.ic-item-row__content-col .ic-item-row__content-link .find-me').exists())
|
||||
ok(tree.find('.ic-item-row__content-col .ic-item-row__content-container .find-me2').exists())
|
||||
ok(!tree.find('.ic-item-row__content-col .ic-item-row__content-link .find-me3').exists())
|
||||
ok(tree.find('.ic-item-row__content-col .ic-item-row__content-link .find-me4').exists())
|
||||
})
|
||||
|
||||
test('renders actions inside actions wrapper', () => {
|
||||
const tree = mount(<CourseItemRow {...props} actionsContent={<span className="find-me" />} />)
|
||||
const node = tree.find('.ic-item-row__meta-actions .find-me')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders metaContent inside meta content wrapper', () => {
|
||||
const tree = mount(<CourseItemRow {...props} metaContent={<span className="find-me" />} />)
|
||||
const node = tree.find('.ic-item-row__meta-content .find-me')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders a checkbox if selectable: true', () => {
|
||||
const tree = mount(<CourseItemRow {...props} selectable />)
|
||||
const node = tree.find('Checkbox')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders a drag handle if draggable: true', () => {
|
||||
const tree = mount(
|
||||
<CourseItemRow {...props} draggable connectDragSource={component => component} />
|
||||
)
|
||||
const node = tree.find('IconDragHandleLine')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders inputted icon', () => {
|
||||
const tree = mount(<CourseItemRow {...props} icon={<IconAssignmentLine />} />)
|
||||
const node = tree.find(IconAssignmentLine)
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders no checkbox if selectable: false', () => {
|
||||
const tree = mount(<CourseItemRow {...props} selectable={false} />)
|
||||
const node = tree.find('Checkbox')
|
||||
notOk(node.exists())
|
||||
})
|
||||
|
||||
test('renders an accessible avatar if showAvatar: true', () => {
|
||||
const tree = mount(<CourseItemRow {...props} showAvatar />)
|
||||
const node = tree.find('Avatar').find("img[alt='John Smith']")
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders no avatar if showAvatar: false', () => {
|
||||
const tree = mount(<CourseItemRow {...props} showAvatar={false} />)
|
||||
const node = tree.find('Avatar')
|
||||
notOk(node.exists())
|
||||
})
|
||||
|
||||
test('renders unread indicator if isRead: false', () => {
|
||||
const tree = mount(<CourseItemRow {...props} isRead={false} />)
|
||||
const rowNode = tree.find('Badge')
|
||||
ok(rowNode.exists())
|
||||
|
||||
const srNode = tree.find('.ic-item-row__content-col Heading ScreenReaderContent').first()
|
||||
ok(srNode.exists())
|
||||
ok(srNode.text().includes('unread,'))
|
||||
})
|
||||
|
||||
test('renders no unread indicator if isRead: true', () => {
|
||||
const tree = mount(<CourseItemRow {...props} isRead />)
|
||||
const rowNode = tree.find('Badge')
|
||||
notOk(rowNode.exists())
|
||||
|
||||
const srNode = tree.find('.ic-item-row__content-col Heading ScreenReaderContent')
|
||||
notOk(srNode.exists())
|
||||
})
|
||||
|
||||
test('passes down className prop to component', () => {
|
||||
const tree = mount(<CourseItemRow {...props} className="find-me" />)
|
||||
const rowNode = tree.find('.ic-item-row')
|
||||
ok(rowNode.hasClass('find-me'))
|
||||
})
|
||||
|
||||
test('renders master course lock icon if isMasterCourse', () => {
|
||||
const masterCourse = {
|
||||
courseData: {isMasterCourse: true, masterCourse: {id: '1'}},
|
||||
getLockOptions: () => ({
|
||||
model: new AnnouncementModel(props.announcement),
|
||||
unlockedText: '',
|
||||
lockedText: '',
|
||||
course_id: '3',
|
||||
content_id: '5',
|
||||
content_type: 'announcement',
|
||||
}),
|
||||
}
|
||||
const tree = mount(<CourseItemRow {...props} masterCourse={masterCourse} />)
|
||||
ok(tree.instance().masterCourseLock)
|
||||
})
|
||||
|
||||
test('renders peer review icon if peer review', () => {
|
||||
const tree = mount(<CourseItemRow {...props} peerReview />)
|
||||
const peerReviewComponent = tree.find('.ic-item-row__peer_review')
|
||||
ok(peerReviewComponent.exists())
|
||||
})
|
||||
|
||||
test('renders master course lock icon if isChildCourse', () => {
|
||||
const masterCourse = {
|
||||
courseData: {isChildCourse: true, masterCourse: {id: '1'}},
|
||||
getLockOptions: () => ({
|
||||
model: new AnnouncementModel(props.announcement),
|
||||
unlockedText: '',
|
||||
lockedText: '',
|
||||
course_id: '3',
|
||||
content_id: '5',
|
||||
content_type: 'announcement',
|
||||
}),
|
||||
}
|
||||
const tree = mount(<CourseItemRow {...props} masterCourse={masterCourse} />)
|
||||
ok(tree.instance().masterCourseLock)
|
||||
})
|
||||
|
||||
test('renders no master course lock icon if no master course data provided', () => {
|
||||
const masterCourse = {
|
||||
courseData: {},
|
||||
getLockOptions: () => ({}),
|
||||
}
|
||||
const tree = mount(<CourseItemRow {...props} masterCourse={masterCourse} />)
|
||||
notOk(tree.instance().masterCourseLock)
|
||||
})
|
||||
|
||||
test('renders no master course lock icon if isMasterCourse and isChildCourse are false', () => {
|
||||
const masterCourse = {
|
||||
courseData: {isMasterCourse: false, isChildCourse: false},
|
||||
getLockOptions: () => ({}),
|
||||
}
|
||||
const tree = mount(<CourseItemRow {...props} masterCourse={masterCourse} />)
|
||||
notOk(tree.instance().masterCourseLock)
|
||||
})
|
||||
|
||||
test('calls onSelectChanged when checkbox is toggled', () => {
|
||||
const onSelectedChanged = sinon.spy()
|
||||
const tree = mount(<CourseItemRow {...props} onSelectedChanged={onSelectedChanged} selectable />)
|
||||
const instance = tree.instance()
|
||||
instance.onSelectChanged({target: {checked: true}})
|
||||
ok(onSelectedChanged.calledWithMatch({id: '5', selected: true}))
|
||||
})
|
||||
|
||||
test('renders no manage menu when showManageMenu is false', () => {
|
||||
const tree = mount(<CourseItemRow {...props} showManageMenu={false} />)
|
||||
const menu = tree.find('.ic-item-row__manage-menu')
|
||||
notOk(menu.exists())
|
||||
})
|
||||
|
||||
test('renders manage menu when showManageMenu is true and manageMenuOptions is not empty', () => {
|
||||
const tree = mount(<CourseItemRow {...props} showManageMenu manageMenuOptions={['one', 'two']} />)
|
||||
const menu = tree.find('.ic-item-row__manage-menu')
|
||||
ok(menu.exists())
|
||||
})
|
||||
|
||||
test('does not render a clickable div if the body is empty', () => {
|
||||
const tree = mount(<CourseItemRow {...props} body={null} />)
|
||||
const contentLinks = tree.find('.ic-item-row__content-link')
|
||||
strictEqual(contentLinks.length, 1)
|
||||
})
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2018 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {mount} from 'enzyme'
|
||||
import merge from 'lodash/merge'
|
||||
import ToggleIcon from 'ui/features/discussion_topics_index/react/components/ToggleIcon'
|
||||
|
||||
QUnit.module('ToggleIcon component')
|
||||
|
||||
const makeProps = (props = {}) =>
|
||||
merge(
|
||||
{
|
||||
toggled: true,
|
||||
OnIcon: <span className="onIcon" />,
|
||||
OffIcon: <span className="offIcon" />,
|
||||
onToggleOn: () => {},
|
||||
onToggleOff: () => {},
|
||||
disabled: false,
|
||||
},
|
||||
props
|
||||
)
|
||||
|
||||
test('renders the ToggleIcon component', () => {
|
||||
const tree = mount(<ToggleIcon {...makeProps()} />)
|
||||
ok(tree.exists())
|
||||
})
|
||||
|
||||
test('renders the on icon when toggled', () => {
|
||||
const tree = mount(<ToggleIcon {...makeProps()} />)
|
||||
ok(tree.find('.onIcon').exists())
|
||||
ok(!tree.find('.offIcon').exists())
|
||||
})
|
||||
|
||||
test('renders the off icon when untoggled', () => {
|
||||
const tree = mount(<ToggleIcon {...makeProps({toggled: false})} />)
|
||||
ok(!tree.find('.onIcon').exists())
|
||||
ok(tree.find('.offIcon').exists())
|
||||
})
|
||||
|
||||
test('calls onToggleOff when clicked while toggled', () => {
|
||||
const onToggleOn = sinon.spy()
|
||||
const onToggleOff = sinon.spy()
|
||||
const tree = mount(<ToggleIcon {...makeProps({onToggleOn, onToggleOff})} />)
|
||||
|
||||
tree.find('.onIcon').simulate('click')
|
||||
strictEqual(onToggleOff.callCount, 1)
|
||||
strictEqual(onToggleOn.callCount, 0)
|
||||
})
|
||||
|
||||
test('calls onToggleOn when clicked while untoggled', () => {
|
||||
const onToggleOn = sinon.spy()
|
||||
const onToggleOff = sinon.spy()
|
||||
const tree = mount(<ToggleIcon {...makeProps({onToggleOn, onToggleOff, toggled: false})} />)
|
||||
|
||||
tree.find('.offIcon').simulate('click')
|
||||
strictEqual(onToggleOff.callCount, 0)
|
||||
strictEqual(onToggleOn.callCount, 1)
|
||||
})
|
||||
|
||||
test('cannot be clicked if disabled', () => {
|
||||
const onToggleOn = sinon.spy()
|
||||
const onToggleOff = sinon.spy()
|
||||
const tree = mount(<ToggleIcon {...makeProps({onToggleOn, onToggleOff, disabled: true})} />)
|
||||
|
||||
tree.find('.onIcon').simulate('click')
|
||||
strictEqual(onToggleOff.callCount, 0)
|
||||
strictEqual(onToggleOn.callCount, 0)
|
||||
})
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2018 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
* Canvas is free software: you can redistribute it and/or modify it under
|
||||
* the terms of the GNU Affero General Public License as published by the Free
|
||||
* Software Foundation, version 3 of the License.
|
||||
*
|
||||
* Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
* A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {mount} from 'enzyme'
|
||||
import TruncateWithTooltip from '@canvas/grade-summary/react/TruncateWithTooltip'
|
||||
|
||||
let componentHost
|
||||
let tooltipHost
|
||||
let component
|
||||
QUnit.module('TruncateWithTooltip', {
|
||||
beforeEach: () => {
|
||||
componentHost = document.createElement('div')
|
||||
componentHost.setAttribute('id', 'TruncateWithTooltipComponent')
|
||||
tooltipHost = document.createElement('div')
|
||||
tooltipHost.setAttribute('id', 'TruncateWithTooltipTooltip')
|
||||
document.body.appendChild(componentHost)
|
||||
document.body.appendChild(tooltipHost)
|
||||
},
|
||||
afterEach: () => {
|
||||
if (component) {
|
||||
component.unmount()
|
||||
}
|
||||
if (componentHost) {
|
||||
componentHost.remove()
|
||||
}
|
||||
if (tooltipHost) {
|
||||
tooltipHost.remove()
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const render = (text, width = null) =>
|
||||
mount(
|
||||
<div style={{width}}>
|
||||
<TruncateWithTooltip mountNode={tooltipHost}>{text}</TruncateWithTooltip>
|
||||
</div>,
|
||||
{
|
||||
attachTo: componentHost,
|
||||
}
|
||||
)
|
||||
|
||||
test('renders the TruncateWithTooltip component', () => {
|
||||
component = render('Boo')
|
||||
ok(component.exists())
|
||||
})
|
||||
|
||||
test('renders short text', () => {
|
||||
component = render('This is some text')
|
||||
equal(component.text(), 'This is some text')
|
||||
})
|
||||
|
||||
test('truncates long text', () => {
|
||||
const long =
|
||||
'This is some long long long long long long long long long long long long long long text'
|
||||
component = render(long, '100px')
|
||||
notEqual(component.text(), long)
|
||||
ok(component.text().includes('\u2026'))
|
||||
})
|
||||
|
||||
test('does not include a popover for short text', () => {
|
||||
component = render('This is some text')
|
||||
const tooltip = tooltipHost.querySelector('[role="tooltip"]')
|
||||
notOk(tooltip)
|
||||
})
|
||||
|
||||
test('includes a popover for long text', () => {
|
||||
const long =
|
||||
'This is some long long long long long long long long long long long long long long text'
|
||||
component = render(long, '100px')
|
||||
const tooltip = tooltipHost.querySelector('[role="tooltip"]')
|
||||
ok(tooltip)
|
||||
equal(tooltip.textContent, long)
|
||||
})
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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 {fireEvent, render, screen} from '@testing-library/react'
|
||||
import ToggleIcon from '../ToggleIcon'
|
||||
|
||||
const defaultProps = (props = {}) => ({
|
||||
toggled: true,
|
||||
OnIcon: <span className="onIcon" />,
|
||||
OffIcon: <span className="offIcon" />,
|
||||
onToggleOn: () => {},
|
||||
onToggleOff: () => {},
|
||||
disabled: false,
|
||||
...props,
|
||||
})
|
||||
|
||||
const renderToggleIcon = (props = {}) => render(<ToggleIcon {...defaultProps(props)} />)
|
||||
|
||||
describe('ToggleIcon', () => {
|
||||
it('renders the ToggleIcon component', () => {
|
||||
renderToggleIcon()
|
||||
|
||||
expect(screen.getByRole('button')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button')).toHaveClass('toggle-button')
|
||||
})
|
||||
|
||||
it('adds the className to the container', () => {
|
||||
const {container} = renderToggleIcon({className: 'foo'})
|
||||
|
||||
expect(container.querySelector('.foo')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders the on icon when toggled', () => {
|
||||
const {container} = renderToggleIcon()
|
||||
|
||||
expect(container.querySelector('.onIcon')).toBeInTheDocument()
|
||||
expect(container.querySelector('.offIcon')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders the off icon when untoggled', () => {
|
||||
const {container} = renderToggleIcon({toggled: false})
|
||||
|
||||
expect(container.querySelector('.onIcon')).not.toBeInTheDocument()
|
||||
expect(container.querySelector('.offIcon')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('calls onToggleOff when clicked while toggled', () => {
|
||||
const onToggleOn = jest.fn()
|
||||
const onToggleOff = jest.fn()
|
||||
const {container} = renderToggleIcon({onToggleOn, onToggleOff})
|
||||
|
||||
fireEvent.click(container.querySelector('.onIcon'))
|
||||
|
||||
expect(onToggleOff).toHaveBeenCalledTimes(1)
|
||||
expect(onToggleOn).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
|
||||
it('calls onToggleOn when clicked while untoggled', () => {
|
||||
const onToggleOn = jest.fn()
|
||||
const onToggleOff = jest.fn()
|
||||
const {container} = renderToggleIcon({onToggleOn, onToggleOff, toggled: false})
|
||||
|
||||
fireEvent.click(container.querySelector('.offIcon'))
|
||||
|
||||
expect(onToggleOff).toHaveBeenCalledTimes(0)
|
||||
expect(onToggleOn).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('cannot be clicked if disabled', () => {
|
||||
const onToggleOn = jest.fn()
|
||||
const onToggleOff = jest.fn()
|
||||
const {container} = renderToggleIcon({onToggleOn, onToggleOff, disabled: true})
|
||||
|
||||
fireEvent.click(container.querySelector('.onIcon'))
|
||||
|
||||
expect(screen.getByRole('button')).toBeDisabled()
|
||||
expect(screen.getByRole('button')).toHaveClass('disabled-toggle-button')
|
||||
expect(onToggleOff).toHaveBeenCalledTimes(0)
|
||||
expect(onToggleOn).toHaveBeenCalledTimes(0)
|
||||
})
|
||||
})
|
|
@ -19,28 +19,34 @@
|
|||
import React from 'react'
|
||||
import $ from 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import {mount} from 'enzyme'
|
||||
import TermsOfServiceModal from 'ui/features/terms_of_service_modal/react/TermsOfServiceModal'
|
||||
import {render, screen} from '@testing-library/react'
|
||||
import TermsOfServiceModal from '../TermsOfServiceModal'
|
||||
|
||||
QUnit.module('Terms of Service Modal Link', {
|
||||
beforeEach() {
|
||||
const renderTermsOfServiceModal = (props = {}) => render(<TermsOfServiceModal {...props} />)
|
||||
|
||||
describe('TermsOfServiceModal', () => {
|
||||
beforeEach(() => {
|
||||
$('#fixtures').html('<div id="main">')
|
||||
},
|
||||
afterEach() {
|
||||
|
||||
window.ENV = {
|
||||
TERMS_OF_SERVICE_CUSTOM_CONTENT: 'Hello World',
|
||||
}
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
$('#fixtures').empty()
|
||||
},
|
||||
})
|
||||
delete window.ENV
|
||||
})
|
||||
|
||||
test('renders correct link when preview is provided', () => {
|
||||
ENV.TERMS_OF_SERVICE_CUSTOM_CONTENT = 'Hello World'
|
||||
const wrapper = mount(<TermsOfServiceModal preview />)
|
||||
const renderedLink = wrapper.find('a')
|
||||
equal(renderedLink.text(), 'Preview')
|
||||
})
|
||||
it('renders correct link when preview is provided', () => {
|
||||
renderTermsOfServiceModal({preview: true})
|
||||
|
||||
test('renders correct link when preview is not provided', () => {
|
||||
ENV.TERMS_OF_SERVICE_CUSTOM_CONTENT = 'Hello World'
|
||||
const wrapper = mount(<TermsOfServiceModal />)
|
||||
const renderedLink = wrapper.find('a')
|
||||
equal(renderedLink.text(), 'Acceptable Use Policy')
|
||||
expect(screen.getByText('Preview')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders correct link when preview is not provided', () => {
|
||||
renderTermsOfServiceModal()
|
||||
|
||||
expect(screen.getByText('Acceptable Use Policy')).toBeInTheDocument()
|
||||
})
|
||||
})
|
|
@ -20,7 +20,7 @@
|
|||
// with the shared utilities created in g/something.
|
||||
import {useScope as useI18nScope} from '@canvas/i18n'
|
||||
import React, {Component} from 'react'
|
||||
import {bool, node, string, func, shape, arrayOf, oneOf} from 'prop-types'
|
||||
import {bool, node, string, func, shape, oneOf} from 'prop-types'
|
||||
import cx from 'classnames'
|
||||
|
||||
import {Text} from '@instructure/ui-text'
|
||||
|
@ -41,7 +41,7 @@ const I18n = useI18nScope('shared_components')
|
|||
|
||||
export default class CourseItemRow extends Component {
|
||||
static propTypes = {
|
||||
actionsContent: arrayOf(node),
|
||||
actionsContent: node,
|
||||
metaContent: node,
|
||||
masterCourse: shape({
|
||||
courseData: masterCourseDataShape,
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Copyright (C) 2017 - 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 {fireEvent, render, screen} from '@testing-library/react'
|
||||
import AnnouncementRow from '../AnnouncementRow'
|
||||
|
||||
const mockLockIconView = {
|
||||
render: jest.fn(),
|
||||
remove: jest.fn(),
|
||||
}
|
||||
|
||||
jest.mock('@canvas/lock-icon', () => jest.fn(() => mockLockIconView))
|
||||
|
||||
const defaultProps = (props = {}) => ({
|
||||
canManage: false,
|
||||
masterCourseData: {},
|
||||
...props,
|
||||
announcement: {
|
||||
id: '1',
|
||||
position: 1,
|
||||
published: true,
|
||||
title: 'Hello World',
|
||||
message: 'Foo bar bar baz boop beep bop Foo',
|
||||
posted_at: 'January 10, 2019 at 10:00 AM',
|
||||
author: {
|
||||
id: '5',
|
||||
name: 'John Smith',
|
||||
display_name: 'John Smith',
|
||||
html_url: '',
|
||||
avatar_image_url: null,
|
||||
},
|
||||
read_state: 'unread',
|
||||
unread_count: 0,
|
||||
discussion_subentry_count: 0,
|
||||
locked: false,
|
||||
html_url: '',
|
||||
user_count: 10,
|
||||
permissions: {
|
||||
reply: true,
|
||||
},
|
||||
...props.announcement,
|
||||
},
|
||||
})
|
||||
|
||||
const renderAnnouncementRow = (props = {}) => render(<AnnouncementRow {...defaultProps(props)} />)
|
||||
|
||||
describe('AnnouncementRow', () => {
|
||||
it('renders the AnnouncementRow component', () => {
|
||||
renderAnnouncementRow()
|
||||
|
||||
expect(screen.getByText('Hello World')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders a checkbox if canManage: true', () => {
|
||||
renderAnnouncementRow({canManage: true})
|
||||
|
||||
expect(screen.getByRole('checkbox')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders no checkbox if canManage: false', () => {
|
||||
renderAnnouncementRow({canManage: false})
|
||||
|
||||
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders UnreadBadge if announcement has replies > 0', () => {
|
||||
renderAnnouncementRow({announcement: {unread_count: 2, discussion_subentry_count: 5}})
|
||||
|
||||
expect(
|
||||
screen.getByRole('tooltip', {
|
||||
name: /2 unread replies/i,
|
||||
})
|
||||
).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders UnreadBadge if announcement has replies == 0', () => {
|
||||
renderAnnouncementRow({announcement: {discussion_subentry_count: 0}})
|
||||
|
||||
expect(screen.getByText(/unread/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders "Delayed" date label if announcement is delayed', () => {
|
||||
const tomorrow = new Date()
|
||||
const dateOptions = {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
timeZone: 'UTC',
|
||||
}
|
||||
const announcement = {}
|
||||
|
||||
tomorrow.setDate(tomorrow.getDate() + 1)
|
||||
announcement.delayed_post_at = tomorrow.toISOString()
|
||||
|
||||
renderAnnouncementRow({announcement})
|
||||
|
||||
const expectedDate = new Intl.DateTimeFormat('en-US', dateOptions).format(tomorrow)
|
||||
|
||||
expect(screen.getByText(/delayed until:/i)).toBeInTheDocument()
|
||||
expect(screen.getByText(new RegExp(expectedDate, 'i'))).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders "Posted on" date label if announcement is not delayed', () => {
|
||||
const test_date = '1/24/2018'
|
||||
|
||||
renderAnnouncementRow({announcement: {delayed_post_at: null, posted_at: test_date}})
|
||||
|
||||
expect(screen.getByText(/Jan 24, 2018/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders the SectionsTooltip component if canHaveSections: true', () => {
|
||||
const announcement = {user_count: 200}
|
||||
|
||||
renderAnnouncementRow({announcement, canHaveSections: true})
|
||||
|
||||
expect(screen.getByText('All Sections')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not render the SectionsTooltip component if canHaveSections: false', () => {
|
||||
const announcement = {user_count: 200, canHaveSections: false}
|
||||
|
||||
renderAnnouncementRow({announcement})
|
||||
|
||||
expect(screen.queryByText('All Sections')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders the SectionsTooltip component with sections', () => {
|
||||
const announcement = {
|
||||
sections: [
|
||||
{id: 6, course_id: 1, name: 'section 4', user_count: 2},
|
||||
{id: 5, course_id: 1, name: 'section 2', user_count: 1},
|
||||
],
|
||||
}
|
||||
|
||||
renderAnnouncementRow({announcement, canHaveSections: true})
|
||||
|
||||
expect(screen.getByText('2 Sections')).toBeInTheDocument()
|
||||
expect(screen.getByText('section 4')).toBeInTheDocument()
|
||||
expect(screen.getByText('section 2')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not render master course lock icon if masterCourseData is not provided', () => {
|
||||
const masterCourseData = null
|
||||
|
||||
const {container} = renderAnnouncementRow({masterCourseData})
|
||||
|
||||
expect(container.querySelector('.lock-icon .lock-icon')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders master course lock icon if masterCourseData is provided', () => {
|
||||
const masterCourseData = {isMasterCourse: true, masterCourse: {id: '1'}}
|
||||
|
||||
renderAnnouncementRow({masterCourseData})
|
||||
|
||||
expect(mockLockIconView.render).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('renders reply button icon if user has reply permission', () => {
|
||||
renderAnnouncementRow({announcement: {permissions: {reply: true}}})
|
||||
|
||||
expect(screen.getByRole('link', {name: /reply/i})).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not render reply button icon if user does not have reply permission', () => {
|
||||
renderAnnouncementRow({announcement: {permissions: {reply: false}}})
|
||||
|
||||
expect(screen.queryByRole('link', {name: /reply/i})).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('removes non-text content from announcement message', () => {
|
||||
const messageHtml = `
|
||||
<p data-testid="custom-html-text1">This is a message within custom HTML</p>
|
||||
<img data-testid="custom-html-image" src="/apple-touch-icon.png" alt=""/>
|
||||
<p data-testid="custom-html-text2">This is also a message within custom HTML</p>
|
||||
`
|
||||
|
||||
renderAnnouncementRow({announcement: {message: messageHtml}})
|
||||
|
||||
expect(screen.getByText(/This is a message within custom HTML/)).toBeInTheDocument()
|
||||
expect(screen.getByText(/This is also a message within custom HTML/)).toBeInTheDocument()
|
||||
expect(screen.queryByTestId('custom-html-image')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('custom-html-text1')).not.toBeInTheDocument()
|
||||
expect(screen.queryByTestId('custom-html-text2')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('/images/stuff/things.png')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not render manage menu if canManage is false', () => {
|
||||
renderAnnouncementRow({canManage: false})
|
||||
|
||||
expect(screen.queryByText(/Manage options for /)).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders manage menu if canManage is true', () => {
|
||||
renderAnnouncementRow({canManage: true})
|
||||
|
||||
expect(screen.getByText(/Manage options for /)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not render Allow Comments menu item if announcements are globally locked', () => {
|
||||
renderAnnouncementRow({
|
||||
canManage: true,
|
||||
canDelete: false,
|
||||
announcementsLocked: true,
|
||||
})
|
||||
|
||||
fireEvent.click(screen.getByRole('button', {name: /Manage options for /}))
|
||||
|
||||
expect(screen.queryByText(/Allow Comments/)).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* Copyright (C) 2017 - 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 {fireEvent, render, screen} from '@testing-library/react'
|
||||
import CourseItemRow from '../CourseItemRow'
|
||||
import AnnouncementModel from '@canvas/discussions/backbone/models/Announcement'
|
||||
|
||||
const mockLockIconView = {
|
||||
render: jest.fn(),
|
||||
remove: jest.fn(),
|
||||
}
|
||||
|
||||
jest.mock('@canvas/lock-icon', () => jest.fn(() => mockLockIconView))
|
||||
|
||||
const defaultProps = {
|
||||
title: 'Hello CourseItemRow title',
|
||||
body: <p>Hello CourseItemRow body</p>,
|
||||
id: '5',
|
||||
position: 1,
|
||||
published: true,
|
||||
message: 'Foo bar bar baz boop beep bop Foo',
|
||||
posted_at: 'January 10, 2019 at 10:00 AM',
|
||||
author: {
|
||||
id: '5',
|
||||
name: 'John Smith',
|
||||
display_name: 'John Smith',
|
||||
html_url: '',
|
||||
avatar_image_url: null,
|
||||
},
|
||||
read_state: 'unread',
|
||||
unread_count: 0,
|
||||
discussion_subentry_count: 0,
|
||||
locked: false,
|
||||
html_url: '',
|
||||
user_count: 10,
|
||||
permissions: {
|
||||
reply: true,
|
||||
},
|
||||
}
|
||||
|
||||
const renderCourseItemRow = (props = {}) => {
|
||||
const activeProps = {...defaultProps, ...props}
|
||||
|
||||
return render(<CourseItemRow {...activeProps} />)
|
||||
}
|
||||
|
||||
describe('CourseItemRow', () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
it('renders the CourseItemRow component', () => {
|
||||
renderCourseItemRow()
|
||||
|
||||
expect(screen.getByText('Hello CourseItemRow body')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("renders the CourseItemRow component when author doesn't exist", () => {
|
||||
renderCourseItemRow({author: null})
|
||||
|
||||
expect(screen.getByText('Hello CourseItemRow body')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders children inside content column', () => {
|
||||
const {container} = renderCourseItemRow({
|
||||
body: <span className="find-me2" />,
|
||||
sectionToolTip: <span className="find-me3" />,
|
||||
replyButton: <span className="find-me4" />,
|
||||
})
|
||||
|
||||
expect(screen.getByText('Hello CourseItemRow title')).toBeInTheDocument()
|
||||
expect(container.querySelector('.ic-item-row__content-col .find-me2')).toBeInTheDocument()
|
||||
expect(container.querySelector('.ic-item-row__content-col .find-me3')).toBeInTheDocument()
|
||||
expect(container.querySelector('.ic-item-row__content-col .find-me4')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders clickable children inside content link', () => {
|
||||
const {container} = renderCourseItemRow({
|
||||
replyButton: <span className="find-me" />,
|
||||
})
|
||||
|
||||
expect(container.querySelector('a.ic-item-row__content-link h3')).toBeInTheDocument()
|
||||
expect(container.querySelector('a.ic-item-row__content-link .find-me')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders actions inside actions wrapper', () => {
|
||||
const {container} = renderCourseItemRow({
|
||||
actionsContent: <span className="find-me" />,
|
||||
})
|
||||
|
||||
expect(container.querySelector('.ic-item-row__meta-actions .find-me')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders metaContent inside meta content wrapper', () => {
|
||||
const {container} = renderCourseItemRow({
|
||||
metaContent: <span className="find-me" />,
|
||||
})
|
||||
|
||||
expect(container.querySelector('.ic-item-row__meta-content .find-me')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders a checkbox if selectable: true', () => {
|
||||
renderCourseItemRow({selectable: true})
|
||||
|
||||
expect(screen.getByRole('checkbox')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders a drag handle if draggable: true', () => {
|
||||
const {container} = renderCourseItemRow({draggable: true})
|
||||
|
||||
expect(container.querySelector('.ic-item-row__drag-col')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders inputted icon', () => {
|
||||
renderCourseItemRow({icon: <span data-testid="custom-icon" />})
|
||||
|
||||
expect(screen.queryByTestId('custom-icon')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders no checkbox if selectable: false', () => {
|
||||
renderCourseItemRow({selectable: false})
|
||||
|
||||
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders an accessible avatar if showAvatar: true', () => {
|
||||
renderCourseItemRow({showAvatar: true})
|
||||
|
||||
expect(screen.getByAltText('John Smith')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders no avatar if showAvatar: false', () => {
|
||||
renderCourseItemRow({showAvatar: false})
|
||||
|
||||
expect(screen.queryByAltText('John Smith')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders unread indicator if isRead: false', () => {
|
||||
renderCourseItemRow({isRead: false})
|
||||
|
||||
expect(screen.getByText(/unread,/)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders no unread indicator if isRead: true', () => {
|
||||
renderCourseItemRow({isRead: true})
|
||||
|
||||
expect(screen.queryByText(/unread,/)).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('passes down className prop to component', () => {
|
||||
const {container} = renderCourseItemRow({className: 'find-me'})
|
||||
|
||||
expect(container.querySelector('.ic-item-row')).toHaveClass('find-me')
|
||||
})
|
||||
|
||||
it('renders master course lock icon if isMasterCourse', () => {
|
||||
const masterCourse = {
|
||||
courseData: {isMasterCourse: true, masterCourse: {id: '1'}},
|
||||
getLockOptions: () => ({
|
||||
model: new AnnouncementModel(defaultProps.announcement),
|
||||
unlockedText: '',
|
||||
lockedText: '',
|
||||
course_id: '3',
|
||||
content_id: '5',
|
||||
content_type: 'announcement',
|
||||
}),
|
||||
}
|
||||
|
||||
renderCourseItemRow({masterCourse})
|
||||
|
||||
expect(mockLockIconView.render).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('renders peer review icon if peer review', () => {
|
||||
const {container} = renderCourseItemRow({peerReview: true})
|
||||
|
||||
expect(container.querySelector('.ic-item-row__peer_review')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders master course lock icon if isChildCourse', () => {
|
||||
const masterCourse = {
|
||||
courseData: {isChildCourse: true, masterCourse: {id: '1'}},
|
||||
getLockOptions: () => ({
|
||||
model: new AnnouncementModel(defaultProps.announcement),
|
||||
unlockedText: '',
|
||||
lockedText: '',
|
||||
course_id: '3',
|
||||
content_id: '5',
|
||||
content_type: 'announcement',
|
||||
}),
|
||||
}
|
||||
|
||||
renderCourseItemRow({masterCourse})
|
||||
|
||||
expect(mockLockIconView.render).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('renders no master course lock icon if no master course data provided', () => {
|
||||
const masterCourse = {
|
||||
courseData: {},
|
||||
getLockOptions: () => ({}),
|
||||
}
|
||||
|
||||
renderCourseItemRow({masterCourse})
|
||||
|
||||
expect(mockLockIconView.render).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('renders no master course lock icon if isMasterCourse and isChildCourse are false', () => {
|
||||
const masterCourse = {
|
||||
courseData: {isMasterCourse: false, isChildCourse: false},
|
||||
getLockOptions: () => ({}),
|
||||
}
|
||||
|
||||
renderCourseItemRow({masterCourse})
|
||||
|
||||
expect(mockLockIconView.render).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('calls onSelectChanged when checkbox is toggled', () => {
|
||||
const onSelectedChanged = jest.fn()
|
||||
|
||||
renderCourseItemRow({selectable: true, onSelectedChanged})
|
||||
|
||||
fireEvent.click(screen.getByRole('checkbox'))
|
||||
|
||||
expect(onSelectedChanged).toHaveBeenCalledWith({id: '5', selected: true})
|
||||
})
|
||||
|
||||
it('renders no manage menu when showManageMenu is false', () => {
|
||||
renderCourseItemRow({showManageMenu: false})
|
||||
|
||||
expect(screen.queryByText(/Manage options for /)).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders manage menu when showManageMenu is true and manageMenuOptions is not empty', () => {
|
||||
renderCourseItemRow({showManageMenu: true, manageMenuOptions: () => null})
|
||||
|
||||
expect(screen.getByText(/Manage options for /)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not render a clickable div if the body is empty', () => {
|
||||
const {container} = renderCourseItemRow({body: null})
|
||||
|
||||
expect(container.querySelectorAll('.ic-item-row__content-link')).toHaveLength(1)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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, screen} from '@testing-library/react'
|
||||
import TruncateWithTooltip from '../TruncateWithTooltip'
|
||||
|
||||
jest.mock('@instructure/ui-truncate-text', () => ({
|
||||
TruncateText: ({children}) => <span data-testid="truncate-text">{children}</span>,
|
||||
}))
|
||||
jest.mock('@instructure/ui-tooltip', () => ({
|
||||
Tooltip: ({renderTip}) => <div role="tooltip">{renderTip}</div>,
|
||||
}))
|
||||
|
||||
const defaultProps = (props = {}) => ({
|
||||
mountNode: document.createElement('div'),
|
||||
...props,
|
||||
})
|
||||
const renderTruncateWithTooltip = (text, props = {}) => {
|
||||
const ref = React.createRef()
|
||||
const wrapper = render(
|
||||
<TruncateWithTooltip {...defaultProps(props)} ref={ref}>
|
||||
{text}
|
||||
</TruncateWithTooltip>
|
||||
)
|
||||
|
||||
return {wrapper, ref}
|
||||
}
|
||||
|
||||
describe('TruncateWithTooltip', () => {
|
||||
it('renders short text', () => {
|
||||
renderTruncateWithTooltip('This is some text')
|
||||
|
||||
expect(screen.getByText('This is some text')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('shows TruncateText if text is not truncated', () => {
|
||||
renderTruncateWithTooltip('TruncateText')
|
||||
|
||||
expect(screen.getByText('TruncateText')).toBeInTheDocument()
|
||||
expect(screen.getByTestId('truncate-text')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('does not include a tooltip for short text', () => {
|
||||
renderTruncateWithTooltip('This is some text')
|
||||
|
||||
expect(screen.queryByRole('tooltip')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('shows Tooltip for truncated text', () => {
|
||||
const {ref} = renderTruncateWithTooltip('Tooltip', '100px')
|
||||
|
||||
ref.current.setState({isTruncated: true})
|
||||
|
||||
expect(screen.getByRole('tooltip')).toBeInTheDocument()
|
||||
})
|
||||
})
|
|
@ -17,31 +17,36 @@
|
|||
*/
|
||||
|
||||
import React from 'react'
|
||||
import {mount, shallow} from 'enzyme'
|
||||
import UnreadBadge from '@canvas/unread-badge'
|
||||
import {render, screen} from '@testing-library/react'
|
||||
|
||||
QUnit.module('UnreadBadge component')
|
||||
|
||||
const defaultProps = () => ({
|
||||
const defaultProps = (props = {}) => ({
|
||||
unreadCount: 2,
|
||||
totalCount: 5,
|
||||
unreadLabel: '2 unread replies',
|
||||
totalLabel: '5 total replies',
|
||||
unreadLabel: 'unreadLabel',
|
||||
totalLabel: 'totalLabel',
|
||||
...props,
|
||||
})
|
||||
|
||||
test('renders the UnreadBadge component', () => {
|
||||
const tree = mount(<UnreadBadge {...defaultProps()} />)
|
||||
ok(tree.exists())
|
||||
})
|
||||
const renderUnreadBadge = (props = {}) => render(<UnreadBadge {...defaultProps(props)} />)
|
||||
|
||||
test('renders the correct unread count', () => {
|
||||
const tree = shallow(<UnreadBadge {...defaultProps()} />)
|
||||
const node = tree.find('.ic-unread-badge__unread-count')
|
||||
equal(node.text(), '2')
|
||||
})
|
||||
describe('UnreadBadge', () => {
|
||||
it('renders the UnreadBadge component', () => {
|
||||
renderUnreadBadge()
|
||||
|
||||
test('renders the correct total count', () => {
|
||||
const tree = shallow(<UnreadBadge {...defaultProps()} />)
|
||||
const node = tree.find('.ic-unread-badge__total-count')
|
||||
equal(node.text(), '5')
|
||||
expect(screen.getByText('unreadLabel')).toBeInTheDocument()
|
||||
expect(screen.getByText('totalLabel')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders the correct unread count', () => {
|
||||
renderUnreadBadge()
|
||||
|
||||
expect(screen.getByText('2 unread replies')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('renders the correct total count', () => {
|
||||
renderUnreadBadge()
|
||||
|
||||
expect(screen.getByText('5 total replies')).toBeInTheDocument()
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue