UNPKG

@instructure/quiz-taking

Version:
300 lines (260 loc) • 11.7 kB
import {sessionStore} from '@instructure/quiz-core/common/util/sessionStore' import {TakeButton} from '../presenter' import React from 'react' import {describe, expect, it, vi} from 'vitest' import userEvent from '@testing-library/user-event' import {canvas} from '@instructure/ui-themes' import {hexToRgb} from '../../../../tests/utils/hexToRgb' import {render, screen} from '../../../../tests/utils/rtlRenderOverride' describe('TakeButton presenter', () => { const submitQuizStub = vi.fn() const nextQuestionStub = vi.fn() const onSubmitQuizSession = () => {} const screenreaderNotificationStub = vi.fn() const withConfirmStub = vi.fn() const defaultProps = { allowBacktracking: true, currentSessionItemPosition: 3, isOneQuestionAtATime: true, currentQuestionIsLast: false, itemId: '66', largeFormatResponse: {value: 'goodbye'}, nextQuestion: nextQuestionStub, quizSessionId: '22', onSubmitQuizSession, screenreaderNotification: screenreaderNotificationStub, submitQuiz: submitQuizStub, userResponse: {value: 'hello'}, withConfirm: withConfirmStub, isPassage: false, } describe('one question at a time on', () => { it('renders a next button if not on the last question', () => { render(<TakeButton {...defaultProps} />) const nextButton = screen.getByRole('button', {name: /next/i}) expect(nextButton).toBeInTheDocument() }) it('renders a submit button if on the last question', () => { render(<TakeButton {...defaultProps} currentQuestionIsLast />) const submitButton = screen.queryByRole('button', {name: /submit/i}) expect(submitButton).toBeInTheDocument() }) describe('when iceTopNavBarEnabled is true and isFooter is false', () => { it('renders a next button if not on the last question', () => { render(<TakeButton {...defaultProps} iceTopNavBarEnabled />) const nextButton = screen.getByRole('button', {name: /next/i}) expect(nextButton).toBeInTheDocument() expect(nextButton).toHaveAttribute('data-automation', 'sdk-oqaat-next-or-submit-button') }) it('renders a submit button if on the last question', () => { render(<TakeButton {...defaultProps} iceTopNavBarEnabled currentQuestionIsLast />) const submitButton = screen.queryByRole('button', {name: /submit/i}) expect(submitButton).toBeInTheDocument() }) }) describe('clicking the next button', () => { it('triggers the correct callback', () => { render(<TakeButton {...defaultProps} />) const button = screen.getByRole('button', {name: /next/i}) userEvent.click(button) const args = [ defaultProps.quizSessionId, defaultProps.allowBacktracking, defaultProps.currentSessionItemPosition === defaultProps.sessionItemsCount, defaultProps.currentSessionItemPosition, defaultProps.itemId, defaultProps.userResponse, defaultProps.largeFormatResponse, ] expect(nextQuestionStub).toHaveBeenCalledWith( ...args, expect.any(Function), expect.any(Boolean), ) }) it('confirms Next when backtracking disabled and no response', () => { render(<TakeButton {...defaultProps} allowBacktracking={false} userResponse={{}} />) const button = screen.getByRole('button', {name: /next/i}) userEvent.click(button) expect(withConfirmStub).toHaveBeenCalled() expect(nextQuestionStub).not.toHaveBeenCalled() }) it('does not confirm Next when there is a response', () => { render( <TakeButton {...defaultProps} allowBacktracking={false} userResponse={{value: 'value'}} />, ) const button = screen.getByRole('button', {name: /next/i}) userEvent.click(button) expect(withConfirmStub).not.toHaveBeenCalled() expect(nextQuestionStub).toHaveBeenCalled() }) it('does not confirm Next when backtracking enabled', () => { render(<TakeButton {...defaultProps} allowBacktracking={true} userResponse={{}} />) const button = screen.getByRole('button', {name: /next/i}) userEvent.click(button) expect(withConfirmStub).not.toHaveBeenCalled() expect(nextQuestionStub).toHaveBeenCalled() }) it('does not confirm Next if user has asked us not to', () => { render(<TakeButton {...defaultProps} allowBacktracking={false} userResponse={{}} />) sessionStore.set(`quiz_session_${defaultProps.quizSessionId}_confirm_next`, 'false') const button = screen.getByRole('button', {name: /next/i}) userEvent.click(button) expect(withConfirmStub).not.toHaveBeenCalled() expect(nextQuestionStub).toHaveBeenCalled() }) describe('required question validation', () => { it('shows required question alert when survey, no backtracking, required, and unanswered', () => { render( <TakeButton {...defaultProps} isSurvey={true} allowBacktracking={false} isRequiredItem={true} userResponse={{}} />, ) const button = screen.getByRole('button', {name: /next/i}) userEvent.click(button) expect(withConfirmStub).toHaveBeenCalled() expect(nextQuestionStub).not.toHaveBeenCalled() const modalOptions = withConfirmStub.mock.calls[0][1] expect(modalOptions.title).toBe('Required Question') expect(modalOptions.continueText).toBe('Ok') expect(modalOptions.hideCancelButton).toBe(true) }) it('does not show required alert when not a survey (shows optional warning instead)', () => { render( <TakeButton {...defaultProps} isSurvey={false} allowBacktracking={false} isRequiredItem={true} userResponse={{}} />, ) const button = screen.getByRole('button', {name: /next/i}) userEvent.click(button) expect(withConfirmStub).toHaveBeenCalled() expect(nextQuestionStub).not.toHaveBeenCalled() const modalOptions = withConfirmStub.mock.calls[0][1] expect(modalOptions.title).toBe('Are you sure?') expect(modalOptions.continueText).toBe('Confirm') expect(modalOptions.hideCancelButton).toBeUndefined() }) it('does not show alert when backtracking is enabled', () => { render( <TakeButton {...defaultProps} isSurvey={true} allowBacktracking={true} isRequiredItem={true} userResponse={{}} />, ) const button = screen.getByRole('button', {name: /next/i}) userEvent.click(button) expect(withConfirmStub).not.toHaveBeenCalled() expect(nextQuestionStub).toHaveBeenCalled() }) it('does not show required alert when question is not required (shows optional warning instead)', () => { render( <TakeButton {...defaultProps} isSurvey={true} allowBacktracking={false} isRequiredItem={false} userResponse={{}} />, ) const button = screen.getByRole('button', {name: /next/i}) userEvent.click(button) expect(withConfirmStub).toHaveBeenCalled() expect(nextQuestionStub).not.toHaveBeenCalled() const modalOptions = withConfirmStub.mock.calls[0][1] expect(modalOptions.title).toBe('Are you sure?') expect(modalOptions.continueText).toBe('Confirm') expect(modalOptions.hideCancelButton).toBeUndefined() }) }) it('reads nothing when backtracking is allowed on the last question', () => { render(<TakeButton {...defaultProps} currentQuestionIsLast />) const button = screen.getByRole('button', {name: /submit/i}) userEvent.click(button) expect(screenreaderNotificationStub).not.toHaveBeenCalled() }) it('reads the text when backtracking is allowed when not on the last question', () => { render(<TakeButton {...defaultProps} allowBacktracking={true} />) const button = screen.getByRole('button', {name: /next/i}) userEvent.click(button) expect(screenreaderNotificationStub).toHaveBeenCalledWith('Moving to next question') }) it('reads the text when backtracking is disabled', () => { render(<TakeButton {...defaultProps} allowBacktracking={false} />) const button = screen.getByRole('button', {name: /next/i}) userEvent.click(button) expect(screenreaderNotificationStub).toHaveBeenCalledWith('Question submitted') }) }) it('shows the submit button with primary light on non final question', () => { render(<TakeButton {...defaultProps} />) const submitButton = screen.getByRole('button', {name: /next/i}) // Note: This test was checking internal Button component props, which RTL discourages // Consider testing the visual appearance or behavior instead expect(submitButton).toBeInTheDocument() }) it('shows the submit button with primary color on final question', () => { render(<TakeButton {...defaultProps} currentQuestionIsLast={true} />) const submitButton = screen.getByRole('button', {name: /submit/i}) expect(submitButton).toHaveStyle({color: hexToRgb(canvas.colors.contrasts.grey125125)}) }) it('disables button when disabled', () => { render(<TakeButton {...defaultProps} disabled />) const button = screen.getByRole('button', {name: /next/i}) expect(button).toBeDisabled() }) describe('with no backtracking', () => { it('does not render a previous button', () => { render(<TakeButton {...defaultProps} allowBacktracking={false} />) const button = screen.queryByRole('button', {name: /previous/i}) expect(button).not.toBeInTheDocument() }) it('disables button when disabled', () => { render(<TakeButton {...defaultProps} allowBacktracking={false} disabled />) const button = screen.queryByRole('button', {name: /next/i}) expect(button).toBeDisabled() }) }) }) describe('one question at a time off', () => { it('shows the submit button with primary color', () => { render(<TakeButton {...defaultProps} isOneQuestionAtATime={false} />) const submitButton = screen.getByRole('button', {name: /submit/i}) expect(submitButton).toHaveStyle({color: hexToRgb(canvas.colors.contrasts.grey125125)}) }) describe('when iceTopNavBarEnabled is true and isFooter is false', () => { it('render a submit button', () => { render( <TakeButton {...defaultProps} isOneQuestionAtATime={false} iceTopNavBarEnabled={true} isFooter={false} />, ) const submitButton = screen.getByRole('button', {name: /submit/i}) expect(submitButton).toBeInTheDocument() }) }) it('calls submit quiz when submit button clicked', () => { render(<TakeButton {...defaultProps} isOneQuestionAtATime={false} />) const submitButton = screen.getByRole('button', {name: /submit/i}) userEvent.click(submitButton) expect(submitQuizStub).toHaveBeenCalledWith('22', onSubmitQuizSession) }) }) })