UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

226 lines (200 loc) • 7.27 kB
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) }) }) })