/* eslint-disable jest/no-conditional-expect */ import React, { useEffect, useRef } from 'react'; import renderer from 'react-test-renderer'; import { render, fireEvent, screen } from '@testing-library/react'; // import userEvent from '@testing-library/user-event'; // import '@testing-library/jest-dom'; import CodeMirror, { ReactCodeMirrorRef } from '..'; // Setup JSDOM mocks for CodeMirror beforeAll(() => { // Mock Range.getClientRects Object.defineProperty(global.Range.prototype, 'getClientRects', { writable: true, value: jest.fn(() => ({ length: 1, item: () => ({ bottom: 16, height: 16, left: 0, right: 100, top: 0, width: 100 }), [Symbol.iterator]: function* () { yield { bottom: 16, height: 16, left: 0, right: 100, top: 0, width: 100 }; }, })), }); Object.defineProperty(global.Range.prototype, 'getBoundingClientRect', { writable: true, value: jest.fn(() => ({ bottom: 16, height: 16, left: 0, right: 100, top: 0, width: 100 })), }); // Mock observers used by CodeMirror internals in JSDOM. class MockIntersectionObserver { observe = jest.fn(); unobserve = jest.fn(); disconnect = jest.fn(); takeRecords = jest.fn(() => []); } class MockResizeObserver { observe = jest.fn(); unobserve = jest.fn(); disconnect = jest.fn(); } class MockMutationObserver { observe = jest.fn(); disconnect = jest.fn(); takeRecords = jest.fn(() => []); } global.IntersectionObserver = MockIntersectionObserver as unknown as typeof IntersectionObserver; global.ResizeObserver = MockResizeObserver as unknown as typeof ResizeObserver; global.MutationObserver = MockMutationObserver as unknown as typeof MutationObserver; window.IntersectionObserver = global.IntersectionObserver; window.ResizeObserver = global.ResizeObserver; window.MutationObserver = global.MutationObserver; // Mock element properties Object.defineProperty(global.HTMLElement.prototype, 'clientHeight', { get: () => 100 }); Object.defineProperty(global.HTMLElement.prototype, 'clientWidth', { get: () => 500 }); Object.defineProperty(global.HTMLElement.prototype, 'offsetHeight', { get: () => 100 }); Object.defineProperty(global.HTMLElement.prototype, 'offsetWidth', { get: () => 500 }); Object.defineProperty(global.Element.prototype, 'scrollIntoView', { writable: true, value: jest.fn() }); // Suppress CodeMirror JSDOM warnings const originalError = console.error; console.error = (...args) => { if (args[0]?.toString?.().includes('getClientRects') || args[0]?.toString?.().includes('observe is not a function')) return; originalError.apply(console, args); }; }); it('CodeMirror', async () => { const component = renderer.create(); let tree = component.toJSON(); if (tree && !Array.isArray(tree)) { expect(tree.type).toEqual('div'); expect(tree.props.className).toEqual('cm-theme-light'); } }); it('CodeMirror onChange', async () => { const handleChange = jest.fn((value) => { expect(value).toEqual('# title'); return Array.isArray(value) ? value.join() : value; }); render(); const input = await screen.findByRole('textbox'); // findByRole('textbox'); fireEvent.change(input, { target: { textContent: '# title' } }); const elm = screen.queryByText('# title'); expect(elm?.innerHTML).toEqual('# title'); }); it('CodeMirror onUpdate', async () => { render( { expect(viewUpdate.state.doc.length).toEqual(27); }} />, ); }); it('CodeMirror ref', async () => { function Demo() { const ref = useRef(null); useEffect(() => { expect(Object.keys(ref.current!)).toEqual(['editor', 'state', 'view']); }, [ref]); return ; } render(); }); it('CodeMirror theme', async () => { const component = renderer.create(); let tree = component.toJSON(); if (tree && !Array.isArray(tree)) { expect(tree.type).toEqual('div'); expect(tree.props.className).toEqual('cm-theme-dark'); } }); it('CodeMirror className', async () => { const component = renderer.create(); let tree = component.toJSON(); if (tree && !Array.isArray(tree)) { expect(tree.type).toEqual('div'); expect(tree.props.className).toEqual('cm-theme-light test'); } }); it('CodeMirror placeholder', async () => { render(); const elm = screen.queryByText('Hello World'); expect(elm!.style['pointerEvents']).toEqual('none'); expect(elm!.className).toEqual('cm-placeholder'); }); it('CodeMirror editable', async () => { render(); const text = screen.getByRole('textbox'); expect(text.className).toEqual('cm-content'); expect(text.tagName).toEqual('DIV'); }); it("CodeMirror doesn't echo changes", async () => { const handleChange = jest.fn(); const { rerender } = render(); rerender(); expect(handleChange).not.toHaveBeenCalled(); });