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.
|
* This file is part of Canvas.
|
||||||
*
|
*
|
||||||
|
@ -18,9 +18,10 @@
|
||||||
|
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {Provider} from 'react-redux'
|
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 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'
|
import MigrationStates from '@canvas/blueprint-courses/react/migrationStates'
|
||||||
|
|
||||||
const noop = () => {}
|
const noop = () => {}
|
||||||
|
@ -90,45 +91,39 @@ function connect(props = {...defaultProps}) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
QUnit.module('UnsyncedChanges component')
|
describe('UnsyncedChanges component', () => {
|
||||||
|
|
||||||
test('renders the UnsyncedChanges component', () => {
|
test('renders the UnsyncedChanges component', () => {
|
||||||
const tree = mount(connect())
|
const tree = render(connect())
|
||||||
let node = tree.find('UnsyncedChanges')
|
let node = tree.container.querySelector('.bcs__unsynced-item__table')
|
||||||
ok(node.exists())
|
expect(node).toBeTruthy()
|
||||||
node = tree.find('.bcs__history')
|
node = tree.container.querySelector('.bcs__history')
|
||||||
ok(node.exists())
|
expect(node).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('renders the migration options component', () => {
|
test('renders the migration options component', () => {
|
||||||
const tree = mount(connect())
|
const tree = render(connect())
|
||||||
const node = tree.find('MigrationOptions')
|
const node = getByText(tree.container, 'History Settings')
|
||||||
ok(node.exists())
|
expect(node).toBeTruthy()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('renders the changes properly', () => {
|
test('renders the changes properly', () => {
|
||||||
const tree = mount(connect())
|
const tree = render(connect())
|
||||||
const changes = tree.find('tr[data-testid="bcs__unsynced-item"]')
|
const changes = tree.container.querySelectorAll('tr[data-testid="bcs__unsynced-item"]')
|
||||||
equal(changes.length, 4)
|
expect(changes.length).toEqual(4)
|
||||||
const locks = changes.find('IconBlueprintLockSolid')
|
const locks = tree.container.querySelectorAll('svg[name="IconBlueprintLock"]')
|
||||||
equal(locks.length, 1)
|
expect(locks.length).toEqual(1)
|
||||||
const unlocks = changes.find('IconBlueprintSolid')
|
const unlocks = tree.container.querySelectorAll('svg[name="IconBlueprint"]')
|
||||||
equal(unlocks.length, 3)
|
expect(unlocks.length).toEqual(3)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('renders the media tracks properly', () => {
|
test('renders the media tracks properly', () => {
|
||||||
const tree = mount(connect())
|
const tree = render(connect())
|
||||||
const changes = tree.find('tr[data-testid="bcs__unsynced-item"]')
|
const changes = tree.container.querySelectorAll('tr[data-testid="bcs__unsynced-item"]')
|
||||||
equal(changes.length, 4)
|
expect(changes.length).toEqual(4)
|
||||||
const assetName = changes.findWhere(
|
const assetName = getAllByText(tree.container, 'media.mp4 (English)')
|
||||||
node =>
|
expect(assetName.length).toEqual(1)
|
||||||
node.name() === 'Text' &&
|
const assetType = getAllByText(tree.container, 'Caption')
|
||||||
node.text() === 'media.mp4 (English)' &&
|
expect(assetType.length).toEqual(1)
|
||||||
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)
|
|
||||||
})
|
})
|
|
@ -67,7 +67,7 @@ export default class LockBanner extends Component {
|
||||||
<Text weight="bold" size="small">
|
<Text weight="bold" size="small">
|
||||||
{I18n.t('Locked:')}
|
{I18n.t('Locked:')}
|
||||||
</Text>
|
</Text>
|
||||||
<Text size="small">{formatLockObject(this.props.itemLocks)}</Text>
|
<Text size="small" data-testid="lockedMessage">{formatLockObject(this.props.itemLocks)}</Text>
|
||||||
</Alert>
|
</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