import React, { useState } from 'react'; import QRCode from '..'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; import { fireEvent, render } from '../../../tests/utils'; import type { QRCodeProps } from '../interface'; describe('QRCode test', () => { mountTest(() => <QRCode value="" />); rtlTest(() => <QRCode value="" />); it('should correct render', () => { const { container } = render(<QRCode value="test" />); expect(container?.querySelector<HTMLCanvasElement>('.ant-qrcode canvas')).toBeTruthy(); expect(container).toMatchSnapshot(); }); it('should render `null` and console Error when value not exist', () => { const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); const { container } = render(<QRCode value={undefined as unknown as string} />); expect(container.firstChild).toBe(null); expect(container.firstChild).toMatchSnapshot(); expect(errSpy).toHaveBeenCalledWith('Warning: [antd: QRCode] need to receive `value` props'); errSpy.mockRestore(); }); it('support custom icon', () => { const { container } = render(<QRCode value="test" icon="test" />); expect(container?.querySelector<HTMLImageElement>('.ant-qrcode img')).toBeTruthy(); }); it('support custom size', () => { const { container } = render(<QRCode value="test" size={100} />); const canvas = container.querySelector<HTMLCanvasElement>('.ant-qrcode > canvas')!; expect(canvas.width).toBe(100); expect(canvas.height).toBe(100); }); it('support refresh', () => { const refresh = jest.fn(); const { container } = render(<QRCode value="test" status="expired" onRefresh={refresh} />); fireEvent.click( container?.querySelector<HTMLButtonElement>('.ant-qrcode button.ant-btn-link')!, ); expect(refresh).toHaveBeenCalled(); }); it('support click', () => { const handleClick = jest.fn(); const { container } = render(<QRCode value="test" onClick={handleClick} />); fireEvent.click(container?.querySelector<HTMLDivElement>('.ant-qrcode')!); expect(handleClick).toHaveBeenCalled(); }); it('support loading', () => { const Demo: React.FC = () => { const [status, setStatus] = useState<QRCodeProps['status']>('active'); return ( <> <QRCode value="test" status={status} /> <button type="button" onClick={() => setStatus('loading')}> set loading </button> </> ); }; const { container } = render(<Demo />); expect(container.querySelector<HTMLDivElement>('.ant-spin-spinning')).toBeFalsy(); fireEvent.click(container?.querySelector<HTMLButtonElement>('button')!); expect(container.querySelector<HTMLDivElement>('.ant-spin-spinning')).toBeTruthy(); }); it('support bordered', () => { const { container } = render(<QRCode value="test" bordered={false} />); expect(container?.querySelector<HTMLDivElement>('.ant-qrcode')).toHaveClass( 'ant-qrcode-borderless', ); }); it('should console Error when icon exist && errorLevel is `L`', () => { const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); render(<QRCode value="test" icon="test" errorLevel="L" />); expect(errSpy).toHaveBeenCalledWith( 'Warning: [antd: QRCode] ErrorLevel `L` is not recommended to be used with `icon`, for scanning result would be affected by low level.', ); errSpy.mockRestore(); }); it('correct style for wrapper & canvas', () => { const { container } = render( <QRCode value="test" size={60} style={{ width: '100%', height: '80%' }} />, ); expect(container.querySelector<HTMLElement>('.ant-qrcode')).toHaveStyle( 'width: 100%; height: 80%;', ); expect(container.querySelector<HTMLElement>('.ant-qrcode canvas')).toHaveStyle( 'width: 100%; height: 80%;', ); }); it('custom status render', () => { const refreshCb = jest.fn(); const customStatusRender: QRCodeProps['statusRender'] = (info) => { switch (info.status) { case 'expired': return ( <div className="custom-expired"> <span>{info.locale?.expired}</span> <button id="refresh" onClick={info.onRefresh} type="button"> refresh </button> </div> ); case 'loading': return <div className="custom-loading">Loading</div>; case 'scanned': return <div className="custom-scanned">{info.locale?.scanned}</div>; default: return null; } }; const { container } = render( <> <QRCode className="qrcode-expired" value="test" status="expired" statusRender={customStatusRender} onRefresh={refreshCb} /> <QRCode className="qrcode-loading" value="test" status="loading" statusRender={customStatusRender} /> <QRCode className="qrcode-scanned" value="test" status="scanned" statusRender={customStatusRender} /> </>, ); expect( container.querySelector<HTMLDivElement>('.qrcode-expired .custom-expired>span')?.textContent, ).toBe('QR code expired'); fireEvent.click(container?.querySelector<HTMLButtonElement>('#refresh')!); expect(refreshCb).toHaveBeenCalled(); expect( container.querySelector<HTMLDivElement>('.qrcode-loading .custom-loading')?.textContent, ).toBe('Loading'); expect( container.querySelector<HTMLDivElement>('.qrcode-scanned .custom-scanned')?.textContent, ).toBe('Scanned'); expect(container).toMatchSnapshot(); }); it('should pass aria and data props to qrcode element', () => { const { container } = render(<QRCode value="test" aria-label="Test QR Code" />); const qrcodeElement = container.querySelector('.ant-qrcode canvas'); expect(qrcodeElement).toHaveAttribute('aria-label', 'Test QR Code'); }); it('should not pass other props to qrcode element', () => { const { container } = render( <QRCode value="test" aria-label="Test QR Code" title="qr-title" // This prop should not be passed to canvas />, ); const qrcodeElement = container.querySelector('.ant-qrcode canvas'); expect(qrcodeElement).toHaveAttribute('aria-label', 'Test QR Code'); expect(qrcodeElement).not.toHaveAttribute('title', 'qr-title'); }); it('should work with both canvas and svg type', () => { const ariaLabel = 'Test QR Code'; // test canvas type const { container: canvasContainer } = render( <QRCode value="test" type="canvas" aria-label={ariaLabel} />, ); expect(canvasContainer.querySelector('canvas')).toHaveAttribute('aria-label', ariaLabel); // test svg type const { container: svgContainer } = render( <QRCode value="test" type="svg" aria-label={ariaLabel} />, ); expect(svgContainer.querySelector('svg')).toHaveAttribute('aria-label', ariaLabel); }); });