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

Commit

Permalink
Filter out FSC before comparing expected children with the actual one…
Browse files Browse the repository at this point in the history
… because FSC is never returned as part of the expected ones.
  • Loading branch information
Reinmar committed Feb 26, 2019
1 parent 2f2b42e commit a1607f3
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 2 deletions.
18 changes: 18 additions & 0 deletions src/view/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,8 @@ export default class Renderer {
* @returns {Array.<String>} The list of actions based on the {@link module:utils/diff~diff} function.
*/
_diffNodeLists( actualDomChildren, expectedDomChildren ) {
actualDomChildren = filterOutFakeSelectionContainer( actualDomChildren, this._fakeSelectionContainer );

return diff( actualDomChildren, expectedDomChildren, sameNodes.bind( null, this.domConverter.blockFiller ) );
}

Expand Down Expand Up @@ -955,3 +957,19 @@ function fixGeckoSelectionAfterBr( focus, domSelection ) {
domSelection.addRange( domSelection.getRangeAt( 0 ) );
}
}

function filterOutFakeSelectionContainer( domChildList, fakeSelectionContainer ) {
const childList = Array.from( domChildList );

if ( childList.length == 0 || !fakeSelectionContainer ) {
return childList;
}

const last = childList[ childList.length - 1 ];

if ( last == fakeSelectionContainer ) {
childList.pop();
}

return childList;
}
141 changes: 139 additions & 2 deletions tests/view/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* For licensing, see LICENSE.md.
*/

/* globals document, window, NodeFilter */
/* globals document, window, NodeFilter, MutationObserver */

import View from '../../src/view/view';
import ViewElement from '../../src/view/element';
Expand Down Expand Up @@ -2302,7 +2302,7 @@ describe( 'Renderer', () => {
} );

// #1417
describe( 'optimal rendering', () => {
describe( 'optimal rendering – reusing existing nodes', () => {
it( 'should render inline element replacement (before text)', () => {
viewRoot._appendChild( parse( '<container:p><attribute:i>A</attribute:i>1</container:p>' ) );

Expand Down Expand Up @@ -3126,6 +3126,143 @@ describe( 'Renderer', () => {
} );
} );

describe( 'optimal (minimal) rendering – minimal children changes', () => {
let observer;

beforeEach( () => {
observer = new MutationObserver( () => {} );

observer.observe( domRoot, {
childList: true,
attributes: false,
subtree: false
} );
} );

afterEach( () => {
observer.disconnect();
} );

it( 'should add only one child (at the beginning)', () => {
viewRoot._appendChild( parse( '<container:p>1</container:p>' ) );

renderer.markToSync( 'children', viewRoot );
renderer.render();
cleanObserver( observer );

viewRoot._insertChild( 0, parse( '<container:p>2</container:p>' ) );

renderer.markToSync( 'children', viewRoot );
renderer.render();

expect( getMutationStats( observer.takeRecords() ) ).to.deep.equal( [
'added: 1, removed: 0'
] );
} );

it( 'should add only one child (at the end)', () => {
viewRoot._appendChild( parse( '<container:p>1</container:p>' ) );

renderer.markToSync( 'children', viewRoot );
renderer.render();
cleanObserver( observer );

viewRoot._appendChild( parse( '<container:p>2</container:p>' ) );

renderer.markToSync( 'children', viewRoot );
renderer.render();

expect( getMutationStats( observer.takeRecords() ) ).to.deep.equal( [
'added: 1, removed: 0'
] );
} );

it( 'should add only one child (in the middle)', () => {
viewRoot._appendChild( parse( '<container:p>1</container:p><container:p>2</container:p>' ) );

renderer.markToSync( 'children', viewRoot );
renderer.render();
cleanObserver( observer );

viewRoot._insertChild( 1, parse( '<container:p>3</container:p>' ) );

renderer.markToSync( 'children', viewRoot );
renderer.render();

expect( getMutationStats( observer.takeRecords() ) ).to.deep.equal( [
'added: 1, removed: 0'
] );
} );

it( 'should not touch elements at all (rendering texts is enough)', () => {
viewRoot._appendChild( parse( '<container:p>1</container:p><container:p>2</container:p>' ) );

renderer.markToSync( 'children', viewRoot );
renderer.render();
cleanObserver( observer );

viewRoot._insertChild( 1, parse( '<container:p>3</container:p>' ) );
viewRoot._removeChildren( 0, 1 );

renderer.markToSync( 'children', viewRoot );
renderer.render();

expect( getMutationStats( observer.takeRecords() ) ).to.be.empty;
} );

it( 'should add and remove one', () => {
viewRoot._appendChild( parse( '<container:p>1</container:p><container:p>2</container:p>' ) );

renderer.markToSync( 'children', viewRoot );
renderer.render();
cleanObserver( observer );

viewRoot._insertChild( 1, parse( '<container:h1>3</container:h1>' ) );
viewRoot._removeChildren( 0, 1 );

renderer.markToSync( 'children', viewRoot );
renderer.render();

expect( getMutationStats( observer.takeRecords() ) ).to.deep.equal( [
'added: 1, removed: 0',
'added: 0, removed: 1'
] );
} );

it( 'should not touch the FSC when rendering children', () => {
viewRoot._appendChild( parse( '<container:p>1</container:p><container:p>2</container:p>' ) );

// Set fake selection on the second paragraph.
selection._setTo( viewRoot.getChild( 1 ), 'on', { fake: true } );

renderer.markToSync( 'children', viewRoot );
renderer.render();
cleanObserver( observer );

// Remove the second paragraph.
viewRoot._removeChildren( 1, 1 );
// And set the fake selection on the first one.
selection._setTo( viewRoot.getChild( 0 ), 'on', { fake: true } );

renderer.markToSync( 'children', viewRoot );
renderer.render();

expect( getMutationStats( observer.takeRecords() ) ).to.deep.equal( [
'added: 0, removed: 1'
] );
} );

function getMutationStats( mutationList ) {
return mutationList.map( mutation => {
return `added: ${ mutation.addedNodes.length }, removed: ${ mutation.removedNodes.length }`;
} );
}

function cleanObserver( observer ) {
observer.takeRecords();
}
} );

// #1560
describe( 'attributes manipulation on replaced element', () => {
it( 'should rerender element if it was removed after having its attributes removed (attribute)', () => {
Expand Down

0 comments on commit a1607f3

Please sign in to comment.