From 399643073440d3c93edc3785c2b26973ef8b523e Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 31 Jul 2020 12:24:36 +0200 Subject: [PATCH 01/11] Fixed helpers tests. --- src/ckeditor/ckeditor.helpers.spec.ts | 14 ++++++++++---- src/ckeditor/ckeditor.helpers.ts | 5 +++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/ckeditor/ckeditor.helpers.spec.ts b/src/ckeditor/ckeditor.helpers.spec.ts index 656e7e61..249bd748 100644 --- a/src/ckeditor/ckeditor.helpers.spec.ts +++ b/src/ckeditor/ckeditor.helpers.spec.ts @@ -21,9 +21,10 @@ describe( 'getEditorNamespace', () => { } ); it( 'typeError thrown when empty string passed', () => { - expect( () => { - getEditorNamespace( '' ); - } ).toThrowError( 'CKEditor URL must be a non-empty string.' ); + return getEditorNamespace( '' ).catch( err => { + expect( err instanceof Error ); + expect( err.message ).toEqual( 'CKEditor URL must be a non-empty string.' ); + } ); } ); it( 'returns promise even if namespace is present', () => { @@ -52,6 +53,11 @@ describe( 'getEditorNamespace', () => { } ); it( 'returns the same promise', () => { - expect( getEditorNamespace( fakeScript ) ).toBe( getEditorNamespace( fakeScript ) ); + const promise1 = getEditorNamespace( fakeScript ); + const promise2 = getEditorNamespace( fakeScript ); + + expect( promise1 ).toBe( promise2 ); + + return Promise.all( [ promise1, promise2 ] ) } ); } ); diff --git a/src/ckeditor/ckeditor.helpers.ts b/src/ckeditor/ckeditor.helpers.ts index a5cdcbc8..b4b42f3f 100644 --- a/src/ckeditor/ckeditor.helpers.ts +++ b/src/ckeditor/ckeditor.helpers.ts @@ -10,7 +10,7 @@ let promise; export function getEditorNamespace( editorURL: string ): Promise<{ [ key: string ]: any; }> { if ( editorURL.length < 1 ) { - throw new TypeError( 'CKEditor URL must be a non-empty string.' ); + return Promise.reject( new TypeError( 'CKEditor URL must be a non-empty string.' ) ); } if ( 'CKEDITOR' in window ) { @@ -22,8 +22,9 @@ export function getEditorNamespace( editorURL: string ): Promise<{ [ key: string scriptReject( err ); } else { scriptResolve( CKEDITOR ); - promise = undefined; } + + promise = undefined; } ); } ); } From bf42cd1f6b372ba457f04b6b6b19a176aee9cd95 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 31 Jul 2020 13:44:32 +0200 Subject: [PATCH 02/11] Refactoring. --- src/ckeditor/ckeditor.component.spec.ts | 66 +++++++++++-------------- 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/src/ckeditor/ckeditor.component.spec.ts b/src/ckeditor/ckeditor.component.spec.ts index 60634b11..21893433 100644 --- a/src/ckeditor/ckeditor.component.spec.ts +++ b/src/ckeditor/ckeditor.component.spec.ts @@ -4,12 +4,11 @@ */ import waitUntil from 'wait-until-promise'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; import { CKEditorComponent } from './ckeditor.component'; import { fireDragEvent, mockDropEvent, - mockPasteEvent, setDataMultipleTimes, whenDataReady, whenEvent @@ -24,11 +23,11 @@ describe( 'CKEditorComponent', () => { fixture: ComponentFixture, config: Object; - beforeEach( async( () => { - TestBed.configureTestingModule( { + beforeEach( () => { + return TestBed.configureTestingModule( { declarations: [ CKEditorComponent ] } ).compileComponents(); - } ) ); + } ) beforeEach( () => { fixture = TestBed.createComponent( CKEditorComponent ); @@ -73,9 +72,10 @@ describe( 'CKEditorComponent', () => { } ); it( 'should have proper editor type', () => { - whenEvent( 'ready', component ).then( () => { + return whenEvent( 'ready', component ).then( () => { fixture.detectChanges(); - expect( component.instance.editable().isInline() ).toBe( component.type !== EditorType.CLASSIC ); + expect( component.instance.editable().isInline() ) + .toBe( component.type !== EditorType.CLASSIC ); } ); } ); @@ -170,14 +170,15 @@ describe( 'CKEditorComponent', () => { } ); describe( 'when set with config', () => { - beforeEach( done => { + beforeEach( () => { component.config = { readOnly: true, width: 1000, height: 1000 }; fixture.detectChanges(); - whenEvent( 'ready', component ).then( done ); + + return whenEvent( 'ready', component ); } ); it( 'editor should be readOnly', () => { @@ -193,84 +194,80 @@ describe( 'CKEditorComponent', () => { expect( component.instance.plugins.undo ).not.toBeUndefined(); } ); - it( 'should register changes', async done => { + it( 'should register changes', () => { const spy = jasmine.createSpy(); component.registerOnChange( spy ); - setDataMultipleTimes( component.instance, [ + return setDataMultipleTimes( component.instance, [ '

Hello World!

', '

I am CKEditor for Angular!

' ] ).then( () => { expect( spy ).toHaveBeenCalledTimes( 2 ); - - done(); } ); } ); } ); describe( 'when set without undo plugin', () => { - beforeEach( ( done ) => { + beforeEach( () => { component.config = { removePlugins: 'undo' }; fixture.detectChanges(); - whenEvent( 'ready', component ).then( done ); + return whenEvent( 'ready', component ); } ); it( 'editor should not have undo plugin', () => { expect( component.instance.plugins.undo ).toBeUndefined(); } ); - it( 'should register changes without undo plugin', async done => { + it( 'should register changes without undo plugin', () => { const spy = jasmine.createSpy(); component.registerOnChange( spy ); - setDataMultipleTimes( component.instance, [ + return setDataMultipleTimes( component.instance, [ '

Hello World!

', '

I am CKEditor for Angular!

' ] ).then( () => { expect( spy ).toHaveBeenCalledTimes( 2 ); - - done(); } ); } ); } ); } ); describe( 'on destroy', () => { - it ( 'should not have call runOutsideAngular when destroy before DOM loaded', done => { + it ( 'should not have call runOutsideAngular when destroy before DOM loaded', () => { spyOn( fixture.ngZone, 'runOutsideAngular' ); fixture.detectChanges(); - waitUntil( () => { + return waitUntil( () => { fixture.destroy(); return true; }, 0 ).then( () => { expect( fixture.ngZone.runOutsideAngular ).toHaveBeenCalledTimes( 1 ); - } ).then( done ); + } ); } ); - it ( 'should not have call runOutsideAngular when destroy before DOM loaded', done => { + it ( 'should not have call runOutsideAngular when destroy before DOM loaded', () => { spyOn( fixture.ngZone, 'runOutsideAngular' ); fixture.detectChanges(); - waitUntil( () => { + return waitUntil( () => { fixture.destroy(); return true; }, 200 ).then( () => { expect( fixture.ngZone.runOutsideAngular ).toHaveBeenCalledTimes( 1 ); - } ).then( done ); + } ); } ); } ); describe( 'when component is ready', () => { - beforeEach( done => { + beforeEach( () => { fixture.detectChanges(); - whenEvent( 'ready', component ).then( done ); + return whenEvent( 'ready', component ); } ); it( 'should be initialized', () => { @@ -319,18 +316,16 @@ describe( 'CKEditorComponent', () => { const data = 'foo', expected = '

foo

\n'; - it( 'should be configurable at the start of the component', async done => { + it( 'should be configurable at the start of the component', async () => { fixture.detectChanges(); await whenDataReady( component.instance, () => component.data = data ); expect( component.data ).toEqual( expected ); expect( component.instance.getData() ).toEqual( expected ); - - done(); } ); - it( 'should be writeable by ControlValueAccessor', async done => { + it( 'should be writeable by ControlValueAccessor', async () => { fixture.detectChanges(); const editor = component.instance; @@ -342,8 +337,6 @@ describe( 'CKEditorComponent', () => { await whenDataReady( editor, () => component.writeValue( '

baz

' ) ); expect( component.instance.getData() ).toEqual( '

baz

\n' ); - - done(); } ); } ); @@ -423,7 +416,7 @@ describe( 'CKEditorComponent', () => { return eventPromise; } ); - it( 'drag/drop events should emit component dragStart, dragEnd and drop', async done => { + it( 'drag/drop events should emit component dragStart, dragEnd and drop', done => { fixture.detectChanges(); const spyDragStart = jasmine.createSpy( 'dragstart' ); @@ -517,17 +510,16 @@ describe( 'CKEditorComponent', () => { expect( spy ).toHaveBeenCalled(); } ); - it( 'onChange callback should be called when editor model changes', async done => { + it( 'onChange callback should be called when editor model changes', () => { fixture.detectChanges(); const spy = jasmine.createSpy(); component.registerOnChange( spy ); - setDataMultipleTimes( component.instance, [ + return setDataMultipleTimes( component.instance, [ 'initial', 'initial', 'modified' ] ).then( () => { expect( spy ).toHaveBeenCalledTimes( 2 ); - done(); } ); } ); } ); From 02b7ebc40d8a82f5178c9fd9bf7decb174035173 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 31 Jul 2020 14:10:17 +0200 Subject: [PATCH 03/11] Update config before each test case, not once for all. --- src/ckeditor/ckeditor.component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ckeditor/ckeditor.component.spec.ts b/src/ckeditor/ckeditor.component.spec.ts index 21893433..c2c1b72e 100644 --- a/src/ckeditor/ckeditor.component.spec.ts +++ b/src/ckeditor/ckeditor.component.spec.ts @@ -141,7 +141,7 @@ describe( 'CKEditorComponent', () => { warn: isDivarea } ].forEach( ( { newConfig, msg, warn } ) => { describe( msg, () => { - beforeAll( () => { + beforeEach( () => { config = newConfig; } ); From 3ed30fd03d7781ac666ed1e52bc40ab15dbbc6fa Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 5 Aug 2020 08:57:19 +0200 Subject: [PATCH 04/11] Removed ie10 sniffing. --- src/ckeditor/ckeditor.helpers.spec.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/ckeditor/ckeditor.helpers.spec.ts b/src/ckeditor/ckeditor.helpers.spec.ts index 249bd748..ac74802d 100644 --- a/src/ckeditor/ckeditor.helpers.spec.ts +++ b/src/ckeditor/ckeditor.helpers.spec.ts @@ -9,8 +9,6 @@ declare let CKEDITOR: any; describe( 'getEditorNamespace', () => { const fakeScript = 'data:text/javascript;base64,d2luZG93LkNLRURJVE9SID0ge307'; - let isIe10 = navigator.userAgent.toLowerCase().indexOf( 'trident/' ) > -1; - isIe10 = isIe10 && document[ 'documentMode' ] === 10; beforeEach( () => { delete window[ 'CKEDITOR' ]; @@ -38,13 +36,11 @@ describe( 'getEditorNamespace', () => { } ); } ); - if ( !isIe10 ) { // Ignore unstable test on IE10. - it( 'load script and resolves with loaded namespace', () => { - return getEditorNamespace( fakeScript ).then( namespace => { - expect( namespace ).toBe( CKEDITOR ); - } ); + it( 'load script and resolves with loaded namespace', () => { + return getEditorNamespace( fakeScript ).then( namespace => { + expect( namespace ).toBe( CKEDITOR ); } ); - } + } ); it( 'rejects with error when script cannot be loaded', () => { return getEditorNamespace( 'non-existent.js' ).catch( err => { From cfd11b1311566acc954737315305588e4d8efad1 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 5 Aug 2020 08:59:27 +0200 Subject: [PATCH 05/11] Replaced invalid space. --- src/ckeditor/ckeditor.helpers.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ckeditor/ckeditor.helpers.spec.ts b/src/ckeditor/ckeditor.helpers.spec.ts index ac74802d..0c2a0734 100644 --- a/src/ckeditor/ckeditor.helpers.spec.ts +++ b/src/ckeditor/ckeditor.helpers.spec.ts @@ -49,8 +49,8 @@ describe( 'getEditorNamespace', () => { } ); it( 'returns the same promise', () => { - const promise1 = getEditorNamespace( fakeScript ); - const promise2 = getEditorNamespace( fakeScript ); + const promise1 = getEditorNamespace( fakeScript ); + const promise2 = getEditorNamespace( fakeScript ); expect( promise1 ).toBe( promise2 ); From 35cb0acc2d9afe142f3629197fa95e659d654c2d Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 5 Aug 2020 09:41:51 +0200 Subject: [PATCH 06/11] Removed unnecessary asynchronous code. --- src/ckeditor/ckeditor.component.spec.ts | 32 +++++++++++-------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/ckeditor/ckeditor.component.spec.ts b/src/ckeditor/ckeditor.component.spec.ts index c2c1b72e..b3168dae 100644 --- a/src/ckeditor/ckeditor.component.spec.ts +++ b/src/ckeditor/ckeditor.component.spec.ts @@ -416,7 +416,7 @@ describe( 'CKEditorComponent', () => { return eventPromise; } ); - it( 'drag/drop events should emit component dragStart, dragEnd and drop', done => { + it( 'drag/drop events should emit component dragStart, dragEnd and drop', () => { fixture.detectChanges(); const spyDragStart = jasmine.createSpy( 'dragstart' ); @@ -428,30 +428,26 @@ describe( 'CKEditorComponent', () => { const spyDrop = jasmine.createSpy( 'drop' ); component.drop.subscribe( spyDrop ); - whenDataReady( component.instance, () => { - const dropEvent = mockDropEvent(); - const paragraph = component.instance.editable().findOne( 'p' ); + const dropEvent = mockDropEvent(); + const paragraph = component.instance.editable().findOne( 'p' ); - component.instance.getSelection().selectElement( paragraph ); + component.instance.getSelection().selectElement( paragraph ); - fireDragEvent( 'dragstart', component.instance, dropEvent ); + fireDragEvent( 'dragstart', component.instance, dropEvent ); - expect( spyDragStart ).toHaveBeenCalledTimes( 1 ); + expect( spyDragStart ).toHaveBeenCalledTimes( 1 ); - fireDragEvent( 'dragend', component.instance, dropEvent ); + fireDragEvent( 'dragend', component.instance, dropEvent ); - expect( spyDragEnd ).toHaveBeenCalledTimes( 1 ); + expect( spyDragEnd ).toHaveBeenCalledTimes( 1 ); - // There is some issue in Firefox with simulating drag-drop flow. The drop event - // is not fired making this assertion fail. Let's skip it for now. - if ( !CKEDITOR.env.gecko ) { - fireDragEvent( 'drop', component.instance, dropEvent ); + // There is some issue in Firefox with simulating drag-drop flow. The drop event + // is not fired making this assertion fail. Let's skip it for now. + if ( !CKEDITOR.env.gecko ) { + fireDragEvent( 'drop', component.instance, dropEvent ); - expect( spyDrop ).toHaveBeenCalledTimes( 1 ); - } - - done(); - } ); + expect( spyDrop ).toHaveBeenCalledTimes( 1 ); + } } ); it( 'fileUploadRequest should emit component fileUploadRequest', () => { From 89f4005f309773ad7563b3d386c7238127f33e91 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 5 Aug 2020 14:52:44 +0200 Subject: [PATCH 07/11] Allow random test order. --- src/karma.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/karma.conf.js b/src/karma.conf.js index 2eeef1d6..9f223ac5 100644 --- a/src/karma.conf.js +++ b/src/karma.conf.js @@ -13,7 +13,7 @@ module.exports = function ( config ) { clearContext: false, // leave Jasmine Spec Runner output visible in browser captureConsole: false, jasmine: { - random: false + random: true } }, coverageIstanbulReporter: { From 5e67c8bf3f30dc6a8b315c06302452e7260673a6 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Thu, 6 Aug 2020 15:35:58 +0200 Subject: [PATCH 08/11] Reverse karma change. --- src/karma.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/karma.conf.js b/src/karma.conf.js index 9f223ac5..2eeef1d6 100644 --- a/src/karma.conf.js +++ b/src/karma.conf.js @@ -13,7 +13,7 @@ module.exports = function ( config ) { clearContext: false, // leave Jasmine Spec Runner output visible in browser captureConsole: false, jasmine: { - random: true + random: false } }, coverageIstanbulReporter: { From 34fe2039c4d00978c6eccefec0200d46e215f295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Jarze=CC=A8bski?= Date: Wed, 5 Aug 2020 14:58:26 +0200 Subject: [PATCH 09/11] Fix whitespaces in repo. --- src/app/demo-form/demo-form.component.css | 2 +- src/app/demo-form/demo-form.component.html | 2 +- src/ckeditor/ckeditor.component.spec.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/demo-form/demo-form.component.css b/src/app/demo-form/demo-form.component.css index 49f15699..4ef27dde 100644 --- a/src/app/demo-form/demo-form.component.css +++ b/src/app/demo-form/demo-form.component.css @@ -27,7 +27,7 @@ form > div { pre { word-wrap: break-word; - white-space: pre-wrap; + white-space: pre-wrap; } p.alert { diff --git a/src/app/demo-form/demo-form.component.html b/src/app/demo-form/demo-form.component.html index b141d27b..f086fba4 100644 --- a/src/app/demo-form/demo-form.component.html +++ b/src/app/demo-form/demo-form.component.html @@ -18,7 +18,7 @@

User profile form

[(ngModel)]="model.description" id="description" name="description" - type="divarea"> + type="divarea">

Description is "dirty".

diff --git a/src/ckeditor/ckeditor.component.spec.ts b/src/ckeditor/ckeditor.component.spec.ts index b3168dae..c1350fe9 100644 --- a/src/ckeditor/ckeditor.component.spec.ts +++ b/src/ckeditor/ckeditor.component.spec.ts @@ -383,7 +383,7 @@ describe( 'CKEditorComponent', () => { const editable = component.instance.editable(); const editor = editable.getEditor( false ); - const eventPromise = whenEvent( 'paste', component ).then( () => { + const eventPromise = whenEvent( 'paste', component ).then( () => { expect( spy ).toHaveBeenCalledTimes( 1 ); expect( component.instance.getData() ).toEqual( '

bam

\n' ); } ); From e3119b12fd7d4a224c28b77cfb32053eb811d9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Jarze=CC=A8bski?= Date: Wed, 5 Aug 2020 14:58:59 +0200 Subject: [PATCH 10/11] Remove legacy function 'mockPasteEvent()'. --- src/test.tools.ts | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/test.tools.ts b/src/test.tools.ts index 27dd1850..3b83c749 100644 --- a/src/test.tools.ts +++ b/src/test.tools.ts @@ -31,25 +31,6 @@ export function setDataMultipleTimes( editor: any, data: Array ) { } ); } -export function mockPasteEvent() { - const dataTransfer = mockNativeDataTransfer(); - let target = new CKEDITOR.dom.element( 'div' ); - - return { - $: { - ctrlKey: true, - clipboardData: ( CKEDITOR.env.ie && CKEDITOR.env.version < 16 ) ? undefined : dataTransfer - }, - preventDefault: function() {}, - getTarget: function() { - return target; - }, - setTarget: function( t: any ) { - target = t; - } - }; -} - export function mockDropEvent() { const dataTransfer = mockNativeDataTransfer(); let target = new CKEDITOR.dom.element( 'div' ); From a43fff7337b70816143a0702bca6bfe6bbb586c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Jarze=CC=A8bski?= Date: Wed, 5 Aug 2020 15:01:58 +0200 Subject: [PATCH 11/11] Add changelog entry [skip ci]. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28d1334d..0bfb3b7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ Other Changes: * [#98](https://github.com/ckeditor/ckeditor4-angular/issues/98): Updated repository dependencies (no changes in the actual `ckeditor4-angular` package). +* [#128](https://github.com/ckeditor/ckeditor4-angular/issues/128): Improve the stability of `getEditorNamespace()` method. ## ckeditor4-angular 1.2.2