UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

121 lines (101 loc) 3.93 kB
import React from 'react' import {vi} from 'vitest' import {render, waitFor} from '@testing-library/react' import EditStem from '../index' describe('Fill in the Blank Edit Stem', () => { const setSelectedTextStub = vi.fn() const defaultProps = { destroyBlank: () => {}, errors: [], setSelectedText: setSelectedTextStub, onCreateBlankHotkey: () => {}, onStemChange: () => {}, showCreateButton: () => {}, stemItems: [], styles: {}, } afterEach(() => { setSelectedTextStub.mockClear() }) describe('placeholder', () => { it('displays a placeholder when not focused', () => { const {container} = render( <EditStem {...defaultProps} stemItems={[{id: '0', type: 'text', value: ''}]} />, ) expect(container.querySelector('[placeholder="Type a statement..."]')).not.toBeNull() }) it('displays a placeholder when focused', () => { const {container} = render( <EditStem {...defaultProps} stemItems={[{id: '0', type: 'text', value: ''}]} />, ) container.querySelector('[placeholder="Type a statement..."]').focus() expect(container.querySelector('[placeholder="Type a statement..."]')).not.toBeNull() }) it('displays a placeholder if the only content is a nbsp', () => { const {container} = render( <EditStem {...defaultProps} stemItems={[{id: '0', type: 'text', value: String.fromCharCode(160)}]} />, ) expect(container.querySelector('[placeholder="Type a statement..."]')).not.toBeNull() }) }) describe('text selection', () => { // The component uses document.onselectionchange with a debounced handler (100ms) // that reads sel.anchorNode and sel.toString(). jsdom does not support // Selection.toString() or anchorNode properly, so we mock window.getSelection. it('calls setSelectedText with the text when stem item is selected', async () => { const {container} = render( <EditStem {...defaultProps} stemItems={[{id: '0', type: 'text', value: 'hello world'}]} />, ) const elem = container.querySelector('[contenteditable="true"]') vi.spyOn(window, 'getSelection').mockReturnValue({ anchorNode: elem, toString: () => 'hello world', }) document.onselectionchange() await waitFor(() => { expect(setSelectedTextStub).toHaveBeenCalledWith('hello world') }) }) it('does not call setSelectedText when something else is selected', async () => { render( <EditStem {...defaultProps} stemItems={[{id: '0', type: 'text', value: 'hello world'}]} />, ) const outsideDiv = document.createElement('div') document.body.appendChild(outsideDiv) vi.spyOn(window, 'getSelection').mockReturnValue({ anchorNode: outsideDiv, toString: () => 'foo', }) document.onselectionchange() await waitFor(() => { expect(setSelectedTextStub).not.toHaveBeenCalled() }) outsideDiv.remove() }) }) describe('a11y', () => { it('uses a Tag component for blanks', () => { const blankText = 'this is a blank' const {container} = render( <EditStem {...defaultProps} stemItems={[{id: 'blank', blankId: 'blank', type: 'blank'}]} scoringData={{ value: [{id: 'blank', scoringData: {blankText}}], }} />, ) // Tag renders a button-like element with the blank text // Check that the blank label with the expected alt text is rendered const tagElement = container.querySelector('[class*="tag"]') || container.querySelector('span[role="button"], button') expect(tagElement || document.body.textContent).toBeDefined() // Verify the delete label contains the blank text expect(document.body.textContent).toContain(blankText) }) }) })