Page MenuHomeWickedGov Phorge

TestUtils.js
No OneTemporary

Size
9 KB
Referenced Files
None
Subscribers
None

TestUtils.js

/**
* @module
*/
'use strict';
require('../core-upgrade.js');
var entities = require('entities');
var ContentUtils = require('../lib/utils/ContentUtils.js').ContentUtils;
var DOMUtils = require('../lib/utils/DOMUtils.js').DOMUtils;
var DOMDataUtils = require('../lib/utils/DOMDataUtils.js').DOMDataUtils;
var Util = require('../lib/utils/Util.js').Util;
var WTUtils = require('../lib/utils/WTUtils.js').WTUtils;
var DOMNormalizer = require('../lib/html2wt/DOMNormalizer.js').DOMNormalizer;
var MockEnv = require('./MockEnv.js').MockEnv;
var TestUtils = {};
/**
* Little helper function for encoding XML entities.
*
* @param {string} string
* @return {string}
*/
TestUtils.encodeXml = function(string) {
return entities.encodeXML(string);
};
/**
* Specialized normalization of the PHP parser & Parsoid output, to ignore
* a few known-ok differences in parser test runs.
*
* This code is also used by the Parsoid round-trip testing code.
*
* If parsoidOnly is true-ish, we allow more markup through (like property
* and typeof attributes), for better checking of parsoid-only test cases.
*
* @param {string} domBody
* @param {Object} options
* @param {boolean} [options.parsoidOnly=false]
* @param {boolean} [options.preserveIEW=false]
* @param {boolean} [options.hackNormalize=false]
* @return {string}
*/
TestUtils.normalizeOut = function(domBody, options) {
if (!options) {
options = {};
}
const parsoidOnly = options.parsoidOnly;
const preserveIEW = options.preserveIEW;
if (options.hackyNormalize) {
// Mock env obj
//
// FIXME: This is ugly.
// (a) The normalizer shouldn't need the full env.
// Pass options and a logger instead?
// (b) DOM diff code is using page-id for some reason.
// That feels like a carryover of 2013 era code.
// If possible, get rid of it and diff-mark dependency
// on the env object.
const env = new MockEnv({}, null);
if (typeof (domBody) === 'string') {
domBody = env.createDocument(domBody).body;
}
var mockState = {
env,
selserMode: false,
};
DOMDataUtils.visitAndLoadDataAttribs(domBody, { markNew: true });
domBody = (new DOMNormalizer(mockState).normalize(domBody));
DOMDataUtils.visitAndStoreDataAttribs(domBody);
} else if (typeof (domBody) === 'string') {
domBody = DOMUtils.parseHTML(domBody).body;
}
var stripTypeof = parsoidOnly ?
/^mw:Placeholder$/ :
/^mw:(?:DisplaySpace|Placeholder|Nowiki|Transclusion|Entity)$/;
domBody = this.unwrapSpansAndNormalizeIEW(domBody, stripTypeof, parsoidOnly, preserveIEW);
var out = ContentUtils.toXML(domBody, { innerXML: true });
// NOTE that we use a slightly restricted regexp for "attribute"
// which works for the output of DOM serialization. For example,
// we know that attribute values will be surrounded with double quotes,
// not unquoted or quoted with single quotes. The serialization
// algorithm is given by:
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#serializing-html-fragments
if (!/[^<]*(<\w+(\s+[^\0-\cZ\s"'>\/=]+(="[^"]*")?)*\/?>[^<]*)*/.test(out)) {
throw new Error("normalizeOut input is not in standard serialized form");
}
// Eliminate a source of indeterminacy from leaked strip markers
out = out.replace(/UNIQ-.*?-QINU/g, '');
// Normalize COINS ids -- they aren't stable
out = out.replace(/\s?id=['"]coins_\d+['"]/ig, '');
// maplink extension
out = out.replace(/\s?data-overlays='[^']*'/ig, '');
if (parsoidOnly) {
// unnecessary attributes, we don't need to check these
// style is in there because we should only check classes.
out = out.replace(/ (data-parsoid|prefix|about|rev|datatype|inlist|usemap|vocab)=\\?"[^\"]*\\?"/g, '');
// single-quoted variant
out = out.replace(/ (data-parsoid|prefix|about|rev|datatype|inlist|usemap|vocab)=\\?'[^\']*\\?'/g, '');
// apos variant
out = out.replace(/ (data-parsoid|prefix|about|rev|datatype|inlist|usemap|vocab)=&apos;.*?&apos;/g, '');
// strip self-closed <nowiki /> because we frequently test WTS
// <nowiki> insertion by providing an html/parsoid section with the
// <meta> tags stripped out, allowing the html2wt test to verify that
// the <nowiki> is correctly added during WTS, while still allowing
// the html2html and wt2html versions of the test to pass as a
// sanity check. If <meta>s were not stripped, these tests would all
// have to be modified and split up. Not worth it at this time.
// (see commit 689b22431ad690302420d049b10e689de6b7d426)
out = out
.replace(/<span typeof="mw:Nowiki"><\/span>/g, '');
return out;
}
// Normalize headings by stripping out Parsoid-added ids so that we don't
// have to add these ids to every parser test that uses headings.
// We will test the id generation scheme separately via mocha tests.
out = out.replace(/(<h[1-6].*?) id="[^"]*"([^>]*>)/g, '$1$2');
// strip meta/link elements
out = out
.replace(/<\/?(?:meta|link)(?: [^\0-\cZ\s"'>\/=]+(?:=(?:"[^"]*"|'[^']*'))?)*\/?>/g, '');
// Ignore troublesome attributes.
// Strip JSON attributes like data-mw and data-parsoid early so that
// comment stripping in normalizeNewlines does not match unbalanced
// comments in wikitext source.
out = out.replace(/ (data-parsoid|prefix|about|rev|datatype|inlist|usemap|vocab|data-mw|resource|rel|property|class)=\\?"[^\"]*\\?"/g, '');
// single-quoted variant
out = out.replace(/ (data-parsoid|prefix|about|rev|datatype|inlist|usemap|vocab|data-mw|resource|rel|property|class)=\\?'[^\']*\\?'/g, '');
// strip typeof last
out = out.replace(/ typeof="[^\"]*"/g, '');
return out
// replace mwt ids
.replace(/ id="mw((t\d+)|([\w-]{2,}))"/g, '')
.replace(/<span[^>]+about="[^"]*"[^>]*>/g, '')
.replace(/(\s)<span>\s*<\/span>\s*/g, '$1')
.replace(/<span>\s*<\/span>/g, '')
.replace(/(href=")(?:\.?\.\/)+/g, '$1')
// replace unnecessary URL escaping
.replace(/ href="[^"]*"/g, Util.decodeURI)
// strip thumbnail size prefixes
.replace(/(src="[^"]*?)\/thumb(\/[0-9a-f]\/[0-9a-f]{2}\/[^\/]+)\/[0-9]+px-[^"\/]+(?=")/g, '$1$2');
};
/**
* Normalize newlines in IEW to spaces instead.
*
* @param {Node} body
* The document `<body>` node to normalize.
* @param {RegExp} [stripSpanTypeof]
* @param {boolean} [parsoidOnly=false]
* @param {boolean} [preserveIEW=false]
* @return {Node}
*/
TestUtils.unwrapSpansAndNormalizeIEW = function(body, stripSpanTypeof, parsoidOnly, preserveIEW) {
var newlineAround = function(node) {
return node && /^(BODY|CAPTION|DIV|DD|DT|LI|P|TABLE|TR|TD|TH|TBODY|DL|OL|UL|H[1-6])$/.test(node.nodeName);
};
var unwrapSpan; // forward declare
var cleanSpans = function(node) {
var child, next;
if (!stripSpanTypeof) {
return;
}
for (child = node.firstChild; child; child = next) {
next = child.nextSibling;
if (child.nodeName === 'SPAN' &&
stripSpanTypeof.test(child.getAttribute('typeof') || '')) {
unwrapSpan(node, child);
}
}
};
unwrapSpan = function(parent, node) {
// first recurse to unwrap any spans in the immediate children.
cleanSpans(node);
// now unwrap this span.
DOMUtils.migrateChildren(node, parent, node);
parent.removeChild(node);
};
var visit = function(node, stripLeadingWS, stripTrailingWS, inPRE) {
var child, next, prev;
if (node.nodeName === 'PRE') {
// Preserve newlines in <pre> tags
inPRE = true;
}
if (!preserveIEW && DOMUtils.isText(node)) {
if (!inPRE) {
node.data = node.data.replace(/\s+/g, ' ');
}
if (stripLeadingWS) {
node.data = node.data.replace(/^\s+/, '');
}
if (stripTrailingWS) {
node.data = node.data.replace(/\s+$/, '');
}
}
// unwrap certain SPAN nodes
cleanSpans(node);
// now remove comment nodes
if (!parsoidOnly) {
for (child = node.firstChild; child; child = next) {
next = child.nextSibling;
if (DOMUtils.isComment(child)) {
node.removeChild(child);
}
}
}
// reassemble text nodes split by a comment or span, if necessary
node.normalize();
// now recurse.
if (node.nodeName === 'PRE') {
// hack, since PHP adds a newline before </pre>
stripLeadingWS = false;
stripTrailingWS = true;
} else if (node.nodeName === 'SPAN' &&
/^mw[:]/.test(node.getAttribute('typeof') || '')) {
// SPAN is transparent; pass the strip parameters down to kids
} else {
stripLeadingWS = stripTrailingWS = newlineAround(node);
}
child = node.firstChild;
// Skip over the empty mw:FallbackId <span> and strip leading WS
// on the other side of it.
if (/^H[1-6]$/.test(node.nodeName) &&
child && WTUtils.isFallbackIdSpan(child)) {
child = child.nextSibling;
}
for (; child; child = next) {
next = child.nextSibling;
visit(child,
stripLeadingWS,
stripTrailingWS && !child.nextSibling,
inPRE);
stripLeadingWS = false;
}
if (inPRE || preserveIEW) {
return node;
}
// now add newlines around appropriate nodes.
for (child = node.firstChild; child; child = next) {
prev = child.previousSibling;
next = child.nextSibling;
if (newlineAround(child)) {
if (prev && DOMUtils.isText(prev)) {
prev.data = prev.data.replace(/\s*$/, '\n');
} else {
prev = node.ownerDocument.createTextNode('\n');
node.insertBefore(prev, child);
}
if (next && DOMUtils.isText(next)) {
next.data = next.data.replace(/^\s*/, '\n');
} else {
next = node.ownerDocument.createTextNode('\n');
node.insertBefore(next, child.nextSibling);
}
}
}
return node;
};
// clone body first, since we're going to destructively mutate it.
return visit(body.cloneNode(true), true, true, false);
};
if (typeof module === "object") {
module.exports.TestUtils = TestUtils;
}

File Metadata

Mime Type
text/plain
Expires
Sat, May 16, 22:29 (1 h, 41 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
9c/63/16aa0563fcf72f34424159774135
Default Alt Text
TestUtils.js (9 KB)

Event Timeline