1
0
mirror of https://github.com/webrecorder/pywb.git synced 2025-03-15 08:04:49 +01:00
pywb/wombat/internal/testPageBundle.js

191 lines
5.9 KiB
JavaScript
Raw Permalink Normal View History

wombat overhaul! fixes #449 (#451) wombat: - I: function overrides applied by wombat now better appear to be the original new function name same as originals when possible - I: WombatLocation now looks and behaves more like the original Location interface - I: The custom storage class now looks and behaves more like the original Storage - I: SVG image rewriting has been improved: both the href and xlink:href deprecated since SVG2 now rewritten always - I: document.open now handles the case of creation of a new window - I: Request object rewriting of the readonly href property is now correctly handled - I: EventTarget.addEventListener, removeEventListener overrides now preserve the original this argument of the wrapped listener - A: document.close override to ensure wombat is initialized after write or writeln usage - A: reconstruction of <doctype...> in rewriteHTMLComplete IFF it was included in the original string of HTML - A: document.body setter override to ensure rewriting of the new body or frameset - A: Attr.[value, nodeValue, textContent] added setter override to perform URL rewrites - A: SVGElements rewriting of the filter, style, xlink:href, href, and src attributes - A: HTMLTrackElement rewriting of the src attribute of the - A: HTMLQuoteElement and HTMLModElement rewriting of the cite attribute - A: Worklet.addModule: Loads JS module specified by a URL. - A: HTMLHyperlinkElementUtils overrides to the areaelement - A: ShadowRootoverrides to: innerHTML even though inherites from DocumentFragement and Node it still has innerHTML getter setter. - A: ShadowRoot, Element, DocumentFragment append, prepend: adds strings of HTML or a new Node inherited from ParentNode - A: StylePropertyMap override: New way to access and set CSS properties. - A: Response.redirecthttps rewriting of the URL argument. - A: UIEvent, MouseEvent, TouchEvent, KeyboardEvent, WheelEvent, InputEvent, and CompositionEven constructor and init{even-name} overrides in order to ensure that wombats JS Proxy usage does not affect their defined behaviors - A: XSLTProcessor override to ensure its usage is not affected by wombats JS Proxy usage. - A: navigator.unregisterProtocolHandler: Same override as existing navigator.registerProtocolHandler but from the inverse operation - A: PresentationRequest: Constructor takes a URL or an array of URLs. - A: EventSource and WebSocket override in order to ensure that they do not cause live leaks - A: overrides for the child node interface - Fix: autofetch worker creatation of the backing worker when it is operating within an execution context with a null origin tests: - A: 559 tests specific to wombat and client side rewritting pywb: - Fix: a few broken tests due to iana.org requiring a user agent in its requests rewrite: - introduced a new JSWorkerRewriter class in order to support rewriting via wombat workers in the context of all supported worker variants via - ensured rewriter app correctly sets the static prefix ci: - Modified travis.yml to specifically enumerate jobs documentation: - Documented new wombat, wombat proxy moded, wombat workers auto-fetch: - switched to mutation observer when in proxy mode so that the behaviors can operate in tandem with the autofetcher
2019-05-15 14:42:51 -04:00
import get from 'lodash-es/get';
/**
* @type {TestOverwatch}
*/
window.TestOverwatch = class TestOverwatch {
/**
* @param {Object} domStructure
*/
constructor(domStructure) {
/**
* @type {{document: Document, window: Window}}
*/
this.ownContextWinDoc = { window, document };
this.wbMessages = { load: false };
this.domStructure = domStructure;
/**
* @type {HTMLIFrameElement}
*/
this.sandbox = domStructure.sandbox;
window.addEventListener(
'message',
event => {
if (event.data) {
const { data } = event;
switch (data.wb_type) {
case 'load':
this.wbMessages.load =
this.wbMessages.load || data.readyState === 'complete';
this.domStructure.load.url.data = data.url;
this.domStructure.load.title.data = data.title;
this.domStructure.load.readyState.data = data.readyState;
break;
case 'replace-url':
this.wbMessages['replace-url'] = data;
this.domStructure.replaceURL.url.data = data.url;
this.domStructure.replaceURL.title.data = data.title;
break;
case 'title':
this.wbMessages.title = data.title;
this.domStructure.titleMsg.data = data.title;
break;
case 'hashchange':
this.domStructure.hashchange.data = data.title;
this.wbMessages.hashchange = data.hash;
break;
case 'cookie':
this.domStructure.cookie.domain = data.domain;
this.domStructure.cookie.cookie = data.cookie;
this.wbMessages.cookie = data;
break;
default:
this.domStructure.unknown.data = JSON.stringify(data);
break;
}
}
},
false
);
}
/**
* This function initializes the wombat in the sandbox and ads a single
* additional property to the sandbox's window WombatTestUtil, an object that provides
* any functionality required for tests. This is done in order to ensure testing
* environment purity.
*/
initSandbox() {
this.domStructure.reset();
this.wbMessages = { load: false };
this.sandbox.contentWindow._WBWombatInit(this.sandbox.contentWindow.wbinfo);
this.sandbox.contentWindow.WombatTestUtil = {
didWombatSendTheLoadMsg: () => this.wbMessages.load,
wombatSentTitleUpdate: () => this.wbMessages.title,
wombatSentReplaceUrlMsg: () => this.wbMessages['replace-url'],
createUntamperedWithElement: init => this.createElement(init),
getElementPropertyAsIs: (elem, prop) =>
this.getElementPropertyAsIs(elem, prop),
getElementNSPropertyAsIs: (elem, ns, prop) =>
this.getElementNSPropertyAsIs(elem, ns, prop),
getOriginalWinDomViaPath: objectPath =>
this.getOriginalWinDomViaPath(objectPath),
getViaPath: (obj, objectPath) => get(obj, objectPath),
getOriginalPropertyDescriptorFor: (elem, prop) =>
this.ownContextWinDoc.window.Reflect.getOwnPropertyDescriptor(
elem,
prop
),
getStylePropertyAsIs: (elem, prop) =>
this.getStylePropertyAsIs(elem, prop),
getCSSPropertyAsIs: (elem, prop) => this.getCSSPropertyAsIs(elem, prop)
};
}
maybeInitSandbox() {
if (this.sandbox.contentWindow.WB_wombat_location != null) return;
this.initSandbox();
}
/**
* Creates a DOM element(s) based on the supplied creation options.
* @param {Object} init - Options for new element creation
* @return {HTMLElement|Node} - The newly created element
*/
createElement(init) {
if (typeof init === 'string') {
return this.ownContextWinDoc.document.createElement(init);
}
if (init.tag === 'textNode') {
var tn = this.ownContextWinDoc.document.createTextNode(init.value || '');
if (init.ref) init.ref(tn);
return tn;
}
var elem = this.ownContextWinDoc.document.createElement(init.tag);
if (init.id) elem.id = init.id;
if (init.className) elem.className = init.className;
if (init.style) elem.style = init.style;
if (init.innerText) elem.innerText = init.innerText;
if (init.innerHTML) elem.innerHTML = init.innerHTML;
if (init.attributes) {
var atts = init.attributes;
for (var attributeName in atts) {
elem.setAttribute(attributeName, atts[attributeName]);
}
}
if (init.dataset) {
var dataset = init.dataset;
for (var dataName in dataset) {
elem.dataset[dataName] = dataset[dataName];
}
}
if (init.events) {
var events = init.events;
for (var eventName in events) {
elem.addEventListener(eventName, events[eventName]);
}
}
if (init.child) {
elem.appendChild(this.createElement(init.child));
}
if (init.children) {
var kids = init.children;
for (var i = 0; i < kids.length; i++) {
elem.appendChild(this.createElement(kids[i]));
}
}
if (init.ref) init.ref(elem);
return elem;
}
/**
* Returns the value of an elements property bypassing wombat rewriting
* @param {Node} elem
* @param {string} prop
* @return {*}
*/
getElementPropertyAsIs(elem, prop) {
return this.ownContextWinDoc.window.Element.prototype.getAttribute.call(
elem,
prop
);
}
getElementNSPropertyAsIs(elem, ns, prop) {
return this.ownContextWinDoc.window.Element.prototype.getAttributeNS.call(
elem,
ns,
prop
);
}
getStylePropertyAsIs(elem, prop) {
var getter = this.ownContextWinDoc.window.CSSStyleDeclaration.prototype.__lookupGetter__(
prop
);
return getter.call(elem, prop);
}
getCSSPropertyAsIs(elem, prop) {
return this.ownContextWinDoc.window.CSSStyleDeclaration.prototype.getPropertyValue.call(
elem,
prop
);
}
getOriginalWinDomViaPath(objectPath) {
return get(this.ownContextWinDoc, objectPath);
}
};