|
|
|
|
@ -5,9 +5,7 @@ import MathUI from '../src/mathui';
|
|
|
|
|
import MainFormView from '../src/ui/mainformview';
|
|
|
|
|
import { ClassicEditor, ContextualBalloon, ButtonView, View, Paragraph, ClickObserver, keyCodes, _setModelData as setModelData } from 'ckeditor5';
|
|
|
|
|
|
|
|
|
|
import { expect } from 'chai';
|
|
|
|
|
import type { SinonSpy } from 'sinon';
|
|
|
|
|
import { describe, beforeEach, it, afterEach } from "vitest";
|
|
|
|
|
import { describe, beforeEach, it, afterEach, vi, expect, MockInstance, expectTypeOf } from "vitest";
|
|
|
|
|
|
|
|
|
|
describe( 'MathUI', () => {
|
|
|
|
|
let editorElement: HTMLDivElement;
|
|
|
|
|
@ -43,8 +41,8 @@ describe( 'MathUI', () => {
|
|
|
|
|
formView = mathUIFeature.formView;
|
|
|
|
|
|
|
|
|
|
// There is no point to execute BalloonPanelView attachTo and pin methods so lets override it.
|
|
|
|
|
sinon.stub( balloon.view, 'attachTo' ).returns( false );
|
|
|
|
|
sinon.stub( balloon.view, 'pin' ).returns();
|
|
|
|
|
vi.spyOn( balloon.view, 'attachTo' ).mockReturnValue( false );
|
|
|
|
|
vi.spyOn( balloon.view, 'pin' ).mockReturnValue();
|
|
|
|
|
|
|
|
|
|
formView?.render();
|
|
|
|
|
} );
|
|
|
|
|
@ -93,19 +91,19 @@ describe( 'MathUI', () => {
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should call #_showUI upon #execute', () => {
|
|
|
|
|
const spy = sinon.stub( mathUIFeature, '_showUI' ).returns( );
|
|
|
|
|
const spy = vi.spyOn( mathUIFeature, '_showUI' ).mockReturnValue();
|
|
|
|
|
|
|
|
|
|
mathButton.fire( 'execute' );
|
|
|
|
|
sinon.assert.calledOnce( spy );
|
|
|
|
|
expect(spy).toHaveBeenCalledOnce();
|
|
|
|
|
} );
|
|
|
|
|
} );
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
describe( '_showUI()', () => {
|
|
|
|
|
let balloonAddSpy: SinonSpy;
|
|
|
|
|
let balloonAddSpy: MockInstance;
|
|
|
|
|
|
|
|
|
|
beforeEach( () => {
|
|
|
|
|
balloonAddSpy = sinon.spy( balloon, 'add' );
|
|
|
|
|
balloonAddSpy = vi.spyOn( balloon, 'add' );
|
|
|
|
|
editor.editing.view.document.isFocused = true;
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
@ -138,12 +136,12 @@ describe( 'MathUI', () => {
|
|
|
|
|
mathUIFeature._showUI();
|
|
|
|
|
|
|
|
|
|
expect( balloon.visibleView ).to.equal( formView );
|
|
|
|
|
sinon.assert.calledWithExactly( balloonAddSpy, {
|
|
|
|
|
expect(balloonAddSpy).toHaveBeenCalledWith({
|
|
|
|
|
view: formView,
|
|
|
|
|
position: {
|
|
|
|
|
target: selectedRange
|
|
|
|
|
}
|
|
|
|
|
} );
|
|
|
|
|
});
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should add #mainFormView to the balloon and attach the balloon to the selection when selection is collapsed', () => {
|
|
|
|
|
@ -153,7 +151,7 @@ describe( 'MathUI', () => {
|
|
|
|
|
mathUIFeature._showUI();
|
|
|
|
|
|
|
|
|
|
expect( balloon.visibleView ).to.equal( formView );
|
|
|
|
|
sinon.assert.calledWithExactly( balloonAddSpy, {
|
|
|
|
|
expect(balloonAddSpy).toHaveBeenCalledWith( balloonAddSpy, {
|
|
|
|
|
view: formView,
|
|
|
|
|
position: {
|
|
|
|
|
target: selectedRange
|
|
|
|
|
@ -195,21 +193,20 @@ describe( 'MathUI', () => {
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should focus the `editable` by default', () => {
|
|
|
|
|
const spy = sinon.spy( editor.editing.view, 'focus' );
|
|
|
|
|
const spy = vi.spyOn( editor.editing.view, 'focus' );
|
|
|
|
|
|
|
|
|
|
mathUIFeature._hideUI();
|
|
|
|
|
|
|
|
|
|
// First call is from _removeFormView.
|
|
|
|
|
sinon.assert.calledTwice( spy );
|
|
|
|
|
expect(spy).toHaveBeenCalledTimes(2);
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should focus the `editable` before before removing elements from the balloon', () => {
|
|
|
|
|
const focusSpy = sinon.spy( editor.editing.view, 'focus' );
|
|
|
|
|
const removeSpy = sinon.spy( balloon, 'remove' );
|
|
|
|
|
const focusSpy = vi.spyOn( editor.editing.view, 'focus' );
|
|
|
|
|
const removeSpy = vi.spyOn( balloon, 'remove' );
|
|
|
|
|
|
|
|
|
|
mathUIFeature._hideUI();
|
|
|
|
|
|
|
|
|
|
expect( focusSpy.calledBefore( removeSpy ) ).to.equal( true );
|
|
|
|
|
expect(focusSpy).toHaveBeenCalledBefore(removeSpy);
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should not throw an error when views are not in the `balloon`', () => {
|
|
|
|
|
@ -221,19 +218,19 @@ describe( 'MathUI', () => {
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should clear ui#update listener from the ViewDocument', () => {
|
|
|
|
|
const spy = sinon.spy();
|
|
|
|
|
const spy = vi.fn();
|
|
|
|
|
|
|
|
|
|
mathUIFeature.listenTo( editor.ui, 'update', spy );
|
|
|
|
|
mathUIFeature._hideUI();
|
|
|
|
|
editor.ui.fire( 'update' );
|
|
|
|
|
|
|
|
|
|
sinon.assert.notCalled( spy );
|
|
|
|
|
expect(spy).not.toHaveBeenCalled();
|
|
|
|
|
} );
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
describe( 'keyboard support', () => {
|
|
|
|
|
it( 'should show the UI on Ctrl+M keystroke', () => {
|
|
|
|
|
const spy = sinon.stub( mathUIFeature, '_showUI' ).returns( );
|
|
|
|
|
const spy = vi.spyOn( mathUIFeature, '_showUI' ).mockReturnValue( );
|
|
|
|
|
const command = editor.commands.get( 'math' )!;
|
|
|
|
|
|
|
|
|
|
command.isEnabled = false;
|
|
|
|
|
@ -244,23 +241,23 @@ describe( 'MathUI', () => {
|
|
|
|
|
altKey: false,
|
|
|
|
|
shiftKey: false,
|
|
|
|
|
metaKey: false,
|
|
|
|
|
preventDefault: sinon.spy(),
|
|
|
|
|
stopPropagation: sinon.spy()
|
|
|
|
|
preventDefault: vi.fn(),
|
|
|
|
|
stopPropagation: vi.fn()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
editor.keystrokes.press( keydata );
|
|
|
|
|
|
|
|
|
|
sinon.assert.notCalled( spy );
|
|
|
|
|
expect(spy).not.toHaveBeenCalled();
|
|
|
|
|
|
|
|
|
|
command.isEnabled = true;
|
|
|
|
|
|
|
|
|
|
editor.keystrokes.press( keydata );
|
|
|
|
|
sinon.assert.calledOnce( spy );
|
|
|
|
|
expect(spy).toHaveBeenCalled();
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should prevent default action on Ctrl+M keystroke', () => {
|
|
|
|
|
const preventDefaultSpy = sinon.spy();
|
|
|
|
|
const stopPropagationSpy = sinon.spy();
|
|
|
|
|
const preventDefaultSpy = vi.fn();
|
|
|
|
|
const stopPropagationSpy = vi.fn();
|
|
|
|
|
|
|
|
|
|
const keyEvtData = {
|
|
|
|
|
altKey: false,
|
|
|
|
|
@ -274,8 +271,8 @@ describe( 'MathUI', () => {
|
|
|
|
|
|
|
|
|
|
editor.keystrokes.press( keyEvtData );
|
|
|
|
|
|
|
|
|
|
sinon.assert.calledOnce( preventDefaultSpy );
|
|
|
|
|
sinon.assert.calledOnce( stopPropagationSpy );
|
|
|
|
|
expect(preventDefaultSpy).toHaveBeenCalledOnce();
|
|
|
|
|
expect(stopPropagationSpy).toHaveBeenCalledOnce();
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should make stack with math visible on Ctrl+M keystroke - no math', () => {
|
|
|
|
|
@ -294,8 +291,8 @@ describe( 'MathUI', () => {
|
|
|
|
|
altKey: false,
|
|
|
|
|
shiftKey: false,
|
|
|
|
|
metaKey: false,
|
|
|
|
|
preventDefault: sinon.spy(),
|
|
|
|
|
stopPropagation: sinon.spy()
|
|
|
|
|
preventDefault: vi.fn(),
|
|
|
|
|
stopPropagation: vi.fn()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
editor.keystrokes.press( keyEvtData );
|
|
|
|
|
@ -322,47 +319,47 @@ describe( 'MathUI', () => {
|
|
|
|
|
shiftKey: false,
|
|
|
|
|
metaKey: false,
|
|
|
|
|
// @ts-expect-error - preventDefault
|
|
|
|
|
preventDefault: sinon.spy(),
|
|
|
|
|
stopPropagation: sinon.spy()
|
|
|
|
|
preventDefault: vi.fn(),
|
|
|
|
|
stopPropagation: vi.fn()
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
expect( balloon.visibleView ).to.equal( formView );
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should hide the UI after Esc key press (from editor) and not focus the editable', () => {
|
|
|
|
|
const spy = sinon.spy( mathUIFeature, '_hideUI' );
|
|
|
|
|
const spy = vi.spyOn( mathUIFeature, '_hideUI' );
|
|
|
|
|
const keyEvtData = {
|
|
|
|
|
altKey: false,
|
|
|
|
|
ctrlKey: false,
|
|
|
|
|
shiftKey: false,
|
|
|
|
|
metaKey: false,
|
|
|
|
|
keyCode: keyCodes.esc,
|
|
|
|
|
preventDefault: sinon.spy(),
|
|
|
|
|
stopPropagation: sinon.spy()
|
|
|
|
|
preventDefault: vi.fn(),
|
|
|
|
|
stopPropagation: vi.fn()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Balloon is visible.
|
|
|
|
|
mathUIFeature._showUI();
|
|
|
|
|
editor.keystrokes.press( keyEvtData );
|
|
|
|
|
|
|
|
|
|
sinon.assert.calledWithExactly( spy );
|
|
|
|
|
expect(spy).toHaveBeenCalledExactlyOnceWith();
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should not hide the UI after Esc key press (from editor) when UI is open but is not visible', () => {
|
|
|
|
|
const spy = sinon.spy( mathUIFeature, '_hideUI' );
|
|
|
|
|
const spy = vi.spyOn( mathUIFeature, '_hideUI' );
|
|
|
|
|
const keyEvtData = {
|
|
|
|
|
altKey: false,
|
|
|
|
|
shiftKey: false,
|
|
|
|
|
ctrlKey: false,
|
|
|
|
|
metaKey: false,
|
|
|
|
|
keyCode: keyCodes.esc,
|
|
|
|
|
preventDefault: sinon.spy(),
|
|
|
|
|
stopPropagation: sinon.spy()
|
|
|
|
|
preventDefault: vi.fn(),
|
|
|
|
|
stopPropagation: vi.fn()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const viewMock = new View();
|
|
|
|
|
sinon.stub( viewMock, 'render' );
|
|
|
|
|
sinon.stub( viewMock, 'destroy' );
|
|
|
|
|
vi.spyOn( viewMock, 'render' );
|
|
|
|
|
vi.spyOn( viewMock, 'destroy' );
|
|
|
|
|
|
|
|
|
|
mathUIFeature._showUI();
|
|
|
|
|
|
|
|
|
|
@ -370,27 +367,27 @@ describe( 'MathUI', () => {
|
|
|
|
|
balloon.add( { view: viewMock } );
|
|
|
|
|
editor.keystrokes.press( keyEvtData );
|
|
|
|
|
|
|
|
|
|
sinon.assert.notCalled( spy );
|
|
|
|
|
expect(spy).not.toHaveBeenCalled();
|
|
|
|
|
} );
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
describe( 'mouse support', () => {
|
|
|
|
|
it( 'should hide the UI and not focus editable upon clicking outside the UI', () => {
|
|
|
|
|
const spy = sinon.spy( mathUIFeature, '_hideUI' );
|
|
|
|
|
const spy = vi.spyOn( mathUIFeature, '_hideUI' );
|
|
|
|
|
|
|
|
|
|
mathUIFeature._showUI();
|
|
|
|
|
document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
|
|
|
|
|
|
|
|
|
|
sinon.assert.calledWithExactly( spy );
|
|
|
|
|
expect(spy).toHaveBeenCalledExactlyOnceWith();
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should not hide the UI upon clicking inside the the UI', () => {
|
|
|
|
|
const spy = sinon.spy( mathUIFeature, '_hideUI' );
|
|
|
|
|
const spy = vi.spyOn( mathUIFeature, '_hideUI' );
|
|
|
|
|
|
|
|
|
|
mathUIFeature._showUI();
|
|
|
|
|
balloon.view.element!.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
|
|
|
|
|
|
|
|
|
|
sinon.assert.notCalled( spy );
|
|
|
|
|
expect(spy).not.toHaveBeenCalled();
|
|
|
|
|
} );
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
@ -420,7 +417,7 @@ describe( 'MathUI', () => {
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should execute math command on mainFormView#submit event', () => {
|
|
|
|
|
const executeSpy = sinon.spy( editor, 'execute' );
|
|
|
|
|
const executeSpy = vi.spyOn( editor, 'execute' );
|
|
|
|
|
|
|
|
|
|
formView!.mathInputView.value = 'x^2';
|
|
|
|
|
expect( formView!.mathInputView.fieldView.element!.value ).to.equal( 'x^2' );
|
|
|
|
|
@ -428,8 +425,7 @@ describe( 'MathUI', () => {
|
|
|
|
|
formView!.mathInputView.fieldView.element!.value = 'x^2';
|
|
|
|
|
formView!.fire( 'submit' );
|
|
|
|
|
|
|
|
|
|
expect( executeSpy.calledOnce ).to.be.true;
|
|
|
|
|
expect( executeSpy.calledWith( 'math', 'x^2' ) ).to.be.true;
|
|
|
|
|
expect(executeSpy).toHaveBeenCalledExactlyOnceWith('math', 'x^2');
|
|
|
|
|
} );
|
|
|
|
|
|
|
|
|
|
it( 'should hide the balloon on mainFormView#cancel if math command does not have a value', () => {
|
|
|
|
|
@ -446,8 +442,8 @@ describe( 'MathUI', () => {
|
|
|
|
|
metaKey: false,
|
|
|
|
|
ctrlKey: false,
|
|
|
|
|
keyCode: keyCodes.esc,
|
|
|
|
|
preventDefault: sinon.spy(),
|
|
|
|
|
stopPropagation: sinon.spy()
|
|
|
|
|
preventDefault: vi.fn(),
|
|
|
|
|
stopPropagation: vi.fn()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
mathUIFeature._showUI();
|
|
|
|
|
@ -460,12 +456,12 @@ describe( 'MathUI', () => {
|
|
|
|
|
it( 'should blur math input element before hiding the view', () => {
|
|
|
|
|
mathUIFeature._showUI();
|
|
|
|
|
|
|
|
|
|
const focusSpy = sinon.spy( formView!.saveButtonView, 'focus' );
|
|
|
|
|
const removeSpy = sinon.spy( balloon, 'remove' );
|
|
|
|
|
const focusSpy = vi.spyOn( formView!.saveButtonView, 'focus' );
|
|
|
|
|
const removeSpy = vi.spyOn( balloon, 'remove' );
|
|
|
|
|
|
|
|
|
|
formView!.fire( 'cancel' );
|
|
|
|
|
|
|
|
|
|
expect( focusSpy.calledBefore( removeSpy ) ).to.equal( true );
|
|
|
|
|
expect(focusSpy).toHaveBeenCalledBefore(removeSpy);
|
|
|
|
|
} );
|
|
|
|
|
} );
|
|
|
|
|
} );
|
|
|
|
|
|