diff --git a/src/conversion/conversion.js b/src/conversion/conversion.js index 276d27d4c..1f8445b3d 100644 --- a/src/conversion/conversion.js +++ b/src/conversion/conversion.js @@ -8,6 +8,8 @@ */ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; +import UpcastHelpers from './upcasthelpers'; +import DowncastHelpers from './downcasthelpers'; /** * A utility class that helps add converters to upcast and downcast dispatchers. @@ -56,45 +58,69 @@ import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; export default class Conversion { /** * Creates a new conversion instance. + * + * @param {module:engine/conversion/downcastdispatcher~DowncastDispatcher| + * Array.} downcastDispatchers + * @param {module:engine/conversion/upcastdispatcher~UpcastDispatcher| + * Array.} upcastDispatchers */ - constructor() { + constructor( downcastDispatchers, upcastDispatchers ) { /** + * Maps dispatchers group name to ConversionHelpers instances. + * * @private - * @member {Map} + * @member {Map.} */ - this._conversionHelpers = new Map(); + this._helpers = new Map(); + + // Define default 'downcast' & 'upcast' dispatchers groups. Those groups are always available as two-way converters needs them. + this._downcast = Array.isArray( downcastDispatchers ) ? downcastDispatchers : [ downcastDispatchers ]; + this._createConversionHelpers( { name: 'downcast', dispatchers: this._downcast, isDowncast: true } ); + + this._upcast = Array.isArray( upcastDispatchers ) ? upcastDispatchers : [ upcastDispatchers ]; + this._createConversionHelpers( { name: 'upcast', dispatchers: this._upcast, isDowncast: false } ); + } /** - * Registers one or more converters under a given group name. The group name can then be used to assign a converter - * to multiple dispatchers at once. + * Define an alias for registered dispatcher. * - * If a given group name is used for the second time, the - * {@link module:utils/ckeditorerror~CKEditorError `conversion-register-group-exists` error} is thrown. + * const conversion = new Conversion( + * [ dataDowncastDispatcher, editingDowncastDispatcher ], + * upcastDispatcher + * ); * - * @param {String} name The name for dispatchers group. - * @param {module:engine/conversion/downcasthelpers~DowncastHelpers| - * module:engine/conversion/upcasthelpers~UpcastHelpers} conversionHelpers + * conversion.addAlias( 'dataDowncast', dataDowncastDispatcher ); + * + * @param {String} alias An alias of a dispatcher. + * @param {module:engine/conversion/downcastdispatcher~DowncastDispatcher| + * module:engine/conversion/upcastdispatcher~UpcastDispatcher} dispatcher Dispatcher which should have an alias. */ - register( name, conversionHelpers ) { - if ( this._conversionHelpers.has( name ) ) { + addAlias( alias, dispatcher ) { + const isDowncast = this._downcast.includes( dispatcher ); + const isUpcast = this._upcast.includes( dispatcher ); + + if ( !isUpcast && !isDowncast ) { /** - * Trying to register a group name that has already been registered. + * Trying to register and alias for a dispatcher that nas not been registered. * - * @error conversion-register-group-exists + * @error conversion-add-alias-dispatcher-not-registered */ - throw new CKEditorError( 'conversion-register-group-exists: Trying to register' + - 'a group name that has already been registered.' ); + throw new CKEditorError( 'conversion-add-alias-dispatcher-not-registered: ' + + 'Trying to register and alias for a dispatcher that nas not been registered.' ); } - this._conversionHelpers.set( name, conversionHelpers ); + this._createConversionHelpers( { name: alias, dispatchers: [ dispatcher ], isDowncast: isDowncast } ); } /** - * Provides a chainable API to assign converters to conversion dispatchers. + * Provides a chainable API to assign converters to conversion dispatchers group. + * + * If the given group name has not been registered, the + * {@link module:utils/ckeditorerror~CKEditorError `conversion-for-unknown-group` error} is thrown. * * You can use conversion helpers available directly in the `for()` chain or your custom ones via - * the {@link module:engine/conversion/conversion~ConversionHelpers#add `add()`} method. + * the {@link module:engine/conversion/conversionhelpers~ConversionHelpers#add `add()`} method. * * # Using bulit-in conversion helpers * @@ -149,7 +175,16 @@ export default class Conversion { * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers} */ for( groupName ) { - return this._getConversionHelpers( groupName ); + if ( !this._helpers.has( groupName ) ) { + /** + * Trying to add a converter to an unknown dispatchers group. + * + * @error conversion-for-unknown-group + */ + throw new CKEditorError( 'conversion-for-unknown-group: Trying to add a converter to an unknown dispatchers group.' ); + } + + return this._helpers.get( groupName ); } /** @@ -535,26 +570,28 @@ export default class Conversion { } /** - * Returns conversion helpers registered under a given name. - * - * If the given group name has not been registered, the - * {@link module:utils/ckeditorerror~CKEditorError `conversion-for-unknown-group` error} is thrown. + * Creates and caches conversion helpers for given dispatchers group. * * @private - * @param {String} groupName - * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers} + * @param {Object} options + * @param {String} options.name Group name. + * @param {Array.} options.dispatchers + * @param {Boolean} options.isDowncast */ - _getConversionHelpers( groupName ) { - if ( !this._conversionHelpers.has( groupName ) ) { + _createConversionHelpers( { name, dispatchers, isDowncast } ) { + if ( this._helpers.has( name ) ) { /** - * Trying to add a converter to an unknown dispatchers group. + * Trying to register a group name that has already been registered. * - * @error conversion-for-unknown-group + * @error conversion-group-exists */ - throw new CKEditorError( 'conversion-for-unknown-group: Trying to add a converter to an unknown dispatchers group.' ); + throw new CKEditorError( 'conversion-group-exists: Trying to register a group name that has already been registered.' ); } - return this._conversionHelpers.get( groupName ); + const helpers = isDowncast ? new DowncastHelpers( dispatchers ) : new UpcastHelpers( dispatchers ); + + this._helpers.set( name, helpers ); } } @@ -605,48 +642,3 @@ function* _getUpcastDefinition( model, view, upcastAlso ) { } } } - -/** - * Base class for conversion helpers. - */ -export class ConversionHelpers { - /** - * Creates a conversion helpers instance. - * - * @param {Array.} dispatcher - */ - constructor( dispatcher ) { - this._dispatchers = Array.isArray( dispatcher ) ? dispatcher : [ dispatcher ]; - } - - /** - * Registers a conversion helper. - * - * **Note**: See full usage example in the `{@link module:engine/conversion/conversion~Conversion#for conversion.for()}` - * method description. - * - * @param {Function} conversionHelper The function to be called on event. - * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers} - */ - add( conversionHelper ) { - this._addToDispatchers( conversionHelper ); - - return this; - } - - /** - * Helper function for the `Conversion` `.add()` method. - * - * Calls `conversionHelper` on each dispatcher from the group specified earlier in the `.for()` call, effectively - * adding converters to all specified dispatchers. - * - * @private - * @param {Function} conversionHelper - */ - _addToDispatchers( conversionHelper ) { - for ( const dispatcher of this._dispatchers ) { - conversionHelper( dispatcher ); - } - } -} diff --git a/src/conversion/conversionhelpers.js b/src/conversion/conversionhelpers.js new file mode 100644 index 000000000..c32dfd9cf --- /dev/null +++ b/src/conversion/conversionhelpers.js @@ -0,0 +1,40 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/** + * @module engine/conversion/conversionhelpers + */ + +/** + * Base class for conversion helpers. + */ +export default class ConversionHelpers { + /** + * Creates a conversion helpers instance. + * + * @param {Array.} dispatchers + */ + constructor( dispatchers ) { + this._dispatchers = dispatchers; + } + + /** + * Registers a conversion helper. + * + * **Note**: See full usage example in the `{@link module:engine/conversion/conversion~Conversion#for conversion.for()}` + * method description. + * + * @param {Function} conversionHelper The function to be called on event. + * @returns {module:engine/conversion/downcasthelpers~DowncastHelpers|module:engine/conversion/upcasthelpers~UpcastHelpers} + */ + add( conversionHelper ) { + for ( const dispatcher of this._dispatchers ) { + conversionHelper( dispatcher ); + } + + return this; + } +} diff --git a/src/conversion/downcasthelpers.js b/src/conversion/downcasthelpers.js index 6a8d3c392..7d4d16649 100644 --- a/src/conversion/downcasthelpers.js +++ b/src/conversion/downcasthelpers.js @@ -9,7 +9,7 @@ import ModelElement from '../model/element'; import ViewAttributeElement from '../view/attributeelement'; import DocumentSelection from '../model/documentselection'; -import { ConversionHelpers } from './conversion'; +import ConversionHelpers from './conversionhelpers'; import log from '@ckeditor/ckeditor5-utils/src/log'; import { cloneDeep } from 'lodash-es'; @@ -23,7 +23,7 @@ import { cloneDeep } from 'lodash-es'; /** * Downcast conversion helper functions. * - * @extends module:engine/conversion/conversion~ConversionHelpers + * @extends module:engine/conversion/conversionhelpers~ConversionHelpers */ export default class DowncastHelpers extends ConversionHelpers { /** diff --git a/src/conversion/upcasthelpers.js b/src/conversion/upcasthelpers.js index 3ab2eece9..f80a450a4 100644 --- a/src/conversion/upcasthelpers.js +++ b/src/conversion/upcasthelpers.js @@ -5,7 +5,7 @@ import Matcher from '../view/matcher'; import ModelRange from '../model/range'; -import { ConversionHelpers } from './conversion'; +import ConversionHelpers from './conversionhelpers'; import { cloneDeep } from 'lodash-es'; import ModelSelection from '../model/selection'; @@ -20,7 +20,7 @@ import ModelSelection from '../model/selection'; /** * Upcast conversion helper functions. * - * @extends module:engine/conversion/conversion~ConversionHelpers + * @extends module:engine/conversion/conversionhelpers~ConversionHelpers */ export default class UpcastHelpers extends ConversionHelpers { /** diff --git a/tests/controller/datacontroller.js b/tests/controller/datacontroller.js index 94cf42e75..fa8cc004c 100644 --- a/tests/controller/datacontroller.js +++ b/tests/controller/datacontroller.js @@ -39,8 +39,8 @@ describe( 'DataController', () => { data = new DataController( model, htmlDataProcessor ); - upcastHelpers = new UpcastHelpers( data.upcastDispatcher ); - downcastHelpers = new DowncastHelpers( data.downcastDispatcher ); + upcastHelpers = new UpcastHelpers( [ data.upcastDispatcher ] ); + downcastHelpers = new DowncastHelpers( [ data.downcastDispatcher ] ); } ); describe( 'constructor()', () => { diff --git a/tests/controller/editingcontroller.js b/tests/controller/editingcontroller.js index f287bdb83..074bf35f7 100644 --- a/tests/controller/editingcontroller.js +++ b/tests/controller/editingcontroller.js @@ -90,7 +90,7 @@ describe( 'EditingController', () => { model.schema.register( 'paragraph', { inheritAllFrom: '$block' } ); model.schema.register( 'div', { inheritAllFrom: '$block' } ); - const downcastHelpers = new DowncastHelpers( editing.downcastDispatcher ); + const downcastHelpers = new DowncastHelpers( [ editing.downcastDispatcher ] ); downcastHelpers.elementToElement( { model: 'paragraph', view: 'p' } ); downcastHelpers.elementToElement( { model: 'div', view: 'div' } ); diff --git a/tests/conversion/conversion.js b/tests/conversion/conversion.js index b32f65eef..a4d1c60f7 100644 --- a/tests/conversion/conversion.js +++ b/tests/conversion/conversion.js @@ -3,7 +3,7 @@ * For licensing, see LICENSE.md. */ -import Conversion, { ConversionHelpers } from '../../src/conversion/conversion'; +import Conversion from '../../src/conversion/conversion'; import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror'; import UpcastDispatcher from '../../src/conversion/upcastdispatcher'; @@ -17,35 +17,39 @@ import Model from '../../src/model/model'; import { parse as viewParse, stringify as viewStringify } from '../../src/dev-utils/view'; import { stringify as modelStringify } from '../../src/dev-utils/model'; +import ConversionHelpers from '../../src/conversion/conversionhelpers'; describe( 'Conversion', () => { - let conversion, dispA, dispB, dispC; + let conversion, downcastDispA, upcastDispaA, downcastDispB; beforeEach( () => { - conversion = new Conversion(); - // Placeholders. Will be used only to see if their were given as attribute for a spy function. - dispA = Symbol( 'dispA' ); - dispB = Symbol( 'dispB' ); - dispC = Symbol( 'dispC' ); - - conversion.register( 'ab', new UpcastHelpers( [ dispA, dispB ] ) ); - conversion.register( 'a', new UpcastHelpers( dispA ) ); - conversion.register( 'b', new UpcastHelpers( dispB ) ); - conversion.register( 'c', new DowncastHelpers( dispC ) ); + downcastDispA = Symbol( 'downA' ); + downcastDispB = Symbol( 'downB' ); + + upcastDispaA = Symbol( 'upA' ); + + conversion = new Conversion( [ downcastDispA, downcastDispB ], upcastDispaA ); } ); - describe( 'register()', () => { + describe( 'addAlias()', () => { it( 'should throw when trying to use same group name twice', () => { expect( () => { - conversion.register( 'ab' ); - } ).to.throw( CKEditorError, /conversion-register-group-exists/ ); + conversion.addAlias( 'upcast', upcastDispaA ); + } ).to.throw( CKEditorError, /conversion-group-exists/ ); + } ); + + it( 'should throw when trying to add not registered dispatcher', () => { + expect( () => { + conversion.addAlias( 'foo', {} ); + } ).to.throw( CKEditorError, /conversion-add-alias-dispatcher-not-registered/ ); } ); } ); describe( 'for()', () => { it( 'should return ConversionHelpers', () => { - expect( conversion.for( 'ab' ) ).to.be.instanceof( ConversionHelpers ); + expect( conversion.for( 'upcast' ) ).to.be.instanceof( ConversionHelpers ); + expect( conversion.for( 'downcast' ) ).to.be.instanceof( ConversionHelpers ); } ); it( 'should throw if non-existing group name has been used', () => { @@ -55,10 +59,15 @@ describe( 'Conversion', () => { } ); it( 'should return proper helpers for group', () => { - expect( conversion.for( 'ab' ) ).to.be.instanceof( UpcastHelpers ); - expect( conversion.for( 'a' ) ).to.be.instanceof( UpcastHelpers ); - expect( conversion.for( 'b' ) ).to.be.instanceof( UpcastHelpers ); - expect( conversion.for( 'c' ) ).to.be.instanceof( DowncastHelpers ); + expect( conversion.for( 'upcast' ) ).to.be.instanceof( UpcastHelpers ); + + conversion.addAlias( 'foo', upcastDispaA ); + expect( conversion.for( 'foo' ) ).to.be.instanceof( UpcastHelpers ); + + expect( conversion.for( 'downcast' ) ).to.be.instanceof( DowncastHelpers ); + + conversion.addAlias( 'bar', downcastDispB ); + expect( conversion.for( 'bar' ) ).to.be.instanceof( DowncastHelpers ); } ); } ); @@ -71,22 +80,24 @@ describe( 'Conversion', () => { } ); it( 'should be chainable', () => { - const forResult = conversion.for( 'ab' ); - const addResult = forResult.add( () => {} ); + const helpers = conversion.for( 'upcast' ); + const addResult = helpers.add( () => {} ); - expect( addResult ).to.equal( addResult.add( () => {} ) ); + expect( addResult ).to.equal( helpers ); } ); it( 'should fire given helper for every dispatcher in given group', () => { - conversion.for( 'ab' ).add( helperA ); + conversion.for( 'downcast' ).add( helperA ); - expect( helperA.calledWithExactly( dispA ) ).to.be.true; - expect( helperA.calledWithExactly( dispB ) ).to.be.true; + expect( helperA.calledWithExactly( downcastDispA ) ).to.be.true; + expect( helperA.calledWithExactly( downcastDispB ) ).to.be.true; + expect( helperA.calledWithExactly( upcastDispaA ) ).to.be.false; - conversion.for( 'b' ).add( helperB ); + conversion.for( 'upcast' ).add( helperB ); - expect( helperB.calledWithExactly( dispA ) ).to.be.false; - expect( helperB.calledWithExactly( dispB ) ).to.be.true; + expect( helperB.calledWithExactly( downcastDispA ) ).to.be.false; + expect( helperB.calledWithExactly( downcastDispB ) ).to.be.false; + expect( helperB.calledWithExactly( upcastDispaA ) ).to.be.true; } ); } ); @@ -121,9 +132,7 @@ describe( 'Conversion', () => { viewDispatcher.on( 'element', convertToModelFragment(), { priority: 'lowest' } ); viewDispatcher.on( 'documentFragment', convertToModelFragment(), { priority: 'lowest' } ); - conversion = new Conversion(); - conversion.register( 'upcast', new UpcastHelpers( [ viewDispatcher ] ) ); - conversion.register( 'downcast', new DowncastHelpers( controller.downcastDispatcher ) ); + conversion = new Conversion( controller.downcastDispatcher, viewDispatcher ); } ); describe( 'elementToElement', () => { @@ -696,38 +705,3 @@ describe( 'Conversion', () => { } } ); } ); - -describe( 'ConversionHelpers', () => { - describe( 'add()', () => { - const dispA = Symbol( 'dispA' ); - const dispB = Symbol( 'dispB' ); - - it( 'should call a helper for one defined dispatcher', () => { - const spy = sinon.spy(); - const helpers = new ConversionHelpers( dispA ); - - helpers.add( spy ); - - sinon.assert.calledOnce( spy ); - sinon.assert.calledWithExactly( spy, dispA ); - } ); - - it( 'should call helper for all defined dispatcherers', () => { - const spy = sinon.spy(); - const helpers = new ConversionHelpers( [ dispA, dispB ] ); - - helpers.add( spy ); - - sinon.assert.calledTwice( spy ); - sinon.assert.calledWithExactly( spy, dispA ); - sinon.assert.calledWithExactly( spy, dispB ); - } ); - - it( 'should be chainable', () => { - const spy = sinon.spy(); - const helpers = new ConversionHelpers( dispA ); - - expect( helpers.add( spy ) ).to.equal( helpers ); - } ); - } ); -} ); diff --git a/tests/conversion/conversionhelpers.js b/tests/conversion/conversionhelpers.js new file mode 100644 index 000000000..6f97d6e10 --- /dev/null +++ b/tests/conversion/conversionhelpers.js @@ -0,0 +1,41 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +import ConversionHelpers from '../../src/conversion/conversionhelpers'; + +describe( 'ConversionHelpers', () => { + describe( 'add()', () => { + const dispA = Symbol( 'dispA' ); + const dispB = Symbol( 'dispB' ); + + it( 'should call a helper for one defined dispatcher', () => { + const spy = sinon.spy(); + const helpers = new ConversionHelpers( [ dispA ] ); + + helpers.add( spy ); + + sinon.assert.calledOnce( spy ); + sinon.assert.calledWithExactly( spy, dispA ); + } ); + + it( 'should call helper for all defined dispatcherers', () => { + const spy = sinon.spy(); + const helpers = new ConversionHelpers( [ dispA, dispB ] ); + + helpers.add( spy ); + + sinon.assert.calledTwice( spy ); + sinon.assert.calledWithExactly( spy, dispA ); + sinon.assert.calledWithExactly( spy, dispB ); + } ); + + it( 'should be chainable', () => { + const spy = sinon.spy(); + const helpers = new ConversionHelpers( [ dispA ] ); + + expect( helpers.add( spy ) ).to.equal( helpers ); + } ); + } ); +} ); diff --git a/tests/conversion/downcasthelpers.js b/tests/conversion/downcasthelpers.js index fa0f6b231..1dcc6594b 100644 --- a/tests/conversion/downcasthelpers.js +++ b/tests/conversion/downcasthelpers.js @@ -5,8 +5,6 @@ import EditingController from '../../src/controller/editingcontroller'; -import Conversion from '../../src/conversion/conversion'; - import Model from '../../src/model/model'; import ModelElement from '../../src/model/element'; import ModelText from '../../src/model/text'; @@ -36,7 +34,7 @@ import createViewRoot from '../view/_utils/createroot'; import { setData as setModelData } from '../../src/dev-utils/model'; describe( 'DowncastHelpers', () => { - let conversion, model, modelRoot, viewRoot, downcastHelpers, controller; + let model, modelRoot, viewRoot, downcastHelpers, controller; let modelRootStart; @@ -53,10 +51,7 @@ describe( 'DowncastHelpers', () => { viewRoot = controller.view.document.getRoot(); - downcastHelpers = new DowncastHelpers( controller.downcastDispatcher ); - - conversion = new Conversion(); - conversion.register( 'downcast', downcastHelpers ); + downcastHelpers = new DowncastHelpers( [ controller.downcastDispatcher ] ); modelRootStart = model.createPositionAt( modelRoot, 0 ); } ); @@ -1474,7 +1469,7 @@ describe( 'downcast converters', () => { controller.view.document.getRoot()._name = 'div'; dispatcher = controller.downcastDispatcher; - const downcastHelpers = new DowncastHelpers( dispatcher ); + const downcastHelpers = new DowncastHelpers( [ dispatcher ] ); downcastHelpers.elementToElement( { model: 'paragraph', view: 'p' } ); modelRootStart = model.createPositionAt( modelRoot, 0 ); @@ -1630,7 +1625,7 @@ describe( 'downcast converters', () => { const modelP = new ModelElement( 'paragraph', null, new ModelText( 'foo' ) ); const modelWidget = new ModelElement( 'widget', null, modelP ); - const downcastHelpers = new DowncastHelpers( dispatcher ); + const downcastHelpers = new DowncastHelpers( [ dispatcher ] ); downcastHelpers.elementToElement( { model: 'widget', view: 'widget' } ); model.change( writer => { @@ -1806,7 +1801,7 @@ describe( 'downcast selection converters', () => { dispatcher.on( 'insert:$text', insertText() ); - downcastHelpers = new DowncastHelpers( dispatcher ); + downcastHelpers = new DowncastHelpers( [ dispatcher ] ); downcastHelpers.attributeToElement( { model: 'bold', view: 'strong' } ); downcastHelpers.markerToHighlight( { model: 'marker', view: { classes: 'marker' }, converterPriority: 1 } ); @@ -2253,7 +2248,7 @@ describe( 'downcast selection converters', () => { model.schema.extend( 'td', { allowIn: 'tr' } ); model.schema.extend( '$text', { allowIn: 'td' } ); - const downcastHelpers = new DowncastHelpers( dispatcher ); + const downcastHelpers = new DowncastHelpers( [ dispatcher ] ); // "Universal" converter to convert table structure. downcastHelpers.elementToElement( { model: 'table', view: 'table' } ); diff --git a/tests/conversion/upcasthelpers.js b/tests/conversion/upcasthelpers.js index 4b8ab5f2b..99cb62254 100644 --- a/tests/conversion/upcasthelpers.js +++ b/tests/conversion/upcasthelpers.js @@ -3,7 +3,6 @@ * For licensing, see LICENSE.md. */ -import Conversion from '../../src/conversion/conversion'; import UpcastDispatcher from '../../src/conversion/upcastdispatcher'; import ViewContainerElement from '../../src/view/containerelement'; @@ -30,7 +29,7 @@ import ViewSelection from '../../src/view/selection'; import ViewRange from '../../src/view/range'; describe( 'UpcastHelpers', () => { - let upcastDispatcher, model, schema, conversion, upcastHelpers; + let upcastDispatcher, model, schema, upcastHelpers; beforeEach( () => { model = new Model(); @@ -51,9 +50,7 @@ describe( 'UpcastHelpers', () => { upcastDispatcher.on( 'element', convertToModelFragment(), { priority: 'lowest' } ); upcastDispatcher.on( 'documentFragment', convertToModelFragment(), { priority: 'lowest' } ); - conversion = new Conversion(); - upcastHelpers = new UpcastHelpers( upcastDispatcher ); - conversion.register( 'upcast', upcastHelpers ); + upcastHelpers = new UpcastHelpers( [ upcastDispatcher ] ); } ); describe( '.elementToElement()', () => {