@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
226 lines (200 loc) • 7.27 kB
JavaScript
import {vi} from 'vitest'
import React from 'react'
import {render, screen} from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import runAxeCheck from '@instructure/ui-axe-check'
import EssayTake from '../index'
const interactionData = {
rce: false,
spellCheck: false,
wordCount: false,
wordLimitEnabled: false,
wordLimitMax: null,
wordLimitMin: null,
notes: '',
}
describe('Essay Take', () => {
describe('rendering', () => {
it('renders the take component without an rce', () => {
const {container} = render(
<EssayTake interactionData={interactionData} itemBody="This is an essay question:" />,
)
const textarea = container.querySelector('textarea')
expect(textarea).toBeInTheDocument()
})
it('renders the take component with an rce', () => {
render(
<EssayTake
interactionData={{...interactionData, rce: true}}
itemBody="This is an essay question:"
/>,
)
const richContentInput = screen.getByTestId('RichContentInput')
expect(richContentInput).toBeInTheDocument()
})
it('should include SR word count message when enabled', () => {
const {container} = render(
<EssayTake
interactionData={{...interactionData, wordCount: true}}
itemBody="This is an essay question:"
/>,
)
expect(container.textContent).toContain('word count below the text area')
})
it('should include SR word limit messages when enabled', () => {
const {container} = render(
<EssayTake
interactionData={{
...interactionData,
wordLimitEnabled: true,
wordLimitMax: 10,
wordLimitMin: 2,
}}
itemBody="This is an essay question:"
/>,
)
expect(container.textContent).toContain('maximum word count of 10')
expect(container.textContent).toContain('minimum word count of 2')
})
it('should fill the editor content with the userResponse value if response', () => {
render(
<EssayTake
interactionData={interactionData}
itemBody="This is an essay question:"
userResponse={{value: 'user response text'}}
/>,
)
expect(screen.getByText('user response text')).toBeDefined()
})
})
describe('event handlers', () => {
describe('handleResponseUpdate', () => {
it('calls handleResponseUpdate with correct args', async () => {
const handleResponseUpdateStub = vi.fn()
const {container} = render(
<EssayTake
handleResponseUpdate={handleResponseUpdateStub}
interactionData={interactionData}
itemBody="This is an essay question:"
/>,
)
const textarea = container.querySelector('textarea')
await userEvent.type(textarea, '1234567890')
expect(handleResponseUpdateStub).toHaveBeenCalled()
})
it('does not blow up if handleResponseUpdate is not provided', async () => {
const {container} = render(
<EssayTake
handleResponseUpdate={void 0}
interactionData={interactionData}
itemBody="This is an essay question:"
/>,
)
const textarea = container.querySelector('textarea')
await userEvent.type(textarea, '1234567890')
expect(textarea.value).toBe('1234567890')
})
it('does nothing if readOnly is set', async () => {
const handleResponseUpdateStub = vi.fn()
const {container} = render(
<EssayTake
handleResponseUpdate={handleResponseUpdateStub}
interactionData={interactionData}
itemBody="This is an essay question:"
readOnly={true}
userResponse={{value: '1234567890'}}
/>,
)
const textarea = container.querySelector('textarea')
// readOnly textarea should not accept input
await userEvent.type(textarea, 'ABCDEFG')
expect(handleResponseUpdateStub).not.toHaveBeenCalled()
})
})
describe('onblur', () => {
it('updates the state with any changes', async () => {
const handleResponseUpdateStub = vi.fn()
const {container} = render(
<EssayTake
handleResponseUpdate={handleResponseUpdateStub}
interactionData={interactionData}
itemBody="This is an essay question:"
userResponse={{value: 'initial user response'}}
/>,
)
const textarea = container.querySelector('textarea')
await userEvent.clear(textarea)
await userEvent.type(textarea, 'second user response')
await userEvent.tab()
expect(handleResponseUpdateStub).toHaveBeenCalled()
})
it('does not send updates if there are no changes', async () => {
const handleResponseUpdateStub = vi.fn()
const {container} = render(
<EssayTake
handleResponseUpdate={handleResponseUpdateStub}
interactionData={interactionData}
itemBody="This is an essay question:"
userResponse={{value: 'initial user response'}}
/>,
)
const textarea = container.querySelector('textarea')
// Just click and blur without changing value
await userEvent.click(textarea)
await userEvent.tab()
expect(handleResponseUpdateStub).not.toHaveBeenCalled()
})
})
})
describe('errors', () => {
describe('documentTreeDepth', () => {
it('must show error message when document tree depth is exceeded', () => {
const longText = 'START' + '<div>'.repeat(420) + 'END' + '</div>'.repeat(420)
render(
<EssayTake
interactionData={interactionData}
itemBody="This is an essay question:"
userResponse={{value: longText}}
/>,
)
expect(
screen.getByText(
'Formatting error. Please ensure that the text entry has not been pasted from a different source. Type text to submit response.',
),
).toBeInTheDocument()
})
})
describe('dynamoRecordSize', () => {
it('must show error message when size is exceeded', () => {
const longText = '.'.repeat(107409) + '&'.repeat(17750)
render(
<EssayTake
interactionData={interactionData}
itemBody="This is an essay question:"
userResponse={{value: longText}}
/>,
)
expect(
screen.getByText('This submission is too large. Please adjust and try to submit again.'),
).toBeInTheDocument()
})
})
})
describe('a11y tests', () => {
it('should meet a11y standards', async () => {
render(
<main>
<EssayTake interactionData={interactionData} itemBody="This is an essay question:" />
</main>,
)
expect(
await runAxeCheck(document.body, {
ignores: [
'radiogroup',
'scrollable-region-focusable', // we conditionally make rceRenderer focusable when we detect content overflow
],
}),
).toBe(true)
})
})
})