Page MenuHomeWickedGov Phorge

ve.qunit.js
No OneTemporary

Size
10 KB
Referenced Files
None
Subscribers
None

ve.qunit.js

/*!
* VisualEditor plugin for QUnit.
*
* @copyright See AUTHORS.txt
*/
/* global difflib,diffview */
( function ( QUnit ) {
/**
* Plugin for QUnit.
*
* @class ve.QUnit
* @extends QUnit
*/
/**
* Builds a summary of a node tree.
*
* Generated summaries contain node types, lengths, outer lengths, attributes and summaries for
* each child recursively. It's simple and fast to use deepEqual on this.
*
* @private
* @param {ve.Node} node Node tree to summarize
* @param {boolean} [shallow] Do not summarize each child recursively
* @return {Object} Summary of node tree
*/
function getNodeTreeSummary( node, shallow ) {
const summary = {
getType: node.getType(),
getLength: node.getLength(),
getOuterLength: node.getOuterLength(),
element: node.element
};
if ( node.children !== undefined ) {
const numChildren = node.children.length;
if ( !shallow ) {
summary.children = [];
for ( let i = 0; i < numChildren; i++ ) {
summary.children.push( getNodeTreeSummary( node.children[ i ] ) );
}
}
}
return summary;
}
/**
* Builds a summary of a node selection.
*
* Generated summaries contain length of results as well as node summaries, ranges, indexes, indexes
* within parent and node ranges for each result. It's simple and fast to use deepEqual on this.
*
* @private
* @param {Object[]} selection Selection to summarize
* @return {Object} Summary of selection
*/
function getNodeSelectionSummary( selection ) {
const summary = {
length: selection.length
};
if ( selection.length ) {
summary.results = [];
for ( let i = 0; i < selection.length; i++ ) {
summary.results.push( {
node: getNodeTreeSummary( selection[ i ].node, true ),
range: selection[ i ].range,
index: selection[ i ].index,
indexInNode: selection[ i ].indexInNode,
nodeRange: selection[ i ].nodeRange,
nodeOuterRange: selection[ i ].nodeOuterRange,
parentOuterRange: selection[ i ].parentOuterRange
} );
}
}
return summary;
}
/**
* Callback for ve#copy to convert nodes to a comparable summary.
*
* @private
* @param {ve.dm.Node|Object} value Value in the object/array
* @return {Object} Node summary if value is a node, otherwise just the value
*/
function convertNodes( value ) {
return value instanceof ve.dm.Node || value instanceof ve.ce.Node ?
getNodeTreeSummary( value ) :
value;
}
/**
* Undo what QUnit's escapeText does.
*
* @ignore
* @param {string} s
* @return {string}
*/
function unescapeText( s ) {
return s.replace( /&(#039|quot|lt|gt|amp);/g, ( match, seq ) => {
switch ( seq ) {
case '#039':
return '\'';
case 'quot':
return '"';
case 'lt':
return '<';
case 'gt':
return '>';
case 'amp':
return '&';
}
} );
}
/**
* Assertion helpers for VisualEditor test suite.
*
* @class ve.QUnit.assert
*/
/**
* Assert that summaries of two node trees are equal.
*
* @static
* @param {ve.Node} actual
* @param {ve.Node} expected
* @param {boolean} shallow
* @param {string} message
*/
QUnit.assert.equalNodeTree = function ( actual, expected, shallow, message ) {
if ( typeof shallow === 'string' && arguments.length === 3 ) {
message = shallow;
shallow = undefined;
}
const actualSummary = getNodeTreeSummary( actual, shallow );
const expectedSummary = getNodeTreeSummary( expected, shallow );
this.pushResult( {
result: QUnit.equiv( actualSummary, expectedSummary ),
actual: actualSummary,
expected: expectedSummary,
message: message
} );
};
/**
* @static
* @param {Object[]} actual
* @param {Object[]} expected
* @param {string} message
*/
QUnit.assert.equalNodeSelection = function ( actual, expected, message ) {
const actualSummary = getNodeSelectionSummary( actual ),
expectedSummary = getNodeSelectionSummary( expected );
for ( let i = 0; i < actual.length; i++ ) {
if ( expected[ i ] && expected[ i ].node !== actual[ i ].node ) {
this.pushResult( {
result: false,
actual: actualSummary,
expected: expectedSummary,
message: message + ' (reference equality for selection[' + i + '].node)'
} );
return;
}
}
this.pushResult( {
result: QUnit.equiv( actualSummary, expectedSummary ),
actual: actualSummary,
expected: expectedSummary,
message: message
} );
};
/**
* @static
* @param {HTMLElement} actual
* @param {HTMLElement} expected
* @param {string} message
*/
QUnit.assert.equalDomElement = function ( actual, expected, message ) {
const actualSummary = ve.getDomElementSummary( actual ),
expectedSummary = ve.getDomElementSummary( expected ),
actualSummaryHtml = ve.getDomElementSummary( actual, true ),
expectedSummaryHtml = ve.getDomElementSummary( expected, true );
this.pushResult( {
result: QUnit.equiv( actualSummary, expectedSummary ),
actual: actualSummaryHtml,
expected: expectedSummaryHtml,
message: message
} );
};
/**
* @static
* @param {HTMLElement} actual
* @param {HTMLElement} expected
* @param {string} message
*/
QUnit.assert.notEqualDomElement = function ( actual, expected, message ) {
const actualSummary = ve.getDomElementSummary( actual ),
expectedSummary = ve.getDomElementSummary( expected ),
actualSummaryHtml = ve.getDomElementSummary( actual, true ),
expectedSummaryHtml = ve.getDomElementSummary( expected, true );
this.pushResult( {
result: !QUnit.equiv( actualSummary, expectedSummary ),
actual: actualSummaryHtml,
expected: 'Not: ' + expectedSummaryHtml,
message: message
} );
};
function removeInternalState( val ) {
ve.deleteProp( val, 'internal', 'changesSinceLoad' );
ve.deleteProp( val, 'internal', 'metaItems' );
}
QUnit.assert.equalLinearData = function ( actual, expected, message ) {
function removeOriginalDomElements( val ) {
if ( val && val.type ) {
ve.deleteProp( val, 'originalDomElementsHash' );
ve.deleteProp( val, 'originalDomElements' );
removeInternalState( val );
}
if ( val && val.origTitle ) {
// HACK: This property is no longer used, ignore it for
// compatibility with existing tests in other extensions
delete val.origTitle;
}
}
actual = ve.copy( actual );
expected = ve.copy( expected );
actual = ve.copy( actual, null, removeOriginalDomElements );
expected = ve.copy( expected, null, removeOriginalDomElements );
this.pushResult( {
result: QUnit.equiv( actual, expected ),
actual: actual,
expected: expected,
message: message
} );
};
QUnit.assert.equalLinearDataWithDom = function ( store, actual, expected, message ) {
function addOriginalDomElements( val ) {
if ( val && val.originalDomElementsHash !== undefined ) {
val.originalDomElements = store.value( val.originalDomElementsHash );
delete val.originalDomElementsHash;
removeInternalState( val );
}
}
actual = ve.copy( actual );
expected = ve.copy( expected );
actual = ve.copy( actual, ve.convertDomElements, addOriginalDomElements );
expected = ve.copy( expected, ve.convertDomElements, addOriginalDomElements );
this.pushResult( {
result: QUnit.equiv( actual, expected ),
actual: actual,
expected: expected,
message: message
} );
};
/**
* Assert that two objects which may contain DOM elements are equal.
*
* @static
* @param {Object} actual
* @param {Object} expected
* @param {string} message
*/
QUnit.assert.deepEqualWithDomElements = function ( actual, expected, message ) {
// Recursively copy objects or arrays, converting any dom elements found to comparable summaries
actual = ve.copy( actual, ve.convertDomElements );
expected = ve.copy( expected, ve.convertDomElements );
this.pushResult( {
result: QUnit.equiv( actual, expected ),
actual: actual,
expected: expected,
message: message
} );
};
/**
* Assert that two objects which may contain node trees are equal.
*
* @static
* @param {Object} actual
* @param {Object} expected
* @param {string} message
*/
QUnit.assert.deepEqualWithNodeTree = function ( actual, expected, message ) {
// Recursively copy objects or arrays, converting any dom elements found to comparable summaries
actual = ve.copy( actual, convertNodes );
expected = ve.copy( expected, convertNodes );
this.pushResult( {
result: QUnit.equiv( actual, expected ),
actual: actual,
expected: expected,
message: message
} );
};
/**
* Assert that two ranges are equal.
*
* A range can be a ve.Range object or null.
*
* @param {ve.Range|null} actual
* @param {ve.Range|null} expected
* @param {string} message
*/
QUnit.assert.equalRange = function ( actual, expected, message ) {
actual = actual && {
from: actual.from,
to: actual.to
};
expected = expected && {
from: expected.from,
to: expected.to
};
this.pushResult( {
result: QUnit.equiv( actual, expected ),
actual: actual,
expected: expected,
message: message
} );
};
QUnit.assert.equalHash = function ( actual, expected, message ) {
actual = JSON.parse( JSON.stringify( actual ) );
expected = JSON.parse( JSON.stringify( expected ) );
this.pushResult( {
result: QUnit.equiv( actual, expected ),
actual: actual,
expected: expected,
message: message
} );
};
/**
* Assert that all linear data items are frozen.
*
* If not, array indexes of non-frozen items are reported.
*
* @static
* @param {ve.dm.LinearData} linearData
* @param {string} message
*/
QUnit.assert.isLinearDataFrozen = function ( linearData, message ) {
const notFrozen = [];
linearData.data.forEach( ( item, i ) => {
if ( !Object.isFrozen( item ) ) {
notFrozen.push( i );
}
} );
this.pushResult( {
result: notFrozen.length === 0,
actual: notFrozen,
expected: [],
message: message
} );
};
QUnit.diff = function ( o, n ) {
// o and n are partially HTML escaped by QUnit. As difflib does
// its own escaping we should unescape them first.
const oLines = difflib.stringAsLines( unescapeText( o ) ),
nLines = difflib.stringAsLines( unescapeText( n ) ),
sm = new difflib.SequenceMatcher( oLines, nLines ),
opcodes = sm.get_opcodes(),
$div = $( '<div>' );
$div.append( diffview.buildView( {
baseTextLines: oLines,
newTextLines: nLines,
opcodes: opcodes,
baseTextName: 'Expected',
newTextName: 'Result',
contextSize: 10,
viewType: 0
} ) );
return $div.html();
};
}( QUnit ) );

File Metadata

Mime Type
text/plain
Expires
Tue, Aug 18, 18:25 (3 w, 2 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
df/06/a5838156a9f64238ac5d9787b384
Default Alt Text
ve.qunit.js (10 KB)

Event Timeline