editor.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /**
  2. * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /* bender-include: ../_tools/tools.js */
  6. 'use strict';
  7. const modules = bender.amd.require( 'core/editor', 'core/editorconfig', 'core/plugin' );
  8. let Editor, EditorConfig, Plugin;
  9. let editor;
  10. let element;
  11. let asyncSpy;
  12. before( () => {
  13. Editor = modules[ 'core/editor' ];
  14. EditorConfig = modules[ 'core/editorconfig' ];
  15. Plugin = modules[ 'core/plugin' ];
  16. } );
  17. beforeEach( () => {
  18. element = document.createElement( 'div' );
  19. document.body.appendChild( element );
  20. editor = new Editor( element );
  21. } );
  22. before( () => {
  23. // Define fake plugins to be used in tests.
  24. bender.tools.core.defineEditorCreatorMock( 'test', {
  25. init: sinon.spy().named( 'creator-test' )
  26. } );
  27. bender.amd.define( 'A', [ 'core/plugin' ], pluginDefinition( 'A' ) );
  28. bender.amd.define( 'B', [ 'core/plugin' ], pluginDefinition( 'B' ) );
  29. bender.amd.define( 'C', [ 'core/plugin', 'B' ], pluginDefinition( 'C' ) );
  30. bender.amd.define( 'D', [ 'core/plugin', 'C' ], pluginDefinition( 'D' ) );
  31. bender.amd.define( 'E', [ 'core/plugin' ], pluginDefinition( 'E' ) );
  32. // Synchronous plugin that depends on an asynchronous one.
  33. bender.amd.define( 'F', [ 'core/plugin', 'async' ], pluginDefinition( 'F' ) );
  34. asyncSpy = sinon.spy().named( 'async-call-spy' );
  35. bender.amd.define( 'async', [ 'core/plugin' ], ( Plugin ) => {
  36. class PluginAsync extends Plugin {}
  37. PluginAsync.prototype.init = sinon.spy( () => {
  38. return new Promise( ( resolve ) => {
  39. setTimeout( () => {
  40. asyncSpy();
  41. resolve();
  42. }, 0 );
  43. } );
  44. } );
  45. return PluginAsync;
  46. } );
  47. } );
  48. function pluginDefinition( name ) {
  49. return ( Plugin ) => {
  50. class NewPlugin extends Plugin {}
  51. NewPlugin.prototype.init = sinon.spy().named( name );
  52. return NewPlugin;
  53. };
  54. }
  55. ///////////////////
  56. describe( 'constructor', () => {
  57. it( 'should create a new editor instance', () => {
  58. expect( editor ).to.have.property( 'element' ).to.equal( element );
  59. } );
  60. } );
  61. describe( 'config', () => {
  62. it( 'should be an instance of EditorConfig', () => {
  63. expect( editor.config ).to.be.an.instanceof( EditorConfig );
  64. } );
  65. } );
  66. describe( 'init', () => {
  67. it( 'should return a promise that resolves properly', () => {
  68. editor = new Editor( element, {
  69. plugins: 'creator-test'
  70. } );
  71. let promise = editor.init();
  72. expect( promise ).to.be.an.instanceof( Promise );
  73. return promise;
  74. } );
  75. it( 'should fill `plugins`', () => {
  76. editor = new Editor( element, {
  77. plugins: 'A,B,creator-test'
  78. } );
  79. expect( editor.plugins.length ).to.equal( 0 );
  80. return editor.init().then( () => {
  81. expect( editor.plugins.length ).to.equal( 3 );
  82. expect( editor.plugins.get( 'A' ) ).to.be.an.instanceof( Plugin );
  83. expect( editor.plugins.get( 'B' ) ).to.be.an.instanceof( Plugin );
  84. expect( editor.plugins.get( 'creator-test' ) ).to.be.an.instanceof( Plugin );
  85. } );
  86. } );
  87. it( 'should initialize plugins in the right order', () => {
  88. editor = new Editor( element, {
  89. plugins: 'creator-test,A,D'
  90. } );
  91. return editor.init().then( () => {
  92. sinon.assert.callOrder(
  93. editor.plugins.get( 'creator-test' ).init,
  94. editor.plugins.get( 'A' ).init,
  95. editor.plugins.get( 'B' ).init,
  96. editor.plugins.get( 'C' ).init,
  97. editor.plugins.get( 'D' ).init
  98. );
  99. } );
  100. } );
  101. it( 'should initialize plugins in the right order, waiting for asynchronous ones', () => {
  102. editor = new Editor( element, {
  103. plugins: 'creator-test,A,F'
  104. } );
  105. return editor.init().then( () => {
  106. sinon.assert.callOrder(
  107. editor.plugins.get( 'creator-test' ).init,
  108. editor.plugins.get( 'A' ).init,
  109. editor.plugins.get( 'async' ).init,
  110. // This one is called with delay by the async init.
  111. asyncSpy,
  112. editor.plugins.get( 'F' ).init
  113. );
  114. } );
  115. } );
  116. it( 'should not fail if loading a plugin that doesn\'t define init()', () => {
  117. editor = new Editor( element, {
  118. plugins: 'E,creator-test'
  119. } );
  120. return editor.init();
  121. } );
  122. } );
  123. describe( 'plugins', () => {
  124. it( 'should be empty on new editor', () => {
  125. expect( editor.plugins.length ).to.equal( 0 );
  126. } );
  127. } );
  128. describe( 'destroy', () => {
  129. it( 'should fire "destroy"', () => {
  130. let spy = sinon.spy();
  131. editor.on( 'destroy', spy );
  132. return editor.destroy().then( () => {
  133. sinon.assert.called( spy );
  134. } );
  135. } );
  136. it( 'should delete the "element" property', () => {
  137. return editor.destroy().then( () => {
  138. expect( editor ).to.not.have.property( 'element' );
  139. } );
  140. } );
  141. } );