Hook up MessageListContainer/Actions to GraphQL
fixes VICE-862 flag=react_inbox How to test 1. Load Canvas 2. Validate Canvas React Inbox FF is enabled 3. Open Conversation Application Expected: Should display new Canvas Inbox with only course and mailbox Test Cases Filter Messages by Course 1. Open Conversations Application 2. Select a course from course filter dropdown in upper left Expected: Should filter messages by course which are not visible in messageListHolder Change Mailboxes 1. Open Conversations Application 2. Select the mailbox dropdown that should say 'Inbox' 3. Pick another mailbox Expected: Should see new mailbox messages in the messageListHolder Change-Id: Ifc185cc0727c81be2566b3a788e4e7d9c25c7353 Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/256995 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Matthew Lemon <mlemon@instructure.com> QA-Review: Matthew Lemon <mlemon@instructure.com> Product-Review: Matthew Lemon <mlemon@instructure.com>
This commit is contained in:
parent
2d605454cc
commit
d0eb97ffdb
Binary file not shown.
|
@ -17,15 +17,21 @@
|
|||
*/
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
import {ConversationParticipantWithConversation} from '../graphqlData/ConversationParticipantWithConversation'
|
||||
import {ConversationParticipantWithConversation} from './graphqlData/ConversationParticipantWithConversation'
|
||||
import {Enrollments} from './graphqlData/Enrollments'
|
||||
import {FavoriteCoursesConnection} from './graphqlData/FavoriteCoursesConnection'
|
||||
import {FavoriteGroupsConnection} from './graphqlData/FavoriteGroupsConnection'
|
||||
|
||||
export const CONVERSATIONS_QUERY = gql`
|
||||
query GetConversationsQuery($userID: ID!) {
|
||||
query GetConversationsQuery($userID: ID!, $course: String, $scope: String = "") {
|
||||
legacyNode(_id: $userID, type: User) {
|
||||
... on User {
|
||||
_id
|
||||
id
|
||||
conversationsConnection {
|
||||
conversationsConnection(
|
||||
scope: $scope # e.g. archived
|
||||
filter: $course # e.g. course_1
|
||||
) {
|
||||
nodes {
|
||||
...ConversationParticipantWithConversation
|
||||
}
|
||||
|
@ -35,3 +41,29 @@ export const CONVERSATIONS_QUERY = gql`
|
|||
}
|
||||
${ConversationParticipantWithConversation.fragment}
|
||||
`
|
||||
export const COURSES_QUERY = gql`
|
||||
query GetUserCourses($userID: ID!) {
|
||||
legacyNode(_id: $userID, type: User) {
|
||||
... on User {
|
||||
id
|
||||
email
|
||||
favoriteGroupsConnection {
|
||||
nodes {
|
||||
...FavoriteGroupsConnection
|
||||
}
|
||||
}
|
||||
favoriteCoursesConnection {
|
||||
nodes {
|
||||
...FavoriteCoursesConnection
|
||||
}
|
||||
}
|
||||
enrollments {
|
||||
...Enrollments
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${Enrollments.fragment}
|
||||
${FavoriteCoursesConnection.fragment}
|
||||
${FavoriteGroupsConnection.fragment}
|
||||
`
|
||||
|
|
|
@ -24,64 +24,74 @@ import {ScreenReaderContent} from '@instructure/ui-a11y-content'
|
|||
import {Select} from '@instructure/ui-select'
|
||||
import I18n from 'i18n!conversations_2'
|
||||
|
||||
const filterOptions = (value, options) => {
|
||||
const filteredOptions = {}
|
||||
Object.keys(options).forEach(key => {
|
||||
filteredOptions[key] = options[key].filter(option =>
|
||||
option.contextName.toLowerCase().startsWith(value.toLowerCase())
|
||||
)
|
||||
})
|
||||
return filteredOptions
|
||||
}
|
||||
|
||||
export class CourseSelect extends React.Component {
|
||||
static propTypes = {
|
||||
mainPage: PropTypes.bool.isRequired,
|
||||
options: PropTypes.shape({
|
||||
favoriteCourses: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.number,
|
||||
_id: PropTypes.string,
|
||||
contextName: PropTypes.string,
|
||||
contextId: PropTypes.string
|
||||
assetString: PropTypes.string
|
||||
})
|
||||
),
|
||||
moreCourses: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.number,
|
||||
_id: PropTypes.string,
|
||||
contextName: PropTypes.string,
|
||||
contextId: PropTypes.string
|
||||
assetString: PropTypes.string
|
||||
})
|
||||
),
|
||||
concludedCourses: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.number,
|
||||
_id: PropTypes.string,
|
||||
contextName: PropTypes.string,
|
||||
contextId: PropTypes.string
|
||||
assetString: PropTypes.string
|
||||
})
|
||||
),
|
||||
groups: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
id: PropTypes.number,
|
||||
_id: PropTypes.string,
|
||||
contextName: PropTypes.string,
|
||||
contextId: PropTypes.string
|
||||
assetString: PropTypes.string
|
||||
})
|
||||
)
|
||||
}).isRequired,
|
||||
onCourseFilterSelect: PropTypes.func
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(props, state) {
|
||||
if (props.options !== state.options) {
|
||||
return {
|
||||
filteredOptions: filterOptions(state.inputValue, props.options)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
state = {
|
||||
inputValue: '',
|
||||
isShowingOptions: false,
|
||||
options: this.props.options,
|
||||
filteredOptions: this.props.options,
|
||||
highlightedOptionId: null,
|
||||
selectedOptionId: null,
|
||||
announcement: null
|
||||
}
|
||||
|
||||
filterOptions = value => {
|
||||
const filteredOptions = {}
|
||||
Object.keys(this.props.options).forEach(key => {
|
||||
filteredOptions[key] = this.props.options[key].filter(option =>
|
||||
option.contextName.toLowerCase().startsWith(value.toLowerCase())
|
||||
)
|
||||
})
|
||||
return filteredOptions
|
||||
}
|
||||
|
||||
getDefaultHighlightedOption = newOptions => {
|
||||
getDefaultHighlightedOption = (newOptions = []) => {
|
||||
const options = Object.values(newOptions).flat()
|
||||
return options.length > 0 ? options[0].contextId : null
|
||||
return options.length > 0 ? options[0].assetString : null
|
||||
}
|
||||
|
||||
getGroupChangedMessage = newOption => {
|
||||
|
@ -104,7 +114,7 @@ export class CourseSelect extends React.Component {
|
|||
if (!option) return
|
||||
return this.getGroupLabel(
|
||||
Object.keys(this.props.options).find(key =>
|
||||
this.props.options[key].find(({contextId}) => contextId === option.contextId)
|
||||
this.props.options[key].find(({assetString}) => assetString === option.assetString)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -112,7 +122,7 @@ export class CourseSelect extends React.Component {
|
|||
getOptionById = id => {
|
||||
return Object.values(this.props.options)
|
||||
.flat()
|
||||
.find(({contextId}) => id === contextId)
|
||||
.find(({assetString}) => id === assetString)
|
||||
}
|
||||
|
||||
handleBlur = () => {
|
||||
|
@ -147,7 +157,7 @@ export class CourseSelect extends React.Component {
|
|||
|
||||
handleInputChange = event => {
|
||||
const value = event.target.value
|
||||
const newOptions = this.filterOptions(value)
|
||||
const newOptions = filterOptions(value, this.props.options)
|
||||
this.setState(state => ({
|
||||
inputValue: value,
|
||||
filteredOptions: newOptions,
|
||||
|
@ -188,14 +198,14 @@ export class CourseSelect extends React.Component {
|
|||
const {highlightedOptionId, selectedOptionId} = this.state
|
||||
|
||||
return Object.keys(options).map(key => {
|
||||
return options[key].length > 0 ? (
|
||||
return options[key]?.length > 0 ? (
|
||||
<Select.Group key={key} renderLabel={this.getGroupLabel(key)}>
|
||||
{options[key].map(option => (
|
||||
<Select.Option
|
||||
id={option.contextId}
|
||||
key={option.contextId}
|
||||
isHighlighted={option.contextId === highlightedOptionId}
|
||||
isSelected={option.contextId === selectedOptionId}
|
||||
id={option.assetString}
|
||||
key={option.assetString}
|
||||
isHighlighted={option.assetString === highlightedOptionId}
|
||||
isSelected={option.assetString === selectedOptionId}
|
||||
>
|
||||
{option.contextName}
|
||||
</Select.Option>
|
||||
|
|
|
@ -28,23 +28,23 @@ const Template = args => <CourseSelect {...args} />
|
|||
|
||||
const options = {
|
||||
favoriteCourses: [
|
||||
{id: 1, contextName: 'Charms', contextId: 'course_1'},
|
||||
{id: 2, contextName: 'Transfiguration', contextId: 'course_2'}
|
||||
{_id: 1, contextName: 'Charms', assetString: 'course_1'},
|
||||
{_id: 2, contextName: 'Transfiguration', assetString: 'course_2'}
|
||||
],
|
||||
moreCourses: [
|
||||
{id: 3, contextName: 'Potions', contextId: 'course_3'},
|
||||
{id: 4, contextName: 'History of Magic', contextId: 'course_4'},
|
||||
{id: 5, contextName: 'Herbology', contextId: 'course_5'},
|
||||
{id: 6, contextName: 'Defense Against the Dark Arts', contextId: 'course_6'}
|
||||
{_id: 3, contextName: 'Potions', assetString: 'course_3'},
|
||||
{_id: 4, contextName: 'History of Magic', assetString: 'course_4'},
|
||||
{_id: 5, contextName: 'Herbology', assetString: 'course_5'},
|
||||
{_id: 6, contextName: 'Defense Against the Dark Arts', assetString: 'course_6'}
|
||||
],
|
||||
concludedCourses: [
|
||||
{id: 7, contextName: 'Muggle Studies', contextId: 'course_7'},
|
||||
{id: 8, contextName: 'Astronomy', contextId: 'course_8'}
|
||||
{_id: 7, contextName: 'Muggle Studies', assetString: 'course_7'},
|
||||
{_id: 8, contextName: 'Astronomy', assetString: 'course_8'}
|
||||
],
|
||||
groups: [
|
||||
{id: 1, contextName: 'Gryffindor Bros', contextId: 'group_1'},
|
||||
{id: 2, contextName: 'Quidditch', contextId: 'group_2'},
|
||||
{id: 3, contextName: "Dumbledore's Army", contextId: 'group_3'}
|
||||
{_id: 1, contextName: 'Gryffindor Bros', assetString: 'group_1'},
|
||||
{_id: 2, contextName: 'Quidditch', assetString: 'group_2'},
|
||||
{_id: 3, contextName: "Dumbledore's Army", assetString: 'group_3'}
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -25,23 +25,23 @@ const createProps = overrides => {
|
|||
mainPage: true,
|
||||
options: {
|
||||
favoriteCourses: [
|
||||
{id: 1, contextName: 'Charms', contextId: 'course_1'},
|
||||
{id: 2, contextName: 'Transfiguration', contextId: 'course_2'}
|
||||
{_id: 1, contextName: 'Charms', assetString: 'course_1'},
|
||||
{_id: 2, contextName: 'Transfiguration', assetString: 'course_2'}
|
||||
],
|
||||
moreCourses: [
|
||||
{id: 3, contextName: 'Potions', contextId: 'course_3'},
|
||||
{id: 4, contextName: 'History of Magic', contextId: 'course_4'},
|
||||
{id: 5, contextName: 'Herbology', contextId: 'course_5'},
|
||||
{id: 6, contextName: 'Defense Against the Dark Arts', contextId: 'course_6'}
|
||||
{_id: 3, contextName: 'Potions', assetString: 'course_3'},
|
||||
{_id: 4, contextName: 'History of Magic', assetString: 'course_4'},
|
||||
{_id: 5, contextName: 'Herbology', assetString: 'course_5'},
|
||||
{_id: 6, contextName: 'Defense Against the Dark Arts', assetString: 'course_6'}
|
||||
],
|
||||
concludedCourses: [
|
||||
{id: 7, contextName: 'Muggle Studies', contextId: 'course_7'},
|
||||
{id: 8, contextName: 'Astronomy', contextId: 'course_8'}
|
||||
{_id: 7, contextName: 'Muggle Studies', assetString: 'course_7'},
|
||||
{_id: 8, contextName: 'Astronomy', assetString: 'course_8'}
|
||||
],
|
||||
groups: [
|
||||
{id: 1, contextName: 'Gryffindor Bros', contextId: 'group_1'},
|
||||
{id: 2, contextName: 'Quidditch', contextId: 'group_2'},
|
||||
{id: 3, contextName: "Dumbledore's Army", contextId: 'group_3'}
|
||||
{_id: 1, contextName: 'Gryffindor Bros', assetString: 'group_1'},
|
||||
{_id: 2, contextName: 'Quidditch', assetString: 'group_2'},
|
||||
{_id: 3, contextName: "Dumbledore's Army", assetString: 'group_3'}
|
||||
]
|
||||
},
|
||||
onCourseFilterSelect: () => {},
|
||||
|
|
|
@ -17,24 +17,47 @@
|
|||
*/
|
||||
|
||||
import {Flex} from '@instructure/ui-flex'
|
||||
import React from 'react'
|
||||
import React, {useState} from 'react'
|
||||
import MessageListContainer from './MessageListContainer'
|
||||
import MessageListActionContainer from './MessageListActionContainer'
|
||||
|
||||
const CanvasInbox = () => {
|
||||
const [scope, setScope] = useState('inbox')
|
||||
const [courseFilter, setCourseFilter] = useState()
|
||||
const [selectedIds, setSelectedIds] = useState([])
|
||||
|
||||
const toggleSelectedMessages = conversation => {
|
||||
const updatedSelectedIds = selectedIds
|
||||
if (updatedSelectedIds.includes(conversation._id)) {
|
||||
const index = updatedSelectedIds.indexOf(conversation._id)
|
||||
updatedSelectedIds.splice(index, 1)
|
||||
} else {
|
||||
updatedSelectedIds.push(conversation._id)
|
||||
}
|
||||
setSelectedIds(updatedSelectedIds)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="canvas-inbox-container">
|
||||
<Flex height="100vh" width="100%" as="div" direction="column">
|
||||
<Flex.Item>
|
||||
<MessageListActionContainer />
|
||||
<MessageListActionContainer
|
||||
onSelectMailbox={setScope}
|
||||
onCourseFilterSelect={setCourseFilter}
|
||||
selectdIds={selectedIds}
|
||||
/>
|
||||
</Flex.Item>
|
||||
<Flex.Item shouldGrow shouldShrink>
|
||||
<Flex height="100%" as="div" align="center" justifyItems="center">
|
||||
<Flex.Item width="400px" height="100%">
|
||||
<MessageListContainer />
|
||||
<MessageListContainer
|
||||
course={courseFilter}
|
||||
scope={scope}
|
||||
onSelectMessage={toggleSelectedMessages}
|
||||
/>
|
||||
</Flex.Item>
|
||||
<Flex.Item shouldGrow shouldShrink height="100%">
|
||||
{/* Message Content Goes Here */}
|
||||
<div className="testing-class-name-canvas-inbox">Message Content Goes Here</div>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Flex.Item>
|
||||
|
|
|
@ -16,15 +16,63 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {AlertManagerContext} from 'jsx/shared/components/AlertManager'
|
||||
import {COURSES_QUERY} from '../Queries'
|
||||
import {CourseSelect} from '../components/CourseSelect/CourseSelect'
|
||||
import {Flex} from '@instructure/ui-flex'
|
||||
import I18n from 'i18n!conversations_2'
|
||||
import {MailboxSelectionDropdown} from '../components/MailboxSelectionDropdown/MailboxSelectionDropdown'
|
||||
import {MessageActionButtons} from '../components/MessageActionButtons/MessageActionButtons'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import {useQuery} from 'react-apollo'
|
||||
import React, {useContext} from 'react'
|
||||
import {View} from '@instructure/ui-view'
|
||||
|
||||
const MessageListActionContainer = props => {
|
||||
const {setOnFailure} = useContext(AlertManagerContext)
|
||||
const userID = ENV.current_user_id?.toString()
|
||||
|
||||
const {loading, error, data} = useQuery(COURSES_QUERY, {
|
||||
variables: {userID}
|
||||
})
|
||||
|
||||
const reduceDuplicateCourses = (enrollments, favoriteCourses) => {
|
||||
if (!enrollments || !favoriteCourses) {
|
||||
return []
|
||||
}
|
||||
return enrollments
|
||||
.map(c => {
|
||||
return {
|
||||
id: c.course.id,
|
||||
contextName: c.course.contextName,
|
||||
assetString: c.course.assetString
|
||||
}
|
||||
})
|
||||
.filter(c => {
|
||||
let isMatch
|
||||
for (let i = 0; i < favoriteCourses.length; i++) {
|
||||
isMatch = favoriteCourses[i].assetString === c.assetString
|
||||
if (isMatch === true) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return !isMatch
|
||||
})
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return <span />
|
||||
}
|
||||
|
||||
if (error) {
|
||||
setOnFailure(I18n.t('Unable to load courses menu.'))
|
||||
}
|
||||
|
||||
const moreCourses = reduceDuplicateCourses(
|
||||
data?.legacyNode?.enrollments,
|
||||
data?.legacyNode?.favoriteCoursesConnection?.nodes
|
||||
)
|
||||
|
||||
return (
|
||||
<View
|
||||
as="div"
|
||||
|
@ -36,15 +84,35 @@ const MessageListActionContainer = props => {
|
|||
>
|
||||
<Flex wrap="wrap">
|
||||
<Flex.Item>
|
||||
{/* // TODO: Wire up course select with container story */}
|
||||
<CourseSelect options={[]} onCourseFilterSelect={props.onCourseFilterSelect} />
|
||||
<CourseSelect
|
||||
mainPage
|
||||
options={{
|
||||
favoriteCourses: data?.legacyNode?.favoriteCoursesConnection?.nodes,
|
||||
moreCourses,
|
||||
concludedCourses: [],
|
||||
groups: data?.legacyNode?.favoriteGroupsConnection?.nodes
|
||||
}}
|
||||
onCourseFilterSelect={props.onCourseFilterSelect}
|
||||
/>
|
||||
</Flex.Item>
|
||||
<Flex.Item padding="none none none xxx-small">
|
||||
<MailboxSelectionDropdown onSelect={props.onSelectMailbox} />
|
||||
<MailboxSelectionDropdown
|
||||
activeMailbox={props.activeMailbox}
|
||||
onSelect={props.onSelectMailbox}
|
||||
/>
|
||||
</Flex.Item>
|
||||
<Flex.Item shouldGrow shouldShrink />
|
||||
<Flex.Item>
|
||||
<MessageActionButtons />
|
||||
<MessageActionButtons
|
||||
archive={() => {}}
|
||||
compose={() => {}}
|
||||
delete={() => {}}
|
||||
forward={() => {}}
|
||||
markAsUnread={() => {}}
|
||||
reply={() => {}}
|
||||
replyAll={() => {}}
|
||||
star={() => {}}
|
||||
/>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</View>
|
||||
|
@ -54,6 +122,7 @@ const MessageListActionContainer = props => {
|
|||
export default MessageListActionContainer
|
||||
|
||||
MessageListActionContainer.propTypes = {
|
||||
activeMailbox: PropTypes.string,
|
||||
onCourseFilterSelect: PropTypes.func,
|
||||
onSelectMailbox: PropTypes.func
|
||||
}
|
||||
|
|
|
@ -16,14 +16,42 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {AlertManagerContext} from 'jsx/shared/components/AlertManager'
|
||||
import {CONVERSATIONS_QUERY} from '../Queries'
|
||||
import {MessageListHolder} from '../components/MessageListHolder/MessageListHolder'
|
||||
import I18n from 'i18n!conversations_2'
|
||||
import {Mask} from '@instructure/ui-overlays'
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import React, {useContext} from 'react'
|
||||
import {Spinner} from '@instructure/ui-spinner'
|
||||
import {useQuery} from 'react-apollo'
|
||||
import {View} from '@instructure/ui-view'
|
||||
|
||||
const MessageListContainer = ({course, scope, onSelectMessage}) => {
|
||||
const {setOnFailure} = useContext(AlertManagerContext)
|
||||
const userID = ENV.current_user_id?.toString()
|
||||
|
||||
const {loading, error, data} = useQuery(CONVERSATIONS_QUERY, {
|
||||
variables: {userID, scope, course}
|
||||
})
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<View as="div" style={{position: 'relative'}} height="100%">
|
||||
<Mask>
|
||||
<Spinner renderTitle={() => I18n.t('Loading Message List')} variant="inverse" />
|
||||
</Mask>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
if (error) {
|
||||
setOnFailure(I18n.t('Unable to load messages. '))
|
||||
}
|
||||
|
||||
const MessageListContainer = ({onSelectMessage}) => {
|
||||
return (
|
||||
<MessageListHolder
|
||||
conversations={null}
|
||||
conversations={data?.legacyNode?.conversationsConnection?.nodes}
|
||||
onOpen={() => {}}
|
||||
onSelect={onSelectMessage}
|
||||
onStar={() => {}}
|
||||
|
@ -34,9 +62,12 @@ const MessageListContainer = ({onSelectMessage}) => {
|
|||
export default MessageListContainer
|
||||
|
||||
MessageListContainer.propTypes = {
|
||||
course: PropTypes.string,
|
||||
scope: PropTypes.string,
|
||||
onSelectMessage: PropTypes.func
|
||||
}
|
||||
|
||||
MessageListContainer.defaultProps = {
|
||||
scope: 'inbox',
|
||||
onSelectMessage: () => {}
|
||||
}
|
||||
|
|
|
@ -16,15 +16,71 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {AlertManagerContext} from '../../../shared/components/AlertManager'
|
||||
import CanvasInbox from '../CanvasInbox'
|
||||
import {createCache} from '../../../canvas-apollo'
|
||||
import {CONVERSATIONS_QUERY} from '../../Queries'
|
||||
import {MockedProvider} from '@apollo/react-testing'
|
||||
import React from 'react'
|
||||
import {render} from '@testing-library/react'
|
||||
import {mockQuery} from '../../mocks'
|
||||
import waitForApolloLoading from '../../helpers/waitForApolloLoading'
|
||||
|
||||
const createGraphqlMocks = () => {
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: CONVERSATIONS_QUERY,
|
||||
variables: {
|
||||
userID: '1',
|
||||
scope: 'inbox'
|
||||
},
|
||||
overrides: {
|
||||
Node: {
|
||||
__typename: 'User'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const mockResults = Promise.all(
|
||||
mocks.map(async m => {
|
||||
const result = await mockQuery(m.request.query, m.request.overrides, m.request.variables)
|
||||
return {
|
||||
request: {query: m.request.query, variables: m.request.variables},
|
||||
result
|
||||
}
|
||||
})
|
||||
)
|
||||
return mockResults
|
||||
}
|
||||
|
||||
const setup = async () => {
|
||||
const mocks = await createGraphqlMocks()
|
||||
return render(
|
||||
<AlertManagerContext.Provider value={{setOnFailure: jest.fn(), setOnSuccess: jest.fn()}}>
|
||||
<MockedProvider mocks={mocks} cache={createCache()}>
|
||||
<CanvasInbox />
|
||||
</MockedProvider>
|
||||
</AlertManagerContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
describe('CanvasInbox App Container', () => {
|
||||
beforeEach(() => {
|
||||
window.ENV = {
|
||||
current_user_id: 1
|
||||
}
|
||||
})
|
||||
|
||||
describe('rendering', () => {
|
||||
it('should render', () => {
|
||||
const component = render(<CanvasInbox />)
|
||||
expect(component).toBeTruthy()
|
||||
it('should render <CanvasInbox />', async () => {
|
||||
const component = await setup()
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
expect(await component).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - 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 MessageListActionContainer from '../MessageListActionContainer'
|
||||
import {createCache} from '../../../canvas-apollo'
|
||||
import {COURSES_QUERY} from '../../Queries'
|
||||
import {MockedProvider} from '@apollo/react-testing'
|
||||
import React from 'react'
|
||||
import {render, fireEvent} from '@testing-library/react'
|
||||
import {mockQuery} from '../../mocks'
|
||||
import waitForApolloLoading from '../../helpers/waitForApolloLoading'
|
||||
|
||||
const createGraphqlMocks = () => {
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: COURSES_QUERY,
|
||||
variables: {
|
||||
userID: '1'
|
||||
},
|
||||
overrides: {
|
||||
Node: {
|
||||
__typename: 'User'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const mockResults = Promise.all(
|
||||
mocks.map(async m => {
|
||||
const result = await mockQuery(m.request.query, m.request.overrides, m.request.variables)
|
||||
return {
|
||||
request: {query: m.request.query, variables: m.request.variables},
|
||||
result
|
||||
}
|
||||
})
|
||||
)
|
||||
return mockResults
|
||||
}
|
||||
|
||||
const setup = async overrideProps => {
|
||||
const mocks = await createGraphqlMocks()
|
||||
return render(
|
||||
<MockedProvider mocks={mocks} cache={createCache()}>
|
||||
<MessageListActionContainer {...overrideProps} />
|
||||
</MockedProvider>
|
||||
)
|
||||
}
|
||||
|
||||
describe('MessageListActionContainer', () => {
|
||||
beforeEach(() => {
|
||||
window.ENV = {
|
||||
current_user_id: 1
|
||||
}
|
||||
})
|
||||
|
||||
describe('rendering', () => {
|
||||
it('should render', async () => {
|
||||
const component = await setup()
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
expect(component.container).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should call onCourseFilterSelect when course selected ', async () => {
|
||||
const mock = jest.fn()
|
||||
|
||||
const component = await setup({
|
||||
onCourseFilterSelect: mock
|
||||
})
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
const courseDropdown = await component.getByTestId('courseSelect')
|
||||
|
||||
fireEvent.click(courseDropdown)
|
||||
await waitForApolloLoading()
|
||||
|
||||
const options = await component.queryAllByText('Hello World')
|
||||
|
||||
expect(options.length).toBe(6)
|
||||
|
||||
fireEvent.click(options[1])
|
||||
|
||||
expect(mock.mock.calls.length).toBe(1)
|
||||
})
|
||||
|
||||
it('should callback to update mailbox when event fires', async () => {
|
||||
const mock = jest.fn()
|
||||
|
||||
const component = await setup({
|
||||
onSelectMailbox: mock
|
||||
})
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
const mailboxDropdown = await component.findByLabelText('Mailbox Selection')
|
||||
|
||||
fireEvent.click(mailboxDropdown)
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
const option = await component.findByText('Sent')
|
||||
|
||||
expect(option).toBeTruthy()
|
||||
|
||||
fireEvent.click(option)
|
||||
|
||||
expect(mock.mock.calls.length).toBe(1)
|
||||
})
|
||||
|
||||
it('should call onSelectMailbox when mailbox changed', async () => {
|
||||
const mock = jest.fn()
|
||||
|
||||
const component = await setup({
|
||||
onSelectMailbox: mock
|
||||
})
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
const mailboxDropdown = await component.findByLabelText('Mailbox Selection')
|
||||
|
||||
fireEvent.click(mailboxDropdown)
|
||||
await waitForApolloLoading()
|
||||
|
||||
const option = await component.findByText('Sent')
|
||||
|
||||
expect(option).toBeTruthy()
|
||||
|
||||
fireEvent.click(option)
|
||||
|
||||
expect(mock.mock.calls.length).toBe(1)
|
||||
})
|
||||
|
||||
it('should load with selected mailbox set via props', async () => {
|
||||
const component = await setup({
|
||||
activeMailbox: 'sent'
|
||||
})
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
const mailboxDropdown = await component.findByDisplayValue('Sent')
|
||||
|
||||
expect(mailboxDropdown).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - 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 MessageListContainer from '../MessageListContainer'
|
||||
import {createCache} from '../../../canvas-apollo'
|
||||
import {CONVERSATIONS_QUERY} from '../../Queries'
|
||||
import {MockedProvider} from '@apollo/react-testing'
|
||||
import React from 'react'
|
||||
import {render, fireEvent} from '@testing-library/react'
|
||||
import {mockQuery} from '../../mocks'
|
||||
import waitForApolloLoading from '../../helpers/waitForApolloLoading'
|
||||
|
||||
const createGraphqlMocks = () => {
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: CONVERSATIONS_QUERY,
|
||||
variables: {
|
||||
userID: '1',
|
||||
scope: 'inbox'
|
||||
},
|
||||
overrides: {
|
||||
Node: {
|
||||
__typename: 'User'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
request: {
|
||||
query: CONVERSATIONS_QUERY,
|
||||
variables: {
|
||||
userID: '1',
|
||||
scope: 'inbox',
|
||||
course: 'course_123'
|
||||
},
|
||||
overrides: {
|
||||
Node: {
|
||||
__typename: 'User'
|
||||
},
|
||||
Conversation: () => ({
|
||||
_id: '1a',
|
||||
contextType: 'context',
|
||||
contextId: 2,
|
||||
subject: 'Second Subject',
|
||||
updateAt: new Date(),
|
||||
conversationMessageConnections: [{}],
|
||||
conversationParticipantsConnection: [{}]
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
request: {
|
||||
query: CONVERSATIONS_QUERY,
|
||||
variables: {
|
||||
userID: '1',
|
||||
scope: 'sent'
|
||||
},
|
||||
overrides: {
|
||||
Node: {
|
||||
__typename: 'User'
|
||||
},
|
||||
Conversation: () => ({
|
||||
_id: '1a',
|
||||
contextType: 'context',
|
||||
contextId: 2,
|
||||
subject: 'Second Subject',
|
||||
updateAt: new Date(),
|
||||
conversationMessageConnections: [{}],
|
||||
conversationParticipantsConnection: [{}]
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const mockResults = Promise.all(
|
||||
mocks.map(async m => {
|
||||
const result = await mockQuery(m.request.query, m.request.overrides, m.request.variables)
|
||||
return {
|
||||
request: {query: m.request.query, variables: m.request.variables},
|
||||
result
|
||||
}
|
||||
})
|
||||
)
|
||||
return mockResults
|
||||
}
|
||||
|
||||
const setup = async messageListContainerProps => {
|
||||
const mocks = await createGraphqlMocks()
|
||||
return render(
|
||||
<MockedProvider mocks={mocks} cache={createCache()}>
|
||||
<MessageListContainer {...messageListContainerProps} />
|
||||
</MockedProvider>
|
||||
)
|
||||
}
|
||||
|
||||
describe('MessageListContainer', () => {
|
||||
beforeEach(() => {
|
||||
window.ENV = {
|
||||
current_user_id: 1
|
||||
}
|
||||
})
|
||||
|
||||
describe('converation_query', () => {
|
||||
it('should render query when successful', async () => {
|
||||
const component = await setup()
|
||||
expect(component).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should change list of messages when scope changes', async () => {
|
||||
const component = await setup()
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
let messages = await component.queryAllByText('Mock Subject')
|
||||
expect(messages.length).toBe(2)
|
||||
|
||||
component.rerender(
|
||||
<MockedProvider mocks={await createGraphqlMocks()}>
|
||||
<MessageListContainer scope="sent" />
|
||||
</MockedProvider>
|
||||
)
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
messages = await component.queryByText('Mock Subject')
|
||||
expect(messages).toBeNull()
|
||||
})
|
||||
|
||||
it('should change list of messaes when course and scope changes', async () => {
|
||||
const component = await setup()
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
let messages = await component.queryAllByText('Mock Subject')
|
||||
expect(messages.length).toBe(2)
|
||||
|
||||
component.rerender(
|
||||
<MockedProvider mocks={await createGraphqlMocks()}>
|
||||
<MessageListContainer course="course_123" />
|
||||
</MockedProvider>
|
||||
)
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
messages = await component.queryByText('Mock Subject')
|
||||
expect(messages).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Selected Messages', () => {
|
||||
it('should track when messages are clicked', async () => {
|
||||
const mock = jest.fn()
|
||||
const messageList = await setup({
|
||||
onSelectMessage: mock
|
||||
})
|
||||
|
||||
await waitForApolloLoading()
|
||||
|
||||
const checkboxes = await messageList.findAllByText('not selected')
|
||||
|
||||
fireEvent(
|
||||
checkboxes[0],
|
||||
new MouseEvent('click', {
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
})
|
||||
)
|
||||
|
||||
expect(mock.mock.calls.length).toBe(1)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -41,7 +41,7 @@ export const Attachment = {
|
|||
}
|
||||
|
||||
export const DefaultMocks = {
|
||||
Attachment: () => ({
|
||||
File: () => ({
|
||||
displayName: 'testing.csv',
|
||||
mimeClass: 'file'
|
||||
})
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
import gql from 'graphql-tag'
|
||||
import {shape, string} from 'prop-types'
|
||||
import {number, shape, string} from 'prop-types'
|
||||
import {ConversationMessage} from './ConversationMessage'
|
||||
import {ConversationParticipant} from './ConversationParticipant'
|
||||
|
||||
|
@ -45,10 +45,22 @@ export const Conversation = {
|
|||
|
||||
shape: shape({
|
||||
_id: string,
|
||||
contextId: string,
|
||||
contextId: number,
|
||||
contextType: string,
|
||||
subject: string,
|
||||
conversationMessagesConnection: ConversationMessage.shape,
|
||||
conversationParticipantsConnection: ConversationParticipant.shape
|
||||
})
|
||||
}
|
||||
|
||||
export const DefaultMocks = {
|
||||
Conversation: () => ({
|
||||
_id: '1a',
|
||||
contextType: 'context',
|
||||
contextId: 2,
|
||||
subject: 'Mock Subject',
|
||||
updatedAt: 'November 5, 2020 at 2:25pm',
|
||||
conversationMessagesConnection: {edges: [{}]},
|
||||
conversationParticipantsConnection: {edges: [{}]}
|
||||
})
|
||||
}
|
|
@ -26,6 +26,7 @@ export const ConversationMessage = {
|
|||
fragment: gql`
|
||||
fragment ConversationMessage on ConversationMessage {
|
||||
_id
|
||||
id
|
||||
createdAt
|
||||
body
|
||||
attachmentsConnection {
|
||||
|
@ -54,3 +55,15 @@ export const ConversationMessage = {
|
|||
mediaComment: MediaComment.shape
|
||||
})
|
||||
}
|
||||
|
||||
export const DefaultMocks = {
|
||||
ConversationMessage: () => ({
|
||||
_id: '1a',
|
||||
conversationId: 'mockConversation',
|
||||
body: 'This is the body of a mocked message',
|
||||
createdAt: 'November 5, 2020 at 2:25pm',
|
||||
author: {},
|
||||
mediaComment: {},
|
||||
attachmentConnection: [{}]
|
||||
})
|
||||
}
|
|
@ -29,6 +29,7 @@ export const ConversationParticipant = {
|
|||
user {
|
||||
...User
|
||||
}
|
||||
workflowState
|
||||
}
|
||||
${User.fragment}
|
||||
`,
|
||||
|
@ -40,3 +41,14 @@ export const ConversationParticipant = {
|
|||
user: User.shape
|
||||
})
|
||||
}
|
||||
|
||||
export const DefaultMocks = {
|
||||
ConversationParticipant: () => ({
|
||||
_id: '1a',
|
||||
user_id: 'mockUserId',
|
||||
workflowState: 'unread',
|
||||
label: 'starred',
|
||||
subscribed: false,
|
||||
updatedAt: 'November 5, 2020 at 2:25pm'
|
||||
})
|
||||
}
|
|
@ -41,3 +41,13 @@ export const ConversationParticipantWithConversation = {
|
|||
user: User.shape
|
||||
})
|
||||
}
|
||||
|
||||
export const DefaultMocks = {
|
||||
ConversationParticipant: () => ({
|
||||
_id: 'mock_id',
|
||||
id: 'mockId',
|
||||
label: 'someLabel',
|
||||
conversation: {},
|
||||
user: {}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - 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 gql from 'graphql-tag'
|
||||
import {shape, string} from 'prop-types'
|
||||
|
||||
export const Enrollments = {
|
||||
fragment: gql`
|
||||
fragment Enrollments on Enrollment {
|
||||
type
|
||||
course {
|
||||
_id
|
||||
contextName: name
|
||||
assetString
|
||||
}
|
||||
}
|
||||
`,
|
||||
shape: shape({
|
||||
id: string,
|
||||
contextName: string,
|
||||
assetString: string
|
||||
})
|
||||
}
|
||||
|
||||
export const DefaultMocks = {
|
||||
Enrollment: () => ({
|
||||
course: {
|
||||
_id: '1',
|
||||
contextName: 'contextName',
|
||||
assetString: 'contextId'
|
||||
}
|
||||
})
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - 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 gql from 'graphql-tag'
|
||||
import {shape, string} from 'prop-types'
|
||||
|
||||
export const FavoriteCoursesConnection = {
|
||||
fragment: gql`
|
||||
fragment FavoriteCoursesConnection on Course {
|
||||
_id
|
||||
contextName: name
|
||||
assetString
|
||||
}
|
||||
`,
|
||||
shape: shape({
|
||||
id: string,
|
||||
contextName: string,
|
||||
assetString: string
|
||||
})
|
||||
}
|
||||
|
||||
export const DefaultMocks = {
|
||||
Course: () => ({
|
||||
id: 'someId',
|
||||
contextName: 'someString',
|
||||
assetString: 'someId'
|
||||
})
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - 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 gql from 'graphql-tag'
|
||||
import {shape, string} from 'prop-types'
|
||||
|
||||
export const FavoriteGroupsConnection = {
|
||||
fragment: gql`
|
||||
fragment FavoriteGroupsConnection on Group {
|
||||
_id
|
||||
contextName: name
|
||||
assetString
|
||||
}
|
||||
`,
|
||||
shape: shape({
|
||||
id: string,
|
||||
contextName: string,
|
||||
assetString: string
|
||||
})
|
||||
}
|
||||
|
||||
export const DefaultMocks = {
|
||||
Group: () => ({
|
||||
id: 'someId',
|
||||
contextName: 'someContextName',
|
||||
assetString: 'someContextId'
|
||||
})
|
||||
}
|
|
@ -49,7 +49,7 @@ export const MediaComment = {
|
|||
}
|
||||
|
||||
export const DefaultMocks = {
|
||||
MediaComment: () => ({
|
||||
MediaObject: () => ({
|
||||
title: 'Test Media Comment Video',
|
||||
canAddCaptions: true
|
||||
})
|
|
@ -35,3 +35,13 @@ export const MediaTrack = {
|
|||
kind: string
|
||||
})
|
||||
}
|
||||
|
||||
export const DefaultMocks = {
|
||||
MediaTrack: () => ({
|
||||
kind: 'kindString',
|
||||
local: 'en-us',
|
||||
content: 'mockContent',
|
||||
mediaObject: {},
|
||||
webvttContent: 'webvttContent'
|
||||
})
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - 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 async () => {
|
||||
await new Promise(resolve => setTimeout(resolve, 0))
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (C) 2021 - 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 glob from 'glob'
|
||||
|
||||
import mockGraphqlQuery from '../shared/graphql_query_mock'
|
||||
|
||||
let _dynamicDefaultMockImports = null
|
||||
const loadDefaultMocks = async () => {
|
||||
if (_dynamicDefaultMockImports !== null) {
|
||||
return _dynamicDefaultMockImports
|
||||
}
|
||||
|
||||
const filesToImport = glob.sync('./graphqlData/**.js', {cwd: './app/jsx/canvas_inbox'})
|
||||
const defaultMocks = await Promise.all(
|
||||
filesToImport.map(async file => {
|
||||
const fileImport = await import(file)
|
||||
return fileImport.DefaultMocks || {}
|
||||
})
|
||||
)
|
||||
_dynamicDefaultMockImports = defaultMocks.filter(m => m !== undefined)
|
||||
return _dynamicDefaultMockImports
|
||||
}
|
||||
|
||||
export async function mockQuery(queryAST, overrides = [], variables = {}) {
|
||||
if (!Array.isArray(overrides)) {
|
||||
overrides = [overrides]
|
||||
}
|
||||
const defaultOverrides = await loadDefaultMocks()
|
||||
const allOverrides = [...defaultOverrides, ...overrides]
|
||||
return mockGraphqlQuery(queryAST, allOverrides, variables)
|
||||
}
|
|
@ -1,6 +1,21 @@
|
|||
{
|
||||
"__schema": {
|
||||
"types": [
|
||||
{
|
||||
"kind": "INTERFACE",
|
||||
"name": "AssetString",
|
||||
"possibleTypes": [
|
||||
{
|
||||
"name": "Course"
|
||||
},
|
||||
{
|
||||
"name": "Enrollment"
|
||||
},
|
||||
{
|
||||
"name": "Group"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "UNION",
|
||||
"name": "AssignmentOverrideSet",
|
||||
|
@ -392,15 +407,6 @@
|
|||
{
|
||||
"name": "ContentTag"
|
||||
},
|
||||
{
|
||||
"name": "Conversation"
|
||||
},
|
||||
{
|
||||
"name": "ConversationMessage"
|
||||
},
|
||||
{
|
||||
"name": "ConversationParticipant"
|
||||
},
|
||||
{
|
||||
"name": "Course"
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue