@instructure/quiz-interactions
Version:
A React UI component Library for quiz interaction types.
237 lines (198 loc) • 8.15 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 Match from '../Match'
describe('Shared Match component', () => {
const updateStub = vi.fn()
const defaultProps = {
disabled: false,
handleResponseUpdate: updateStub,
itemBody: 'Match the Presidential term with the corresponding President',
interactionData: {
questions: [
{id: 'quuid1', itemBody: '1st President'},
{id: 'quuid2', itemBody: '16th President'},
{id: 'quuid3', itemBody: '44th President'},
{id: 'quuid4', itemBody: '45th President'},
{id: 'quuid5', itemBody: '46th President'},
],
answers: [
'George Washington',
'george washington',
'Thomas Jefferson',
'Abraham Lincoln',
'Barack Obama',
'Donald"Trump',
"Jo'e Biden",
],
},
selectedAnswers: {value: {}},
readOnly: false,
}
afterEach(() => {
updateStub.mockClear()
})
it('should render', () => {
const {container} = render(<Match {...defaultProps} />)
expect(container.firstChild).toBeInTheDocument()
})
describe('rendering', () => {
it('renders each question', () => {
const {container} = render(<Match {...defaultProps} />)
const expected = defaultProps.interactionData.questions.map(question => question.itemBody)
const result = Array.from(container.querySelectorAll('[data-testid="question"]')).map(
elem => elem.innerHTML,
)
const contains = result.reduce((prev, curr, i) => curr.includes(expected[i]) && prev, true)
expect(contains).toBe(true)
})
it('renders an option for each answer', async () => {
render(<Match {...defaultProps} />)
const select = await screen.findByRole('combobox', {name: /1st president/i})
userEvent.click(select)
const options = await screen.findAllByRole('option')
const availableOptions = options.map(option => option.textContent)
expect(availableOptions).toEqual(defaultProps.interactionData.answers)
})
it('renders with answers which are supplied', async () => {
render(
<Match
{...defaultProps}
selectedAnswers={{
value: {
quuid1: 'Thomas Jefferson',
quuid3: 'Barack Obama',
},
}}
/>,
)
const firstSelect = await screen.findByRole('combobox', {name: /1st president/i})
userEvent.click(firstSelect)
const firstSelection = screen.queryByRole('option', {selected: true})
const secondSelect = await screen.findByRole('combobox', {name: /16th president/i})
userEvent.click(secondSelect)
const secondSelection = screen.queryByRole('option', {selected: true})
const thirdSelect = await screen.findByRole('combobox', {name: /44th president/i})
userEvent.click(thirdSelect)
const thirdSelection = screen.queryByRole('option', {selected: true})
expect(firstSelection.textContent).toBe('Thomas Jefferson')
expect(secondSelection).toBeNull()
expect(thirdSelection.textContent).toBe('Barack Obama')
})
it('renders questions with quotes properly', async () => {
render(
<Match
{...defaultProps}
selectedAnswers={{
value: {
quuid4: 'Donald"Trump',
quuid5: "Jo'e Biden",
},
}}
/>,
)
const firstSelect = await screen.findByRole('combobox', {name: /45th president/i})
userEvent.click(firstSelect)
const firstSelection = screen.queryByRole('option', {selected: true})
const secondSelect = await screen.findByRole('combobox', {name: /46th president/i})
userEvent.click(secondSelect)
const secondSelection = screen.queryByRole('option', {selected: true})
expect(firstSelection.textContent).toBe('Donald"Trump')
expect(secondSelection.textContent).toBe("Jo'e Biden")
})
})
describe('updating', () => {
const selectOptionInFirstSelect = async targetOption => {
const select = await screen.findByRole('combobox', {name: /1st president/i})
userEvent.click(select)
const options = await screen.findAllByRole('option')
const optionToSelect = options.find(option => option.textContent === targetOption)
userEvent.click(optionToSelect)
}
it('does not change case when answers only differ by case', async () => {
render(<Match {...defaultProps} />)
await selectOptionInFirstSelect('george washington')
const call1 = updateStub.mock.calls[0]
expect(call1).toEqual([{quuid1: 'george washington'}])
userEvent.click(document.body)
const call2 = updateStub.mock.calls[1]
expect(call2).toEqual([{quuid1: 'george washington'}])
})
it('updates with a new answer when no answers are present', async () => {
render(<Match {...defaultProps} />)
await selectOptionInFirstSelect('Thomas Jefferson')
const call = updateStub.mock.calls[0]
expect(call).toEqual([{quuid1: 'Thomas Jefferson'}])
})
it('updates with a new answer when an answers is already present', async () => {
render(<Match {...defaultProps} selectedAnswers={{value: {quuid2: 'Thomas Jefferson'}}} />)
await selectOptionInFirstSelect('Abraham Lincoln')
const call = updateStub.mock.calls[0]
expect(call).toEqual([{quuid1: 'Abraham Lincoln', quuid2: 'Thomas Jefferson'}])
})
it('updates with a changed answer when an answer is already present', async () => {
render(<Match {...defaultProps} selectedAnswers={{value: {quuid1: 'Thomas Jefferson'}}} />)
await selectOptionInFirstSelect('George Washington')
const call = updateStub.mock.calls[0]
expect(call).toEqual([{quuid1: 'George Washington'}])
})
it('updates with a changed answer when an answer is already present', async () => {
render(
<Match
{...defaultProps}
selectedAnswers={{value: {quuid1: 'Thomas Jefferson', quuid2: 'Abraham Lincoln'}}}
/>,
)
const select = await screen.findByRole('combobox', {name: /1st president/i})
userEvent.clear(select)
userEvent.click(document.body)
const call = updateStub.mock.calls[0]
expect(call).toEqual([{quuid1: '', quuid2: 'Abraham Lincoln'}])
})
it('updates with no answer after answer was present', async () => {
render(<Match {...defaultProps} selectedAnswers={{value: {quuid1: 'Abraham Lincoln'}}} />)
const select = await screen.findByRole('combobox', {name: /1st president/i})
userEvent.clear(select)
userEvent.click(document.body)
const call = updateStub.mock.calls[0]
expect(call).toEqual([{quuid1: ''}])
})
})
describe('show component', () => {
it('does render readOnly elements', () => {
render(
<Match
{...defaultProps}
readOnly
selectedAnswers={{value: {quuid1: 'Thomas Jefferson', quuid3: 'Barack Obama'}}}
/>,
)
const selects = screen.getAllByRole('combobox')
expect(selects.length > 0).toBe(true)
selects.forEach(select => {
expect(select.readOnly).toBe(true)
})
})
})
describe('interaction tests', () => {
// TODO: Cannot migrate to RTL - checkInteractionComponents walks React fiber tree to verify
// InstUI component props, which is not feasible with RTL. Jira: QUIZ-XXXXX
it.skip('should pass the given readOnly prop as readonly interaction to instui components', () => {})
})
describe('a11y tests', () => {
it('should meet a11y standards', async () => {
render(<Match {...defaultProps} />)
await expect(
await runAxeCheck(document.body, {
ignores: [
'aria-allowed-role', // TODO: remove this when instui fixes Select
'label', // FIXME: false positive?
'region',
],
}),
).toBe(true)
})
})
})