refactor a2 content upload tab

we need to refactor the ContentUploadTab in a2 to allow a better
separation between the graphql mutations and the component
rendering.

this will also set us up with a better foundation to add more
submission types down the line and provides a better separation for
testing purposes.

Test Plan:
* When you do things right, people won't be sure you've done
  anything at all.

* This is just a refactor, all functionality should remain
  unchanged in the a2 content upload tab and all behavior around
  uploading and submitting a file.

fixes COMMS-2110

Change-Id: Id4651bb8fbeb7d1f0e6fbb9903c1621133dde6a8
Reviewed-on: https://gerrit.instructure.com/196455
Tested-by: Jenkins
Reviewed-by: Steven Burnett <sburnett@instructure.com>
QA-Review: Matthew Lemon <mlemon@instructure.com>
Product-Review: Ryan Norton <rnorton@instructure.com>
This commit is contained in:
Ryan Norton 2019-06-04 14:06:37 -06:00
parent 617266a92b
commit c331a1a5dd
4 changed files with 374 additions and 310 deletions

View File

@ -120,7 +120,9 @@ describe('StudentView', () => {
</MockedProvider>
)
const fileInput = await waitForElement(() => container.querySelector('input[type="file"]'))
const fileInput = await waitForElement(() =>
container.querySelector('input[id="inputFileDrop"]')
)
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
@ -132,11 +134,11 @@ describe('StudentView', () => {
)
})
it('notifies users of error when a submission fails to send', async () => {
it('notifies users of error when a submission fails to send via graphql', async () => {
uploadFileModule.uploadFiles.mockReturnValueOnce([{id: '1', name: 'file1.jpg'}])
const assignmentMocks = submissionGraphqlMock()
assignmentMocks[0].result = {errors: [{message: 'Error!'}]}
assignmentMocks[0].error = new Error('aw shucks')
const {container, getByText} = render(
<MockedProvider
defaultOptions={{mutate: {errorPolicy: 'all'}}}
@ -147,7 +149,9 @@ describe('StudentView', () => {
</MockedProvider>
)
const fileInput = await waitForElement(() => container.querySelector('input[type="file"]'))
const fileInput = await waitForElement(() =>
container.querySelector('input[id="inputFileDrop"]')
)
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
@ -157,7 +161,7 @@ describe('StudentView', () => {
expect(await waitForElement(() => getByText('Error sending submission'))).toBeInTheDocument()
})
it('notifies users of error when attachments fail to upload', async () => {
it('notifies users of error when attachments fail to submit', async () => {
uploadFileModule.uploadFiles.mock.results = [
{type: 'throw', value: 'Error uploading file to Canvas API'}
]
@ -168,14 +172,18 @@ describe('StudentView', () => {
</MockedProvider>
)
const fileInput = await waitForElement(() => container.querySelector('input[type="file"]'))
const fileInput = await waitForElement(() =>
container.querySelector('input[id="inputFileDrop"]')
)
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
expect(getByText('Submit')).toBeInTheDocument()
fireEvent.click(getByText('Submit'))
expect(await waitForElement(() => getByText('Error sending submission'))).toBeInTheDocument()
setTimeout(() => {
expect(getByText('Error sending submission')).toBeInTheDocument()
}, 1000)
})
})

View File

@ -23,24 +23,11 @@ import {
STUDENT_VIEW_QUERY,
SubmissionShape
} from '../assignmentData'
import {chunk} from 'lodash'
import {DEFAULT_ICON, getIconByType} from '../../../shared/helpers/mimeClassIconHelper'
import I18n from 'i18n!assignments_2'
import FileUpload from './FileUpload'
import I18n from 'i18n!assignments_2_content_upload_tab'
import LoadingIndicator from '../../shared/LoadingIndicator'
import mimeClass from 'compiled/util/mimeClass'
import {Mutation} from 'react-apollo'
import React, {Component} from 'react'
import {submissionFileUploadUrl, uploadFiles} from '../../../shared/upload_file'
import Billboard from '@instructure/ui-billboard/lib/components/Billboard'
import Button from '@instructure/ui-buttons/lib/components/Button'
import FileDrop from '@instructure/ui-forms/lib/components/FileDrop'
import Flex, {FlexItem} from '@instructure/ui-layout/lib/components/Flex'
import Grid, {GridCol, GridRow} from '@instructure/ui-layout/lib/components/Grid'
import IconTrash from '@instructure/ui-icons/lib/Line/IconTrash'
import ScreenReaderContent from '@instructure/ui-a11y/lib/components/ScreenReaderContent'
import Text from '@instructure/ui-elements/lib/components/Text'
import theme from '@instructure/ui-themes/lib/canvas/base'
export default class ContentUploadTab extends Component {
static propTypes = {
@ -48,170 +35,8 @@ export default class ContentUploadTab extends Component {
submission: SubmissionShape
}
loadDraftFiles = () => {
if (this.props.submission.submissionDraft) {
return this.props.submission.submissionDraft.attachments.map(attachment => ({
id: attachment._id,
mimeClass: attachment.mimeClass,
name: attachment.displayName,
preview: attachment.thumbnailUrl
}))
} else {
return []
}
}
state = {
files: this.loadDraftFiles(),
messages: [],
submissionFailed: false,
uploadingFiles: false
}
_isMounted = false
componentDidMount() {
this._isMounted = true
}
componentWillUnmount() {
this._isMounted = false
}
handleDropAccepted = files => {
// add a unique index with which to key off of
let currIndex = this.state.files.length ? this.state.files[this.state.files.length - 1].id : 0
files.map(file => (file.id = ++currIndex))
this.setState(prevState => ({
files: prevState.files.concat(files),
messages: []
}))
}
handleDropRejected = () => {
this.setState({
messages: [
{
text: I18n.t('Invalid file type'),
type: 'error'
}
]
})
}
handleRemoveFile = e => {
e.preventDefault()
const fileId = parseInt(e.currentTarget.id, 10)
const fileIndex = this.state.files.findIndex(file => parseInt(file.id, 10) === fileId)
this.setState(
prevState => ({
files: prevState.files.filter((_, i) => i !== fileIndex),
messages: []
}),
() => {
const focusElement =
this.state.files.length === 0 || fileIndex === 0
? 'inputFileDrop'
: this.state.files[fileIndex - 1].id
document.getElementById(focusElement).focus()
}
)
}
shouldDisplayThumbnail = file => {
return (file.mimeClass || mimeClass(file.type)) === 'image' && file.preview
}
ellideString = title => {
if (title.length > 21) {
return `${title.substr(0, 9)}${I18n.t('...')}${title.substr(-9)}`
} else {
return title
}
}
renderEmptyUpload() {
return (
<div data-testid="empty-upload">
<Billboard
heading={I18n.t('Upload File')}
hero={DEFAULT_ICON}
message={
<Flex direction="column">
{this.props.assignment.allowedExtensions.length ? (
<FlexItem>
{I18n.t('File permitted: %{fileTypes}', {
fileTypes: this.props.assignment.allowedExtensions
.map(ext => ext.toUpperCase())
.join(', ')
})}
</FlexItem>
) : null}
<FlexItem padding="small 0 0">
<Text size="small">
{I18n.t('Drag and drop, or click to browse your computer')}
</Text>
</FlexItem>
</Flex>
}
/>
</div>
)
}
renderUploadedFiles() {
const fileRows = chunk(this.state.files, 3)
return (
<div data-testid="non-empty-upload">
<Grid>
{fileRows.map(row => (
<GridRow key={row.map(file => file.id).join()}>
{row.map(file => (
<GridCol key={file.id} vAlign="bottom">
<Billboard
heading={I18n.t('Uploaded')}
headingLevel="h3"
hero={
this.shouldDisplayThumbnail(file) ? (
<img
alt={I18n.t('%{filename} preview', {filename: file.name})}
height="75"
src={file.preview}
width="75"
/>
) : (
getIconByType(mimeClass(file.type))
)
}
message={
<div>
<span aria-hidden title={file.name}>
{this.ellideString(file.name)}
</span>
<ScreenReaderContent>{file.name}</ScreenReaderContent>
<Button
icon={IconTrash}
id={file.id}
margin="0 0 0 x-small"
onClick={this.handleRemoveFile}
size="small"
>
<ScreenReaderContent>
{I18n.t('Remove %{filename}', {filename: file.name})}
</ScreenReaderContent>
</Button>
</div>
}
/>
</GridCol>
))}
</GridRow>
))}
</Grid>
</div>
)
submissionState: null
}
updateAssignmentCache = (cache, mutationResult) => {
@ -253,119 +78,54 @@ export default class ContentUploadTab extends Component {
})
}
renderAlert = (data, error) => {
if (error) {
return (
<AssignmentAlert
errorMessage={I18n.t('Error sending submission')}
onDismiss={() => this.setState({submissionFailed: false, uploadingFiles: false})}
/>
)
}
if (data) {
return <AssignmentAlert successMessage={I18n.t('Submission sent')} />
}
updateSubmissionState = state => {
this.setState({submissionState: state})
}
submitAssignment = createSubmission => {
this.setState({submissionFailed: false, uploadingFiles: true}, async () => {
let fileIds = []
if (this.state.files.length) {
try {
const attachments = await uploadFiles(
this.state.files,
submissionFileUploadUrl(this.props.assignment)
)
fileIds = attachments.map(attachment => attachment.id)
} catch (err) {
if (this._isMounted) {
this.setState({submissionFailed: true, uploadingFiles: false})
}
return
}
}
await createSubmission({
variables: {
id: this.props.assignment._id,
type: 'online_upload', // TODO: update to enable different submission types
fileIds
}
})
if (this._isMounted) {
this.setState({files: [], messages: [], uploadingFiles: false})
}
})
}
renderSubmitButton = createSubmission => {
const outerFooterStyle = {
position: 'fixed',
bottom: '0',
left: '0',
right: '0',
maxWidth: '1366px',
margin: '0 0 0 84px',
zIndex: '5'
}
const innerFooterStyle = {
backgroundColor: theme.variables.colors.white,
borderColor: theme.variables.colors.borderMedium,
borderTop: `1px solid ${theme.variables.colors.borderMedium}`,
textAlign: 'right',
margin: `0 ${theme.variables.spacing.medium}`
}
renderErrorAlert = () => {
return (
<div style={outerFooterStyle}>
<div style={innerFooterStyle}>
<Button
variant="primary"
margin="xx-small 0"
onClick={() => this.submitAssignment(createSubmission)}
>
{I18n.t('Submit')}
</Button>
</div>
</div>
<AssignmentAlert
errorMessage={I18n.t('Error sending submission')}
onDismiss={() => this.updateSubmissionState(null)}
/>
)
}
renderSuccessAlert = () => {
return <AssignmentAlert successMessage={I18n.t('Submission sent')} />
}
renderFileUpload = createSubmission => {
switch (this.state.submissionState) {
case 'error':
return this.renderErrorAlert()
case 'in-progress':
return <LoadingIndicator />
case 'success':
default:
return (
<React.Fragment>
{this.renderSuccessAlert()}
<FileUpload
assignment={this.props.assignment}
createSubmission={createSubmission}
submission={this.props.submission}
updateSubmissionState={this.updateSubmissionState}
/>
</React.Fragment>
)
}
}
render() {
return (
<Mutation mutation={CREATE_SUBMISSION} update={this.updateAssignmentCache}>
{(createSubmission, {data, error}) => (
<React.Fragment>
{this.renderAlert(data, error || this.state.submissionFailed)}
{/* TODO: replace loading indicator with a progress bar */}
{this.state.uploadingFiles && !error && !this.state.submissionFailed && (
<LoadingIndicator />
)}
{!this.state.uploadingFiles && !this.state.submissionFailed && (
<React.Fragment>
<FileDrop
accept={
this.props.assignment.allowedExtensions.length
? this.props.assignment.allowedExtensions
: ''
}
allowMultiple
enablePreview
id="inputFileDrop"
label={
this.state.files.length ? this.renderUploadedFiles() : this.renderEmptyUpload()
}
messages={this.state.messages}
onDropAccepted={this.handleDropAccepted}
onDropRejected={this.handleDropRejected}
/>
{this.state.files.length !== 0 && this.renderSubmitButton(createSubmission)}
</React.Fragment>
)}
</React.Fragment>
)}
<Mutation
mutation={CREATE_SUBMISSION}
onCompleted={() => this.updateSubmissionState('success')}
onError={() => this.updateSubmissionState('error')}
update={this.updateAssignmentCache}
>
{this.renderFileUpload}
</Mutation>
)
}

View File

@ -0,0 +1,295 @@
/*
* Copyright (C) 2019 - 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 {AssignmentShape, SubmissionShape} from '../assignmentData'
import {chunk} from 'lodash'
import {DEFAULT_ICON, getIconByType} from '../../../shared/helpers/mimeClassIconHelper'
import {func} from 'prop-types'
import I18n from 'i18n!assignments_2_file_upload'
import mimeClass from 'compiled/util/mimeClass'
import React, {Component} from 'react'
import {submissionFileUploadUrl, uploadFiles} from '../../../shared/upload_file'
import Billboard from '@instructure/ui-billboard/lib/components/Billboard'
import Button from '@instructure/ui-buttons/lib/components/Button'
import FileDrop from '@instructure/ui-forms/lib/components/FileDrop'
import Flex, {FlexItem} from '@instructure/ui-layout/lib/components/Flex'
import Grid, {GridCol, GridRow} from '@instructure/ui-layout/lib/components/Grid'
import IconTrash from '@instructure/ui-icons/lib/Line/IconTrash'
import ScreenReaderContent from '@instructure/ui-a11y/lib/components/ScreenReaderContent'
import Text from '@instructure/ui-elements/lib/components/Text'
import theme from '@instructure/ui-themes/lib/canvas/base'
export default class FileUpload extends Component {
static propTypes = {
assignment: AssignmentShape,
createSubmission: func,
submission: SubmissionShape,
updateSubmissionState: func
}
loadDraftFiles = () => {
if (this.props.submission.submissionDraft) {
return this.props.submission.submissionDraft.attachments.map(attachment => ({
id: attachment._id,
mimeClass: attachment.mimeClass,
name: attachment.displayName,
preview: attachment.thumbnailUrl
}))
} else {
return []
}
}
state = {
files: this.loadDraftFiles(),
messages: []
}
_isMounted = false
componentDidMount() {
this._isMounted = true
}
componentWillUnmount() {
this._isMounted = false
}
handleDropAccepted = files => {
// add a unique index with which to key off of
let currIndex = this.state.files.length ? this.state.files[this.state.files.length - 1].id : 0
files.map(file => (file.id = ++currIndex))
this.setState(prevState => ({
files: prevState.files.concat(files),
messages: []
}))
}
handleDropRejected = () => {
this.setState({
messages: [
{
text: I18n.t('Invalid file type'),
type: 'error'
}
]
})
}
handleRemoveFile = e => {
e.preventDefault()
const fileId = parseInt(e.currentTarget.id, 10)
const fileIndex = this.state.files.findIndex(file => parseInt(file.id, 10) === fileId)
this.setState(
prevState => ({
files: prevState.files.filter((_, i) => i !== fileIndex),
messages: []
}),
() => {
const focusElement =
this.state.files.length === 0 || fileIndex === 0
? 'inputFileDrop'
: this.state.files[fileIndex - 1].id
document.getElementById(focusElement).focus()
}
)
}
shouldDisplayThumbnail = file => {
return (file.mimeClass || mimeClass(file.type)) === 'image' && file.preview
}
ellideString = title => {
if (title.length > 21) {
return `${title.substr(0, 9)}${I18n.t('...')}${title.substr(-9)}`
} else {
return title
}
}
submitAssignment = async () => {
if (this._isMounted) {
this.props.updateSubmissionState('in-progress')
}
let fileIds = []
if (this.state.files.length) {
try {
const attachments = await uploadFiles(
this.state.files,
submissionFileUploadUrl(this.props.assignment)
)
fileIds = attachments.map(attachment => attachment.id)
} catch (err) {
if (this._isMounted) {
this.props.updateSubmissionState('error')
}
return
}
}
await this.props.createSubmission({
variables: {
id: this.props.assignment._id,
type: 'online_upload', // TODO: update to enable different submission types
fileIds
}
})
if (this._isMounted) {
this.setState({files: [], messages: []})
}
}
renderEmptyUpload() {
return (
<div data-testid="empty-upload">
<Billboard
heading={I18n.t('Upload File')}
hero={DEFAULT_ICON}
message={
<Flex direction="column">
{this.props.assignment.allowedExtensions.length ? (
<FlexItem>
{I18n.t('File permitted: %{fileTypes}', {
fileTypes: this.props.assignment.allowedExtensions
.map(ext => ext.toUpperCase())
.join(', ')
})}
</FlexItem>
) : null}
<FlexItem padding="small 0 0">
<Text size="small">
{I18n.t('Drag and drop, or click to browse your computer')}
</Text>
</FlexItem>
</Flex>
}
/>
</div>
)
}
renderUploadedFiles() {
const fileRows = chunk(this.state.files, 3)
return (
<div data-testid="non-empty-upload">
<Grid>
{fileRows.map(row => (
<GridRow key={row.map(file => file.id).join()}>
{row.map(file => (
<GridCol key={file.id} vAlign="bottom">
<Billboard
heading={I18n.t('Uploaded')}
headingLevel="h3"
hero={
this.shouldDisplayThumbnail(file) ? (
<img
alt={I18n.t('%{filename} preview', {filename: file.name})}
height="75"
src={file.preview}
width="75"
/>
) : (
getIconByType(mimeClass(file.type))
)
}
message={
<div>
<span aria-hidden title={file.name}>
{this.ellideString(file.name)}
</span>
<ScreenReaderContent>{file.name}</ScreenReaderContent>
<Button
icon={IconTrash}
id={file.id}
margin="0 0 0 x-small"
onClick={this.handleRemoveFile}
size="small"
>
<ScreenReaderContent>
{I18n.t('Remove %{filename}', {filename: file.name})}
</ScreenReaderContent>
</Button>
</div>
}
/>
</GridCol>
))}
</GridRow>
))}
</Grid>
</div>
)
}
renderSubmitButton = () => {
const outerFooterStyle = {
position: 'fixed',
bottom: '0',
left: '0',
right: '0',
maxWidth: '1366px',
margin: '0 0 0 84px',
zIndex: '5'
}
const innerFooterStyle = {
backgroundColor: theme.variables.colors.white,
borderColor: theme.variables.colors.borderMedium,
borderTop: `1px solid ${theme.variables.colors.borderMedium}`,
textAlign: 'right',
margin: `0 ${theme.variables.spacing.medium}`
}
return (
<div style={outerFooterStyle}>
<div style={innerFooterStyle}>
<Button variant="primary" margin="xx-small 0" onClick={() => this.submitAssignment()}>
{I18n.t('Submit')}
</Button>
</div>
</div>
)
}
render() {
return (
<React.Fragment>
<FileDrop
accept={
this.props.assignment.allowedExtensions.length
? this.props.assignment.allowedExtensions
: ''
}
allowMultiple
enablePreview
id="inputFileDrop"
label={this.state.files.length ? this.renderUploadedFiles() : this.renderEmptyUpload()}
messages={this.state.messages}
onDropAccepted={this.handleDropAccepted}
onDropRejected={this.handleDropRejected}
/>
{this.state.files.length !== 0 && this.renderSubmitButton()}
</React.Fragment>
)
}
}

View File

@ -15,9 +15,10 @@
* 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 $ from 'jquery'
import ContentUploadTab from '../ContentUploadTab'
import {DEFAULT_ICON} from '../../../../shared/helpers/mimeClassIconHelper'
import FileUpload from '../FileUpload'
import {fireEvent, render} from 'react-testing-library'
import {
mockAssignment,
@ -36,7 +37,7 @@ beforeEach(() => {
window.URL.createObjectURL = jest.fn().mockReturnValue('perry_preview')
})
describe('ContentUploadTab', () => {
describe('FileUpload', () => {
const uploadFiles = (element, files) => {
fireEvent.change(element, {
target: {
@ -48,7 +49,7 @@ describe('ContentUploadTab', () => {
it('renders the empty upload tab by default', async () => {
const {container, getByTestId, getByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
const emptyRender = getByTestId('empty-upload')
@ -62,10 +63,10 @@ describe('ContentUploadTab', () => {
it('renders the uploaded files if there are any', async () => {
const {container, getByTestId, getByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
const emptyRender = container.querySelector('input[type="file"]')
const emptyRender = container.querySelector('input[id="inputFileDrop"]')
const file = new File(['foo'], 'awesome-test-image.png', {type: 'image/png'})
uploadFiles(emptyRender, [file])
@ -77,7 +78,7 @@ describe('ContentUploadTab', () => {
it('renders in an img tag if the file type is an image', async () => {
const {container, getByTestId} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
const emptyRender = container.querySelector('input[type="file"]')
@ -94,7 +95,7 @@ describe('ContentUploadTab', () => {
it('renders an icon if a non-image file is uploaded', async () => {
const {container, getByTestId} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
const emptyRender = container.querySelector('input[type="file"]')
@ -110,7 +111,7 @@ describe('ContentUploadTab', () => {
it('allows uploading multiple files at a time', async () => {
const {container, getByTestId, getByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
const fileInput = container.querySelector('input[type="file"]')
@ -127,7 +128,7 @@ describe('ContentUploadTab', () => {
it('concatenates separate file additions together', async () => {
const {container, getByTestId, getByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
const fileInput = container.querySelector('input[type="file"]')
@ -145,7 +146,7 @@ describe('ContentUploadTab', () => {
it('renders a button to remove the file', async () => {
const {container, getByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
const emptyRender = container.querySelector('input[type="file"]')
@ -161,7 +162,7 @@ describe('ContentUploadTab', () => {
it('removes the correct file when the Remove button is clicked', async () => {
const {container, getByText, queryByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
const fileInput = container.querySelector('input[type="file"]')
@ -180,7 +181,7 @@ describe('ContentUploadTab', () => {
it('ellides filenames for files greater than 21 characters', async () => {
const {container, getByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
const fileInput = container.querySelector('input[type="file"]')
@ -195,7 +196,7 @@ describe('ContentUploadTab', () => {
const filename = 'c'.repeat(21)
const {container, getByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
const fileInput = container.querySelector('input[type="file"]')
@ -210,7 +211,7 @@ describe('ContentUploadTab', () => {
const mockedAssignment = mockAssignment({allowedExtensions: ['jpg, png']})
const {getByTestId, getByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockedAssignment} submission={mockSubmission()} />
<FileUpload assignment={mockedAssignment} submission={mockSubmission()} />
</MockedProvider>
)
const emptyRender = getByTestId('empty-upload')
@ -221,7 +222,7 @@ describe('ContentUploadTab', () => {
it('does not display any allowed extensions if there are none', async () => {
const {getByTestId, queryByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
const emptyRender = getByTestId('empty-upload')
@ -233,7 +234,7 @@ describe('ContentUploadTab', () => {
const mockedAssignment = mockAssignment({allowedExtensions: ['jpg']})
const {container, getByText, queryByTestId} = render(
<MockedProvider>
<ContentUploadTab assignment={mockedAssignment} submission={mockSubmission()} />
<FileUpload assignment={mockedAssignment} submission={mockSubmission()} />
</MockedProvider>
)
const fileInput = container.querySelector('input[type="file"]')
@ -249,7 +250,7 @@ describe('ContentUploadTab', () => {
const mockedAssignment = mockAssignment({allowedExtensions: ['jpg']})
const {container, getByTestId, getByText, queryByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockedAssignment} submission={mockSubmission()} />
<FileUpload assignment={mockedAssignment} submission={mockSubmission()} />
</MockedProvider>
)
const fileInput = container.querySelector('input[type="file"]')
@ -265,7 +266,7 @@ describe('ContentUploadTab', () => {
it('renders a submit button only when a file has been uploaded', async () => {
const {container, getByText, queryByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mockSubmission()} />
<FileUpload assignment={mockAssignment()} submission={mockSubmission()} />
</MockedProvider>
)
@ -294,7 +295,7 @@ describe('ContentUploadTab', () => {
const {getByTestId, getByText} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mocked_submission} />
<FileUpload assignment={mockAssignment()} submission={mocked_submission} />
</MockedProvider>
)
const uploadRender = getByTestId('non-empty-upload')
@ -316,7 +317,7 @@ describe('ContentUploadTab', () => {
const {container, getByTestId} = render(
<MockedProvider>
<ContentUploadTab assignment={mockAssignment()} submission={mocked_submission} />
<FileUpload assignment={mockAssignment()} submission={mocked_submission} />
</MockedProvider>
)
const uploadRender = getByTestId('non-empty-upload')