1146 lines
39 KiB
JavaScript
1146 lines
39 KiB
JavaScript
/*
|
|
* Copyright 2016 Jacek Caban for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
var compat_version;
|
|
var tests = [];
|
|
|
|
sync_test("builtin_toString", function() {
|
|
var tags = [
|
|
[ "abbr", "Phrase" ],
|
|
[ "acronym", "Phrase" ],
|
|
[ "address", "Block" ],
|
|
// [ "applet", "Applet" ], // makes Windows pop up a dialog box
|
|
[ "article", "" ],
|
|
[ "aside", "" ],
|
|
[ "audio", "Audio" ],
|
|
[ "b", "Phrase" ],
|
|
[ "base", "Base" ],
|
|
[ "basefont", "BaseFont" ],
|
|
[ "bdi", "Unknown" ],
|
|
[ "bdo", "Phrase" ],
|
|
[ "big", "Phrase" ],
|
|
[ "blockquote", "Block" ],
|
|
[ "body", "Body" ],
|
|
[ "br", "BR" ],
|
|
[ "button", "Button" ],
|
|
[ "canvas", "Canvas" ],
|
|
[ "caption", "TableCaption" ],
|
|
[ "center", "Block" ],
|
|
[ "cite", "Phrase" ],
|
|
[ "code", "Phrase" ],
|
|
[ "col", "TableCol" ],
|
|
[ "colgroup", "TableCol" ],
|
|
[ "data", "Unknown" ],
|
|
[ "datalist", "DataList", 10 ],
|
|
[ "dd", "DD" ],
|
|
[ "del", "Mod" ],
|
|
[ "details", "Unknown" ],
|
|
[ "dfn", "Phrase" ],
|
|
[ "dialog", "Unknown" ],
|
|
[ "dir", "Directory" ],
|
|
[ "div", "Div" ],
|
|
[ "dl", "DList" ],
|
|
[ "dt", "DT" ],
|
|
[ "em", "Phrase" ],
|
|
[ "embed", "Embed" ],
|
|
[ "fieldset", "FieldSet" ],
|
|
[ "figcaption", "" ],
|
|
[ "figure", "" ],
|
|
[ "font", "Font" ],
|
|
[ "footer", "" ],
|
|
[ "form", "Form" ],
|
|
[ "frame", "Frame" ],
|
|
[ "frameset", "FrameSet" ],
|
|
[ "h1", "Heading" ],
|
|
[ "h2", "Heading" ],
|
|
[ "h3", "Heading" ],
|
|
[ "h4", "Heading" ],
|
|
[ "h5", "Heading" ],
|
|
[ "h6", "Heading" ],
|
|
[ "h7", "Unknown" ],
|
|
[ "head", "Head" ],
|
|
[ "header", "" ],
|
|
[ "hr", "HR" ],
|
|
[ "html", "Html" ],
|
|
[ "i", "Phrase" ],
|
|
[ "iframe", "IFrame" ],
|
|
[ "img", "Image" ],
|
|
[ "input", "Input" ],
|
|
[ "ins", "Mod" ],
|
|
[ "kbd", "Phrase" ],
|
|
[ "label", "Label" ],
|
|
[ "legend", "Legend" ],
|
|
[ "li", "LI" ],
|
|
[ "link", "Link" ],
|
|
[ "main", "Unknown" ],
|
|
[ "map", "Map" ],
|
|
[ "mark", "" ],
|
|
[ "meta", "Meta" ],
|
|
[ "meter", "Unknown" ],
|
|
[ "nav", "" ],
|
|
[ "noframes", "" ],
|
|
[ "noscript", "" ],
|
|
[ "object", "Object" ],
|
|
[ "ol", "OList" ],
|
|
[ "optgroup", "OptGroup" ],
|
|
[ "option", "Option" ],
|
|
[ "output", "Unknown" ],
|
|
[ "p", "Paragraph" ],
|
|
[ "param", "Param" ],
|
|
[ "picture", "Unknown" ],
|
|
[ "pre", "Pre" ],
|
|
[ "progress", "Progress", 10 ],
|
|
[ "q", "Quote" ],
|
|
[ "rp", "Phrase" ],
|
|
[ "rt", "Phrase" ],
|
|
[ "ruby", "Phrase" ],
|
|
[ "s", "Phrase" ],
|
|
[ "samp", "Phrase" ],
|
|
[ "script", "Script" ],
|
|
[ "section", "" ],
|
|
[ "select", "Select" ],
|
|
[ "small", "Phrase" ],
|
|
[ "source", "Source" ],
|
|
[ "span", "Span" ],
|
|
[ "strike", "Phrase" ],
|
|
[ "strong", "Phrase" ],
|
|
[ "style", "Style" ],
|
|
[ "sub", "Phrase" ],
|
|
[ "summary", "Unknown" ],
|
|
[ "sup", "Phrase" ],
|
|
[ "svg", "Unknown" ],
|
|
[ "table", "Table" ],
|
|
[ "tbody", "TableSection" ],
|
|
[ "td", "TableDataCell" ],
|
|
[ "template", "Unknown" ],
|
|
[ "textarea", "TextArea" ],
|
|
[ "tfoot", "TableSection" ],
|
|
[ "th", "TableHeaderCell" ],
|
|
[ "thead", "TableSection" ],
|
|
[ "time", "Unknown" ],
|
|
[ "title", "Title" ],
|
|
[ "tr", "TableRow" ],
|
|
[ "track", "Track", 10 ],
|
|
[ "tt", "Phrase" ],
|
|
[ "u", "Phrase" ],
|
|
[ "ul", "UList" ],
|
|
[ "var", "Phrase" ],
|
|
[ "video", "Video" ],
|
|
[ "wbr", "" ],
|
|
[ "winetest", "Unknown" ]
|
|
];
|
|
var v = document.documentMode, e;
|
|
|
|
function test(msg, obj, name, tostr) {
|
|
var s;
|
|
if(obj.toString) {
|
|
s = obj.toString();
|
|
todo_wine_if(name !== "HTMLElement" && s === "[object HTMLElement]").
|
|
ok(s === (tostr ? tostr : (v < 9 ? "[object]" : "[object " + name + "]")), msg + " toString returned " + s);
|
|
}
|
|
s = Object.prototype.toString.call(obj);
|
|
todo_wine_if(v >= 9 && name != "Object").
|
|
ok(s === (v < 9 ? "[object Object]" : "[object " + name + "]"), msg + " Object.toString returned " + s);
|
|
}
|
|
|
|
for(var i = 0; i < tags.length; i++)
|
|
if(tags[i].length < 3 || v >= tags[i][2])
|
|
test("tag '" + tags[i][0] + "'", document.createElement(tags[i][0]), "HTML" + tags[i][1] + "Element");
|
|
|
|
e = document.createElement("a");
|
|
ok(e.toString() === "", "tag 'a' (without href) toString returned " + e.toString());
|
|
e.href = "https://www.winehq.org/";
|
|
test("tag 'a'", e, "HTMLAnchorElement", "https://www.winehq.org/");
|
|
|
|
e = document.createElement("area");
|
|
ok(e.toString() === "", "tag 'area' (without href) toString returned " + e.toString());
|
|
e.href = "https://www.winehq.org/";
|
|
test("tag 'area'", e, "HTMLAreaElement", "https://www.winehq.org/");
|
|
|
|
e = document.createElement("style");
|
|
document.body.appendChild(e);
|
|
var sheet = v >= 9 ? e.sheet : e.styleSheet;
|
|
if(v >= 9)
|
|
sheet.insertRule("div { border: none }", 0);
|
|
else
|
|
sheet.addRule("div", "border: none", 0);
|
|
|
|
e = document.createElement("p");
|
|
e.className = "testclass another ";
|
|
e.textContent = "Test content";
|
|
e.style.border = "1px solid black";
|
|
document.body.appendChild(e);
|
|
|
|
var txtRange = document.body.createTextRange();
|
|
txtRange.moveToElementText(e);
|
|
|
|
var clientRects = e.getClientRects();
|
|
if(!clientRects) win_skip("getClientRects() is buggy and not available, skipping");
|
|
|
|
var currentStyle = e.currentStyle;
|
|
if(!currentStyle) win_skip("currentStyle is buggy and not available, skipping");
|
|
|
|
// w10pro64 testbot VM throws WININET_E_INTERNAL_ERROR for some reason
|
|
var localStorage;
|
|
try {
|
|
localStorage = window.localStorage;
|
|
}catch(e) {
|
|
ok(e.number === 0x72ee4 - 0x80000000, "localStorage threw " + e.number + ": " + e);
|
|
}
|
|
if(!localStorage) win_skip("localStorage is buggy and not available, skipping");
|
|
|
|
test("attribute", document.createAttribute("class"), "Attr");
|
|
if(false /* todo_wine */) test("attributes", e.attributes, "NamedNodeMap");
|
|
test("childNodes", document.body.childNodes, "NodeList");
|
|
if(clientRects) test("clientRect", clientRects[0], "ClientRect");
|
|
if(clientRects) test("clientRects", clientRects, "ClientRectList");
|
|
if(currentStyle) test("currentStyle", currentStyle, "MSCurrentStyleCSSProperties");
|
|
if(v >= 11 /* todo_wine */) test("document", document, v < 11 ? "Document" : "HTMLDocument");
|
|
test("elements", document.getElementsByTagName("body"), "HTMLCollection");
|
|
test("history", window.history, "History");
|
|
test("implementation", document.implementation, "DOMImplementation");
|
|
if(localStorage) test("localStorage", localStorage, "Storage");
|
|
test("location", window.location, "Object", window.location.href);
|
|
if(v >= 11 /* todo_wine */) test("mimeTypes", window.navigator.mimeTypes, v < 11 ? "MSMimeTypesCollection" : "MimeTypeArray");
|
|
test("navigator", window.navigator, "Navigator");
|
|
test("performance", window.performance, "Performance");
|
|
test("performanceNavigation", window.performance.navigation, "PerformanceNavigation");
|
|
test("performanceTiming", window.performance.timing, "PerformanceTiming");
|
|
if(v >= 11 /* todo_wine */) test("plugins", window.navigator.plugins, v < 11 ? "MSPluginsCollection" : "PluginArray");
|
|
test("screen", window.screen, "Screen");
|
|
test("sessionStorage", window.sessionStorage, "Storage");
|
|
test("style", document.body.style, "MSStyleCSSProperties");
|
|
test("styleSheet", sheet, "CSSStyleSheet");
|
|
test("styleSheetRule", sheet.rules.item(0), "CSSStyleRule");
|
|
test("styleSheetRules", sheet.rules, "MSCSSRuleList");
|
|
test("styleSheets", document.styleSheets, "StyleSheetList");
|
|
test("textNode", document.createTextNode("testNode"), "Text", v < 9 ? "testNode" : null);
|
|
test("textRange", txtRange, "TextRange");
|
|
test("window", window, "Window", "[object Window]");
|
|
test("xmlHttpRequest", new XMLHttpRequest(), "XMLHttpRequest");
|
|
if(v < 10) {
|
|
test("namespaces", document.namespaces, "MSNamespaceInfoCollection");
|
|
}
|
|
if(v < 11) {
|
|
test("eventObject", document.createEventObject(), "MSEventObj");
|
|
test("selection", document.selection, "MSSelection");
|
|
}
|
|
if(v >= 9) {
|
|
test("computedStyle", window.getComputedStyle(e), "CSSStyleDeclaration");
|
|
|
|
test("Event", document.createEvent("Event"), "Event");
|
|
test("CustomEvent", document.createEvent("CustomEvent"), "CustomEvent");
|
|
test("KeyboardEvent", document.createEvent("KeyboardEvent"), "KeyboardEvent");
|
|
test("MouseEvent", document.createEvent("MouseEvent"), "MouseEvent");
|
|
test("UIEvent", document.createEvent("UIEvent"), "UIEvent");
|
|
}
|
|
if(v >= 10) {
|
|
test("classList", e.classList, "DOMTokenList", "testclass another ");
|
|
test("console", window.console, "Console");
|
|
}
|
|
if(v >= 9) {
|
|
document.body.innerHTML = "<!--...-->";
|
|
test("comment", document.body.firstChild, "Comment");
|
|
}
|
|
});
|
|
|
|
sync_test("elem_props", function() {
|
|
var elem = document.documentElement;
|
|
|
|
function test_exposed(prop, expect) {
|
|
if(expect)
|
|
ok(prop in elem, prop + " not found in element.");
|
|
else
|
|
ok(!(prop in elem), prop + " found in element.");
|
|
}
|
|
|
|
var v = document.documentMode;
|
|
|
|
test_exposed("doScroll", v < 11);
|
|
test_exposed("readyState", v < 11);
|
|
test_exposed("clientTop", true);
|
|
test_exposed("title", true);
|
|
test_exposed("querySelectorAll", v >= 8);
|
|
test_exposed("textContent", v >= 9);
|
|
test_exposed("prefix", v >= 9);
|
|
test_exposed("firstElementChild", v >= 9);
|
|
test_exposed("onsubmit", v >= 9);
|
|
test_exposed("getElementsByClassName", v >= 9);
|
|
test_exposed("removeAttributeNS", v >= 9);
|
|
test_exposed("addEventListener", v >= 9);
|
|
if (v != 8 /* todo_wine */) test_exposed("hasAttribute", v >= 8);
|
|
test_exposed("removeEventListener", v >= 9);
|
|
test_exposed("dispatchEvent", v >= 9);
|
|
test_exposed("msSetPointerCapture", v >= 10);
|
|
if (v >= 9) test_exposed("spellcheck", v >= 10);
|
|
|
|
elem = document.createElement("style");
|
|
test_exposed("media", true);
|
|
test_exposed("type", true);
|
|
test_exposed("disabled", true);
|
|
test_exposed("media", true);
|
|
test_exposed("sheet", v >= 9);
|
|
test_exposed("readyState", v < 11);
|
|
test_exposed("styleSheet", v < 11);
|
|
test_exposed("classList", v >= 10);
|
|
});
|
|
|
|
sync_test("doc_props", function() {
|
|
function test_exposed(prop, expect) {
|
|
if(expect)
|
|
ok(prop in document, prop + " not found in document.");
|
|
else
|
|
ok(!(prop in document), prop + " found in document.");
|
|
}
|
|
|
|
var v = document.documentMode;
|
|
|
|
test_exposed("textContent", v >= 9);
|
|
test_exposed("prefix", v >= 9);
|
|
test_exposed("defaultView", v >= 9);
|
|
test_exposed("head", v >= 9);
|
|
test_exposed("addEventListener", v >= 9);
|
|
test_exposed("removeEventListener", v >= 9);
|
|
test_exposed("dispatchEvent", v >= 9);
|
|
test_exposed("createEvent", v >= 9);
|
|
|
|
test_exposed("parentWindow", true);
|
|
if(v >= 9) ok(document.defaultView === document.parentWindow, "defaultView != parentWindow");
|
|
});
|
|
|
|
sync_test("docfrag_props", function() {
|
|
var docfrag = document.createDocumentFragment();
|
|
|
|
function test_exposed(prop, expect) {
|
|
if(expect)
|
|
ok(prop in docfrag, prop + " not found in document fragent.");
|
|
else
|
|
ok(!(prop in docfrag), prop + " found in document fragent.");
|
|
}
|
|
|
|
var v = document.documentMode;
|
|
|
|
test_exposed("compareDocumentPosition", v >= 9);
|
|
});
|
|
|
|
sync_test("window_props", function() {
|
|
function test_exposed(prop, expect) {
|
|
if(expect)
|
|
ok(prop in window, prop + " not found in window.");
|
|
else
|
|
ok(!(prop in window), prop + " found in window.");
|
|
}
|
|
|
|
var v = document.documentMode;
|
|
|
|
test_exposed("postMessage", true);
|
|
test_exposed("sessionStorage", true);
|
|
test_exposed("localStorage", true);
|
|
test_exposed("addEventListener", v >= 9);
|
|
test_exposed("removeEventListener", v >= 9);
|
|
test_exposed("dispatchEvent", v >= 9);
|
|
test_exposed("getSelection", v >= 9);
|
|
test_exposed("onfocusout", v >= 9);
|
|
test_exposed("getComputedStyle", v >= 9);
|
|
test_exposed("requestAnimationFrame", v >= 10);
|
|
test_exposed("Map", v >= 11);
|
|
test_exposed("Set", v >= 11);
|
|
test_exposed("performance", true);
|
|
test_exposed("console", v >= 10);
|
|
});
|
|
|
|
sync_test("xhr_props", function() {
|
|
var xhr = new XMLHttpRequest();
|
|
|
|
function test_exposed(prop, expect) {
|
|
if(expect)
|
|
ok(prop in xhr, prop + " not found in XMLHttpRequest.");
|
|
else
|
|
ok(!(prop in xhr), prop + " found in XMLHttpRequest.");
|
|
}
|
|
|
|
var v = document.documentMode;
|
|
|
|
test_exposed("addEventListener", v >= 9);
|
|
test_exposed("removeEventListener", v >= 9);
|
|
test_exposed("dispatchEvent", v >= 9);
|
|
});
|
|
|
|
sync_test("stylesheet_props", function() {
|
|
var v = document.documentMode;
|
|
var elem = document.createElement("style");
|
|
document.body.appendChild(elem);
|
|
var sheet = v >= 9 ? elem.sheet : elem.styleSheet;
|
|
|
|
function test_exposed(prop, expect) {
|
|
if(expect)
|
|
ok(prop in sheet, prop + " not found in style sheet.");
|
|
else
|
|
ok(!(prop in sheet), prop + " found in style sheet.");
|
|
}
|
|
|
|
test_exposed("href", true);
|
|
test_exposed("title", true);
|
|
test_exposed("type", true);
|
|
test_exposed("media", true);
|
|
test_exposed("ownerNode", v >= 9);
|
|
test_exposed("ownerRule", v >= 9);
|
|
test_exposed("cssRules", v >= 9);
|
|
test_exposed("insertRule", v >= 9);
|
|
test_exposed("deleteRule", v >= 9);
|
|
test_exposed("disabled", true);
|
|
test_exposed("parentStyleSheet", true);
|
|
test_exposed("owningElement", true);
|
|
test_exposed("readOnly", true);
|
|
test_exposed("imports", true);
|
|
test_exposed("id", true);
|
|
test_exposed("addImport", true);
|
|
test_exposed("addRule", true);
|
|
test_exposed("removeImport", true);
|
|
test_exposed("removeRule", true);
|
|
test_exposed("cssText", true);
|
|
test_exposed("rules", true);
|
|
});
|
|
|
|
sync_test("xhr open", function() {
|
|
var e = false;
|
|
try {
|
|
(new XMLHttpRequest()).open("GET", "https://www.winehq.org/");
|
|
}catch(ex) {
|
|
e = true;
|
|
}
|
|
|
|
if(document.documentMode < 10)
|
|
ok(e, "expected exception");
|
|
else
|
|
ok(!e, "unexpected exception");
|
|
});
|
|
|
|
sync_test("style_props", function() {
|
|
var style = document.body.style;
|
|
|
|
function test_exposed(prop, expect) {
|
|
if(expect)
|
|
ok(prop in style, prop + " not found in style object.");
|
|
else
|
|
ok(!(prop in style), prop + " found in style object.");
|
|
}
|
|
|
|
var v = document.documentMode;
|
|
|
|
test_exposed("removeAttribute", true);
|
|
test_exposed("zIndex", true);
|
|
test_exposed("z-index", true);
|
|
test_exposed("filter", true);
|
|
test_exposed("pixelTop", true);
|
|
test_exposed("float", true);
|
|
test_exposed("css-float", false);
|
|
test_exposed("style-float", false);
|
|
test_exposed("setProperty", v >= 9);
|
|
test_exposed("removeProperty", v >= 9);
|
|
test_exposed("background-clip", v >= 9);
|
|
test_exposed("msTransform", v >= 9);
|
|
test_exposed("transform", v >= 10);
|
|
|
|
style = document.body.currentStyle;
|
|
|
|
test_exposed("zIndex", true);
|
|
test_exposed("z-index", true);
|
|
test_exposed("filter", true);
|
|
test_exposed("pixelTop", false);
|
|
test_exposed("float", true);
|
|
test_exposed("css-float", false);
|
|
test_exposed("style-float", false);
|
|
test_exposed("setProperty", v >= 9);
|
|
test_exposed("removeProperty", v >= 9);
|
|
test_exposed("background-clip", v >= 9);
|
|
test_exposed("transform", v >= 10);
|
|
|
|
if(window.getComputedStyle) {
|
|
style = window.getComputedStyle(document.body);
|
|
|
|
test_exposed("removeAttribute", false);
|
|
test_exposed("zIndex", true);
|
|
test_exposed("z-index", true);
|
|
test_exposed("pixelTop", false);
|
|
test_exposed("float", true);
|
|
test_exposed("css-float", false);
|
|
test_exposed("style-float", false);
|
|
test_exposed("setProperty", v >= 9);
|
|
test_exposed("removeProperty", v >= 9);
|
|
test_exposed("background-clip", v >= 9);
|
|
test_exposed("transform", v >= 10);
|
|
}
|
|
});
|
|
|
|
sync_test("createElement_inline_attr", function() {
|
|
var v = document.documentMode, e, s;
|
|
|
|
if(v < 9) {
|
|
s = document.createElement("<div>").tagName;
|
|
ok(s === "DIV", "<div>.tagName returned " + s);
|
|
s = document.createElement("<div >").tagName;
|
|
ok(s === "DIV", "<div >.tagName returned " + s);
|
|
s = document.createElement("<div/>").tagName;
|
|
ok(s === "DIV", "<div/>.tagName returned " + s);
|
|
e = 0;
|
|
try {
|
|
document.createElement("<div");
|
|
}catch(ex) {
|
|
e = ex.number;
|
|
}
|
|
ok(e === 0x4005 - 0x80000000, "<div e = " + e);
|
|
e = 0;
|
|
try {
|
|
document.createElement("<div test=1");
|
|
}catch(ex) {
|
|
e = ex.number;
|
|
}
|
|
ok(e === 0x4005 - 0x80000000, "<div test=1 e = " + e);
|
|
|
|
var tags = [ "div", "head", "body", "title", "html" ];
|
|
|
|
for(var i = 0; i < tags.length; i++) {
|
|
e = document.createElement("<" + tags[i] + " test='a\"' abcd=\""b"\">");
|
|
ok(e.tagName === tags[i].toUpperCase(), "<" + tags[i] + " test=\"a\" abcd=\"b\">.tagName returned " + e.tagName);
|
|
todo_wine_if(v == 8).
|
|
ok(e.test === "a\"", "<" + tags[i] + " test='a\"' abcd=\""b"\">.test returned " + e.test);
|
|
todo_wine_if(v == 8).
|
|
ok(e.abcd === "\"b\"", "<" + tags[i] + " test='a\"' abcd=\""b"\">.abcd returned " + e.abcd);
|
|
}
|
|
}else {
|
|
s = "";
|
|
e = 0;
|
|
try {
|
|
document.createElement("<div>");
|
|
}catch(ex) {
|
|
s = ex.toString();
|
|
e = ex.number;
|
|
}
|
|
todo_wine.
|
|
ok(e === undefined, "<div> e = " + e);
|
|
todo_wine.
|
|
ok(s === "InvalidCharacterError", "<div> s = " + s);
|
|
s = "";
|
|
e = 0;
|
|
try {
|
|
document.createElement("<div test=\"a\">");
|
|
}catch(ex) {
|
|
s = ex.toString();
|
|
e = ex.number;
|
|
}
|
|
todo_wine.
|
|
ok(e === undefined, "<div test=\"a\"> e = " + e);
|
|
todo_wine.
|
|
ok(s === "InvalidCharacterError", "<div test=\"a\"> s = " + s);
|
|
}
|
|
});
|
|
|
|
sync_test("JS objs", function() {
|
|
var g = window;
|
|
|
|
function test_exposed(func, obj, expect) {
|
|
if(expect)
|
|
ok(func in obj, func + " not found in " + obj);
|
|
else
|
|
ok(!(func in obj), func + " found in " + obj);
|
|
}
|
|
|
|
function test_parses(code, expect) {
|
|
var success;
|
|
try {
|
|
eval(code);
|
|
success = true;
|
|
}catch(e) {
|
|
success = false;
|
|
}
|
|
if(expect)
|
|
ok(success === true, code + " did not parse");
|
|
else
|
|
ok(success === false, code + " parsed");
|
|
}
|
|
|
|
var v = document.documentMode;
|
|
|
|
test_exposed("ScriptEngineMajorVersion", g, true);
|
|
|
|
test_exposed("JSON", g, v >= 8);
|
|
test_exposed("now", Date, true);
|
|
test_exposed("toISOString", Date.prototype, v >= 9);
|
|
test_exposed("isArray", Array, v >= 9);
|
|
test_exposed("forEach", Array.prototype, v >= 9);
|
|
test_exposed("indexOf", Array.prototype, v >= 9);
|
|
test_exposed("trim", String.prototype, v >= 9);
|
|
test_exposed("map", Array.prototype, v >= 9);
|
|
|
|
/* FIXME: IE8 implements weird semi-functional property descriptors. */
|
|
if(v != 8) {
|
|
test_exposed("getOwnPropertyDescriptor", Object, v >= 8);
|
|
test_exposed("defineProperty", Object, v >= 8);
|
|
test_exposed("defineProperties", Object, v >= 8);
|
|
}
|
|
|
|
test_exposed("getPrototypeOf", Object, v >= 9);
|
|
|
|
test_parses("if(false) { o.default; }", v >= 9);
|
|
test_parses("if(false) { o.with; }", v >= 9);
|
|
test_parses("if(false) { o.if; }", v >= 9);
|
|
});
|
|
|
|
sync_test("elem_by_id", function() {
|
|
document.body.innerHTML = '<form id="testid" name="testname"></form>';
|
|
|
|
var id_elem = document.getElementById("testid");
|
|
ok(id_elem.tagName === "FORM", "id_elem.tagName = " + id_elem.tagName);
|
|
|
|
var name_elem = document.getElementById("testname");
|
|
if(document.documentMode < 8)
|
|
ok(id_elem === name_elem, "id_elem != id_elem");
|
|
else
|
|
ok(name_elem === null, "name_elem != null");
|
|
});
|
|
|
|
sync_test("doc_mode", function() {
|
|
compat_version = parseInt(document.location.search.substring(1));
|
|
|
|
trace("Testing compatibility mode " + compat_version);
|
|
|
|
if(compat_version > 6 && compat_version > document.documentMode) {
|
|
win_skip("Document mode not supported (expected " + compat_version + " got " + document.documentMode + ")");
|
|
reportSuccess();
|
|
return;
|
|
}
|
|
|
|
ok(Math.max(compat_version, 5) === document.documentMode, "documentMode = " + document.documentMode);
|
|
|
|
if(document.documentMode > 5)
|
|
ok(document.compatMode === "CSS1Compat", "document.compatMode = " + document.compatMode);
|
|
else
|
|
ok(document.compatMode === "BackCompat", "document.compatMode = " + document.compatMode);
|
|
});
|
|
|
|
async_test("iframe_doc_mode", function() {
|
|
var iframe = document.createElement("iframe");
|
|
|
|
iframe.onload = function() {
|
|
var iframe_mode = iframe.contentWindow.document.documentMode;
|
|
if(document.documentMode < 9)
|
|
ok(iframe_mode === 5, "iframe_mode = " + iframe_mode);
|
|
else
|
|
ok(iframe_mode === document.documentMode, "iframe_mode = " + iframe_mode);
|
|
next_test();
|
|
}
|
|
|
|
iframe.src = "about:blank";
|
|
document.body.appendChild(iframe);
|
|
});
|
|
|
|
sync_test("conditional_comments", function() {
|
|
var div = document.createElement("div");
|
|
document.body.appendChild(div);
|
|
|
|
function test_version(v) {
|
|
var version = compat_version ? compat_version : 7;
|
|
|
|
div.innerHTML = "<!--[if lte IE " + v + "]>true<![endif]-->";
|
|
ok(div.innerText === (version <= v ? "true" : ""),
|
|
"div.innerText = " + div.innerText + " for version (<=) " + v);
|
|
|
|
div.innerHTML = "<!--[if lt IE " + v + "]>true<![endif]-->";
|
|
ok(div.innerText === (version < v ? "true" : ""),
|
|
"div.innerText = " + div.innerText + " for version (<) " + v);
|
|
|
|
div.innerHTML = "<!--[if gte IE " + v + "]>true<![endif]-->";
|
|
ok(div.innerText === (version >= v && version < 10 ? "true" : ""),
|
|
"div.innerText = " + div.innerText + " for version (>=) " + v);
|
|
|
|
div.innerHTML = "<!--[if gt IE " + v + "]>true<![endif]-->";
|
|
ok(div.innerText === (version > v && version < 10 ? "true" : ""),
|
|
"div.innerText = " + div.innerText + " for version (>) " + v);
|
|
}
|
|
|
|
test_version(5);
|
|
test_version(6);
|
|
test_version(7);
|
|
test_version(8);
|
|
});
|
|
|
|
var ready_states;
|
|
|
|
async_test("script_load", function() {
|
|
var v = document.documentMode;
|
|
if(v < 9) {
|
|
next_test();
|
|
return;
|
|
}
|
|
|
|
var elem = document.createElement("script");
|
|
ready_states = "";
|
|
|
|
elem.onreadystatechange = guard(function() {
|
|
ok(v < 11, "unexpected onreadystatechange call");
|
|
ready_states += elem.readyState + ",";
|
|
});
|
|
|
|
elem.onload = guard(function() {
|
|
switch(v) {
|
|
case 9:
|
|
ok(ready_states === "loading,exec,loaded,", "ready_states = " + ready_states);
|
|
break;
|
|
case 10:
|
|
ok(ready_states === "loading,exec,", "ready_states = " + ready_states);
|
|
break;
|
|
case 11:
|
|
ok(ready_states === "exec,", "ready_states = " + ready_states);
|
|
break;
|
|
}
|
|
next_test();
|
|
});
|
|
|
|
document.body.appendChild(elem);
|
|
elem.src = "jsstream.php?simple";
|
|
external.writeStream("simple", "ready_states += 'exec,';");
|
|
});
|
|
|
|
sync_test("navigator", function() {
|
|
var v = document.documentMode, re;
|
|
var app = navigator.appVersion;
|
|
ok(navigator.userAgent === "Mozilla/" + app,
|
|
"userAgent = " + navigator.userAgent + " appVersion = " + app);
|
|
|
|
re = v < 11
|
|
? "^" + (v < 9 ? "4" : "5") + "\\.0 \\(compatible; MSIE " + (v < 7 ? 7 : v) +
|
|
"\\.0; Windows NT [0-9].[0-9]; .*Trident/[678]\\.0.*\\)$"
|
|
: "^5.0 \\(Windows NT [0-9].[0-9]; .*Trident/[678]\\.0.*rv:11.0\\) like Gecko$";
|
|
ok(new RegExp(re).test(app), "appVersion = " + app);
|
|
|
|
ok(navigator.appCodeName === "Mozilla", "appCodeName = " + navigator.appCodeName);
|
|
ok(navigator.appName === (v < 11 ? "Microsoft Internet Explorer" : "Netscape"),
|
|
"appName = " + navigator.appName);
|
|
ok(navigator.toString() === (v < 9 ? "[object]" : "[object Navigator]"),
|
|
"navigator.toString() = " + navigator.toString());
|
|
});
|
|
|
|
sync_test("delete_prop", function() {
|
|
var v = document.documentMode;
|
|
var obj = document.createElement("div"), r, obj2;
|
|
|
|
obj.prop1 = true;
|
|
r = false;
|
|
try {
|
|
delete obj.prop1;
|
|
}catch(ex) {
|
|
r = true;
|
|
}
|
|
if(v < 8) {
|
|
ok(r, "did not get an expected exception");
|
|
return;
|
|
}
|
|
ok(!r, "got an unexpected exception");
|
|
ok(!("prop1" in obj), "prop1 is still in obj");
|
|
|
|
/* again, this time prop1 does not exist */
|
|
r = false;
|
|
try {
|
|
delete obj.prop1;
|
|
}catch(ex) {
|
|
r = true;
|
|
}
|
|
if(v < 9) {
|
|
ok(r, "did not get an expected exception");
|
|
return;
|
|
}else {
|
|
ok(!r, "got an unexpected exception");
|
|
ok(!("prop1" in obj), "prop1 is still in obj");
|
|
}
|
|
|
|
r = (delete obj.className);
|
|
ok(r, "delete returned " + r);
|
|
ok("className" in obj, "className deleted from obj");
|
|
ok(obj.className === "", "className = " + obj.className);
|
|
|
|
/* builtin propertiles don't throw any exception, but are not really deleted */
|
|
r = (delete obj.tagName);
|
|
ok(r, "delete returned " + r);
|
|
ok("tagName" in obj, "tagName deleted from obj");
|
|
ok(obj.tagName === "DIV", "tagName = " + obj.tagName);
|
|
|
|
obj = document.querySelectorAll("*");
|
|
ok("0" in obj, "0 is not in obj");
|
|
obj2 = obj[0];
|
|
r = (delete obj[0]);
|
|
ok("0" in obj, "0 is not in obj");
|
|
ok(obj[0] === obj2, "obj[0] != obj2");
|
|
|
|
/* test window object and its global scope handling */
|
|
obj = window;
|
|
|
|
obj.globalprop1 = true;
|
|
ok(globalprop1, "globalprop1 = " + globalprop1);
|
|
r = false;
|
|
try {
|
|
delete obj.globalprop1;
|
|
}catch(ex) {
|
|
r = true;
|
|
}
|
|
if(v < 9) {
|
|
ok(r, "did not get an expected exception");
|
|
}else {
|
|
ok(!r, "got an unexpected globalprop1 exception");
|
|
ok(!("globalprop1" in obj), "globalprop1 is still in obj");
|
|
}
|
|
|
|
globalprop2 = true;
|
|
ok(obj.globalprop2, "globalprop2 = " + globalprop2);
|
|
r = false;
|
|
try {
|
|
delete obj.globalprop2;
|
|
}catch(ex) {
|
|
r = true;
|
|
}
|
|
if(v < 9) {
|
|
ok(r, "did not get an expected globalprop2 exception");
|
|
}else {
|
|
ok(!r, "got an unexpected exception");
|
|
todo_wine.
|
|
ok(!("globalprop2" in obj), "globalprop2 is still in obj");
|
|
}
|
|
|
|
obj.globalprop3 = true;
|
|
ok(globalprop3, "globalprop3 = " + globalprop3);
|
|
r = false;
|
|
try {
|
|
delete globalprop3;
|
|
}catch(ex) {
|
|
r = true;
|
|
}
|
|
if(v < 9) {
|
|
ok(r, "did not get an expected exception");
|
|
ok("globalprop3" in obj, "globalprop3 is not in obj");
|
|
}else {
|
|
ok(!r, "got an unexpected globalprop3 exception");
|
|
ok(!("globalprop3" in obj), "globalprop3 is still in obj");
|
|
}
|
|
|
|
globalprop4 = true;
|
|
ok(obj.globalprop4, "globalprop4 = " + globalprop4);
|
|
r = (delete globalprop4);
|
|
ok(r, "delete returned " + r);
|
|
todo_wine.
|
|
ok(!("globalprop4" in obj), "globalprop4 is still in obj");
|
|
});
|
|
|
|
var func_scope_val = 1;
|
|
var func_scope_val2 = 2;
|
|
|
|
sync_test("func_scope", function() {
|
|
var func_scope_val = 2;
|
|
|
|
var f = function func_scope_val() {
|
|
return func_scope_val;
|
|
};
|
|
|
|
func_scope_val = 3;
|
|
if(document.documentMode < 9) {
|
|
ok(f() === 3, "f() = " + f());
|
|
return;
|
|
}
|
|
ok(f === f(), "f() = " + f());
|
|
|
|
f = function func_scope_val(a) {
|
|
func_scope_val = 4;
|
|
return func_scope_val;
|
|
};
|
|
|
|
func_scope_val = 3;
|
|
ok(f === f(), "f() = " + f());
|
|
ok(func_scope_val === 3, "func_scope_val = " + func_scope_val);
|
|
ok(window.func_scope_val === 1, "window.func_scope_val = " + window.func_scope_val);
|
|
|
|
f = function func_scope_val(a) {
|
|
return (function() { return a ? func_scope_val(false) : func_scope_val; })();
|
|
};
|
|
|
|
ok(f === f(true), "f(true) = " + f(true));
|
|
|
|
window = 1;
|
|
ok(window === window.self, "window = " + window);
|
|
|
|
! function func_scope_val2() {};
|
|
ok(window.func_scope_val2 === 2, "window.func_scope_val2 = " + window.func_scope_val2);
|
|
|
|
var o = {};
|
|
(function(x) {
|
|
ok(x === o, "x = " + x);
|
|
! function x() {};
|
|
ok(x === o, "x != o");
|
|
})(o);
|
|
|
|
(function(x) {
|
|
ok(x === o, "x = " + x);
|
|
1, function x() {};
|
|
ok(x === o, "x != o");
|
|
})(o);
|
|
|
|
(function() {
|
|
! function x() {};
|
|
try {
|
|
x();
|
|
ok(false, "expected exception");
|
|
}catch(e) {}
|
|
})(o);
|
|
});
|
|
|
|
sync_test("set_obj", function() {
|
|
if(!("Set" in window)) return;
|
|
|
|
var s = new Set, r;
|
|
ok(Object.getPrototypeOf(s) === Set.prototype, "unexpected Set prototype");
|
|
|
|
function test_length(name, len) {
|
|
ok(Set.prototype[name].length === len, "Set.prototype." + name + " = " + Set.prototype[name].length);
|
|
}
|
|
test_length("add", 1);
|
|
test_length("clear", 0);
|
|
test_length("delete", 1);
|
|
test_length("forEach", 1);
|
|
test_length("has", 1);
|
|
ok(!("entries" in s), "entries are in Set");
|
|
ok(!("keys" in s), "keys are in Set");
|
|
ok(!("values" in s), "values are in Set");
|
|
|
|
r = Object.prototype.toString.call(s);
|
|
ok(r === "[object Object]", "toString returned " + r);
|
|
});
|
|
|
|
sync_test("map_obj", function() {
|
|
if(!("Map" in window)) return;
|
|
|
|
var s = new Map, r, i;
|
|
ok(Object.getPrototypeOf(s) === Map.prototype, "unexpected Map prototype");
|
|
|
|
function test_length(name, len) {
|
|
ok(Map.prototype[name].length === len, "Map.prototype." + name + " = " + Map.prototype[name].length);
|
|
}
|
|
test_length("clear", 0);
|
|
test_length("delete", 1);
|
|
test_length("forEach", 1);
|
|
test_length("get", 1);
|
|
test_length("has", 1);
|
|
test_length("set", 2);
|
|
ok(!("entries" in s), "entries are in Map");
|
|
ok(!("keys" in s), "keys are in Map");
|
|
ok(!("values" in s), "values are in Map");
|
|
todo_wine.
|
|
ok("size" in Map.prototype, "size is not in Map.prototype");
|
|
|
|
r = Object.prototype.toString.call(s);
|
|
ok(r === "[object Object]", "toString returned " + r);
|
|
|
|
r = s.get("test");
|
|
ok(r === undefined, "get(test) returned " + r);
|
|
r = s.has("test");
|
|
ok(r === false, "has(test) returned " + r);
|
|
ok(s.size === 0, "size = " + s.size + " expected 0");
|
|
|
|
r = s.set("test", 1);
|
|
ok(r === undefined, "set returned " + r);
|
|
ok(s.size === 1, "size = " + s.size + " expected 1");
|
|
r = s.get("test");
|
|
ok(r === 1, "get(test) returned " + r);
|
|
r = s.has("test");
|
|
ok(r === true, "has(test) returned " + r);
|
|
|
|
s.size = 100;
|
|
ok(s.size === 1, "size = " + s.size + " expected 1");
|
|
|
|
s.set("test", 2);
|
|
r = s.get("test");
|
|
ok(r === 2, "get(test) returned " + r);
|
|
r = s.has("test");
|
|
ok(r === true, "has(test) returned " + r);
|
|
|
|
r = s["delete"]("test"); /* using s.delete() would break parsing in quirks mode */
|
|
ok(r === true, "delete(test) returned " + r);
|
|
ok(s.size === 0, "size = " + s.size + " expected 0");
|
|
r = s["delete"]("test");
|
|
ok(r === false, "delete(test) returned " + r);
|
|
|
|
var test_keys = [undefined, null, NaN, 3, "str", false, true, {}];
|
|
for(i in test_keys) {
|
|
r = s.set(test_keys[i], test_keys[i] + 1);
|
|
ok(r === undefined, "set(test) returned " + r);
|
|
}
|
|
ok(s.size === test_keys.length, "size = " + s.size + " expected " + test_keys.length);
|
|
for(i in test_keys) {
|
|
r = s.get(test_keys[i]);
|
|
if(isNaN(test_keys[i]))
|
|
ok(isNaN(r), "get(" + test_keys[i] + ") returned " + r);
|
|
else
|
|
ok(r === test_keys[i] + 1, "get(" + test_keys[i] + ") returned " + r);
|
|
}
|
|
|
|
var calls = [];
|
|
i = 0;
|
|
r = s.forEach(function(value, key) {
|
|
if(isNaN(test_keys[i])) {
|
|
ok(isNaN(key), "key = " + key + " expected NaN");
|
|
ok(isNaN(value), "value = " + value + " expected NaN");
|
|
}else {
|
|
ok(key === test_keys[i], "key = " + key + " expected " + test_keys[i]);
|
|
ok(value === key + 1, "value = " + value);
|
|
}
|
|
i++;
|
|
});
|
|
ok(i === test_keys.length, "i = " + i);
|
|
ok(r === undefined, "forEach returned " + r);
|
|
|
|
s.set(3, "test2")
|
|
calls = [];
|
|
i = 0;
|
|
s.forEach(function(value, key) {
|
|
if(isNaN(test_keys[i]))
|
|
ok(isNaN(key), "key = " + key + " expected " + test_keys[i]);
|
|
else
|
|
ok(key === test_keys[i], "key = " + key + " expected " + test_keys[i]);
|
|
i++;
|
|
});
|
|
ok(i === test_keys.length, "i = " + i);
|
|
|
|
r = s.clear();
|
|
ok(r === undefined, "clear returned " + r);
|
|
ok(s.size === 0, "size = " + s.size + " expected 0");
|
|
r = s.get(test_keys[0]);
|
|
ok(r === undefined, "get returned " + r);
|
|
|
|
s = new Map();
|
|
s.set(1, 10);
|
|
s.set(2, 20);
|
|
s.set(3, 30);
|
|
i = true;
|
|
s.forEach(function() {
|
|
ok(i, "unexpected call");
|
|
s.clear();
|
|
i = false;
|
|
});
|
|
|
|
s = new Map();
|
|
s.set(1, 10);
|
|
s.set(2, 20);
|
|
s.set(3, 30);
|
|
i = 0;
|
|
s.forEach(function(value, key) {
|
|
i += key + value;
|
|
r = s["delete"](key);
|
|
ok(r === true, "delete returned " + r);
|
|
});
|
|
ok(i === 66, "i = " + i);
|
|
|
|
try {
|
|
Map.prototype.set.call({}, 1, 2);
|
|
ok(false, "expected exception");
|
|
}catch(e) {
|
|
ok(e.number === 0xa13fc - 0x80000000, "e.number = " + e.number);
|
|
}
|
|
});
|
|
|
|
sync_test("elem_attr", function() {
|
|
var v = document.documentMode;
|
|
var elem = document.createElement("div"), r;
|
|
|
|
r = elem.getAttribute("class");
|
|
ok(r === null, "class attr = " + r);
|
|
r = elem.getAttribute("className");
|
|
ok(r === (v < 8 ? "" : null), "className attr = " + r);
|
|
|
|
elem.className = "cls";
|
|
r = elem.getAttribute("class");
|
|
ok(r === (v < 8 ? null : "cls"), "class attr = " + r);
|
|
r = elem.getAttribute("className");
|
|
ok(r === (v < 8 ? "cls" : null), "className attr = " + r);
|
|
|
|
elem.setAttribute("class", "cls2");
|
|
ok(elem.className === (v < 8 ? "cls" : "cls2"), "elem.className = " + elem.className);
|
|
r = elem.getAttribute("class");
|
|
ok(r === "cls2", "class attr = " + r);
|
|
r = elem.getAttribute("className");
|
|
ok(r === (v < 8 ? "cls" : null), "className attr = " + r);
|
|
|
|
elem.setAttribute("className", "cls3");
|
|
ok(elem.className === (v < 8 ? "cls3" : "cls2"), "elem.className = " + elem.className);
|
|
r = elem.getAttribute("class");
|
|
ok(r === "cls2", "class attr = " + r);
|
|
r = elem.getAttribute("className");
|
|
ok(r === "cls3", "className attr = " + r);
|
|
});
|
|
|
|
sync_test("__proto__", function() {
|
|
var v = document.documentMode;
|
|
var r, x = 42;
|
|
|
|
if(v < 11) {
|
|
ok(x.__proto__ === undefined, "x.__proto__ = " + x.__proto__);
|
|
ok(!("__proto__" in Object), "Object.__proto__ = " + Object.__proto__);
|
|
return;
|
|
}
|
|
|
|
ok(x.__proto__ === Number.prototype, "x.__proto__ = " + x.__proto__);
|
|
ok(Object.__proto__ === Function.prototype, "Object.__proto__ = " + Object.__proto__);
|
|
ok(Object.prototype.__proto__ === null, "Object.prototype.__proto__ = " + Object.prototype.__proto__);
|
|
ok(Object.prototype.hasOwnProperty("__proto__"), "__proto__ is not a property of Object.prototype");
|
|
ok(!Object.prototype.hasOwnProperty.call(x, "__proto__"), "__proto__ is a property of x");
|
|
|
|
x.__proto__ = Object.prototype;
|
|
ok(x.__proto__ === Number.prototype, "x.__proto__ set to Object.prototype = " + x.__proto__);
|
|
ok(!Object.prototype.hasOwnProperty.call(x, "__proto__"), "__proto__ is a property of x after set to Object.prototype");
|
|
x = {};
|
|
x.__proto__ = null;
|
|
r = Object.getPrototypeOf(x);
|
|
ok(x.__proto__ === undefined, "x.__proto__ after set to null = " + x.__proto__);
|
|
ok(r === null, "getPrototypeOf(x) after set to null = " + r);
|
|
|
|
function check(expect, msg) {
|
|
var r = Object.getPrototypeOf(x);
|
|
ok(x.__proto__ === expect, "x.__proto__ " + msg + " = " + x.__proto__);
|
|
ok(r === expect, "getPrototypeOf(x) " + msg + " = " + r);
|
|
ok(!Object.prototype.hasOwnProperty.call(x, "__proto__"), "__proto__ is a property of x " + msg);
|
|
}
|
|
|
|
x = {};
|
|
check(Object.prototype, "after x set to {}");
|
|
x.__proto__ = Number.prototype;
|
|
check(Number.prototype, "after set to Number.prototype");
|
|
x.__proto__ = Object.prototype;
|
|
check(Object.prototype, "after re-set to Object.prototype");
|
|
|
|
function ctor() { }
|
|
var obj = new ctor();
|
|
x.__proto__ = obj;
|
|
check(obj, "after set to obj");
|
|
x.__proto__ = ctor.prototype;
|
|
check(obj.__proto__, "after set to ctor.prototype");
|
|
ok(obj.__proto__ === ctor.prototype, "obj.__proto__ !== ctor.prototype");
|
|
|
|
r = (delete x.__proto__);
|
|
todo_wine.
|
|
ok(r, "delete x.__proto__ returned " + r);
|
|
ok(Object.prototype.hasOwnProperty("__proto__"), "__proto__ is not a property of Object.prototype after delete");
|
|
r = Object.getPrototypeOf(x);
|
|
ok(r === ctor.prototype, "x.__proto__ after delete = " + r);
|
|
});
|