import React from 'react' import { render, fireEvent, act } from '@testing-library/react' import { trans } from '@/scripts/i18n' import $ from 'jquery' import Modal from '@/components/Modal' test('hidden by default', () => { const { queryByRole } = render() expect(queryByRole('dialog')).toBeNull() }) test('receive id', () => { const { getByRole } = render() expect(getByRole('dialog')).toHaveAttribute('id', 'kumiko') }) test('centered dialog', () => { const { getByRole } = render() expect(getByRole('document')).toHaveClass('modal-dialog-centered') }) test('background color', () => { const { container } = render() expect(container.querySelector('.modal-content')).toHaveClass('bg-primary') }) test('jQuery events', () => { const { getByText } = render() act(() => { jest.runAllTimers() $('.modal').trigger('hidden.bs.modal') }) fireEvent.click(getByText(trans('general.cancel'))) act(() => { jest.runAllTimers() $('.modal').trigger('hidden.bs.modal') }) }) describe('modal header', () => { it('modal title', () => { const { queryByText } = render() expect(queryByText('Tips')).toBeInTheDocument() }) it('hide modal header', () => { const { queryByText } = render( , ) expect(queryByText('Tips')).not.toBeInTheDocument() }) }) describe('modal body', () => { it('custom children', () => { const { queryByText } = render(body) expect(queryByText('body')).toBeInTheDocument() }) it('text with linebreaks', () => { const { queryByText } = render() expect(queryByText('L1')).toBeInTheDocument() expect(queryByText('L2')).toBeInTheDocument() }) it('dangerous HTML', () => { const { getByText } = render( , ) expect(getByText('ab')).toHaveClass('h1') }) describe('input control', () => { it('set default value', () => { const { queryByDisplayValue } = render( , ) expect(queryByDisplayValue('val')).toBeInTheDocument() }) it('placeholder', () => { const { queryByPlaceholderText } = render( , ) expect(queryByPlaceholderText('hint')).toBeInTheDocument() }) it('input control type', () => { const { getByPlaceholderText } = render( , ) expect(getByPlaceholderText('password')).toHaveAttribute( 'type', 'password', ) }) }) }) describe('modal footer', () => { it('custom footer content', () => { const { queryByText } = render(footer} show />) expect(queryByText('footer')).toBeInTheDocument() expect(queryByText(trans('general.confirm'))).not.toBeInTheDocument() }) it('flex footer', () => { const { getByText } = render() expect(getByText('footer')).toHaveClass('d-flex', 'justify-content-between') }) it('custom ok button', () => { const { getByText } = render( , ) expect(getByText('kumiko')).toHaveClass('btn-primary') }) it('custom cancel button', () => { const { getByText } = render( , ) expect(getByText('reina')).toHaveClass('btn-success') }) }) describe('"alert" mode', () => { it('buttons', () => { const resolve = jest.fn() const { getByText, queryByText } = render( , ) fireEvent.click(getByText(trans('general.confirm'))) expect(resolve).toBeCalledWith({ value: '' }) expect(queryByText(trans('general.cancel'))).toBeNull() }) it('confirm callback is optional', () => { const { getByText } = render() fireEvent.click(getByText(trans('general.confirm'))) }) }) describe('"confirm" mode', () => { it('default mode is "confirm"', () => { const { queryByText } = render() expect(queryByText(trans('general.confirm'))).toBeInTheDocument() expect(queryByText(trans('general.cancel'))).toBeInTheDocument() }) it('"confirm" button', () => { const resolve = jest.fn() const reject = jest.fn() const { getByText } = render( , ) fireEvent.click(getByText(trans('general.confirm'))) expect(resolve).toBeCalledWith({ value: '' }) expect(reject).not.toBeCalled() }) it('"cancel" button', () => { const resolve = jest.fn() const reject = jest.fn() const { getByText } = render( , ) fireEvent.click(getByText(trans('general.cancel'))) expect(resolve).not.toBeCalled() expect(reject).toBeCalled() }) }) describe('"prompt" mode', () => { it('retrieve input value', () => { const resolve = jest.fn() const reject = jest.fn() const { getByPlaceholderText, getByText } = render( , ) fireEvent.change(getByPlaceholderText('hint'), { target: { value: 'my' }, }) fireEvent.click(getByText(trans('general.confirm'))) expect(resolve).toBeCalledWith({ value: 'my' }) expect(reject).not.toBeCalled() }) it('cancel dialog', () => { const resolve = jest.fn() const reject = jest.fn() const { getByText } = render( , ) fireEvent.click(getByText(trans('general.cancel'))) expect(resolve).not.toBeCalled() expect(reject).toBeCalled() }) it('radio inputs', () => { const choices = [ { text: 'A', value: 'a' }, { text: 'B', value: 'b' }, ] const resolve = jest.fn() const { getByText, getByLabelText } = render( , ) fireEvent.click(getByLabelText('B')) fireEvent.click(getByText(trans('general.confirm'))) expect(resolve).toBeCalledWith({ value: 'b' }) }) it('validate input', () => { const resolve = jest.fn() const reject = jest.fn() const validator = jest.fn().mockReturnValue(true) const { getByText } = render( , ) fireEvent.click(getByText(trans('general.confirm'))) expect(resolve).toBeCalledWith({ value: 'val' }) expect(reject).not.toBeCalled() }) it('report validator message', () => { const message = 'Invalid input.' const resolve = jest.fn() const reject = jest.fn() const validator = jest.fn().mockReturnValue(message) const { getByText, queryByText } = render( , ) expect(queryByText(message)).not.toBeInTheDocument() fireEvent.click(getByText(trans('general.confirm'))) expect(queryByText(message)).toBeInTheDocument() expect(resolve).not.toBeCalled() expect(reject).not.toBeCalled() }) }) describe('"onClose" event', () => { it('button confirm', () => { const mock = jest.fn() const { getByText } = render() fireEvent.click(getByText(trans('general.confirm'))) expect(mock).toBeCalled() }) it('button cancel', () => { const mock = jest.fn() const { getByText } = render() fireEvent.click(getByText(trans('general.cancel'))) expect(mock).toBeCalled() }) })