import Mathematics from '../src/math.js'; import AutoMath from '../src/automath.js'; import { ClassicEditor, Clipboard, Paragraph, Undo, Typing, getData, setData } from 'ckeditor5'; import { expect } from 'chai'; import type { SinonFakeTimers } from 'sinon'; import { describe, beforeEach, it, afterEach } from "vitest"; describe( 'AutoMath - integration', () => { let editorElement: HTMLDivElement, editor: ClassicEditor; beforeEach( async () => { editorElement = document.createElement( 'div' ); document.body.appendChild( editorElement ); return ClassicEditor .create( editorElement, { plugins: [ Mathematics, AutoMath, Typing, Paragraph ], math: { engine: ( equation, element, display ) => { if ( display ) { element.innerHTML = '\\[' + equation + '\\]'; } else { element.innerHTML = '\\(' + equation + '\\)'; } } } } ) .then( newEditor => { editor = newEditor; } ); } ); afterEach( () => { editorElement.remove(); return editor.destroy(); } ); it( 'should load Clipboard plugin', () => { expect( editor.plugins.get( Clipboard ) ).to.instanceOf( Clipboard ); } ); it( 'should load Undo plugin', () => { expect( editor.plugins.get( Undo ) ).to.instanceOf( Undo ); } ); it( 'has proper name', () => { expect( AutoMath.pluginName ).to.equal( 'AutoMath' ); } ); describe( 'use fake timers', () => { let clock: SinonFakeTimers; beforeEach( () => { clock = sinon.useFakeTimers(); } ); afterEach( () => { clock.restore(); } ); it( 'replaces pasted text with mathtex element after 100ms', () => { setData( editor.model, '[]' ); pasteHtml( editor, '\\[x^2\\]' ); expect( getData( editor.model ) ).to.equal( '\\[x^2\\][]' ); clock.tick( 100 ); expect( getData( editor.model ) ).to.equal( '[]' ); } ); it( 'replaces pasted text with inline mathtex element after 100ms', () => { setData( editor.model, '[]' ); pasteHtml( editor, '\\(x^2\\)' ); expect( getData( editor.model ) ).to.equal( '\\(x^2\\)[]' ); clock.tick( 100 ); expect( getData( editor.model ) ).to.equal( '[]' ); } ); it( 'can undo auto-mathing', () => { setData( editor.model, '[]' ); pasteHtml( editor, '\\[x^2\\]' ); expect( getData( editor.model ) ).to.equal( '\\[x^2\\][]' ); clock.tick( 100 ); editor.commands.execute( 'undo' ); expect( getData( editor.model ) ).to.equal( '\\[x^2\\][]' ); } ); it( 'works for not collapsed selection inside single element', () => { setData( editor.model, '[Foo]' ); pasteHtml( editor, '\\[x^2\\]' ); clock.tick( 100 ); expect( getData( editor.model ) ).to.equal( '[]' ); } ); it( 'works for not collapsed selection over a few elements', () => { setData( editor.model, 'Fo[oBa]r' ); pasteHtml( editor, '\\[x^2\\]' ); clock.tick( 100 ); expect( getData( editor.model ) ).to.equal( 'Fo[]r' ); } ); it( 'inserts mathtex in-place (collapsed selection)', () => { setData( editor.model, 'Foo []Bar' ); pasteHtml( editor, '\\[x^2\\]' ); clock.tick( 100 ); expect( getData( editor.model ) ).to.equal( 'Foo ' + '[]' + 'Bar' ); } ); it( 'inserts math in-place (non-collapsed selection)', () => { setData( editor.model, 'Foo [Bar] Baz' ); pasteHtml( editor, '\\[x^2\\]' ); clock.tick( 100 ); expect( getData( editor.model ) ).to.equal( 'Foo ' + '[]' + ' Baz' ); } ); it( 'does nothing if pasted two equation as text', () => { setData( editor.model, '[]' ); pasteHtml( editor, '\\[x^2\\] \\[\\sqrt{x}2\\]' ); clock.tick( 100 ); expect( getData( editor.model ) ).to.equal( '\\[x^2\\] \\[\\sqrt{x}2\\][]' ); } ); } ); function pasteHtml( editor: ClassicEditor, html: string ) { editor.editing.view.document.fire( 'paste', { dataTransfer: createDataTransfer( { 'text/html': html } ), preventDefault() { return undefined; } } ); } function createDataTransfer( data: Record ) { return { getData( type: string ) { return data[ type ]; } }; } } );