Explorar o código

Merge branch 't/58'

Other: `FileRepository` will automatically warn when it's initialized but no upload adapter was enabled. Closes #58.
Piotrek Koszuliński %!s(int64=8) %!d(string=hai) anos
pai
achega
d99395c96b

+ 110 - 53
packages/ckeditor5-upload/src/filerepository.js

@@ -20,7 +20,17 @@ import FileReader from './filereader.js';
 import uid from '@ckeditor/ckeditor5-utils/src/uid.js';
 import uid from '@ckeditor/ckeditor5-utils/src/uid.js';
 
 
 /**
 /**
- * FileRepository plugin.
+ * File repository plugin. A central point for managing file upload.
+ *
+ * To use it, first you need an upload adapter. Upload adapter's job is to handle communication with the server
+ * (sending the file and handling server's response). You can use one of the existing plugins introducing upload adapters
+ * (e.g. {@link module:easy-image/cloudservicesuploadadapter~CloudServicesUploadAdapter} or
+ * {@link module:adapter-ckfinder/uploadadapter~CKFinderUploadAdapter}) or write your own one
+ * (which boils down to setting the {@link ~FileRepository#createAdapter} factory function – see
+ * {@link ~Adapter `Adapter` interface} documentation).
+ *
+ * Then, you can use {@link ~FileRepository#createLoader `createLoader()`} and the returned {@link ~FileLoader} instance to
+ * load and upload files.
  *
  *
  * @extends module:core/plugin~Plugin
  * @extends module:core/plugin~Plugin
  */
  */
@@ -44,15 +54,15 @@ export default class FileRepository extends Plugin {
 		this.loaders = new Collection();
 		this.loaders = new Collection();
 
 
 		/**
 		/**
-		 * Function that should be defined before using FileRepository. It should return new instance of
-		 * {@link module:upload/filerepository~Adapter Adapter} that will be used to upload files.
-		 * {@link module:upload/filerepository~FileLoader FileLoader} instance associated with the adapter
+		 * A factory function which should be defined before using `FileRepository`.
+		 *
+		 * It should return a new instance of {@link module:upload/filerepository~Adapter} that will be used to upload files.
+		 * {@link module:upload/filerepository~FileLoader} instance associated with the adapter
 		 * will be passed to that function.
 		 * will be passed to that function.
-		 * For more information and example see {@link module:upload/filerepository~Adapter Adapter}.
 		 *
 		 *
-		 * @abstract
-		 * @function
-		 * @name #createAdapter
+		 * For more information and example see {@link module:upload/filerepository~Adapter}.
+		 *
+		 * @member {Function} #createAdapter
 		 */
 		 */
 
 
 		/**
 		/**
@@ -66,6 +76,7 @@ export default class FileRepository extends Plugin {
 
 
 		/**
 		/**
 		 * Number of total bytes to upload.
 		 * Number of total bytes to upload.
+		 *
 		 * It might be different than the file size because of headers and additional data.
 		 * It might be different than the file size because of headers and additional data.
 		 * It contains `null` if value is not available yet, so it's better to use {@link #uploadedPercent} to monitor
 		 * It contains `null` if value is not available yet, so it's better to use {@link #uploadedPercent} to monitor
 		 * the progress.
 		 * the progress.
@@ -88,11 +99,49 @@ export default class FileRepository extends Plugin {
 		} );
 		} );
 	}
 	}
 
 
+	afterInit() {
+		if ( !this.createAdapter ) {
+			/**
+			 * You need to enable an upload adapter in order to be able to upload files.
+			 *
+			 * This warning shows up when {@link module:upload/filerepository~FileRepository} is being used
+			 * without {@link #createAdapter definining an upload adapter}.
+			 *
+			 * If you see this warning when using one of the {@glink builds/index CKEditor 5 Builds}
+			 * it means that you did not configure any of the upload adapters available by default in those builds.
+			 * See:
+			 *
+			 * * {@link module:core/editor/editorconfig~EditorConfig#cloudServices `config.cloudServices`} for
+			 * Easy Image with Cloud Services integration,
+			 * * {@link module:core/editor/editorconfig~EditorConfig#ckfinder `config.ckfinder`} for CKFinder
+			 * file upload integration.
+			 *
+			 * If you do not need file upload functionality at all and you use one of the builds, you can disable the built-in
+			 * upload adapters to hide this warning:
+			 *
+			 *		ClassicEditor
+			 *			.create( document.querySelector( '#editor' ), {
+			 * 				removePlugins: [ 'EasyImage', 'CKFinderUploadAdapter' ]
+			 *			} )
+			 *			.then( ... )
+			 *			.catch( ... );
+			 *
+			 * If you wish to implement your own upload adapter refer to the {@link ~Adapter `Adapter` interface} documentation.
+			 *
+			 * @error filerepository-no-adapter
+			 */
+			log.warn( 'filerepository-no-adapter: Upload adapter is not defined.' );
+
+			return null;
+		}
+	}
+
 	/**
 	/**
 	 * Returns the loader associated with specified file.
 	 * Returns the loader associated with specified file.
+	 *
 	 * To get loader by id use `fileRepository.loaders.get( id )`.
 	 * To get loader by id use `fileRepository.loaders.get( id )`.
 	 *
 	 *
-	 * @param {File} file Native File object.
+	 * @param {File} file Native file handle.
 	 * @returns {module:upload/filerepository~FileLoader|null}
 	 * @returns {module:upload/filerepository~FileLoader|null}
 	 */
 	 */
 	getLoader( file ) {
 	getLoader( file ) {
@@ -106,15 +155,16 @@ export default class FileRepository extends Plugin {
 	}
 	}
 
 
 	/**
 	/**
-	 * Creates loader for specified file.
-	 * Shows console warning and returns `null` if {@link #createAdapter} method is not defined.
+	 * Creates a loader instance for the given file.
+	 *
+	 * Requires {@link #createAdapter} factory to be defined.
 	 *
 	 *
 	 * @param {File} file Native File object.
 	 * @param {File} file Native File object.
 	 * @returns {module:upload/filerepository~FileLoader|null}
 	 * @returns {module:upload/filerepository~FileLoader|null}
 	 */
 	 */
 	createLoader( file ) {
 	createLoader( file ) {
 		if ( !this.createAdapter ) {
 		if ( !this.createAdapter ) {
-			log.warn( 'FileRepository: no createAdapter method found. Please define it before creating a loader.' );
+			log.error( 'filerepository-no-adapter: Upload adapter is not defined.' );
 
 
 			return null;
 			return null;
 		}
 		}
@@ -150,7 +200,7 @@ export default class FileRepository extends Plugin {
 	}
 	}
 
 
 	/**
 	/**
-	 * Destroys loader.
+	 * Destroys the given loader.
 	 *
 	 *
 	 * @param {File|module:upload/filerepository~FileLoader} fileOrLoader File associated with that loader or loader
 	 * @param {File|module:upload/filerepository~FileLoader} fileOrLoader File associated with that loader or loader
 	 * itself.
 	 * itself.
@@ -172,9 +222,9 @@ mix( FileRepository, ObservableMixin );
  */
  */
 class FileLoader {
 class FileLoader {
 	/**
 	/**
-	 * Creates instance of FileLoader.
+	 * Creates a new instance of `FileLoader`.
 	 *
 	 *
-	 * @param {File} file
+	 * @param {File} file A native file instance.
 	 * @param {module:upload/filerepository~Adapter} adapter
 	 * @param {module:upload/filerepository~Adapter} adapter
 	 */
 	 */
 	constructor( file, adapter ) {
 	constructor( file, adapter ) {
@@ -187,7 +237,7 @@ class FileLoader {
 		this.id = uid();
 		this.id = uid();
 
 
 		/**
 		/**
-		 * File instance associated with FileLoader.
+		 * A `File` instance associated with this file loader.
 		 *
 		 *
 		 * @readonly
 		 * @readonly
 		 * @member {File}
 		 * @member {File}
@@ -195,7 +245,7 @@ class FileLoader {
 		this.file = file;
 		this.file = file;
 
 
 		/**
 		/**
-		 * Adapter instance associated with FileLoader.
+		 * Adapter instance associated with this file loader.
 		 *
 		 *
 		 * @private
 		 * @private
 		 * @member {module:upload/filerepository~Adapter}
 		 * @member {module:upload/filerepository~Adapter}
@@ -212,6 +262,7 @@ class FileLoader {
 
 
 		/**
 		/**
 		 * Current status of FileLoader. It can be one of the following:
 		 * Current status of FileLoader. It can be one of the following:
+		 *
 		 * * 'idle',
 		 * * 'idle',
 		 * * 'reading',
 		 * * 'reading',
 		 * * 'uploading',
 		 * * 'uploading',
@@ -219,11 +270,13 @@ class FileLoader {
 		 * * 'error'.
 		 * * 'error'.
 		 *
 		 *
 		 * When reading status can change in a following way:
 		 * When reading status can change in a following way:
+		 *
 		 * `idle` -> `reading` -> `idle`
 		 * `idle` -> `reading` -> `idle`
 		 * `idle` -> `reading -> `aborted`
 		 * `idle` -> `reading -> `aborted`
 		 * `idle` -> `reading -> `error`
 		 * `idle` -> `reading -> `error`
 		 *
 		 *
 		 * When uploading status can change in a following way:
 		 * When uploading status can change in a following way:
+		 *
 		 * `idle` -> `uploading` -> `idle`
 		 * `idle` -> `uploading` -> `idle`
 		 * `idle` -> `uploading` -> `aborted`
 		 * `idle` -> `uploading` -> `aborted`
 		 * `idle` -> `uploading` -> `error`
 		 * `idle` -> `uploading` -> `error`
@@ -275,17 +328,19 @@ class FileLoader {
 
 
 	/**
 	/**
 	 * Reads file using {@link module:upload/filereader~FileReader}.
 	 * Reads file using {@link module:upload/filereader~FileReader}.
+	 *
 	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-read-wrong-status` when status
 	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-read-wrong-status` when status
 	 * is different than `idle`.
 	 * is different than `idle`.
+	 *
 	 * Example usage:
 	 * Example usage:
 	 *
 	 *
 	 *	fileLoader.read()
 	 *	fileLoader.read()
 	 *		.then( data => { ... } )
 	 *		.then( data => { ... } )
-	 *		.catch( e => {
-	 *			if ( e === 'aborted' ) {
+	 *		.catch( err => {
+	 *			if ( err === 'aborted' ) {
 	 *				console.log( 'Reading aborted.' );
 	 *				console.log( 'Reading aborted.' );
 	 *			} else {
 	 *			} else {
-	 *				console.log( 'Reading error.', e );
+	 *				console.log( 'Reading error.', err );
 	 *			}
 	 *			}
 	 *		} );
 	 *		} );
 	 *
 	 *
@@ -317,7 +372,8 @@ class FileLoader {
 	}
 	}
 
 
 	/**
 	/**
-	 * Reads file using provided {@link module:upload/filerepository~Adapter}.
+	 * Reads file using the provided {@link module:upload/filerepository~Adapter}.
+	 *
 	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-upload-wrong-status` when status
 	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `filerepository-upload-wrong-status` when status
 	 * is different than `idle`.
 	 * is different than `idle`.
 	 * Example usage:
 	 * Example usage:
@@ -398,39 +454,40 @@ mix( FileLoader, ObservableMixin );
  * handles file uploads. It should contain logic necessary to initiate upload process and monitor its progress.
  * handles file uploads. It should contain logic necessary to initiate upload process and monitor its progress.
  *
  *
  * It should implement two methods:
  * It should implement two methods:
- * * {@link module:upload/filerepository~Adapter#upload upload()},
- * * {@link module:upload/filerepository~Adapter#abort abort()}.
+ *
+ * * {@link module:upload/filerepository~Adapter#upload `upload()`},
+ * * {@link module:upload/filerepository~Adapter#abort `abort()`}.
  *
  *
  * Example adapter implementation:
  * Example adapter implementation:
  *
  *
- *	class Adapter {
- *		constructor( loader ) {
- *			// Save Loader instance to update upload progress.
- *			this.loader = loader;
- *		}
+ *		class Adapter {
+ *			constructor( loader ) {
+ *				// Save Loader instance to update upload progress.
+ *				this.loader = loader;
+ *			}
  *
  *
- *		upload() {
- *			// Update loader's progress.
- *			server.onUploadProgress( data => {
- *				loader.uploadTotal = data.total;
- *				loader.uploaded = data.uploaded;
- *			} ):
+ *			upload() {
+ *				// Update loader's progress.
+ *				server.onUploadProgress( data => {
+ *					loader.uploadTotal = data.total;
+ *					loader.uploaded = data.uploaded;
+ *				} ):
  *
  *
- *			// Return promise that will be resolved when file is uploaded.
- *			return server.upload( loader.file );
- *		}
+ *				// Return promise that will be resolved when file is uploaded.
+ *				return server.upload( loader.file );
+ *			}
  *
  *
- *		abort() {
- *			// Reject promise returned from upload() method.
- *			server.abortUpload();
+ *			abort() {
+ *				// Reject promise returned from upload() method.
+ *				server.abortUpload();
+ *			}
  *		}
  *		}
- *	}
  *
  *
  * Then adapter can be set to be used by {@link module:upload/filerepository~FileRepository FileRepository}:
  * Then adapter can be set to be used by {@link module:upload/filerepository~FileRepository FileRepository}:
  *
  *
- *	editor.plugins.get( 'FileRepository' ).createAdapter = function( loader ) {
- *		return new Adapter( loader );
- *	};
+ *		editor.plugins.get( 'FileRepository' ).createAdapter = function( loader ) {
+ *			return new Adapter( loader );
+ *		};
  *
  *
  * @interface Adapter
  * @interface Adapter
  */
  */
@@ -440,18 +497,18 @@ mix( FileLoader, ObservableMixin );
  * This method should return a promise that will resolve when data will be uploaded to server. Promise should be
  * This method should return a promise that will resolve when data will be uploaded to server. Promise should be
  * resolved with an object containing information about uploaded file:
  * resolved with an object containing information about uploaded file:
  *
  *
- *	{
- *		default: 'http://server/default-size.image.png'
- *	}
+ *		{
+ *			default: 'http://server/default-size.image.png'
+ *		}
  *
  *
  * Additionally, other image sizes can be provided:
  * Additionally, other image sizes can be provided:
  *
  *
- *	{
- *		default: 'http://server/default-size.image.png',
- *		'160': 'http://server/size-160.image.png',
- *		'500': 'http://server/size-500.image.png',
- *		'1000': 'http://server/size-1000.image.png'
- *	}
+ *		{
+ *			default: 'http://server/default-size.image.png',
+ *			'160': 'http://server/size-160.image.png',
+ *			'500': 'http://server/size-500.image.png',
+ *			'1000': 'http://server/size-1000.image.png'
+ *		}
  *
  *
  * Take a look at {@link module:upload/filerepository~Adapter example Adapter implementation} and
  * Take a look at {@link module:upload/filerepository~Adapter example Adapter implementation} and
  * {@link module:upload/filerepository~FileRepository#createAdapter createAdapter method}.
  * {@link module:upload/filerepository~FileRepository#createAdapter createAdapter method}.

+ 9 - 0
packages/ckeditor5-upload/tests/_utils/mocks.js

@@ -3,6 +3,8 @@
  * For licensing, see LICENSE.md.
  * For licensing, see LICENSE.md.
  */
  */
 
 
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
+
 /**
 /**
  * Returns object that mocks native File object.
  * Returns object that mocks native File object.
  */
  */
@@ -117,3 +119,10 @@ export class NativeFileReaderMock {
 	}
 	}
 }
 }
 
 
+export class UploadAdapterPluginMock extends Plugin {
+	init() {
+		const fileRepository = this.editor.plugins.get( 'FileRepository' );
+
+		fileRepository.createAdapter = () => {};
+	}
+}

+ 57 - 19
packages/ckeditor5-upload/tests/filerepository.js

@@ -6,7 +6,10 @@
 /* globals window */
 /* globals window */
 
 
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
+
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import FileRepository from '../src/filerepository';
 import FileRepository from '../src/filerepository';
+
 import Collection from '@ckeditor/ckeditor5-utils/src/collection';
 import Collection from '@ckeditor/ckeditor5-utils/src/collection';
 import { createNativeFileMock, AdapterMock, NativeFileReaderMock } from './_utils/mocks';
 import { createNativeFileMock, AdapterMock, NativeFileReaderMock } from './_utils/mocks';
 import log from '@ckeditor/ckeditor5-utils/src/log';
 import log from '@ckeditor/ckeditor5-utils/src/log';
@@ -15,28 +18,40 @@ import FileReader from '../src/filereader';
 
 
 describe( 'FileRepository', () => {
 describe( 'FileRepository', () => {
 	let editor, fileRepository, adapterMock;
 	let editor, fileRepository, adapterMock;
+
 	testUtils.createSinonSandbox();
 	testUtils.createSinonSandbox();
 
 
+	class UploadAdapterPluginMock extends Plugin {
+		init() {
+			fileRepository = this.editor.plugins.get( 'FileRepository' );
+
+			fileRepository.createAdapter = loader => {
+				adapterMock = new AdapterMock( loader );
+
+				return adapterMock;
+			};
+		}
+	}
+
 	beforeEach( () => {
 	beforeEach( () => {
-		return VirtualTestEditor.create( {
-			plugins: [ FileRepository ]
-		} )
+		return VirtualTestEditor
+			.create( {
+				plugins: [ FileRepository, UploadAdapterPluginMock ]
+			} )
 			.then( newEditor => {
 			.then( newEditor => {
 				editor = newEditor;
 				editor = newEditor;
-				fileRepository = editor.plugins.get( 'FileRepository' );
-				fileRepository.createAdapter = loader => {
-					adapterMock = new AdapterMock( loader );
-
-					return adapterMock;
-				};
 			} );
 			} );
 	} );
 	} );
 
 
+	afterEach( () => {
+		return editor.destroy();
+	} );
+
 	it( 'should be initialized', () => {
 	it( 'should be initialized', () => {
 		expect( fileRepository ).to.be.instanceOf( FileRepository );
 		expect( fileRepository ).to.be.instanceOf( FileRepository );
 	} );
 	} );
 
 
-	describe( 'init', () => {
+	describe( 'init()', () => {
 		it( 'should create loaders collection', () => {
 		it( 'should create loaders collection', () => {
 			expect( fileRepository.loaders ).to.be.instanceOf( Collection );
 			expect( fileRepository.loaders ).to.be.instanceOf( Collection );
 		} );
 		} );
@@ -76,16 +91,39 @@ describe( 'FileRepository', () => {
 		} );
 		} );
 	} );
 	} );
 
 
-	describe( 'createLoader', () => {
-		it( 'should show warning if adapter is not present', () => {
+	describe( 'afterInit()', () => {
+		it( 'logs a warning if no adapter was defined', () => {
 			const stub = testUtils.sinon.stub( log, 'warn' );
 			const stub = testUtils.sinon.stub( log, 'warn' );
+
+			return VirtualTestEditor
+				.create()
+				.then( editor => {
+					const fileRepository = new FileRepository( editor );
+
+					fileRepository.init();
+					fileRepository.afterInit();
+
+					sinon.assert.calledOnce( stub );
+					sinon.assert.calledWithExactly(
+						stub,
+						'filerepository-no-adapter: Upload adapter is not defined.'
+					);
+				} );
+		} );
+	} );
+
+	describe( 'createLoader()', () => {
+		it( 'should return null if adapter is not present', () => {
+			const stub = testUtils.sinon.stub( log, 'error' );
+
 			fileRepository.createAdapter = undefined;
 			fileRepository.createAdapter = undefined;
-			fileRepository.createLoader( createNativeFileMock() );
+
+			expect( fileRepository.createLoader( createNativeFileMock() ) ).to.be.null;
 
 
 			sinon.assert.calledOnce( stub );
 			sinon.assert.calledOnce( stub );
 			sinon.assert.calledWithExactly(
 			sinon.assert.calledWithExactly(
 				stub,
 				stub,
-				'FileRepository: no createAdapter method found. Please define it before creating a loader.'
+				'filerepository-no-adapter: Upload adapter is not defined.'
 			);
 			);
 		} );
 		} );
 
 
@@ -107,7 +145,7 @@ describe( 'FileRepository', () => {
 		} );
 		} );
 	} );
 	} );
 
 
-	describe( 'getLoader', () => {
+	describe( 'getLoader()', () => {
 		it( 'should return null if loader does not exists', () => {
 		it( 'should return null if loader does not exists', () => {
 			const file1 = createNativeFileMock();
 			const file1 = createNativeFileMock();
 			const file2 = createNativeFileMock();
 			const file2 = createNativeFileMock();
@@ -124,7 +162,7 @@ describe( 'FileRepository', () => {
 		} );
 		} );
 	} );
 	} );
 
 
-	describe( 'destroyLoader', () => {
+	describe( 'destroyLoader()', () => {
 		let file, loader, destroySpy;
 		let file, loader, destroySpy;
 
 
 		beforeEach( () => {
 		beforeEach( () => {
@@ -162,7 +200,7 @@ describe( 'FileRepository', () => {
 			loader = fileRepository.createLoader( file );
 			loader = fileRepository.createLoader( file );
 		} );
 		} );
 
 
-		describe( 'constructor', () => {
+		describe( 'constructor()', () => {
 			it( 'should initialize id', () => {
 			it( 'should initialize id', () => {
 				expect( loader.id ).to.be.a( 'string' );
 				expect( loader.id ).to.be.a( 'string' );
 			} );
 			} );
@@ -238,7 +276,7 @@ describe( 'FileRepository', () => {
 			} );
 			} );
 		} );
 		} );
 
 
-		describe( 'read', () => {
+		describe( 'read()', () => {
 			it( 'should throw error when status is defferent than idle', () => {
 			it( 'should throw error when status is defferent than idle', () => {
 				loader.status = 'uploading';
 				loader.status = 'uploading';
 
 
@@ -292,7 +330,7 @@ describe( 'FileRepository', () => {
 			} );
 			} );
 		} );
 		} );
 
 
-		describe( 'upload', () => {
+		describe( 'upload()', () => {
 			it( 'should throw error when status is defferent than idle', () => {
 			it( 'should throw error when status is defferent than idle', () => {
 				loader.status = 'reading';
 				loader.status = 'reading';
 
 

+ 11 - 3
packages/ckeditor5-upload/tests/imageupload.js

@@ -11,22 +11,30 @@ import ImageUpload from '../src/imageupload';
 import ImageUploadProgress from '../src/imageuploadprogress';
 import ImageUploadProgress from '../src/imageuploadprogress';
 import ImageUploadButton from '../src/imageuploadbutton';
 import ImageUploadButton from '../src/imageuploadbutton';
 
 
+import { UploadAdapterPluginMock } from './_utils/mocks';
+
 describe( 'ImageUpload', () => {
 describe( 'ImageUpload', () => {
-	let editor;
+	let editor, editorElement;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		const editorElement = document.createElement( 'div' );
+		editorElement = document.createElement( 'div' );
 		document.body.appendChild( editorElement );
 		document.body.appendChild( editorElement );
 
 
 		return ClassicEditor
 		return ClassicEditor
 			.create( editorElement, {
 			.create( editorElement, {
-				plugins: [ Image, ImageUpload ]
+				plugins: [ Image, ImageUpload, UploadAdapterPluginMock ]
 			} )
 			} )
 			.then( newEditor => {
 			.then( newEditor => {
 				editor = newEditor;
 				editor = newEditor;
 			} );
 			} );
 	} );
 	} );
 
 
+	afterEach( () => {
+		editorElement.remove();
+
+		return editor.destroy();
+	} );
+
 	it( 'should include ImageUploadProgress', () => {
 	it( 'should include ImageUploadProgress', () => {
 		expect( editor.plugins.get( ImageUploadProgress ) ).to.be.instanceOf( ImageUploadProgress );
 		expect( editor.plugins.get( ImageUploadProgress ) ).to.be.instanceOf( ImageUploadProgress );
 	} );
 	} );

+ 11 - 6
packages/ckeditor5-upload/tests/imageuploadbutton.js

@@ -7,6 +7,7 @@
 
 
 import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
 import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
 
 
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import Image from '@ckeditor/ckeditor5-image/src/image';
 import Image from '@ckeditor/ckeditor5-image/src/image';
 import FileDialogButtonView from '../src/ui/filedialogbuttonview';
 import FileDialogButtonView from '../src/ui/filedialogbuttonview';
 import FileRepository from '../src/filerepository';
 import FileRepository from '../src/filerepository';
@@ -21,23 +22,27 @@ import { setData as setModelData, getData as getModelData } from '@ckeditor/cked
 describe( 'ImageUploadButton', () => {
 describe( 'ImageUploadButton', () => {
 	let editor, doc, editorElement, fileRepository;
 	let editor, doc, editorElement, fileRepository;
 
 
+	class UploadAdapterPluginMock extends Plugin {
+		init() {
+			fileRepository = this.editor.plugins.get( FileRepository );
+			fileRepository.createAdapter = loader => {
+				return new AdapterMock( loader );
+			};
+		}
+	}
+
 	beforeEach( () => {
 	beforeEach( () => {
 		editorElement = document.createElement( 'div' );
 		editorElement = document.createElement( 'div' );
 		document.body.appendChild( editorElement );
 		document.body.appendChild( editorElement );
 
 
 		return ClassicEditor
 		return ClassicEditor
 			.create( editorElement, {
 			.create( editorElement, {
-				plugins: [ Paragraph, Image, ImageUploadButton, FileRepository ]
+				plugins: [ Paragraph, Image, ImageUploadButton, FileRepository, UploadAdapterPluginMock ]
 			} )
 			} )
 			.then( newEditor => {
 			.then( newEditor => {
 				editor = newEditor;
 				editor = newEditor;
 				doc = editor.document;
 				doc = editor.document;
 
 
-				fileRepository = editor.plugins.get( FileRepository );
-				fileRepository.createAdapter = loader => {
-					return new AdapterMock( loader );
-				};
-
 				// Hide all notifications (prevent alert() calls).
 				// Hide all notifications (prevent alert() calls).
 				const notification = editor.plugins.get( Notification );
 				const notification = editor.plugins.get( Notification );
 				notification.on( 'show', evt => evt.stop() );
 				notification.on( 'show', evt => evt.stop() );

+ 14 - 5
packages/ckeditor5-upload/tests/imageuploadcommand.js

@@ -4,8 +4,12 @@
  */
  */
 
 
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
+
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
+
 import ImageUploadCommand from '../src/imageuploadcommand';
 import ImageUploadCommand from '../src/imageuploadcommand';
 import FileRepository from '../src/filerepository';
 import FileRepository from '../src/filerepository';
+
 import { createNativeFileMock, AdapterMock } from './_utils/mocks';
 import { createNativeFileMock, AdapterMock } from './_utils/mocks';
 import { setData as setModelData, getData as getModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 import { setData as setModelData, getData as getModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 import Image from '@ckeditor/ckeditor5-image/src/image/imageengine';
 import Image from '@ckeditor/ckeditor5-image/src/image/imageengine';
@@ -16,18 +20,23 @@ import ModelPosition from '@ckeditor/ckeditor5-engine/src/model/position';
 describe( 'ImageUploadCommand', () => {
 describe( 'ImageUploadCommand', () => {
 	let editor, command, doc, fileRepository;
 	let editor, command, doc, fileRepository;
 
 
+	class UploadAdapterPluginMock extends Plugin {
+		init() {
+			fileRepository = this.editor.plugins.get( FileRepository );
+			fileRepository.createAdapter = loader => {
+				return new AdapterMock( loader );
+			};
+		}
+	}
+
 	beforeEach( () => {
 	beforeEach( () => {
 		return VirtualTestEditor
 		return VirtualTestEditor
 			.create( {
 			.create( {
-				plugins: [ FileRepository, Image, Paragraph ]
+				plugins: [ FileRepository, Image, Paragraph, UploadAdapterPluginMock ]
 			} )
 			} )
 			.then( newEditor => {
 			.then( newEditor => {
 				editor = newEditor;
 				editor = newEditor;
 				command = new ImageUploadCommand( editor );
 				command = new ImageUploadCommand( editor );
-				fileRepository = editor.plugins.get( FileRepository );
-				fileRepository.createAdapter = loader => {
-					return new AdapterMock( loader );
-				};
 
 
 				doc = editor.document;
 				doc = editor.document;
 
 

+ 16 - 9
packages/ckeditor5-upload/tests/imageuploadengine.js

@@ -6,6 +6,8 @@
 /* globals window, setTimeout */
 /* globals window, setTimeout */
 
 
 import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
+
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import ImageEngine from '@ckeditor/ckeditor5-image/src/image/imageengine';
 import ImageEngine from '@ckeditor/ckeditor5-image/src/image/imageengine';
 import ImageUploadEngine from '../src/imageuploadengine';
 import ImageUploadEngine from '../src/imageuploadengine';
 import ImageUploadCommand from '../src/imageuploadcommand';
 import ImageUploadCommand from '../src/imageuploadcommand';
@@ -28,8 +30,21 @@ describe( 'ImageUploadEngine', () => {
 	// eslint-disable-next-line max-len
 	// eslint-disable-next-line max-len
 	const base64Sample = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=';
 	const base64Sample = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=';
 	let editor, doc, fileRepository, viewDocument, nativeReaderMock, loader, adapterMock;
 	let editor, doc, fileRepository, viewDocument, nativeReaderMock, loader, adapterMock;
+
 	testUtils.createSinonSandbox();
 	testUtils.createSinonSandbox();
 
 
+	class UploadAdapterPluginMock extends Plugin {
+		init() {
+			fileRepository = this.editor.plugins.get( FileRepository );
+			fileRepository.createAdapter = newLoader => {
+				loader = newLoader;
+				adapterMock = new AdapterMock( loader );
+
+				return adapterMock;
+			};
+		}
+	}
+
 	beforeEach( () => {
 	beforeEach( () => {
 		testUtils.sinon.stub( window, 'FileReader' ).callsFake( () => {
 		testUtils.sinon.stub( window, 'FileReader' ).callsFake( () => {
 			nativeReaderMock = new NativeFileReaderMock();
 			nativeReaderMock = new NativeFileReaderMock();
@@ -39,20 +54,12 @@ describe( 'ImageUploadEngine', () => {
 
 
 		return ClassicTestEditor
 		return ClassicTestEditor
 			.create( {
 			.create( {
-				plugins: [ ImageEngine, ImageUploadEngine, Paragraph, UndoEngine ]
+				plugins: [ ImageEngine, ImageUploadEngine, Paragraph, UndoEngine, UploadAdapterPluginMock ]
 			} )
 			} )
 			.then( newEditor => {
 			.then( newEditor => {
 				editor = newEditor;
 				editor = newEditor;
 				doc = editor.document;
 				doc = editor.document;
 				viewDocument = editor.editing.view;
 				viewDocument = editor.editing.view;
-
-				fileRepository = editor.plugins.get( FileRepository );
-				fileRepository.createAdapter = newLoader => {
-					loader = newLoader;
-					adapterMock = new AdapterMock( loader );
-
-					return adapterMock;
-				};
 			} );
 			} );
 	} );
 	} );
 
 

+ 18 - 1
packages/ckeditor5-upload/tests/imageuploadprogress.js

@@ -6,11 +6,14 @@
 /* globals window */
 /* globals window */
 
 
 import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
 import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
+
+import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
 import ImageEngine from '@ckeditor/ckeditor5-image/src/image/imageengine';
 import ImageEngine from '@ckeditor/ckeditor5-image/src/image/imageengine';
 import ImageUploadEngine from '../src/imageuploadengine';
 import ImageUploadEngine from '../src/imageuploadengine';
 import ImageUploadProgress from '../src/imageuploadprogress';
 import ImageUploadProgress from '../src/imageuploadprogress';
 import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
 import FileRepository from '../src/filerepository';
 import FileRepository from '../src/filerepository';
+
 import { AdapterMock, createNativeFileMock, NativeFileReaderMock } from './_utils/mocks';
 import { AdapterMock, createNativeFileMock, NativeFileReaderMock } from './_utils/mocks';
 import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
 import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
@@ -20,9 +23,23 @@ import svgPlaceholder from '../theme/icons/image_placeholder.svg';
 
 
 describe( 'ImageUploadProgress', () => {
 describe( 'ImageUploadProgress', () => {
 	const imagePlaceholder = encodeURIComponent( svgPlaceholder );
 	const imagePlaceholder = encodeURIComponent( svgPlaceholder );
+
 	// eslint-disable-next-line max-len
 	// eslint-disable-next-line max-len
 	const base64Sample = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=';
 	const base64Sample = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=';
 	let editor, document, fileRepository, viewDocument, nativeReaderMock, loader, adapterMock;
 	let editor, document, fileRepository, viewDocument, nativeReaderMock, loader, adapterMock;
+
+	class UploadAdapterPluginMock extends Plugin {
+		init() {
+			fileRepository = this.editor.plugins.get( FileRepository );
+			fileRepository.createAdapter = newLoader => {
+				loader = newLoader;
+				adapterMock = new AdapterMock( loader );
+
+				return adapterMock;
+			};
+		}
+	}
+
 	testUtils.createSinonSandbox();
 	testUtils.createSinonSandbox();
 
 
 	beforeEach( () => {
 	beforeEach( () => {
@@ -34,7 +51,7 @@ describe( 'ImageUploadProgress', () => {
 
 
 		return ClassicTestEditor
 		return ClassicTestEditor
 			.create( {
 			.create( {
-				plugins: [ ImageEngine, Paragraph, ImageUploadProgress ]
+				plugins: [ ImageEngine, Paragraph, ImageUploadProgress, UploadAdapterPluginMock ]
 			} )
 			} )
 			.then( newEditor => {
 			.then( newEditor => {
 				editor = newEditor;
 				editor = newEditor;