8
0
Просмотр исходного кода

Internal: Enabled memory leak tests. Closes #1731.

Re-enable Memory tests.
Marek Lewandowski 5 лет назад
Родитель
Сommit
9f0efa80c1

+ 15 - 5
packages/ckeditor5-core/tests/_utils/memory.js

@@ -31,8 +31,8 @@ const GARBAGE_COLLECTOR_TIMEOUT = 500;
  */
  */
 export function describeMemoryUsage( callback ) {
 export function describeMemoryUsage( callback ) {
 	// Skip all memory tests due to https://github.com/ckeditor/ckeditor5/issues/1731.
 	// Skip all memory tests due to https://github.com/ckeditor/ckeditor5/issues/1731.
-	describe.skip( 'memory usage', () => {
-		skipIfNoGarbageCollector();
+	describe( 'memory usage', () => {
+		skipIfIncompatibleEnvironment();
 
 
 		beforeEach( createEditorElement );
 		beforeEach( createEditorElement );
 
 
@@ -141,16 +141,26 @@ function collectMemoryStats() {
 	} );
 	} );
 }
 }
 
 
-// Will skip test suite if not in compatible browser.
+// Will skip test suite if tests are run inside incompatible environment:
+// - No window.gc (only Google Chrome).
+// - Chrome on Windows (tests heavily break).
+//
 // Currently on Google Chrome supports this method and must be run with proper flags:
 // Currently on Google Chrome supports this method and must be run with proper flags:
 //
 //
 // 		google-chrome -js-flags="--expose-gc"
 // 		google-chrome -js-flags="--expose-gc"
 //
 //
-function skipIfNoGarbageCollector() {
+function skipIfIncompatibleEnvironment() {
 	// eslint-disable-next-line mocha/no-top-level-hooks
 	// eslint-disable-next-line mocha/no-top-level-hooks
 	before( function() {
 	before( function() {
-		if ( !window.gc ) {
+		if ( !window.gc || isWindows() ) {
 			this.skip();
 			this.skip();
 		}
 		}
 	} );
 	} );
 }
 }
+
+// The windows environment does not cooperate with this tests.
+function isWindows() {
+	const userAgent = window.navigator.userAgent.toLowerCase();
+
+	return userAgent.indexOf( 'windows' ) > -1;
+}

+ 2 - 2
packages/ckeditor5-editor-balloon/tests/manual/memory.md

@@ -2,7 +2,7 @@
 2. Go to Memory tab.
 2. Go to Memory tab.
 3. Select "Heap snapshot" profiling type.
 3. Select "Heap snapshot" profiling type.
 4. Click "Collect Garbage" (trash icon) and "Clear all profiles" (don't go icon).
 4. Click "Collect Garbage" (trash icon) and "Clear all profiles" (don't go icon).
-5. Record heap snapshot ("Take heap snapshot" a record icon).
+5. Take heap snapshot (record icon).
 6. Repeat multiple times:
 6. Repeat multiple times:
     - click "Init editor",
     - click "Init editor",
     - wait to editor show up ,
     - wait to editor show up ,
@@ -23,7 +23,7 @@
         --disable-extensions \
         --disable-extensions \
         --disable-plugins \
         --disable-plugins \
         --incognito \
         --incognito \
-        http://localhost:8125 
+        http://localhost:8125
     ```
     ```
 
 
     The above will run Chrome without extensions or plugins in incognito mode and open manual tests page.
     The above will run Chrome without extensions or plugins in incognito mode and open manual tests page.

+ 2 - 2
packages/ckeditor5-editor-classic/tests/manual/memory.md

@@ -2,7 +2,7 @@
 2. Go to Memory tab.
 2. Go to Memory tab.
 3. Select "Heap snapshot" profiling type.
 3. Select "Heap snapshot" profiling type.
 4. Click "Collect Garbage" (trash icon) and "Clear all profiles" (don't go icon).
 4. Click "Collect Garbage" (trash icon) and "Clear all profiles" (don't go icon).
-5. Record heap snapshot ("Take heap snapshot" a record icon).
+5. Take heap snapshot (record icon).
 6. Repeat multiple times:
 6. Repeat multiple times:
     - click "Init editor",
     - click "Init editor",
     - wait to editor show up ,
     - wait to editor show up ,
@@ -23,7 +23,7 @@
         --disable-extensions \
         --disable-extensions \
         --disable-plugins \
         --disable-plugins \
         --incognito \
         --incognito \
-        http://localhost:8125 
+        http://localhost:8125
     ```
     ```
 
 
     The above will run Chrome without extensions or plugins in incognito mode and open manual tests page.
     The above will run Chrome without extensions or plugins in incognito mode and open manual tests page.

+ 2 - 2
packages/ckeditor5-editor-decoupled/tests/manual/memory.md

@@ -2,7 +2,7 @@
 2. Go to Memory tab.
 2. Go to Memory tab.
 3. Select "Heap snapshot" profiling type.
 3. Select "Heap snapshot" profiling type.
 4. Click "Collect Garbage" (trash icon) and "Clear all profiles" (don't go icon).
 4. Click "Collect Garbage" (trash icon) and "Clear all profiles" (don't go icon).
-5. Record heap snapshot ("Take heap snapshot" a record icon).
+5. Take heap snapshot (record icon).
 6. Repeat multiple times:
 6. Repeat multiple times:
     - click "Init editor",
     - click "Init editor",
     - wait to editor show up ,
     - wait to editor show up ,
@@ -23,7 +23,7 @@
         --disable-extensions \
         --disable-extensions \
         --disable-plugins \
         --disable-plugins \
         --incognito \
         --incognito \
-        http://localhost:8125 
+        http://localhost:8125
     ```
     ```
 
 
     The above will run Chrome without extensions or plugins in incognito mode and open manual tests page.
     The above will run Chrome without extensions or plugins in incognito mode and open manual tests page.

+ 2 - 2
packages/ckeditor5-editor-inline/tests/manual/memory.md

@@ -2,7 +2,7 @@
 2. Go to Memory tab.
 2. Go to Memory tab.
 3. Select "Heap snapshot" profiling type.
 3. Select "Heap snapshot" profiling type.
 4. Click "Collect Garbage" (trash icon) and "Clear all profiles" (don't go icon).
 4. Click "Collect Garbage" (trash icon) and "Clear all profiles" (don't go icon).
-5. Record heap snapshot ("Take heap snapshot" a record icon).
+5. Take heap snapshot (record icon).
 6. Repeat multiple times:
 6. Repeat multiple times:
     - click "Init editor",
     - click "Init editor",
     - wait to editor show up ,
     - wait to editor show up ,
@@ -23,7 +23,7 @@
         --disable-extensions \
         --disable-extensions \
         --disable-plugins \
         --disable-plugins \
         --incognito \
         --incognito \
-        http://localhost:8125 
+        http://localhost:8125
     ```
     ```
 
 
     The above will run Chrome without extensions or plugins in incognito mode and open manual tests page.
     The above will run Chrome without extensions or plugins in incognito mode and open manual tests page.

+ 186 - 0
tests/manual/memory/memory.html

@@ -0,0 +1,186 @@
+<head>
+	<meta http-equiv="Content-Security-Policy" content="script-src 'self' https://ckeditor.com 'unsafe-inline' 'unsafe-eval'">
+</head>
+
+<p>
+	<button id="destroyEditor">Destroy editor</button>
+	<button id="initEditor">Init editor</button>
+</p>
+
+<div style="margin-bottom: 10px;">
+	<button type="button" id="clear-content">Clear editor</button>
+	<button type="button" id="print-data-action">Open print preview</button>
+	<button id="read-only">Turn on read-only mode</button>
+
+	<iframe id="print-data-container" aria-hidden="true" tabindex="-1"></iframe>
+</div>
+
+<div id="editor">
+	<h2>Lists in the table</h2>
+	<figure class="table">
+		<table style="width: 600px;border-bottom:2px dashed hsl(0, 0%, 60%);border-left:2px dashed hsl(0, 0%, 60%);border-right:2px dashed hsl(0, 0%, 60%);border-top:2px dashed hsl(0, 0%, 60%);">
+			<tbody>
+				<tr>
+					<td style="text-align: center"><span class="text-big" style="font-weight: bold">Bulleted list</span></td>
+					<td style="text-align: center"><span class="text-big" style="font-weight: bold">Numbered list</span></td>
+					<td style="text-align: center"><span class="text-big" style="font-weight: bold">To do list</span></td>
+				</tr>
+				<tr>
+					<td style="vertical-align:top; width: 33%">
+						<ul>
+							<li>UL List item 1</li>
+							<li>UL List item 2</li>
+						</ul>
+					</td>
+					<td style="vertical-align:top; width: 33%">
+						<ol>
+							<li>OL List item 1</li>
+							<li>OL List item 2</li>
+						</ol>
+					</td>
+					<td style="vertical-align:top; width: 33%">
+						<ul class="todo-list">
+							<li>
+								<label class="todo-list__label">
+									<input type="checkbox" />
+									<span class="todo-list__label__description">Foo</span>
+								</label>
+							</li>
+							<li>
+								<label class="todo-list__label">
+									<input type="checkbox" checked="checked" />
+									<span class="todo-list__label__description">Foo</span>
+								</label>
+							</li>
+						</ul>
+					</td>
+				</tr>
+			</tbody>
+		</table>
+	</figure>
+
+	<h2>Basic features overview</h2>
+	<p>Lorem <b>ipsum dolor sit </b>amet, consectetur <i>adipisicing elit</i>.<sub>1</sub></p>
+	<h3>Basic styles</h3>
+	<p>Ad alias, <s>architecto</s> culpa <b><i>cumque</i></b> dignissimos <code>dolor eos incidunt ipsa itaque</code> <u>laboriosam</u> magnam molestias nihil <i><u>numquam</u></i> odit quam, suscipit <i><s>veritatis</s></i> voluptate voluptatum.<sup>2</sup></p>
+	<h3>Image</h3>
+	<figure class="image">
+		<img alt="bar" src="../sample.jpg">
+		<figcaption>Caption</figcaption>
+	</figure>
+	<h3>Blockquote</h3>
+	<blockquote>
+		<p>Quote</p>
+		<ul>
+			<li><a href="#">Quoted</a> UL List item 1</li>
+			<li>Quoted UL List item 2</li>
+		</ul>
+		<p>Quote</p>
+	</blockquote>
+
+	<div class="page-break" style="page-break-after:always;"><span style="display:none;">&nbsp;</span></div>
+
+	<h2>Media with previews in the table</h2>
+	<figure class="table">
+		<table style="background-color:hsl(0,0%,90%);border-bottom:2px solid hsl(0, 0%, 0%);border-left:2px solid hsl(0, 0%, 0%);border-right:2px solid hsl(0, 0%, 0%);border-top:2px solid hsl(0, 0%, 0%);">
+			<tbody>
+				<tr>
+					<td style="text-align: center"><span class="text-big" style="font-weight: bold">Service</span></td>
+					<td style="text-align: center"><span class="text-big" style="font-weight: bold">Preview</span></td>
+					<td style="text-align: center"><span class="text-big" style="font-weight: bold">URL</span></td>
+				</tr>
+				<tr>
+					<td style="text-align: center"><u>YouTube</u></td>
+					<td>
+						<figure class="media">
+							<oembed url="https://www.youtube.com/watch?v=ZVv7UMQPEWk"></oembed>
+						</figure>
+					</td>
+					<td>
+						<span class="text-small"><a href="https://www.youtube.com/watch?v=ZVv7UMQPEWk">https://www.youtube.com/watch?v=ZVv7UMQPEWk</a></span>
+					</td>
+				</tr>
+				<tr>
+					<td style="text-align: center"><u>Vimeo</u></td>
+					<td>
+						<figure class="media">
+							<oembed url="https://vimeo.com/1084537"></oembed>
+						</figure>
+					</td>
+					<td>
+						<span class="text-small"><a href="https://vimeo.com/1084537">https://vimeo.com/1084537</a></span>
+					</td>
+				</tr>
+			</tbody>
+		</table>
+	</figure>
+
+	<h2>Code blocks in the table</h2>
+	<figure class="table">
+		<table style="border-bottom:2px dashed hsl(0, 0%, 60%);border-left:2px dashed hsl(0, 0%, 60%);border-right:2px dashed hsl(0, 0%, 60%);border-top:2px dashed hsl(0, 0%, 60%);">
+			<tbody>
+				<tr>
+					<td style="text-align: center"><span class="text-big" style="font-weight: bold">Language</span></td>
+					<td style="text-align: center"><span class="text-big" style="font-weight: bold">Code snippet</span></td>
+					<td style="text-align: center"><span class="text-big" style="font-weight: bold">Language</span></td>
+					<td style="text-align: center"><span class="text-big" style="font-weight: bold">Code snippet</span></td>
+				</tr>
+				<tr>
+					<td style="text-align: center;vertical-align:top">CSS</td>
+					<td style="vertical-align:top">
+					<pre><code class="language-css">body {
+	color: red;
+}
+
+p {
+	font-size: 10px;
+}</code></pre></td>
+					<td style="text-align: center;vertical-align:top">PHP</td>
+					<td style="vertical-align:top"><pre><code class="language-php">&lt;?php
+
+function dump( array ...$args ) {
+	foreach ( $args as $item ) {
+		var_dump( $item );
+	}
+
+	die;
+}</code></pre></td>
+				</tr>
+				<tr>
+					<td style="text-align: center;vertical-align:top">JavaScript</td>
+					<td style="vertical-align:top">
+					<pre><code class="language-javascript">function foo() {
+	console.log( 'indented using 1 tab' );
+}
+
+function bar() {
+    console.log( 'indented using spaces' );
+}</code></pre></td>
+					<td style="text-align: center;vertical-align:top">Plaintext</td>
+					<td style="vertical-align:top"><pre><code class="language-plaintext">Plain text</code></pre></td>
+				</tr>
+			</tbody>
+		</table>
+	</figure>
+</div>
+
+<style>
+	#print-data-container {
+		position: absolute;
+		width: 1px;
+		height: 1px;
+		margin: -1px;
+		border: 0;
+		padding: 0;
+		white-space: nowrap;
+		clip-path: inset(100%);
+		clip: rect(0 0 0 0);
+		overflow: hidden;
+	}
+	.custom-class {
+		margin-top: 100px;
+		margin-left: 100px;
+		margin-bottom: 100px;
+		width: 450px;
+	}
+</style>

+ 155 - 0
tests/manual/memory/memory.js

@@ -0,0 +1,155 @@
+/**
+ * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
+ */
+
+/* globals console:false, document */
+
+import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
+import TableProperties from '@ckeditor/ckeditor5-table/src/tableproperties';
+import TableCellProperties from '@ckeditor/ckeditor5-table/src/tablecellproperties';
+import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset';
+import Underline from '@ckeditor/ckeditor5-basic-styles/src/underline';
+import Code from '@ckeditor/ckeditor5-basic-styles/src/code';
+import Strikethrough from '@ckeditor/ckeditor5-basic-styles/src/strikethrough';
+import Superscript from '@ckeditor/ckeditor5-basic-styles/src/superscript';
+import Subscript from '@ckeditor/ckeditor5-basic-styles/src/subscript';
+import FontColor from '@ckeditor/ckeditor5-font/src/fontcolor';
+import FontBackgroundColor from '@ckeditor/ckeditor5-font/src/fontbackgroundcolor';
+import FontFamily from '@ckeditor/ckeditor5-font/src/fontfamily';
+import FontSize from '@ckeditor/ckeditor5-font/src/fontsize';
+import CodeBlock from '@ckeditor/ckeditor5-code-block/src/codeblock';
+import WordCount from '@ckeditor/ckeditor5-word-count/src/wordcount';
+import TodoList from '@ckeditor/ckeditor5-list/src/todolist';
+import SpecialCharacters from '@ckeditor/ckeditor5-special-characters/src/specialcharacters';
+import SpecialCharactersEssentials from '@ckeditor/ckeditor5-special-characters/src/specialcharactersessentials';
+import PageBreak from '@ckeditor/ckeditor5-page-break/src/pagebreak';
+import HorizontalLine from '@ckeditor/ckeditor5-horizontal-line/src/horizontalline';
+import Highlight from '@ckeditor/ckeditor5-highlight/src/highlight';
+import IndentBlock from '@ckeditor/ckeditor5-indent/src/indentblock';
+import EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';
+import Mention from '@ckeditor/ckeditor5-mention/src/mention';
+import RemoveFormat from '@ckeditor/ckeditor5-remove-format/src/removeformat';
+import Alignment from '@ckeditor/ckeditor5-alignment/src/alignment';
+import TextTransformation from '@ckeditor/ckeditor5-typing/src/texttransformation';
+
+import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config';
+
+/*
+ * Memory-leak safe version of balloon editor manual test does not:
+ * - define global variables (such as let editor; in main file scope)
+ * - console.log() objects
+ * - add event listeners with () => {} methods which reference other
+ */
+function initEditor() {
+	ClassicEditor
+		.create( document.querySelector( '#editor' ), {
+			plugins: [
+				ArticlePluginSet, CodeBlock, Alignment,
+				TableProperties, TableCellProperties, SpecialCharacters, SpecialCharactersEssentials,
+				Code, Underline, Strikethrough, Superscript, Subscript,
+				Highlight, FontColor, FontBackgroundColor, FontFamily, FontSize,
+				IndentBlock, WordCount, EasyImage,
+				TodoList, PageBreak, HorizontalLine, Mention, RemoveFormat, TextTransformation
+			],
+			toolbar: [
+				'heading',
+				'|',
+				'removeFormat', 'bold', 'italic', 'strikethrough', 'underline', 'code', 'subscript', 'superscript', 'link',
+				'|',
+				'highlight', 'fontSize', 'fontFamily', 'fontColor', 'fontBackgroundColor',
+				'|',
+				'bulletedList', 'numberedList', 'todoList',
+				'|',
+				'blockQuote', 'imageUpload', 'insertTable', 'mediaEmbed', 'codeBlock',
+				'|',
+				'alignment', 'outdent', 'indent',
+				'|',
+				'pageBreak', 'horizontalLine', 'specialCharacters',
+				'|',
+				'undo', 'redo'
+			],
+			cloudServices: CS_CONFIG,
+			table: {
+				contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells', 'tableProperties', 'tableCellProperties' ]
+			},
+			image: {
+				styles: [
+					'full',
+					'alignLeft',
+					'alignRight'
+				],
+				toolbar: [ 'imageTextAlternative', '|', 'imageStyle:alignLeft', 'imageStyle:full', 'imageStyle:alignRight' ]
+			},
+			placeholder: 'Type the content here!',
+			mention: {
+				feeds: [
+					{
+						marker: '@',
+						feed: [
+							'@apple', '@bears', '@brownie', '@cake', '@cake', '@candy', '@canes', '@chocolate', '@cookie', '@cotton',
+							'@cream', '@cupcake', '@danish', '@donut', '@dragée', '@fruitcake', '@gingerbread', '@gummi', '@ice',
+							'@jelly-o', '@liquorice', '@macaroon', '@marzipan', '@oat', '@pie', '@plum', '@pudding', '@sesame',
+							'@snaps', '@soufflé', '@sugar', '@sweet', '@topping', '@wafer'
+						],
+						minimumCharacters: 1
+					}
+				]
+			}
+		} )
+		.then( editor => {
+			editor.plugins.get( 'WordCount' ).on( 'update', ( evt, stats ) => {
+				console.log( `Characters: ${ stats.characters }, words: ${ stats.words }.` );
+			} );
+
+			document.getElementById( 'clear-content' ).addEventListener( 'click', clearData );
+			document.getElementById( 'print-data-action' ).addEventListener( 'click', printData );
+			document.getElementById( 'read-only' ).addEventListener( 'click', readOnly );
+			document.getElementById( 'destroyEditor' ).addEventListener( 'click', destroyEditor );
+
+			function destroyEditor() {
+				editor.destroy().then( () => console.log( 'Editor was destroyed' ) );
+				editor = null;
+				document.getElementById( 'destroyEditor' ).removeEventListener( 'click', destroyEditor );
+				document.getElementById( 'clear-content' ).removeEventListener( 'click', clearData );
+				document.getElementById( 'print-data-action' ).removeEventListener( 'click', printData );
+				document.getElementById( 'read-only' ).removeEventListener( 'click', readOnly );
+			}
+
+			function readOnly() {
+				editor.isReadOnly = !editor.isReadOnly;
+				document.getElementById( 'read-only' ).textContent =
+					editor.isReadOnly ? 'Turn off read-only mode' : 'Turn on read-only mode';
+
+				editor.editing.view.focus();
+			}
+
+			function printData() {
+				const iframeElement = document.getElementById( 'print-data-container' );
+
+				/* eslint-disable max-len */
+				iframeElement.srcdoc = '<html>' +
+					'<head>' +
+					`<title>${ document.title }</title>` +
+					'<link rel="stylesheet" href="https://ckeditor.com/docs/ckeditor5/latest/snippets/features/page-break/snippet.css" type="text/css">' +
+					'</head>' +
+					'<body class="ck-content">' +
+					editor.getData() +
+					'<script>' +
+					'window.addEventListener( \'DOMContentLoaded\', () => { window.print(); } );' +
+					'</script>' +
+					'</body>' +
+					'</html>';
+				/* eslint-enable max-len */
+			}
+
+			function clearData() {
+				editor.setData( '' );
+			}
+		} )
+		.catch( err => {
+			console.error( err.stack );
+		} );
+}
+
+document.getElementById( 'initEditor' ).addEventListener( 'click', initEditor );

+ 31 - 0
tests/manual/memory/memory.md

@@ -0,0 +1,31 @@
+1. Open DevTools on Chrome.
+2. Go to Memory tab.
+3. Select "Heap snapshot" profiling type.
+4. Click "Collect Garbage" (trash icon) and "Clear all profiles" (don't go icon).
+5. Take heap snapshot (record icon).
+6. Repeat multiple times:
+    - click "Init editor",
+    - wait to editor show up ,
+    - click "Destroy editor".
+7. Record heap snapshot again.
+8. Compare Snapshot 1 with Snapshot 2 and look for:
+    - "detached" - HTML Elements/DOM nodes
+    - "EventListener" - there should be only 1
+    - Any CKEditor5 classes instances like "Editor" or "LivePosition"
+
+## Notes:
+
+* Browser extensions might attach event listeners to the DOM, so the safest way to run this test is by running Chrome from command line:
+
+    ```
+    google-chrome \
+        --enable-precise-memory-info \
+        --disable-extensions \
+        --disable-plugins \
+        --incognito \
+        http://localhost:8125/ckeditor5/tests/manual/memory/memory.html
+    ```
+
+    The above will run Chrome without extensions or plugins in incognito mode and open manual tests page.
+
+* 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).