@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
199 lines (154 loc) • 6.24 kB
JavaScript
import {vi} from 'vitest'
import React from 'react'
import {fireEvent, render, screen, waitFor} from '@testing-library/react'
import runAxeCheck from '@instructure/ui-axe-check'
import userEvent from '@testing-library/user-event'
import FileUploadTake from '../index'
describe('File Upload Take', () => {
let props
beforeEach(() => {
props = {
itemBody: 'Give three examples of people',
interactionData: {
restrictCount: true,
filesCount: '3',
},
properties: {
restrictTypes: true,
allowedTypes: ['image/jpeg', 'application/pdf'],
},
userResponse: {
value: [
{
id: 0,
name: 'slide-3.jpg',
url: 'http://instructure.github.io/images/slide-3.jpg',
size: 49067,
},
{
id: 1,
name: 'maxresdefault.jpg',
url: 'https://i.ytimg.com/vi/LgkAebhJ7iE/maxresdefault.jpg',
size: 30437,
},
],
},
handleResponseUpdate: vi.fn(),
mediaUpload: vi.fn(),
cancelMediaUpload: vi.fn(),
}
})
describe('Response mods', () => {
it('Handles response removal', async () => {
render(<FileUploadTake {...props} />)
const removeButton = screen.getByText('Remove File Named slide-3.jpg')
userEvent.click(removeButton)
expect(props.handleResponseUpdate).toHaveBeenCalledWith([props.userResponse.value[1]])
})
it('Uploads a dropped file', async () => {
const userResponse = {
value: [],
}
const file = new File([''], 'fake.png', {type: 'image/png'})
render(<FileUploadTake {...props} userResponse={userResponse} />)
const dropLabel = screen.getByLabelText(/Drag and Drop here or Browse/i)
userEvent.upload(dropLabel, file)
expect(dropLabel.files[0]).toBe(file)
expect(dropLabel.files.item(0)).toBe(file)
expect(dropLabel.files).toHaveLength(1)
})
// TODO: QUIZ-17438 - FileDrop from @instructure/ui-file-drop does not process
// fireEvent.change or userEvent.upload in jsdom; mediaUpload callback is never triggered
it.skip('Adds a response on file dropped', async () => {
const userResponse = {
value: [],
}
const file = new File([''], 'fake.pdf', {type: 'application/pdf'})
const {container} = render(<FileUploadTake {...props} userResponse={userResponse} />)
const fileInput = container.querySelector('input[type="file"]')
fireEvent.change(fileInput, {target: {files: [file]}})
await waitFor(() => {
expect(props.mediaUpload).toHaveBeenCalled()
})
expect(props.handleResponseUpdate).not.toHaveBeenCalled()
const callback = props.mediaUpload.mock.calls[0][2]
const fakeFilename = 'fake.pdf'
callback(fakeFilename)
const newResponseValue = props.handleResponseUpdate.mock.calls[0][0]
expect(newResponseValue.length).toBe(1)
})
})
describe('rendering', () => {
it('has title', async () => {
render(<FileUploadTake {...props} />)
const title = screen.getByText(props.itemBody)
expect(title).toBeInTheDocument()
})
it('renders the list of existing files', async () => {
render(<FileUploadTake {...props} />)
const firstFile = screen.getByText(props.userResponse.value[0].name)
const secondFile = screen.getByText(props.userResponse.value[1].name)
expect(firstFile).toBeInTheDocument()
expect(secondFile).toBeInTheDocument()
})
// TODO: QUIZ-17438 - FileDrop from @instructure/ui-file-drop does not process
// fireEvent.change in jsdom; rejection path is never triggered
it.skip('renders errors if attempted to upload invalid file type', async () => {
const file = new File([''], 'fake.png', {type: 'image/png'})
const {container} = render(<FileUploadTake {...props} />)
const fileInput = container.querySelector('input[type="file"]')
fireEvent.change(fileInput, {target: {files: [file]}})
await waitFor(() => {
expect(screen.getByText('Invalid file type')).toBeInTheDocument()
})
})
it('renders a FileDrop if the max files limit has not been reached', async () => {
render(<FileUploadTake {...props} />)
const dropLabel = screen.getByLabelText(/Drag and Drop here or Browse/i)
expect(dropLabel).toBeInTheDocument()
})
it("always renders a FileDrop if there's no max file limit", async () => {
const interactionData = {
restrictCount: false,
filesCount: '2',
}
render(<FileUploadTake {...props} interactionData={interactionData} />)
const dropLabel = screen.getByLabelText(/Drag and Drop here or Browse/i)
expect(dropLabel).toBeInTheDocument()
})
it('does not render a FileDrop if the max file limit has been reached', async () => {
const interactionData = {
restrictCount: true,
filesCount: '2',
}
render(<FileUploadTake {...props} interactionData={interactionData} />)
const dropLabel = screen.queryByText(
(content, element) => content.includes('Drag and Drop here') && content.includes('Browse'),
)
expect(dropLabel).not.toBeInTheDocument()
})
})
describe('a11y tests', () => {
it('should meet a11y standards', async () => {
render(<FileUploadTake {...props} />)
expect(
await runAxeCheck(document.body, {
ignores: ['region'],
}),
).toBe(true)
})
})
it('should prevent dropping a file when in read only mode', async () => {
const file = new File([''], 'fake.pdf', {type: 'application/pdf'})
render(<FileUploadTake {...props} readOnly />)
const dropLabel = screen.getByLabelText(/Drag and Drop here or Browse/i)
userEvent.upload(dropLabel, file)
expect(props.mediaUpload).not.toHaveBeenCalled()
})
it('should disable the remove button(s) when in read only mode', async () => {
render(<FileUploadTake {...props} readOnly />)
const removeButton = screen.getByText('Remove File Named slide-3.jpg')
removeButton.click()
expect(props.handleResponseUpdate).not.toHaveBeenCalled()
})
})