8
0

creator.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. 'use strict';
  6. /* bender-tags: editor, creator */
  7. import moduleUtils from '/tests/_utils/module.js';
  8. import testUtils from '/tests/_utils/utils.js';
  9. import coreTestUtils from '/tests/core/_utils/utils.js';
  10. import Editor from '/ckeditor5/core/editor.js';
  11. import Creator from '/ckeditor5/core/creator.js';
  12. import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
  13. let editor, element;
  14. function initEditor( config ) {
  15. element = document.createElement( 'div' );
  16. document.body.appendChild( element );
  17. editor = new Editor( element, config );
  18. return editor.init();
  19. }
  20. testUtils.createSinonSandbox();
  21. before( () => {
  22. coreTestUtils.defineEditorCreatorMock( 'test1', {
  23. create: sinon.spy(),
  24. destroy: sinon.spy()
  25. } );
  26. coreTestUtils.defineEditorCreatorMock( 'test-throw-on-many1' );
  27. coreTestUtils.defineEditorCreatorMock( 'test-throw-on-many2' );
  28. coreTestUtils.defineEditorCreatorMock( 'test-config1', {
  29. create: sinon.spy()
  30. } );
  31. coreTestUtils.defineEditorCreatorMock( 'test-config2', {
  32. create: sinon.spy()
  33. } );
  34. moduleUtils.define( 'test3', [ 'core/plugin' ], ( Plugin ) => {
  35. return class extends Plugin {};
  36. } );
  37. moduleUtils.define( 'creator-async-create', [ 'core/creator' ], ( Creator ) => {
  38. return class extends Creator {
  39. create() {
  40. return new Promise( ( resolve, reject ) => {
  41. reject( new Error( 'Catch me - create.' ) );
  42. } );
  43. }
  44. destroy() {}
  45. };
  46. } );
  47. moduleUtils.define( 'creator-async-destroy', [ 'core/creator' ], ( Creator ) => {
  48. return class extends Creator {
  49. create() {}
  50. destroy() {
  51. return new Promise( ( resolve, reject ) => {
  52. reject( new Error( 'Catch me - destroy.' ) );
  53. } );
  54. }
  55. };
  56. } );
  57. moduleUtils.define( 'creator-destroy-order', [ 'core/creator' ], ( Creator ) => {
  58. return class extends Creator {
  59. create() {}
  60. destroy() {
  61. editor._elementInsideCreatorDestroy = this.editor.element;
  62. editor._destroyOrder.push( 'creator' );
  63. }
  64. };
  65. } );
  66. } );
  67. afterEach( () => {
  68. editor = null; // To make sure we're using the freshly inited editor.
  69. } );
  70. ///////////////////
  71. describe( 'init', () => {
  72. it( 'should instantiate the creator and call create()', () => {
  73. return initEditor( {
  74. creator: 'creator-test1'
  75. } )
  76. .then( () => {
  77. let creator = editor.plugins.get( 'creator-test1' );
  78. expect( creator ).to.be.instanceof( Creator );
  79. // The create method has been called.
  80. sinon.assert.calledOnce( creator.create );
  81. } );
  82. } );
  83. it( 'should throw if creator is not defined', () => {
  84. return initEditor( {} )
  85. .then( () => {
  86. throw new Error( 'This should not be executed.' );
  87. } )
  88. .catch( ( err ) => {
  89. expect( err ).to.be.instanceof( CKEditorError );
  90. expect( err.message ).to.match( /^editor-undefined-creator:/ );
  91. } );
  92. } );
  93. it( 'should use the creator specified in config.creator', () => {
  94. return initEditor( {
  95. creator: 'creator-test-config2',
  96. features: [ 'creator-test-config1', 'creator-test-config2' ],
  97. } )
  98. .then( () => {
  99. let creator1 = editor.plugins.get( 'creator-test-config1' );
  100. let creator2 = editor.plugins.get( 'creator-test-config2' );
  101. sinon.assert.calledOnce( creator2.create );
  102. sinon.assert.notCalled( creator1.create );
  103. } );
  104. } );
  105. it( 'should throw an error if the creator doesn\'t exist', () => {
  106. return initEditor( {
  107. creator: 'bad'
  108. } )
  109. .then( () => {
  110. throw new Error( 'This should not be executed.' );
  111. } )
  112. .catch( ( err ) => {
  113. // It's the Require.JS error.
  114. expect( err ).to.be.an.instanceof( Error );
  115. expect( err.message ).to.match( /^Script error for/ );
  116. } );
  117. } );
  118. it( 'should chain the promise from the creator (enables async creators)', () => {
  119. return initEditor( {
  120. creator: 'creator-async-create'
  121. } )
  122. .then( () => {
  123. throw new Error( 'This should not be executed.' );
  124. } )
  125. .catch( ( err ) => {
  126. // Unfortunately fake timers don't work with promises, so throwing in the creator's create()
  127. // seems to be the only way to test that the promise chain isn't broken.
  128. expect( err ).to.have.property( 'message', 'Catch me - create.' );
  129. } );
  130. } );
  131. } );
  132. describe( 'destroy', () => {
  133. it( 'should call "destroy" on the creator', () => {
  134. let creator1;
  135. return initEditor( {
  136. creator: 'creator-test1'
  137. } )
  138. .then( () => {
  139. creator1 = editor.plugins.get( 'creator-test1' );
  140. return editor.destroy();
  141. } )
  142. .then( () => {
  143. sinon.assert.calledOnce( creator1.destroy );
  144. } );
  145. } );
  146. it( 'should chain the promise from the creator (enables async creators)', () => {
  147. return initEditor( {
  148. creator: 'creator-async-destroy'
  149. } )
  150. .then( () => {
  151. return editor.destroy();
  152. } )
  153. .then( () => {
  154. throw new Error( 'This should not be executed.' );
  155. } )
  156. .catch( ( err ) => {
  157. // Unfortunately fake timers don't work with promises, so throwing in the creator's destroy()
  158. // seems to be the only way to test that the promise chain isn't broken.
  159. expect( err ).to.have.property( 'message', 'Catch me - destroy.' );
  160. } );
  161. } );
  162. it( 'should do things in the correct order', () => {
  163. return initEditor( {
  164. creator: 'creator-destroy-order'
  165. } )
  166. .then( () => {
  167. editor._destroyOrder = [];
  168. editor.on( 'destroy', () => {
  169. editor._destroyOrder.push( 'event' );
  170. } );
  171. return editor.destroy();
  172. } )
  173. .then( () => {
  174. expect( editor._elementInsideCreatorDestroy ).to.not.be.undefined;
  175. expect( editor._destroyOrder ).to.deep.equal( [ 'event', 'creator' ] );
  176. } );
  177. } );
  178. } );