UNPKG

@instructure/quiz-interactions

Version:

A React UI component Library for quiz interaction types.

303 lines (267 loc) • 9.19 kB
import React from 'react' import {vi} from 'vitest' import runAxeCheck from '@instructure/ui-axe-check' import {render} from '@testing-library/react' import TargetContainer from '../index' import Target from '../../../Take/Target' const renderUserResponseFeedbackStub = vi.fn() const renderScoringDataFeedbackStub = vi.fn() const props = { coordinates: [{x: 0.3, y: 0.3}], drawingType: Target, readOnly: false, handleSetCoordinates: () => {}, renderUserResponseFeedback: renderUserResponseFeedbackStub, hotspots: [ { coordinates: [{x: 0.1, y: 0.2}], drawingType: Target, renderScoringDataFeedback: renderScoringDataFeedbackStub, }, ], results: true, url: 'https://i.ytimg.com/vi/LgkAebhJ7iE/maxresdefault.jpg', userResponseCoordinate: [{x: 0.1, y: 0.2, correct: 'correct'}], } // TargetContainer is wrapped by withStyleOverrides HOC; use originalType for ref access const TargetContainerRaw = TargetContainer.originalType describe('Target Container', () => { afterEach(() => { renderUserResponseFeedbackStub.mockClear() renderScoringDataFeedbackStub.mockClear() }) it('should render', () => { const {container} = render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} />, ) expect(container.firstChild).toBeDefined() }) describe('rendering', () => { it('renders image and Target components when readOnly is false', () => { const {container} = render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} />, ) const images = container.querySelectorAll('img') expect(images.length).toBe(1) expect(images[0].src).toBe(props.url) }) it('#renderImage', () => { const ref = React.createRef() render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} ref={ref} />, ) const component = ref.current.renderImage() expect(component.props.src).toBe(props.url) expect(component.props.alt).toBe('Target Image') }) it('does not render feedback components if results is false', () => { render( <TargetContainerRaw {...props} results={false} makeStyles={vi.fn()} styles={{image: {}, container: {}}} />, ) expect(renderUserResponseFeedbackStub).not.toHaveBeenCalled() expect(renderScoringDataFeedbackStub).not.toHaveBeenCalled() }) it('renders feedback components when results is true', () => { render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} />, ) expect(renderUserResponseFeedbackStub).toHaveBeenCalledOnce() expect(renderScoringDataFeedbackStub).toHaveBeenCalledOnce() }) }) describe('Helpers', () => { describe('#componentDidMount', () => { it('adds event listener', () => { const addEventListenerSpy = vi.spyOn(window, 'addEventListener') const ref = React.createRef() render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} ref={ref} />, ) ref.current.componentDidMount() const resizeCall = addEventListenerSpy.mock.calls.find(call => call[0] === 'resize') expect(resizeCall).toBeDefined() expect(resizeCall[0]).toBe('resize') addEventListenerSpy.mockRestore() }) }) describe('#componentWillUnmount', () => { it('removes event listener', () => { const removeEventListenerSpy = vi.spyOn(window, 'removeEventListener') const ref = React.createRef() render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} ref={ref} />, ) ref.current.componentWillUnmount() const resizeCall = removeEventListenerSpy.mock.calls.find(call => call[0] === 'resize') expect(resizeCall).toBeDefined() expect(resizeCall[0]).toBe('resize') removeEventListenerSpy.mockRestore() }) }) describe('#convertCoordinate', () => { it('returns the current coordinates proportional to the image size', () => { const ref = React.createRef() render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} ref={ref} />, ) const newState = {imageWidth: 700, imageHeight: 500} const oldCoordinates = props.coordinates[0] ref.current.setState(newState) const convertedCoordinates = ref.current.convertCoordinate(oldCoordinates) expect(convertedCoordinates.x).toBe(oldCoordinates.x * newState.imageWidth) expect(convertedCoordinates.y).toBe(oldCoordinates.y * newState.imageHeight) }) }) describe('#currentCoordinates', () => { it('returns null when coordinates array is empty', () => { const ref = React.createRef() render( <TargetContainerRaw {...props} coordinates={[]} makeStyles={vi.fn()} styles={{image: {}, container: {}}} ref={ref} />, ) expect(ref.current.currentCoordinates([])).toBeNull() }) it('returns converted coordinates relative to the image size', () => { const ref = React.createRef() render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} ref={ref} />, ) const newState = {imageWidth: 700, imageHeight: 500} ref.current.setState(newState) const currentCoordinates = ref.current.currentCoordinates(props.coordinates) const expectedX = props.coordinates[0].x * newState.imageWidth const expectedY = props.coordinates[0].y * newState.imageHeight expect(currentCoordinates[0].x).toBe(expectedX) expect(currentCoordinates[0].y).toBe(expectedY) }) }) describe('#currentImageWidth', () => { it('returns current image width', () => { const ref = React.createRef() render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} ref={ref} />, ) const newState = { imageWidth: 700, imageHeight: 500, } ref.current.state = newState const imageWidth = ref.current.state.imageWidth expect(imageWidth).toBe(newState.imageWidth) }) }) describe('#currentImageHeight', () => { it('returns current image width', () => { const ref = React.createRef() render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} ref={ref} />, ) const newState = { imageWidth: 700, imageHeight: 500, } ref.current.state = newState const imageHeight = ref.current.state.imageHeight expect(imageHeight).toBe(newState.imageHeight) }) }) }) describe('Actions', () => { describe('#updateImageDimensions', () => { it('updates the state with the new image width and height', () => { const ref = React.createRef() render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} ref={ref} />, ) const onSetStateStub = vi.fn() ref.current.setState = onSetStateStub ref.current.updateImageDimensions() const newState = onSetStateStub.mock.calls[0][0] expect(newState.imageWidth).toBeDefined() expect(newState.imageHeight).toBeDefined() }) }) describe('#handleImageLoad', () => { it('updates the state with the new image width and height', () => { const ref = React.createRef() render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} ref={ref} />, ) const onSetStateStub = vi.fn() ref.current.setState = onSetStateStub ref.current.handleImageLoad({ target: { offsetWidth: 100, offsetHeight: 200, }, }) const newState = onSetStateStub.mock.calls[0][0] expect(newState.imageWidth).toBe(100) expect(newState.imageHeight).toBe(200) }) }) }) describe('a11y tests', () => { it('should meet a11y standards', async () => { const {container} = render( <TargetContainerRaw {...props} makeStyles={vi.fn()} styles={{image: {}, container: {}}} />, ) expect(await runAxeCheck(container)).toBe(true) }) }) })