@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
205 lines (166 loc) • 6.32 kB
JavaScript
import {vi} from 'vitest'
import React from 'react'
import {render} from '@testing-library/react'
import withEditTools from '../withEditTools'
describe('withEditTools test', () => {
let changeItemState
let getInteractionErrors
beforeEach(() => {
changeItemState = vi.fn()
getInteractionErrors = vi.fn().mockReturnValue({})
})
class ExampleComponent extends React.Component {
static interactionType = {getErrors: (...args) => getInteractionErrors(...args)}
render() {
return <div />
}
}
const DecoratedComponent = withEditTools(ExampleComponent)
function getBaseProps(overrides = {}) {
return {
changeItemState,
itemBody: 'STEM',
interactionData: {},
scoringData: {},
userResponse: {},
errorsAreShowing: true,
...overrides,
}
}
it('should render', () => {
const {container} = render(<DecoratedComponent {...getBaseProps()} />)
expect(container.firstChild).toBeDefined()
})
it('has onDescriptionChange and getErrors functions', () => {
let capturedProps
class ProbeComponent extends React.Component {
static interactionType = {getErrors: (...args) => getInteractionErrors(...args)}
render() {
capturedProps = this.props
return <div />
}
}
const Decorated = withEditTools(ProbeComponent)
render(<Decorated {...getBaseProps()} />)
expect(typeof capturedProps.onDescriptionChange).toBe('function')
expect(typeof capturedProps.getErrors).toBe('function')
})
it('has "getErrors" that gets errors', () => {
let capturedProps
class ProbeComponent extends React.Component {
static interactionType = {getErrors: (...args) => getInteractionErrors(...args)}
render() {
capturedProps = this.props
return <div />
}
}
const Decorated = withEditTools(ProbeComponent)
const errors = {
scoringData: {
data: {
errors: ['scoringData error message'],
},
},
}
render(<Decorated {...getBaseProps({errors})} />)
const scoringDataErrors = capturedProps.getErrors('scoringData.data.errors')
const interactionDataErrors = capturedProps.getErrors('interactionData.data.errors')
const expectedErrors = errors.scoringData.data.errors.map(error => ({
text: error,
type: 'error',
}))
expect(scoringDataErrors).toEqual(expectedErrors)
expect(interactionDataErrors).toHaveLength(0)
})
it('has "getErrors" that returns [] when errors are not showing', () => {
let capturedProps
class ProbeComponent extends React.Component {
static interactionType = {getErrors: (...args) => getInteractionErrors(...args)}
render() {
capturedProps = this.props
return <div />
}
}
const Decorated = withEditTools(ProbeComponent)
render(
<Decorated
{...getBaseProps({
errors: {
scoringData: {
data: {
errors: ['scoringData error message'],
},
},
},
errorsAreShowing: false,
})}
/>,
)
const scoringDataErrors = capturedProps.getErrors('scoringData.data.errors')
const interactionDataErrors = capturedProps.getErrors('interactionData.data.errors')
expect(scoringDataErrors).toHaveLength(0)
expect(interactionDataErrors).toHaveLength(0)
})
it('has "onDescriptionChange" that calls changeItemState', () => {
let capturedProps
const localChangeItemState = vi.fn()
class ProbeComponent extends React.Component {
static interactionType = {getErrors: () => ({})}
render() {
capturedProps = this.props
return <div />
}
}
const Decorated = withEditTools(ProbeComponent)
render(<Decorated {...getBaseProps({changeItemState: localChangeItemState})} />)
const newDescription = 'This is a new description'
capturedProps.onDescriptionChange(newDescription)
expect(localChangeItemState).toHaveBeenCalledWith(
expect.objectContaining({
itemBody: newDescription,
}),
)
})
describe('changeItemState', () => {
it('calls changeItemState on mount if there are errors', () => {
const localChangeItemState = vi.fn()
const errors = {interactionData: ['nope']}
getInteractionErrors.mockReturnValue(errors)
render(<DecoratedComponent {...getBaseProps({changeItemState: localChangeItemState})} />)
expect(localChangeItemState).toHaveBeenCalledWith(expect.objectContaining({errors}))
})
it('does not call changeItemState on mount if there are no errors', () => {
const localChangeItemState = vi.fn()
getInteractionErrors.mockReturnValue({})
render(<DecoratedComponent {...getBaseProps({changeItemState: localChangeItemState})} />)
expect(localChangeItemState).not.toHaveBeenCalled()
})
it('calls changeItemState on update if there are new errors', () => {
const localChangeItemState = vi.fn()
getInteractionErrors.mockReturnValue({})
const {rerender} = render(
<DecoratedComponent {...getBaseProps({changeItemState: localChangeItemState})} />,
)
const errors = {interactionData: ['nope']}
getInteractionErrors.mockReturnValue(errors)
rerender(<DecoratedComponent {...getBaseProps({changeItemState: localChangeItemState})} />)
expect(localChangeItemState).toHaveBeenCalledWith(expect.objectContaining({errors}))
})
it('does not call changeItemState on update if there are no new errors', () => {
const localChangeItemState = vi.fn()
const errors = {interactionData: ['nope']}
getInteractionErrors.mockReturnValue(errors)
const {rerender} = render(
<DecoratedComponent {...getBaseProps({changeItemState: localChangeItemState, errors})} />,
)
// changeItemState was called once on mount due to errors
expect(localChangeItemState).toHaveBeenCalledTimes(1)
localChangeItemState.mockClear()
// Re-render with same errors - componentDidUpdate should not call again
rerender(
<DecoratedComponent {...getBaseProps({changeItemState: localChangeItemState, errors})} />,
)
expect(localChangeItemState).not.toHaveBeenCalled()
})
})
})