Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit 1e2f912

Browse files
authored
Merge pull request #24 from ckeditor/t/ckeditor5/1341
Fix: There should be no memory leaks when the editor is created and destroyed (see ckeditor/ckeditor5#1341).
2 parents 4072ce0 + f94350c commit 1e2f912

File tree

5 files changed

+169
-0
lines changed

5 files changed

+169
-0
lines changed

tests/decouplededitor.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import DataApiMixin from '@ckeditor/ckeditor5-core/src/editor/utils/dataapimixin
1818
import RootElement from '@ckeditor/ckeditor5-engine/src/model/rootelement';
1919

2020
import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
21+
import { describeMemoryUsage, testMemoryUsage } from '@ckeditor/ckeditor5-core/tests/_utils/memory';
22+
import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
2123

2224
const editorData = '<p><strong>foo</strong> bar</p>';
2325

@@ -303,4 +305,17 @@ describe( 'DecoupledEditor', () => {
303305
} );
304306
}
305307
} );
308+
309+
describeMemoryUsage( () => {
310+
testMemoryUsage(
311+
'should not grow on multiple create/destroy',
312+
() => DecoupledEditor
313+
.create( document.querySelector( '#mem-editor' ), {
314+
plugins: [ ArticlePluginSet ],
315+
toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote' ],
316+
image: {
317+
toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ]
318+
}
319+
} ) );
320+
} );
306321
} );

tests/manual/memory.html

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<p>
2+
<button id="destroyEditor">Destroy editor</button>
3+
<button id="initEditor">Init editor</button>
4+
</p>
5+
6+
<h2>The toolbar</h2>
7+
<div class="toolbar-container"></div>
8+
9+
<h2>The editable</h2>
10+
<div class="editable-container"></div>
11+
12+
<style>
13+
.editable-container,
14+
.toolbar-container {
15+
position: relative;
16+
border: 1px solid red;
17+
}
18+
19+
.editable-container::after,
20+
.toolbar-container::after {
21+
content: attr(class);
22+
position: absolute;
23+
background: red;
24+
color: #fff;
25+
top: 0;
26+
right: 0;
27+
font: 10px/2 monospace;
28+
padding: .1em .3em;
29+
}
30+
31+
.toolbar-container{
32+
padding: 1em;
33+
}
34+
35+
.editable-container {
36+
padding: 3em;
37+
overflow-y: scroll;
38+
max-height: 300px;
39+
}
40+
41+
.editable-container .ck-editor__editable {
42+
min-height: 21cm;
43+
padding: 2em;
44+
border: 1px #D3D3D3 solid;
45+
border-radius: var(--ck-border-radius);
46+
background: white;
47+
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
48+
}
49+
</style>

tests/manual/memory.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
3+
* For licensing, see LICENSE.md.
4+
*/
5+
6+
/* globals console:false, document, window */
7+
8+
import DecoupledEditor from '../../src/decouplededitor';
9+
import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
10+
11+
const editorData = '<h2>Hello world</h2><p>This is the decoupled editor.</p><img src="sample.jpg" />';
12+
13+
/*
14+
* Memory-leak safe version of decoupled editor manual test does not:
15+
* - define global variables (such as let editor; in main file scope)
16+
* - console.log() objects
17+
* - add event listeners with () => {} methods which reference other
18+
*/
19+
function initEditor() {
20+
DecoupledEditor
21+
.create( editorData, {
22+
plugins: [ ArticlePluginSet ],
23+
toolbar: {
24+
items: [
25+
'heading',
26+
'|',
27+
'bold',
28+
'italic',
29+
'link',
30+
'bulletedList',
31+
'numberedList',
32+
'blockQuote',
33+
'insertTable',
34+
'mediaEmbed',
35+
'undo',
36+
'redo'
37+
]
38+
},
39+
image: {
40+
toolbar: [
41+
'imageStyle:full',
42+
'imageStyle:side',
43+
'|',
44+
'imageTextAlternative'
45+
]
46+
},
47+
table: {
48+
contentToolbar: [
49+
'tableColumn',
50+
'tableRow',
51+
'mergeTableCells'
52+
]
53+
}
54+
} )
55+
.then( newEditor => {
56+
window.editor = newEditor;
57+
58+
document.querySelector( '.toolbar-container' ).appendChild( newEditor.ui.view.toolbar.element );
59+
document.querySelector( '.editable-container' ).appendChild( newEditor.ui.view.editable.element );
60+
61+
document.getElementById( 'destroyEditor' ).addEventListener( 'click', destroyEditor );
62+
} )
63+
.catch( err => {
64+
console.error( err.stack );
65+
} );
66+
67+
function destroyEditor() {
68+
window.editor.destroy().then( () => console.log( 'Editor was destroyed' ) );
69+
window.editor = null;
70+
document.getElementById( 'destroyEditor' ).removeEventListener( 'click', destroyEditor );
71+
}
72+
}
73+
74+
document.getElementById( 'initEditor' ).addEventListener( 'click', initEditor );

tests/manual/memory.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
1. Open DevTools on Chrome.
2+
2. Go to Memory tab.
3+
3. Select "Heap snapshot" profiling type.
4+
4. Click "Collect Garbage" (trash icon) and "Clear all profiles" (don't go icon).
5+
5. Record heap snapshot ("Take heap snapshot" a record icon).
6+
6. Repeat multiple times:
7+
- click "Init editor",
8+
- wait to editor show up ,
9+
- click "Destroy editor".
10+
7. Record heap snapshot again.
11+
8. Compare Snapshot 1 with Snapshot 2 and look for:
12+
- "detached" - HTML Elements/DOM nodes
13+
- "EventListener" - there should be only 1
14+
- Any CKEditor5 classes instances like "Editor" or "LivePosition"
15+
16+
## Notes:
17+
18+
* Browser extensions might attach event listeners to the DOM so the safest way to run this test is by running Chrome from command line:
19+
20+
```
21+
google-chrome \
22+
--enable-precise-memory-info \
23+
--disable-extensions \
24+
--disable-plugins \
25+
--incognito \
26+
http://localhost:8125
27+
```
28+
29+
The above will run Chrome without extensions or plugins in incognito mode and open manual tests page.
30+
31+
* Close any running Chrome instance beforehand because otherwise it will open a tab in currently opened Chrome (look for "Opening in existing browser session." in command line).

tests/manual/sample.jpg

112 KB
Loading

0 commit comments

Comments
 (0)