spec: Remove enzyme.mount from blueprint_courses components
fixes LF-1430 flag=none test plan: - tests pass - tests are still testing what they were before Change-Id: I1bec3043950a31b22e38a25085e6baf618c42322 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/345618 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Jacob DeWar <jacob.dewar@instructure.com> QA-Review: Jacob DeWar <jacob.dewar@instructure.com> Product-Review: Eric Saupe <eric.saupe@instructure.com>
This commit is contained in:
parent
47633af85d
commit
3bc74a4844
|
@ -1,223 +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 $ from 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import {Provider} from 'react-redux'
|
||||
import * as enzyme from 'enzyme'
|
||||
import moxios from 'moxios'
|
||||
|
||||
import {ConnectedCourseSidebar} from 'ui/features/blueprint_course_master/react/components/CourseSidebar'
|
||||
import MigrationStates from '@canvas/blueprint-courses/react/migrationStates'
|
||||
import getSampleData from '../getSampleData'
|
||||
import mockStore from '../mockStore'
|
||||
|
||||
let clock
|
||||
let sidebarContentRef = null
|
||||
|
||||
const initialState = {
|
||||
masterCourse: getSampleData().masterCourse,
|
||||
existingAssociations: getSampleData().courses,
|
||||
unsyncedChanges: getSampleData().unsyncedChanges,
|
||||
migrationStatus: MigrationStates.states.unknown,
|
||||
canManageCourse: true,
|
||||
hasLoadedAssociations: true,
|
||||
hasLoadedUnsyncedChanges: true,
|
||||
}
|
||||
|
||||
const defaultProps = () => ({
|
||||
contentRef: cr => {
|
||||
sidebarContentRef = cr
|
||||
},
|
||||
routeTo: () => {},
|
||||
})
|
||||
|
||||
function connect(props = defaultProps(), storeState = initialState) {
|
||||
return (
|
||||
<Provider store={mockStore(storeState)}>
|
||||
<ConnectedCourseSidebar {...props} />
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
|
||||
QUnit.module('Course Sidebar component', {
|
||||
setup() {
|
||||
clock = sinon.useFakeTimers()
|
||||
const appElement = document.createElement('div')
|
||||
appElement.id = 'application'
|
||||
document.getElementById('fixtures').appendChild(appElement)
|
||||
sidebarContentRef = null
|
||||
moxios.install()
|
||||
moxios.stubRequest('/api/v1/courses/4/blueprint_templates/default/migrations', {
|
||||
status: 200,
|
||||
response: [{id: '1'}],
|
||||
})
|
||||
},
|
||||
teardown() {
|
||||
moxios.uninstall()
|
||||
document.getElementById('fixtures').innerHTML = ''
|
||||
clock.restore()
|
||||
},
|
||||
})
|
||||
|
||||
test('renders the closed CourseSidebar component', () => {
|
||||
const tree = enzyme.mount(connect())
|
||||
const node = tree.find('button')
|
||||
equal(node.text().trim(), 'Open Blueprint Sidebar')
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders the open CourseSidebar component', () => {
|
||||
const tree = enzyme.mount(connect())
|
||||
tree.find('button').simulate('click')
|
||||
clock.tick(500)
|
||||
ok(sidebarContentRef, 'sidebar contents')
|
||||
|
||||
const sidebar = $(sidebarContentRef)
|
||||
const rows = sidebar.find('.bcs__row')
|
||||
|
||||
// associations
|
||||
ok(rows.eq(0).find('button#mcSidebarAsscBtn').size(), 'Associations button')
|
||||
equal(
|
||||
rows.eq(0).text().trim(),
|
||||
`Associations${initialState.existingAssociations.length}`,
|
||||
'Associations count'
|
||||
)
|
||||
|
||||
// sync history
|
||||
ok(rows.eq(1).find('button#mcSyncHistoryBtn').size(), 'sync history button')
|
||||
|
||||
// unsynced changes
|
||||
ok(rows.eq(2).find('button#mcUnsyncedChangesBtn').size(), 'unsynced changes button')
|
||||
equal(rows.eq(2).find('span').eq(0).text(), 'Unsynced Changes')
|
||||
|
||||
const count = rows.eq(2).find('.bcs__row-right-content').text()
|
||||
equal(count, initialState.unsyncedChanges.length, 'unsynced changes count')
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Uncynced Changes link if there are none', () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.unsyncedChanges = []
|
||||
const tree = enzyme.mount(connect(props, state))
|
||||
tree.find('button').simulate('click')
|
||||
ok(sidebarContentRef)
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
// no unsynced changes
|
||||
notOk(sidebar.find('button#mcUnsyncedChangesBtn').size())
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Uncynced Changes link if there are no associations', () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.existingAssociations = []
|
||||
const tree = enzyme.mount(connect(props, state))
|
||||
tree.find('button').simulate('click')
|
||||
ok(sidebarContentRef)
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
// no unsynced changes
|
||||
notOk(sidebar.find('button#mcUnsyncedChangesBtn').size())
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Uncynced Changes link if sync is in progress', () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.migrationStatus = MigrationStates.states.imports_queued
|
||||
const tree = enzyme.mount(connect(props, state))
|
||||
tree.find('button').simulate('click')
|
||||
ok(sidebarContentRef)
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
// no unsynced changes
|
||||
notOk(sidebar.find('button#mcUnsyncedChangesBtn').size())
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Associations link if the user not an admin', () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.canManageCourse = false
|
||||
const tree = enzyme.mount(connect(props, state))
|
||||
tree.find('button').simulate('click')
|
||||
ok(sidebarContentRef)
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
// no unsynced changes
|
||||
notOk(sidebar.find('button#mcSidebarAsscBtn').size())
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders Sync button if has associations and sync is active and no unsyced changes', () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.unsyncedChanges = []
|
||||
state.migrationStatus = MigrationStates.states.imports_queued
|
||||
const tree = enzyme.mount(connect(props, state))
|
||||
tree.find('button').simulate('click')
|
||||
clock.tick(500)
|
||||
ok(sidebarContentRef)
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
ok(sidebar.find('.bcs__migration-sync').size())
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders Sync button if has associations and has unsynced changes', () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
const tree = enzyme.mount(connect(props, state))
|
||||
tree.find('button').simulate('click')
|
||||
clock.tick(500)
|
||||
ok(sidebarContentRef)
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
ok(sidebar.find('.bcs__migration-sync').size())
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Sync button if there are no associations', () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.existingAssociations = []
|
||||
const tree = enzyme.mount(connect(props, state))
|
||||
tree.find('button').simulate('click')
|
||||
ok(sidebarContentRef)
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
notOk(sidebar.find('.bcs__migration-sync').size())
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Sync button if there are associations, but no unsynced changes and no sync in progress', () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.unsyncedChanges = []
|
||||
const tree = enzyme.mount(connect(props, state))
|
||||
tree.find('button').simulate('click')
|
||||
ok(sidebarContentRef)
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
notOk(sidebar.find('.bcs__migration-sync').size())
|
||||
tree.unmount()
|
||||
})
|
|
@ -1,73 +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 * as enzyme from 'enzyme'
|
||||
import LockBanner from '@canvas/blueprint-courses/react/components/LockManager/LockBanner'
|
||||
|
||||
QUnit.module('LockBanner component')
|
||||
|
||||
const defaultProps = () => ({
|
||||
isLocked: true,
|
||||
itemLocks: {
|
||||
content: true,
|
||||
points: false,
|
||||
due_dates: false,
|
||||
availability_dates: false,
|
||||
},
|
||||
})
|
||||
|
||||
test('renders an Alert when LockBanner is locked', () => {
|
||||
const props = defaultProps()
|
||||
props.isLocked = true
|
||||
const tree = enzyme.mount(<LockBanner {...props} />)
|
||||
const node = tree.find('Alert')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('does not render Alert when LockBanner is locked', () => {
|
||||
const props = defaultProps()
|
||||
props.isLocked = false
|
||||
const tree = enzyme.mount(<LockBanner {...props} />)
|
||||
const node = tree.find('Alert')
|
||||
notOk(node.exists())
|
||||
})
|
||||
|
||||
test('displays locked description text appropriately when one attribute is locked', () => {
|
||||
const props = defaultProps()
|
||||
const tree = enzyme.mount(<LockBanner {...props} />)
|
||||
const text = tree.find('Text').at(2).text()
|
||||
equal(text, 'Content')
|
||||
})
|
||||
|
||||
test('displays locked description text appropriately when two attributes are locked', () => {
|
||||
const props = defaultProps()
|
||||
props.itemLocks.points = true
|
||||
const tree = enzyme.mount(<LockBanner {...props} />)
|
||||
const text = tree.find('Text').at(2).text()
|
||||
equal(text, 'Content & Points')
|
||||
})
|
||||
|
||||
test('displays locked description text appropriately when more than two attributes are locked', () => {
|
||||
const props = defaultProps()
|
||||
props.itemLocks.points = true
|
||||
props.itemLocks.due_dates = true
|
||||
const tree = enzyme.mount(<LockBanner {...props} />)
|
||||
const text = tree.find('Text').at(2).text()
|
||||
equal(text, 'Content, Points & Due Dates')
|
||||
})
|
|
@ -1,66 +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 * as enzyme from 'enzyme'
|
||||
import LockToggle from '@canvas/blueprint-courses/react/components/LockManager/LockToggle'
|
||||
|
||||
QUnit.module('LockToggle component')
|
||||
|
||||
const defaultProps = () => ({
|
||||
isLocked: true,
|
||||
isToggleable: true,
|
||||
})
|
||||
|
||||
test('renders the LockToggle component', () => {
|
||||
const tree = enzyme.mount(<LockToggle {...defaultProps()} />)
|
||||
const node = tree.find('.bpc-lock-toggle')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders a button when LockToggle is toggleable', () => {
|
||||
const props = defaultProps()
|
||||
props.isToggleable = true
|
||||
const tree = enzyme.mount(<LockToggle {...props} />)
|
||||
const node = tree.find('Button')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('does not render a button when LockToggle is not toggleable', () => {
|
||||
const props = defaultProps()
|
||||
props.isToggleable = false
|
||||
const tree = enzyme.shallow(<LockToggle {...props} />)
|
||||
const node = tree.find('Button')
|
||||
notOk(node.exists())
|
||||
})
|
||||
|
||||
test('renders a locked icon when LockToggle is locked', () => {
|
||||
const props = defaultProps()
|
||||
props.isLocked = true
|
||||
const tree = enzyme.mount(<LockToggle {...props} />)
|
||||
const node = tree.find('IconBlueprintLockSolid')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders an unlocked icon when LockToggle is unlocked', () => {
|
||||
const props = defaultProps()
|
||||
props.isLocked = false
|
||||
const tree = enzyme.mount(<LockToggle {...props} />)
|
||||
const node = tree.find('IconBlueprintSolid')
|
||||
ok(node.exists())
|
||||
})
|
|
@ -1,85 +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 * as enzyme from 'enzyme'
|
||||
import MigrationOptions from 'ui/features/blueprint_course_master/react/components/MigrationOptions'
|
||||
import MigrationStates from '@canvas/blueprint-courses/react/migrationStates'
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
QUnit.module('MigrationOptions component')
|
||||
|
||||
const defaultProps = {
|
||||
migrationStatus: MigrationStates.states.unknown,
|
||||
willSendNotification: false,
|
||||
willIncludeCustomNotificationMessage: false,
|
||||
willIncludeCourseSettings: false,
|
||||
notificationMessage: '',
|
||||
enableSendNotification: noop,
|
||||
includeCustomNotificationMessage: noop,
|
||||
setNotificationMessage: noop,
|
||||
includeCourseSettings: noop,
|
||||
}
|
||||
|
||||
test('renders the MigrationOptions component', () => {
|
||||
const tree = enzyme.shallow(<MigrationOptions {...defaultProps} />)
|
||||
const node = tree.find({as: 'fieldset'})
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders the course-settings and notification-enable checkboxes', () => {
|
||||
const tree = enzyme.mount(<MigrationOptions {...defaultProps} />)
|
||||
const checkboxes = tree.find('input[type="checkbox"]')
|
||||
equal(checkboxes.length, 2)
|
||||
equal(checkboxes.at(0).prop('checked'), false)
|
||||
equal(checkboxes.at(1).prop('checked'), false)
|
||||
})
|
||||
|
||||
test('renders the add a message checkbox', () => {
|
||||
const props = {...defaultProps}
|
||||
props.willSendNotification = true
|
||||
|
||||
const tree = enzyme.mount(<MigrationOptions {...props} />)
|
||||
|
||||
ok(tree.find('Checkbox[label="Include Course Settings"]').first().exists())
|
||||
equal(tree.find('Checkbox[label="Include Course Settings"]').first().prop('checked'), false)
|
||||
|
||||
ok(tree.find('Checkbox[label="Send Notification"]').first().exists())
|
||||
equal(tree.find('Checkbox[label="Send Notification"]').first().prop('checked'), true)
|
||||
|
||||
const checkbox3 = tree
|
||||
.find('Checkbox')
|
||||
.filterWhere(n => n.text().includes('0/140'))
|
||||
.first()
|
||||
ok(checkbox3.exists())
|
||||
equal(checkbox3.prop('checked'), false)
|
||||
|
||||
const messagebox = tree.find('TextArea')
|
||||
ok(!messagebox.exists())
|
||||
})
|
||||
|
||||
test('renders the message text area', () => {
|
||||
const props = {...defaultProps}
|
||||
props.willSendNotification = true
|
||||
props.willIncludeCustomNotificationMessage = true
|
||||
|
||||
const tree = enzyme.mount(<MigrationOptions {...props} />)
|
||||
const messagebox = tree.find('TextArea')
|
||||
ok(messagebox.exists())
|
||||
})
|
|
@ -1,79 +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 * as enzyme from 'enzyme'
|
||||
import MigrationSync from 'ui/features/blueprint_course_master/react/components/MigrationSync'
|
||||
|
||||
QUnit.module('MigrationSync component')
|
||||
|
||||
const defaultProps = () => ({
|
||||
migrationStatus: 'void',
|
||||
hasCheckedMigration: true,
|
||||
isLoadingBeginMigration: false,
|
||||
checkMigration: () => {},
|
||||
beginMigration: () => {},
|
||||
stopMigrationStatusPoll: () => {},
|
||||
})
|
||||
|
||||
test('renders the MigrationSync component', () => {
|
||||
const tree = enzyme.shallow(<MigrationSync {...defaultProps()} />)
|
||||
const node = tree.find('.bcs__migration-sync')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders the progress indicator if in a loading migration state', () => {
|
||||
const props = defaultProps()
|
||||
props.migrationStatus = 'queued'
|
||||
const tree = enzyme.shallow(<MigrationSync {...props} />)
|
||||
const node = tree.find('.bcs__migration-sync__loading')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders the progress indicator if in the process of beginning a migration', () => {
|
||||
const props = defaultProps()
|
||||
props.isLoadingBeginMigration = true
|
||||
const tree = enzyme.shallow(<MigrationSync {...props} />)
|
||||
const node = tree.find('.bcs__migration-sync__loading')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('calls beginMigration when sync button is clicked', () => {
|
||||
const props = defaultProps()
|
||||
props.beginMigration = sinon.spy()
|
||||
const tree = enzyme.mount(<MigrationSync {...props} />)
|
||||
const button = tree.find('.bcs__migration-sync button')
|
||||
button.at(0).simulate('click')
|
||||
equal(props.beginMigration.callCount, 1)
|
||||
})
|
||||
|
||||
test('calls checkMigration on mount if it has not been checked already', () => {
|
||||
const props = defaultProps()
|
||||
props.hasCheckedMigration = false
|
||||
props.checkMigration = sinon.spy()
|
||||
const tree = enzyme.shallow(<MigrationSync {...props} />)
|
||||
equal(props.checkMigration.callCount, 1)
|
||||
})
|
||||
|
||||
test('does not call checkMigration on mount if it has been checked already', () => {
|
||||
const props = defaultProps()
|
||||
props.hasCheckedMigration = true
|
||||
props.checkMigration = sinon.spy()
|
||||
const tree = enzyme.shallow(<MigrationSync {...props} />)
|
||||
equal(props.checkMigration.callCount, 0)
|
||||
})
|
|
@ -1,67 +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 * as enzyme from 'enzyme'
|
||||
import SyncHistoryItem from '@canvas/blueprint-courses/react/components/SyncHistoryItem'
|
||||
import getSampleData from '../getSampleData'
|
||||
|
||||
QUnit.module('SyncHistoryItem component')
|
||||
|
||||
const defaultProps = () => ({
|
||||
heading: null,
|
||||
migration: getSampleData().history[0],
|
||||
})
|
||||
|
||||
test('renders the SyncHistoryItem component', () => {
|
||||
const tree = enzyme.shallow(<SyncHistoryItem {...defaultProps()} />)
|
||||
const node = tree.find('.bcs__history-item')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders heading component when migration has changes', () => {
|
||||
const props = defaultProps()
|
||||
props.heading = <p className="test-heading">test</p>
|
||||
const tree = enzyme.shallow(<SyncHistoryItem {...props} />)
|
||||
const node = tree.find('.bcs__history-item .test-heading')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('does not render the heading component when migration has no changes', () => {
|
||||
const props = defaultProps()
|
||||
props.heading = <p className="test-heading">test</p>
|
||||
props.migration.changes = []
|
||||
const tree = enzyme.shallow(<SyncHistoryItem {...props} />)
|
||||
const node = tree.find('.bcs__history-item .test-heading')
|
||||
notOk(node.exists())
|
||||
})
|
||||
|
||||
test('renders changes using the appropriate prop component', () => {
|
||||
const props = defaultProps()
|
||||
props.ChangeComponent = () => <div className="test-change" />
|
||||
const tree = enzyme.mount(<SyncHistoryItem {...props} />)
|
||||
const node = tree.find('.bcs__history-item .test-change')
|
||||
equal(node.length, props.migration.changes.length)
|
||||
})
|
||||
|
||||
test('includes the name of the person who started the sync', () => {
|
||||
const tree = enzyme.mount(<SyncHistoryItem {...defaultProps()} />)
|
||||
const node = tree.find('.bcs__history-item__title')
|
||||
const text = node.text()
|
||||
notEqual(text.indexOf('changes pushed by Bob Jones'), -1)
|
||||
})
|
|
@ -1,54 +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 * as enzyme from 'enzyme'
|
||||
import SyncHistory from 'ui/features/blueprint_course_master/react/components/SyncHistory'
|
||||
import getSampleData from '../getSampleData'
|
||||
|
||||
QUnit.module('SyncHistory component')
|
||||
|
||||
const defaultProps = () => ({
|
||||
loadHistory: () => {},
|
||||
isLoadingHistory: false,
|
||||
hasLoadedHistory: false,
|
||||
loadAssociations: () => {},
|
||||
isLoadingAssociations: false,
|
||||
hasLoadedAssociations: false,
|
||||
migrations: getSampleData().history,
|
||||
})
|
||||
|
||||
test('renders the SyncHistory component', () => {
|
||||
const tree = enzyme.shallow(<SyncHistory {...defaultProps()} />)
|
||||
const node = tree.find('.bcs__history')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('displays spinner when loading courses', () => {
|
||||
const props = defaultProps()
|
||||
props.isLoadingHistory = true
|
||||
const tree = enzyme.shallow(<SyncHistory {...props} />)
|
||||
const node = tree.find('.bcs__history Spinner')
|
||||
ok(node.exists())
|
||||
})
|
||||
|
||||
test('renders SyncHistoryItem components for each migration', () => {
|
||||
const tree = enzyme.mount(<SyncHistory {...defaultProps()} />)
|
||||
const node = tree.find('SyncHistoryItem')
|
||||
equal(node.length, 1)
|
||||
})
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 - 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 {createStore, applyMiddleware} from 'redux'
|
||||
import {thunk} from 'redux-thunk'
|
||||
import rootReducer from '@canvas/blueprint-courses/react/reducer'
|
||||
|
||||
export default function mockStore(initialState) {
|
||||
return applyMiddleware(thunk)(createStore)(rootReducer, initialState)
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright (C) 2024 - 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 $ from 'jquery'
|
||||
import 'jquery-migrate'
|
||||
import {Provider} from 'react-redux'
|
||||
import {render} from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import moxios from 'moxios'
|
||||
import sinon from 'sinon'
|
||||
|
||||
import {ConnectedCourseSidebar} from '../CourseSidebar'
|
||||
import MigrationStates from '@canvas/blueprint-courses/react/migrationStates'
|
||||
import getSampleData from './getSampleData'
|
||||
|
||||
import {createStore, applyMiddleware} from 'redux'
|
||||
import {thunk} from 'redux-thunk'
|
||||
import rootReducer from '@canvas/blueprint-courses/react/reducer'
|
||||
|
||||
let clock
|
||||
let sidebarContentRef = null
|
||||
|
||||
const initialState = {
|
||||
masterCourse: getSampleData().masterCourse,
|
||||
existingAssociations: getSampleData().courses,
|
||||
unsyncedChanges: getSampleData().unsyncedChanges,
|
||||
migrationStatus: MigrationStates.states.unknown,
|
||||
canManageCourse: true,
|
||||
hasLoadedAssociations: true,
|
||||
hasLoadedUnsyncedChanges: true,
|
||||
canAutoPublishCourses: false,
|
||||
}
|
||||
|
||||
const defaultProps = () => ({
|
||||
contentRef: cr => {
|
||||
sidebarContentRef = cr
|
||||
},
|
||||
routeTo: () => {}
|
||||
})
|
||||
|
||||
function mockStore(initialState) {
|
||||
return applyMiddleware(thunk)(createStore)(rootReducer, initialState)
|
||||
}
|
||||
|
||||
function connect(props = defaultProps(), storeState = initialState) {
|
||||
return (
|
||||
<Provider store={mockStore(storeState)}>
|
||||
<ConnectedCourseSidebar {...props} />
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
|
||||
describe('Course Sidebar component', () => {
|
||||
beforeEach(() => {
|
||||
clock = sinon.useFakeTimers()
|
||||
moxios.install()
|
||||
moxios.stubRequest('/api/v1/courses/4/blueprint_templates/default/migrations', {
|
||||
status: 200,
|
||||
response: [{id: '1'}],
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
moxios.uninstall()
|
||||
clock.restore()
|
||||
})
|
||||
|
||||
test('renders the closed CourseSidebar component', () => {
|
||||
const tree = render(connect())
|
||||
const node = tree.container.querySelector('button')
|
||||
expect(node.textContent.trim()).toEqual('Open Blueprint Sidebar')
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders the open CourseSidebar component', async () => {
|
||||
const tree = render(connect())
|
||||
const button = tree.container.querySelector('button')
|
||||
const user = userEvent.setup({delay: null})
|
||||
await user.click(button)
|
||||
|
||||
clock.tick(500)
|
||||
expect(sidebarContentRef).toBeTruthy()
|
||||
|
||||
const sidebar = $(sidebarContentRef)
|
||||
const rows = sidebar.find('.bcs__row')
|
||||
|
||||
// associations
|
||||
expect(rows.eq(0).find('button#mcSidebarAsscBtn').size()).toBeTruthy()
|
||||
expect(rows.eq(0).text().trim()).toEqual(`Associations${initialState.existingAssociations.length}`)
|
||||
|
||||
// sync history
|
||||
expect(rows.eq(1).find('button#mcSyncHistoryBtn').size()).toBeTruthy()
|
||||
|
||||
// unsynced changes
|
||||
expect(rows.eq(2).find('button#mcUnsyncedChangesBtn').size()).toBeTruthy()
|
||||
expect(rows.eq(2).find('span').eq(0).text()).toEqual('Unsynced Changes')
|
||||
|
||||
const count = Number(rows.eq(2).find('.bcs__row-right-content').text())
|
||||
expect(count).toEqual(initialState.unsyncedChanges.length)
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Uncynced Changes link if there are none', async () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.unsyncedChanges = []
|
||||
const tree = render(connect(props, state))
|
||||
const button = tree.container.querySelector('button')
|
||||
const user = userEvent.setup({delay: null})
|
||||
await user.click(button)
|
||||
|
||||
expect(sidebarContentRef).toBeTruthy()
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
// no unsynced changes
|
||||
expect(sidebar.find('button#mcUnsyncedChangesBtn').size()).toBeFalsy()
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Uncynced Changes link if there are no associations', async () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.existingAssociations = []
|
||||
const tree = render(connect(props, state))
|
||||
const button = tree.container.querySelector('button')
|
||||
const user = userEvent.setup({delay: null})
|
||||
await user.click(button)
|
||||
|
||||
expect(sidebarContentRef).toBeTruthy()
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
// no unsynced changes
|
||||
expect(sidebar.find('button#mcUnsyncedChangesBtn').size()).toBeFalsy()
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Uncynced Changes link if sync is in progress', async () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.migrationStatus = MigrationStates.states.imports_queued
|
||||
const tree = render(connect(props, state))
|
||||
const button = tree.container.querySelector('button')
|
||||
const user = userEvent.setup({delay: null})
|
||||
await user.click(button)
|
||||
|
||||
expect(sidebarContentRef).toBeTruthy()
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
// no unsynced changes
|
||||
expect(sidebar.find('button#mcUnsyncedChangesBtn').size()).toBeFalsy()
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Associations link if the user not an admin', async () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.canManageCourse = false
|
||||
const tree = render(connect(props, state))
|
||||
const button = tree.container.querySelector('button')
|
||||
const user = userEvent.setup({delay: null})
|
||||
await user.click(button)
|
||||
|
||||
expect(sidebarContentRef).toBeTruthy()
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
// no unsynced changes
|
||||
expect(sidebar.find('button#mcSidebarAsscBtn').size()).toBeFalsy()
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders Sync button if has associations and sync is active and no unsyced changes', async () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.unsyncedChanges = []
|
||||
state.migrationStatus = MigrationStates.states.imports_queued
|
||||
const tree = render(connect(props, state))
|
||||
const button = tree.container.querySelector('button')
|
||||
const user = userEvent.setup({delay: null})
|
||||
await user.click(button)
|
||||
|
||||
clock.tick(500)
|
||||
expect(sidebarContentRef).toBeTruthy()
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
expect(sidebar.find('.bcs__migration-sync').size()).toBeTruthy()
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders Sync button if has associations and has unsynced changes', async() => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
const tree = render(connect(props, state))
|
||||
const button = tree.container.querySelector('button')
|
||||
const user = userEvent.setup({delay: null})
|
||||
await user.click(button)
|
||||
|
||||
clock.tick(500)
|
||||
expect(sidebarContentRef).toBeTruthy()
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
expect(sidebar.find('.bcs__migration-sync').size()).toBeTruthy()
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Sync button if there are no associations', async () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.existingAssociations = []
|
||||
const tree = render(connect(props, state))
|
||||
const button = tree.container.querySelector('button')
|
||||
const user = userEvent.setup({delay: null})
|
||||
await user.click(button)
|
||||
|
||||
expect(sidebarContentRef).toBeTruthy()
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
expect(sidebar.find('.bcs__migration-sync').size()).toBeFalsy()
|
||||
tree.unmount()
|
||||
})
|
||||
|
||||
test('renders no Sync button if there are associations, but no unsynced changes and no sync in progress', async () => {
|
||||
const props = defaultProps()
|
||||
const state = {...initialState}
|
||||
state.unsyncedChanges = []
|
||||
const tree = render(connect(props, state))
|
||||
const button = tree.container.querySelector('button')
|
||||
const user = userEvent.setup({delay: null})
|
||||
await user.click(button)
|
||||
|
||||
expect(sidebarContentRef).toBeTruthy()
|
||||
const sidebar = $(sidebarContentRef)
|
||||
|
||||
expect(sidebar.find('.bcs__migration-sync').size()).toBeFalsy()
|
||||
tree.unmount()
|
||||
})
|
||||
})
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (C) 2024 - 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 {shallow} from 'enzyme'
|
||||
import {render} from '@testing-library/react'
|
||||
import {getByLabelText} from '@testing-library/dom'
|
||||
import MigrationOptions from '../MigrationOptions'
|
||||
import MigrationStates from '@canvas/blueprint-courses/react/migrationStates'
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
describe('MigrationOptions component', () => {
|
||||
|
||||
const defaultProps = {
|
||||
migrationStatus: MigrationStates.states.unknown,
|
||||
willSendNotification: false,
|
||||
willIncludeCustomNotificationMessage: false,
|
||||
willIncludeCourseSettings: false,
|
||||
notificationMessage: '',
|
||||
enableSendNotification: noop,
|
||||
includeCustomNotificationMessage: noop,
|
||||
setNotificationMessage: noop,
|
||||
includeCourseSettings: noop,
|
||||
}
|
||||
|
||||
test('renders the MigrationOptions component', () => {
|
||||
const tree = shallow(<MigrationOptions {...defaultProps} />)
|
||||
const node = tree.find({as: 'fieldset'})
|
||||
expect(node.exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
test('renders the course-settings and notification-enable checkboxes', () => {
|
||||
const tree = render(<MigrationOptions {...defaultProps} />)
|
||||
const checkboxes = tree.container.querySelectorAll('input[type="checkbox"]')
|
||||
expect(checkboxes.length).toEqual(2)
|
||||
expect(checkboxes[0].checked).toEqual(false)
|
||||
expect(checkboxes[1].checked).toEqual(false)
|
||||
})
|
||||
|
||||
test('renders the add a message checkbox', () => {
|
||||
const props = {...defaultProps}
|
||||
props.willSendNotification = true
|
||||
|
||||
const tree = render(<MigrationOptions {...props} />)
|
||||
|
||||
const courseSettingsCheckbox = getByLabelText(tree.container, 'Include Course Settings')
|
||||
expect(courseSettingsCheckbox).toBeTruthy()
|
||||
expect(courseSettingsCheckbox.checked).toEqual(false)
|
||||
|
||||
const notificationCheckbox = getByLabelText(tree.container, 'Send Notification')
|
||||
expect(notificationCheckbox).toBeTruthy()
|
||||
expect(notificationCheckbox.checked).toEqual(true)
|
||||
|
||||
const checkbox3 = getByLabelText(tree.container, 'Add a Message (0/140)')
|
||||
expect(checkbox3).toBeTruthy()
|
||||
expect(checkbox3.checked).toEqual(false)
|
||||
|
||||
const messagebox = tree.container.querySelector('textarea')
|
||||
expect(messagebox).toBeFalsy()
|
||||
})
|
||||
|
||||
test('renders the message text area', () => {
|
||||
const props = {...defaultProps}
|
||||
props.willSendNotification = true
|
||||
props.willIncludeCustomNotificationMessage = true
|
||||
|
||||
const tree = render(<MigrationOptions {...props} />)
|
||||
const messagebox = tree.container.querySelector('textarea')
|
||||
expect(messagebox).toBeTruthy()
|
||||
})
|
||||
})
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (C) 2024 - 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 '@testing-library/react'
|
||||
import {shallow} from 'enzyme'
|
||||
import sinon from 'sinon'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import MigrationSync from '../MigrationSync'
|
||||
|
||||
describe('MigrationSync component', () => {
|
||||
|
||||
const defaultProps = () => ({
|
||||
migrationStatus: 'void',
|
||||
hasCheckedMigration: true,
|
||||
isLoadingBeginMigration: false,
|
||||
checkMigration: () => {},
|
||||
beginMigration: () => {},
|
||||
stopMigrationStatusPoll: () => {},
|
||||
})
|
||||
|
||||
test('renders the MigrationSync component', () => {
|
||||
const tree = shallow(<MigrationSync {...defaultProps()} />)
|
||||
const node = tree.find('.bcs__migration-sync')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('renders the progress indicator if in a loading migration state', () => {
|
||||
const props = defaultProps()
|
||||
props.migrationStatus = 'queued'
|
||||
const tree = shallow(<MigrationSync {...props} />)
|
||||
const node = tree.find('.bcs__migration-sync__loading')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('renders the progress indicator if in the process of beginning a migration', () => {
|
||||
const props = defaultProps()
|
||||
props.isLoadingBeginMigration = true
|
||||
const tree = shallow(<MigrationSync {...props} />)
|
||||
const node = tree.find('.bcs__migration-sync__loading')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('calls beginMigration when sync button is clicked', async () => {
|
||||
const props = defaultProps()
|
||||
props.beginMigration = sinon.spy()
|
||||
const tree = render(<MigrationSync {...props} />)
|
||||
const button = tree.container.querySelector('.bcs__migration-sync button')
|
||||
const user = userEvent.setup({delay: null})
|
||||
await user.click(button)
|
||||
expect(props.beginMigration.callCount).toEqual(1)
|
||||
})
|
||||
|
||||
test('calls checkMigration on mount if it has not been checked already', () => {
|
||||
const props = defaultProps()
|
||||
props.hasCheckedMigration = false
|
||||
props.checkMigration = sinon.spy()
|
||||
const tree = shallow(<MigrationSync {...props} />)
|
||||
expect(props.checkMigration.callCount).toEqual(1)
|
||||
})
|
||||
|
||||
test('does not call checkMigration on mount if it has been checked already', () => {
|
||||
const props = defaultProps()
|
||||
props.hasCheckedMigration = true
|
||||
props.checkMigration = sinon.spy()
|
||||
const tree = shallow(<MigrationSync {...props} />)
|
||||
expect(props.checkMigration.callCount).toEqual(0)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2024 - 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 '@testing-library/react'
|
||||
import {shallow} from 'enzyme'
|
||||
import SyncHistory from '../SyncHistory'
|
||||
import getSampleData from './getSampleData'
|
||||
|
||||
describe('SyncHistory component', () => {
|
||||
|
||||
const defaultProps = () => ({
|
||||
loadHistory: () => {},
|
||||
isLoadingHistory: false,
|
||||
hasLoadedHistory: false,
|
||||
loadAssociations: () => {},
|
||||
isLoadingAssociations: false,
|
||||
hasLoadedAssociations: false,
|
||||
migrations: getSampleData().history,
|
||||
})
|
||||
|
||||
test('renders the SyncHistory component', () => {
|
||||
const tree = shallow(<SyncHistory {...defaultProps()} />)
|
||||
const node = tree.find('.bcs__history')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('displays spinner when loading courses', () => {
|
||||
const props = defaultProps()
|
||||
props.isLoadingHistory = true
|
||||
const tree = shallow(<SyncHistory {...props} />)
|
||||
const node = tree.find('.bcs__history Spinner')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('renders SyncHistoryItem components for each migration', () => {
|
||||
const tree = render(<SyncHistory {...defaultProps()} />)
|
||||
console.log(tree.container.innerHTML)
|
||||
const node = tree.container.querySelectorAll('.bcs__history-item')
|
||||
expect(node.length).toEqual(1)
|
||||
})
|
||||
})
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2017 - present Instructure, Inc.
|
||||
* Copyright (C) 2024 - present Instructure, Inc.
|
||||
*
|
||||
* This file is part of Canvas.
|
||||
*
|
||||
|
@ -18,9 +18,10 @@
|
|||
|
||||
import React from 'react'
|
||||
import {Provider} from 'react-redux'
|
||||
import {mount} from 'enzyme'
|
||||
import {render} from '@testing-library/react'
|
||||
import {getByText, getAllByText} from '@testing-library/dom'
|
||||
import createStore from '@canvas/blueprint-courses/react/store'
|
||||
import {ConnectedUnsyncedChanges} from 'ui/features/blueprint_course_master/react/components/UnsyncedChanges'
|
||||
import {ConnectedUnsyncedChanges} from '../UnsyncedChanges'
|
||||
import MigrationStates from '@canvas/blueprint-courses/react/migrationStates'
|
||||
|
||||
const noop = () => {}
|
||||
|
@ -90,45 +91,39 @@ function connect(props = {...defaultProps}) {
|
|||
)
|
||||
}
|
||||
|
||||
QUnit.module('UnsyncedChanges component')
|
||||
describe('UnsyncedChanges component', () => {
|
||||
|
||||
test('renders the UnsyncedChanges component', () => {
|
||||
const tree = mount(connect())
|
||||
let node = tree.find('UnsyncedChanges')
|
||||
ok(node.exists())
|
||||
node = tree.find('.bcs__history')
|
||||
ok(node.exists())
|
||||
})
|
||||
test('renders the UnsyncedChanges component', () => {
|
||||
const tree = render(connect())
|
||||
let node = tree.container.querySelector('.bcs__unsynced-item__table')
|
||||
expect(node).toBeTruthy()
|
||||
node = tree.container.querySelector('.bcs__history')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('renders the migration options component', () => {
|
||||
const tree = mount(connect())
|
||||
const node = tree.find('MigrationOptions')
|
||||
ok(node.exists())
|
||||
})
|
||||
test('renders the migration options component', () => {
|
||||
const tree = render(connect())
|
||||
const node = getByText(tree.container, 'History Settings')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('renders the changes properly', () => {
|
||||
const tree = mount(connect())
|
||||
const changes = tree.find('tr[data-testid="bcs__unsynced-item"]')
|
||||
equal(changes.length, 4)
|
||||
const locks = changes.find('IconBlueprintLockSolid')
|
||||
equal(locks.length, 1)
|
||||
const unlocks = changes.find('IconBlueprintSolid')
|
||||
equal(unlocks.length, 3)
|
||||
})
|
||||
test('renders the changes properly', () => {
|
||||
const tree = render(connect())
|
||||
const changes = tree.container.querySelectorAll('tr[data-testid="bcs__unsynced-item"]')
|
||||
expect(changes.length).toEqual(4)
|
||||
const locks = tree.container.querySelectorAll('svg[name="IconBlueprintLock"]')
|
||||
expect(locks.length).toEqual(1)
|
||||
const unlocks = tree.container.querySelectorAll('svg[name="IconBlueprint"]')
|
||||
expect(unlocks.length).toEqual(3)
|
||||
})
|
||||
|
||||
test('renders the media tracks properly', () => {
|
||||
const tree = mount(connect())
|
||||
const changes = tree.find('tr[data-testid="bcs__unsynced-item"]')
|
||||
equal(changes.length, 4)
|
||||
const assetName = changes.findWhere(
|
||||
node =>
|
||||
node.name() === 'Text' &&
|
||||
node.text() === 'media.mp4 (English)' &&
|
||||
node.parent().type() === 'span'
|
||||
)
|
||||
equal(assetName.length, 1)
|
||||
const assetType = changes.findWhere(
|
||||
node => node.name() === 'Text' && node.text() === 'Caption' && node.parent().type() === 'td'
|
||||
)
|
||||
equal(assetType.length, 1)
|
||||
test('renders the media tracks properly', () => {
|
||||
const tree = render(connect())
|
||||
const changes = tree.container.querySelectorAll('tr[data-testid="bcs__unsynced-item"]')
|
||||
expect(changes.length).toEqual(4)
|
||||
const assetName = getAllByText(tree.container, 'media.mp4 (English)')
|
||||
expect(assetName.length).toEqual(1)
|
||||
const assetType = getAllByText(tree.container, 'Caption')
|
||||
expect(assetType.length).toEqual(1)
|
||||
})
|
||||
})
|
|
@ -67,7 +67,7 @@ export default class LockBanner extends Component {
|
|||
<Text weight="bold" size="small">
|
||||
{I18n.t('Locked:')}
|
||||
</Text>
|
||||
<Text size="small">{formatLockObject(this.props.itemLocks)}</Text>
|
||||
<Text size="small" data-testid="lockedMessage">{formatLockObject(this.props.itemLocks)}</Text>
|
||||
</Alert>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (C) 2024 - 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 '@testing-library/react'
|
||||
import LockBanner from '../LockBanner'
|
||||
|
||||
describe('LockBanner component', () => {
|
||||
|
||||
const defaultProps = () => ({
|
||||
isLocked: true,
|
||||
itemLocks: {
|
||||
content: true,
|
||||
points: false,
|
||||
due_dates: false,
|
||||
availability_dates: false,
|
||||
},
|
||||
})
|
||||
|
||||
test('renders an Alert when LockBanner is locked', () => {
|
||||
const props = defaultProps()
|
||||
props.isLocked = true
|
||||
const tree = render(<LockBanner {...props} />)
|
||||
const node = tree.container.querySelector('div')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('does not render Alert when LockBanner is locked', () => {
|
||||
const props = defaultProps()
|
||||
props.isLocked = false
|
||||
const tree = render(<LockBanner {...props} />)
|
||||
const node = tree.container.querySelector('div')
|
||||
expect(node).toBeFalsy()
|
||||
})
|
||||
|
||||
test('displays locked description text appropriately when one attribute is locked', () => {
|
||||
const props = defaultProps()
|
||||
const tree = render(<LockBanner {...props} />)
|
||||
const text = tree.container.querySelector("[data-testid='lockedMessage'").textContent
|
||||
expect(text).toEqual('Content')
|
||||
})
|
||||
|
||||
test('displays locked description text appropriately when two attributes are locked', () => {
|
||||
const props = defaultProps()
|
||||
props.itemLocks.points = true
|
||||
const tree = render(<LockBanner {...props} />)
|
||||
const text = tree.container.querySelector("[data-testid='lockedMessage'").textContent
|
||||
expect(text).toEqual('Content & Points')
|
||||
})
|
||||
|
||||
test('displays locked description text appropriately when more than two attributes are locked', () => {
|
||||
const props = defaultProps()
|
||||
props.itemLocks.points = true
|
||||
props.itemLocks.due_dates = true
|
||||
const tree = render(<LockBanner {...props} />)
|
||||
const text = tree.container.querySelector("[data-testid='lockedMessage'").textContent
|
||||
expect(text).toEqual('Content, Points & Due Dates')
|
||||
})
|
||||
})
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (C) 2024 - 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 {shallow} from 'enzyme'
|
||||
import {render} from '@testing-library/react'
|
||||
import LockToggle from '../LockToggle'
|
||||
|
||||
describe('LockToggle component', () => {
|
||||
|
||||
const defaultProps = () => ({
|
||||
isLocked: true,
|
||||
isToggleable: true,
|
||||
})
|
||||
|
||||
test('renders the LockToggle component', () => {
|
||||
const tree = render(<LockToggle {...defaultProps()} />)
|
||||
const node = tree.container.querySelector('.bpc-lock-toggle')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('renders a button when LockToggle is toggleable', () => {
|
||||
const props = defaultProps()
|
||||
props.isToggleable = true
|
||||
const tree = render(<LockToggle {...props} />)
|
||||
const node = tree.container.querySelector('button')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('does not render a button when LockToggle is not toggleable', () => {
|
||||
const props = defaultProps()
|
||||
props.isToggleable = false
|
||||
const tree = shallow(<LockToggle {...props} />)
|
||||
const node = tree.find('button')
|
||||
expect(node.exists()).toBeFalsy()
|
||||
})
|
||||
|
||||
test('renders a locked icon when LockToggle is locked', () => {
|
||||
const props = defaultProps()
|
||||
props.isLocked = true
|
||||
const tree = render(<LockToggle {...props} />)
|
||||
console.log(tree.container.innerHTML)
|
||||
const node = tree.container.querySelector('svg[name="IconBlueprintLock"]')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('renders an unlocked icon when LockToggle is unlocked', () => {
|
||||
const props = defaultProps()
|
||||
props.isLocked = false
|
||||
const tree = render(<LockToggle {...props} />)
|
||||
console.log(tree.container.innerHTML)
|
||||
const node = tree.container.querySelector('svg[name="IconBlueprint"]')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
})
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2024 - 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 '@testing-library/react'
|
||||
import {shallow} from 'enzyme'
|
||||
import SyncHistoryItem from '../SyncHistoryItem'
|
||||
import getSampleData from './getSampleData'
|
||||
|
||||
describe('SyncHistoryItem component', () => {
|
||||
|
||||
const defaultProps = () => ({
|
||||
heading: null,
|
||||
migration: getSampleData().history[0],
|
||||
})
|
||||
|
||||
test('renders the SyncHistoryItem component', () => {
|
||||
const tree = shallow(<SyncHistoryItem {...defaultProps()} />)
|
||||
const node = tree.find('.bcs__history-item')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('renders heading component when migration has changes', () => {
|
||||
const props = defaultProps()
|
||||
props.heading = <p className="test-heading">test</p>
|
||||
const tree = shallow(<SyncHistoryItem {...props} />)
|
||||
const node = tree.find('.bcs__history-item .test-heading')
|
||||
expect(node).toBeTruthy()
|
||||
})
|
||||
|
||||
test('does not render the heading component when migration has no changes', () => {
|
||||
const props = defaultProps()
|
||||
props.heading = <p className="test-heading">test</p>
|
||||
props.migration.changes = []
|
||||
const tree = shallow(<SyncHistoryItem {...props} />)
|
||||
const node = tree.find('.bcs__history-item .test-heading')
|
||||
expect(node.exists()).toBeFalsy()
|
||||
})
|
||||
|
||||
test('renders changes using the appropriate prop component', () => {
|
||||
const props = defaultProps()
|
||||
props.ChangeComponent = () => <div className="test-change" />
|
||||
const tree = render(<SyncHistoryItem {...props} />)
|
||||
const node = tree.container.querySelectorAll('.bcs__history-item .test-change')
|
||||
expect(node.length).toEqual(props.migration.changes.length)
|
||||
})
|
||||
|
||||
test('includes the name of the person who started the sync', () => {
|
||||
const tree = render(<SyncHistoryItem {...defaultProps()} />)
|
||||
const node = tree.container.querySelector('.bcs__history-item__title')
|
||||
const text = node.textContent
|
||||
expect(text.indexOf('changes pushed by Bob Jones')).toEqual(57)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
export default function getSampleData() {
|
||||
return {
|
||||
terms: [
|
||||
{id: '1', name: 'Term One'},
|
||||
{id: '2', name: 'Term Two'},
|
||||
],
|
||||
subAccounts: [
|
||||
{id: '1', name: 'Account One'},
|
||||
{id: '2', name: 'Account Two'},
|
||||
],
|
||||
childCourse: {
|
||||
id: '1',
|
||||
enrollment_term_id: '1',
|
||||
name: 'Course 1',
|
||||
},
|
||||
masterCourse: {
|
||||
id: '2',
|
||||
enrollment_term_id: '1',
|
||||
name: 'Course 2',
|
||||
},
|
||||
courses: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Course One',
|
||||
course_code: 'course_1',
|
||||
term: {
|
||||
id: '1',
|
||||
name: 'Term One',
|
||||
},
|
||||
teachers: [
|
||||
{
|
||||
display_name: 'Teacher One',
|
||||
},
|
||||
],
|
||||
sis_course_id: '1001',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Course Two',
|
||||
course_code: 'course_2',
|
||||
term: {
|
||||
id: '2',
|
||||
name: 'Term Two',
|
||||
},
|
||||
teachers: [
|
||||
{
|
||||
display_name: 'Teacher Two',
|
||||
},
|
||||
],
|
||||
sis_course_id: '1001',
|
||||
},
|
||||
],
|
||||
history: [
|
||||
{
|
||||
id: '2',
|
||||
workflow_state: 'completed',
|
||||
created_at: '2013-08-28T23:59:00-06:00',
|
||||
user: {
|
||||
display_name: 'Bob Jones',
|
||||
},
|
||||
changes: [
|
||||
{
|
||||
asset_id: '2',
|
||||
asset_type: 'quiz',
|
||||
asset_name: 'Chapter 5 Quiz',
|
||||
change_type: 'updated',
|
||||
html_url: 'http://localhost:3000/courses/3/quizzes/2',
|
||||
exceptions: [
|
||||
{
|
||||
course_id: '1',
|
||||
conflicting_changes: ['points'],
|
||||
name: 'Course 1',
|
||||
term: {name: 'Default Term'},
|
||||
},
|
||||
{
|
||||
course_id: '5',
|
||||
conflicting_changes: ['content'],
|
||||
name: 'Course 5',
|
||||
term: {name: 'Default Term'},
|
||||
},
|
||||
{
|
||||
course_id: '56',
|
||||
conflicting_changes: ['deleted'],
|
||||
name: 'Course 56',
|
||||
term: {name: 'Default Term'},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
unsyncedChanges: [
|
||||
{
|
||||
asset_id: '22',
|
||||
asset_type: 'assignment',
|
||||
asset_name: 'Another Discussion',
|
||||
change_type: 'deleted',
|
||||
html_url: '/courses/4/assignments/22',
|
||||
locked: false,
|
||||
},
|
||||
{
|
||||
asset_id: '22',
|
||||
asset_type: 'attachment',
|
||||
asset_name: 'Bulldog.png',
|
||||
change_type: 'updated',
|
||||
html_url: '/courses/4/files/96',
|
||||
locked: true,
|
||||
},
|
||||
{
|
||||
asset_id: 'page-1',
|
||||
asset_type: 'wiki_page',
|
||||
asset_name: 'Page 1',
|
||||
change_type: 'created',
|
||||
html_url: '/4/pages/page-1',
|
||||
locked: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue