diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /dom/html/test | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
684 files changed, 53186 insertions, 0 deletions
diff --git a/dom/html/test/347174transform.xsl b/dom/html/test/347174transform.xsl new file mode 100644 index 0000000000..1b201de3f3 --- /dev/null +++ b/dom/html/test/347174transform.xsl @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> + +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:template match="/"> +<html> +<head> +<script> +window.parent.frameScriptTag(document.readyState); + +function attachCustomEventListener(element, eventName, command) { + if (window.addEventListener && !window.opera) + element.addEventListener(eventName, command, true); + else if (window.attachEvent) + element.attachEvent("on" + eventName, command); +} + +function load() { + window.parent.frameLoad(document.readyState); +} + +function readyStateChange() { + window.parent.frameReadyStateChange(document.readyState); +} + +function DOMContentLoaded() { + window.parent.frameDOMContentLoaded(document.readyState); +} + +window.onload=load; + +attachCustomEventListener(document, "readystatechange", readyStateChange); +attachCustomEventListener(document, "DOMContentLoaded", DOMContentLoaded); + +</script> +</head> +<body> +</body> +</html> +</xsl:template> + +</xsl:stylesheet>
\ No newline at end of file diff --git a/dom/html/test/347174transformable.xml b/dom/html/test/347174transformable.xml new file mode 100644 index 0000000000..68f7bc6dca --- /dev/null +++ b/dom/html/test/347174transformable.xml @@ -0,0 +1,3 @@ +<?xml version='1.0'?> +<?xml-stylesheet type="text/xsl" href="347174transform.xsl"?> +<doc>This is a sample document.</doc> diff --git a/dom/html/test/allowMedia.sjs b/dom/html/test/allowMedia.sjs new file mode 100644 index 0000000000..f29619cd89 --- /dev/null +++ b/dom/html/test/allowMedia.sjs @@ -0,0 +1,12 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function handleRequest(req, resp) { + resp.setHeader("Cache-Control", "no-cache", false); + resp.setHeader("Content-Type", "text/plain", false); + + let stateKey = "allowMediaState"; + let state = getState(stateKey); + setState(stateKey, req.queryString ? "FAIL" : ""); + resp.write(state || "PASS"); +} diff --git a/dom/html/test/browser.toml b/dom/html/test/browser.toml new file mode 100644 index 0000000000..13775f607b --- /dev/null +++ b/dom/html/test/browser.toml @@ -0,0 +1,46 @@ +[DEFAULT] +support-files = [ + "bug592641_img.jpg", + "dummy_page.html", + "image.png", + "submission_flush.html", + "post_action_page.html", + "form_data_file.bin", + "form_data_file.txt", + "form_submit_server.sjs", + "head.js", +] + +["browser_DOMDocElementInserted.js"] +skip-if = ["bits == 64 && (os == 'mac' || os == 'linux')"] #Bug 1646862 + +["browser_ImageDocument_svg_zoom.js"] + +["browser_bug436200.js"] +support-files = ["bug436200.html"] + +["browser_bug592641.js"] + +["browser_bug1081537.js"] + +["browser_bug1108547.js"] +support-files = [ + "file_bug1108547-1.html", + "file_bug1108547-2.html", + "file_bug1108547-3.html", +] + +["browser_containerLoadingContent.js"] + +["browser_form_post_from_file_to_http.js"] + +["browser_refresh_after_document_write.js"] +support-files = ["file_refresh_after_document_write.html"] + +["browser_submission_flush.js"] + +["browser_targetBlankNoOpener.js"] +support-files = [ + "empty.html", + "image_yellow.png", +] diff --git a/dom/html/test/browser_DOMDocElementInserted.js b/dom/html/test/browser_DOMDocElementInserted.js new file mode 100644 index 0000000000..fb2b2ae63b --- /dev/null +++ b/dom/html/test/browser_DOMDocElementInserted.js @@ -0,0 +1,23 @@ +// Tests that the DOMDocElementInserted event is visible on the frame +add_task(async function () { + let tab = BrowserTestUtils.addTab(gBrowser); + let uri = "data:text/html;charset=utf-8,<html/>"; + + let eventPromise = ContentTask.spawn(tab.linkedBrowser, null, function () { + return new Promise(resolve => { + addEventListener( + "DOMDocElementInserted", + event => resolve(event.target.documentURIObject.spec), + { + once: true, + } + ); + }); + }); + + BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, uri); + let loadedURI = await eventPromise; + is(loadedURI, uri, "Should have seen the event for the right URI"); + + gBrowser.removeTab(tab); +}); diff --git a/dom/html/test/browser_ImageDocument_svg_zoom.js b/dom/html/test/browser_ImageDocument_svg_zoom.js new file mode 100644 index 0000000000..f0df2282a3 --- /dev/null +++ b/dom/html/test/browser_ImageDocument_svg_zoom.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const URL = `data:image/svg+xml,<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" fill="green"/></svg>`; + +function test_once() { + return BrowserTestUtils.withNewTab(URL, async browser => { + return await SpecialPowers.spawn(browser, [], async function () { + const rect = content.document.documentElement.getBoundingClientRect(); + info( + `${rect.width}x${rect.height}, ${content.innerWidth}x${content.innerHeight}` + ); + is( + Math.round(rect.height), + content.innerHeight, + "Should fill the viewport and not overflow" + ); + }); + }); +} + +add_task(async function test_with_no_text_zoom() { + await test_once(); +}); + +add_task(async function test_with_text_zoom() { + let dpi = window.devicePixelRatio; + + await SpecialPowers.pushPrefEnv({ set: [["ui.textScaleFactor", 200]] }); + Assert.greater( + window.devicePixelRatio, + dpi, + "DPI should change as a result of the pref flip" + ); + + return test_once(); +}); diff --git a/dom/html/test/browser_bug1081537.js b/dom/html/test/browser_bug1081537.js new file mode 100644 index 0000000000..2a079be2f7 --- /dev/null +++ b/dom/html/test/browser_bug1081537.js @@ -0,0 +1,11 @@ +// This test is useful because mochitest-browser runs as an addon, so we test +// addon-scope paths here. +var ifr; +function test() { + ifr = document.createXULElement("iframe"); + document.getElementById("main-window").appendChild(ifr); + is(ifr.contentDocument.nodePrincipal.origin, "[System Principal]"); + ifr.contentDocument.open(); + ok(true, "Didn't throw"); +} +registerCleanupFunction(() => ifr.remove()); diff --git a/dom/html/test/browser_bug1108547.js b/dom/html/test/browser_bug1108547.js new file mode 100644 index 0000000000..4949827086 --- /dev/null +++ b/dom/html/test/browser_bug1108547.js @@ -0,0 +1,149 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +requestLongerTimeout(2); + +function test() { + waitForExplicitFinish(); + + runPass("file_bug1108547-2.html", function () { + runPass("file_bug1108547-3.html", function () { + finish(); + }); + }); +} + +function runPass(getterFile, finishedCallback) { + var rootDir = "http://mochi.test:8888/browser/dom/html/test/"; + var testBrowser; + var privateWin; + + function whenDelayedStartupFinished(win, callback) { + let topic = "browser-delayed-startup-finished"; + Services.obs.addObserver(function onStartup(aSubject) { + if (win != aSubject) { + return; + } + + Services.obs.removeObserver(onStartup, topic); + executeSoon(callback); + }, topic); + } + + // First, set the cookie in a normal window. + gBrowser.selectedTab = BrowserTestUtils.addTab( + gBrowser, + rootDir + "file_bug1108547-1.html" + ); + BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then( + afterOpenCookieSetter + ); + + function afterOpenCookieSetter() { + gBrowser.removeCurrentTab(); + + // Now, open a private window. + privateWin = OpenBrowserWindow({ private: true }); + whenDelayedStartupFinished(privateWin, afterPrivateWindowOpened); + } + + function afterPrivateWindowOpened() { + // In the private window, open the getter file, and wait for a new tab to be opened. + privateWin.gBrowser.selectedTab = BrowserTestUtils.addTab( + privateWin.gBrowser, + rootDir + getterFile + ); + testBrowser = privateWin.gBrowser.selectedBrowser; + privateWin.gBrowser.tabContainer.addEventListener( + "TabOpen", + onNewTabOpened, + true + ); + } + + function fetchResult() { + return SpecialPowers.spawn(testBrowser, [], function () { + return content.document.getElementById("result").textContent; + }); + } + + function onNewTabOpened() { + // When the new tab is opened, wait for it to load. + privateWin.gBrowser.tabContainer.removeEventListener( + "TabOpen", + onNewTabOpened, + true + ); + BrowserTestUtils.browserLoaded( + privateWin.gBrowser.tabs[privateWin.gBrowser.tabs.length - 1] + .linkedBrowser + ) + .then(fetchResult) + .then(onNewTabLoaded); + } + + function onNewTabLoaded(result) { + // Now, ensure that the private tab doesn't have access to the cookie set in normal mode. + is(result, "", "Shouldn't have access to the cookies"); + + // We're done with the private window, close it. + privateWin.close(); + + // Clear all cookies. + Cc["@mozilla.org/cookiemanager;1"] + .getService(Ci.nsICookieManager) + .removeAll(); + + // Open a new private window, this time to set a cookie inside it. + privateWin = OpenBrowserWindow({ private: true }); + whenDelayedStartupFinished(privateWin, afterPrivateWindowOpened2); + } + + function afterPrivateWindowOpened2() { + // In the private window, open the setter file, and wait for it to load. + privateWin.gBrowser.selectedTab = BrowserTestUtils.addTab( + privateWin.gBrowser, + rootDir + "file_bug1108547-1.html" + ); + BrowserTestUtils.browserLoaded(privateWin.gBrowser.selectedBrowser).then( + afterOpenCookieSetter2 + ); + } + + function afterOpenCookieSetter2() { + // We're done with the private window now, close it. + privateWin.close(); + + // Now try to read the cookie in a normal window, and wait for a new tab to be opened. + gBrowser.selectedTab = BrowserTestUtils.addTab( + gBrowser, + rootDir + getterFile + ); + testBrowser = gBrowser.selectedBrowser; + gBrowser.tabContainer.addEventListener("TabOpen", onNewTabOpened2, true); + } + + function onNewTabOpened2() { + // When the new tab is opened, wait for it to load. + gBrowser.tabContainer.removeEventListener("TabOpen", onNewTabOpened2, true); + BrowserTestUtils.browserLoaded( + gBrowser.tabs[gBrowser.tabs.length - 1].linkedBrowser + ) + .then(fetchResult) + .then(onNewTabLoaded2); + } + + function onNewTabLoaded2(result) { + // Now, ensure that the normal tab doesn't have access to the cookie set in private mode. + is(result, "", "Shouldn't have access to the cookies"); + + // Remove both of the tabs opened here. + gBrowser.removeCurrentTab(); + gBrowser.removeCurrentTab(); + + privateWin = null; + testBrowser = null; + + finishedCallback(); + } +} diff --git a/dom/html/test/browser_bug436200.js b/dom/html/test/browser_bug436200.js new file mode 100644 index 0000000000..7e739c02ad --- /dev/null +++ b/dom/html/test/browser_bug436200.js @@ -0,0 +1,60 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const kTestPage = "https://example.org/browser/dom/html/test/bug436200.html"; + +async function run_test(shouldShowPrompt, msg) { + let promptShown = false; + + function tabModalObserver(subject) { + promptShown = true; + subject.querySelector(".tabmodalprompt-button0").click(); + } + Services.obs.addObserver(tabModalObserver, "tabmodal-dialog-loaded"); + + function commonDialogObserver(subject) { + let dialog = subject.Dialog; + promptShown = true; + dialog.ui.button0.click(); + } + Services.obs.addObserver(commonDialogObserver, "common-dialog-loaded"); + + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, kTestPage); + + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { + let form = content.document.getElementById("test_form"); + form.submit(); + }); + Services.obs.removeObserver(tabModalObserver, "tabmodal-dialog-loaded"); + Services.obs.removeObserver(commonDialogObserver, "common-dialog-loaded"); + + is(promptShown, shouldShowPrompt, msg); + BrowserTestUtils.removeTab(tab); +} + +add_task(async function test_prompt() { + await run_test(true, "Should show prompt"); +}); + +add_task(async function test_noprompt() { + await SpecialPowers.pushPrefEnv({ + set: [["security.warn_submit_secure_to_insecure", false]], + }); + await run_test(false, "Should not show prompt"); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async function test_prompt_modal() { + await SpecialPowers.pushPrefEnv({ + set: [ + [ + "prompts.modalType.insecureFormSubmit", + Services.prompt.MODAL_TYPE_WINDOW, + ], + ], + }); + await run_test(true, "Should show prompt"); + await SpecialPowers.popPrefEnv(); +}); diff --git a/dom/html/test/browser_bug592641.js b/dom/html/test/browser_bug592641.js new file mode 100644 index 0000000000..761af6a568 --- /dev/null +++ b/dom/html/test/browser_bug592641.js @@ -0,0 +1,61 @@ +// Test for bug 592641 - Image document doesn't show dimensions of cached images + +// Globals +var testPath = "http://mochi.test:8888/browser/dom/html/test/"; +var ctx = { loadsDone: 0 }; + +// Entry point from Mochikit +function test() { + waitForExplicitFinish(); + + ctx.tab1 = BrowserTestUtils.addTab(gBrowser, testPath + "bug592641_img.jpg"); + ctx.tab1Browser = gBrowser.getBrowserForTab(ctx.tab1); + BrowserTestUtils.browserLoaded(ctx.tab1Browser).then(load1Soon); +} + +function checkTitle(title) { + ctx.loadsDone++; + ok( + /^bug592641_img\.jpg \(JPEG Image, 1500\u00A0\u00D7\u00A01500 pixels\)/.test( + title + ), + "Title should be correct on load #" + ctx.loadsDone + ", was: " + title + ); +} + +function load1Soon() { + // onload is fired in OnStopDecode, so let's use executeSoon() to make sure + // that any other OnStopDecode event handlers get the chance to fire first. + executeSoon(load1Done); +} + +function load1Done() { + // Check the title + var title = ctx.tab1Browser.contentTitle; + checkTitle(title); + + // Try loading the same image in a new tab to make sure things work in + // the cached case. + ctx.tab2 = BrowserTestUtils.addTab(gBrowser, testPath + "bug592641_img.jpg"); + ctx.tab2Browser = gBrowser.getBrowserForTab(ctx.tab2); + BrowserTestUtils.browserLoaded(ctx.tab2Browser).then(load2Soon); +} + +function load2Soon() { + // onload is fired in OnStopDecode, so let's use executeSoon() to make sure + // that any other OnStopDecode event handlers get the chance to fire first. + executeSoon(load2Done); +} + +function load2Done() { + // Check the title + var title = ctx.tab2Browser.contentTitle; + checkTitle(title); + + // Clean up + gBrowser.removeTab(ctx.tab1); + gBrowser.removeTab(ctx.tab2); + + // Test done + finish(); +} diff --git a/dom/html/test/browser_containerLoadingContent.js b/dom/html/test/browser_containerLoadingContent.js new file mode 100644 index 0000000000..4fb10db614 --- /dev/null +++ b/dom/html/test/browser_containerLoadingContent.js @@ -0,0 +1,108 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const DIRPATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "" +); + +const ORIGIN = "https://example.com"; +const CROSSORIGIN = "https://example.org"; + +const TABURL = `${ORIGIN}/${DIRPATH}dummy_page.html`; + +const IMAGEURL = `${ORIGIN}/${DIRPATH}image.png`; +const CROSSIMAGEURL = `${CROSSORIGIN}/${DIRPATH}image.png`; + +const DOCUMENTURL = `${ORIGIN}/${DIRPATH}dummy_page.html`; +const CROSSDOCUMENTURL = `${CROSSORIGIN}/${DIRPATH}dummy_page.html`; + +function getPids(browser) { + return browser.browsingContext.children.map( + child => child.currentWindowContext.osPid + ); +} + +async function runTest(spec, tabUrl, imageurl, crossimageurl, check) { + await BrowserTestUtils.withNewTab(tabUrl, async browser => { + await SpecialPowers.spawn( + browser, + [spec, imageurl, crossimageurl], + async ({ element, attribute }, url1, url2) => { + for (let url of [url1, url2]) { + const object = content.document.createElement(element); + object[attribute] = url; + const onloadPromise = new Promise(res => { + object.onload = res; + }); + content.document.body.appendChild(object); + await onloadPromise; + } + } + ); + + await check(browser); + }); +} + +let iframe = { element: "iframe", attribute: "src" }; +let embed = { element: "embed", attribute: "src" }; +let object = { element: "object", attribute: "data" }; + +async function checkImage(browser) { + let pids = getPids(browser); + is(pids.length, 2, "There should be two browsing contexts"); + ok(pids[0], "The first pid should have a sane value"); + ok(pids[1], "The second pid should have a sane value"); + isnot(pids[0], pids[1], "The two pids should be different"); + + let images = []; + for (let context of browser.browsingContext.children) { + images.push( + await SpecialPowers.spawn(context, [], async () => { + let img = new URL(content.document.querySelector("img").src); + is( + `${img.protocol}//${img.host}`, + `${content.location.protocol}//${content.location.host}`, + "Images should be loaded in the same domain as the document" + ); + return img.href; + }) + ); + } + isnot(images[0], images[1], "The images should have different sources"); +} + +function checkDocument(browser) { + let pids = getPids(browser); + is(pids.length, 2, "There should be two browsing contexts"); + ok(pids[0], "The first pid should have a sane value"); + ok(pids[1], "The second pid should have a sane value"); + isnot(pids[0], pids[1], "The two pids should be different"); +} + +add_task(async function test_iframeImageDocument() { + await runTest(iframe, TABURL, IMAGEURL, CROSSIMAGEURL, checkImage); +}); + +add_task(async function test_embedImageDocument() { + await runTest(embed, TABURL, IMAGEURL, CROSSIMAGEURL, checkImage); +}); + +add_task(async function test_objectImageDocument() { + await runTest(object, TABURL, IMAGEURL, CROSSIMAGEURL, checkImage); +}); + +add_task(async function test_iframeDocument() { + await runTest(iframe, TABURL, DOCUMENTURL, CROSSDOCUMENTURL, checkDocument); +}); + +add_task(async function test_embedDocument() { + await runTest(embed, TABURL, DOCUMENTURL, CROSSDOCUMENTURL, checkDocument); +}); + +add_task(async function test_objectDocument() { + await runTest(object, TABURL, DOCUMENTURL, CROSSDOCUMENTURL, checkDocument); +}); diff --git a/dom/html/test/browser_form_post_from_file_to_http.js b/dom/html/test/browser_form_post_from_file_to_http.js new file mode 100644 index 0000000000..e62912bdcd --- /dev/null +++ b/dom/html/test/browser_form_post_from_file_to_http.js @@ -0,0 +1,181 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ + +const TEST_HTTP_POST = + "http://example.org/browser/dom/html/test/form_submit_server.sjs"; + +// Test for bug 1351358. +async function runTest(doNewTab) { + // Create file URI and test data file paths. + let testFile = getChromeDir(getResolvedURI(gTestPath)); + testFile.append("dummy_page.html"); + const fileUriString = Services.io.newFileURI(testFile).spec; + let filePaths = []; + testFile.leafName = "form_data_file.txt"; + filePaths.push(testFile.path); + testFile.leafName = "form_data_file.bin"; + filePaths.push(testFile.path); + + // Open file:// page tab in which to run the test. + await BrowserTestUtils.withNewTab( + fileUriString, + async function (fileBrowser) { + // Create a form to post to server that writes posted data into body as JSON. + + var promiseLoad; + if (doNewTab) { + promiseLoad = BrowserTestUtils.waitForNewTab( + gBrowser, + TEST_HTTP_POST, + true, + false + ); + } else { + promiseLoad = BrowserTestUtils.browserLoaded( + fileBrowser, + false, + TEST_HTTP_POST + ); + } + + /* eslint-disable no-shadow */ + await SpecialPowers.spawn( + fileBrowser, + [TEST_HTTP_POST, filePaths, doNewTab], + (actionUri, filePaths, doNewTab) => { + // eslint-disable-next-line mozilla/reject-importGlobalProperties + Cu.importGlobalProperties(["File"]); + + let doc = content.document; + let form = doc.body.appendChild(doc.createElement("form")); + form.action = actionUri; + form.method = "POST"; + form.enctype = "multipart/form-data"; + if (doNewTab) { + form.target = "_blank"; + } + + let inputText = form.appendChild(doc.createElement("input")); + inputText.type = "text"; + inputText.name = "text"; + inputText.value = "posted"; + + let inputCheckboxOn = form.appendChild(doc.createElement("input")); + inputCheckboxOn.type = "checkbox"; + inputCheckboxOn.name = "checked"; + inputCheckboxOn.checked = true; + + let inputCheckboxOff = form.appendChild(doc.createElement("input")); + inputCheckboxOff.type = "checkbox"; + inputCheckboxOff.name = "unchecked"; + inputCheckboxOff.checked = false; + + let inputFile = form.appendChild(doc.createElement("input")); + inputFile.type = "file"; + inputFile.name = "file"; + let fileList = []; + let promises = []; + for (let path of filePaths) { + promises.push( + File.createFromFileName(path).then(file => { + fileList.push(file); + }) + ); + } + + Promise.all(promises).then(() => { + inputFile.mozSetFileArray(fileList); + form.submit(); + }); + } + ); + /* eslint-enable no-shadow */ + + var href; + var testBrowser; + var newTab; + if (doNewTab) { + newTab = await promiseLoad; + testBrowser = newTab.linkedBrowser; + href = testBrowser.currentURI.spec; + } else { + testBrowser = fileBrowser; + href = await promiseLoad; + } + is( + href, + TEST_HTTP_POST, + "Check that the loaded page is the one to which we posted." + ); + + let binContentType; + if (AppConstants.platform == "macosx") { + binContentType = "application/macbinary"; + } else { + binContentType = "application/octet-stream"; + } + + /* eslint-disable no-shadow */ + await SpecialPowers.spawn( + testBrowser, + [binContentType], + binContentType => { + let data = JSON.parse(content.document.body.textContent); + is( + data[0].headers["Content-Disposition"], + 'form-data; name="text"', + "Check text input Content-Disposition" + ); + is(data[0].body, "posted", "Check text input body"); + + is( + data[1].headers["Content-Disposition"], + 'form-data; name="checked"', + "Check checkbox input Content-Disposition" + ); + is(data[1].body, "on", "Check checkbox input body"); + + // Note that unchecked checkbox details are not sent. + + is( + data[2].headers["Content-Disposition"], + 'form-data; name="file"; filename="form_data_file.txt"', + "Check text file input Content-Disposition" + ); + is( + data[2].headers["Content-Type"], + "text/plain", + "Check text file input Content-Type" + ); + is(data[2].body, "1234\n", "Check text file input body"); + + is( + data[3].headers["Content-Disposition"], + 'form-data; name="file"; filename="form_data_file.bin"', + "Check binary file input Content-Disposition" + ); + is( + data[3].headers["Content-Type"], + binContentType, + "Check binary file input Content-Type" + ); + is( + data[3].body, + "\u0001\u0002\u0003\u0004\n", + "Check binary file input body" + ); + } + ); + /* eslint-enable no-shadow */ + + if (newTab) { + BrowserTestUtils.removeTab(newTab); + } + } + ); +} + +add_task(async function runWithDocumentChannel() { + await runTest(false); + await runTest(true); +}); diff --git a/dom/html/test/browser_refresh_after_document_write.js b/dom/html/test/browser_refresh_after_document_write.js new file mode 100644 index 0000000000..88e0dbe489 --- /dev/null +++ b/dom/html/test/browser_refresh_after_document_write.js @@ -0,0 +1,52 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* +Test that after using document.write(...), refreshing the document and calling write again, +resulting document.URL is identical to the original URL. + +This testcase is aimed at preventing bug 619092 +*/ +var testURL = + "http://mochi.test:8888/browser/dom/html/test/file_refresh_after_document_write.html"; +let aTab, aBrowser; + +function test() { + waitForExplicitFinish(); + + aTab = BrowserTestUtils.addTab(gBrowser, testURL); + aBrowser = gBrowser.getBrowserForTab(aTab); + BrowserTestUtils.browserLoaded(aBrowser) + .then(() => { + is( + aBrowser.currentURI.spec, + testURL, + "Make sure we start at the correct URL" + ); + + SpecialPowers.spawn(aBrowser, [], () => { + // test_btn calls document.write() then reloads the document + let test_btn = content.document.getElementById("test_btn"); + + docShell.chromeEventHandler.addEventListener( + "load", + () => { + test_btn.click(); + }, + { once: true, capture: true } + ); + + test_btn.click(); + }); + + return BrowserTestUtils.browserLoaded(aBrowser); + }) + .then(() => { + return SpecialPowers.spawn(aBrowser, [], () => content.document.URL); + }) + .then(url => { + is(url, testURL, "Document URL should be identical after reload"); + gBrowser.removeTab(aTab); + finish(); + }); +} diff --git a/dom/html/test/browser_submission_flush.js b/dom/html/test/browser_submission_flush.js new file mode 100644 index 0000000000..add886c6a3 --- /dev/null +++ b/dom/html/test/browser_submission_flush.js @@ -0,0 +1,97 @@ +"use strict"; +// Form submissions triggered by the Javascript 'submit' event listener are +// deferred until the event listener finishes. However, changes to specific +// attributes ("action" and "target" attributes) need to cause an immediate +// flush of any pending submission to prevent the form submission from using the +// wrong action or target. This test ensures that such flushes happen properly. + +const kTestPage = + "https://example.org/browser/dom/html/test/submission_flush.html"; +// This is the page pointed to by the form action in the test HTML page. +const kPostActionPage = + "https://example.org/browser/dom/html/test/post_action_page.html"; + +const kFormId = "test_form"; +const kFrameId = "test_frame"; +const kSubmitButtonId = "submit_button"; + +// Take in a variety of actions (in the form of setting and unsetting form +// attributes). Then submit the form in the submit event listener to cause a +// deferred form submission. Then perform the test actions and ensure that the +// form used the correct attribute values rather than the changed ones. +async function runTest(aTestActions) { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, kTestPage); + registerCleanupFunction(() => BrowserTestUtils.removeTab(tab)); + + /* eslint-disable no-shadow */ + let frame_url = await SpecialPowers.spawn( + gBrowser.selectedBrowser, + [{ kFormId, kFrameId, kSubmitButtonId, aTestActions }], + async function ({ kFormId, kFrameId, kSubmitButtonId, aTestActions }) { + let form = content.document.getElementById(kFormId); + + form.addEventListener( + "submit", + event => { + // Need to trigger the deferred submission by submitting in the submit + // event handler. To prevent the form from being submitted twice, the + // <form> tag contains the attribute |onsubmit="return false;"| to cancel + // the original submission. + form.submit(); + + if (aTestActions.setattr) { + for (let { attr, value } of aTestActions.setattr) { + form.setAttribute(attr, value); + } + } + if (aTestActions.unsetattr) { + for (let attr of aTestActions.unsetattr) { + form.removeAttribute(attr); + } + } + }, + { capture: true, once: true } + ); + + // Trigger the above event listener + content.document.getElementById(kSubmitButtonId).click(); + + // Test that the form was submitted to the correct target (the frame) with + // the correct action (kPostActionPage). + let frame = content.document.getElementById(kFrameId); + await new Promise(resolve => { + frame.addEventListener("load", resolve, { once: true }); + }); + return frame.contentWindow.location.href; + } + ); + /* eslint-enable no-shadow */ + is( + frame_url, + kPostActionPage, + "Form should have submitted with correct target and action" + ); +} + +add_task(async function () { + info("Changing action should flush pending submissions"); + await runTest({ setattr: [{ attr: "action", value: "about:blank" }] }); +}); + +add_task(async function () { + info("Changing target should flush pending submissions"); + await runTest({ setattr: [{ attr: "target", value: "_blank" }] }); +}); + +add_task(async function () { + info("Unsetting action should flush pending submissions"); + await runTest({ unsetattr: ["action"] }); +}); + +// On failure, this test will time out rather than failing an assert. When the +// target attribute is not set, the form will submit the active page, navigating +// it away and preventing the wait for iframe load from ever finishing. +add_task(async function () { + info("Unsetting target should flush pending submissions"); + await runTest({ unsetattr: ["target"] }); +}); diff --git a/dom/html/test/browser_targetBlankNoOpener.js b/dom/html/test/browser_targetBlankNoOpener.js new file mode 100644 index 0000000000..1647df0be2 --- /dev/null +++ b/dom/html/test/browser_targetBlankNoOpener.js @@ -0,0 +1,121 @@ +const TEST_URL = "http://mochi.test:8888/browser/dom/html/test/empty.html"; + +async function checkOpener(browser, elm, name, rel) { + let p = BrowserTestUtils.waitForNewTab(gBrowser, null, true, true); + + await SpecialPowers.spawn( + browser, + [{ url: TEST_URL, name, rel, elm }], + async obj => { + let element; + + if (obj.elm == "anchor") { + element = content.document.createElement("a"); + content.document.body.appendChild(element); + element.appendChild(content.document.createTextNode(obj.name)); + } else { + let img = content.document.createElement("img"); + img.src = "image_yellow.png"; + content.document.body.appendChild(img); + + element = content.document.createElement("area"); + img.appendChild(element); + + element.setAttribute("shape", "rect"); + element.setAttribute("coords", "0,0,100,100"); + } + + element.setAttribute("target", "_blank"); + element.setAttribute("href", obj.url); + + if (obj.rel) { + element.setAttribute("rel", obj.rel); + } + + element.click(); + } + ); + + let newTab = await p; + let newBrowser = gBrowser.getBrowserForTab(newTab); + + let hasOpener = await SpecialPowers.spawn( + newTab.linkedBrowser, + [], + _ => !!content.window.opener + ); + + BrowserTestUtils.removeTab(newTab); + return hasOpener; +} + +async function runTests(browser, elm) { + info("Creating an " + elm + " with target=_blank rel=opener"); + ok( + !!(await checkOpener(browser, elm, "rel=opener", "opener")), + "We want the opener with rel=opener" + ); + + info("Creating an " + elm + " with target=_blank rel=noopener"); + ok( + !(await checkOpener(browser, elm, "rel=noopener", "noopener")), + "We don't want the opener with rel=noopener" + ); + + info("Creating an " + elm + " with target=_blank"); + ok( + !(await checkOpener(browser, elm, "no rel", null)), + "We don't want the opener with no rel is passed" + ); + + info("Creating an " + elm + " with target=_blank rel='noopener opener'"); + ok( + !(await checkOpener( + browser, + elm, + "rel=noopener+opener", + "noopener opener" + )), + "noopener wins with rel=noopener+opener" + ); + + info("Creating an " + elm + " with target=_blank rel='noreferrer opener'"); + ok( + !(await checkOpener(browser, elm, "noreferrer wins", "noreferrer opener")), + "We don't want the opener with rel=noreferrer+opener" + ); + + info("Creating an " + elm + " with target=_blank rel='opener noreferrer'"); + ok( + !(await checkOpener( + browser, + elm, + "noreferrer wins again", + "noreferrer opener" + )), + "We don't want the opener with rel=opener+noreferrer" + ); +} + +add_task(async _ => { + await SpecialPowers.flushPrefEnv(); + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.block_multiple_popups", false], + ["dom.disable_open_during_load", true], + ["dom.targetBlankNoOpener.enabled", true], + ], + }); + + let tab = BrowserTestUtils.addTab(gBrowser, TEST_URL); + gBrowser.selectedTab = tab; + + let browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + + await runTests(browser, "anchor"); + await runTests(browser, "area"); + + info("Removing the tab"); + BrowserTestUtils.removeTab(tab); +}); diff --git a/dom/html/test/bug100533_iframe.html b/dom/html/test/bug100533_iframe.html new file mode 100644 index 0000000000..ddf58a15c6 --- /dev/null +++ b/dom/html/test/bug100533_iframe.html @@ -0,0 +1,8 @@ +<html> +<head> +<title></title> +</head> +<body> +<form method='get' action='bug100533_load.html' id='b'><input type="submit"/></form> +</body> +</html> diff --git a/dom/html/test/bug100533_load.html b/dom/html/test/bug100533_load.html new file mode 100644 index 0000000000..99cf26640c --- /dev/null +++ b/dom/html/test/bug100533_load.html @@ -0,0 +1,14 @@ +<html> +<head> +<title></title> +</head> + + +<body onload="parent.submitted();"> + +<span id="foo"></span> + + + +</body> +</html> diff --git a/dom/html/test/bug1260704_iframe.html b/dom/html/test/bug1260704_iframe.html new file mode 100644 index 0000000000..695dc7c1ac --- /dev/null +++ b/dom/html/test/bug1260704_iframe.html @@ -0,0 +1,38 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript"> + var noDefault = (location.search.includes("noDefault=true")); + var isMap = (location.search.includes("isMap=true")); + + window.addEventListener("load", () => { + let image = document.getElementById("testImage"); + isMap ? image.setAttribute("ismap", "") : image.removeAttribute("ismap"); + image.addEventListener("click", event => { + if (noDefault) { + ok(true, "image element prevents default"); + event.preventDefault(); + } + }); + + window.addEventListener("click", event => { + ok(true, "expected prevent default = " + noDefault); + ok(true, "actual prevent default = " + event.defaultPrevented); + ok(event.defaultPrevented == noDefault, "PreventDefault should work fine"); + if (noDefault) { + window.parent.postMessage("finished", "http://mochi.test:8888"); + } + }); + window.parent.postMessage("started", "http://mochi.test:8888"); + }); + </script> +</head> +<body> +<a href="bug1260704_iframe_empty.html"> + <img id="testImage" src="file_bug1260704.png" width="100" height="100"/> +</a> +</body> +</html> diff --git a/dom/html/test/bug1260704_iframe_empty.html b/dom/html/test/bug1260704_iframe_empty.html new file mode 100644 index 0000000000..e826b1e5e6 --- /dev/null +++ b/dom/html/test/bug1260704_iframe_empty.html @@ -0,0 +1,15 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript"> + window.addEventListener("load", () => { + window.parent.postMessage("empty_frame_loaded", "http://mochi.test:8888"); + }); + </script> +</head> +<body> +</body> +</html> diff --git a/dom/html/test/bug1292522_iframe.html b/dom/html/test/bug1292522_iframe.html new file mode 100644 index 0000000000..99a3369d00 --- /dev/null +++ b/dom/html/test/bug1292522_iframe.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html><head><title>iframe</title></head> + <body> + <p>var testvar = "testiframe"</p> + <script> + document.domain='example.org'; + var testvar = "testiframe"; + </script> + </body> +</html> diff --git a/dom/html/test/bug1292522_page.html b/dom/html/test/bug1292522_page.html new file mode 100644 index 0000000000..9570f12d2d --- /dev/null +++ b/dom/html/test/bug1292522_page.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> + <head> + <title>Test for Bug 1292522</title> + <script> + var check_var = function() { + opener.postMessage(document.getElementsByTagName('iframe')[0].contentWindow.testvar, "http://mochi.test:8888"); + } + </script> + </head> + <body> + <iframe src="http://test2.example.org:80/tests/dom/html/test/bug1292522_iframe.html" onload="document.domain='example.org';check_var();"></iframe> + </body> +</html> diff --git a/dom/html/test/bug1315146-iframe.html b/dom/html/test/bug1315146-iframe.html new file mode 100644 index 0000000000..280db53052 --- /dev/null +++ b/dom/html/test/bug1315146-iframe.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<script> +document.domain = "example.org"; +</script> diff --git a/dom/html/test/bug1315146-main.html b/dom/html/test/bug1315146-main.html new file mode 100644 index 0000000000..e9f356dda6 --- /dev/null +++ b/dom/html/test/bug1315146-main.html @@ -0,0 +1,15 @@ +<!DOCTYPE HTML> +<iframe src="http://example.org/tests/dom/html/test/bug1315146-iframe.html"></iframe> +<input value="test"> +<script> +document.domain = "example.org"; +onload = function() { + let iframe = document.querySelector("iframe"); + let input = document.querySelector("input"); + input.selectionStart = input.selectionEnd = 2; + document.body.style.overflow = "scroll"; + iframe.contentDocument.body.offsetWidth; + opener.postMessage({start: input.selectionStart, + end: input.selectionEnd}, "*"); +} +</script> diff --git a/dom/html/test/bug196523-subframe.html b/dom/html/test/bug196523-subframe.html new file mode 100644 index 0000000000..ac53572a7a --- /dev/null +++ b/dom/html/test/bug196523-subframe.html @@ -0,0 +1,37 @@ +<!DOCTYPE html> +<script> + function checkDomain(str, msg) { + window.parent.postMessage((str == document.domain) + ";" +msg, + "http://mochi.test:8888"); + } + + function reportException(msg) { + window.parent.postMessage(false + ";" + msg, "http://mochi.test:8888"); + } + + var win1; + try { + win1 = window.open("", "", "width=100,height=100"); + var otherDomain1 = win1.document.domain; + win1.close(); + checkDomain(otherDomain1, "Opened document should have our domain"); + } catch(e) { + reportException("Exception getting document.domain: " + e); + } finally { + win1.close(); + } + + document.domain = "example.org"; + + var win2; + try { + win2 = window.open("", "", "width=100,height=100"); + var otherDomain2 = win2.document.domain; + checkDomain(otherDomain2, "Opened document should have our domain"); + win2.close(); + } catch(e) { + reportException("Exception getting document.domain after domain set: " + e); + } finally { + win2.close(); + } +</script> diff --git a/dom/html/test/bug199692-nested-d2.html b/dom/html/test/bug199692-nested-d2.html new file mode 100644 index 0000000000..70064efe74 --- /dev/null +++ b/dom/html/test/bug199692-nested-d2.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=199692 +--> +<head> + <title>Nested, nested iframe for bug 199692 tests</title> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +</head> +<body> + <div id="nest2div" style="border: 2px dotted blue;">nested, depth 2</div> +</body> +</html> + diff --git a/dom/html/test/bug199692-nested.html b/dom/html/test/bug199692-nested.html new file mode 100644 index 0000000000..27201a953d --- /dev/null +++ b/dom/html/test/bug199692-nested.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=199692 +--> +<head> + <title>Nested iframe for bug 199692 tests</title> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +</head> +<body> + <div id="nest1div" style="border: 2px dotted green;">nested, depth 1</div> + <iframe src="bug199692-nested-d2.html"></iframe> +</body> +</html> + diff --git a/dom/html/test/bug199692-popup.html b/dom/html/test/bug199692-popup.html new file mode 100644 index 0000000000..de93ca8599 --- /dev/null +++ b/dom/html/test/bug199692-popup.html @@ -0,0 +1,190 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=199692 +--> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <title>Popup in test for Bug 199692</title> + <style type="text/css"> +#content * { + border: 2px solid black; + margin: 2px; + clear: both; + height: 20px; + overflow: hidden; +} + +#txt, #static, #fixed, #absolute, #relative, #hidden, #float, #empty, #static, #relative { + width: 200px !important; +} + </style> + +</head> +<!-- +Elements are styled in such a way that they don't overlap visually +unless they also overlap structurally. + +This file is designed to be opened from test_bug199692.html in a popup +window, to guarantee that the window in which document.elementFromPoint runs +is large enough to display all the elements being tested. +--> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=199692">Mozilla Bug 199692</a> + +<div id="content" style="width: 500px; background-color: #ccc;"> + +<!-- element containing text --> +<div id="txt" style="height: 30px;">txt</div> + +<!-- element not containing text --> +<div id="empty" style="border: 2px solid blue;"></div> + +<!-- element with only whitespace --> +<p id="whitespace" style="border: 2px solid magenta;"> </p> + +<!-- position: static --> +<span id="static" style="position: static; border-color: green;">static</span> + +<!-- floated element --> +<div id="float" style="border-color: red; float: right;">float</div> + +<!-- position: fixed --> +<span id="fixed" style="position: fixed; top: 500px; left: 100px; border: 3px solid yellow;">fixed</span> + +<!-- position: absolute --> +<span id="absolute" style="position: absolute; top: 550px; left: 150px; border-color: orange;">abs</span> + +<!-- position: relative --> +<div id="relative" style="position: relative; top: 200px; border-color: teal;">rel</div> + +<!-- visibility: hidden --> +<div id="hidden-wrapper" style="border: 1px dashed teal;"> + <div id="hidden" style="opacity: 0.5; background-color: blue; visibility:hidden;">hidden</div> +</div> + +<!-- iframe (within iframe) --> +<iframe id="our-iframe" src="bug199692-nested.html" style="height: 100px; overflow: scroll;"></iframe> + +<input type="textbox" id="textbox" value="textbox"></input> +</div> + +<!-- interaction with scrolling --> +<iframe id="scrolled-iframe" + src="bug199692-scrolled.html#down" + style="position: absolute; top: 345px; left: 325px; height: 200px; width: 200px"></iframe> + +<script type="application/javascript"> + +var SimpleTest = window.opener.SimpleTest; +function ok() { window.opener.ok.apply(window.opener, arguments); } +function is() { window.opener.is.apply(window.opener, arguments); } +function todo() { window.opener.todo.apply(window.opener, arguments); } +function todo_is() { window.opener.todo_is.apply(window.opener, arguments); } +function $(id) { return document.getElementById(id); } + +/** + * Like is, but for tests which don't always succeed or always fail on all + * platforms. + */ +function random_fail(a, b, m) +{ + if (a != b) + todo_is(a, b, m); + else + is(a, b, m); +} + +/* Test for Bug 199692 */ + +function getCoords(elt) +{ + var x = 0, y = 0; + + do + { + x += elt.offsetLeft; + y += elt.offsetTop; + } while ((elt = elt.offsetParent)); + + return { x, y }; +} + +var elts = ["txt", "empty", "whitespace", "static", "fixed", "absolute", + "relative", "float", "textbox"]; + +function testPoints() +{ + ok('elementFromPoint' in document, "document.elementFromPoint must exist"); + ok(typeof document.elementFromPoint === "function", "must be a function"); + + var doc = document; + doc.pt = doc.elementFromPoint; // for shorter lines + is(doc.pt(-1, 0), null, "Negative coordinates (-1, 0) should return null"); + is(doc.pt(0, -1), null, "Negative coordinates (0, -1) should return null"); + is(doc.pt(-1, -1), null, "Negative coordinates (-1, -1) should return null"); + + var pos; + for (var i = 0; i < elts.length; i++) + { + var id = elts[i]; + var elt = $(id); + + // The upper left corner of an element (with a moderate offset) will + // usually contain text, and the lower right corner usually won't. + var pos = getCoords(elt); + var x = pos.x, y = pos.y; + var w = elt.offsetWidth, h = elt.offsetHeight; + + var d = 5; + is(doc.pt(x + d, y + d), elt, + "(" + (x + d) + "," + (y + d) + ") IDs should match (upper left " + + "corner of " + id + ")"); + is(doc.pt(x + w - d, y + h - d), elt, + "(" + (x + w - d) + "," + (y + h - d) + ") IDs should match (lower " + + "right corner of " + id + ")"); + } + + // content + var c = $("content"); + pos = getCoords(c); + x = pos.x + c.offsetWidth / 2; + y = pos.y; + + // This fails on some platforms but not others for unknown reasons + random_fail(doc.pt(x, y), c, "Point to right of #txt should be #content"); + is(doc.pt(x, y + 1), c, "Point to right of #txt should be #content"); + random_fail(doc.pt(x + 1, y), c, "Point to right of #txt should be #content"); + is(doc.pt(x + 1, y + 1), c, "Point to right of #txt should be #content"); + + // hidden + c = $("hidden"); + pos = getCoords(c); + x = pos.x; + y = pos.y; + is(doc.pt(x, y), $("hidden-wrapper"), + "Hit testing should bypass hidden elements."); + + // iframe nested + var iframe = $("our-iframe"); + pos = getCoords(iframe); + x = pos.x; + y = pos.y; + is(doc.pt(x + 20, y + 20), $("our-iframe"), + "Element from nested iframe returned is from calling document"); + // iframe, doubly nested + is(doc.pt(x + 60, y + 60), $("our-iframe"), + "Element from doubly nested iframe returned is from calling document"); + + // scrolled iframe tests + $("scrolled-iframe").contentWindow.runTests(); + + SimpleTest.finish(); + window.close(); +} + +window.onload = testPoints; +</script> +</body> +</html> + diff --git a/dom/html/test/bug199692-scrolled.html b/dom/html/test/bug199692-scrolled.html new file mode 100644 index 0000000000..f13bf7ab12 --- /dev/null +++ b/dom/html/test/bug199692-scrolled.html @@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=199692 +--> +<head> + <title>Scrolled page for bug 199692 tests</title> + <style type="text/css"> +/* Disable default margins/padding/borders so (0, 0) gets a div. */ +* { margin: 0; padding: 0; border: 0; } + </style> + <script type="application/javascript"> +function $(id) { return document.getElementById(id); } + +function runTests() +{ + var is = window.parent.is; + + is(document.elementFromPoint(0, 0), $("down"), + "document.elementFromPoint not respecting scrolling?"); + is(document.elementFromPoint(200, 200), null, + "should have returned null for a not-visible point"); + is(document.elementFromPoint(3, -5), null, + "should have returned null for a not-visible point"); +} + </script> +</head> +<!-- This page is loaded in a 200px-square iframe scrolled to #down. --> +<body> +<div style="height: 150px; background: lightblue;">first</div> +<div id="down" style="height: 250px; background: lightgreen;">second</div> +</body> +</html> + diff --git a/dom/html/test/bug242709_iframe.html b/dom/html/test/bug242709_iframe.html new file mode 100644 index 0000000000..1155299692 --- /dev/null +++ b/dom/html/test/bug242709_iframe.html @@ -0,0 +1,20 @@ +<html> +<head> +<title></title> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<script type="text/javascript"> +function submitIframeForm () { + document.getElementById('b').submit(); + document.getElementById('thebutton').disabled = true; +} +</script> + +</head> +<body onload="sendMouseEvent({type:'click'}, 'thebutton')"> + +<form method="get" action="bug242709_load.html" id="b"> +<input type="submit" onclick="submitIframeForm()" id="thebutton"> +</form> + +</body> +</html> diff --git a/dom/html/test/bug242709_load.html b/dom/html/test/bug242709_load.html new file mode 100644 index 0000000000..c9be79b241 --- /dev/null +++ b/dom/html/test/bug242709_load.html @@ -0,0 +1,11 @@ +<html> +<head> +<title></title> +</head> + +<body onload="parent.submitted();"> + +<span id="foo"></span> + +</body> +</html> diff --git a/dom/html/test/bug277724_iframe1.html b/dom/html/test/bug277724_iframe1.html new file mode 100644 index 0000000000..d0d881b766 --- /dev/null +++ b/dom/html/test/bug277724_iframe1.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML> +<html> +<!-- Use an unload handler to prevent bfcache from messing with us --> +<body onunload="parent.childUnloaded = true;"> + <select id="select"> + <option>aaa</option> + <option>bbbb</option> + </select> + + <textarea id="textarea"> + </textarea> + + <input type="text" id="text"> + <input type="password" id="password"> + <input type="checkbox" id="checkbox"> + <input type="radio" id="radio"> + <input type="image" id="image"> + <input type="submit" id="submit"> + <input type="reset" id="reset"> + <input type="button" id="button input"> + <input type="hidden" id="hidden"> + <input type="file" id="file"> + + <button type="submit" id="submit button"></button> + <button type="reset" id="reset button"></button> + <button type="button" id="button"></button> +</body> +</html> diff --git a/dom/html/test/bug277724_iframe2.xhtml b/dom/html/test/bug277724_iframe2.xhtml new file mode 100644 index 0000000000..14423aa06c --- /dev/null +++ b/dom/html/test/bug277724_iframe2.xhtml @@ -0,0 +1,27 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- Use an unload handler to prevent bfcache from messing with us --> +<body onunload="parent.childUnloaded = true;"> + <select id="select"> + <option>aaa</option> + <option>bbbb</option> + </select> + + <textarea id="textarea"> + </textarea> + + <input type="text" id="text" /> + <input type="password" id="password" /> + <input type="checkbox" id="checkbox" /> + <input type="radio" id="radio" /> + <input type="image" id="image" /> + <input type="submit" id="submit" /> + <input type="reset" id="reset" /> + <input type="button" id="button input" /> + <input type="hidden" id="hidden" /> + <input type="file" id="file" /> + + <button type="submit" id="submit button"></button> + <button type="reset" id="reset button"></button> + <button type="button" id="button"></button> +</body> +</html> diff --git a/dom/html/test/bug277890_iframe.html b/dom/html/test/bug277890_iframe.html new file mode 100644 index 0000000000..c1cb4ff2e1 --- /dev/null +++ b/dom/html/test/bug277890_iframe.html @@ -0,0 +1,20 @@ +<html> +<head> +<title></title> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<script type="text/javascript"> +function submitIframeForm () { + document.getElementById('b').submit(); + document.getElementById('thebutton').disabled = true; +} +</script> + +</head> +<body onload="sendMouseEvent({type:'click'}, 'thebutton')"> + +<form method="get" action="bug277890_load.html" id="b"> +<button onclick="submitIframeForm()" id="thebutton">Submit</button> +</form> + +</body> +</html> diff --git a/dom/html/test/bug277890_load.html b/dom/html/test/bug277890_load.html new file mode 100644 index 0000000000..c9be79b241 --- /dev/null +++ b/dom/html/test/bug277890_load.html @@ -0,0 +1,11 @@ +<html> +<head> +<title></title> +</head> + +<body onload="parent.submitted();"> + +<span id="foo"></span> + +</body> +</html> diff --git a/dom/html/test/bug340800_iframe.txt b/dom/html/test/bug340800_iframe.txt new file mode 100644 index 0000000000..369dfe7441 --- /dev/null +++ b/dom/html/test/bug340800_iframe.txt @@ -0,0 +1,4 @@ +Line 1. +Line 2. +Line 3. +Line 4. diff --git a/dom/html/test/bug369370-popup.png b/dom/html/test/bug369370-popup.png Binary files differnew file mode 100644 index 0000000000..9063d12648 --- /dev/null +++ b/dom/html/test/bug369370-popup.png diff --git a/dom/html/test/bug372098-link-target.html b/dom/html/test/bug372098-link-target.html new file mode 100644 index 0000000000..b22b8e020e --- /dev/null +++ b/dom/html/test/bug372098-link-target.html @@ -0,0 +1,7 @@ +<html> +<script type="text/javascript"> + +parent.callback(location.search.substr(1)); + +</script> +</html> diff --git a/dom/html/test/bug436200.html b/dom/html/test/bug436200.html new file mode 100644 index 0000000000..1ef7e73b5e --- /dev/null +++ b/dom/html/test/bug436200.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"/> + <title>Secure to Insecure Test</title> + </head> + <body> + <form id="test_form" action="http://example.org/browser/dom/html/test/bug436200.html"> + <button type="submit" id="submit_button">Submit</button> + </form> + </body> +</html> diff --git a/dom/html/test/bug441930_iframe.html b/dom/html/test/bug441930_iframe.html new file mode 100644 index 0000000000..532cd5c36a --- /dev/null +++ b/dom/html/test/bug441930_iframe.html @@ -0,0 +1,27 @@ +<html> +<body> + The content of this <code>textarea</code> should not disappear on page reload:<br /> + <textarea>This text should not disappear on page reload!</textarea> + <script> + var ta = document.getElementsByTagName("textarea").item(0); + if (!parent.reloaded) { + parent.reloaded = true; + ta.disabled = true; + location.reload(); + } else { + // Primary regression test: + parent.isnot(ta.value, "", + "Content of dynamically disabled textarea disappeared on page reload."); + + // Bonus regression test: changing the textarea's defaultValue after + // reloading should also update the textarea's value. + var newDefaultValue = "new default value"; + ta.defaultValue = newDefaultValue; + parent.is(ta.value, newDefaultValue, + "Changing the defaultValue attribute of a textarea fails to update its value attribute."); + + parent.SimpleTest.finish(); + } + </script> +</body> +</html> diff --git a/dom/html/test/bug445004-inner.html b/dom/html/test/bug445004-inner.html new file mode 100644 index 0000000000..b946520ea6 --- /dev/null +++ b/dom/html/test/bug445004-inner.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> + <head> + <base href="http://test1.example.org/tests/dom/html/test/bug445004-inner.html"> + <script src="bug445004-inner.js"></script> + </head> + <body> + <iframe name="w" id="w" width="100" height="100"></iframe> + <iframe name="x" id="x" width="100" height="100"></iframe> + <iframe name="y" id="y" width="100" height="100"></iframe> + <iframe name="z" id="z" width="100" height="100"></iframe> + <img src="test1.example.org.png"> + </body> +</html> diff --git a/dom/html/test/bug445004-inner.js b/dom/html/test/bug445004-inner.js new file mode 100644 index 0000000000..2d751da454 --- /dev/null +++ b/dom/html/test/bug445004-inner.js @@ -0,0 +1,27 @@ +document.domain = "example.org"; +function $(str) { + return document.getElementById(str); +} +function hookLoad(str) { + $(str).onload = function () { + window.parent.parent.postMessage("end", "*"); + }; + window.parent.parent.postMessage("start", "*"); +} +window.onload = function () { + hookLoad("w"); + $("w").contentWindow.location.href = "test1.example.org.png"; + hookLoad("x"); + var doc = $("x").contentDocument; + doc.write('<img src="test1.example.org.png">'); + doc.close(); +}; +function doIt() { + hookLoad("y"); + $("y").contentWindow.location.href = "example.org.png"; + hookLoad("z"); + var doc = $("z").contentDocument; + doc.write('<img src="example.org.png">'); + doc.close(); +} +window.addEventListener("message", doIt); diff --git a/dom/html/test/bug445004-outer-abs.html b/dom/html/test/bug445004-outer-abs.html new file mode 100644 index 0000000000..8a93ef2b73 --- /dev/null +++ b/dom/html/test/bug445004-outer-abs.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> + <head> + <base href="http://example.org/tests/dom/html/test/bug445004-outer.html"> + <script>document.domain = "example.org"</script> + </head> + <body> + <iframe width="500" height="200" src="http://test1.example.org/tests/dom/html/test/bug445004-inner.html" + onload="window.frames[0].doIt()"></iframe> + </body> +</html> diff --git a/dom/html/test/bug445004-outer-rel.html b/dom/html/test/bug445004-outer-rel.html new file mode 100644 index 0000000000..0967338899 --- /dev/null +++ b/dom/html/test/bug445004-outer-rel.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> + <head> + <base href="http://example.org/tests/dom/html/test/bug445004-outer.html"> + <script>document.domain = "example.org"</script> + </head> + <body> + <iframe width="500" height="200" src="bug445004-inner.html" + onload="window.frames[0].doIt()"></iframe> + </body> +</html> diff --git a/dom/html/test/bug445004-outer-write.html b/dom/html/test/bug445004-outer-write.html new file mode 100644 index 0000000000..be6e37b6d7 --- /dev/null +++ b/dom/html/test/bug445004-outer-write.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> + <head> + <base href="http://example.org/tests/dom/html/test/bug445004-outer.html"> + <script>document.domain = "example.org"</script> + </head> + <body> + <iframe width="500" height="200" src="javascript:"<!DOCTYPE html> <html> <script> function $(str) { return document.getElementById(str); } function hookLoad(str) { $(str).onload = function() { window.parent.parent.postMessage('end', '*'); }; window.parent.parent.postMessage('start', '*'); } window.onload = function() { hookLoad(\"w\"); $(\"w\").contentWindow.location.href = \"example.org.png\"; hookLoad(\"x\"); var doc = $(\"x\").contentDocument; doc.write('<img src=\"example.org.png\">'); doc.close(); }; function doIt() { hookLoad(\"y\"); $(\"y\").contentWindow.location.href = \"example.org.png\"; hookLoad(\"z\"); var doc = $(\"z\").contentDocument; doc.write('<img src=\"example.org.png\">'); doc.close(); } </script> <body> <iframe name=\"w\" id=\"w\" width=\"100\" height=\"100\"></iframe> <iframe name=\"x\" id=\"x\" width=\"100\" height=\"100\"></iframe> <iframe name=\"y\" id=\"y\" width=\"100\" height=\"100\"></iframe> <iframe name=\"z\" id=\"z\" width=\"100\" height=\"100\"></iframe><img src=\"example.org.png\"> </body> </html>" " + onload="window.frames[0].doIt();"></iframe> + </body> +</html> diff --git a/dom/html/test/bug446483-iframe.html b/dom/html/test/bug446483-iframe.html new file mode 100644 index 0000000000..fe5a6cf9f7 --- /dev/null +++ b/dom/html/test/bug446483-iframe.html @@ -0,0 +1,10 @@ +<script>
+function doe(){
+window.focus();
+window.getSelection().collapse(document.body, 0);
+}
+setTimeout(doe,50);
+
+setTimeout(function() {window.location.reload()}, 200);
+</script>
+<span contenteditable="true"></span>
diff --git a/dom/html/test/bug448564-echo.sjs b/dom/html/test/bug448564-echo.sjs new file mode 100644 index 0000000000..1eee116fd7 --- /dev/null +++ b/dom/html/test/bug448564-echo.sjs @@ -0,0 +1,6 @@ +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-cache", false); + response.setStatusLine(request.httpVersion, 200, "OK"); + + response.write(request.queryString); +} diff --git a/dom/html/test/bug448564-iframe-1.html b/dom/html/test/bug448564-iframe-1.html new file mode 100644 index 0000000000..4f3e79e5d2 --- /dev/null +++ b/dom/html/test/bug448564-iframe-1.html @@ -0,0 +1,16 @@ +<html> +<body> + + <table> + <form action="bug448564-echo.sjs" method="GET"> + <tr><td><input name="a" value="aval"></td></tr> + <input type="hidden" name="b" value="bval"> + <input name="c" value="cval"> + <tr><td><input name="d" value="dval" type="submit"></td></tr> + </form> + </table> + + <script src="bug448564-submit.js"></script> + +</body> +</html> diff --git a/dom/html/test/bug448564-iframe-2.html b/dom/html/test/bug448564-iframe-2.html new file mode 100644 index 0000000000..dba19b37e2 --- /dev/null +++ b/dom/html/test/bug448564-iframe-2.html @@ -0,0 +1,16 @@ +<html> +<body> + + <form action="bug448564-echo.sjs" method="GET"> + <table> + <tr><td><input name="a" value="aval"></td></tr> + <input type="hidden" name="b" value="bval"> + <input name="c" value="cval"> + <tr><td><input name="d" value="dval" type="submit"></td></tr> + </table> + </form> + + <script src="bug448564-submit.js"></script> + +</body> +</html> diff --git a/dom/html/test/bug448564-iframe-3.html b/dom/html/test/bug448564-iframe-3.html new file mode 100644 index 0000000000..64288ebb15 --- /dev/null +++ b/dom/html/test/bug448564-iframe-3.html @@ -0,0 +1,16 @@ +<html> +<body> + + <table> + <span><form action="bug448564-echo.sjs" method="GET"> + <tr><td><input name="a" value="aval"></td></tr> + <input type="hidden" name="b" value="bval"> + <input name="c" value="cval"> + <tr><td><input name="d" value="dval" type="submit"></td></tr> + </form></span> + </table> + + <script src="bug448564-submit.js"></script> + +</body> +</html> diff --git a/dom/html/test/bug448564-submit.js b/dom/html/test/bug448564-submit.js new file mode 100644 index 0000000000..a650487d65 --- /dev/null +++ b/dom/html/test/bug448564-submit.js @@ -0,0 +1,6 @@ +var inputs = document.getElementsByTagName("input"); +for (var input, i = 0; (input = inputs[i]); ++i) { + if ("submit" == input.type) { + input.click(); + } +} diff --git a/dom/html/test/bug499092.html b/dom/html/test/bug499092.html new file mode 100644 index 0000000000..0476fa4e76 --- /dev/null +++ b/dom/html/test/bug499092.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<script> +var title = document.createElementNS("http://www.w3.org/1999/xhtml", "aa:title"); +title.textContent = "HTML OK"; +document.documentElement.firstChild.appendChild(title); +</script> diff --git a/dom/html/test/bug499092.xml b/dom/html/test/bug499092.xml new file mode 100644 index 0000000000..eedd2c77b3 --- /dev/null +++ b/dom/html/test/bug499092.xml @@ -0,0 +1,4 @@ +<?xml version="1.0"?> +<doc xmlns:aa="http://www.w3.org/1999/xhtml"> +<aa:title>XML OK</aa:title> +</doc> diff --git a/dom/html/test/bug514856_iframe.html b/dom/html/test/bug514856_iframe.html new file mode 100644 index 0000000000..2abf9e91e2 --- /dev/null +++ b/dom/html/test/bug514856_iframe.html @@ -0,0 +1,21 @@ +<html> + <head> + <style> + html, body, a, img { + padding: 0px; + margin: 0px; + border: 0px; + } + img { + width: 100%; + height: 100%; + } + </style> + </head> + <body> + <a href="bug514856_iframe.html"> + <img ismap="ismap" + src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IAAAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1JREFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jqch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0vr4MkhoXe0rZigAAAABJRU5ErkJggg=="> + </a> + </body> +</html> diff --git a/dom/html/test/bug592641_img.jpg b/dom/html/test/bug592641_img.jpg Binary files differnew file mode 100644 index 0000000000..c9103b8b0e --- /dev/null +++ b/dom/html/test/bug592641_img.jpg diff --git a/dom/html/test/bug649134/file_bug649134-1.sjs b/dom/html/test/bug649134/file_bug649134-1.sjs new file mode 100644 index 0000000000..fed0a9d693 --- /dev/null +++ b/dom/html/test/bug649134/file_bug649134-1.sjs @@ -0,0 +1,12 @@ +function handleRequest(request, response) { + response.seizePower(); + var r = + "HTTP/1.1 200 OK\r\n" + + "Content-Type: text/html\r\n" + + 'Link: < \014>; rel="stylesheet"\r\n' + + "\r\n" + + "<!-- selector {} body {display:none;} --><body>PASS</body>\r\n"; + response.bodyOutputStream.write(r, r.length); + response.bodyOutputStream.flush(); + response.finish(); +} diff --git a/dom/html/test/bug649134/file_bug649134-2.sjs b/dom/html/test/bug649134/file_bug649134-2.sjs new file mode 100644 index 0000000000..3cbacf7184 --- /dev/null +++ b/dom/html/test/bug649134/file_bug649134-2.sjs @@ -0,0 +1,12 @@ +function handleRequest(request, response) { + response.seizePower(); + var r = + "HTTP/1.1 200 OK\r\n" + + "Content-Type: text/html\r\n" + + 'Link: < \014>; rel="stylesheet",\r\n' + + "\r\n" + + "<!-- selector {} body {display:none;} --><body>PASS</body>\r\n"; + response.bodyOutputStream.write(r, r.length); + response.bodyOutputStream.flush(); + response.finish(); +} diff --git a/dom/html/test/bug649134/index.html b/dom/html/test/bug649134/index.html new file mode 100644 index 0000000000..2f3973704e --- /dev/null +++ b/dom/html/test/bug649134/index.html @@ -0,0 +1,3 @@ +body { + display:none; +} diff --git a/dom/html/test/chrome.toml b/dom/html/test/chrome.toml new file mode 100644 index 0000000000..ac226b51c2 --- /dev/null +++ b/dom/html/test/chrome.toml @@ -0,0 +1,12 @@ +[DEFAULT] +support-files = [ + "file_anchor_ping.html", + "image.png", +] + +["test_anchor_ping.html"] +skip-if = ["os == 'android'"] + +["test_bug1414077.html"] + +["test_external_protocol_iframe.html"] diff --git a/dom/html/test/dialog/mochitest.toml b/dom/html/test/dialog/mochitest.toml new file mode 100644 index 0000000000..18f1f551a7 --- /dev/null +++ b/dom/html/test/dialog/mochitest.toml @@ -0,0 +1,4 @@ +[DEFAULT] + +["test_bug1648877_dialog_fullscreen_denied.html"] + diff --git a/dom/html/test/dialog/test_bug1648877_dialog_fullscreen_denied.html b/dom/html/test/dialog/test_bug1648877_dialog_fullscreen_denied.html new file mode 100644 index 0000000000..906c7dd53e --- /dev/null +++ b/dom/html/test/dialog/test_bug1648877_dialog_fullscreen_denied.html @@ -0,0 +1,52 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1648877 +--> +<head> + <title>Test for Bug 1648877</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=1648877">Requesting + fullscreen a dialog element should be denied</a> +<p id="display"></p> +<dialog> +</dialog> +<div style="width: 30px; height:30px" </div> + +<pre id="test"> +<script type="application/javascript"> +SimpleTest.waitForExplicitFinish(); + +function runTest() { + document.addEventListener("fullscreenchange", () => { + ok(false, "Should never receive " + + "a fullscreenchange event in the main window."); + }); + + document.addEventListener('fullscreenerror', (event) => { + ok(!document.fullscreenElement, + "Should not grant request if the element is dialog"); + SimpleTest.finish(); + }); + + const div = document.querySelector("div"); + + div.addEventListener("click", function() { + const dialog = document.querySelector("dialog"); + dialog.requestFullscreen(); + }); + + synthesizeMouseAtCenter(div, {}); +} + +SimpleTest.waitForFocus(runTest); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/dummy_page.html b/dom/html/test/dummy_page.html new file mode 100644 index 0000000000..fd238954c6 --- /dev/null +++ b/dom/html/test/dummy_page.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html lang="en"> +<head> +<title>Dummy test page</title> +<meta charset="utf-8"/> +</head> +<body> +<p>Dummy test page</p> +</body> +</html> diff --git a/dom/html/test/empty.html b/dom/html/test/empty.html new file mode 100644 index 0000000000..0dc101b533 --- /dev/null +++ b/dom/html/test/empty.html @@ -0,0 +1 @@ +<html><body></body></html> diff --git a/dom/html/test/file.webm b/dom/html/test/file.webm Binary files differnew file mode 100644 index 0000000000..7bc738b8b4 --- /dev/null +++ b/dom/html/test/file.webm diff --git a/dom/html/test/file_anchor_ping.html b/dom/html/test/file_anchor_ping.html new file mode 100644 index 0000000000..3b9717263f --- /dev/null +++ b/dom/html/test/file_anchor_ping.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>file_anchor_ping.html</title> + </head> + <body onload="document.body.firstElementChild.click()"> + <a href="/">click me</a> + <script> + document.body.firstElementChild.ping = window.location.search.slice(1); + </script> + </body> +</html> diff --git a/dom/html/test/file_broadcast_load.html b/dom/html/test/file_broadcast_load.html new file mode 100644 index 0000000000..ffae9c6536 --- /dev/null +++ b/dom/html/test/file_broadcast_load.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<h1>file_broadcast_load.html</h1> +<script> +let channel = new BroadcastChannel("test"); +channel.onmessage = function(e) { + console.log("file_broadcast_load.html got message:", e.data); + if (e.data == "close") { + window.close(); + } +}; + +addEventListener("load", function() { + console.log("file_broadcast_load.html loaded"); + channel.postMessage("load"); +}); +</script> diff --git a/dom/html/test/file_bug1108547-1.html b/dom/html/test/file_bug1108547-1.html new file mode 100644 index 0000000000..efc0eae494 --- /dev/null +++ b/dom/html/test/file_bug1108547-1.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<script> +document.cookie = "foo=bar"; +</script> diff --git a/dom/html/test/file_bug1108547-2.html b/dom/html/test/file_bug1108547-2.html new file mode 100644 index 0000000000..f5d8c5f964 --- /dev/null +++ b/dom/html/test/file_bug1108547-2.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<body onload="document.querySelector('form').submit();"> +<form action="javascript:opener.document.getElementById('result').textContent = document.cookie;" target="_blank" rel="opener"> +</form> +<div id="result">not tested yet</div> +</body> diff --git a/dom/html/test/file_bug1108547-3.html b/dom/html/test/file_bug1108547-3.html new file mode 100644 index 0000000000..e6a8ba3fa2 --- /dev/null +++ b/dom/html/test/file_bug1108547-3.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<body onload="document.querySelector('a').click();"> +<a href="javascript:opener.document.getElementById('result').textContent = document.cookie;" target="_blank" rel="opener">test</a> +<div id="result">not tested yet</div> +</body> diff --git a/dom/html/test/file_bug1166138_1x.png b/dom/html/test/file_bug1166138_1x.png Binary files differnew file mode 100644 index 0000000000..df421453c2 --- /dev/null +++ b/dom/html/test/file_bug1166138_1x.png diff --git a/dom/html/test/file_bug1166138_2x.png b/dom/html/test/file_bug1166138_2x.png Binary files differnew file mode 100644 index 0000000000..6f76d44387 --- /dev/null +++ b/dom/html/test/file_bug1166138_2x.png diff --git a/dom/html/test/file_bug1166138_def.png b/dom/html/test/file_bug1166138_def.png Binary files differnew file mode 100644 index 0000000000..144a2f0b93 --- /dev/null +++ b/dom/html/test/file_bug1166138_def.png diff --git a/dom/html/test/file_bug1260704.png b/dom/html/test/file_bug1260704.png Binary files differnew file mode 100644 index 0000000000..df421453c2 --- /dev/null +++ b/dom/html/test/file_bug1260704.png diff --git a/dom/html/test/file_bug209275_1.html b/dom/html/test/file_bug209275_1.html new file mode 100644 index 0000000000..3f7233876b --- /dev/null +++ b/dom/html/test/file_bug209275_1.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML> +<html> +<head> + <base href="http://example.org" /> +</head> +<body onload="load();"> +Initial state + +<script> +function load() { + // Nuke and rebuild the page. + document.removeChild(document.documentElement); + var html = document.createElement("html"); + var body = document.createElement("body"); + html.appendChild(body); + var link = document.createElement("a"); + link.href = "#"; + link.id = "link"; + body.appendChild(link); + document.appendChild(html); + + // Tell our parent to have a look at us. + parent.gGen.next(); +} +</script> + +</body> +</html> diff --git a/dom/html/test/file_bug209275_2.html b/dom/html/test/file_bug209275_2.html new file mode 100644 index 0000000000..36e9ff4672 --- /dev/null +++ b/dom/html/test/file_bug209275_2.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML> +<html> +<head> + <base href="http://example.com" /> +</head> +<body onload="load();"> +Page 2 initial state + +<script> +function load() { + // Nuke and rebuild the page. + document.removeChild(document.documentElement); + html = document.createElement("html"); + html.innerHTML = "<body><a href='/' id='link'>B</a></body>" + document.appendChild(html); + + // Tell our parent to have a look at us + parent.gGen.next(); +} +</script> + +</body> +</html> diff --git a/dom/html/test/file_bug209275_3.html b/dom/html/test/file_bug209275_3.html new file mode 100644 index 0000000000..2544115901 --- /dev/null +++ b/dom/html/test/file_bug209275_3.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML> +<html> +<head> + <base href="http://example.org" /> +</head> +<body onload="load();"> +Initial state + +<script> +function load() { + // Nuke and rebuild the page. If document.open() clears the <base> properly, + // our new <base> will take precedence and the test will pass. + document.open(); + document.write("<html><base href='http://mochi.test:8888' /><body>" + + "<a id='link' href='/'>A</a></body></html>"); + + // Tell our parent to have a look at us. + parent.gGen.next(); +} +</script> + +</body> +</html> diff --git a/dom/html/test/file_bug297761.html b/dom/html/test/file_bug297761.html new file mode 100644 index 0000000000..5e861a00fd --- /dev/null +++ b/dom/html/test/file_bug297761.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html> + <head> + <base href="http://www.mozilla.org/"> + </head> + <body> + <form action=""> + <input type='submit' formaction=""> + <button type='submit' formaction=""></button> + <input id='i' type='image' formaction=""> + </form> + </body> +</html> diff --git a/dom/html/test/file_bug417760.png b/dom/html/test/file_bug417760.png Binary files differnew file mode 100644 index 0000000000..743292dc6f --- /dev/null +++ b/dom/html/test/file_bug417760.png diff --git a/dom/html/test/file_bug871161-1.html b/dom/html/test/file_bug871161-1.html new file mode 100644 index 0000000000..16015f0c4e --- /dev/null +++ b/dom/html/test/file_bug871161-1.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset=windows-1251> +<title>Page with non-default charset</title> +<script> +function run() { + document.forms[0].submit(); +} +</script> +</head> +<body onload="run();"> +<form method=post action="http://example.org/tests/dom/html/test/file_bug871161-2.html"></form> +</body> +</html> + diff --git a/dom/html/test/file_bug871161-2.html b/dom/html/test/file_bug871161-2.html new file mode 100644 index 0000000000..18cf825b2d --- /dev/null +++ b/dom/html/test/file_bug871161-2.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> +<head> +<title>Page without declared charset</title> +<script> +function done() { + window.opener.postMessage(document.characterSet, "*"); +} +</script> +</head> +<body onload="done();"> +</body> +</html> + diff --git a/dom/html/test/file_bug893537.html b/dom/html/test/file_bug893537.html new file mode 100644 index 0000000000..1dcb454ff1 --- /dev/null +++ b/dom/html/test/file_bug893537.html @@ -0,0 +1,9 @@ +<!doctype html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=893537 +--> +<body> +<iframe id="iframe" src="data:text/html;charset=US-ASCII,Goodbye World" srcdoc="Hello World"></iframe> +</body> +</html> diff --git a/dom/html/test/file_cookiemanager.js b/dom/html/test/file_cookiemanager.js new file mode 100644 index 0000000000..08c9d72898 --- /dev/null +++ b/dom/html/test/file_cookiemanager.js @@ -0,0 +1,20 @@ +/* eslint-env mozilla/chrome-script */ + +addMessageListener("getCookieFromManager", ({ host, path }) => { + let cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager); + let values = []; + path = path.substring(0, path.lastIndexOf("/")); + for (let cookie of cm.cookies) { + if (!cookie) { + break; + } + if (host != cookie.host || path != cookie.path) { + continue; + } + values.push(cookie.name + "=" + cookie.value); + } + + sendAsyncMessage("getCookieFromManager:return", { + cookie: values.join("; "), + }); +}); diff --git a/dom/html/test/file_formSubmission_img.jpg b/dom/html/test/file_formSubmission_img.jpg Binary files differnew file mode 100644 index 0000000000..dcd99b9670 --- /dev/null +++ b/dom/html/test/file_formSubmission_img.jpg diff --git a/dom/html/test/file_formSubmission_text.txt b/dom/html/test/file_formSubmission_text.txt new file mode 100644 index 0000000000..a496efee84 --- /dev/null +++ b/dom/html/test/file_formSubmission_text.txt @@ -0,0 +1 @@ +This is a text file diff --git a/dom/html/test/file_iframe_sandbox_a_if1.html b/dom/html/test/file_iframe_sandbox_a_if1.html new file mode 100644 index 0000000000..b60d52ca00 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if1.html @@ -0,0 +1,13 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + I am sandboxed without any permissions + <iframe id="if_2a" src="file_iframe_sandbox_a_if2.html" height="10" width="10"></iframe> + <iframe id="if_2b" sandbox="allow-scripts" src="file_iframe_sandbox_a_if2.html" height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_a_if10.html b/dom/html/test/file_iframe_sandbox_a_if10.html new file mode 100644 index 0000000000..14306eb613 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if10.html @@ -0,0 +1,12 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<frameset> + <frame src="file_iframe_sandbox_a_if11.html"> + <frame src="file_iframe_sandbox_a_if16.html"> +</frameset> +</html> diff --git a/dom/html/test/file_iframe_sandbox_a_if11.html b/dom/html/test/file_iframe_sandbox_a_if11.html new file mode 100644 index 0000000000..8eee71df1d --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if11.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script> + function doStuff() { + try { + window.parent.parent.ok_wrapper(false, "a frame inside a sandboxed iframe should NOT be same origin with the iframe's parent"); + } + catch (e) { + window.parent.parent.postMessage({ok: true, desc: "a frame inside a sandboxed iframe is not same origin with the iframe's parent"}, "*"); + } + } + </script> +</head> +<frameset> + <frame onload='doStuff()' src="file_iframe_sandbox_a_if12.html"> +</frameset> +I'm a <frame> inside an iframe which is sandboxed with 'allow-scripts allow-forms' +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if12.html b/dom/html/test/file_iframe_sandbox_a_if12.html new file mode 100644 index 0000000000..d49d4e5625 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if12.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> +function doStuff() { + try { + window.parent.parent.parent.ok_wrapper(false, "a frame inside a frame inside a sandboxed iframe should NOT be same origin with the iframe's parent"); + } + catch (e) { + dump("caught some e if12\n"); + window.parent.parent.parent.postMessage({ok: true, desc: "a frame inside a frame inside a sandboxed iframe is not same origin with the iframe's parent"}, "*"); + } +} +</script> +<body onload='doStuff()'> + I'm a <frame> inside a <frame> inside an iframe which is sandboxed with 'allow-scripts allow-forms' +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if13.html b/dom/html/test/file_iframe_sandbox_a_if13.html new file mode 100644 index 0000000000..8737a7682e --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if13.html @@ -0,0 +1,13 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 886262</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body> + <object data="file_iframe_sandbox_a_if14.html"></object> +</body> + +</html> diff --git a/dom/html/test/file_iframe_sandbox_a_if14.html b/dom/html/test/file_iframe_sandbox_a_if14.html new file mode 100644 index 0000000000..b588f7ec50 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if14.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 886262</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + window.addEventListener("message", receiveMessage); + + function receiveMessage(event) + { + window.parent.parent.postMessage({ok: event.data.ok, desc: "objects containing " + event.data.desc}, "*"); + } + + function doStuff() { + try { + window.parent.parent.ok_wrapper(false, "an object inside a sandboxed iframe should NOT be same origin with the iframe's parent"); + } + catch (e) { + window.parent.parent.postMessage({ok: true, desc: "an object inside a sandboxed iframe is not same origin with the iframe's parent"}, "*"); + } + } +</script> + +<body onload='doStuff()'> +I'm a <object> inside an iframe which is sandboxed with 'allow-scripts allow-forms' + + <object data="file_iframe_sandbox_a_if15.html"></object> +</body> + +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if15.html b/dom/html/test/file_iframe_sandbox_a_if15.html new file mode 100644 index 0000000000..9c5a003d7c --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if15.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 886262</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> +function doStuff() { + try { + window.parent.parent.parent.ok_wrapper(false, "an object inside a frame or object inside a sandboxed iframe should NOT be same origin with the iframe's parent"); + } + catch (e) { + window.parent.parent.parent.postMessage({ok: true, desc: "an object inside a frame or object inside a sandboxed iframe is not same origin with the iframe's parent"}, "*"); + } + + // Check that sandboxed forms browsing context flag NOT set by attempting to submit a form. + document.getElementById('a_form').submit(); +} +</script> + +<body onload='doStuff()'> + I'm a <object> inside a <frame> or <object> inside an iframe which is sandboxed with 'allow-scripts allow-forms' + + <form method="get" action="file_iframe_sandbox_form_pass.html" id="a_form"> + First name: <input type="text" name="firstname"> + Last name: <input type="text" name="lastname"> + <input type="submit" id="a_button"> + </form> +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if16.html b/dom/html/test/file_iframe_sandbox_a_if16.html new file mode 100644 index 0000000000..141d3c2b06 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if16.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 886262</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + window.addEventListener("message", receiveMessage); + + function receiveMessage(event) + { + window.parent.parent.postMessage({ok: event.data.ok, desc: "objects containing " + event.data.desc}, "*"); + } +</script> + +<body> +I'm a <frame> inside an iframe which is sandboxed with 'allow-scripts allow-forms' + + <object data="file_iframe_sandbox_a_if15.html"></object> +</body> + +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if17.html b/dom/html/test/file_iframe_sandbox_a_if17.html new file mode 100644 index 0000000000..a736924bf5 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if17.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 886262</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + function doTest() { + var if_18_19 = document.getElementById('if_18_19'); + if_18_19.sandbox = "allow-scripts allow-same-origin"; + if_18_19.contentWindow.postMessage("go", "*"); + } +</script> + +<body onload="doTest()"> + I am sandboxed but with "allow-scripts". I change the sandbox flags on if_18_19 to + "allow-scripts allow-same-origin" then get it to re-navigate itself to + file_iframe_sandbox_a_if18.html, which attemps to call a function in my parent. + This should fail since my sandbox flags should be copied to it when the sandbox + flags are changed. + + <iframe sandbox="allow-scripts" id="if_18_19" src="file_iframe_sandbox_a_if19.html" height="10" width="10"></iframe> +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if18.html b/dom/html/test/file_iframe_sandbox_a_if18.html new file mode 100644 index 0000000000..bbe90970d4 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if18.html @@ -0,0 +1,26 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 886262</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + function doTest() { + try { + window.parent.parent.ok_wrapper(false, "an iframe in an iframe SHOULD copy its parent's sandbox flags when its sandbox flags are changed"); + } + catch (e) { + window.parent.parent.postMessage({ok: true, desc: "an iframe in an iframe copies its parent's sandbox flags when its sandbox flags are changed"}, "*"); + } + } +</script> + +<body onload="doTest()"> + I'm an iframe whose sandbox flags have been changed to include allow-same-origin. + I should not be able to call a function in my parent's parent because my parent's + iframe does not have allow-same-origin set. +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if19.html b/dom/html/test/file_iframe_sandbox_a_if19.html new file mode 100644 index 0000000000..e4d3d68887 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if19.html @@ -0,0 +1,21 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 886262</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> + +<script> + window.addEventListener("message", function(e){ + window.open("file_iframe_sandbox_a_if18.html", "_self"); + }); +</script> + +<body> + I'm just here to navigate to file_iframe_sandbox_a_if18.html after my owning + iframe has had allow-same-origin added. +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if2.html b/dom/html/test/file_iframe_sandbox_a_if2.html new file mode 100644 index 0000000000..72bde69e41 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if2.html @@ -0,0 +1,21 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="text/javascript"> +function doStuff() { + // should NOT be able to execute scripts + window.parent.parent.postMessage({ok: false, desc: "a document within an iframe sandboxed with sandbox='' should NOT be able to execute scripts"}, "*"); +} +</script> + +<body onLoad="doStuff()"> + I am NOT sandboxed or am sandboxed with "allow-scripts" but am contained within an iframe sandboxed with sandbox = "" + or am sandboxed with sandbox='' inside an iframe sandboxed with "allow-scripts" +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if3.html b/dom/html/test/file_iframe_sandbox_a_if3.html new file mode 100644 index 0000000000..899c2f1093 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if3.html @@ -0,0 +1,24 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> + +<script type="text/javascript"> + function ok_wrapper(condition, msg) { + window.parent.ok_wrapper(condition, msg); + } +</script> + +<body> + I am sandboxed but with "allow-scripts" + + <iframe id='if_4' src='file_iframe_sandbox_a_if4.html' height="10" width="10"></iframe> + <iframe id='if_7' src='file_iframe_sandbox_a_if7.html' height="10" width="10"></iframe> + <iframe id='if_2' sandbox='' src='file_iframe_sandbox_a_if2.html' height="10" width="10"></iframe> +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if4.html b/dom/html/test/file_iframe_sandbox_a_if4.html new file mode 100644 index 0000000000..a216fb572a --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if4.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> + +<script type="text/javascript"> +function doStuff() { + try { + window.parent.ok_wrapper(false, "a document contained within a sandboxed document without 'allow-same-origin' should NOT be same domain with its parent"); + } catch(e) { + window.parent.parent.postMessage({type: "ok", ok: true, desc: "a document contained within a sandboxed document without 'allow-same-origin' should NOT be same domain with its parent"}, "*"); + } + + try { + window.parent.parent.ok_wrapper(false, "a document contained within a sandboxed document without 'allow-same-origin' should NOT be same domain with the top level"); + } catch(e) { + window.parent.parent.postMessage({type: "ok", ok: true, desc: "a document contained within a sandboxed document without 'allow-same-origin' should NOT be same domain with the top level"}, "*"); + } +} +</script> + +<body onLoad="doStuff()"> + I am not sandboxed but contained within a sandboxed document with 'allow-scripts' +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if5.html b/dom/html/test/file_iframe_sandbox_a_if5.html new file mode 100644 index 0000000000..c1081c5039 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if5.html @@ -0,0 +1,22 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> + +<script type="text/javascript"> + function ok_wrapper(result, desc) { + window.parent.ok_wrapper(result, desc); + } +</script> + +<body> + I am sandboxed but with "allow-scripts allow-same-origin" + + <iframe sandbox='allow-scripts allow-same-origin' id='if_6' src='file_iframe_sandbox_a_if6.html' height="10" width="10"></iframe> +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if6.html b/dom/html/test/file_iframe_sandbox_a_if6.html new file mode 100644 index 0000000000..62a7114316 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if6.html @@ -0,0 +1,21 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> + +<script type="text/javascript"> +function doStuff() { + window.parent.ok_wrapper(true, "a document sandboxed with 'allow-same-origin' and contained within a sandboxed document with 'allow-same-origin' should be same domain with its parent"); + window.parent.parent.ok_wrapper(true, "a document sandboxed with 'allow-same-origin' contained within a sandboxed document with 'allow-same-origin' should be same domain with the top level"); +} +</script> + +<body onLoad="doStuff()"> + I am sandboxed with 'allow-scripts allow-same-origin' and contained within a sandboxed document with 'allow-scripts allow-same-origin' +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if7.html b/dom/html/test/file_iframe_sandbox_a_if7.html new file mode 100644 index 0000000000..6480eebdba --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if7.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="text/javascript"> +function doStuff() { + // should be able to execute scripts + window.parent.parent.postMessage({ok: true, desc: "a document contained within an iframe contained within an iframe sandboxed with 'allow-scripts' should be able to execute scripts"}, "*"); +} +</script> + +<body onLoad="doStuff()"> + I am NOT sandboxed but am contained within an iframe contained within an iframe sandboxed with sandbox = "allow-scripts" +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if8.html b/dom/html/test/file_iframe_sandbox_a_if8.html new file mode 100644 index 0000000000..87748f542a --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if8.html @@ -0,0 +1,26 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script> +function doSubload() { + var if_9 = document.getElementById('if_9'); + if_9.src = 'file_iframe_sandbox_a_if9.html'; +} + +window.doSubload = doSubload; + +</script> +<body> + I am sandboxed but with "allow-scripts allow-same-origin". After my initial load, "allow-same-origin" is removed + and then I load file_iframe_sandbox_a_if9.html, which attemps to call a function in window.top. This should + succeed since the new sandbox flags shouldn't have taken affect on me until I'm reloaded. + + <iframe id='if_9' src='about:blank' height="10" width="10"></iframe> +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_a_if9.html b/dom/html/test/file_iframe_sandbox_a_if9.html new file mode 100644 index 0000000000..da2bcf1fa3 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_a_if9.html @@ -0,0 +1,18 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> +function doStuff() { + window.parent.parent.ok_wrapper(true, "a subloaded document should inherit the flags of the document, not of the docshell/sandbox attribute"); +} +</script> +<body onload='doStuff()'> + I'm a subloaded document of file_iframe_sandbox_a_if8.html. I should be able to call a function in window.top + because I should be same-origin with it. +</body> +</html> + diff --git a/dom/html/test/file_iframe_sandbox_b_if1.html b/dom/html/test/file_iframe_sandbox_b_if1.html new file mode 100644 index 0000000000..a65cbec6b9 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_b_if1.html @@ -0,0 +1,11 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + I am sandboxed without any permissions +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_b_if2.html b/dom/html/test/file_iframe_sandbox_b_if2.html new file mode 100644 index 0000000000..08e7453574 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_b_if2.html @@ -0,0 +1,49 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> + function ok(condition, msg) { + window.parent.ok_wrapper(condition, msg); + } + + function testXHR() { + var xhr = new XMLHttpRequest(); + + xhr.open("GET", "file_iframe_sandbox_b_if1.html"); + + xhr.onreadystatechange = function (oEvent) { + var result = false; + if (xhr.readyState == 4) { + if (xhr.status == 200) { + result = true; + } + ok(result, "XHR should work normally in an iframe sandboxed with 'allow-same-origin'"); + } + } + + xhr.send(null); + } + + function doStuff() { + ok(true, "documents sandboxed with 'allow-same-origin' should be able to access their parent"); + + // should be able to access document.cookie since we have 'allow-same-origin' + ok(document.cookie == "", "a document sandboxed with allow-same-origin should be able to access document.cookie"); + + // should be able to access localStorage since we have 'allow-same-origin' + ok(window.localStorage, "a document sandboxed with allow-same-origin should be able to access localStorage"); + + // should be able to access sessionStorage since we have 'allow-same-origin' + ok(window.sessionStorage, "a document sandboxed with allow-same-origin should be able to access sessionStorage"); + + testXHR(); + } +</script> +<body onLoad="doStuff()"> + I am sandboxed but with "allow-same-origin" and "allow-scripts" +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_b_if3.html b/dom/html/test/file_iframe_sandbox_b_if3.html new file mode 100644 index 0000000000..350e2ac472 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_b_if3.html @@ -0,0 +1,92 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> + function ok(result, message) { + window.parent.postMessage({ok: result, desc: message}, "*"); + } + + function testXHR() { + // Standard URL should be blocked as we have a unique origin. + var xhr = new XMLHttpRequest(); + xhr.open("GET", "file_iframe_sandbox_b_if1.html"); + xhr.onreadystatechange = function (oEvent) { + var result = false; + if (xhr.readyState == 4) { + if (xhr.status == 0) { + result = true; + } + ok(result, "XHR should be blocked in an iframe sandboxed WITHOUT 'allow-same-origin'"); + } + } + xhr.send(null); + + // Blob URL should work as it will have our unique origin. + var blobXhr = new XMLHttpRequest(); + var blobUrl = URL.createObjectURL(new Blob(["wibble"], {type: "text/plain"})); + blobXhr.open("GET", blobUrl); + blobXhr.onreadystatechange = function () { + if (this.readyState == 4) { + ok(this.status == 200 && this.response == "wibble", "XHR for a blob URL created in this document should NOT be blocked in an iframe sandboxed WITHOUT 'allow-same-origin'"); + } + } + try { + blobXhr.send(); + } catch(e) { + ok(false, "failed to send XHR for blob URL: error: " + e); + } + + // Data URL should work as it inherits the loader's origin. + var dataXhr = new XMLHttpRequest(); + dataXhr.open("GET", "data:text/html,wibble"); + dataXhr.onreadystatechange = function () { + if (this.readyState == 4) { + ok(this.status == 200 && this.response == "wibble", "XHR for a data URL should NOT be blocked in an iframe sandboxed WITHOUT 'allow-same-origin'"); + } + } + try { + dataXhr.send(); + } catch(e) { + ok(false, "failed to send XHR for data URL: error: " + e); + } + } + + function doStuff() { + try { + window.parent.ok(false, "documents sandboxed without 'allow-same-origin' should NOT be able to access their parent"); + } catch (error) { + ok(true, "documents sandboxed without 'allow-same-origin' should NOT be able to access their parent"); + } + + // should NOT be able to access document.cookie + try { + var foo = document.cookie; + } catch(error) { + ok(true, "a document sandboxed without allow-same-origin should NOT be able to access document.cookie"); + } + + // should NOT be able to access localStorage + try { + var foo = window.localStorage; + } catch(error) { + ok(true, "a document sandboxed without allow-same-origin should NOT be able to access localStorage"); + } + + // should NOT be able to access sessionStorage + try { + var foo = window.sessionStorage; + } catch(error) { + ok(true, "a document sandboxed without allow-same-origin should NOT be able to access sessionStorage"); + } + + testXHR(); + } +</script> +<body onLoad="doStuff()"> + I am sandboxed but with "allow-scripts" +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_c_if1.html b/dom/html/test/file_iframe_sandbox_c_if1.html new file mode 100644 index 0000000000..c2fbf136ae --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_c_if1.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="text/javascript"> + function ok(result, desc) { + window.parent.postMessage({ok: result, desc}, "*"); + } + + function doStuff() { + ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts"); + + document.getElementById('a_form').submit(); + + // trigger the javascript: url test + sendMouseEvent({type:'click'}, 'a_link'); + } +</script> +<script src='file_iframe_sandbox_pass.js'></script> +<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'> + I am sandboxed but with "allow-scripts" + + <form method="get" action="file_iframe_sandbox_form_fail.html" id="a_form"> + First name: <input type="text" name="firstname"> + Last name: <input type="text" name="lastname"> + <input type="submit" onclick="doSubmit()" id="a_button"> + </form> + + <a href = 'javascript:ok(true, "documents sandboxed with allow-scripts should be able to run script from javascript: URLs");' id='a_link'>click me</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_c_if2.html b/dom/html/test/file_iframe_sandbox_c_if2.html new file mode 100644 index 0000000000..1ea8a90ca3 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_c_if2.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + +</head> +<script type="text/javascript"> + function ok(result, desc) { + window.parent.postMessage({ok: result, desc}, "*"); + } + + function doStuff() { + ok(false, "documents sandboxed without allow-scripts should NOT be able to run inline scripts"); + } +</script> +<script src='file_iframe_sandbox_fail.js'></script> +<body onLoad='window.parent.postmessage({ok: false, desc: "documents sandboxed without allow-scripts should NOT be able to run script from event handlers"}, "*");doStuff();'> + I am sandboxed with no permissions + <img src="about:blank" onerror='ok(false, "documents sandboxed without allow-scripts should NOT be able to run script from event handlers");')> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_c_if3.html b/dom/html/test/file_iframe_sandbox_c_if3.html new file mode 100644 index 0000000000..fdf98d93d4 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_c_if3.html @@ -0,0 +1,26 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + +</head> +<script type="text/javascript"> + function doStuff() { + dump("*** c_if3 has loaded\n"); + // try and submit the form - this should succeed + document.getElementById('a_form').submit(); + } +</script> +<body onLoad="doStuff()"> + I am sandboxed but with "allow-scripts allow-forms" + + <form method="get" action="file_iframe_sandbox_form_pass.html" id="a_form"> + First name: <input type="text" name="firstname"> + Last name: <input type="text" name="lastname"> + <input type="submit" onclick="doSubmit()" id="a_button"> + </form> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_c_if4.html b/dom/html/test/file_iframe_sandbox_c_if4.html new file mode 100644 index 0000000000..ee2438f28a --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_c_if4.html @@ -0,0 +1,36 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="text/javascript"> + function ok(result, desc) { + window.parent.ok_wrapper(result, desc); + } + + function doStuff() { + // try to open a new window via target="_blank", target="BC341604", and window.open() + // the window we try to open closes itself once it opens + sendMouseEvent({type:'click'}, 'target_blank'); + sendMouseEvent({type:'click'}, 'target_BC341604'); + + var threw = false; + try { + window.open("about:blank"); + } catch (error) { + threw = true; + } + + ok(threw, "window.open threw a JS exception and was not allowed"); + } +</script> +<body onLoad="doStuff()"> + I am sandboxed but with "allow-scripts allow-same-origin" + + <a href="file_iframe_sandbox_open_window_fail.html" target="_blank" id="target_blank" rel="opener">open window</a> + <a href="file_iframe_sandbox_open_window_fail.html" target="BC341604" id="target_BC341604">open window</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_c_if5.html b/dom/html/test/file_iframe_sandbox_c_if5.html new file mode 100644 index 0000000000..bd368de425 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_c_if5.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + +</head> +<script type="text/javascript"> + function ok(result, desc) { + window.parent.ok_wrapper(result, desc); + } +</script> +<body onLoad="doStuff()"> + I am sandboxed but with "allow-same-origin" + + <a href = 'javascript:ok(false, "documents sandboxed without allow-scripts should not be able to run script with javascript: URLs");' id='a_link'>click me</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_c_if6.html b/dom/html/test/file_iframe_sandbox_c_if6.html new file mode 100644 index 0000000000..e5ecf3051e --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_c_if6.html @@ -0,0 +1,24 @@ +<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 341604</title>
+ <script src="/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+</head>
+<script type="text/javascript">
+ function ok(result, desc) {
+ window.parent.ok_wrapper(result, desc);
+ window.parent.postMessage({ok: result, desc}, "*");
+ }
+
+ function doStuff() {
+ ok(true, "a document sandboxed with allow-same-origin and allow-scripts should be same origin with its parent and able to run scripts " +
+ "regardless of what kind of whitespace was used in its sandbox attribute");
+ }
+</script>
+<body onLoad="doStuff()">
+ I am sandboxed but with "allow-same-origin" and "allow-scripts"
+</body>
+</html>
diff --git a/dom/html/test/file_iframe_sandbox_c_if7.html b/dom/html/test/file_iframe_sandbox_c_if7.html new file mode 100644 index 0000000000..b9a55def6f --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_c_if7.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 341604</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<script type="text/javascript">
+ function ok(result, desc) {
+ window.parent.postMessage({ok: result, desc}, "*");
+ }
+
+ function doStuff() {
+ try {
+ var thing = indexedDB.open("sandbox");
+ ok(false, "documents sandboxed without allow-same-origin should NOT be able to access indexedDB");
+ }
+
+ catch(e) {
+ ok(true, "documents sandboxed without allow-same-origin should NOT be able to access indexedDB");
+ }
+ }
+</script>
+<body onLoad='doStuff();'>
+ I am sandboxed but with "allow-scripts"
+</body>
+</html>
diff --git a/dom/html/test/file_iframe_sandbox_c_if8.html b/dom/html/test/file_iframe_sandbox_c_if8.html new file mode 100644 index 0000000000..d8b8948466 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_c_if8.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 341604</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<script type="text/javascript">
+ function ok(result, desc) {
+ window.parent.postMessage({ok: result, desc}, "*");
+ }
+
+ function doStuff() {
+ var thing = indexedDB.open("sandbox");
+
+ thing.onerror = function(event) {
+ ok(false, "documents sandboxed with allow-same-origin SHOULD be able to access indexedDB");
+ };
+ thing.onsuccess = function(event) {
+ ok(true, "documents sandboxed with allow-same-origin SHOULD be able to access indexedDB");
+ };
+ }
+</script>
+<body onLoad='doStuff();'>
+ I am sandboxed but with "allow-scripts allow-same-origin"
+</body>
+</html>
diff --git a/dom/html/test/file_iframe_sandbox_c_if9.html b/dom/html/test/file_iframe_sandbox_c_if9.html new file mode 100644 index 0000000000..0c88a677cb --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_c_if9.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 671389</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + I am + <ul> + <li>sandboxed but with "allow-forms", "allow-pointer-lock", "allow-popups", "allow-same-origin", "allow-scripts", and "allow-top-navigation", </li> + <li>sandboxed but with "allow-same-origin", "allow-scripts", </li> + <li>sandboxed, or </li> + <li>not sandboxed.</li> + </ul> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_close.html b/dom/html/test/file_iframe_sandbox_close.html new file mode 100644 index 0000000000..3b87534978 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_close.html @@ -0,0 +1,3 @@ +<script> + self.close(); +</script> diff --git a/dom/html/test/file_iframe_sandbox_d_if1.html b/dom/html/test/file_iframe_sandbox_d_if1.html new file mode 100644 index 0000000000..744594e813 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if1.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script type="application/javascript"> +function doTest() { + sendMouseEvent({type:'click'}, 'anchor'); +} +</script> +<body onload="doTest()"> + I am sandboxed with 'allow-scripts' + + <a href="file_iframe_sandbox_navigation_pass.html?Test 1:%20" target="_self" id='anchor'> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if10.html b/dom/html/test/file_iframe_sandbox_d_if10.html new file mode 100644 index 0000000000..41fb46b586 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if10.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script type="application/javascript"> +function doTest() { + window.parent.postMessage({type: "if_10"}, "*"); +} +</script> +<body onload='doTest()'> + I am sandboxed with 'allow-scripts' +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if11.html b/dom/html/test/file_iframe_sandbox_d_if11.html new file mode 100644 index 0000000000..63880587f5 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if11.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script type="application/javascript"> + +function navigateAway() { + document.getElementById("anchor").click(); +} + +function doTest() { + try { + // this should fail the first time, but work the second + window.parent.ok_wrapper(true, "a document that was loaded, navigated to another document, had 'allow-same-origin' added and then was" + + " navigated back should be same-origin with its parent"); + } catch (e) { + navigateAway(); + } +} + +</script> +<body onload='doTest()'> + I am sandboxed with 'allow-scripts' + <a href='file_iframe_sandbox_d_if12.html' id='anchor'>CLICK ME</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if12.html b/dom/html/test/file_iframe_sandbox_d_if12.html new file mode 100644 index 0000000000..0d7936512e --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if12.html @@ -0,0 +1,16 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="application/javascript"> +function doTest() { + window.parent.postMessage({test:'if_11'}, "*"); +} +</script> +<body onload='doTest()'> + I am sandboxed with 'allow-scripts' +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if13.html b/dom/html/test/file_iframe_sandbox_d_if13.html new file mode 100644 index 0000000000..aad330c33c --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if13.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script type="application/javascript"> +window.addEventListener("message", receiveMessage); + +function receiveMessage(event) { + // this message is part of if_11's test + if (event.data.test == 'if_11') { + doIf11TestPart2(); + } +} + +function ok_wrapper(result, msg) { + window.opener.postMessage({ok: result, desc: msg}, "*"); + window.close(); +} + +function doIf11TestPart2() { + var if_11 = document.getElementById('if_11'); + if_11.sandbox = 'allow-scripts allow-same-origin'; + // window.history is no longer cross-origin accessible in gecko. + SpecialPowers.wrap(if_11).contentWindow.history.back(); +} +</script> +<body> + <iframe sandbox='allow-scripts' id="if_11" src="file_iframe_sandbox_d_if11.html" height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if14.html b/dom/html/test/file_iframe_sandbox_d_if14.html new file mode 100644 index 0000000000..237a9d704f --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if14.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Tests for Bug 838692</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="text/javascript"> + var test20Context = "Test 20: Navigate another window (not opened by us): "; + + function doTest() { + // Try to navigate auxiliary browsing context (window) not opened by us. + // We should not be able to do this as we are sandboxed. + sendMouseEvent({type:'click'}, 'navigate_window'); + window.parent.postMessage({type: "attempted"}, "*"); + + // Try to navigate auxiliary browsing context (window) not opened by us, using window.open(). + // We should not be able to do this as we are sandboxed. + try { + window.open("file_iframe_sandbox_window_navigation_fail.html?" + escape(test20Context), "window_to_navigate2"); + window.parent.postMessage({type: "attempted"}, "*"); + } catch(error) { + window.parent.postMessage({ok: true, desc: test20Context + "as expected, error thrown during window.open(..., \"window_to_navigate2\")"}, "*"); + } + } +</script> + +<body onload="doTest()"> + I am sandboxed but with "allow-scripts allow-same-origin allow-top-navigation". + + <a href="file_iframe_sandbox_window_navigation_fail.html?Test 14: Navigate another window (not opened by us):%20" target="window_to_navigate" id="navigate_window">navigate window</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if15.html b/dom/html/test/file_iframe_sandbox_d_if15.html new file mode 100644 index 0000000000..6c969c8fe1 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if15.html @@ -0,0 +1,14 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body> + I am an unsandboxed iframe. + + <iframe sandbox="allow-same-origin allow-scripts" id="if_16" src="file_iframe_sandbox_d_if16.html" height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if16.html b/dom/html/test/file_iframe_sandbox_d_if16.html new file mode 100644 index 0000000000..e50dd97ea0 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if16.html @@ -0,0 +1,22 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> + +<script type="application/javascript"> +function doTest() { + window.parent.parent.postMessage({type: "attempted"}, "*"); + sendMouseEvent({type:'click'}, 'anchor'); +} +</script> + +<body onload="doTest()"> + I am sandboxed with 'allow-same-origin allow-scripts' + + <a href="file_iframe_sandbox_navigation_fail.html?Test 16: Navigate parent/ancestor by name:%20" target='if_parent' id='anchor'> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if17.html b/dom/html/test/file_iframe_sandbox_d_if17.html new file mode 100644 index 0000000000..047a08137d --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if17.html @@ -0,0 +1,24 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="application/javascript"> + var testContext = "Test 17: navigate _self with window.open(): "; + + function doTest() { + try { + window.open("file_iframe_sandbox_navigation_pass.html?" + escape(testContext), "_self"); + } catch(error) { + window.parent.postMessage({ok: false, desc: testContext + "error thrown during window.open(..., \"_self\")"}, "*"); + } + } +</script> + +<body onload="doTest()"> + I am sandboxed with 'allow-scripts' +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if18.html b/dom/html/test/file_iframe_sandbox_d_if18.html new file mode 100644 index 0000000000..fdcb4198f4 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if18.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> + +<script type="application/javascript"> + window.addEventListener("message", receiveMessage); + + function receiveMessage(event) { + window.parent.postMessage(event.data, "*"); + } + + var testContext = "Test 18: navigate child with window.open(): "; + + function doTest() { + try { + window.open("file_iframe_sandbox_navigation_pass.html?" + escape(testContext), "foo"); + } catch(error) { + window.parent.postMessage({ok: false, desc: testContext + " error thrown during window.open(..., \"foo\")"}, "*"); + } + } +</script> + +<body onload="doTest()"> + I am sandboxed with 'allow-scripts' + + <iframe name="foo" height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if19.html b/dom/html/test/file_iframe_sandbox_d_if19.html new file mode 100644 index 0000000000..d766d26492 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if19.html @@ -0,0 +1,13 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + I am sandboxed with 'allow-scripts' + + <iframe sandbox="allow-scripts" id="if_20" src="file_iframe_sandbox_d_if20.html" height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if2.html b/dom/html/test/file_iframe_sandbox_d_if2.html new file mode 100644 index 0000000000..b45cb975ca --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if2.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script type="application/javascript"> +// needed to forward the message to the main test page +window.addEventListener("message", receiveMessage); + +function receiveMessage(event) { + window.parent.postMessage(event.data, "*"); +} + +function doTest() { + sendMouseEvent({type:'click'}, 'anchor'); +} +</script> +<body onload="doTest()"> + I am sandboxed with 'allow-scripts' + + <iframe name="foo" src="file_iframe_sandbox_navigation_start.html" height="10" width="10"></iframe> + + <a href="file_iframe_sandbox_navigation_pass.html?Test 2:%20" target='foo' id='anchor'> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if20.html b/dom/html/test/file_iframe_sandbox_d_if20.html new file mode 100644 index 0000000000..005c4bc823 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if20.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="application/javascript"> + var testContext = "Test 19: navigate _parent with window.open(): "; + + function doTest() { + try { + window.open("file_iframe_sandbox_navigation_fail.html?" + escape(testContext), "_parent"); + window.parent.parent.postMessage({type: "attempted"}, "*"); + } catch(error) { + window.parent.parent.postMessage({ok: true, desc: testContext + "as expected, error thrown during window.open(..., \"_parent\")"}, "*"); + } + } +</script> + +<body onload="doTest()"> + I am sandboxed with 'allow-scripts' +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if21.html b/dom/html/test/file_iframe_sandbox_d_if21.html new file mode 100644 index 0000000000..6d0ab232e0 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if21.html @@ -0,0 +1,14 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body> + I am an unsandboxed iframe. + + <iframe sandbox="allow-same-origin allow-scripts" id="if_22" src="file_iframe_sandbox_d_if22.html" height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if22.html b/dom/html/test/file_iframe_sandbox_d_if22.html new file mode 100644 index 0000000000..bd27157926 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if22.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="application/javascript"> + var testContext = "Test 21: navigate parent by name with window.open(): "; + + function doTest() { + try { + window.open("file_iframe_sandbox_navigation_fail.html?" + escape(testContext), "if_parent2"); + window.parent.parent.postMessage({type: "attempted"}, "*"); + } catch(error) { + window.parent.parent.postMessage({ok: true, desc: testContext + "as expected, error thrown during window.open(..., \"if_parent2\")"}, "*"); + } + } +</script> + +<body onload="doTest()"> + I am sandboxed with 'allow-same-origin allow-scripts' +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if23.html b/dom/html/test/file_iframe_sandbox_d_if23.html new file mode 100644 index 0000000000..e755511e37 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if23.html @@ -0,0 +1,61 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="application/javascript"> + var test27Context = "Test 27: navigate opened window by name with anchor: "; + var test28Context = "Test 28: navigate opened window by name with window.open(): "; + + var windowsToClose = new Array(); + + function closeWindows() { + for (var i = 0; i < windowsToClose.length; i++) { + windowsToClose[i].close(); + } + } + + // Add message listener to forward messages on to parent + window.addEventListener("message", receiveMessage); + + function receiveMessage(event) { + switch (event.data.type) { + case "closeWindows": + closeWindows(); + break; + default: + window.parent.postMessage(event.data, "*"); + } + } + + function doTest() { + try { + windowsToClose.push(window.open("about:blank", "test27window")); + var test27Anchor = document.getElementById("test27Anchor"); + test27Anchor.href = "file_iframe_sandbox_window_navigation_pass.html?" + escape(test27Context); + sendMouseEvent({type:"click"}, "test27Anchor"); + window.parent.postMessage({type: "attempted"}, "*"); + } catch(error) { + window.parent.postMessage({ok: false, desc: test27Context + "error thrown during window.open(): " + error}, "*"); + } + + try { + windowsToClose.push(window.open("about:blank", "test28window")); + window.open("file_iframe_sandbox_window_navigation_pass.html?" + escape(test28Context), "test28window"); + window.parent.postMessage({type: "attempted"}, "*"); + } catch(error) { + window.parent.postMessage({ok: false, desc: test28Context + "error thrown during window.open(): " + error}, "*"); + } + } +</script> + +<body onload="doTest()"> + I am sandboxed with 'allow-scripts allow-popups' + + <a id="test27Anchor" target="test27window">Test 27 anchor</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if3.html b/dom/html/test/file_iframe_sandbox_d_if3.html new file mode 100644 index 0000000000..cd2d53bce9 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if3.html @@ -0,0 +1,13 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + I am sandboxed with 'allow-scripts' + + <iframe sandbox="allow-scripts" id="if_4" src="file_iframe_sandbox_d_if4.html" height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if4.html b/dom/html/test/file_iframe_sandbox_d_if4.html new file mode 100644 index 0000000000..c11a414551 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if4.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script type="application/javascript"> +function doTest() { + window.parent.parent.postMessage({type: "attempted"}, "*"); + sendMouseEvent({type:'click'}, 'anchor'); +} +</script> +<body onload="doTest()"> + I am sandboxed with 'allow-scripts' + + <a href="file_iframe_sandbox_navigation_fail.html" target='_parent' id='anchor'> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if5.html b/dom/html/test/file_iframe_sandbox_d_if5.html new file mode 100644 index 0000000000..d8fe4289af --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if5.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script type="application/javascript"> +function doTest() { + window.parent.postMessage({type: "attempted"}, "*"); + sendMouseEvent({type:'click'}, 'anchor'); +} +</script> +<body onload="doTest()"> + I am sandboxed with 'allow-scripts allow-same-origin' + + <a href="file_iframe_sandbox_navigation_fail.html?Test 4: Navigate sibling iframe by name:%20" target='if_sibling' id='anchor'> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if6.html b/dom/html/test/file_iframe_sandbox_d_if6.html new file mode 100644 index 0000000000..9bb48cbb20 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if6.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script type="application/javascript"> +function doTest() { + sendMouseEvent({type:'click'}, 'anchor'); +} +</script> +<body onload="doTest()"> + I am sandboxed with 'allow-scripts' + + <a href="file_iframe_sandbox_d_if7.html" target='_self' id='anchor'> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if7.html b/dom/html/test/file_iframe_sandbox_d_if7.html new file mode 100644 index 0000000000..5023ee0294 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if7.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="application/javascript"> +function doTest() { + try { + window.parent.ok_wrapper(false, "a sandboxed document when navigated should still NOT be same-origin with its parent"); + } catch(error) { + window.parent.postMessage({ok: true, desc: "sandboxed document's attempt to access parent after navigation blocked, as not same-origin."}, "*"); + } +} +</script> +<body onload="doTest()"> + I am sandboxed with 'allow-scripts' +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if8.html b/dom/html/test/file_iframe_sandbox_d_if8.html new file mode 100644 index 0000000000..2b4398ef00 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if8.html @@ -0,0 +1,18 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="application/javascript"> + function doTest() { + window.parent.modify_if_8(); + } +</script> + +<body onload="doTest()"> + I am sandboxed with 'allow-scripts' and 'allow-same-origin' the first time I am loaded, and with 'allow-scripts' the second time +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_d_if9.html b/dom/html/test/file_iframe_sandbox_d_if9.html new file mode 100644 index 0000000000..ee641904fc --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_d_if9.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 341604</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<script type="application/javascript">
+function doTest() {
+ window.parent.modify_if_9();
+}
+</script>
+<body onload="doTest()">
+ I am sandboxed with 'allow-scripts' and 'allow-same-origin' the first time I am loaded, and with 'allow-same-origin' the second time
+</body>
+</html>
+
diff --git a/dom/html/test/file_iframe_sandbox_e_if1.html b/dom/html/test/file_iframe_sandbox_e_if1.html new file mode 100644 index 0000000000..e3882dfb28 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if1.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> + +<script> + function doTest() { + var testContext = location.search == "" ? "?Test 10: Navigate _top:%20" : location.search; + document.getElementById("if_6").src = "file_iframe_sandbox_e_if6.html" + testContext; + } +</script> + +<body onload="doTest()"> + <iframe sandbox='allow-scripts' id='if_6' height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if10.html b/dom/html/test/file_iframe_sandbox_e_if10.html new file mode 100644 index 0000000000..2484b8f342 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if10.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + function doTest() { + var testContext = "?Test 23: Nested navigate _top with window.open():%20"; + document.getElementById("if_9").src = "file_iframe_sandbox_e_if9.html" + testContext; + } +</script> + +<body onload="doTest()"> + <iframe sandbox='allow-scripts allow-top-navigation' id='if_9' height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if11.html b/dom/html/test/file_iframe_sandbox_e_if11.html new file mode 100644 index 0000000000..106c4c629b --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if11.html @@ -0,0 +1,22 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> + function doTest() { + var testContext = location.search.substring(1); + try { + window.open("file_iframe_sandbox_top_navigation_pass.html?" + testContext, "_top"); + } catch(error) { + window.top.opener.postMessage({ok: false, desc: unescape(testContext) + "error thrown during window.open(..., \"_top\")"}, "*"); + window.top.close(); + } + } +</script> +<body onload="doTest()"> + I am sandboxed with 'allow-scripts and allow-top-navigation' +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if12.html b/dom/html/test/file_iframe_sandbox_e_if12.html new file mode 100644 index 0000000000..0b1b87e09b --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if12.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + function doTest() { + var testContext = location.search == "" ? "?Test 24: Navigate _top with window.open():%20" : location.search; + document.getElementById("if_14").src = "file_iframe_sandbox_e_if14.html" + testContext; + } +</script> + +<body onload="doTest()"> + <iframe sandbox='allow-scripts' id='if_14' height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if13.html b/dom/html/test/file_iframe_sandbox_e_if13.html new file mode 100644 index 0000000000..f5cf912f67 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if13.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + function doTest() { + var testContext = "?Test 25: Nested navigate _top with window.open():%20"; + document.getElementById("if_12").src = "file_iframe_sandbox_e_if12.html" + testContext; + } +</script> + +<body onload="doTest()"> + <iframe sandbox='allow-scripts allow-top-navigation' id='if_12' height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if14.html b/dom/html/test/file_iframe_sandbox_e_if14.html new file mode 100644 index 0000000000..76d9787020 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if14.html @@ -0,0 +1,24 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> + function doTest() { + var testContext = location.search.substring(1); + try { + var topsOpener = window.top.opener; + window.open("file_iframe_sandbox_top_navigation_fail.html?" + testContext, "_top"); + topsOpener.postMessage({ok: false, desc: unescape(testContext) + "top navigation should NOT be allowed by a document sandboxed without 'allow-top-navigation.'"}, "*"); + } catch(error) { + window.top.opener.postMessage({ok: true, desc: unescape(testContext) + "as expected error thrown during window.open(..., \"_top\")"}, "*"); + window.top.close(); + } + } +</script> +<body onload="doTest()"> + I am sandboxed with 'allow-scripts' +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if15.html b/dom/html/test/file_iframe_sandbox_e_if15.html new file mode 100644 index 0000000000..bf4138e1d6 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if15.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + // Set our name, to allow an attempt to navigate us by name. + window.name = "e_if15"; +</script> + +<body> + <iframe sandbox='allow-scripts' id='if_16' src="file_iframe_sandbox_e_if16.html" height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if16.html b/dom/html/test/file_iframe_sandbox_e_if16.html new file mode 100644 index 0000000000..06c8bf8714 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if16.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Tests for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + var testContext = "Test 26: navigate top by name with window.open(): "; + + function doTest() { + try { + var topsOpener = window.top.opener; + window.open("file_iframe_sandbox_top_navigation_fail.html?" + escape(testContext), "e_if15"); + topsOpener.postMessage({ok: false, desc: unescape(testContext) + "top navigation should NOT be allowed by a document sandboxed without 'allow-top-navigation.'"}, "*"); + } catch(error) { + window.top.opener.postMessage({ok: true, desc: testContext + "as expected, error thrown during window.open(..., \"e_if15\")"}, "*"); + window.top.close(); + } + } +</script> + +<body onload="doTest()"> + I am sandboxed but with "allow-scripts" +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if2.html b/dom/html/test/file_iframe_sandbox_e_if2.html new file mode 100644 index 0000000000..739dbacbd5 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if2.html @@ -0,0 +1,12 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> + <iframe sandbox='allow-scripts allow-top-navigation allow-same-origin' id='if_1' src="file_iframe_sandbox_e_if1.html?Test 11: Nested navigate _top:%20" height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if3.html b/dom/html/test/file_iframe_sandbox_e_if3.html new file mode 100644 index 0000000000..ce010e6893 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if3.html @@ -0,0 +1,11 @@ +<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 341604</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+ <iframe sandbox='allow-scripts allow-top-navigation' id='if_5' src="file_iframe_sandbox_e_if5.html" height="10" width="10"></iframe>
+</body>
+</html>
diff --git a/dom/html/test/file_iframe_sandbox_e_if4.html b/dom/html/test/file_iframe_sandbox_e_if4.html new file mode 100644 index 0000000000..740a33a94d --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if4.html @@ -0,0 +1,11 @@ +<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 341604</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+ <iframe sandbox='allow-scripts allow-top-navigation' id='if_3' src="file_iframe_sandbox_e_if3.html" height="10" width="10"></iframe>
+</body>
+</html>
diff --git a/dom/html/test/file_iframe_sandbox_e_if5.html b/dom/html/test/file_iframe_sandbox_e_if5.html new file mode 100644 index 0000000000..e550df45e5 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if5.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script type="application/javascript"> +function navigateAway() { + document.getElementById("anchor").click(); +} +</script> +<body onload="navigateAway()"> + I am sandboxed with 'allow-scripts and allow-top-navigation' + + <a href="file_iframe_sandbox_top_navigation_pass.html" target='_top' id='anchor'>Click me</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if6.html b/dom/html/test/file_iframe_sandbox_e_if6.html new file mode 100644 index 0000000000..399c3c202b --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if6.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script type="application/javascript"> +function doTest() { + document.getElementById('anchor').href = "file_iframe_sandbox_top_navigation_fail.html" + location.search; + window.top.opener.postMessage({type: "attempted"}, "*"); + sendMouseEvent({type:'click'}, 'anchor'); +} +</script> +<body onload="doTest()"> + I am sandboxed with 'allow-scripts' + + <a target='_top' id='anchor'> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if7.html b/dom/html/test/file_iframe_sandbox_e_if7.html new file mode 100644 index 0000000000..9d60ed2dbc --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if7.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + // Set our name, to allow an attempt to navigate us by name. + window.name = "e_if7"; +</script> + +<body> + <iframe sandbox='allow-scripts' id='if_8' src="file_iframe_sandbox_e_if8.html" height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if8.html b/dom/html/test/file_iframe_sandbox_e_if8.html new file mode 100644 index 0000000000..97699abba9 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if8.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Tests for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> + +<script> + function doTest() { + // Try to navigate top using its name (e_if7). We should not be able to do this as allow-top-navigation is not specified. + window.top.opener.postMessage({type: "attempted"}, "*"); + sendMouseEvent({type:'click'}, 'navigate_top'); + } +</script> + +<body onload="doTest()"> + I am sandboxed but with "allow-scripts" + + <a href="file_iframe_sandbox_top_navigation_fail.html?Test 15: Navigate top by name:%20" target="e_if7" id="navigate_top">navigate top</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_e_if9.html b/dom/html/test/file_iframe_sandbox_e_if9.html new file mode 100644 index 0000000000..f18a16dba6 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_e_if9.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + function doTest() { + var testContext = location.search == "" ? "?Test 22: Navigate _top with window.open():%20" : location.search; + document.getElementById("if_11").src = "file_iframe_sandbox_e_if11.html" + testContext; + } +</script> + +<body onload="doTest()"> + <iframe sandbox='allow-scripts allow-top-navigation' id='if_11' height="10" width="10"></iframe> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_fail.js b/dom/html/test/file_iframe_sandbox_fail.js new file mode 100644 index 0000000000..1f1290d046 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_fail.js @@ -0,0 +1,4 @@ +ok( + false, + "documents sandboxed with allow-scripts should NOT be able to run <script src=...>" +); diff --git a/dom/html/test/file_iframe_sandbox_form_fail.html b/dom/html/test/file_iframe_sandbox_form_fail.html new file mode 100644 index 0000000000..6976ced8ad --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_form_fail.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body onLoad="doStuff()"> + I should NOT be loaded by a form submit from a sandbox without 'allow-forms' +</body> +</html> + +<script> + function doStuff() { + window.parent.postMessage({ok: false, desc: "documents sandboxed without allow-forms should NOT be able to submit forms"}, "*"); + } +</script>
\ No newline at end of file diff --git a/dom/html/test/file_iframe_sandbox_form_pass.html b/dom/html/test/file_iframe_sandbox_form_pass.html new file mode 100644 index 0000000000..1ba8853fa5 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_form_pass.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> +</head> + +<body onLoad="doStuff()"> + I should be loaded by a form submit from a sandbox with 'allow-forms' +</body> +</html> + +<script> + function doStuff() { + window.parent.postMessage({ok: true, desc: "documents sandboxed with allow-forms should be able to submit forms"}, "*"); + } +</script>
\ No newline at end of file diff --git a/dom/html/test/file_iframe_sandbox_g_if1.html b/dom/html/test/file_iframe_sandbox_g_if1.html new file mode 100644 index 0000000000..67604f1f64 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_g_if1.html @@ -0,0 +1,60 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="text/javascript"> + function ok(result, desc) { + window.parent.postMessage({ok: result, desc}, "*"); + } + + function doStuff() { + // test data URI + + // self.onmessage = function(event) { + // self.postMessage('make it so'); + // }; + var data_url = "data:text/plain;charset=utf-8;base64,c2VsZi5vbm1lc3NhZ2UgPSBmdW5jdGlvbihldmVudCkgeyAgDQogICAgc2VsZi5wb3N0TWVzc2FnZSgnbWFrZSBpdCBzbycpOyAgDQp9Ow=="; + var worker_data = new Worker(data_url); + worker_data.addEventListener('message', function(event) { + ok(true, "a worker in a sandboxed document should be able to be loaded from a data: URI"); + }); + + worker_data.postMessage("engage!"); + + // test a blob URI we created (will have the same null principal + // as us + var b = new Blob(["onmessage = function(event) { self.postMessage('make it so');};"]); + + var blobURL = URL.createObjectURL(b); + + var worker_blob = new Worker(blobURL); + + worker_blob.addEventListener('message', function(event) { + ok(true, "a worker in a sandboxed document should be able to be loaded from a blob URI " + + "created by that sandboxed document"); + }); + + worker_blob.postMessage("engage!"); + + // test loading with relative url - this should fail since we are + // sandboxed and have a null principal + var worker_js = new Worker('file_iframe_sandbox_worker.js'); + worker_js.onerror = function(error) { + ok(true, "a worker in a sandboxed document should tell the load error via error event"); + } + + worker_js.addEventListener('message', function(event) { + ok(false, "a worker in a sandboxed document should not be able to load from a relative URI"); + }); + + worker_js.postMessage('engage'); + } +</script> +<body onload='doStuff();'> + I am sandboxed but with "allow-scripts" +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_h_if1.html b/dom/html/test/file_iframe_sandbox_h_if1.html new file mode 100644 index 0000000000..7c5cada2dc --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_h_if1.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Tests for Bug 766282</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + +</head> +<script type="text/javascript"> + function ok(result, desc) { + window.parent.ok_wrapper(result, desc); + } + + function doStuff() { + // Try to open a new window via target="_blank", target="BC766282" and window.open(). + // The window we try to open closes itself once it opens. + sendMouseEvent({type:'click'}, 'target_blank'); + sendMouseEvent({type:'click'}, 'target_BC766282'); + + try { + window.open("file_iframe_sandbox_open_window_pass.html"); + } catch(e) { + ok(false, "Test 3: iframes sandboxed with allow-popups, should be able to open windows"); + } + } +</script> +<body onLoad="doStuff()"> + I am sandboxed but with "allow-popups allow-scripts allow-same-origin" + + <a href="file_iframe_sandbox_open_window_pass.html" target="_blank" rel="opener" id="target_blank">open window</a> + <a href="file_iframe_sandbox_open_window_pass.html?BC766282" target="BC766282" id="target_BC766282">open window</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_k_if1.html b/dom/html/test/file_iframe_sandbox_k_if1.html new file mode 100644 index 0000000000..f6f1238085 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_k_if1.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="text/javascript"> + var windowsToClose = new Array(); + + function closeWindows() { + for (var i = 0; i < windowsToClose.length; i++) { + windowsToClose[i].close(); + } + window.open("file_iframe_sandbox_close.html", "blank_if2"); + window.open("file_iframe_sandbox_close.html", "BC766282_if2"); + } + + // Add message listener to forward messages on to parent + window.addEventListener("message", receiveMessage); + + function receiveMessage(event) { + switch (event.data.type) { + case "closeWindows": + closeWindows(); + break; + } + } + + function doStuff() { + // Open a new window via target="_blank", target="BC766282_if2" and window.open(). + sendMouseEvent({type:'click'}, 'target_blank_if2'); + sendMouseEvent({type:'click'}, 'target_BC766282_if2'); + + windowsToClose.push(window.open("file_iframe_sandbox_k_if2.html")); + } +</script> +<body onLoad="doStuff()"> + I am navigated to from file_iframe_sandbox_k_if8.html. + This was opened in an iframe with "allow-scripts allow-popups allow-same-origin". + However allow-same-origin was removed from the iframe before navigating to me, + so I should only have "allow-scripts allow-popups" in force. + <a href="file_iframe_sandbox_k_if2.html" target="_blank" id="target_blank_if2" rel="opener">open window</a> + <a href="file_iframe_sandbox_k_if2.html" target="BC766282_if2" id="target_BC766282_if2">open window</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_k_if2.html b/dom/html/test/file_iframe_sandbox_k_if2.html new file mode 100644 index 0000000000..dce42aef54 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_k_if2.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="text/javascript"> + if (window.name == "") { + window.name = "blank_if2"; + } + + function ok(result, message) { + window.opener.parent.postMessage({type: "ok", ok: result, desc: message}, "*"); + } + + function doStuff() { + // Check that sandboxed forms browsing context flag copied by attempting to submit a form. + document.getElementById('a_form').submit(); + window.opener.parent.postMessage({type: "attempted"}, "*"); + + // Check that sandboxed origin browsing context flag copied by attempting to access cookies. + try { + var foo = document.cookie; + ok(false, "Sandboxed origin browsing context flag NOT copied to new auxiliary browsing context."); + } catch(error) { + ok(true, "Sandboxed origin browsing context flag copied to new auxiliary browsing context."); + } + + // Check that sandboxed top-level navigation browsing context flag copied. + // if_3 tries to navigate this document. + var if_3 = document.getElementById('if_3'); + if_3.src = "file_iframe_sandbox_k_if3.html"; + } +</script> + +<body onLoad="doStuff()"> + I am not sandboxed directly, but opened from a sandboxed document with 'allow-scripts allow-popups' + + <form method="get" action="file_iframe_sandbox_window_form_fail.html" id="a_form"> + First name: <input type="text" name="firstname"> + Last name: <input type="text" name="lastname"> + <input type="submit" id="a_button"> + </form> + + <iframe id="if_3" src="about:blank" height="10" width="10"></iframe> + +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_k_if3.html b/dom/html/test/file_iframe_sandbox_k_if3.html new file mode 100644 index 0000000000..a2619dd006 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_k_if3.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> +<script type="application/javascript"> + function doTest() { + sendMouseEvent({type:'click'}, 'anchor'); + window.parent.opener.parent.postMessage({type: "attempted"}, "*"); + } +</script> +<body onload="doTest()"> + I am sandboxed with 'allow-scripts allow-popups' + + <a href="file_iframe_sandbox_window_top_navigation_fail.html" target='_top' id='anchor'> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_k_if4.html b/dom/html/test/file_iframe_sandbox_k_if4.html new file mode 100644 index 0000000000..3d030158dc --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_k_if4.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="text/javascript"> + function doStuff() { + // Open a new window via target="_blank", target="BC766282_if5" and window.open(). + sendMouseEvent({type:'click'}, 'target_blank_if5'); + sendMouseEvent({type:'click'}, 'target_BC766282_if5'); + + window.open("file_iframe_sandbox_k_if5.html"); + + // Open a new window via target="_blank", target="BC766282_if7" and window.open(). + sendMouseEvent({type:'click'}, 'target_blank_if7'); + sendMouseEvent({type:'click'}, 'target_BC766282_if7'); + + window.open("file_iframe_sandbox_k_if7.html"); + } +</script> + +<body onLoad="doStuff()"> + I am sandboxed with "allow-scripts allow-popups allow-same-origin allow-forms allow-top-navigation". + <a href="file_iframe_sandbox_k_if5.html" target="_blank" id="target_blank_if5" rel="opener">open window</a> + <a href="file_iframe_sandbox_k_if5.html" target="BC766282_if5" id="target_BC766282_if5">open window</a> + + <a href="file_iframe_sandbox_k_if7.html" target="_blank" id="target_blank_if7" rel="opener">open window</a> + <a href="file_iframe_sandbox_k_if7.html" target="BC766282_if7" id="target_BC766282_if7">open window</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_k_if5.html b/dom/html/test/file_iframe_sandbox_k_if5.html new file mode 100644 index 0000000000..8deb65852f --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_k_if5.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="text/javascript"> + function doStuff() { + // Check that sandboxed origin browsing context flag NOT set by attempting to access cookies. + try { + var foo = document.cookie; + window.opener.parent.ok_wrapper(true, "Sandboxed origin browsing context flag NOT set on new auxiliary browsing context."); + } catch(error) { + window.opener.parent.ok_wrapper(false, "Sandboxed origin browsing context flag set on new auxiliary browsing context."); + } + + // Check that sandboxed top-level navigation browsing context flag NOT set. + // if_6 tries to navigate this document. + var if_6 = document.getElementById('if_6'); + if_6.src = "file_iframe_sandbox_k_if6.html"; + } +</script> + +<body onLoad="doStuff()"> + I am not sandboxed directly, but opened from a sandboxed document with at least + 'allow-scripts allow-popups allow-same-origin allow-top-navigation' + + <iframe id="if_6" src="about:blank" height="10" width="10"></iframe> + +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_k_if6.html b/dom/html/test/file_iframe_sandbox_k_if6.html new file mode 100644 index 0000000000..53ed080e3e --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_k_if6.html @@ -0,0 +1,21 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script src="/tests/SimpleTest/EventUtils.js"></script> +</head> + +<script type="application/javascript"> + function doTest() { + sendMouseEvent({type:'click'}, 'anchor'); + } +</script> + +<body onload="doTest()"> + I am sandboxed with at least 'allow-scripts allow-popups allow-top-navigation' + + <a href="file_iframe_sandbox_window_top_navigation_pass.html" target='_top' id='anchor'> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_k_if7.html b/dom/html/test/file_iframe_sandbox_k_if7.html new file mode 100644 index 0000000000..269e31eb5b --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_k_if7.html @@ -0,0 +1,26 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="text/javascript"> + function doStuff() { + // Check that sandboxed forms browsing context flag NOT set by attempting to submit a form. + document.getElementById('a_form').submit(); + } +</script> + +<body onLoad="doStuff()"> + I am not sandboxed directly, but opened from a sandboxed document with at least + 'allow-scripts allow-popups allow-forms allow-same-origin' + + <form method="get" action="file_iframe_sandbox_window_form_pass.html" id="a_form"> + First name: <input type="text" name="firstname"> + Last name: <input type="text" name="lastname"> + <input type="submit" id="a_button"> + </form> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_k_if8.html b/dom/html/test/file_iframe_sandbox_k_if8.html new file mode 100644 index 0000000000..e4aad97f3b --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_k_if8.html @@ -0,0 +1,36 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="text/javascript"> + function doSubOpens() { + // Open a new window via target="_blank", target="BC766282_if9" and window.open(). + sendMouseEvent({type:'click'}, 'target_blank_if9'); + sendMouseEvent({type:'click'}, 'target_BC766282_if9'); + + window.open("file_iframe_sandbox_k_if9.html"); + + sendMouseEvent({type:'click'}, 'target_if1'); + } + + window.doSubOpens = doSubOpens; +</script> + +<body> + I am sandboxed but with "allow-scripts allow-popups allow-same-origin". + After my initial load, "allow-same-origin" is removed and then I open file_iframe_sandbox_k_if9.html + in 3 different ways, which attemps to call a function in my parent. + This should succeed since the new sandbox flags shouldn't have taken affect on me until I'm reloaded. + <a href="file_iframe_sandbox_k_if9.html" target="_blank" id="target_blank_if9" rel="opener">open window</a> + <a href="file_iframe_sandbox_k_if9.html" target="BC766282_if9" id="target_BC766282_if9">open window</a> + + Now navigate to file_iframe_sandbox_k_if1.html to do tests for a sandbox opening a window + when only "allow-scripts allow-popups" are specified. + <a href="file_iframe_sandbox_k_if1.html" id="target_if1">navigate to if1</a> +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_k_if9.html b/dom/html/test/file_iframe_sandbox_k_if9.html new file mode 100644 index 0000000000..56e8db3f9a --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_k_if9.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + function doStuff() { + window.opener.parent.ok_wrapper(true, "A window opened from within a sandboxed document should inherit the flags of the document, not of the docshell/sandbox attribute."); + self.close(); + } +</script> + +<body onload='doStuff()'> + I'm a window opened from the sandboxed document of file_iframe_sandbox_k_if8.html. + I should be able to call ok_wrapper in main test page directly because I should be same-origin with it. +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_navigation_fail.html b/dom/html/test/file_iframe_sandbox_navigation_fail.html new file mode 100644 index 0000000000..bae5276bd1 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_navigation_fail.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body onLoad="doStuff()"> +FAIL +</body> +<script> + function doStuff() { + var testContext = unescape(location.search.substring(1)); + window.parent.postMessage({ok: false, desc: testContext + "this navigation should NOT be allowed by a sandboxed document", addToAttempted: false}, "*"); + } +</script> +</html> diff --git a/dom/html/test/file_iframe_sandbox_navigation_pass.html b/dom/html/test/file_iframe_sandbox_navigation_pass.html new file mode 100644 index 0000000000..e07248247b --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_navigation_pass.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> +function doStuff() { + var testContext = unescape(location.search.substring(1)); + window.parent.postMessage({ok: true, desc: testContext + "this navigation should be allowed by a sandboxed document"}, "*"); +} +</script> +<body onLoad="doStuff()"> +PASS +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_navigation_start.html b/dom/html/test/file_iframe_sandbox_navigation_start.html new file mode 100644 index 0000000000..fa56425177 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_navigation_start.html @@ -0,0 +1,11 @@ +<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 341604</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+I am just a normal HTML document, probably contained in a sandboxed iframe
+</body>
+</html>
diff --git a/dom/html/test/file_iframe_sandbox_open_window_fail.html b/dom/html/test/file_iframe_sandbox_open_window_fail.html new file mode 100644 index 0000000000..64e0d36180 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_open_window_fail.html @@ -0,0 +1,19 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body onLoad="doStuff()"> + I should NOT be opened by a sandboxed iframe via any method +</body> +</html> + +<script> + function doStuff() { + window.opener.ok(false, "sandboxed documents should NOT be able to open windows"); + self.close(); + } +</script> diff --git a/dom/html/test/file_iframe_sandbox_open_window_pass.html b/dom/html/test/file_iframe_sandbox_open_window_pass.html new file mode 100644 index 0000000000..ac45c7fd32 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_open_window_pass.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body onLoad="doStuff()"> + I should be opened by a sandboxed iframe via any method when "allow-popups" is specified. +</body> +</html> + +<script> + function doStuff() { + // Check that the browsing context's (window's) name is as expected. + var expectedName = location.search.substring(1); + if (expectedName == window.name) { + window.opener.ok(true, "sandboxed documents should be able to open windows when \"allow-popups\" is specified"); + } else { + window.opener.ok(false, "window opened with \"allow-popups\", but expected name was " + expectedName + " and actual was " + window.name); + } + self.close(); + } +</script> diff --git a/dom/html/test/file_iframe_sandbox_pass.js b/dom/html/test/file_iframe_sandbox_pass.js new file mode 100644 index 0000000000..15b3e7d3ff --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_pass.js @@ -0,0 +1,4 @@ +ok( + true, + "documents sandboxed with allow-scripts should be able to run <script src=...>" +); diff --git a/dom/html/test/file_iframe_sandbox_redirect.html b/dom/html/test/file_iframe_sandbox_redirect.html new file mode 100644 index 0000000000..62419d7f46 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_redirect.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<body>redirect</body> diff --git a/dom/html/test/file_iframe_sandbox_redirect.html^headers^ b/dom/html/test/file_iframe_sandbox_redirect.html^headers^ new file mode 100644 index 0000000000..71b739c42a --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_redirect.html^headers^ @@ -0,0 +1,2 @@ +HTTP 301 Moved Permanently +Location: file_iframe_sandbox_redirect_target.html diff --git a/dom/html/test/file_iframe_sandbox_redirect_target.html b/dom/html/test/file_iframe_sandbox_redirect_target.html new file mode 100644 index 0000000000..c134ac0ffd --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_redirect_target.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<head> + <script> + onmessage = function(event) { + parent.postMessage(event.data + " redirect target", "*"); + } + </script> +</head> +<body>I have been redirected</body> diff --git a/dom/html/test/file_iframe_sandbox_refresh.html b/dom/html/test/file_iframe_sandbox_refresh.html new file mode 100644 index 0000000000..1fad80c428 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_refresh.html @@ -0,0 +1,2 @@ +<!DOCTYPE html> +<body>refresh</body> diff --git a/dom/html/test/file_iframe_sandbox_refresh.html^headers^ b/dom/html/test/file_iframe_sandbox_refresh.html^headers^ new file mode 100644 index 0000000000..a7cc383b4f --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_refresh.html^headers^ @@ -0,0 +1 @@ +Refresh: 0 url=data:text/html,Refreshed diff --git a/dom/html/test/file_iframe_sandbox_srcdoc_allow_scripts.html b/dom/html/test/file_iframe_sandbox_srcdoc_allow_scripts.html new file mode 100644 index 0000000000..7d585be04f --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_srcdoc_allow_scripts.html @@ -0,0 +1 @@ +<script>parent.parent.ok_wrapper(true, "an object inside an iframe sandboxed with allow-scripts allow-same-origin should be able to run scripts and call functions in the parent of the iframe")</script> diff --git a/dom/html/test/file_iframe_sandbox_srcdoc_no_allow_scripts.html b/dom/html/test/file_iframe_sandbox_srcdoc_no_allow_scripts.html new file mode 100644 index 0000000000..b6faf83cc9 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_srcdoc_no_allow_scripts.html @@ -0,0 +1 @@ +<script>parent.parent.ok_wrapper(false, 'an object inside an iframe sandboxed with only allow-same-origin should not be able to run scripts')</script> diff --git a/dom/html/test/file_iframe_sandbox_top_navigation_fail.html b/dom/html/test/file_iframe_sandbox_top_navigation_fail.html new file mode 100644 index 0000000000..dad6b2c006 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_top_navigation_fail.html @@ -0,0 +1,18 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> +function doStuff() { + var testContext = unescape(location.search.substring(1)); + window.opener.postMessage({ok: false, desc: testContext + "top navigation should NOT be allowed by a document sandboxed without 'allow-top-navigation'", addToAttempted: false}, "*"); + window.close(); +} +</script> +<body onLoad="doStuff()"> +FAIL\ +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_top_navigation_pass.html b/dom/html/test/file_iframe_sandbox_top_navigation_pass.html new file mode 100644 index 0000000000..712240ecb2 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_top_navigation_pass.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> +function doStuff() { + var testContext = unescape(location.search.substring(1)); + var bc = new BroadcastChannel("test_iframe_sandbox_navigation"); + bc.postMessage({ok: true, desc: testContext + "top navigation should be allowed by a document sandboxed with 'allow-top-navigation'"}); + bc.close(); + window.close(); +} +</script> +<body onLoad="doStuff()"> +PASS +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_window_form_fail.html b/dom/html/test/file_iframe_sandbox_window_form_fail.html new file mode 100644 index 0000000000..2d678b3ac9 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_window_form_fail.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body onLoad="doStuff()"> + I should NOT be loaded by a form submit from a window opened from a sandbox without 'allow-forms'. +</body> +</html> + +<script> + function doStuff() { + window.opener.parent.postMessage({ok: false, desc: "documents sandboxed without allow-forms should NOT be able to submit forms"}, "*"); + + self.close(); + } +</script> diff --git a/dom/html/test/file_iframe_sandbox_window_form_pass.html b/dom/html/test/file_iframe_sandbox_window_form_pass.html new file mode 100644 index 0000000000..dd2656c1ec --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_window_form_pass.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + function doStuff() { + window.opener.parent.ok_wrapper(true, "Sandboxed forms browsing context flag NOT set on new auxiliary browsing context."); + + self.close(); + } +</script> + +<body onLoad="doStuff()"> + I should be loaded by a form submit from a window opened from a sandbox with 'allow-forms allow-same-origin'. +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_window_navigation_fail.html b/dom/html/test/file_iframe_sandbox_window_navigation_fail.html new file mode 100644 index 0000000000..f8e3c83ce8 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_window_navigation_fail.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 838692</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> +function doStuff() { + var testContext = unescape(location.search.substring(1)); + window.opener.postMessage({ok: false, desc: testContext + "a sandboxed document should not be able to navigate a window it hasn't opened.", addToAttempted: false}, "*"); + window.close(); +} +</script> + +<body onLoad="doStuff()"> +FAIL +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_window_navigation_pass.html b/dom/html/test/file_iframe_sandbox_window_navigation_pass.html new file mode 100644 index 0000000000..a1bff9eb83 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_window_navigation_pass.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> +function doStuff() { + var testContext = unescape(location.search.substring(1)); + window.opener.postMessage({type: "ok", ok: true, desc: testContext + "a permitted sandboxed document should be able to navigate a window it has opened.", addToAttempted: false}, "*"); + window.close(); +} +</script> + +<body onLoad="doStuff()"> +PASS +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_window_top_navigation_fail.html b/dom/html/test/file_iframe_sandbox_window_top_navigation_fail.html new file mode 100644 index 0000000000..af50476045 --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_window_top_navigation_fail.html @@ -0,0 +1,24 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script> + function doStuff() { + window.opener.parent.postMessage({ok: false, desc: "Sandboxed top-level navigation browsing context flag NOT copied to new auxiliary browsing context."}, "*"); + + // Check that when no browsing context returned by "target='_top'", a new browsing context isn't opened by mistake. + try { + window.opener.parent.opener.parent.postMessage({ok: false, desc: "An attempt at top navigation without 'allow-top-navigation' should not have opened a new browsing context."}, "*"); + } catch (error) { + } + + self.close(); + } +</script> +<body onLoad="doStuff()"> +FAIL +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_window_top_navigation_pass.html b/dom/html/test/file_iframe_sandbox_window_top_navigation_pass.html new file mode 100644 index 0000000000..d3637fb04e --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_window_top_navigation_pass.html @@ -0,0 +1,20 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test for Bug 766282</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script> + function doStuff() { + window.opener.parent.ok_wrapper(true, "Sandboxed top-level navigation browsing context flag NOT copied to new auxiliary browsing context."); + + self.close(); + } +</script> + +<body onLoad="doStuff()"> + I am navigated to from a window opened from a sandbox with allow-top-navigation. +</body> +</html> diff --git a/dom/html/test/file_iframe_sandbox_worker.js b/dom/html/test/file_iframe_sandbox_worker.js new file mode 100644 index 0000000000..3cb9f650dc --- /dev/null +++ b/dom/html/test/file_iframe_sandbox_worker.js @@ -0,0 +1,3 @@ +self.onmessage = function (event) { + self.postMessage("make it so"); +}; diff --git a/dom/html/test/file_refresh_after_document_write.html b/dom/html/test/file_refresh_after_document_write.html new file mode 100644 index 0000000000..ebf3272e08 --- /dev/null +++ b/dom/html/test/file_refresh_after_document_write.html @@ -0,0 +1,15 @@ +<html> +<head> +<title></title> +</head> +<script> +function write_and_refresh(){ + document.write("This could be anything"); + location.reload(); +} +</script> +<body> +<button id='test_btn' onclick='write_and_refresh()'> +</body> + +</html> diff --git a/dom/html/test/file_script_module.html b/dom/html/test/file_script_module.html new file mode 100644 index 0000000000..78c4992654 --- /dev/null +++ b/dom/html/test/file_script_module.html @@ -0,0 +1,42 @@ +<html> +<body> + <script> +// Helper methods. +function ok(a, msg) { + parent.postMessage({ check: !!a, msg }, "*") +} + +function is(a, b, msg) { + ok(a === b, msg); +} + +function finish() { + parent.postMessage({ done: true }, "*"); +} + </script> + + <script id="a" nomodule>42</script> + <script id="b">42</script> + <script> +// Let's test the behavior of nomodule attribute and noModule getter/setter. +var a = document.getElementById("a"); +is(a.noModule, true, "HTMLScriptElement with nomodule attribute has noModule set to true"); +a.removeAttribute("nomodule"); +is(a.noModule, false, "HTMLScriptElement without nomodule attribute has noModule set to false"); +a.noModule = true; +ok(a.hasAttribute('nomodule'), "HTMLScriptElement.noModule = true add the nomodule attribute"); + +var b = document.getElementById("b"); +is(b.noModule, false, "HTMLScriptElement without nomodule attribute has noModule set to false"); +b.noModule = true; +ok(b.hasAttribute('nomodule'), "HTMLScriptElement.noModule = true add the nomodule attribute"); + </script> + + <script>var foo = 42;</script> + <script nomodule>foo = 43;</script> + <script> +is(foo, 42, "nomodule HTMLScriptElements should not be executed in modern browsers"); +finish(); + </script> +</body> +</html> diff --git a/dom/html/test/file_srcdoc-2.html b/dom/html/test/file_srcdoc-2.html new file mode 100644 index 0000000000..bd75f5e059 --- /dev/null +++ b/dom/html/test/file_srcdoc-2.html @@ -0,0 +1,10 @@ +<!doctype html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=802895 +--> +<body> +<iframe id="iframe" srcdoc="Hello World"></iframe> +</body> + +</html> diff --git a/dom/html/test/file_srcdoc.html b/dom/html/test/file_srcdoc.html new file mode 100644 index 0000000000..7f084bc74b --- /dev/null +++ b/dom/html/test/file_srcdoc.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=802895 +--> +<body> +<iframe id="iframe" srcdoc="Hello World"></iframe> + +<iframe id="iframe1" src="about:mozilla" + srcdoc="Goodbye World"></iframe> +<iframe id="iframe2" srcdoc="Peeking test" sandbox=""></iframe> +<iframe id="iframe3" src="file_srcdoc_iframe3.html" + srcdoc="Going"></iframe> +</body> + +</html> diff --git a/dom/html/test/file_srcdoc_iframe3.html b/dom/html/test/file_srcdoc_iframe3.html new file mode 100644 index 0000000000..233692734f --- /dev/null +++ b/dom/html/test/file_srcdoc_iframe3.html @@ -0,0 +1 @@ +Gone diff --git a/dom/html/test/file_window_close_and_open.html b/dom/html/test/file_window_close_and_open.html new file mode 100644 index 0000000000..ad96e50aac --- /dev/null +++ b/dom/html/test/file_window_close_and_open.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<html> +<script> + console.log("loading file_window_close_and_open.html"); + addEventListener("load", function() { + console.log("got load event!"); + let link = document.querySelector("a"); + if (window.location.hash === "#noopener") { + link.setAttribute("rel", "noopener"); + } else if (window.location.hash === "#opener") { + link.setAttribute("rel", "opener"); + } + link.click(); + }); +</script> +<body> + <h1>close and re-open popup</h1> + <a href="file_broadcast_load.html" target="_blank" onclick="window.close()">close and open</a> +</body> +</html> diff --git a/dom/html/test/file_window_open_close_inner.html b/dom/html/test/file_window_open_close_inner.html new file mode 100644 index 0000000000..dbc7e3aba8 --- /dev/null +++ b/dom/html/test/file_window_open_close_inner.html @@ -0,0 +1,7 @@ +<html> +<body> +<script> +window.close(); +</script> +</html> +</body> diff --git a/dom/html/test/file_window_open_close_outer.html b/dom/html/test/file_window_open_close_outer.html new file mode 100644 index 0000000000..682b399e75 --- /dev/null +++ b/dom/html/test/file_window_open_close_outer.html @@ -0,0 +1,5 @@ +<html> +<body> +<a id="link" href="file_window_open_close_inner.html" target="_blank" rel="opener" onclick="setTimeout(function () { window.close() }, 0)">link</a> +</html> +</body> diff --git a/dom/html/test/formData_test.js b/dom/html/test/formData_test.js new file mode 100644 index 0000000000..3997aff4d1 --- /dev/null +++ b/dom/html/test/formData_test.js @@ -0,0 +1,289 @@ +function testHas() { + var f = new FormData(); + f.append("foo", "bar"); + f.append("another", "value"); + ok(f.has("foo"), "has() on existing name should be true."); + ok(f.has("another"), "has() on existing name should be true."); + ok(!f.has("nonexistent"), "has() on non-existent name should be false."); +} + +function testGet() { + var f = new FormData(); + f.append("foo", "bar"); + f.append("foo", "bar2"); + f.append("blob", new Blob(["hey"], { type: "text/plain" })); + f.append("file", new File(["hey"], "testname", { type: "text/plain" })); + + is(f.get("foo"), "bar", "get() on existing name should return first value"); + ok( + f.get("blob") instanceof Blob, + "get() on existing name should return first value" + ); + is( + f.get("blob").type, + "text/plain", + "get() on existing name should return first value" + ); + ok( + f.get("file") instanceof File, + "get() on existing name should return first value" + ); + is( + f.get("file").name, + "testname", + "get() on existing name should return first value" + ); + + is( + f.get("nonexistent"), + null, + "get() on non-existent name should return null." + ); +} + +function testGetAll() { + var f = new FormData(); + f.append("other", "value"); + f.append("foo", "bar"); + f.append("foo", "bar2"); + f.append("foo", new Blob(["hey"], { type: "text/plain" })); + + var arr = f.getAll("foo"); + is(arr.length, 3, "getAll() should retrieve all matching entries."); + is(arr[0], "bar", "values should match and be in order"); + is(arr[1], "bar2", "values should match and be in order"); + ok(arr[2] instanceof Blob, "values should match and be in order"); + + is( + f.get("nonexistent"), + null, + "get() on non-existent name should return null." + ); +} + +function testDelete() { + var f = new FormData(); + f.append("other", "value"); + f.append("foo", "bar"); + f.append("foo", "bar2"); + f.append("foo", new Blob(["hey"], { type: "text/plain" })); + + ok(f.has("foo"), "has() on existing name should be true."); + f.delete("foo"); + ok(!f.has("foo"), "has() on deleted name should be false."); + is(f.getAll("foo").length, 0, "all entries should be deleted."); + + is(f.getAll("other").length, 1, "other names should still be there."); + f.delete("other"); + is(f.getAll("other").length, 0, "all entries should be deleted."); +} + +function testSet() { + var f = new FormData(); + + f.set("other", "value"); + ok(f.has("other"), "set() on new name should be similar to append()"); + is( + f.getAll("other").length, + 1, + "set() on new name should be similar to append()" + ); + + f.append("other", "value2"); + is( + f.getAll("other").length, + 2, + "append() should not replace existing entries." + ); + + f.append("foo", "bar"); + f.append("other", "value3"); + f.append("other", "value3"); + f.append("other", "value3"); + is( + f.getAll("other").length, + 5, + "append() should not replace existing entries." + ); + + f.set("other", "value4"); + is(f.getAll("other").length, 1, "set() should replace existing entries."); + is(f.getAll("other")[0], "value4", "set() should replace existing entries."); +} + +function testFilename() { + var f = new FormData(); + f.append("blob", new Blob(["hi"])); + ok(f.get("blob") instanceof Blob, "We should have a blob back."); + + // If a filename is passed, that should replace the original. + f.append("blob2", new Blob(["hi"]), "blob2.txt"); + is( + f.get("blob2").name, + "blob2.txt", + 'Explicit filename should override "blob".' + ); + + var file = new File(["hi"], "file1.txt"); + f.append("file1", file); + // If a file is passed, the "create entry" algorithm should not create a new File, but reuse the existing one. + is( + f.get("file1"), + file, + "Retrieved File object should be original File object and not a copy." + ); + is( + f.get("file1").name, + "file1.txt", + "File's filename should be original's name if no filename is explicitly passed." + ); + + file = new File(["hi"], "file2.txt"); + f.append("file2", file, "fakename.txt"); + ok( + f.get("file2") !== file, + "Retrieved File object should be new File object if explicit filename is passed." + ); + is( + f.get("file2").name, + "fakename.txt", + "File's filename should be explicitly passed name." + ); + f.append("file3", new File(["hi"], "")); + is(f.get("file3").name, "", "File's filename is returned even if empty."); +} + +function testIterable() { + var fd = new FormData(); + fd.set("1", "2"); + fd.set("2", "4"); + fd.set("3", "6"); + fd.set("4", "8"); + fd.set("5", "10"); + + var key_iter = fd.keys(); + var value_iter = fd.values(); + var entries_iter = fd.entries(); + for (var i = 0; i < 5; ++i) { + var v = i + 1; + var key = key_iter.next(); + var value = value_iter.next(); + var entry = entries_iter.next(); + is(key.value, v.toString(), "Correct Key iterator: " + v.toString()); + ok(!key.done, "key.done is false"); + is( + value.value, + (v * 2).toString(), + "Correct Value iterator: " + (v * 2).toString() + ); + ok(!value.done, "value.done is false"); + is( + entry.value[0], + v.toString(), + "Correct Entry 0 iterator: " + v.toString() + ); + is( + entry.value[1], + (v * 2).toString(), + "Correct Entry 1 iterator: " + (v * 2).toString() + ); + ok(!entry.done, "entry.done is false"); + } + + var last = key_iter.next(); + ok(last.done, "Nothing more to read."); + is(last.value, undefined, "Undefined is the last key"); + + last = value_iter.next(); + ok(last.done, "Nothing more to read."); + is(last.value, undefined, "Undefined is the last value"); + + last = entries_iter.next(); + ok(last.done, "Nothing more to read."); + + key_iter = fd.keys(); + key_iter.next(); + key_iter.next(); + fd.delete("1"); + fd.delete("2"); + fd.delete("3"); + fd.delete("4"); + fd.delete("5"); + + last = key_iter.next(); + ok(last.done, "Nothing more to read."); + is(last.value, undefined, "Undefined is the last key"); +} + +function testSend(doneCb) { + var xhr = new XMLHttpRequest(); + xhr.open("POST", "form_submit_server.sjs"); + xhr.onload = function () { + var response = xhr.response; + + for (var entry of response) { + is(entry.body, "hey"); + is(entry.headers["Content-Type"], "text/plain"); + } + + is( + response[0].headers["Content-Disposition"], + 'form-data; name="empty"; filename="blob"' + ); + + is( + response[1].headers["Content-Disposition"], + 'form-data; name="explicit"; filename="explicit-file-name"' + ); + + is( + response[2].headers["Content-Disposition"], + 'form-data; name="explicit-empty"; filename=""' + ); + + is( + response[3].headers["Content-Disposition"], + 'form-data; name="file-name"; filename="testname"' + ); + + is( + response[4].headers["Content-Disposition"], + 'form-data; name="empty-file-name"; filename=""' + ); + + is( + response[5].headers["Content-Disposition"], + 'form-data; name="file-name-overwrite"; filename="overwrite"' + ); + + doneCb(); + }; + + var file, + blob = new Blob(["hey"], { type: "text/plain" }); + + var fd = new FormData(); + fd.append("empty", blob); + fd.append("explicit", blob, "explicit-file-name"); + fd.append("explicit-empty", blob, ""); + file = new File([blob], "testname", { type: "text/plain" }); + fd.append("file-name", file); + file = new File([blob], "", { type: "text/plain" }); + fd.append("empty-file-name", file); + file = new File([blob], "testname", { type: "text/plain" }); + fd.append("file-name-overwrite", file, "overwrite"); + xhr.responseType = "json"; + xhr.send(fd); +} + +function runTest(doneCb) { + testHas(); + testGet(); + testGetAll(); + testDelete(); + testSet(); + testFilename(); + testIterable(); + // Finally, send an XHR and verify the response matches. + testSend(doneCb); +} diff --git a/dom/html/test/formData_worker.js b/dom/html/test/formData_worker.js new file mode 100644 index 0000000000..750522fbfa --- /dev/null +++ b/dom/html/test/formData_worker.js @@ -0,0 +1,23 @@ +function ok(a, msg) { + postMessage({ type: "status", status: !!a, msg: a + ": " + msg }); +} + +function is(a, b, msg) { + postMessage({ + type: "status", + status: a === b, + msg: a + " === " + b + ": " + msg, + }); +} + +function todo(a, msg) { + postMessage({ type: "todo", status: !!a, msg: a + ": " + msg }); +} + +importScripts("formData_test.js"); + +onmessage = function () { + runTest(function () { + postMessage({ type: "finish" }); + }); +}; diff --git a/dom/html/test/formSubmission_chrome.js b/dom/html/test/formSubmission_chrome.js new file mode 100644 index 0000000000..da1224d107 --- /dev/null +++ b/dom/html/test/formSubmission_chrome.js @@ -0,0 +1,20 @@ +/* eslint-env mozilla/chrome-script */ + +// eslint-disable-next-line mozilla/reject-importGlobalProperties +Cu.importGlobalProperties(["File"]); + +addMessageListener("files.open", function (message) { + let list = []; + let promises = []; + for (let path of message) { + promises.push( + File.createFromFileName(path).then(file => { + list.push(file); + }) + ); + } + + Promise.all(promises).then(() => { + sendAsyncMessage("files.opened", list); + }); +}); diff --git a/dom/html/test/form_data_file.bin b/dom/html/test/form_data_file.bin new file mode 100644 index 0000000000..744bde3558 --- /dev/null +++ b/dom/html/test/form_data_file.bin @@ -0,0 +1 @@ + diff --git a/dom/html/test/form_data_file.txt b/dom/html/test/form_data_file.txt new file mode 100644 index 0000000000..81c545efeb --- /dev/null +++ b/dom/html/test/form_data_file.txt @@ -0,0 +1 @@ +1234 diff --git a/dom/html/test/form_submit_server.sjs b/dom/html/test/form_submit_server.sjs new file mode 100644 index 0000000000..553809c01f --- /dev/null +++ b/dom/html/test/form_submit_server.sjs @@ -0,0 +1,86 @@ +const CC = Components.Constructor; +const BinaryInputStream = CC( + "@mozilla.org/binaryinputstream;1", + "nsIBinaryInputStream", + "setInputStream" +); + +function utf8decode(s) { + return decodeURIComponent(escape(s)); +} + +function utf8encode(s) { + return unescape(encodeURIComponent(s)); +} + +function handleRequest(request, response) { + var bodyStream = new BinaryInputStream(request.bodyInputStream); + var result = []; + var requestBody = ""; + while ((bodyAvail = bodyStream.available()) > 0) { + requestBody += bodyStream.readBytes(bodyAvail); + } + + if (request.method == "POST") { + var contentTypeParams = {}; + request + .getHeader("Content-Type") + .split(/\s*\;\s*/) + .forEach(function (s) { + if (s.indexOf("=") >= 0) { + let [name, value] = s.split("="); + contentTypeParams[name] = value; + } else { + contentTypeParams[""] = s; + } + }); + + if ( + contentTypeParams[""] == "multipart/form-data" && + request.queryString == "" + ) { + requestBody + .split("--" + contentTypeParams.boundary) + .slice(1, -1) + .forEach(function (s) { + let headers = {}; + let headerEnd = s.indexOf("\r\n\r\n"); + s.substr(2, headerEnd - 2) + .split("\r\n") + .forEach(function (str) { + // We're assuming UTF8 for now + let [name, value] = str.split(": "); + headers[name] = utf8decode(value); + }); + + let body = s.substring(headerEnd + 4, s.length - 2); + if ( + !headers["Content-Type"] || + headers["Content-Type"] == "text/plain" + ) { + // We're assuming UTF8 for now + body = utf8decode(body); + } + result.push({ headers, body }); + }); + } + if ( + contentTypeParams[""] == "text/plain" && + request.queryString == "plain" + ) { + result = utf8decode(requestBody); + } + if ( + contentTypeParams[""] == "application/x-www-form-urlencoded" && + request.queryString == "url" + ) { + result = requestBody; + } + } else if (request.method == "GET") { + result = request.queryString; + } + + // Send response body + response.setHeader("Content-Type", "text/plain; charset=utf-8", false); + response.write(utf8encode(JSON.stringify(result))); +} diff --git a/dom/html/test/forms/FAIL.html b/dom/html/test/forms/FAIL.html new file mode 100644 index 0000000000..94e1707e85 --- /dev/null +++ b/dom/html/test/forms/FAIL.html @@ -0,0 +1 @@ +FAIL diff --git a/dom/html/test/forms/PASS.html b/dom/html/test/forms/PASS.html new file mode 100644 index 0000000000..7ef22e9a43 --- /dev/null +++ b/dom/html/test/forms/PASS.html @@ -0,0 +1 @@ +PASS diff --git a/dom/html/test/forms/chrome.toml b/dom/html/test/forms/chrome.toml new file mode 100644 index 0000000000..0f49518b9b --- /dev/null +++ b/dom/html/test/forms/chrome.toml @@ -0,0 +1,6 @@ +[DEFAULT] +support-files = ["submit_invalid_file.sjs"] + +["test_autocompleteinfo.html"] + +["test_submit_invalid_file.html"] diff --git a/dom/html/test/forms/file_double_submit.html b/dom/html/test/forms/file_double_submit.html new file mode 100644 index 0000000000..44889f86bc --- /dev/null +++ b/dom/html/test/forms/file_double_submit.html @@ -0,0 +1,11 @@ +<form action="PASS.html" method="POST"><input name="foo"></form> +<button>clicky</button> + +<script> +document.querySelector("button") + .addEventListener("click", () => { + let f = document.querySelector("form"); + f.dispatchEvent(new Event("submit")); + f.submit(); + }); +</script> diff --git a/dom/html/test/forms/file_login_fields.html b/dom/html/test/forms/file_login_fields.html new file mode 100644 index 0000000000..f23ee0ad6a --- /dev/null +++ b/dom/html/test/forms/file_login_fields.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> + <head> + <script> + // Add an unload listener to bypass bfcache. + window.addEventListner("unload", _ => _); + </script> + </head> + <body> + <input id="un" /> + <input id="pw1" type="password" /> + <input id="pw2" /> + <a id="navigate" href="?navigated">Navigate</a> + <a id="back" href="javascript:history.back()">Back</a> + </body> +</html> diff --git a/dom/html/test/forms/mochitest.toml b/dom/html/test/forms/mochitest.toml new file mode 100644 index 0000000000..80d6d3530f --- /dev/null +++ b/dom/html/test/forms/mochitest.toml @@ -0,0 +1,229 @@ +[DEFAULT] +support-files = [ + "save_restore_radio_groups.sjs", + "test_input_number_data.js", + "!/dom/html/test/reflect.js", + "FAIL.html", + "PASS.html", +] +prefs = ["formhelper.autozoom.force-disable.test-only=true"] + +["test_MozEditableElement_setUserInput.html"] + +["test_autocomplete.html"] + +["test_bug1039548.html"] + +["test_bug1283915.html"] + +["test_bug1286509.html"] + +["test_button_attributes_reflection.html"] + +["test_change_event.html"] + +["test_datalist_element.html"] + +["test_double_submit.html"] +support-files = ["file_double_submit.html"] + +["test_form_attribute-1.html"] + +["test_form_attribute-2.html"] + +["test_form_attribute-3.html"] + +["test_form_attribute-4.html"] + +["test_form_attributes_reflection.html"] + +["test_form_named_getter_dynamic.html"] + +["test_formaction_attribute.html"] + +["test_formnovalidate_attribute.html"] + +["test_input_attributes_reflection.html"] + +["test_input_color_input_change_events.html"] + +["test_input_color_picker_datalist.html"] + +["test_input_color_picker_initial.html"] + +["test_input_color_picker_popup.html"] + +["test_input_color_picker_update.html"] + +["test_input_date_bad_input.html"] + +["test_input_date_key_events.html"] + +["test_input_datetime_calendar_button.html"] + +["test_input_datetime_disabled_focus.html"] + +["test_input_datetime_focus_blur.html"] + +["test_input_datetime_focus_blur_events.html"] + +["test_input_datetime_focus_state.html"] + +["test_input_datetime_hidden.html"] + +["test_input_datetime_input_change_events.html"] + +["test_input_datetime_readonly.html"] + +["test_input_datetime_reset_default_value_input_change_event.html"] + +["test_input_datetime_tabindex.html"] + +["test_input_defaultValue.html"] + +["test_input_email.html"] + +["test_input_event.html"] + +["test_input_file_picker.html"] + +["test_input_hasBeenTypePassword.html"] + +["test_input_hasBeenTypePassword_navigation.html"] +support-files = ["file_login_fields.html"] + +["test_input_list_attribute.html"] + +["test_input_number_focus.html"] + +["test_input_number_key_events.html"] + +["test_input_number_l10n.html"] + +["test_input_number_mouse_events.html"] +# Not run on Firefox for Android where the spin buttons are hidden: +skip-if = [ + "os == 'android'", + "os == 'mac' && debug", # Bug 1484442 +] + +["test_input_number_placeholder_shown.html"] + +["test_input_number_rounding.html"] + +["test_input_number_validation.html"] + +["test_input_password_click_show_password_button.html"] + +["test_input_password_show_password_button.html"] + +["test_input_radio_indeterminate.html"] + +["test_input_radio_radiogroup.html"] + +["test_input_radio_required.html"] + +["test_input_range_attr_order.html"] + +["test_input_range_key_events.html"] + +["test_input_range_mouse_and_touch_events.html"] + +["test_input_range_rounding.html"] + +["test_input_sanitization.html"] + +["test_input_setting_value.html"] + +["test_input_textarea_set_value_no_scroll.html"] + +["test_input_time_key_events.html"] + +["test_input_time_sec_millisec_field.html"] + +["test_input_types_pref.html"] + +["test_input_typing_sanitization.html"] + +["test_input_untrusted_key_events.html"] + +["test_input_url.html"] + +["test_interactive_content_in_label.html"] + +["test_interactive_content_in_summary.html"] + +["test_label_control_attribute.html"] + +["test_label_input_controls.html"] + +["test_max_attribute.html"] + +["test_maxlength_attribute.html"] + +["test_meter_element.html"] + +["test_meter_pseudo-classes.html"] + +["test_min_attribute.html"] + +["test_minlength_attribute.html"] + +["test_mozistextfield.html"] + +["test_novalidate_attribute.html"] + +["test_option_disabled.html"] + +["test_option_index_attribute.html"] + +["test_option_text.html"] + +["test_output_element.html"] + +["test_pattern_attribute.html"] + +["test_preserving_metadata_between_reloads.html"] + +["test_progress_element.html"] + +["test_radio_in_label.html"] + +["test_radio_radionodelist.html"] + +["test_reportValidation_preventDefault.html"] + +["test_required_attribute.html"] + +["test_restore_form_elements.html"] + +["test_save_restore_custom_elements.html"] +support-files = ["save_restore_custom_elements_sample.html"] + +["test_save_restore_radio_groups.html"] + +["test_select_change_event.html"] +skip-if = ["os == 'mac'"] + +["test_select_input_change_event.html"] +skip-if = ["os == 'mac'"] + +["test_select_selectedOptions.html"] + +["test_select_validation.html"] + +["test_set_range_text.html"] + +["test_step_attribute.html"] + +["test_stepup_stepdown.html"] + +["test_textarea_attributes_reflection.html"] + +["test_validation.html"] + +["test_validation_not_in_doc.html"] + +["test_valueasdate_attribute.html"] + +["test_valueasnumber_attribute.html"] diff --git a/dom/html/test/forms/save_restore_custom_elements_sample.html b/dom/html/test/forms/save_restore_custom_elements_sample.html new file mode 100644 index 0000000000..75dc4c388d --- /dev/null +++ b/dom/html/test/forms/save_restore_custom_elements_sample.html @@ -0,0 +1,43 @@ +<script> + class CEBase extends HTMLElement { + static formAssociated = true; + constructor() { + super(); + this.internals = this.attachInternals(); + this.state_ = undefined; + } + formStateRestoreCallback(state, reason) { + if (reason == "restore") { + this.state_ = state; + } + } + set(state, value) { + this.state_ = state; + this.value_ = value; + this.internals.setFormValue(value, state); + } + get state() { + return this.state_; + } + get value() { + return this.value_; + } + } + + customElements.define("c-e", class extends CEBase {}); +</script> +<form> + <c-e id="custom0"></c-e> + <c-e id="custom1"></c-e> + <c-e id="custom2"></c-e> + <c-e id="custom3"></c-e> + <c-e id="custom4"></c-e> + <upgraded-ce id="upgraded0"></upgraded-ce> + <upgraded-ce id="upgraded1"></upgraded-ce> + <upgraded-ce id="upgraded2"></upgraded-ce> + <upgraded-ce id="upgraded3"></upgraded-ce> + <upgraded-ce id="upgraded4"></upgraded-ce> +</form> +<script> + customElements.define("upgraded-ce", class extends CEBase {}); +</script> diff --git a/dom/html/test/forms/save_restore_radio_groups.sjs b/dom/html/test/forms/save_restore_radio_groups.sjs new file mode 100644 index 0000000000..b4c9c4401a --- /dev/null +++ b/dom/html/test/forms/save_restore_radio_groups.sjs @@ -0,0 +1,48 @@ +var pages = [ + "<!DOCTYPE html>" + + "<html><body>" + + "<form>" + + "<input name='a' type='radio' checked><input name='a' type='radio'><input name='a' type='radio'>" + + "</form>" + + "</body></html>", + "<!DOCTYPE html>" + + "<html><body>" + + "<form>" + + "<input name='a' type='radio'><input name='a' type='radio' checked><input name='a' type='radio'>" + + "</form>" + + "</body></html>", +]; + +/** + * This SJS is going to send the same page the two first times it will be called + * and another page the two following times. After that, the response will have + * no content. + * The use case is to have two iframes using this SJS and both being reloaded + * once. + */ + +function handleRequest(request, response) { + var counter = +getState("counter"); // convert to number; +"" === 0 + + response.setStatusLine(request.httpVersion, 200, "Ok"); + response.setHeader("Content-Type", "text/html"); + response.setHeader("Cache-Control", "no-cache"); + + switch (counter) { + case 0: + case 1: + response.write(pages[0]); + break; + case 2: + case 3: + response.write(pages[1]); + break; + } + + // When we finish the test case we need to reset the counter + if (counter == 3) { + setState("counter", "0"); + } else { + setState("counter", "" + ++counter); + } +} diff --git a/dom/html/test/forms/submit_invalid_file.sjs b/dom/html/test/forms/submit_invalid_file.sjs new file mode 100644 index 0000000000..3b4b576ec6 --- /dev/null +++ b/dom/html/test/forms/submit_invalid_file.sjs @@ -0,0 +1,13 @@ +function handleRequest(request, response) { + response.setStatusLine(request.httpVersion, 200, "Ok"); + response.setHeader("Content-Type", "text/html"); + response.setHeader("Cache-Control", "no-cache"); + + var result = {}; + request.bodyInputStream.search("testfile", true, result, {}); + if (result.value) { + response.write("SUCCESS"); + } else { + response.write("FAIL"); + } +} diff --git a/dom/html/test/forms/test_MozEditableElement_setUserInput.html b/dom/html/test/forms/test_MozEditableElement_setUserInput.html new file mode 100644 index 0000000000..06380776f6 --- /dev/null +++ b/dom/html/test/forms/test_MozEditableElement_setUserInput.html @@ -0,0 +1,581 @@ +<!DOCTYPE> +<html> +<head> + <title>Test for MozEditableElement.setUserInput()</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<div id="display"> +</div> +<div id="content"></div> +<pre id="test"> +</pre> + +<script class="testbody" type="application/javascript"> +SimpleTest.waitForExplicitFinish(); +// eslint-disable-next-line complexity +SimpleTest.waitForFocus(async () => { + const kSetUserInputCancelable = SpecialPowers.getBoolPref("dom.input_event.allow_to_cancel_set_user_input"); + + let content = document.getElementById("content"); + /** + * Test structure: + * element: the tag name to create. + * type: the type attribute value for the element. If unnecessary omit it. + * input: the values calling setUserInput() with. + * before: used when calling setUserInput() before the element gets focus. + * after: used when calling setUserInput() after the element gets focus. + * result: the results of calling setUserInput(). + * before: the element's expected value of calling setUserInput() before the element gets focus. + * after: the element's expected value of calling setUserInput() after the element gets focus. + * fireBeforeInputEvent: true if "beforeinput" event should be fired. Otherwise, false. + * fireInputEvent: true if "input" event should be fired. Otherwise, false. + */ + for (let test of [{element: "input", type: "hidden", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: false}}, + {element: "input", type: "text", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: true, fireInputEvent: true}}, + {element: "input", type: "search", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: true, fireInputEvent: true}}, + {element: "input", type: "tel", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: true, fireInputEvent: true}}, + {element: "input", type: "url", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: true, fireInputEvent: true}}, + {element: "input", type: "email", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: true, fireInputEvent: true}}, + {element: "input", type: "password", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: true, fireInputEvent: true}}, + // "date" does not support setUserInput, but dispatches "input" event... + {element: "input", type: "date", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: true}}, + // "month" does not support setUserInput, but dispatches "input" event... + {element: "input", type: "month", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: true}}, + // "week" does not support setUserInput, but dispatches "input" event... + {element: "input", type: "week", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: true}}, + // "time" does not support setUserInput, but dispatches "input" event... + {element: "input", type: "time", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: true}}, + // "datetime-local" does not support setUserInput, but dispatches "input" event... + {element: "input", type: "datetime-local", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: true}}, + {element: "input", type: "number", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: true, fireInputEvent: true}}, + {element: "input", type: "range", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: true}}, + // "color" does not support setUserInput, but dispatches "input" event... + {element: "input", type: "color", + input: {before: "#5C5C5C", after: "#FFFFFF"}, + result: {before: "#5c5c5c", after:"#ffffff", fireBeforeInputEvent: false, fireInputEvent: true}}, + {element: "input", type: "checkbox", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: true}}, + {element: "input", type: "radio", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: true}}, + // "file" is not supported by setUserInput? But there is a path... + {element: "input", type: "file", + input: {before: "3", after: "6"}, + result: {before: "", after:"", fireBeforeInputEvent: false, fireInputEvent: true}}, + {element: "input", type: "submit", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: false}}, + {element: "input", type: "image", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: false}}, + {element: "input", type: "reset", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: false}}, + {element: "input", type: "button", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: false, fireInputEvent: false}}, + {element: "textarea", + input: {before: "3", after: "6"}, + result: {before: "3", after:"6", fireBeforeInputEvent: true, fireInputEvent: true}}]) { + let tag = + test.type !== undefined ? `<${test.element} type="${test.type}">` : + `<${test.element}>`; + content.innerHTML = + test.element !== "input" ? tag : `${tag}</${test.element}>`; + content.scrollTop; // Flush pending layout. + let target = content.firstChild; + + let inputEvents = [], beforeInputEvents = []; + function onBeforeInput(aEvent) { + beforeInputEvents.push(aEvent); + } + function onInput(aEvent) { + inputEvents.push(aEvent); + } + target.addEventListener("beforeinput", onBeforeInput); + target.addEventListener("input", onInput); + + // Before setting focus, editor of the element may have not been created yet. + let previousValue = target.value; + SpecialPowers.wrap(target).setUserInput(test.input.before); + if (target.value == previousValue && test.result.before != previousValue) { + todo_is(target.value, test.result.before, `setUserInput("${test.input.before}") before ${tag} gets focus should set its value to "${test.result.before}"`); + } else { + is(target.value, test.result.before, `setUserInput("${test.input.before}") before ${tag} gets focus should set its value to "${test.result.before}"`); + } + if (target.value == previousValue) { + if (test.type === "date" || test.type === "time" || test.type === "datetime-local") { + todo_is(inputEvents.length, 0, + `No "input" event should be dispatched when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + } else { + is(inputEvents.length, 0, + `No "input" event should be dispatched when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + } + } else { + if (!test.result.fireBeforeInputEvent) { + is(beforeInputEvents.length, 0, + `No "beforeinput" event should be dispatched when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + } else { + is(beforeInputEvents.length, 1, + `Only one "beforeinput" event should be dispatched when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + } + if (!test.result.fireInputEvent) { + // HTML spec defines that "input" elements whose type are "hidden", + // "submit", "image", "reset" and "button" shouldn't fire input event + // when its value is changed. + // XXX Perhaps, we shouldn't support setUserInput() with such types. + if (test.type === "hidden" || + test.type === "submit" || + test.type === "image" || + test.type === "reset" || + test.type === "button") { + todo_is(inputEvents.length, 0, + `No "input" event should be dispatched when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + } else { + is(inputEvents.length, 0, + `No "input" event should be dispatched when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + } + } else { + is(inputEvents.length, 1, + `Only one "input" event should be dispatched when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + } + } + if (inputEvents.length) { + if (SpecialPowers.wrap(target).isInputEventTarget) { + if (test.type === "time") { + todo(inputEvents[0] instanceof InputEvent, + `"input" event should be dispatched with InputEvent interface when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + } else { + if (beforeInputEvents.length && test.result.fireBeforeInputEvent) { + is(beforeInputEvents[0].cancelable, kSetUserInputCancelable, + `"beforeinput" event for "insertReplacementText" should be cancelable when setUserInput("${test.input.before}") is called before ${tag} gets focus unless it's suppressed by the pref`); + is(beforeInputEvents[0].inputType, "insertReplacementText", + `inputType of "beforeinput"event should be "insertReplacementText" when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + is(beforeInputEvents[0].data, test.input.before, + `data of "beforeinput" event should be "${test.input.before}" when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + is(beforeInputEvents[0].dataTransfer, null, + `dataTransfer of "beforeinput" event should be null when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + is(beforeInputEvents[0].getTargetRanges().length, 0, + `getTargetRanges() of "beforeinput" event should return empty array when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + } + ok(inputEvents[0] instanceof InputEvent, + `"input" event should be dispatched with InputEvent interface when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + is(inputEvents[0].inputType, "insertReplacementText", + `inputType of "input" event should be "insertReplacementText" when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + is(inputEvents[0].data, test.input.before, + `data of "input" event should be "${test.input.before}" when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + is(inputEvents[0].dataTransfer, null, + `dataTransfer of "input" event should be null when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + is(inputEvents[0].getTargetRanges().length, 0, + `getTargetRanges() of "input" event should return empty array when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + } + } else { + ok(inputEvents[0] instanceof Event && !(inputEvents[0] instanceof UIEvent), + `"input" event should be dispatched with Event interface when setUserInput("${test.input.before}") is called before ${tag} gets focus`); + } + is(inputEvents[0].cancelable, false, + `"input" event should be never cancelable (${tag}, before getting focus)`); + is(inputEvents[0].bubbles, true, + `"input" event should always bubble (${tag}, before getting focus)`); + } + + beforeInputEvents = []; + inputEvents = []; + target.focus(); + previousValue = target.value; + SpecialPowers.wrap(target).setUserInput(test.input.after); + if (target.value == previousValue && test.result.after != previousValue) { + todo_is(target.value, test.result.after, `setUserInput("${test.input.after}") after ${tag} gets focus should set its value to "${test.result.after}"`); + } else { + is(target.value, test.result.after, `setUserInput("${test.input.after}") after ${tag} gets focus should set its value to "${test.result.after}"`); + } + if (target.value == previousValue) { + if (test.type === "date" || test.type === "time" || test.type === "datetime-local") { + todo_is(inputEvents.length, 0, + `No "input" event should be dispatched when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + } else { + is(inputEvents.length, 0, + `No "input" event should be dispatched when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + } + } else { + if (!test.result.fireBeforeInputEvent) { + is(beforeInputEvents.length, 0, + `No "beforeinput" event should be dispatched when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + } else { + is(beforeInputEvents.length, 1, + `Only one "beforeinput" event should be dispatched when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + } + if (!test.result.fireInputEvent) { + // HTML spec defines that "input" elements whose type are "hidden", + // "submit", "image", "reset" and "button" shouldn't fire input event + // when its value is changed. + // XXX Perhaps, we shouldn't support setUserInput() with such types. + if (test.type === "hidden" || + test.type === "submit" || + test.type === "image" || + test.type === "reset" || + test.type === "button") { + todo_is(inputEvents.length, 0, + `No "input" event should be dispatched when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + } else { + is(inputEvents.length, 0, + `No "input" event should be dispatched when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + } + } else { + is(inputEvents.length, 1, + `Only one "input" event should be dispatched when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + } + } + if (inputEvents.length) { + if (SpecialPowers.wrap(target).isInputEventTarget) { + if (test.type === "time") { + todo(inputEvents[0] instanceof InputEvent, + `"input" event should be dispatched with InputEvent interface when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + } else { + if (beforeInputEvents.length && test.result.fireBeforeInputEvent) { + is(beforeInputEvents[0].cancelable, kSetUserInputCancelable, + `"beforeinput" event should be cancelable when setUserInput("${test.input.after}") is called after ${tag} gets focus unless it's suppressed by the pref`); + is(beforeInputEvents[0].inputType, "insertReplacementText", + `inputType of "beforeinput" event should be "insertReplacementText" when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + is(beforeInputEvents[0].data, test.input.after, + `data of "beforeinput" should be "${test.input.after}" when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + is(beforeInputEvents[0].dataTransfer, null, + `dataTransfer of "beforeinput" should be null when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + is(beforeInputEvents[0].getTargetRanges().length, 0, + `getTargetRanges() of "beforeinput" should return empty array when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + } + ok(inputEvents[0] instanceof InputEvent, + `"input" event should be dispatched with InputEvent interface when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + is(inputEvents[0].inputType, "insertReplacementText", + `inputType of "input" event should be "insertReplacementText" when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + is(inputEvents[0].data, test.input.after, + `data of "input" event should be "${test.input.after}" when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + is(inputEvents[0].dataTransfer, null, + `dataTransfer of "input" event should be null when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + is(inputEvents[0].getTargetRanges().length, 0, + `getTargetRanges() of "input" event should return empty array when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + } + } else { + ok(inputEvents[0] instanceof Event && !(inputEvents[0] instanceof UIEvent), + `"input" event should be dispatched with Event interface when setUserInput("${test.input.after}") is called after ${tag} gets focus`); + } + is(inputEvents[0].cancelable, false, + `"input" event should be never cancelable (${tag}, after getting focus)`); + is(inputEvents[0].bubbles, true, + `"input" event should always bubble (${tag}, after getting focus)`); + } + + target.removeEventListener("input", onInput); + } + + function testValidationMessage(aType, aInvalidValue, aValidValue) { + let tag = `<input type="${aType}">` + content.innerHTML = tag; + content.scrollTop; // Flush pending layout. + let target = content.firstChild; + + let inputEvents = []; + let validationMessage = ""; + + function reset() { + inputEvents = []; + validationMessage = ""; + } + + function onInput(aEvent) { + inputEvents.push(aEvent); + validationMessage = aEvent.target.validationMessage; + } + target.addEventListener("input", onInput); + + reset(); + SpecialPowers.wrap(target).setUserInput(aInvalidValue); + is(inputEvents.length, 1, + `Only one "input" event should be dispatched when setUserInput("${aInvalidValue}") is called before ${tag} gets focus`); + isnot(validationMessage, "", + `${tag}.validationMessage should not be empty when setUserInput("${aInvalidValue}") is called before ${tag} gets focus`); + ok(target.matches(":invalid"), + `The target should have invalid pseudo class when setUserInput("${aInvalidValue}") is called before ${tag} gets focus`); + + reset(); + SpecialPowers.wrap(target).setUserInput(aValidValue); + is(inputEvents.length, 1, + `Only one "input" event should be dispatched when setUserInput("${aValidValue}") is called before ${tag} gets focus`); + is(validationMessage, "", + `${tag}.validationMessage should be empty when setUserInput("${aValidValue}") is called before ${tag} gets focus`); + ok(!target.matches(":invalid"), + `The target shouldn't have invalid pseudo class when setUserInput("${aValidValue}") is called before ${tag} gets focus`); + + reset(); + SpecialPowers.wrap(target).setUserInput(aInvalidValue); + is(inputEvents.length, 1, + `Only one "input" event should be dispatched again when setUserInput("${aInvalidValue}") is called before ${tag} gets focus`); + isnot(validationMessage, "", + `${tag}.validationMessage should not be empty again when setUserInput("${aInvalidValue}") is called before ${tag} gets focus`); + ok(target.matches(":invalid"), + `The target should have invalid pseudo class again when setUserInput("${aInvalidValue}") is called before ${tag} gets focus`); + + target.value = ""; + target.focus(); + + reset(); + SpecialPowers.wrap(target).setUserInput(aInvalidValue); + is(inputEvents.length, 1, + `Only one "input" event should be dispatched when setUserInput("${aInvalidValue}") is called after ${tag} gets focus`); + isnot(validationMessage, "", + `${tag}.validationMessage should not be empty when setUserInput("${aInvalidValue}") is called after ${tag} gets focus`); + ok(target.matches(":invalid"), + `The target should have invalid pseudo class when setUserInput("${aInvalidValue}") is called after ${tag} gets focus`); + + reset(); + SpecialPowers.wrap(target).setUserInput(aValidValue); + is(inputEvents.length, 1, + `Only one "input" event should be dispatched when setUserInput("${aValidValue}") is called after ${tag} gets focus`); + is(validationMessage, "", + `${tag}.validationMessage should be empty when setUserInput("${aValidValue}") is called after ${tag} gets focus`); + ok(!target.matches(":invalid"), + `The target shouldn't have invalid pseudo class when setUserInput("${aValidValue}") is called after ${tag} gets focus`); + + reset(); + SpecialPowers.wrap(target).setUserInput(aInvalidValue); + is(inputEvents.length, 1, + `Only one "input" event should be dispatched again when setUserInput("${aInvalidValue}") is called after ${tag} gets focus`); + isnot(validationMessage, "", + `${tag}.validationMessage should not be empty again when setUserInput("${aInvalidValue}") is called after ${tag} gets focus`); + ok(target.matches(":invalid"), + `The target should have invalid pseudo class again when setUserInput("${aInvalidValue}") is called after ${tag} gets focus`); + + target.removeEventListener("input", onInput); + } + testValidationMessage("email", "f", "foo@example.com"); + + function testValueMissing(aType, aValidValue) { + let tag = aType === "textarea" ? "<textarea required>" : `<input type="${aType}" required>`; + content.innerHTML = `${tag}${aType === "textarea" ? "</textarea>" : ""}`; + content.scrollTop; // Flush pending layout. + let target = content.firstChild; + + let inputEvents = [], beforeInputEvents = []; + function reset() { + beforeInputEvents = []; + inputEvents = []; + } + + function onBeforeInput(aEvent) { + aEvent.validity = aEvent.target.checkValidity(); + beforeInputEvents.push(aEvent); + } + function onInput(aEvent) { + aEvent.validity = aEvent.target.checkValidity(); + inputEvents.push(aEvent); + } + target.addEventListener("beforeinput", onBeforeInput); + target.addEventListener("input", onInput); + + reset(); + SpecialPowers.wrap(target).setUserInput(aValidValue); + is(beforeInputEvents.length, 1, `Calling ${tag}.setUserInput(${aValidValue}) should cause a "beforeinput" event (before gets focus)`); + if (beforeInputEvents.length) { + is(beforeInputEvents[0].validity, false, + `The ${tag} should be invalid at "beforeinput" event (before gets focus)`); + } + is(inputEvents.length, 1, `Calling ${tag}.setUserInput(${aValidValue}) should cause a "input" event (before gets focus)`); + if (inputEvents.length) { + is(inputEvents[0].validity, true, + `The ${tag} should be valid at "input" event (before gets focus)`); + } + + target.removeEventListener("beforeinput", onBeforeInput); + target.removeEventListener("input", onInput); + + content.innerHTML = ""; + content.scrollTop; // Flush pending layout. + content.innerHTML = `${tag}${aType === "textarea" ? "</textarea>" : ""}`; + content.scrollTop; // Flush pending layout. + target = content.firstChild; + + target.focus(); + target.addEventListener("beforeinput", onBeforeInput); + target.addEventListener("input", onInput); + + reset(); + SpecialPowers.wrap(target).setUserInput(aValidValue); + is(beforeInputEvents.length, 1, `Calling ${tag}.setUserInput(${aValidValue}) should cause a "beforeinput" event (after gets focus)`); + if (beforeInputEvents.length) { + is(beforeInputEvents[0].validity, false, + `The ${tag} should be invalid at "beforeinput" event (after gets focus)`); + } + is(inputEvents.length, 1, `Calling ${tag}.setUserInput(${aValidValue}) should cause a "input" event (after gets focus)`); + if (inputEvents.length) { + is(inputEvents[0].validity, true, + `The ${tag} should be valid at "input" event (after gets focus)`); + } + + target.removeEventListener("beforeinput", onBeforeInput); + target.removeEventListener("input", onInput); + } + testValueMissing("text", "abc"); + testValueMissing("password", "abc"); + testValueMissing("textarea", "abc"); + testValueMissing("email", "foo@example.com"); + testValueMissing("url", "https://example.com/"); + + function testEditorValueAtEachEvent(aType) { + let tag = aType === "textarea" ? "<textarea>" : `<input type="${aType}">` + let closeTag = aType === "textarea" ? "</textarea>" : ""; + content.innerHTML = `${tag}${closeTag}`; + content.scrollTop; // Flush pending layout. + let target = content.firstChild; + target.value = "Old Value"; + let description = `Setting new value of ${tag} before setting focus: `; + let onBeforeInput = (aEvent) => { + is(target.value, "Old Value", + `${description}The value should not have been modified at "beforeinput" event yet (inputType: "${aEvent.inputType}", data: "${aEvent.data}")`); + }; + let onInput = (aEvent) => { + is(target.value, "New Value", + `${description}The value should have been modified at "input" event (inputType: "${aEvent.inputType}", data: "${aEvent.data}"`); + }; + target.addEventListener("beforeinput", onBeforeInput); + target.addEventListener("input", onInput); + SpecialPowers.wrap(target).setUserInput("New Value"); + + description = `Setting new value of ${tag} after setting focus: `; + target.value = "Old Value"; + target.focus(); + SpecialPowers.wrap(target).setUserInput("New Value"); + + target.removeEventListener("beforeinput", onBeforeInput); + target.removeEventListener("input", onInput); + + // FYI: This is not realistic situation because we should do nothing + // while user composing IME. + // TODO: TextControlState should stop returning setting value as the value + // while committing composition. + description = `Setting new value of ${tag} during composition: `; + target.value = ""; + target.focus(); + synthesizeCompositionChange({ + composition: { + string: "composition string", + clauses: [{length: 18, attr: COMPOSITION_ATTR_RAW_CLAUSE}], + }, + caret: {start: 18, length: 0}, + }); + let onCompositionUpdate = (aEvent) => { + todo_is(target.value, "composition string", + `${description}The value should not have been modified at "compositionupdate" event yet (data: "${aEvent.data}")`); + }; + let onCompositionEnd = (aEvent) => { + todo_is(target.value, "composition string", + `${description}The value should not have been modified at "compositionupdate" event yet (data: "${aEvent.data}")`); + }; + onBeforeInput = (aEvent) => { + if (aEvent.inputType === "insertCompositionText") { + todo_is(target.value, "composition string", + `${description}The value should not have been modified at "beforeinput" event yet (inputType: "${aEvent.inputType}", data: "${aEvent.data}")`); + } else { + is(target.value, "composition string", + `${description}The value should not have been modified at "beforeinput" event yet (inputType: "${aEvent.inputType}", data: "${aEvent.data}")`); + } + }; + onInput = (aEvent) => { + if (aEvent.inputType === "insertCompositionText") { + todo_is(target.value, "composition string", + `${description}The value should not have been modified at "input" event yet (inputType: "${aEvent.inputType}", data: "${aEvent.data}")`); + } else { + is(target.value, "New Value", + `${description}The value should have been modified at "input" event (inputType: "${aEvent.inputType}", data: "${aEvent.data}"`); + } + }; + target.addEventListener("compositionupdate", onCompositionUpdate); + target.addEventListener("compositionend", onCompositionEnd); + target.addEventListener("beforeinput", onBeforeInput); + target.addEventListener("input", onInput); + SpecialPowers.wrap(target).setUserInput("New Value"); + target.removeEventListener("compositionupdate", onCompositionUpdate); + target.removeEventListener("compositionend", onCompositionEnd); + target.removeEventListener("beforeinput", onBeforeInput); + target.removeEventListener("input", onInput); + } + testEditorValueAtEachEvent("text"); + testEditorValueAtEachEvent("textarea"); + + async function testBeforeInputCancelable(aType) { + let tag = aType === "textarea" ? "<textarea>" : `<input type="${aType}">` + let closeTag = aType === "textarea" ? "</textarea>" : ""; + for (const kShouldBeCancelable of [true, false]) { + await SpecialPowers.pushPrefEnv({ + set: [["dom.input_event.allow_to_cancel_set_user_input", kShouldBeCancelable]], + }); + + content.innerHTML = `${tag}${closeTag}`; + content.scrollTop; // Flush pending layout. + let target = content.firstChild; + target.value = "Old Value"; + let description = `Setting new value of ${tag} before setting focus (the pref ${kShouldBeCancelable ? "allows" : "disallows"} to cancel beforeinput): `; + let onBeforeInput = (aEvent) => { + is(aEvent.cancelable, kShouldBeCancelable, + `${description}The "beforeinput" event should be ${kShouldBeCancelable ? "cancelable" : "not be cancelable due to suppressed by the pref"}`); + }; + let onInput = (aEvent) => { + is(aEvent.cancelable, false, + `${description}The value should have been modified at "input" event (inputType: "${aEvent.inputType}", data: "${aEvent.data}"`); + }; + target.addEventListener("beforeinput", onBeforeInput); + target.addEventListener("input", onInput); + SpecialPowers.wrap(target).setUserInput("New Value"); + + description = `Setting new value of ${tag} after setting focus (the pref ${kShouldBeCancelable ? "allows" : "disallows"} to cancel beforeinput): `; + target.value = "Old Value"; + target.focus(); + SpecialPowers.wrap(target).setUserInput("New Value"); + + target.removeEventListener("beforeinput", onBeforeInput); + target.removeEventListener("input", onInput); + } + + await SpecialPowers.clearUserPref({ + clear: [["dom.input_event.allow_to_cancel_set_user_input"]], + }); + } + await testBeforeInputCancelable("text"); + await testBeforeInputCancelable("textarea"); + + SimpleTest.finish(); +}); +</script> +</body> +</html> diff --git a/dom/html/test/forms/test_autocomplete.html b/dom/html/test/forms/test_autocomplete.html new file mode 100644 index 0000000000..c98be94eea --- /dev/null +++ b/dom/html/test/forms/test_autocomplete.html @@ -0,0 +1,164 @@ +<!DOCTYPE html> +<html> +<!-- +Test @autocomplete on <input>/<select>/<textarea> +--> +<head> + <title>Test for @autocomplete</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +<script> +"use strict"; + +var values = [ + // @autocomplete content attribute, expected IDL attribute value + + // Missing or empty attribute + [undefined, ""], + ["", ""], + + // One token + ["on", "on"], + ["On", "on"], + ["off", "off"], + ["OFF", "off"], + ["name", "name"], + [" name ", "name"], + ["username", "username"], + [" username ", "username"], + ["cc-csc", ""], + ["one-time-code", ""], + ["language", ""], + [" language ", ""], + ["tel-extension", ""], + ["foobar", ""], + ["section-blue", ""], + [" WEBAUTHN ", "webauthn"], + + // One token + WebAuthn credential type + ["on webauthn", ""], + ["off webauthn", ""], + ["webauthn webauthn", ""], + ["username WebAuthn", "username webauthn"], + ["current-PASSWORD webauthn", "current-password webauthn"], + + // Two tokens + ["on off", ""], + ["off on", ""], + ["username tel", ""], + ["tel username ", ""], + [" username tel ", ""], + ["tel mobile", ""], + ["tel shipping", ""], + ["shipping tel", "shipping tel"], + ["shipPING tel", "shipping tel"], + ["mobile tel", "mobile tel"], + [" MoBiLe TeL ", "mobile tel"], + ["pager impp", ""], + ["fax tel-extension", ""], + ["XXX tel", ""], + ["XXX username", ""], + ["name section-blue", ""], + ["scetion-blue cc-name", ""], + ["pager language", ""], + ["fax url", ""], + ["section-blue name", "section-blue name"], + ["section-blue tel", "section-blue tel"], + ["webauthn username", ""], + + // Two tokens + WebAuthn credential type + ["fax url webauthn", ""], + ["shipping tel webauthn", "shipping tel webauthn"], + + // Three tokens + ["billing invalid tel", ""], + ["___ mobile tel", ""], + ["mobile foo tel", ""], + ["mobile tel foo", ""], + ["tel mobile billing", ""], + ["billing mobile tel", "billing mobile tel"], + [" BILLing MoBiLE tEl ", "billing mobile tel"], + ["billing home tel", "billing home tel"], + ["home section-blue tel", ""], + ["setion-blue work email", ""], + ["section-blue home address-level2", ""], + ["section-blue shipping name", "section-blue shipping name"], + ["section-blue mobile tel", "section-blue mobile tel"], + ["shipping webauthn tel", ""], + + // Three tokens + WebAuthn credential type + ["invalid mobile tel webauthn", ""], + ["section-blue shipping name webauthn", "section-blue shipping name webauthn"], + + // Four tokens + ["billing billing mobile tel", ""], + ["name section-blue shipping home", ""], + ["secti shipping work address-line1", ""], + ["section-blue shipping home name", ""], + ["section-blue shipping mobile tel", "section-blue shipping mobile tel"], + ["section-blue webauthn mobile tel", ""], + + // Four tokens + WebAuthn credential type + ["section-blue shipping home name webauthn", ""], + ["section-blue shipping mobile tel webauthn", "section-blue shipping mobile tel webauthn"], + + // Five tokens (invalid) + ["billing billing billing mobile tel", ""], + ["section-blue section-blue billing mobile tel", ""], + ["section-blue section-blue billing webauthn tel", ""], + + // Five tokens + WebAuthn credential type (invalid) + ["billing billing billing mobile tel webauthn", ""], +]; + +var types = [undefined, "hidden", "text", "search"]; // Valid types for all non-multiline hints. + +function checkAutocompleteValues(field, type) { + for (var test of values) { + if (typeof(test[0]) === "undefined") + field.removeAttribute("autocomplete"); + else + field.setAttribute("autocomplete", test[0]); + is(field.autocomplete, test[1], "Checking @autocomplete for @type=" + type + " of: " + test[0]); + is(field.autocomplete, test[1], "Checking cached @autocomplete for @type=" + type + " of: " + test[0]); + } +} + +function start() { + var inputField = document.getElementById("input-field"); + for (var type of types) { + // Switch the input type + if (typeof(type) === "undefined") + inputField.removeAttribute("type"); + else + inputField.type = type; + checkAutocompleteValues(inputField, type || ""); + } + + var selectField = document.getElementById("select-field"); + checkAutocompleteValues(selectField, "select"); + + var textarea = document.getElementById("textarea"); + checkAutocompleteValues(textarea, "textarea"); + + SimpleTest.finish(); +} + +SimpleTest.waitForExplicitFinish(); +SpecialPowers.pushPrefEnv({"set": [["dom.forms.autocomplete.formautofill", true]]}, start); +</script> +</head> + +<body> +<p id="display"></p> +<div id="content" style="display: none"> + <form> + <input id="input-field" /> + <select id="select-field" /> + <textarea id="textarea"></textarea> + </form> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_autocompleteinfo.html b/dom/html/test/forms/test_autocompleteinfo.html new file mode 100644 index 0000000000..a3357ac8de --- /dev/null +++ b/dom/html/test/forms/test_autocompleteinfo.html @@ -0,0 +1,206 @@ +<!DOCTYPE html> +<html> +<!-- +Test getAutocompleteInfo() on <input> and <select> +--> +<head> + <title>Test for getAutocompleteInfo()</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> +</head> + +<body> +<p id="display"></p> +<div id="content" style="display: none"> + <form> + <input id="input"/> + <select id="select" /> + </form> +</div> +<pre id="test"> +<script> +"use strict"; + +var values = [ + // Missing or empty attribute + [undefined, {}, ""], + ["", {}, ""], + + // One token + ["on", {fieldName: "on" }, "on"], + ["On", {fieldName: "on" }, "on"], + ["off", {fieldName: "off", canAutomaticallyPersist: false}, "off" ], + ["name", {fieldName: "name" }, "name"], + [" name ", {fieldName: "name" }, "name"], + ["username", {fieldName: "username"}, "username"], + [" username ", {fieldName: "username"}, "username"], + ["current-password", {fieldName: "current-password", canAutomaticallyPersist: false}, "current-password"], + ["new-password", {fieldName: "new-password", canAutomaticallyPersist: false}, "new-password"], + ["cc-number", {fieldName: "cc-number", canAutomaticallyPersist: false}, "cc-number"], + ["cc-csc", {fieldName: "cc-csc", canAutomaticallyPersist: false}, ""], + ["one-time-code", {fieldName: "one-time-code", canAutomaticallyPersist: false}, ""], + ["language", {fieldName: "language"}, ""], + [" language ", {fieldName: "language"}, ""], + ["tel-extension", {fieldName: "tel-extension"}, ""], + ["foobar", {}, ""], + ["section-blue", {}, ""], + [" WEBAUTHN ", {fieldName: "webauthn", credentialType: "webauthn"}, "webauthn"], + + // One token + WebAuthn credential type + ["on webauthn", {}, ""], + ["off webauthn", {}, ""], + ["webauthn webauthn", {}, ""], + ["username WebAuthn", {fieldName: "username", credentialType: "webauthn"}, "username webauthn"], + ["current-PASSWORD webauthn", {fieldName: "current-password", credentialType: "webauthn", canAutomaticallyPersist: false}, "current-password webauthn"], + + // Two tokens + ["on off", {}, ""], + ["off on", {}, ""], + ["username tel", {}, ""], + ["tel username ", {}, ""], + [" username tel ", {}, ""], + ["tel mobile", {}, ""], + ["tel shipping", {}, ""], + ["shipping tel", {addressType: "shipping", fieldName: "tel"}, "shipping tel"], + ["shipPING tel", {addressType: "shipping", fieldName: "tel"}, "shipping tel"], + ["mobile tel", {contactType: "mobile", fieldName: "tel"}, "mobile tel"], + [" MoBiLe TeL ", {contactType: "mobile", fieldName: "tel"}, "mobile tel"], + ["pager impp", {contactType: "pager", fieldName: "impp"}, ""], + ["fax tel-extension", {contactType: "fax", fieldName: "tel-extension"}, ""], + ["XXX tel", {}, ""], + ["XXX username", {}, ""], + ["name section-blue", {}, ""], + ["scetion-blue cc-name", {}, ""], + ["pager language", {}, ""], + ["fax url", {}, ""], + ["section-blue name", {section: "section-blue", fieldName: "name"}, "section-blue name"], + ["section-blue tel", {section: "section-blue", fieldName: "tel"}, "section-blue tel"], + ["webauthn username", {}, ""], + + // Two tokens + WebAuthn credential type + ["fax url webauthn", {}, ""], + ["shipping tel webauthn", {addressType: "shipping", fieldName: "tel", credentialType: "webauthn"}, "shipping tel webauthn"], + + // Three tokens + ["billing invalid tel", {}, ""], + ["___ mobile tel", {}, ""], + ["mobile foo tel", {}, ""], + ["mobile tel foo", {}, ""], + ["tel mobile billing", {}, ""], + ["billing mobile tel", {addressType: "billing", contactType: "mobile", fieldName: "tel"}, "billing mobile tel"], + [" BILLing MoBiLE tEl ", {addressType: "billing", contactType: "mobile", fieldName: "tel"}, "billing mobile tel"], + ["billing home tel", {addressType: "billing", contactType: "home", fieldName: "tel"}, "billing home tel"], + ["home section-blue tel", {}, ""], + ["setion-blue work email", {}, ""], + ["section-blue home address-level2", {}, ""], + ["section-blue shipping name", {section: "section-blue", addressType: "shipping", fieldName: "name"}, "section-blue shipping name"], + ["section-blue mobile tel", {section: "section-blue", contactType: "mobile", fieldName: "tel"}, "section-blue mobile tel"], + ["shipping webauthn tel", {}, ""], + + // Three tokens + WebAuthn credential type + ["invalid mobile tel webauthn", {}, ""], + ["section-blue shipping name webauthn", {section: "section-blue", addressType: "shipping", fieldName: "name", credentialType: "webauthn"}, "section-blue shipping name webauthn"], + + // Four tokens + ["billing billing mobile tel", {}, ""], + ["name section-blue shipping home", {}, ""], + ["secti shipping work address-line1", {}, ""], + ["section-blue shipping home name", {}, ""], + ["section-blue shipping mobile tel", {section: "section-blue", addressType: "shipping", contactType: "mobile", fieldName: "tel"}, "section-blue shipping mobile tel"], + ["section-blue webauthn mobile tel", {}, ""], + + // Four tokens + WebAuthn credential type + ["section-blue shipping home name webauthn", {}, ""], + ["section-blue shipping mobile tel webauthn", {section: "section-blue", addressType: "shipping", contactType: "mobile", fieldName: "tel", credentialType: "webauthn"}, "section-blue shipping mobile tel webauthn"], + + // Five tokens (invalid) + ["billing billing billing mobile tel", {}, ""], + ["section-blue section-blue billing mobile tel", {}, ""], + ["section-blue section-blue billing webauthn tel", {}, ""], + + // Five tokens + WebAuthn credential type (invalid) + ["billing billing billing mobile tel webauthn", {}, ""], +]; + +var autocompleteInfoFieldIds = ["input", "select"]; +var autocompleteEnabledTypes = ["hidden", "text", "search", "url", "tel", + "email", "password", "date", "time", "number", + "range", "color"]; +var autocompleteDisabledTypes = ["reset", "submit", "image", "button", "radio", + "checkbox", "file"]; + +function testInputTypes() { + let field = document.getElementById("input"); + + for (var type of autocompleteEnabledTypes) { + testAutocomplete(field, type, true); + } + + for (var type of autocompleteDisabledTypes) { + testAutocomplete(field, type, false); + } + + // Clear input type attribute. + field.removeAttribute("type"); +} + +function testAutocompleteInfoValue(aEnabled) { + for (var fieldId of autocompleteInfoFieldIds) { + let field = document.getElementById(fieldId); + + for (var test of values) { + if (typeof(test[0]) === "undefined") + field.removeAttribute("autocomplete"); + else + field.setAttribute("autocomplete", test[0]); + + var info = field.getAutocompleteInfo(); + if (aEnabled) { + // We need to consider if getAutocompleteInfo() is valid, + // but @autocomplete is invalid case, because @autocomplete + // has smaller set of values. + is(field.autocomplete, test[2], "Checking @autocomplete of: " + test[0]); + } + + is(info.section, "section" in test[1] ? test[1].section : "", + "Checking autocompleteInfo.section for " + field + ": " + test[0]); + is(info.addressType, "addressType" in test[1] ? test[1].addressType : "", + "Checking autocompleteInfo.addressType for " + field + ": " + test[0]); + is(info.contactType, "contactType" in test[1] ? test[1].contactType : "", + "Checking autocompleteInfo.contactType for " + field + ": " + test[0]); + is(info.fieldName, "fieldName" in test[1] ? test[1].fieldName : "", + "Checking autocompleteInfo.fieldName for " + field + ": " + test[0]); + is(info.credentialType, "credentialType" in test[1] ? test[1].credentialType: "", + "Checking autocompleteInfo.credentialType for " + field + ": " + test[0]); + is(info.canAutomaticallyPersist, "canAutomaticallyPersist" in test[1] ? test[1].canAutomaticallyPersist : true, + "Checking autocompleteInfo.canAutomaticallyPersist for " + field + ": " + test[0]); + } + } +} + +function testAutocomplete(aField, aType, aEnabled) { + aField.type = aType; + if (aEnabled) { + ok(aField.getAutocompleteInfo() !== null, "getAutocompleteInfo shouldn't return null"); + } else { + is(aField.getAutocompleteInfo(), null, "getAutocompleteInfo should return null"); + } +} + +// getAutocompleteInfo() should be able to parse all tokens as defined +// in the spec regardless of whether dom.forms.autocomplete.formautofill pref +// is on or off. +add_task(async function testAutocompletePreferenceEnabled() { + await SpecialPowers.pushPrefEnv({"set": [["dom.forms.autocomplete.formautofill", true]]}, testInputTypes); + testAutocompleteInfoValue(true); +}); + +add_task(async function testAutocompletePreferenceDisabled() { + await SpecialPowers.pushPrefEnv({"set": [["dom.forms.autocomplete.formautofill", false]]}, testInputTypes); + testAutocompleteInfoValue(false); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_bug1039548.html b/dom/html/test/forms/test_bug1039548.html new file mode 100644 index 0000000000..cea3cd67ef --- /dev/null +++ b/dom/html/test/forms/test_bug1039548.html @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1039548 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1039548</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 1039548 **/ + + SimpleTest.waitForExplicitFinish(); + + SimpleTest.waitForFocus(test); + + var didTryToSubmit; + function test() { + var r = document.getElementById("radio"); + r.focus(); + didTryToSubmit = false; + sendKey("return"); + ok(!didTryToSubmit, "Shouldn't have tried to submit!"); + + var t = document.getElementById("text"); + t.focus(); + didTryToSubmit = false; + sendKey("return"); + ok(didTryToSubmit, "Should have tried to submit!"); + SimpleTest.finish(); + } + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1039548">Mozilla Bug 1039548</a> +<p id="display"></p> +<div id="content"> + + <form onsubmit="didTryToSubmit = true; event.preventDefault();"> + <input type="radio" id="radio"> + </form> + + <form onsubmit="didTryToSubmit = true; event.preventDefault();"> + <input type="text" id="text"> + </form> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_bug1283915.html b/dom/html/test/forms/test_bug1283915.html new file mode 100644 index 0000000000..90bffd4b20 --- /dev/null +++ b/dom/html/test/forms/test_bug1283915.html @@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1283915 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1283915</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 1283915 **/ + + SimpleTest.waitForExplicitFinish(); + + function isCursorAtEnd(field){ + is(field.selectionStart, field.value.length); + is(field.selectionEnd, field.value.length); + } + + function test() { + var tField = document.getElementById("textField"); + tField.focus(); + + sendString("a"); + is(tField.value, "a"); + isCursorAtEnd(tField); + document.body.offsetWidth; // frame must be created after type change + + sendString("b"); + is(tField.value, "ab"); + isCursorAtEnd(tField); + + sendString("c"); + is(tField.value, "abc"); + isCursorAtEnd(tField); + + var nField = document.getElementById("numField"); + nField.focus(); + + sendString("1"); + is(nField.value, "1"); + document.body.offsetWidth; + + sendString("2"); + is(nField.value, "12"); + + sendString("3"); + is(nField.value, "123"); + + SimpleTest.finish(); + } + + SimpleTest.waitForFocus(test); + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1283915">Mozilla Bug 1283915</a> +<p id="display"></p> +<input id="textField" type="text" oninput="if (this.type !='password') this.type = 'password';"> +<input id="numField" type="text" oninput="if (this.type !='number') this.type = 'number';"> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_bug1286509.html b/dom/html/test/forms/test_bug1286509.html new file mode 100644 index 0000000000..638e7fe85c --- /dev/null +++ b/dom/html/test/forms/test_bug1286509.html @@ -0,0 +1,49 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1286509 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1286509</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1286509">Mozilla Bug 1286509</a> +<p id="display"></p> +<div id="content"> + <input type="range" id="test_input" min="0" max="10" value="5"> +</div> +<pre id="test"> + <script type="application/javascript"> + /** Test for Bug 1286509 **/ + SimpleTest.waitForExplicitFinish(); + var expectedEventSequence = ['keydown', 'change', 'keyup']; + var eventCounts = {}; + var expectedEventIdx = 0; + + function test() { + var range = document.getElementById("test_input"); + range.focus(); + expectedEventSequence.forEach((eventName) => { + eventCounts[eventName] = 0; + range.addEventListener(eventName, (e) => { + ++eventCounts[eventName]; + is(expectedEventSequence[expectedEventIdx], e.type, "Events sequence should be keydown, change, keyup"); + expectedEventIdx = (expectedEventIdx + 1) % 3; + }); + }); + synthesizeKey("KEY_ArrowUp"); + synthesizeKey("KEY_ArrowDown"); + synthesizeKey("KEY_ArrowLeft"); + synthesizeKey("KEY_ArrowRight"); + is(eventCounts.change, 4, "Expect key up/down/left/right should trigger range input to fire change events"); + SimpleTest.finish(); + } + addLoadEvent(test); + </script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_button_attributes_reflection.html b/dom/html/test/forms/test_button_attributes_reflection.html new file mode 100644 index 0000000000..de2097cb4c --- /dev/null +++ b/dom/html/test/forms/test_button_attributes_reflection.html @@ -0,0 +1,144 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLButtonElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="../reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLButtonElement attributes reflection **/ + +// .autofocus +reflectBoolean({ + element: document.createElement("button"), + attribute: "autofocus", +}); + +// .disabled +reflectBoolean({ + element: document.createElement("button"), + attribute: "disabled", +}); + +// .formAction +reflectURL({ + element: document.createElement("button"), + attribute: "formAction", +}); + +// .formEnctype +reflectLimitedEnumerated({ + element: document.createElement("button"), + attribute: "formEnctype", + validValues: [ + "application/x-www-form-urlencoded", + "multipart/form-data", + "text/plain", + ], + invalidValues: [ "text/html", "", "tulip" ], + defaultValue: { + invalid: "application/x-www-form-urlencoded", + missing: "", + } +}); + +// .formMethod +add_task(async function() { + reflectLimitedEnumerated({ + element: document.createElement("button"), + attribute: "formMethod", + validValues: [ "get", "post", "dialog"], + invalidValues: [ "put", "", "tulip" ], + defaultValue: { + invalid: "get", + missing: "", + } + }); +}); + +// .formNoValidate +reflectBoolean({ + element: document.createElement("button"), + attribute: "formNoValidate", +}); + +// .formTarget +reflectString({ + element: document.createElement("button"), + attribute: "formTarget", + otherValues: [ "_blank", "_self", "_parent", "_top" ], +}); + +// .name +reflectString({ + element: document.createElement("button"), + attribute: "name", + otherValues: [ "isindex", "_charset_" ] +}); + +// .type +reflectLimitedEnumerated({ + element: document.createElement("button"), + attribute: "type", + validValues: [ "submit", "reset", "button" ], + invalidValues: [ "this-is-probably-a-wrong-type", "", "tulip" ], + unsupportedValues: [ "menu" ], + defaultValue: "submit", +}); + +// .value +reflectString({ + element: document.createElement("button"), + attribute: "value", +}); + +// .willValidate +ok("willValidate" in document.createElement("button"), + "willValidate should be an IDL attribute of the button element"); +is(typeof(document.createElement("button").willValidate), "boolean", + "button.willValidate should be a boolean"); + +// .validity +ok("validity" in document.createElement("button"), + "validity should be an IDL attribute of the button element"); +is(typeof(document.createElement("button").validity), "object", + "button.validity should be an object"); +ok(document.createElement("button").validity instanceof ValidityState, + "button.validity sohuld be an instance of ValidityState"); + +// .validationMessage +ok("validationMessage" in document.createElement("button"), + "validationMessage should be an IDL attribute of the button element"); +is(typeof(document.createElement("button").validationMessage), "string", + "button.validationMessage should be a string"); + +// .checkValidity() +ok("checkValidity" in document.createElement("button"), + "checkValidity() should be a method of the button element"); +is(typeof(document.createElement("button").checkValidity), "function", + "button.checkValidity should be a function"); + +// .setCustomValidity() +ok("setCustomValidity" in document.createElement("button"), + "setCustomValidity() should be a method of the button element"); +is(typeof(document.createElement("button").setCustomValidity), "function", + "button.setCustomValidity should be a function"); + +// .labels +ok("labels" in document.createElement("button"), + "button.labels should be an IDL attribute of the button element"); +is(typeof(document.createElement("button").labels), "object", + "button.labels should be an object"); +ok(document.createElement("button").labels instanceof NodeList, + "button.labels sohuld be an instance of NodeList"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_change_event.html b/dom/html/test/forms/test_change_event.html new file mode 100644 index 0000000000..8be4554c58 --- /dev/null +++ b/dom/html/test/forms/test_change_event.html @@ -0,0 +1,286 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=722599 +--> +<head> +<title>Test for Bug 722599</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=722599">Mozilla Bug 722599</a> +<p id="display"></p> +<div id="content"> +<input type="file" id="fileInput"></input> +<textarea id="textarea" onchange="++textareaChange;"></textarea> +<input type="text" id="input_text" onchange="++textInputChange[0];"></input> +<input type="email" id="input_email" onchange="++textInputChange[1];"></input> +<input type="search" id="input_search" onchange="++textInputChange[2];"></input> +<input type="tel" id="input_tel" onchange="++textInputChange[3];"></input> +<input type="url" id="input_url" onchange="++textInputChange[4];"></input> +<input type="password" id="input_password" onchange="++textInputChange[5];"></input> + +<!-- "Non-text" inputs--> +<input type="button" id="input_button" onchange="++NonTextInputChange[0];"></input> +<input type="submit" id="input_submit" onchange="++NonTextInputChange[1];"></input> +<input type="image" id="input_image" onchange="++NonTextInputChange[2];"></input> +<input type="reset" id="input_reset" onchange="++NonTextInputChange[3];"></input> +<input type="radio" id="input_radio" onchange="++NonTextInputChange[4];"></input> +<input type="checkbox" id="input_checkbox" onchange="++NonTextInputChange[5];"></input> +<input type="number" id="input_number" onchange="++numberChange;"></input> +<input type="range" id="input_range" onchange="++rangeChange;"></input> + +<!-- Input text with default value and blurs on focus--> +<input type="text" id="input_text_value" onchange="++textInputValueChange" + onfocus="this.blur();" value="foo"></input> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + + /** Test for Bug 722599 **/ + + const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent); + + var textareaChange = 0; + var fileInputChange = 0; + var textInputValueChange = 0; + + var textInputTypes = ["text", "email", "search", "tel", "url", "password"]; + var textInputChange = [0, 0, 0, 0, 0, 0]; + + var NonTextInputTypes = ["button", "submit", "image", "reset", "radio", "checkbox"]; + var NonTextInputChange = [0, 0, 0, 0, 0, 0]; + + var numberChange = 0; + var rangeChange = 0; + + var blurTestCalled = false; //Sentinel to prevent infinite loop. + + SimpleTest.waitForExplicitFinish(); + var MockFilePicker = SpecialPowers.MockFilePicker; + MockFilePicker.init(window); + + function fileInputBlurTest() { + var btn = document.getElementById('fileInput'); + btn.focus() + btn.blur(); + is(fileInputChange, 1, "change event shouldn't be dispatched on blur for file input element(1)"); + } + + function testUserInput() { + //Simulating an OK click and with a file name return. + MockFilePicker.useBlobFile(); + MockFilePicker.returnValue = MockFilePicker.returnOK; + var input = document.getElementById('fileInput'); + input.focus(); + + input.addEventListener("change", function (aEvent) { + ++fileInputChange; + if (!blurTestCalled) { + is(fileInputChange, 1, "change event should have been dispatched on file input."); + blurTestCalled = true; + fileInputBlurTest(); + } + else { + is(fileInputChange, 1, "change event shouldn't be dispatched on blur for file input element (2)"); + } + }); + input.click(); + // blur the file input, we can't use blur() because of bug 760283 + document.getElementById('input_text').focus(); + setTimeout(testUserInput2, 0); + } + + function testUserInput2() { + var input = document.getElementById('fileInput'); + // remove it, otherwise cleanup() opens a native file picker! + input.remove(); + MockFilePicker.cleanup(); + + //text, email, search, telephone, url & password input tests + for (var i = 0; i < textInputTypes.length; ++i) { + input = document.getElementById("input_" + textInputTypes[i]); + input.focus(); + synthesizeKey("KEY_Enter"); + is(textInputChange[i], 0, "Change event shouldn't be dispatched on " + textInputTypes[i] + " input element"); + + sendString("m"); + synthesizeKey("KEY_Enter"); + is(textInputChange[i], 1, textInputTypes[i] + " input element should have dispatched change event."); + } + + //focus and blur text input + input = document.getElementById("input_text"); + input.focus(); + sendString("f"); + input.blur(); + is(textInputChange[0], 2, "text input element should have dispatched change event (2)."); + + // value being set while focused + input.focus(); + input.value = 'foo'; + input.blur(); + is(textInputChange[0], 2, "text input element should not have dispatched change event (2)."); + + // value being set while focused after being modified manually + input.focus(); + sendString("f"); + input.value = 'bar'; + input.blur(); + is(textInputChange[0], 3, "text input element should have dispatched change event (3)."); + + //focus and blur textarea + var textarea = document.getElementById("textarea"); + textarea.focus(); + sendString("f"); + textarea.blur(); + is(textareaChange, 1, "Textarea element should have dispatched change event."); + + // value being set while focused + textarea.focus(); + textarea.value = 'foo'; + textarea.blur(); + is(textareaChange, 1, "textarea should not have dispatched change event (1)."); + + // value being set while focused after being modified manually + textarea.focus(); + sendString("f"); + textarea.value = 'bar'; + textarea.blur(); + is(textareaChange, 2, "textearea should have dispatched change event (2)."); + + //Non-text input tests: + for (var i = 0; i < NonTextInputTypes.length; ++i) { + //button, submit, image and reset input type tests. + if (i < 4) { + input = document.getElementById("input_" + NonTextInputTypes[i]); + input.focus(); + input.click(); + is(NonTextInputChange[i], 0, "Change event shouldn't be dispatched on " + NonTextInputTypes[i] + " input element"); + input.blur(); + is(NonTextInputChange[i], 0, "Change event shouldn't be dispatched on " + NonTextInputTypes[i] + " input element(2)"); + } + //for radio and and checkboxes, we require that change event should ONLY be dispatched on setting the value. + else { + input = document.getElementById("input_" + NonTextInputTypes[i]); + input.focus(); + input.click(); + is(NonTextInputChange[i], 1, NonTextInputTypes[i] + " input element should have dispatched change event."); + input.blur(); + is(NonTextInputChange[i], 1, "Change event shouldn't be dispatched on " + NonTextInputTypes[i] + " input element"); + + // Test that change event is not dispatched if click event is cancelled. + function preventDefault(e) { + e.preventDefault(); + } + input.addEventListener("click", preventDefault); + input.click(); + is(NonTextInputChange[i], 1, "Change event shouldn't be dispatched if click event is cancelled"); + input.removeEventListener("click", preventDefault); + } + } + + // Special case type=number + var number = document.getElementById("input_number"); + number.focus(); + sendString("a"); + number.blur(); + is(numberChange, 0, "Change event shouldn't be dispatched on number input element for key changes that don't change its value"); + number.value = ""; + number.focus(); + sendString("12"); + is(numberChange, 0, "Change event shouldn't be dispatched on number input element for keyboard input until it loses focus"); + number.blur(); + is(numberChange, 1, "Change event should be dispatched on number input element on blur"); + is(number.value, "12", "Sanity check that number keys were actually handled"); + if (isDesktop) { // up/down arrow keys not supported on android/b2g + number.value = ""; + number.focus(); + synthesizeKey("KEY_ArrowUp"); + synthesizeKey("KEY_ArrowUp"); + synthesizeKey("KEY_ArrowDown"); + is(numberChange, 4, "Change event should be dispatched on number input element for up/down arrow keys (a special case)"); + is(number.value, "1", "Sanity check that number and arrow keys were actually handled"); + } + + // Special case type=range + var range = document.getElementById("input_range"); + range.focus(); + sendString("a"); + range.blur(); + is(rangeChange, 0, "Change event shouldn't be dispatched on range input element for key changes that don't change its value"); + range.focus(); + synthesizeKey("VK_HOME"); + is(rangeChange, 1, "Change event should be dispatched on range input element for key changes"); + range.blur(); + is(rangeChange, 1, "Change event shouldn't be dispatched on range input element on blur"); + range.focus(); + var bcr = range.getBoundingClientRect(); + var centerOfRangeX = bcr.width / 2; + var centerOfRangeY = bcr.height / 2; + synthesizeMouse(range, centerOfRangeX - 10, centerOfRangeY, { type: "mousedown" }); + is(rangeChange, 1, "Change event shouldn't be dispatched on range input element for mousedown"); + synthesizeMouse(range, centerOfRangeX - 5, centerOfRangeY, { type: "mousemove" }); + is(rangeChange, 1, "Change event shouldn't be dispatched on range input element during drag of thumb"); + synthesizeMouse(range, centerOfRangeX, centerOfRangeY, { type: "mouseup" }); + is(rangeChange, 2, "Change event should be dispatched on range input element at end of drag"); + range.blur(); + is(rangeChange, 2, "Change event shouldn't be dispatched on range input element when range loses focus after a drag"); + synthesizeMouse(range, centerOfRangeX - 10, centerOfRangeY, {}); + is(rangeChange, 3, "Change event should be dispatched on range input element for a click that gives the range focus"); + + if (isDesktop) { // up/down arrow keys not supported on android/b2g + synthesizeKey("KEY_ArrowUp"); + is(rangeChange, 4, "Change event should be dispatched on range input element for key changes that change its value (KEY_ArrowUp)"); + synthesizeKey("KEY_ArrowDown"); + is(rangeChange, 5, "Change event should be dispatched on range input element for key changes that change its value (KEY_ArrowDown)"); + synthesizeKey("KEY_ArrowRight"); + is(rangeChange, 6, "Change event should be dispatched on range input element for key changes that change its value (KEY_ArrowRight)"); + synthesizeKey("KEY_ArrowLeft"); + is(rangeChange, 7, "Change event should be dispatched on range input element for key changes that change its value (KEY_ArrowLeft)"); + synthesizeKey("KEY_ArrowUp", {shiftKey: true}); + is(rangeChange, 8, "Change event should be dispatched on range input element for key changes that change its value (Shift+KEY_ArrowUp)"); + synthesizeKey("KEY_ArrowDown", {shiftKey: true}); + is(rangeChange, 9, "Change event should be dispatched on range input element for key changes that change its value (Shift+KEY_ArrowDown)"); + synthesizeKey("KEY_ArrowRight", {shiftKey: true}); + is(rangeChange, 10, "Change event should be dispatched on range input element for key changes that change its value (Shift+KEY_ArrowRight)"); + synthesizeKey("KEY_ArrowLeft", {shiftKey: true}); + is(rangeChange, 11, "Change event should be dispatched on range input element for key changes that change its value (Shift+KEY_ArrowLeft)"); + synthesizeKey("KEY_PageUp"); + is(rangeChange, 12, "Change event should be dispatched on range input element for key changes that change its value (KEY_PageUp)"); + synthesizeKey("KEY_PageDown"); + is(rangeChange, 13, "Change event should be dispatched on range input element for key changes that change its value (KEY_PageDown"); + synthesizeKey("KEY_ArrowRight", {shiftKey: true}); + is(rangeChange, 14, "Change event should be dispatched on range input element for key changes that change its value (Shift+KEY_PageUp)"); + synthesizeKey("KEY_ArrowLeft", {shiftKey: true}); + is(rangeChange, 15, "Change event should be dispatched on range input element for key changes that change its value (Shift+KEY_PageDown)"); + } + //Input type change test. + input = document.getElementById("input_checkbox"); + input.type = "text"; + input.focus(); + input.click(); + input.blur(); + is(NonTextInputChange[5], 1, "Change event shouldn't be dispatched for checkbox ---> text input type change"); + + setTimeout(testInputWithDefaultValue, 0); + } + + function testInputWithDefaultValue() { + // focus and blur an input text should not trigger change event if content hasn't changed. + var input = document.getElementById('input_text_value'); + input.focus(); + is(textInputValueChange, 0, "change event shouldn't be dispatched on input text with default value"); + + SimpleTest.finish(); + } + + addLoadEvent(testUserInput); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_datalist_element.html b/dom/html/test/forms/test_datalist_element.html new file mode 100644 index 0000000000..5f05634018 --- /dev/null +++ b/dom/html/test/forms/test_datalist_element.html @@ -0,0 +1,118 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for the datalist element</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> + <datalist> + </datalist> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 555840 **/ + +function checkClassesAndAttributes() +{ + var d = document.getElementsByTagName('datalist'); + is(d.length, 1, "One datalist has been found"); + + d = d[0]; + ok(d instanceof HTMLDataListElement, + "The datalist should be instance of HTMLDataListElement"); + + ok('options' in d, "datalist has an options IDL attribute"); + + ok(d.options, "options IDL attribute is not null"); + ok(!d.getAttribute('options'), "datalist has no options content attribute"); + + ok(d.options instanceof HTMLCollection, + "options IDL attribute should be instance of HTMLCollection"); +} + +function checkOptions() +{ + var testData = [ + /* [ Child list, Function modifying children, Recognized options ] */ + [['option'], null, 1], + [['option', 'option', 'option', 'option'], null, 4], + /* Disabled options are not valid. */ + [['option'], function(d) { d.childNodes[0].disabled = true; }, 0], + [['option', 'option'], function(d) { d.childNodes[0].disabled = true; }, 1], + /* Non-option elements are not recognized. */ + [['input'], null, 0], + [['input', 'option'], null, 1], + [['input', 'textarea'], null, 0], + /* .value and .label are not needed to be valid options. */ + [['option', 'option'], function(d) { d.childNodes[0].value = 'value'; }, 2], + [['option', 'option'], function(d) { d.childNodes[0].label = 'label'; }, 2], + [['option', 'option'], function(d) { d.childNodes[0].value = 'value'; d.childNodes[0].label = 'label'; }, 2], + [['select'], + function(d) { + var s = d.childNodes[0]; + s.appendChild(new Option("foo")); + s.appendChild(new Option("bar")); + }, + 2], + [['select'], + function(d) { + var s = d.childNodes[0]; + s.appendChild(new Option("foo")); + s.appendChild(new Option("bar")); + var label = document.createElement("label"); + d.appendChild(label); + label.appendChild(new Option("foobar")); + }, + 3], + [['select'], + function(d) { + var s = d.childNodes[0]; + s.appendChild(new Option("foo")); + s.appendChild(new Option("bar")); + var label = document.createElement("label"); + d.appendChild(label); + label.appendChild(new Option("foobar")); + s.appendChild(new Option()) + }, + 4], + [[], function(d) { d.appendChild(document.createElementNS("foo", "option")); }, 0] + ]; + + var d = document.getElementsByTagName('datalist')[0]; + var cachedOptions = d.options; + + testData.forEach(function(data) { + data[0].forEach(function(e) { + d.appendChild(document.createElement(e)); + }) + + /* Modify children. */ + if (data[1]) { + data[1](d); + } + + is(d.options, cachedOptions, "Should get the same object") + is(d.options.length, data[2], + "The number of recognized options should be " + data[2]) + + for (var i = 0; i < d.options.length; ++i) { + is(d.options[i].localName, "option", + "Should get an option for d.options[" + i + "]") + } + + /* Cleaning-up. */ + d.textContent = ""; + }) +} + +checkClassesAndAttributes(); +checkOptions(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_double_submit.html b/dom/html/test/forms/test_double_submit.html new file mode 100644 index 0000000000..d27fb290a4 --- /dev/null +++ b/dom/html/test/forms/test_double_submit.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for multiple submissions in straightline code</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<script> + +add_task(async function double_submit() { + dump("test start\n"); + let popup = window.open("file_double_submit.html"); + await new Promise(resolve => { + popup.addEventListener("load", resolve, {once: true}) + }); + + let numCalls = 0; + popup.addEventListener("beforeunload", () => { + numCalls++; + info("beforeunload called " + numCalls + " times"); + }); + + info("clicking button"); + popup.document.querySelector("button").click(); + + is(numCalls, 1, "beforeunload should only fire once"); + popup.close(); +}); + +</script> +</body> +</html> diff --git a/dom/html/test/forms/test_form_attribute-1.html b/dom/html/test/forms/test_form_attribute-1.html new file mode 100644 index 0000000000..6735f514ae --- /dev/null +++ b/dom/html/test/forms/test_form_attribute-1.html @@ -0,0 +1,473 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=588683 +--> +<head> + <title>Test for form attributes 1</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=588683">Mozilla Bug 588683</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for form attributes 1 **/ + +/** + * All functions take an array of forms in first argument and an array of + * elements in second argument. + * Then, it returns an array containing an array of form and an array of array + * of elements. The array represent the form association with elements like this: + * [ [ form1, form2 ], [ [ elmt1ofForm1, elmt2ofForm2 ], [ elmtofForm2 ] ] ] + */ + +/** + * test0a and test0b are testing the regular behavior of form ownership. + */ +function test0a(aForms, aElements) +{ + // <form><element></form> + // <form><element></form> + aForms[0].appendChild(aElements[0]); + aForms[1].appendChild(aElements[1]); + + return [[aForms[0],aForms[1]],[[aElements[0]],[aElements[1]]]]; +} + +function test0b(aForms, aElements) +{ + // <form><element><form><element></form></form> + aForms[0].appendChild(aElements[0]); + aForms[0].appendChild(aForms[1]); + aForms[1].appendChild(aElements[1]); + + return [[aForms[0],aForms[1]],[[aElements[0]],[aElements[1]]]]; +} + +/** + * This function test that, when an element is not a descendant of a form + * element and has @form set to a valid form id, it's form owner is the form + * which has the id. + */ +function test1(aForms, aElements) +{ + // <form id='f'></form><element id='f'> + aForms[0].id = 'f'; + aElements[0].setAttribute('form', 'f'); + + return [[aForms[0]], [[aElements[0]]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a valid form id (not it's descendant), it's form + * owner is the form which has the id. + */ +function test2(aForms, aElements) +{ + // <form id='f'></form><form><element form='f'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f'); + + return [[aForms[0], aForms[1]], [[aElements[0]],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a valid form id (not it's descendant), then the + * form attribute is removed, it does not have a form owner. + */ +function test3(aForms, aElements) +{ + // <form id='f'></form><form><element form='f'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f'); + aElements[0].removeAttribute('form'); + + return [[aForms[0], aForms[1]], [[],[aElements[0]]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a valid form id (not it's descendant), then the + * form's id attribute is removed, it does not have a form owner. + */ +function test4(aForms, aElements) +{ + // <form id='f'></form><form><element form='f'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f'); + aForms[0].removeAttribute('id'); + + return [[aForms[0], aForms[1]], [[],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to an invalid form id, then it does not have a form + * owner. + */ +function test5(aForms, aElements) +{ + // <form id='f'></form><form><element form='foo'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'foo'); + + return [[aForms[0], aForms[1]], [[],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a valid form id (not it's descendant), then the + * form id attribute is changed to an invalid id, it does not have a form owner. + */ +function test6(aForms, aElements) +{ + // <form id='f'></form><form><element form='f'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f'); + aElements[0].setAttribute('form', 'foo'); + + return [[aForms[0], aForms[1]], [[],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to an invalid form id, then the form id attribute + * is changed to a valid form id, it's form owner is the form which has this id. + */ +function test7(aForms, aElements) +{ + // <form id='f'></form><form><element form='foo'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'foo'); + aElements[0].setAttribute('form', 'f'); + + return [[aForms[0], aForms[1]], [[aElements[0]],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a list of ids containing one valid form, then + * it does not have a form owner. + */ +function test8(aForms, aElements) +{ + // <form id='f'></form><form><element form='f foo'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f foo'); + + return [[aForms[0], aForms[1]], [[],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a form id which is valid in a case insensitive + * way, then it does not have a form owner. + */ +function test9(aForms, aElements) +{ + // <form id='f'></form><form><element form='F'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'F'); + + return [[aForms[0], aForms[1]], [[],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a form id which is not a valid id, then it's + * form owner is it does not have a form owner. + */ +function test10(aForms, aElements) +{ + // <form id='F'></form><form><element form='f'></form> + aForms[0].id = 'F'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f'); + + return [[aForms[0], aForms[1]], [[],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a form id which is not a valid id, then it's + * form owner is it does not have a form owner. + */ +function test11(aForms, aElements) +{ + // <form id='foo bar'></form><form><element form='foo bar'></form> + aForms[0].id = 'foo bar'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'foo bar'); + + return [[aForms[0], aForms[1]], [[aElements[0]],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a valid form id and the form id change, then + * it does not have a form owner. + */ +function test12(aForms, aElements) +{ + // <form id='f'></form><form><element form='f'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f'); + aForms[0].id = 'foo'; + + return [[aForms[0], aForms[1]], [[],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to an invalid form id and the form id change to a + * valid one, then it's form owner is the form which has the id. + */ +function test13(aForms, aElements) +{ + // <form id='foo'></form><form><element form='f'></form> + aForms[0].id = 'foo'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f'); + aForms[0].id = 'f'; + + return [[aForms[0], aForms[1]], [[aElements[0]],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a valid form id and a form with the same id is + * inserted before in the tree, then it's form owner is the form which has the + * id. + */ +function test14(aForms, aElements) +{ + // <form id='f'></form><form><element form='f'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f'); + aForms[2].id = 'f'; + + document.getElementById('content').insertBefore(aForms[2], aForms[0]); + + return [[aForms[0], aForms[1], aForms[2]], [[],[],[aElements[0]]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a valid form id and an element with the same id is + * inserted before in the tree, then it does not have a form owner. + */ +function test15(aForms, aElements) +{ + // <form id='f'></form><form><element form='f'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f'); + aElements[1].id = 'f'; + + document.getElementById('content').insertBefore(aElements[1], aForms[0]); + + return [[aForms[0], aForms[1]], [[],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form + * element and has @form set to a valid form id and the form is removed from + * the tree, then it does not have a form owner. + */ +function test16(aForms, aElements) +{ + // <form id='f'></form><form><element form='f'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f'); + aElements[1].id = 'f'; + + document.getElementById('content').removeChild(aForms[0]); + + return [[aForms[0], aForms[1]], [[],[]]]; +} + +/** + * This function test that, when an element is a descendant of a form element + * and has @form set to the empty string, it does not have a form owner. + */ +function test17(aForms, aElements) +{ + // <form><element form=''></form> + aForms[0].appendChild(aElements[0]); + aElements[0].setAttribute('form', ''); + + return [[aForms[0]], [[]]]; +} + +/** + * This function test that, when an element is a descendant of a form element + * and has @form set to the empty string, it does not have a form owner even if + * it's parent has its id equals to the empty string. + */ +function test18(aForms, aElements) +{ + // <form id=''><element form=''></form> + aForms[0].id = ''; + aForms[0].appendChild(aElements[0]); + aElements[0].setAttribute('form', ''); + + return [[aForms[0]], [[]]]; +} + +/** + * This function test that, when an element is a descendant of a form element + * and has @form set to a valid form id and the element is being moving inside + * it's parent, it's form owner will remain the form with the id. + */ +function test19(aForms, aElements) +{ + // <form id='f'></form><form><element form='f'><element></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aForms[1].appendChild(aElements[1]); + aElements[0].setAttribute('form', 'f'); + aForms[1].appendChild(aElements[0]); + + return [[aForms[0],aForms[1]],[[aElements[0]],[aElements[1]]]]; +} + +/** + * This function test that, when an element is a descendant of a form element + * and has @form set to a valid form id and the element is being moving inside + * another form, it's form owner will remain the form with the id. + */ +function test20(aForms, aElements) +{ + // <form id='f'></form><form><element form='f'><element></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aForms[1].appendChild(aElements[1]); + aElements[0].setAttribute('form', 'f'); + aForms[2].appendChild(aElements[0]); + + return [[aForms[0],aForms[1],aForms[2]],[[aElements[0]],[aElements[1]],[]]]; +} + +/** + * This function test that when removing a form, the elements with a @form set + * will be correctly removed from there form owner. + */ +function test21(aForms, aElements) +{ + // <form id='f'><form><form><element form='f'></form> + aForms[0].id = 'f'; + aForms[1].appendChild(aElements[0]); + aElements[0].setAttribute('form', 'f'); + document.getElementById('content').removeChild(aForms[1]); + + return [[aForms[0]],[[]]]; +} + +var functions = [ + test0a, test0b, + test1, test2, test3, test4, test5, test6, test7, test8, test9, + test10, test11, test12, test13, test14, test15, test16, test17, test18, test19, + test20, test21, +]; + +// Global variable to have an easy access to <div id='content'>. +var content = document.getElementById('content'); + +// Initializing the needed elements. +var forms = [ + document.createElement('form'), + document.createElement('form'), + document.createElement('form'), +]; + +var elementNames = [ + 'button', 'fieldset', 'input', 'label', 'object', 'output', 'select', + 'textarea' +]; + +var todoElements = [ + ['keygen', 'Keygen'], +]; + +for (var e of todoElements) { + var node = document.createElement(e[0]); + var nodeString = HTMLElement.prototype.toString.apply(node); + nodeString = nodeString.replace(/Element[\] ].*/, "Element"); + todo_is(nodeString, "[object HTML" + e[1] + "Element", + e[0] + " should not be implemented"); +} + +for (var name of elementNames) { + var elements = [ + document.createElement(name), + document.createElement(name), + ]; + + for (var func of functions) { + // Clean-up. + while (content.firstChild) { + content.firstChild.remove(); + } + for (form of forms) { + content.appendChild(form); + form.removeAttribute('id'); + } + for (e of elements) { + content.appendChild(e); + e.removeAttribute('form'); + is(e.form, null, "The element should not have a form owner"); + } + + // Calling the test. + var results = func(forms, elements); + + // Checking the results. + var formsList = results[0]; + for (var i=0; i<formsList.length; ++i) { + var elementsList = results[1][i]; + if (name != 'label' && name != 'meter' && name != 'progress') { + is(formsList[i].elements.length, elementsList.length, + "The form should contain " + elementsList.length + " elements"); + } + for (var j=0; j<elementsList.length; ++j) { + if (name != 'label' && name != 'meter' && name != 'progress') { + is(formsList[i].elements[j], elementsList[j], + "The form should contain " + elementsList[j]); + } + if (name != 'label') { + is(elementsList[j].form, formsList[i], + "The form owner should be the form associated to the list"); + } + } + } + } + + // Cleaning-up. + for (e of elements) { + e.remove(); + e = null; + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_form_attribute-2.html b/dom/html/test/forms/test_form_attribute-2.html new file mode 100644 index 0000000000..b7fe5daa87 --- /dev/null +++ b/dom/html/test/forms/test_form_attribute-2.html @@ -0,0 +1,53 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=588683 +--> +<head> + <title>Test for form attributes 2</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=588683">Mozilla Bug 588683</a> +<p id="display"></p> +<div id="content" style="display: none"> + <form id='a'> + <form id='b'> + <input id='i' form='b'> + <script> + is(document.getElementById('i').form, document.getElementById('b'), + "While parsing, the form property should work."); + </script> + </form> + </form> + <form id='c'> + <form id='d'> + <input id='i2' form='c'> + <script> + is(document.getElementById('i2').form, document.getElementById('c'), + "While parsing, the form property should work."); + </script> + </form> + </form> + <!-- Let's tests without @form --> + <form id='e'> + <form id='f'> + <input id='i3'> + <script> + // bug 589073 + todo_is(document.getElementById('i3').form, document.getElementById('f'), + "While parsing, the form property should work."); + </script> + </form> + </form> + <form id='g'> + <input id='i4'> + <script> + is(document.getElementById('i4').form, document.getElementById('g'), + "While parsing, the form property should work."); + </script> + </form> +</div> +</body> +</html> diff --git a/dom/html/test/forms/test_form_attribute-3.html b/dom/html/test/forms/test_form_attribute-3.html new file mode 100644 index 0000000000..9ceed86716 --- /dev/null +++ b/dom/html/test/forms/test_form_attribute-3.html @@ -0,0 +1,68 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=588683 +--> +<head> + <title>Test for form attributes 3</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=588683">Mozilla Bug 588683</a> +<p id="display"></p> +<div id="content"> + <form id='f'> + <input name='e1'> + </form> + <form id='f2'> + <input name='e2'> + <input id='i3' form='f' + onfocus="var catched=false; + try { e1; } catch(e) { catched=true; } + ok(!catched, 'e1 should be in the scope of i3'); + catched = false; + try { e2; } catch(e) { catched=true; } + ok(catched, 'e2 should not be in the scope of i3'); + document.getElementById('i4').focus();" + > + <input id='i4' form='f2' + onfocus="var catched=false; + try { e2; } catch(e) { catched=true; } + ok(!catched, 'e2 should be in the scope of i4'); + document.getElementById('i5').focus();" + > + <input id='i5' + onfocus="var catched=false; + try { e2; } catch(e) { catched=true; } + ok(!catched, 'e2 should be in the scope of i5'); + document.getElementById('i6').focus();" + > + </form> + <input id='i6' form='f' + onfocus="var catched=false; + try { e1; } catch(e) { catched=true; } + ok(!catched, 'e1 should be in the scope of i6'); + document.getElementById('i7').focus();" + > + <input id='i7' form='f2' + onfocus="var catched=false; + try { e2; } catch(e) { catched=true; } + ok(!catched, 'e2 should be in the scope of i7'); + this.blur(); + SimpleTest.finish();" + > +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for form attributes 3 **/ + +SimpleTest.waitForExplicitFinish(); + +document.getElementById('i3').focus(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_form_attribute-4.html b/dom/html/test/forms/test_form_attribute-4.html new file mode 100644 index 0000000000..f2228cec45 --- /dev/null +++ b/dom/html/test/forms/test_form_attribute-4.html @@ -0,0 +1,48 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=588683 +--> +<head> + <title>Test for form attributes 4</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=588683">Mozilla Bug 588683</a> +<p id="display"></p> +<div id="content" style='display:none;'> + <form id='f'> + </form> + <table id='t'> + <form id='f2'> + <tr><td><input id='i1'></td></tr> + <tr><td><input id='i2' form='f'></td></tr> + </form> + </table> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for form attributes 4 **/ + +var table = document.getElementById('t'); +var i1 = document.getElementById('i1'); +var i2 = document.getElementById('i2'); + +is(i1.form, document.getElementById('f2'), + "i1 form should be it's parent"); +is(i2.form, document.getElementById('f'), + "i1 form should be the form with the id in @form"); + +table.removeChild(document.getElementById('f2')); +is(i1, document.getElementById('i1'), + "i1 should still be in the document"); +is(i1.form, null, "i1 should not have any form owner"); +is(i2.form, document.getElementById('f'), + "i1 form should be the form with the id in @form"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_form_attributes_reflection.html b/dom/html/test/forms/test_form_attributes_reflection.html new file mode 100644 index 0000000000..0d0ef6b870 --- /dev/null +++ b/dom/html/test/forms/test_form_attributes_reflection.html @@ -0,0 +1,90 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLFormElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="../reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLFormElement attributes reflection **/ + +// .acceptCharset +reflectString({ + element: document.createElement("form"), + attribute: { idl: "acceptCharset", content: "accept-charset" }, + otherValues: [ "ISO-8859-1", "UTF-8" ], +}); + +reflectURL({ + element: document.createElement("form"), + attribute: "action", +}); + +// .autocomplete +reflectLimitedEnumerated({ + element: document.createElement("form"), + attribute: "autocomplete", + validValues: [ "on", "off" ], + invalidValues: [ "", "foo", "tulip", "default" ], + defaultValue: "on", +}); + +// .enctype +reflectLimitedEnumerated({ + element: document.createElement("form"), + attribute: "enctype", + validValues: [ "application/x-www-form-urlencoded", "multipart/form-data", + "text/plain" ], + invalidValues: [ "", "foo", "tulip", "multipart/foo" ], + defaultValue: "application/x-www-form-urlencoded" +}); + +// .encoding +reflectLimitedEnumerated({ + element: document.createElement("form"), + attribute: { idl: "encoding", content: "enctype" }, + validValues: [ "application/x-www-form-urlencoded", "multipart/form-data", + "text/plain" ], + invalidValues: [ "", "foo", "tulip", "multipart/foo" ], + defaultValue: "application/x-www-form-urlencoded" +}); + +// .method +reflectLimitedEnumerated({ + element: document.createElement("form"), + attribute: "method", + validValues: [ "get", "post" ], + invalidValues: [ "", "foo", "tulip" ], + defaultValue: "get" +}); + +// .name +reflectString({ + element: document.createElement("form"), + attribute: "name", +}); + +// .noValidate +reflectBoolean({ + element: document.createElement("form"), + attribute: "noValidate", +}); + +// .target +reflectString({ + element: document.createElement("form"), + attribute: "target", + otherValues: [ "_blank", "_self", "_parent", "_top" ], +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_form_named_getter_dynamic.html b/dom/html/test/forms/test_form_named_getter_dynamic.html new file mode 100644 index 0000000000..4a19768453 --- /dev/null +++ b/dom/html/test/forms/test_form_named_getter_dynamic.html @@ -0,0 +1,54 @@ +<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=377413
+-->
+<head>
+ <title>Test for Bug 377413</title>
+ <script type="text/javascript" src="/resources/testharness.js"></script>
+ <link rel='stylesheet' href='/resources/testharness.css'>
+ <script type="text/javascript" src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=377413">Mozilla Bug 377413</a>
+<p id="log"></p>
+<div id="content">
+ <form>
+ <table>
+ <tbody>
+ </tbody>
+ </table>
+ </form>
+</div>
+
+<script type="text/javascript">
+
+/** Tests for Bug 377413 **/
+var tb = document.getElementsByTagName('tbody')[0];
+
+test(function(){
+ tb.innerHTML = '<tr><td><input name="fooboo"></td></tr>';
+ document.forms[0].fooboo.value = 'testme';
+ document.getElementsByTagName('table')[0].deleteRow(0);
+ assert_equals(document.forms[0].fooboo, undefined);
+}, "no element reference after deleting it with deleteRow()");
+
+test(function(){
+ var b = tb.appendChild(document.createElement('tr')).appendChild(document.createElement('td')).appendChild(document.createElement('button'));
+ b.name = b.value = 'boofoo';
+ assert_equals(document.forms[0].elements[0].value, 'boofoo');
+}, 'element value set correctly');
+
+test(function(){
+ assert_true('boofoo' in document.forms[0]);
+}, 'element name has created property on form');
+
+test(function(){
+ tb.innerHTML = '';
+ assert_false('boofoo' in document.forms[0]);
+}, "no element reference after deleting it by setting innerHTML");
+
+
+</script>
+</body>
+</html>
diff --git a/dom/html/test/forms/test_formaction_attribute.html b/dom/html/test/forms/test_formaction_attribute.html new file mode 100644 index 0000000000..0dee2f172d --- /dev/null +++ b/dom/html/test/forms/test_formaction_attribute.html @@ -0,0 +1,169 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=566160 +--> +<head> + <title>Test for Bug 566160</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=566160">Mozilla Bug 566160</a> +<p id="display"></p> +<style> + iframe { width: 130px; height: 100px;} +</style> +<iframe name='frame1' id='frame1'></iframe> +<iframe name='frame2' id='frame2'></iframe> +<iframe name='frame3' id='frame3'></iframe> +<iframe name='frame3bis' id='frame3bis'></iframe> +<iframe name='frame4' id='frame4'></iframe> +<iframe name='frame5' id='frame5'></iframe> +<iframe name='frame6' id='frame6'></iframe> +<iframe name='frame7' id='frame7'></iframe> +<div id="content"> + <!-- submit controls with formaction that are validated with a CLICK --> + <form target="frame1" action="FAIL.html" method="GET"> + <input name='foo' value='foo'> + <input type='submit' id='is' formaction="PASS.html"> + </form> + <form target="frame2" action="FAIL.html" method="GET"> + <input name='bar' value='bar'> + <input type='image' id='ii' formaction="PASS.html"> + </form> + <form target="frame3" action="FAIL.html" method="GET"> + <input name='tulip' value='tulip'> + <button type='submit' id='bs' formaction="PASS.html">submit</button> + </form> + <form target="frame3bis" action="FAIL.html" method="GET"> + <input name='tulipbis' value='tulipbis'> + <button type='submit' id='bsbis' formaction="PASS.html">submit</button> + </form> + + <!-- submit controls with formaction that are validated with ENTER --> + <form target="frame4" action="FAIL.html" method="GET"> + <input name='footulip' value='footulip'> + <input type='submit' id='is2' formaction="PASS.html"> + </form> + <form target="frame5" action="FAIL.html" method="GET"> + <input name='foobar' value='foobar'> + <input type='image' id='ii2' formaction="PASS.html"> + </form> + <form target="frame6" action="FAIL.html" method="GET"> + <input name='tulip2' value='tulip2'> + <button type='submit' id='bs2' formaction="PASS.html">submit</button> + </form> + + <!-- check that when submitting a from from an element + which is not a submit control, @formaction isn't used --> + <form target='frame7' action="PASS.html" method="GET"> + <input id='enter' name='input' value='enter' formaction="FAIL.html"> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 566160 **/ + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(runTests); + +const BASE_URI = `${location.origin}/tests/dom/html/test/forms/PASS.html`; +var gTestResults = { + frame1: BASE_URI + "?foo=foo", + frame2: BASE_URI + "?bar=bar&x=0&y=0", + frame3: BASE_URI + "?tulip=tulip", + frame3bis: BASE_URI + "?tulipbis=tulipbis", + frame4: BASE_URI + "?footulip=footulip", + frame5: BASE_URI + "?foobar=foobar&x=0&y=0", + frame6: BASE_URI + "?tulip2=tulip2", + frame7: BASE_URI + "?input=enter", +}; + +var gPendingLoad = 0; // Has to be set after depending on the frames number. + +function runTests() +{ + // We add a load event for the frames which will be called when the forms + // will be submitted. + var frames = [ document.getElementById('frame1'), + document.getElementById('frame2'), + document.getElementById('frame3'), + document.getElementById('frame3bis'), + document.getElementById('frame4'), + document.getElementById('frame5'), + document.getElementById('frame6'), + document.getElementById('frame7'), + ]; + gPendingLoad = frames.length; + + for (var i=0; i<frames.length; i++) { + frames[i].setAttribute('onload', "frameLoaded(this);"); + } + + /** + * We are going to focus each element before interacting with either for + * simulating the ENTER key (synthesizeKey) or a click (synthesizeMouse) or + * using .click(). This because it may be needed (ENTER) and because we want + * to have the element visible in the iframe. + * + * Focusing the first element (id='is') is launching the tests. + */ + document.getElementById('is').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('is'), 5, 5, {}); + document.getElementById('ii').focus(); + }, {once: true}); + + document.getElementById('ii').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('ii'), 5, 5, {}); + document.getElementById('bs').focus(); + }, {once: true}); + + document.getElementById('bs').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('bs'), 5, 5, {}); + document.getElementById('bsbis').focus(); + }, {once: true}); + + document.getElementById('bsbis').addEventListener('focus', function(aEvent) { + document.getElementById('bsbis').click(); + document.getElementById('is2').focus(); + }, {once: true}); + + document.getElementById('is2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('ii2').focus(); + }, {once: true}); + + document.getElementById('ii2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('bs2').focus(); + }, {once: true}); + + document.getElementById('bs2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('enter').focus(); + }, {once: true}); + + document.getElementById('enter').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + }, {once: true}); + + document.getElementById('is').focus(); +} + +function frameLoaded(aFrame) { + // Check if formaction/action has the correct behavior. + is(aFrame.contentWindow.location.href, gTestResults[aFrame.name], + "the action attribute doesn't have the correct behavior"); + + if (--gPendingLoad == 0) { + SimpleTest.finish(); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_formnovalidate_attribute.html b/dom/html/test/forms/test_formnovalidate_attribute.html new file mode 100644 index 0000000000..2e3714d2fe --- /dev/null +++ b/dom/html/test/forms/test_formnovalidate_attribute.html @@ -0,0 +1,125 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=589696 +--> +<head> + <title>Test for Bug 589696</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=589696">Mozilla Bug 589696</a> +<p id="display"></p> +<iframe style='width:50px; height: 50px;' name='t'></iframe> +<div id="content"> + <!-- Next forms should not submit because formnovalidate isn't set on the + element used for the submission. --> + <form target='t' action='data:text/html,'> + <input id='av' required> + <input type='submit' formnovalidate> + <input id='a' type='submit'> + </form> + <form target='t' action='data:text/html,'> + <input id='bv' type='checkbox' required> + <button type='submit' formnovalidate></button> + <button id='b' type='submit'></button> + </form> + <!-- Next form should not submit because formnovalidate only applies for + submit controls. --> + <form target='t' action='data:text/html,'> + <input id='c' required formnovalidate> + </form> + <!--- Next forms should submit without any validation check. --> + <form target='t' action='data:text/html,'> + <input id='dv' required> + <input id='d' type='submit' formnovalidate> + </form> + <form target='t' action='data:text/html,'> + <input id='ev' type='checkbox' required> + <button id='e' type='submit' formnovalidate></button> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 589696 **/ + +document.getElementById('av').addEventListener("invalid", function(aEvent) { + aEvent.target.removeAttribute("invalid", arguments.callee, false); + ok(true, "formnovalidate should not apply on if not set on the submit " + + "control used for the submission"); + document.getElementById('b').click(); +}); + +document.getElementById('bv').addEventListener("invalid", function(aEvent) { + aEvent.target.removeAttribute("invalid", arguments.callee, false); + ok(true, "formnovalidate should not apply on if not set on the submit " + + "control used for the submission"); + var c = document.getElementById('c'); + c.focus(); + synthesizeKey("KEY_Enter"); +}); + +document.getElementById('c').addEventListener("invalid", function(aEvent) { + aEvent.target.removeAttribute("invalid", arguments.callee, false); + ok(true, "formnovalidate should only apply on submit controls"); + document.getElementById('d').click(); +}); + +document.forms[3].addEventListener("submit", function(aEvent) { + aEvent.target.removeAttribute("submit", arguments.callee, false); + ok(true, "formnovalidate applies if set on the submit control used for the submission"); + document.getElementById('e').click(); +}); + +document.forms[4].addEventListener("submit", function(aEvent) { + aEvent.target.removeAttribute("submit", arguments.callee, false); + ok(true, "formnovalidate applies if set on the submit control used for the submission"); + SimpleTest.executeSoon(SimpleTest.finish); +}); + +/** + * We have to be sure invalid events behave as expected. + * They should be sent before the submit event so we can just create a test + * failure if we got one when unexpected. All of them should be caught if + * sent. + * At worst, we got random green which isn't harmful. + * If expected, they will be part of the chain reaction. + */ +function unexpectedInvalid(aEvent) +{ + aEvent.target.removeAttribute("invalid", unexpectedInvalid, false); + ok(false, "invalid event should not be sent"); +} + +document.getElementById('dv').addEventListener("invalid", unexpectedInvalid); +document.getElementById('ev').addEventListener("invalid", unexpectedInvalid); + +/** + * Some submission have to be canceled. In that case, the submit events should + * not be sent. + * Same behavior as unexpected invalid events. + */ +function unexpectedSubmit(aEvent) +{ + aEvent.target.removeAttribute("submit", unexpectedSubmit, false); + ok(false, "submit event should not be sent"); +} + +document.forms[0].addEventListener("submit", unexpectedSubmit); +document.forms[1].addEventListener("submit", unexpectedSubmit); +document.forms[2].addEventListener("submit", unexpectedSubmit); + +SimpleTest.waitForExplicitFinish(); + +// This is going to call all the tests (with a chain reaction). +SimpleTest.waitForFocus(function() { + document.getElementById('a').click(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_attributes_reflection.html b/dom/html/test/forms/test_input_attributes_reflection.html new file mode 100644 index 0000000000..348ea0f80d --- /dev/null +++ b/dom/html/test/forms/test_input_attributes_reflection.html @@ -0,0 +1,271 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLInputElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="../reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLInputElement attributes reflection **/ + +// TODO: maybe make those reflections be tested against all input types. + +function testWidthHeight(attr) { + var element = document.createElement('input'); + is(element[attr], 0, attr + ' always returns 0 if not type=image'); + element.setAttribute(attr, '42'); + is(element[attr], 0, attr + ' always returns 0 if not type=image'); + is(element.getAttribute(attr), '42'); + element[attr] = 0; + is(element.getAttribute(attr), '0', 'setting ' + attr + ' changes the content attribute'); + element[attr] = 12; + is(element.getAttribute(attr), '12', 'setting ' + attr + ' changes the content attribute'); + + element.removeAttribute(attr); + is(element.getAttribute(attr), null); + + element = document.createElement('input'); + element.type = 'image'; + element.style.display = "inline"; + document.getElementById('content').appendChild(element); + isnot(element[attr], 0, attr + ' represents the dimension of the element if type=image'); + + element.setAttribute(attr, '42'); + isnot(element[attr], 0, attr + ' represents the dimension of the element if type=image'); + isnot(element[attr], 42, attr + ' represents the dimension of the element if type=image'); + is(element.getAttribute(attr), '42'); + element[attr] = 0; + is(element.getAttribute(attr), '0', 'setting ' + attr + ' changes the content attribute'); + element[attr] = 12; + is(element.getAttribute(attr), '12', 'setting ' + attr + ' changes the content attribute'); + + element.removeAttribute(attr); + is(element.getAttribute(attr), null); +} + +// .accept +reflectString({ + element: document.createElement("input"), + attribute: "accept", + otherValues: [ "audio/*", "video/*", "image/*", "image/png", + "application/msword", "appplication/pdf" ], +}); + +// .alt +reflectString({ + element: document.createElement("input"), + attribute: "alt", +}); + +// .autocomplete +reflectLimitedEnumerated({ + element: document.createElement("input"), + attribute: "autocomplete", + validValues: [ "on", "off" ], + invalidValues: [ "", "default", "foo", "tulip" ], +}); + +// .autofocus +reflectBoolean({ + element: document.createElement("input"), + attribute: "autofocus", +}); + +// .defaultChecked +reflectBoolean({ + element: document.createElement("input"), + attribute: { idl: "defaultChecked", content: "checked" }, +}); + +// .checked doesn't reflect a content attribute. + +// .dirName +reflectString({ + element: document.createElement("input"), + attribute: "dirName" +}); + +// .disabled +reflectBoolean({ + element: document.createElement("input"), + attribute: "disabled", +}); + +// TODO: form (HTMLFormElement) +// TODO: files (FileList) + +// .formAction +reflectURL({ + element: document.createElement("button"), + attribute: "formAction", +}); + +// .formEnctype +reflectLimitedEnumerated({ + element: document.createElement("input"), + attribute: "formEnctype", + validValues: [ "application/x-www-form-urlencoded", "multipart/form-data", + "text/plain" ], + invalidValues: [ "", "foo", "tulip", "multipart/foo" ], + defaultValue: { invalid: "application/x-www-form-urlencoded", missing: "" } +}); + +// .formMethod +reflectLimitedEnumerated({ + element: document.createElement("input"), + attribute: "formMethod", + validValues: [ "get", "post" ], + invalidValues: [ "", "foo", "tulip" ], + defaultValue: { invalid: "get", missing: "" } +}); + +// .formNoValidate +reflectBoolean({ + element: document.createElement("input"), + attribute: "formNoValidate", +}); + +// .formTarget +reflectString({ + element: document.createElement("input"), + attribute: "formTarget", + otherValues: [ "_blank", "_self", "_parent", "_top" ], +}); + +// .height +testWidthHeight('height'); + +// .indeterminate doesn't reflect a content attribute. + +// TODO: list (HTMLElement) + +// .max +reflectString({ + element: document.createElement('input'), + attribute: 'max', +}); + +// .maxLength +reflectInt({ + element: document.createElement("input"), + attribute: "maxLength", + nonNegative: true, +}); + +// .min +reflectString({ + element: document.createElement('input'), + attribute: 'min', +}); + +// .multiple +reflectBoolean({ + element: document.createElement("input"), + attribute: "multiple", +}); + +// .name +reflectString({ + element: document.createElement("input"), + attribute: "name", + otherValues: [ "isindex", "_charset_" ], +}); + +// .pattern +reflectString({ + element: document.createElement("input"), + attribute: "pattern", + otherValues: [ "[0-9][A-Z]{3}" ], +}); + +// .placeholder +reflectString({ + element: document.createElement("input"), + attribute: "placeholder", + otherValues: [ "foo\nbar", "foo\rbar", "foo\r\nbar" ], +}); + +// .readOnly +reflectBoolean({ + element: document.createElement("input"), + attribute: "readOnly", +}); + +// .required +reflectBoolean({ + element: document.createElement("input"), + attribute: "required", +}); + +// .size +reflectUnsignedInt({ + element: document.createElement("input"), + attribute: "size", + nonZero: true, + defaultValue: 20, +}); + +// .src (URL) +reflectURL({ + element: document.createElement('input'), + attribute: 'src', +}); + +// .step +reflectString({ + element: document.createElement('input'), + attribute: 'step', +}); + +// .type +reflectLimitedEnumerated({ + element: document.createElement("input"), + attribute: "type", + validValues: [ "hidden", "text", "search", "tel", "url", "email", "password", + "checkbox", "radio", "file", "submit", "image", "reset", + "button", "date", "time", "number", "range", "color", "month", + "week", "datetime-local" ], + invalidValues: [ "this-is-probably-a-wrong-type", "", "tulip" ], + defaultValue: "text" +}); + +// .defaultValue +reflectString({ + element: document.createElement("input"), + attribute: { idl: "defaultValue", content: "value" }, + otherValues: [ "foo\nbar", "foo\rbar", "foo\r\nbar" ], +}); + +// .value doesn't reflect a content attribute. + +// .valueAsDate +is("valueAsDate" in document.createElement("input"), true, + "valueAsDate should be available"); + +// Deeper check will be done with bug 763305. +is('valueAsNumber' in document.createElement("input"), true, + "valueAsNumber should be available"); + +// .selectedOption +todo("selectedOption" in document.createElement("input"), + "selectedOption isn't implemented yet"); + +// .width +testWidthHeight('width'); + +// .willValidate doesn't reflect a content attribute. +// .validity doesn't reflect a content attribute. +// .validationMessage doesn't reflect a content attribute. +// .labels doesn't reflect a content attribute. + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_color_input_change_events.html b/dom/html/test/forms/test_input_color_input_change_events.html new file mode 100644 index 0000000000..f97d54f66e --- /dev/null +++ b/dom/html/test/forms/test_input_color_input_change_events.html @@ -0,0 +1,119 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=885996 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1234567</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test that update() modifies the element value such as done() when it is + * not called as a concellation. + */ + + SimpleTest.waitForExplicitFinish(); + + var MockColorPicker = SpecialPowers.MockColorPicker; + + var test = runTest(); + + SimpleTest.waitForFocus(function() { + test.next(); + }); + + function* runTest() { + MockColorPicker.init(window); + var element = null; + + MockColorPicker.showCallback = function(picker, update) { + is(picker.initialColor, element.value); + + var inputEvent = false; + var changeEvent = false; + element.oninput = function() { + inputEvent = true; + }; + element.onchange = function() { + changeEvent = true; + }; + + if (element.dataset.type == 'update') { + update('#f00ba4'); + + is(inputEvent, true, 'input event should have been received'); + is(changeEvent, false, 'change event should not have been received'); + + inputEvent = changeEvent = false; + + is(element.value, '#f00ba4'); + + MockColorPicker.returnColor = '#f00ba7'; + isnot(element.value, MockColorPicker.returnColor); + } else if (element.dataset.type == 'cancel') { + MockColorPicker.returnColor = '#bababa'; + isnot(element.value, MockColorPicker.returnColor); + } else if (element.dataset.type == 'done') { + MockColorPicker.returnColor = '#098766'; + isnot(element.value, MockColorPicker.returnColor); + } else if (element.dataset.type == 'noop-done') { + MockColorPicker.returnColor = element.value; + is(element.value, MockColorPicker.returnColor); + } + + SimpleTest.executeSoon(function() { + if (element.dataset.type == 'cancel') { + isnot(element.value, MockColorPicker.returnColor); + is(inputEvent, false, 'no input event should have been sent'); + is(changeEvent, false, 'no change event should have been sent'); + } else if (element.dataset.type == 'noop-done') { + is(element.value, MockColorPicker.returnColor); + is(inputEvent, false, 'no input event should have been sent'); + is(changeEvent, false, 'no change event should have been sent'); + } else { + is(element.value, MockColorPicker.returnColor); + is(inputEvent, true, 'input event should have been sent'); + is(changeEvent, true, 'change event should have been sent'); + } + + changeEvent = false; + element.blur(); + + setTimeout(function() { + is(changeEvent, false, "change event should not be fired on blur"); + test.next(); + }); + }); + + return element.dataset.type == 'cancel' ? "" : MockColorPicker.returnColor; + }; + + for (var i = 0; i < document.getElementsByTagName('input').length; ++i) { + element = document.getElementsByTagName('input')[i]; + element.focus(); + synthesizeMouseAtCenter(element, {}); + yield undefined; + }; + + MockColorPicker.cleanup(); + SimpleTest.finish(); + } + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=885996">Mozilla Bug 885996</a> +<p id="display"></p> +<div id="content"> + <input type='color' data-type='update'> + <input type='color' data-type='cancel'> + <input type='color' data-type='done'> + <input type='color' data-type='noop-done'> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_color_picker_datalist.html b/dom/html/test/forms/test_input_color_picker_datalist.html new file mode 100644 index 0000000000..1a268c0701 --- /dev/null +++ b/dom/html/test/forms/test_input_color_picker_datalist.html @@ -0,0 +1,42 @@ +<!DOCTYPE HTML> +<html> +<head> +<meta charset="utf-8"> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +<script> +SimpleTest.waitForExplicitFinish(); + +function runTest() { + let MockColorPicker = SpecialPowers.MockColorPicker; + + MockColorPicker.init(window); + + MockColorPicker.showCallback = (picker) => { + is(picker.defaultColors.length, 2); + is(picker.defaultColors[0], "#112233"); + is(picker.defaultColors[1], "#00ffaa"); + + MockColorPicker.cleanup(); + SimpleTest.finish(); + } + + let input = document.querySelector("input"); + synthesizeMouseAtCenter(input, {}); +} + +SimpleTest.waitForFocus(runTest); +</script> +</head> +<body> +<input type="color" list="color-list"> +<datalist id="color-list"> + <option value="#112233"></option> + <option value="black"></option> <!-- invalid --> + <option value="#000000" disabled></option> + <option value="#00FFAA"></option> + <option></option> +</datalist> +</body> +</html> diff --git a/dom/html/test/forms/test_input_color_picker_initial.html b/dom/html/test/forms/test_input_color_picker_initial.html new file mode 100644 index 0000000000..c7467c7520 --- /dev/null +++ b/dom/html/test/forms/test_input_color_picker_initial.html @@ -0,0 +1,78 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=885996 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1234567</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test that the initial value of the nsIColorPicker is the current value of + the <input type='color'> element. **/ + + SimpleTest.waitForExplicitFinish(); + + var MockColorPicker = SpecialPowers.MockColorPicker; + + var test = runTest(); + + SimpleTest.waitForFocus(function() { + test.next(); + }); + + function* runTest() { + MockColorPicker.init(window); + var element = null; + + MockColorPicker.showCallback = function(picker) { + is(picker.initialColor, element.value); + SimpleTest.executeSoon(function() { + test.next(); + }); + return ""; + }; + + for (var i = 0; i < document.getElementsByTagName('input').length; ++i) { + element = document.getElementsByTagName('input')[i]; + if (element.parentElement.id === 'dynamic-values') { + element.value = '#deadbe'; + } + synthesizeMouseAtCenter(element, {}); + yield undefined; + }; + + MockColorPicker.cleanup(); + SimpleTest.finish(); + } + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=885996">Mozilla Bug 885996</a> +<p id="display"></p> +<div id="content"> + <div id='valid-values'> + <input type='color' value='#ff00ff'> + <input type='color' value='#ab3275'> + <input type='color' value='#abcdef'> + <input type='color' value='#ABCDEF'> + </div> + <div id='invalid-values'> + <input type='color' value='ffffff'> + <input type='color' value='#abcdez'> + <input type='color' value='#0123456'> + </div> + <div id='dynamic-values'> + <input type='color' value='#ab4594'> + <input type='color' value='#984534'> + <input type='color' value='#f8b9a0'> + </div> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_color_picker_popup.html b/dom/html/test/forms/test_input_color_picker_popup.html new file mode 100644 index 0000000000..9fbebf15bc --- /dev/null +++ b/dom/html/test/forms/test_input_color_picker_popup.html @@ -0,0 +1,144 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=885996 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1234567</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> body { font-family: serif } </style> + <script type="application/javascript"> + + /** Test the behaviour of the <input type='color'> when clicking on it from + different ways. **/ + + SimpleTest.waitForExplicitFinish(); + + var MockColorPicker = SpecialPowers.MockColorPicker; + + var test = runTest(); + var testData = [ + { id: 'normal', result: true }, + { id: 'hidden', result: false }, + { id: 'normal', type: 'untrusted', result: true }, + { id: 'normal', type: 'prevent-default-1', result: false }, + { id: 'normal', type: 'prevent-default-2', result: false }, + { id: 'normal', type: 'click-method', result: true }, + { id: 'normal', type: 'show-picker', result: true }, + { id: 'normal', type: 'right-click', result: false }, + { id: 'normal', type: 'middle-click', result: false }, + { id: 'label-1', result: true }, + { id: 'label-2', result: true }, + { id: 'label-3', result: true }, + { id: 'label-4', result: true }, + { id: 'button-click', result: true }, + { id: 'button-down', result: true }, + { id: 'button-up', result: true }, + { id: 'div-click', result: true }, + { id: 'div-click-on-demand', result: true }, + ]; + + SimpleTest.waitForFocus(function() { + test.next(); + }); + + function* runTest() { + let currentTest = null; + MockColorPicker.init(window); + var element = null; + + MockColorPicker.showCallback = function(picker) { + ok(currentTest.result); + SimpleTest.executeSoon(function() { + test.next(); + }); + return ""; + }; + + while (testData.length) { + currentTest = testData.shift(); + element = document.getElementById(currentTest.id); + + // To make sure we can actually click on the element. + element.focus(); + + switch (currentTest.type) { + case 'untrusted': + var e = document.createEvent('MouseEvents'); + e.initEvent('click', true, false); + document.getElementById(element.dispatchEvent(e)); + break; + case 'prevent-default-1': + element.onclick = function() { + return false; + }; + element.click(); + element.onclick = function() {}; + break; + case 'prevent-default-2': + element.onclick = function(event) { + event.preventDefault(); + }; + element.click(); + element.onclick = function() {}; + break; + case 'click-method': + element.click(); + break; + case 'show-picker': + SpecialPowers.wrap(document).notifyUserGestureActivation(); + element.showPicker(); + break; + case 'right-click': + synthesizeMouseAtCenter(element, { button: 2 }); + break; + case 'middle-click': + synthesizeMouseAtCenter(element, { button: 1 }); + break; + default: + synthesizeMouseAtCenter(element, {}); + } + + if (!currentTest.result) { + setTimeout(function() { + setTimeout(function() { + ok(true); + SimpleTest.executeSoon(function() { + test.next(); + }); + }); + }); + } + yield undefined; + }; + + MockColorPicker.cleanup(); + SimpleTest.finish(); + } + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=885996">Mozilla Bug 885996</a> +<p id="display"></p> +<div id="content"> + <input type='color' id='normal'> + <input type='color' id='hidden' hidden> + <label id='label-1'>foo<input type='color'></label> + <label id='label-2' for='labeled-2'>foo</label><input id='labeled-2' type='color'></label> + <label id='label-3'>foo<input type='color'></label> + <label id='label-4' for='labeled-4'>foo</label><input id='labeled-4' type='color'></label> + <input id='by-button' type='color'> + <button id='button-click' onclick="document.getElementById('by-button').click();">click</button> + <button id='button-down' onclick="document.getElementById('by-button').click();">click</button> + <button id='button-up' onclick="document.getElementById('by-button').click();">click</button> + <div id='div-click' onclick="document.getElementById('by-button').click();">click</div> + <div id='div-click-on-demand' onclick="var i=document.createElement('input'); i.type='color'; i.click();">click</div> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_color_picker_update.html b/dom/html/test/forms/test_input_color_picker_update.html new file mode 100644 index 0000000000..5c22b667e1 --- /dev/null +++ b/dom/html/test/forms/test_input_color_picker_update.html @@ -0,0 +1,86 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=885996 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1234567</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> body { font-family: serif } </style> + <script type="application/javascript"> + + /** Test that update() modifies the element value such as done() when it is + * not called as a concellation. + */ + + SimpleTest.waitForExplicitFinish(); + + var MockColorPicker = SpecialPowers.MockColorPicker; + + var test = runTest(); + + SimpleTest.waitForFocus(function() { + test.next(); + }); + + function* runTest() { + MockColorPicker.init(window); + var element = null; + + MockColorPicker.showCallback = function(picker, update) { + is(picker.initialColor, element.value); + + if (element.dataset.type == 'update') { + update('#f00ba4'); + is(element.value, '#f00ba4'); + + MockColorPicker.returnColor = '#f00ba7'; + isnot(element.value, MockColorPicker.returnColor); + } else if (element.dataset.type == 'cancel') { + MockColorPicker.returnColor = '#bababa'; + isnot(element.value, MockColorPicker.returnColor); + } else if (element.dataset.type == 'done') { + MockColorPicker.returnColor = '#098766'; + isnot(element.value, MockColorPicker.returnColor); + } + + SimpleTest.executeSoon(function() { + if (element.dataset.type == 'cancel') { + isnot(element.value, MockColorPicker.returnColor); + } else { + is(element.value, MockColorPicker.returnColor); + } + + test.next(); + }); + + return element.dataset.type == 'cancel' ? "" : MockColorPicker.returnColor; + }; + + for (var i = 0; i < document.getElementsByTagName('input').length; ++i) { + element = document.getElementsByTagName('input')[i]; + synthesizeMouseAtCenter(element, {}); + yield undefined; + }; + + MockColorPicker.cleanup(); + SimpleTest.finish(); + } + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=885996">Mozilla Bug 885996</a> +<p id="display"></p> +<div id="content"> + <input type='color' data-type='update'> + <input type='color' data-type='cancel'> + <input type='color' data-type='done'> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_date_bad_input.html b/dom/html/test/forms/test_input_date_bad_input.html new file mode 100644 index 0000000000..516d48263f --- /dev/null +++ b/dom/html/test/forms/test_input_date_bad_input.html @@ -0,0 +1,113 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1372369 +--> +<head> + <title>Test for <input type='date'> bad input validity state</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + input { background-color: rgb(0,0,0) !important; } + :valid { background-color: rgb(0,255,0) !important; } + :invalid { background-color: rgb(255,0,0) !important; } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1372369">Mozilla Bug 1372369</a> +<p id="display"></p> +<div id="content"> + <form> + <input type="date" id="input"> + <form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for <input type='date'> bad input validity state **/ + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +const DATE_BAD_INPUT_MSG = "Please enter a valid date."; +const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent); + +function checkValidity(aElement, aIsBadInput) { + is(aElement.validity.valid, !aIsBadInput, + "validity.valid should be " + (aIsBadInput ? "false" : "true")); + is(aElement.validity.badInput, !!aIsBadInput, + "validity.badInput should be " + (aIsBadInput ? "true" : "false")); + is(aElement.validationMessage, aIsBadInput ? DATE_BAD_INPUT_MSG : "", + "validationMessage should be: " + (aIsBadInput ? DATE_BAD_INPUT_MSG : "")); + + is(window.getComputedStyle(aElement).getPropertyValue('background-color'), + aIsBadInput ? "rgb(255, 0, 0)" : "rgb(0, 255, 0)", + (aIsBadInput ? ":invalid" : "valid") + " pseudo-class should apply"); +} + +function sendKeys(aKey) { + if (aKey.startsWith("KEY_")) { + synthesizeKey(aKey); + } else { + sendString(aKey); + } +} + +function test() { + var elem = document.getElementById("input"); + + elem.focus(); + sendKeys("02312017"); + elem.blur(); + checkValidity(elem, true); + + elem.focus(); + sendKeys("02292016"); + elem.blur(); + checkValidity(elem, false); + + elem.focus(); + sendKeys("06312000"); + elem.blur(); + checkValidity(elem, true); + + // Removing some of the fields keeps the input as invalid. + elem.focus(); + sendKeys("KEY_Backspace"); + elem.blur(); + checkValidity(elem, true); + + // Removing all of the fields manually makes the input valid (but empty) again. + elem.focus(); + sendKeys("KEY_ArrowRight"); + sendKeys("KEY_Backspace"); + sendKeys("KEY_ArrowRight"); + sendKeys("KEY_Delete"); + elem.blur(); + checkValidity(elem, false); + + elem.focus(); + sendKeys("02292017"); + elem.blur(); + checkValidity(elem, true); + + // Clearing all fields should clear bad input validity state as well. + elem.focus(); + synthesizeKey("KEY_Backspace", { accelKey: true }); + checkValidity(elem, false); + + sendKeys("22334444"); + elem.blur(); + elem.focus(); + synthesizeKey("KEY_Delete", { accelKey: true }); + checkValidity(elem, false); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_date_key_events.html b/dom/html/test/forms/test_input_date_key_events.html new file mode 100644 index 0000000000..387cb37af7 --- /dev/null +++ b/dom/html/test/forms/test_input_date_key_events.html @@ -0,0 +1,270 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1286182 +--> +<head> + <title>Test key events for date control</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1286182">Mozilla Bug 1286182</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1804669">Mozilla Bug 1804669</a> +<p id="display"></p> +<div id="content"> + <input id="input" type="date"> + <div id="host"></div> +</div> +<pre id="test"> +<script type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +var testData = [ + /** + * keys: keys to send to the input element. + * initialVal: initial value set to the input element. + * expectedVal: expected value of the input element after sending the keys. + */ + { + // Type 11222016, default order is month, day, year. + keys: ["11222016"], + initialVal: "", + expectedVal: "2016-11-22" + }, + { + // Type 3 in the month field will automatically advance to the day field, + // then type 5 in the day field will automatically advance to the year + // field. + keys: ["352016"], + initialVal: "", + expectedVal: "2016-03-05" + }, + { + // Type 13 in the month field will set it to the maximum month, which is + // 12. + keys: ["13012016"], + initialVal: "", + expectedVal: "2016-12-01" + }, + { + // Type 00 in the month field will set it to the minimum month, which is 1. + keys: ["00012016"], + initialVal: "", + expectedVal: "2016-01-01" + }, + { + // Type 33 in the day field will set it to the maximum day, which is 31. + keys: ["12332016"], + initialVal: "", + expectedVal: "2016-12-31" + }, + { + // Type 00 in the day field will set it to the minimum day, which is 1. + keys: ["12002016"], + initialVal: "", + expectedVal: "2016-12-01" + }, + { + // Type 275769 in the year field will set it to 0069, because the + // 5th digit will erase the previous 4 digits. + keys: ["0101275769"], + initialVal: "", + expectedVal: "0069-01-01" + }, + { + // Type 0000 in the year field will set it to the minimum year, which is + // 0001. + keys: ["01010000"], + initialVal: "", + expectedVal: "0001-01-01" + }, + { + // Advance to year field and decrement. + keys: ["KEY_Tab", "KEY_Tab", "KEY_ArrowDown"], + initialVal: "2016-11-25", + expectedVal: "2015-11-25" + }, + { + // Right key should do the same thing as TAB key. + keys: ["KEY_ArrowRight", "KEY_ArrowRight", "KEY_ArrowDown"], + initialVal: "2016-11-25", + expectedVal: "2015-11-25" + }, + { + // Advance to day field then back to month field and decrement. + keys: ["KEY_ArrowRight", "KEY_ArrowLeft", "KEY_ArrowDown"], + initialVal: "2000-05-01", + expectedVal: "2000-04-01" + }, + { + // Focus starts on the first field, month in this case, and increment. + keys: ["KEY_ArrowUp"], + initialVal: "2000-03-01", + expectedVal: "2000-04-01" + }, + { + // Advance to day field and decrement. + keys: ["KEY_Tab", "KEY_ArrowDown"], + initialVal: "1234-01-01", + expectedVal: "1234-01-31" + }, + { + // Advance to day field and increment. + keys: ["KEY_Tab", "KEY_ArrowUp"], + initialVal: "1234-01-01", + expectedVal: "1234-01-02" + }, + { + // PageUp on month field increments month by 3. + keys: ["KEY_PageUp"], + initialVal: "1999-01-01", + expectedVal: "1999-04-01" + }, + { + // PageDown on month field decrements month by 3. + keys: ["KEY_PageDown"], + initialVal: "1999-01-01", + expectedVal: "1999-10-01" + }, + { + // PageUp on day field increments day by 7. + keys: ["KEY_Tab", "KEY_PageUp"], + initialVal: "1999-01-01", + expectedVal: "1999-01-08" + }, + { + // PageDown on day field decrements day by 7. + keys: ["KEY_Tab", "KEY_PageDown"], + initialVal: "1999-01-01", + expectedVal: "1999-01-25" + }, + { + // PageUp on year field increments year by 10. + keys: ["KEY_Tab", "KEY_Tab", "KEY_PageUp"], + initialVal: "1999-01-01", + expectedVal: "2009-01-01" + }, + { + // PageDown on year field decrements year by 10. + keys: ["KEY_Tab", "KEY_Tab", "KEY_PageDown"], + initialVal: "1999-01-01", + expectedVal: "1989-01-01" + }, + { + // Home key on month field sets it to the minimum month, which is 01. + keys: ["KEY_Home"], + initialVal: "2016-06-01", + expectedVal: "2016-01-01" + }, + { + // End key on month field sets it to the maximum month, which is 12. + keys: ["KEY_End"], + initialVal: "2016-06-01", + expectedVal: "2016-12-01" + }, + { + // Home key on day field sets it to the minimum day, which is 01. + keys: ["KEY_Tab", "KEY_Home"], + initialVal: "2016-01-10", + expectedVal: "2016-01-01" + }, + { + // End key on day field sets it to the maximum day, which is 31. + keys: ["KEY_Tab", "KEY_End"], + initialVal: "2016-01-10", + expectedVal: "2016-01-31" + }, + { + // Home key should have no effect on year field. + keys: ["KEY_Tab", "KEY_Tab", "KEY_Home"], + initialVal: "2016-01-01", + expectedVal: "2016-01-01" + }, + { + // End key should have no effect on year field. + keys: ["KEY_Tab", "KEY_Tab", "KEY_End"], + initialVal: "2016-01-01", + expectedVal: "2016-01-01" + }, + { + // Incomplete value maps to empty .value. + keys: ["1111"], + initialVal: "", + expectedVal: "" + }, + { + // Backspace key should clean a month field and map to empty .value. + keys: ["KEY_Backspace"], + initialVal: "2016-01-01", + expectedVal: "" + }, + { + // Backspace key should clean a day field and map to empty .value. + keys: ["KEY_Tab", "KEY_Backspace"], + initialVal: "2016-01-01", + expectedVal: "" + }, + { + // Backspace key should clean a year field and map to empty .value. + keys: ["KEY_Tab", "KEY_Tab", "KEY_Backspace"], + initialVal: "2016-01-01", + expectedVal: "" + }, + { + // Backspace key on Calendar button should not change a value. + keys: ["KEY_Tab", "KEY_Tab", "KEY_Tab", "KEY_Backspace"], + initialVal: "2016-01-01", + expectedVal: "2016-01-01" + }, +]; + +function sendKeys(aKeys) { + for (let i = 0; i < aKeys.length; i++) { + let key = aKeys[i]; + if (key.startsWith("KEY_")) { + synthesizeKey(key); + } else { + sendString(key); + } + } +} + +function test() { + document.querySelector("#host").attachShadow({ mode: "open" }).innerHTML = ` + <input type="date"> + `; + + function chromeListener(e) { + ok(false, "Picker should not be opened when dispatching untrusted click."); + } + + for (const elem of [document.getElementById("input"), document.getElementById("host").shadowRoot.querySelector("input")]) { + for (let { keys, initialVal, expectedVal } of testData) { + elem.focus(); + elem.value = initialVal; + sendKeys(keys); + is(elem.value, expectedVal, + "Test with " + keys + ", result should be " + expectedVal); + elem.value = ""; + elem.blur(); + } + SpecialPowers.addChromeEventListener("MozOpenDateTimePicker", + chromeListener); + elem.click(); + SpecialPowers.removeChromeEventListener("MozOpenDateTimePicker", + chromeListener); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_datetime_calendar_button.html b/dom/html/test/forms/test_input_datetime_calendar_button.html new file mode 100644 index 0000000000..970eee9027 --- /dev/null +++ b/dom/html/test/forms/test_input_datetime_calendar_button.html @@ -0,0 +1,179 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1479708 +--> +<head> +<title>Test required date/datetime-local input's Calendar button</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<link rel="stylesheet" href="/tests/SimpleTest/test.css" /> +</head> +<body> +Created for <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1479708">Mozilla Bug 1479708</a> and updated by <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1676068">Mozilla Bug 1676068</a> and <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1865885">Mozilla Bug 1865885</a> +<p id="display"></p> +<div id="content"> +<input type="date" id="id_date" value="2017-06-08"> +<input type="time" id="id_time" value="10:30"> +<input type="datetime-local" id="id_datetime-local" value="2017-06-08T10:30"> +<input type="date" id="id_date_required" value="2017-06-08" required> +<input type="time" id="id_time_required" value="10:30" required> +<input type="datetime-local" id="id_datetime-local_required" value="2017-06-08T10:30" required> +<input type="date" id="id_date_readonly" value="2017-06-08" readonly> +<input type="time" id="id_time_readonly" value="10:30" readonly> +<input type="datetime-local" id="id_datetime-local_readonly" value="2017-06-08T10:30" readonly> +<input type="date" id="id_date_disabled" value="2017-06-08" disabled> +<input type="time" id="id_time_disabled" value="10:30" disabled> +<input type="datetime-local" id="id_datetime-local_disabled" value="2017-06-08T10:30" disabled> +</div> +<pre id="test"> +<script class="testbody"> + +const kTypes = ["date", "time", "datetime-local"]; + +function id_for_type(type, kind) { + return "id_" + type + (kind ? "_" + kind : ""); +} + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + // Initial load. + assert_calendar_visible_all(""); + assert_calendar_visible_all("required"); + assert_calendar_hidden_all("readonly"); + assert_calendar_hidden_all("disabled"); + + // Dynamic toggling. + test_make_readonly(""); + test_make_editable("readonly"); + test_disabled_field_disabled(); + + // Now toggle the inputs to the initial state, but while being + // display: none. This tests for bug 1567191. + for (const input of document.querySelectorAll("input")) { + input.style.display = "none"; + is(input.getBoundingClientRect().width, 0, "Should be undisplayed"); + } + + test_make_readonly("readonly"); + test_make_editable(""); + + // And test other toggling as well. + test_readonly_field_disabled(); + test_disabled_field_disabled(); + + SimpleTest.finish(); +}); + +function test_disabled_field_disabled() { + for (let type of kTypes) { + const id = id_for_type(type, "disabled"); + const input = document.getElementById(id); + + ok(input.disabled, `#${id} Should be disabled`); + ok( + is_calendar_button_hidden(id), + `disabled's Calendar button is hidden (${id})` + ); + + input.disabled = false; + ok(!input.disabled, `#${id} Should not be disabled anymore`); + if (type === "time") { + assert_calendar_hidden(id); + } else { + ok( + !is_calendar_button_hidden(id), + `enabled field's Calendar button is not hidden (${id})` + ); + } + + input.disabled = true; // reset to the original state. + } +} + +function test_readonly_field_disabled() { + for (let type of kTypes) { + const id = id_for_type(type, "readonly"); + const input = document.getElementById(id); + + ok(input.readOnly, `#${id} Should be read-only`); + ok(is_calendar_button_hidden(id), `readonly field's Calendar button is hidden (${id})`); + + input.readOnly = false; + ok(!input.readOnly, `#${id} Should not be read-only anymore`); + if (type === "time") { + assert_calendar_hidden(id); + } else { + ok( + !is_calendar_button_hidden(id), + `non-readonly field's Calendar button is not hidden (${id})` + ); + } + + input.readOnly = true; // reset to the original state. + } +} + +function test_make_readonly(kind) { + for (let type of kTypes) { + const id = id_for_type(type, kind); + const input = document.getElementById(id); + is(input.readOnly, false, `Precondition: input #${id} is editable`); + + input.readOnly = true; + assert_calendar_hidden(id); + } +} + +function test_make_editable(kind) { + for (let type of kTypes) { + const id = id_for_type(type, kind); + const input = document.getElementById(id); + is(input.readOnly, true, `Precondition: input #${id} is read-only`); + + input.readOnly = false; + if (type === "time") { + assert_calendar_hidden(id); + } else { + assert_calendar_visible(id); + } + } +} + +function assert_calendar_visible_all(kind) { + for (let type of kTypes) { + if (type === "time") { + assert_calendar_hidden(id_for_type(type, kind)); + } else { + assert_calendar_visible(id_for_type(type, kind)); + } + } +} +function assert_calendar_visible(id) { + const isCalendarButtonHidden = is_calendar_button_hidden(id); + ok(!isCalendarButtonHidden, `Calendar button is not hidden on #${id}`); +} + +function assert_calendar_hidden_all(kind) { + for (let type of kTypes) { + assert_calendar_hidden(id_for_type(type, kind)); + } +} + +function assert_calendar_hidden(id) { + const isCalendarButtonHidden = is_calendar_button_hidden(id); + ok(isCalendarButtonHidden, `Calendar button is hidden on #${id}`); +} + +function is_calendar_button_hidden(id) { + const input = document.getElementById(id); + const shadowRoot = SpecialPowers.wrap(input).openOrClosedShadowRoot; + const calendarButton = shadowRoot.getElementById("calendar-button"); + const calendarButtonDisplay = SpecialPowers.wrap(window).getComputedStyle(calendarButton).display; + return calendarButtonDisplay === "none"; +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_datetime_disabled_focus.html b/dom/html/test/forms/test_input_datetime_disabled_focus.html new file mode 100644 index 0000000000..68a89b1780 --- /dev/null +++ b/dom/html/test/forms/test_input_datetime_disabled_focus.html @@ -0,0 +1,82 @@ +<!DOCTYPE html>
+<title>Test for bugs 1772841 and 1865885</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1772841">Mozilla Bug 1772841</a> and <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1865885">Mozilla Bug 1865885</a>
+<div id="content">
+ <!-- Disabled -->
+ <input type="date" id="date" disabled>
+ <input type="time" id="time" disabled>
+ <input type="datetime-local" id="datetime-local" disabled>
+ <fieldset id="fieldset" disabled>
+ <input type="date" id="fieldset-date">
+ <input type="time" id="fieldset-time">
+ <input type="datetime-local" id="fieldset-datetime-local">
+ </fieldset>
+
+ <!-- Dynamically disabled -->
+ <input type="date" id="date1">
+ <input type="time" id="time1">
+ <input type="datetime-local" id="datetime-local1">
+ <fieldset id="fieldset1">
+ <input type="date" id="fieldset-date1">
+ <input type="time" id="fieldset-time1">
+ <input type="datetime-local" id="fieldset-datetime-local1">
+ </fieldset>
+
+ <!-- Dynamically enabled -->
+ <input type="date" id="date2" disabled>
+ <input type="time" id="time2" disabled>
+ <input type="datetime-local" id="datetime-local2" disabled>
+ <fieldset id="fieldset2" disabled>
+ <input type="date" id="fieldset-date2">
+ <input type="time" id="fieldset-time2">
+ <input type="datetime-local" id="fieldset-datetime-local2">
+ </fieldset>
+</div>
+<script>
+ /*
+ * Test for bugs 1772841 and 1865885
+ * This test checks that when a datetime input element is disabled by itself
+ * or from its containing fieldset, it should not be focusable by click.
+ **/
+
+ add_task(async function() {
+ await SimpleTest.promiseFocus(window);
+ for (let inputId of ["time", "date", "datetime-local", "fieldset-time", "fieldset-date", "fieldset-datetime-local"]) {
+ testFocusState(inputId, /* isDisabled = */ true);
+ testDynamicChange(inputId, "1", /* isDisabling = */ true);
+ testDynamicChange(inputId, "2", /* isDisabling = */ false);
+ }
+ })
+ function testFocusState(inputId, isDisabled) {
+ let input = document.getElementById(inputId);
+
+ document.getElementById("content").click();
+ input.click();
+ if (isDisabled) {
+ isnot(document.activeElement, input, `This disabled ${inputId} input should not be focusable by click`);
+ } else {
+ // The click method won't set the focus on clicked input, thus we
+ // only check that the state is changed to enabled here
+ ok(!input.disabled, `This ${inputId} input is not disabled`);
+ }
+
+ document.getElementById("content").click();
+ synthesizeMouseAtCenter(input, {});
+ if (isDisabled) {
+ isnot(document.activeElement, input, `This disabled ${inputId} input should not be focusable by click`);
+ } else {
+ is(document.activeElement, input, `This enabled ${inputId} input should be focusable by click`);
+ }
+ }
+ function testDynamicChange(inputId, index, isDisabling) {
+ if (inputId.split("-")[0] === "fieldset") {
+ document.getElementById("fieldset" + index).disabled = isDisabling;
+ } else {
+ document.getElementById(inputId + index).disabled = isDisabling;
+ }
+ testFocusState(inputId + index, /* isDisabled = */ isDisabling);
+ }
+</script>
diff --git a/dom/html/test/forms/test_input_datetime_focus_blur.html b/dom/html/test/forms/test_input_datetime_focus_blur.html new file mode 100644 index 0000000000..bff7b2ceb8 --- /dev/null +++ b/dom/html/test/forms/test_input_datetime_focus_blur.html @@ -0,0 +1,64 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1288591 +--> +<head> + <title>Test focus/blur behaviour for date/time input types</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1288591">Mozilla Bug 1288591</a> +<p id="display"></p> +<div id="content"> + <input id="input_time" type="time"> + <input id="input_date" type="date"> + <input id="input_datetime-local" type="datetime-local"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** + * Test for Bug 1288591. + * This test checks whether date/time input types' .focus()/.blur() works + * correctly. This test also checks when focusing on an date/time input element, + * the focus is redirected to the anonymous text control, but the + * document.activeElement still returns date/time input element. + **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +function testFocusBlur(type) { + let input = document.getElementById("input_" + type); + input.focus(); + + // The active element returns the date/time input element. + let activeElement = document.activeElement; + is(activeElement, input, "activeElement should be the date/time input element"); + is(activeElement.localName, "input", "activeElement should be an input element"); + is(activeElement.type, type, "activeElement should be of type " + type); + + // Use FocusManager to check that the actual focus is on the anonymous + // text control. + let fm = SpecialPowers.Cc["@mozilla.org/focus-manager;1"] + .getService(SpecialPowers.Ci.nsIFocusManager); + let focusedElement = fm.focusedElement; + is(focusedElement.localName, "span", "focusedElement should be an span element"); + + input.blur(); + isnot(document.activeElement, input, "activeElement should no longer be the datetime input element"); +} + +function test() { + for (let inputType of ["time", "date", "datetime-local"]) { + testFocusBlur(inputType); + } +} +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_datetime_focus_blur_events.html b/dom/html/test/forms/test_input_datetime_focus_blur_events.html new file mode 100644 index 0000000000..2e4e918119 --- /dev/null +++ b/dom/html/test/forms/test_input_datetime_focus_blur_events.html @@ -0,0 +1,93 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1301306 +--> +<head> +<title>Test for Bug 1301306</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1301306">Mozilla Bug 722599</a> +<p id="display"></p> +<div id="content"> +<input type="time" id="input_time" onfocus="++focusEvents[0]" + onblur="++blurEvents[0]" onfocusin="++focusInEvents[0]" + onfocusout="++focusOutEvents[0]"> +<input type="date" id="input_date" onfocus="++focusEvents[1]" + onblur="++blurEvents[1]" onfocusin="++focusInEvents[1]" + onfocusout="++focusOutEvents[1]"> +<input type="datetime-local" id="input_datetime-local" onfocus="++focusEvents[2]" + onblur="++blurEvents[2]" onfocusin="++focusInEvents[2]" + onfocusout="++focusOutEvents[2]"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** + * Test for Bug 1301306. + * This test checks that when moving inside the time input element, e.g. jumping + * through the inner text boxes, does not fire extra focus/blur events. + **/ + +var inputTypes = ["time", "date", "datetime-local"]; +var focusEvents = [0, 0, 0]; +var focusInEvents = [0, 0, 0]; +var focusOutEvents = [0, 0, 0]; +var blurEvents = [0, 0, 0]; + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +function test() { + for (var i = 0; i < inputTypes.length; i++) { + var input = document.getElementById("input_" + inputTypes[i]); + + input.focus(); + is(focusEvents[i], 1, inputTypes[i] + " input element should have dispatched focus event."); + is(focusInEvents[i], 1, inputTypes[i] + " input element should have dispatched focusin event."); + is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event."); + is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event."); + + // Move around inside the input element's input box. + synthesizeKey("KEY_Tab"); + is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event."); + is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event."); + is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event."); + is(blurEvents[i], 0, inputTypes[i] + " time input element should not have dispatched blur event."); + + synthesizeKey("KEY_ArrowRight"); + is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event."); + is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event."); + is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event."); + is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event."); + + synthesizeKey("KEY_ArrowLeft"); + is(focusEvents[i], 1,inputTypes[i] + " input element should not have dispatched focus event."); + is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event."); + is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event."); + is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event."); + + synthesizeKey("KEY_ArrowRight"); + is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event."); + is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event."); + is(focusOutEvents[i], 0, inputTypes[i] + " input element should not have dispatched focusout event."); + is(blurEvents[i], 0, inputTypes[i] + " input element should not have dispatched blur event."); + + input.blur(); + is(focusEvents[i], 1, inputTypes[i] + " input element should not have dispatched focus event."); + is(focusInEvents[i], 1, inputTypes[i] + " input element should not have dispatched focusin event."); + is(focusOutEvents[i], 1, inputTypes[i] + " input element should have dispatched focusout event."); + is(blurEvents[i], 1, inputTypes[i] + " input element should have dispatched blur event."); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_datetime_focus_state.html b/dom/html/test/forms/test_input_datetime_focus_state.html new file mode 100644 index 0000000000..3b771f2394 --- /dev/null +++ b/dom/html/test/forms/test_input_datetime_focus_state.html @@ -0,0 +1,79 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1346085 +--> +<head> + <title>Test moving focus in onfocus/onblur handler</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1346085">Mozilla Bug 1346085</a> +<p id="display"></p> +<div id="content"> + <input id="input_time" type="time"> + <input id="input_date" type="date"> + <input id="input_dummy" type="text"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** + * Test for Bug 1346085. + * This test checks whether date/time input types' focus state are set + * correctly, event when moving focus in onfocus/onblur handler. + **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +function testFocusState(type) { + let input = document.getElementById("input_" + type); + + input.focus(); + let focus = document.querySelector(":focus"); + let focusRing = document.querySelector(":-moz-focusring"); + is(focus, input, "input should have :focus state after focus"); + is(focusRing, input, "input should have :-moz-focusring state after focus"); + + input.blur(); + focus = document.querySelector(":focus"); + focusRing = document.querySelector(":-moz-focusring"); + isnot(focus, input, "input should not have :focus state after blur"); + isnot(focusRing, input, "input should not have :-moz-focusring state after blur"); + + input.addEventListener("focus", function() { + document.getElementById("input_dummy").focus(); + }, { once: true }); + + input.focus(); + focus = document.querySelector(":focus"); + focusRing = document.querySelector(":-moz-focusring"); + isnot(focus, input, "input should not have :focus state when moving focus in onfocus handler"); + isnot(focusRing, input, "input should not have :-moz-focusring state when moving focus in onfocus handler"); + + input.addEventListener("blur", function() { + document.getElementById("input_dummy").focus(); + }, { once: true }); + + input.blur(); + focus = document.querySelector(":focus"); + focusRing = document.querySelector(":-moz-focusring"); + isnot(focus, input, "input should not have :focus state when moving focus in onblur handler"); + isnot(focusRing, input, "input should not have :-moz-focusring state when moving focus in onblur handler"); +} + +function test() { + let inputTypes = ["time", "date"]; + + for (let i = 0; i < inputTypes.length; i++) { + testFocusState(inputTypes[i]); + } +} +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_datetime_hidden.html b/dom/html/test/forms/test_input_datetime_hidden.html new file mode 100644 index 0000000000..7d8a6766a9 --- /dev/null +++ b/dom/html/test/forms/test_input_datetime_hidden.html @@ -0,0 +1,32 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1514040 +--> +<head> + <title>Test construction of hidden date input type</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1514040">Mozilla Bug 1514040</a> +<p id="display"></p> +<div id="content"> + <input id="date" type="date" hidden value="1947-02-28"> +</div> +<pre id="test"> +<script type="application/javascript"> + +let el = document.getElementById("date"); +ok(el.hidden, "element is hidden"); +is(el.value, "1947-02-28", ".value is set correctly"); +let fieldElements = Array.from(SpecialPowers.wrap(el).openOrClosedShadowRoot.querySelectorAll(".datetime-edit-field")); +is(fieldElements[0].textContent, "02", "month is set"); +is(fieldElements[1].textContent, "28", "day is set"); +is(fieldElements[2].textContent, "1947", "year is set"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_datetime_input_change_events.html b/dom/html/test/forms/test_input_datetime_input_change_events.html new file mode 100644 index 0000000000..63c8012252 --- /dev/null +++ b/dom/html/test/forms/test_input_datetime_input_change_events.html @@ -0,0 +1,143 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1370858 +--> +<head> +<title>Test for Bugs 1370858 and 1804881</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1370858">Mozilla Bug 1370858</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1804881">Mozilla Bug 1804881</a> +<p id="display"></p> +<div id="content"> +<input type="time" id="input_time" onchange="++changeEvents[0]" + oninput="++inputEvents[0]"> +<input type="date" id="input_date" onchange="++changeEvents[1]" + oninput="++inputEvents[1]"> +<input type="datetime-local" id="input_datetime-local" onchange="++changeEvents[2]" + oninput="++inputEvents[2]"> +</div> +<pre id="test"> +<script class="testbody"> + +/** + * Test for Bug 1370858. + * Test that change and input events are (not) fired for date/time inputs. + **/ + +const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent); + +var inputTypes = ["time", "date", "datetime-local"]; +var changeEvents = [0, 0, 0]; +var inputEvents = [0, 0, 0]; +var values = ["10:30", "2017-06-08", "2017-06-08T10:30"]; +var expectedValues = [ + ["09:30", "01:30", "01:25", "", "01:59", "13:59", ""], + ["2017-05-08", "2017-01-08", "2017-01-25", "", "2017-01-31", "2017-01-31", ""], + ["2017-05-08T10:30", "2017-01-08T10:30", "2017-01-25T10:30", "", "2017-01-31T10:30", "2017-01-31T10:30", ""] +]; + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +function test() { + for (var i = 0; i < inputTypes.length; i++) { + var input = document.getElementById("input_" + inputTypes[i]); + + is(changeEvents[i], 0, "Number of change events should be 0 at start."); + is(inputEvents[i], 0, "Number of input events should be 0 at start."); + + // Test that change and input events are not dispatched setting .value by + // script. + input.value = values[i]; + is(input.value, values[i], "Check that value was set correctly (0)."); + is(changeEvents[i], 0, "Change event should not have dispatched (0)."); + is(inputEvents[i], 0, "Input event should not have dispatched (0)."); + + // Test that change and input events are fired when changing the value using + // up/down keys. + input.focus(); + synthesizeKey("KEY_ArrowDown"); + is(input.value, expectedValues[i][0], "Check that value was set correctly (1)."); + is(changeEvents[i], 1, "Change event should be dispatched (1)."); + is(inputEvents[i], 1, "Input event should be dispatched (1)."); + + // Test that change and input events are fired when changing the value with + // the keyboard. + sendString("01"); + // We get event per character. + is(input.value, expectedValues[i][1], "Check that value was set correctly (2)."); + is(changeEvents[i], 3, "Change event should be dispatched (2)."); + is(inputEvents[i], 3, "Input event should be dispatched (2)."); + + // Test that change and input events are fired when changing the value with + // both the numeric keyboard and digit keys. + synthesizeKey("2", { code: "Numpad2" }); + synthesizeKey("5"); + // We get event per character. + is(input.value, expectedValues[i][2], "Check that value was set correctly (3)."); + is(changeEvents[i], 5, "Change event should be dispatched (3)."); + is(inputEvents[i], 5, "Input event should be dispatched (3)."); + + // Test that change and input events are not fired when navigating with Tab. + // Return to the previously focused field (minutes, day, day). + synthesizeKey("KEY_Tab", { shiftKey: true }); + is(input.value, expectedValues[i][2], "Check that value was not changed (4)."); + is(changeEvents[i], 5, "Change event should not be dispatched (4)."); + is(inputEvents[i], 5, "Input event should not be dispatched (4)."); + + // Test that change and input events are fired when using Backspace. + synthesizeKey("KEY_Backspace"); + // We get event per character. + is(input.value, expectedValues[i][3], "Check that value was set correctly (5)."); + is(changeEvents[i], 6, "Change event should be dispatched (5)."); + is(inputEvents[i], 6, "Input event should be dispatched (5)."); + + // Test that change and input events are fired when using Home key. + synthesizeKey("KEY_End"); + // We get event per character. + is(input.value, expectedValues[i][4], "Check that value was set correctly (6)."); + is(changeEvents[i], 7, "Change event should be dispatched (6)."); + is(inputEvents[i], 7, "Input event should be dispatched (6)."); + + // Test that change and input events are fired for time and not fired + // for others when changing the value with a letter key. + // Navigate to the next field (time of the day, year, year). + synthesizeKey("KEY_Tab"); + synthesizeKey("P"); + // We get event per character. + is(input.value, expectedValues[i][5], "Check that value was set correctly (7)."); + if (i === 0) { + // For the time input, the time of the day should be focused and it, + // as an AM/PM toggle, should change to "PM" when the "p" key is pressed + is(changeEvents[i], 8, "Change event should be dispatched (7)."); + is(inputEvents[i], 8, "Input event should be dispatched (7)."); + } else { + // For the date and datetime inputs, the year should be focused and it, + // as a numeric value, should not change when the "p" key is pressed + is(changeEvents[i], 7, "Change event should not be dispatched (7)."); + is(inputEvents[i], 7, "Input event should not be dispatched (7)."); + } + + // Test that change and input events are fired when clearing the value + // using a Ctrl/Cmd+Delete/Backspace key combination + let events = (i === 0) ? 9 : 8; + synthesizeKey("KEY_Backspace", { accelKey: true }); + // We get one event + is(input.value, expectedValues[i][6], "Check that value was cleared out correctly (8)."); + is(changeEvents[i], events, "Change event should be dispatched (8)."); + is(inputEvents[i], events, "Input event should be dispatched (8)."); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_datetime_readonly.html b/dom/html/test/forms/test_input_datetime_readonly.html new file mode 100644 index 0000000000..aa7b40753b --- /dev/null +++ b/dom/html/test/forms/test_input_datetime_readonly.html @@ -0,0 +1,20 @@ +<!doctype html> +<title>Test for bug 1461509</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +<input id="i" type="date" value="1995-11-20" readonly required> +<script> +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + let input = document.getElementById("i"); + let value = input.value; + + isnot(value, "", "should have a value"); + + input.focus(); + synthesizeKey("KEY_Backspace"); + is(input.value, value, "Value shouldn't change"); + SimpleTest.finish(); +}); +</script> diff --git a/dom/html/test/forms/test_input_datetime_reset_default_value_input_change_event.html b/dom/html/test/forms/test_input_datetime_reset_default_value_input_change_event.html new file mode 100644 index 0000000000..393de9fdee --- /dev/null +++ b/dom/html/test/forms/test_input_datetime_reset_default_value_input_change_event.html @@ -0,0 +1,122 @@ +<!DOCTYPE HTML> +<html> +<!-- + https://bugzilla.mozilla.org/show_bug.cgi?id=1446722 +--> +<head> +<title>Test for bug 1446722</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<script type="application/javascript" src="utils.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1446722">Mozilla bug 1446722</a> +<p id="display"></p> +<div id="content"> +<form> +<input type="time" id="input_time" value="10:30" onchange="++numberChangeEvents" + oninput="++numberInputEvents"> +<input type="date" id="input_date" value="2012-05-06" onchange="++numberChangeEvents" + oninput="++numberInputEvents"> +<input type="time" id="input_time2" value="11:30" onchange="++numberChangeEvents" + oninput="++numberInputEvents"> +<input type="date" id="input_date2" value="2014-07-08" + onchange="++numberChangeEvents" + oninput="++numberInputEvents"> +<input type="time" id="input_time3" value="12:30" onchange="++numberChangeEvents" + oninput="++numberInputEvents"> +<input type="date" id="input_date3" value="2014-08-09" + onchange="++numberChangeEvents" + oninput="++numberInputEvents"> +<input type="reset" id="input_reset"> +</form> +</div> +<pre id="test"> +<script class="testbody" type="application/javascript"> + +/** + * Test for bug 1446722. + * + * Test change and input events are fired for date and time inputs when the + * default value is reset from the date UI and the time UI. + * Test they are not fired when the value is changed via a script. + * Test clicking the reset button of a form does not fire these events. + **/ + +const INPUT_FIELD_ID_PREFIX = "input_"; + +var numberChangeEvents = 0; +var numberInputEvents = 0; + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test_reset_in_script_does_not_trigger_change_and_input_event( + "time2", numberChangeEvents, numberInputEvents); + test_reset_in_script_does_not_trigger_change_and_input_event( + "date2", numberChangeEvents, numberInputEvents); + + test_reset_form_does_not_trigger_change_and_input_events("time3", "14:00", + numberChangeEvents, numberInputEvents); + test_reset_form_does_not_trigger_change_and_input_events("date3", "2016-01-01", + numberChangeEvents, numberInputEvents); + + SimpleTest.finish(); +}); + +function test_reset_in_script_does_not_trigger_change_and_input_event( + inputFieldIdSuffix, oldNumberChangeEvents, oldNumberInputEvents) { + const inputFieldName = INPUT_FIELD_ID_PREFIX + inputFieldIdSuffix; + var input = document.getElementById(inputFieldName); + + is(input.value, input.defaultValue, + "Check " + inputFieldName + "'s default value is initialized correctly."); + is(numberChangeEvents, oldNumberChangeEvents, + "Check numberChangeEvents is initialized correctly for " + inputFieldName + + "."); + is(numberInputEvents, oldNumberInputEvents, + "Check numberInputEvents is initialized correctly for " + inputFieldName + + "."); + + input.value = ""; + + is(numberChangeEvents, oldNumberChangeEvents, + "Change event should not be dispatched for " + inputFieldName + "."); + is(numberInputEvents, oldNumberInputEvents, + "Input event should not be dispatched for " + inputFieldName + "."); +} + +function test_reset_form_does_not_trigger_change_and_input_events( + inputFieldIdSuffix, newValue, oldNumberChangeEvents, oldNumberInputEvents) { + const inputFieldName = INPUT_FIELD_ID_PREFIX + inputFieldIdSuffix; + const inputFieldResetButtonName = "input_reset"; + var input = document.getElementById(inputFieldName); + + is(input.value, input.defaultValue, + "Check " + inputFieldName + "'s default value is initialized correctly."); + isnot(input.defaultValue, newValue, "Check default value differs from newValue for " + + inputFieldName + "."); + is(numberChangeEvents, oldNumberChangeEvents, + "Check numberChangeEvents is initialized correctly for " + inputFieldName + + "."); + is(numberInputEvents, oldNumberInputEvents, + "Check numberInputEvents is initialized correctly for " + inputFieldName + + "."); + + input.value = newValue; + + var resetButton = document.getElementById(inputFieldResetButtonName); + synthesizeMouseAtCenter(resetButton, {}); + + is(input.value, input.defaultValue, "Check value is reset to default for " + + inputFieldName + "."); + is(numberChangeEvents, oldNumberChangeEvents, + "Change event should not be dispatched for " + inputFieldResetButtonName + "."); + is(numberInputEvents, oldNumberInputEvents, + "Input event should not be dispatched for " + inputFieldResetButtonName + "."); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_datetime_tabindex.html b/dom/html/test/forms/test_input_datetime_tabindex.html new file mode 100644 index 0000000000..207a7a8a8e --- /dev/null +++ b/dom/html/test/forms/test_input_datetime_tabindex.html @@ -0,0 +1,113 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1288591 +--> +<head> + <title>Test tabindex attribute for date/time input types</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1288591">Mozilla Bug 1288591</a> +<p id="display"></p> +<div id="content"> + <input id="time1" type="time" tabindex="0"> + <input id="time2" type="time" tabindex="-1"> + <input id="time3" type="time" tabindex="0"> + <input id="time4" type="time" disabled> + <input id="date1" type="date" tabindex="0"> + <input id="date2" type="date" tabindex="-1"> + <input id="date3" type="date" tabindex="0"> + <input id="date4" type="date" disabled> + <input id="datetime-local1" type="datetime-local" tabindex="0"> + <input id="datetime-local2" type="datetime-local" tabindex="-1"> + <input id="datetime-local3" type="datetime-local" tabindex="0"> + <input id="datetime-local4" type="datetime-local" disabled> +</div> +<pre id="test"> +<script> +/** + * Test for Bug 1288591. + * This test checks whether date/time input types tabindex attribute works + * correctly. + **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +function checkInnerTextboxTabindex(input, tabindex) { + let fields = SpecialPowers.wrap(input).openOrClosedShadowRoot.querySelectorAll(".datetime-edit-field"); + + for (let field of fields) { + is(field.tabIndex, tabindex, "tabIndex in the inner textbox should be correct"); + } + +} + +function testTabindex(type) { + let input1 = document.getElementById(type + "1"); + let input2 = document.getElementById(type + "2"); + let input3 = document.getElementById(type + "3"); + let input4 = document.getElementById(type + "4"); + + input1.focus(); + is(document.activeElement, input1, + "input element with tabindex=0 is focusable"); + + // Time input does not include a Calendar button + let fieldCount; + if (type == "datetime-local") { + fieldCount = 7; + } else if (type == "date") { + fieldCount = 4; + } else { + fieldCount = 3; + }; + + // Advance through inner fields. + for (let i = 0; i < fieldCount - 1; ++i) { + synthesizeKey("KEY_Tab"); + is(document.activeElement, input1, + "input element with tabindex=0 is tabbable"); + } + + // Advance to next element + synthesizeKey("KEY_Tab"); + is(document.activeElement, input3, + "input element with tabindex=-1 is not tabbable"); + + input2.focus(); + is(document.activeElement, input2, + "input element with tabindex=-1 is still focusable"); + + checkInnerTextboxTabindex(input1, 0); + checkInnerTextboxTabindex(input2, -1); + checkInnerTextboxTabindex(input3, 0); + + // Changing the tabindex attribute dynamically. + input3.setAttribute("tabindex", "-1"); + + synthesizeKey("KEY_Tab"); // need only one TAB since input2 is not tabbable + + isnot(document.activeElement, input3, + "element with tabindex changed to -1 should not be tabbable"); + isnot(document.activeElement, input4, + "disabled element should not be tabbable"); + + checkInnerTextboxTabindex(input3, -1); +} + +function test() { + for (let inputType of ["time", "date", "datetime-local"]) { + testTabindex(inputType); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_defaultValue.html b/dom/html/test/forms/test_input_defaultValue.html new file mode 100644 index 0000000000..03849d7f54 --- /dev/null +++ b/dom/html/test/forms/test_input_defaultValue.html @@ -0,0 +1,81 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=977029 +--> +<head> + <title>Test for Bug 977029</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> +<div id="content"> + <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=977029">Bug 977029</a> + <p> + Goal of this test is to check that modifying defaultValue and value attribute + of input types is working as expected. + </p> + <form> + <input id='a' type="color" value="#00ff00"> + <input id='b' type="text" value="foo"> + <input id='c' type="email" value="foo"> + <input id='d' type="date" value="2010-09-20"> + <input id='e' type="search" value="foo"> + <input id='f' type="tel" value="foo"> + <input id='g' type="url" value="foo"> + <input id='h' type="number" value="42"> + <input id='i' type="range" value="42" min="0" max="100"> + <input id='j' type="time" value="17:00:25.54"> + </form> +</div> +<script type="application/javascript"> + +// [ element id | original defaultValue | another value | another default value] +// Preferably use only valid values: the goal of this test isn't to test the +// value sanitization algorithm (for input types which have one) as this is +// already part of another test) +var testData = [["a", "#00ff00", "#00aaaa", "#00ccaa"], + ["b", "foo", "bar", "tulip"], + ["c", "foo", "foo@bar.org", "tulip"], + ["d", "2010-09-20", "2012-09-21", ""], + ["e", "foo", "bar", "tulip"], + ["f", "foo", "bar", "tulip"], + ["g", "foo", "bar", "tulip"], + ["h", "42", "1337", "3"], + ["i", "42", "17", "3"], + ["j", "17:00:25.54", "07:00:25", "03:00:03"], + ]; + +for (var data of testData) { + id = data[0]; + input = document.getElementById(id); + originalDefaultValue = data[1]; + is(originalDefaultValue, input.defaultValue, + "Default value isn't the expected one"); + is(originalDefaultValue, input.value, + "input.value original value is different from defaultValue"); + input.defaultValue = data[2] + is(input.defaultValue, input.value, + "Changing default value before value was changed should change value too"); + input.value = data[3]; + input.defaultValue = originalDefaultValue; + is(input.value, data[3], + "Changing default value after value was changed should not change value"); + input.value = data[2]; + is(originalDefaultValue, input.defaultValue, + "defaultValue shouldn't change when changing value"); + input.defaultValue = data[3]; + is(input.defaultValue, data[3], + "defaultValue should have changed"); + // Change the value... + input.value = data[2]; + is(input.value, data[2], + "value should have changed"); + // ...then reset the form + input.form.reset(); + is(input.defaultValue, input.value, + "reset form should bring back the default value"); +} +</script> +</body> +</html> + diff --git a/dom/html/test/forms/test_input_email.html b/dom/html/test/forms/test_input_email.html new file mode 100644 index 0000000000..96ff939215 --- /dev/null +++ b/dom/html/test/forms/test_input_email.html @@ -0,0 +1,237 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=555559 +https://bugzilla.mozilla.org/show_bug.cgi?id=668817 +https://bugzilla.mozilla.org/show_bug.cgi?id=854812 +--> +<head> + <title>Test for <input type='email'> validity</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=555559">Mozilla Bug 555559</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=668817">Mozilla Bug 668817</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=854812">Mozilla Bug 854812</a> +<p id="display"></p> +<div id="content" style="display: none"> + <form> + <input type='email' name='email' id='i' oninvalid="invalidEventHandler(event);"> + <form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for <input type='email'> validity **/ + +var gInvalid = false; + +function invalidEventHandler(e) +{ + is(e.type, "invalid", "Invalid event type should be invalid"); + gInvalid = true; +} + +function checkValidEmailAddress(element) +{ + gInvalid = false; + ok(!element.validity.typeMismatch && !element.validity.badInput, + "Element should not suffer from type mismatch or bad input (with value='"+element.value+"')"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "Element should be valid"); + ok(!gInvalid, "The invalid event should not have been thrown"); + is(element.validationMessage, '', + "Validation message should be the empty string"); + ok(element.matches(":valid"), ":valid pseudo-class should apply"); +} + +const VALID = 0; +const TYPE_MISMATCH = 1 << 0; +const BAD_INPUT = 1 << 1; + +function checkInvalidEmailAddress(element, failedValidityStates) +{ + info("Checking " + element.value); + gInvalid = false; + var expectTypeMismatch = !!(failedValidityStates & TYPE_MISMATCH); + var expectBadInput = !!(failedValidityStates & BAD_INPUT); + ok(element.validity.typeMismatch == expectTypeMismatch, + "Element should " + (expectTypeMismatch ? "" : "not ") + "suffer from type mismatch (with value='"+element.value+"')"); + ok(element.validity.badInput == expectBadInput, + "Element should " + (expectBadInput ? "" : "not ") + "suffer from bad input (with value='"+element.value+"')"); + ok(!element.validity.valid, "Element should not be valid"); + ok(!element.checkValidity(), "Element should not be valid"); + ok(gInvalid, "The invalid event should have been thrown"); + is(element.validationMessage, "Please enter an email address.", + "Validation message is not valid"); + ok(element.matches(":invalid"), ":invalid pseudo-class should apply"); +} + +function testEmailAddress(aElement, aValue, aMultiple, aValidityFailures) +{ + aElement.multiple = aMultiple; + aElement.value = aValue; + + if (!aValidityFailures) { + checkValidEmailAddress(aElement); + } else { + checkInvalidEmailAddress(aElement, aValidityFailures); + } +} + +var email = document.forms[0].elements[0]; + +// Simple values, checking the e-mail syntax validity. +var values = [ + [ '' ], // The empty string shouldn't be considered as invalid. + [ 'foo@bar.com', VALID ], + [ ' foo@bar.com', VALID ], + [ 'foo@bar.com ', VALID ], + [ '\r\n foo@bar.com', VALID ], + [ 'foo@bar.com \n\r', VALID ], + [ '\n\n \r\rfoo@bar.com\n\n \r\r', VALID ], + [ '\n\r \n\rfoo@bar.com\n\r \n\r', VALID ], + [ 'tulip', TYPE_MISMATCH ], + // Some checks on the user part of the address. + [ '@bar.com', TYPE_MISMATCH ], + [ 'f\noo@bar.com', VALID ], + [ 'f\roo@bar.com', VALID ], + [ 'f\r\noo@bar.com', VALID ], + [ 'fü@foo.com', TYPE_MISMATCH ], + // Some checks for the domain part. + [ 'foo@bar', VALID ], + [ 'foo@b', VALID ], + [ 'foo@', TYPE_MISMATCH ], + [ 'foo@bar.', TYPE_MISMATCH ], + [ 'foo@foo.bar', VALID ], + [ 'foo@foo..bar', TYPE_MISMATCH ], + [ 'foo@.bar', TYPE_MISMATCH ], + [ 'foo@tulip.foo.bar', VALID ], + [ 'foo@tulip.foo-bar', VALID ], + [ 'foo@1.2', VALID ], + [ 'foo@127.0.0.1', VALID ], + [ 'foo@1.2.3', VALID ], + [ 'foo@b\nar.com', VALID ], + [ 'foo@b\rar.com', VALID ], + [ 'foo@b\r\nar.com', VALID ], + [ 'foo@.', TYPE_MISMATCH ], + [ 'foo@fü.com', VALID ], + [ 'foo@fu.cüm', VALID ], + [ 'thisUsernameIsLongerThanSixtyThreeCharactersInLengthRightAboutNow@mozilla.tld', VALID ], + // Long strings with UTF-8 in username. + [ 'this.is.email.should.be.longer.than.sixty.four.characters.föö@mözillä.tld', TYPE_MISMATCH ], + [ 'this-is-email-should-be-longer-than-sixty-four-characters-föö@mözillä.tld', TYPE_MISMATCH, true ], + // Long labels (labels greater than 63 chars long are not allowed). + [ 'foo@thislabelisexactly63characterssssssssssssssssssssssssssssssssss', VALID ], + [ 'foo@thislabelisexactly63characterssssssssssssssssssssssssssssssssss.com', VALID ], + [ 'foo@foo.thislabelisexactly63characterssssssssssssssssssssssssssssssssss.com', VALID ], + [ 'foo@foo.thislabelisexactly63characterssssssssssssssssssssssssssssssssss', VALID ], + [ 'foo@thislabelisexactly64charactersssssssssssssssssssssssssssssssssss', TYPE_MISMATCH | BAD_INPUT ], + [ 'foo@thislabelisexactly64charactersssssssssssssssssssssssssssssssssss.com', TYPE_MISMATCH | BAD_INPUT ], + [ 'foo@foo.thislabelisexactly64charactersssssssssssssssssssssssssssssssssss.com', TYPE_MISMATCH | BAD_INPUT ], + [ 'foo@foo.thislabelisexactly64charactersssssssssssssssssssssssssssssssssss', TYPE_MISMATCH | BAD_INPUT ], + // Long labels with UTF-8 (punycode encoding will increase the label to more than 63 chars). + [ 'foo@thisläbelisexäctly63charäcterssssssssssssssssssssssssssssssssss', TYPE_MISMATCH | BAD_INPUT ], + [ 'foo@thisläbelisexäctly63charäcterssssssssssssssssssssssssssssssssss.com', TYPE_MISMATCH | BAD_INPUT ], + [ 'foo@foo.thisläbelisexäctly63charäcterssssssssssssssssssssssssssssssssss.com', TYPE_MISMATCH | BAD_INPUT ], + [ 'foo@foo.thisläbelisexäctly63charäcterssssssssssssssssssssssssssssssssss', TYPE_MISMATCH | BAD_INPUT ], + // The domains labels (sub-domains or tld) can't start or finish with a '-' + [ 'foo@foo-bar', VALID ], + [ 'foo@-foo', TYPE_MISMATCH ], + [ 'foo@foo-.bar', TYPE_MISMATCH ], + [ 'foo@-.-', TYPE_MISMATCH ], + [ 'foo@fo-o.bar', VALID ], + [ 'foo@fo-o.-bar', TYPE_MISMATCH ], + [ 'foo@fo-o.bar-', TYPE_MISMATCH ], + [ 'foo@fo-o.-', TYPE_MISMATCH ], + [ 'foo@fo--o', VALID ], +]; + +// Multiple values, we don't check e-mail validity, only multiple stuff. +var multipleValues = [ + [ 'foo@bar.com, foo@bar.com', VALID ], + [ 'foo@bar.com,foo@bar.com', VALID ], + [ 'foo@bar.com,foo@bar.com,foo@bar.com', VALID ], + [ ' foo@bar.com , foo@bar.com ', VALID ], + [ '\tfoo@bar.com\t,\tfoo@bar.com\t', VALID ], + [ '\rfoo@bar.com\r,\rfoo@bar.com\r', VALID ], + [ '\nfoo@bar.com\n,\nfoo@bar.com\n', VALID ], + [ '\ffoo@bar.com\f,\ffoo@bar.com\f', VALID ], + [ '\t foo@bar.com\r,\nfoo@bar.com\f', VALID ], + [ 'foo@b,ar.com,foo@bar.com', TYPE_MISMATCH ], + [ 'foo@bar.com,foo@bar.com,', TYPE_MISMATCH ], + [ ' foo@bar.com , foo@bar.com , ', TYPE_MISMATCH ], + [ ',foo@bar.com,foo@bar.com', TYPE_MISMATCH ], + [ ',foo@bar.com,foo@bar.com', TYPE_MISMATCH ], + [ 'foo@bar.com,,,foo@bar.com', TYPE_MISMATCH ], + [ 'foo@bar.com;foo@bar.com', TYPE_MISMATCH ], + [ '<foo@bar.com>, <foo@bar.com>', TYPE_MISMATCH ], + [ 'foo@bar, foo@bar.com', VALID ], + [ 'foo@bar.com, foo', TYPE_MISMATCH ], + [ 'foo, foo@bar.com', TYPE_MISMATCH ], +]; + +/* Additional username checks. */ + +var legalCharacters = "abcdefghijklmnopqrstuvwxyz"; +legalCharacters += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +legalCharacters += "0123456789"; +legalCharacters += "!#$%&'*+-/=?^_`{|}~."; + +// Add all username legal characters individually to the list. +for (c of legalCharacters) { + values.push([c + "@bar.com", VALID]); +} +// Add the concatenation of all legal characters too. +values.push([legalCharacters + "@bar.com", VALID]); + +// Add username illegal characters, the same way. +var illegalCharacters = "()<>[]:;@\\, \t"; +for (c of illegalCharacters) { + values.push([illegalCharacters + "@bar.com", TYPE_MISMATCH]); +} + +/* Additional domain checks. */ + +legalCharacters = "abcdefghijklmnopqrstuvwxyz"; +legalCharacters += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +legalCharacters += "0123456789"; + +// Add domain legal characters (except '.' and '-' because they are special). +for (c of legalCharacters) { + values.push(["foo@foo.bar" + c, VALID]); +} +// Add the concatenation of all legal characters too. +values.push(["foo@bar." + legalCharacters, VALID]); + +// Add domain illegal characters. +illegalCharacters = "()<>[]:;@\\,!#$%&'*+/=?^_`{|}~ \t"; +for (c of illegalCharacters) { + values.push(['foo@foo.ba' + c + 'r', TYPE_MISMATCH]); +} + +values.forEach(function([value, valid, todo]) { + if (todo === true) { + email.value = value; + todo_is(email.validity.valid, true, "value should be valid"); + } else { + testEmailAddress(email, value, false, valid); + } +}); + +multipleValues.forEach(function([value, valid]) { + testEmailAddress(email, value, true, valid); +}); + +// Make sure setting multiple changes the value. +email.multiple = false; +email.value = "foo@bar.com, foo@bar.com"; +checkInvalidEmailAddress(email, TYPE_MISMATCH); +email.multiple = true; +checkValidEmailAddress(email); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_event.html b/dom/html/test/forms/test_input_event.html new file mode 100644 index 0000000000..72863ca335 --- /dev/null +++ b/dom/html/test/forms/test_input_event.html @@ -0,0 +1,409 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=851780 +--> +<head> +<title>Test for input event</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=851780">Mozilla Bug 851780</a> +<p id="display"></p> +<div id="content"></div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + + /** Test for input event. This is highly based on test_change_event.html **/ + + const isDesktop = !/Mobile|Tablet/.test(navigator.userAgent); + + let expectedInputType = ""; + let expectedData = null; + let expectedBeforeInputCancelable = false; + function checkBeforeInputEvent(aEvent, aDescription) { + ok(aEvent instanceof InputEvent, + `"beforeinput" event should be dispatched with InputEvent interface ${aDescription}`); + is(aEvent.inputType, expectedInputType, + `inputType of "beforeinput" event should be "${expectedInputType}" ${aDescription}`); + is(aEvent.data, expectedData, + `data of "beforeinput" event should be ${expectedData} ${aDescription}`); + is(aEvent.dataTransfer, null, + `dataTransfer of "beforeinput" event should be null ${aDescription}`); + is(aEvent.getTargetRanges().length, 0, + `getTargetRanges() of "beforeinput" event should return empty array ${aDescription}`); + is(aEvent.cancelable, expectedBeforeInputCancelable, + `"beforeinput" event for "${expectedInputType}" should ${expectedBeforeInputCancelable ? "be" : "not be"} cancelable ${aDescription}`); + is(aEvent.bubbles, true, + `"beforeinput" event should always bubble ${aDescription}`); + } + + let skipExpectedDataCheck = false; + function checkIfInputIsInputEvent(aEvent, aDescription) { + ok(aEvent instanceof InputEvent, + `"input" event should be dispatched with InputEvent interface ${aDescription}`); + is(aEvent.inputType, expectedInputType, + `inputType should be "${expectedInputType}" ${aDescription}`); + if (!skipExpectedDataCheck) + is(aEvent.data, expectedData, `data should be ${expectedData} ${aDescription}`); + else + info(`data is ${aEvent.data} ${aDescription}`); + is(aEvent.dataTransfer, null, + `dataTransfer should be null ${aDescription}`); + is(aEvent.cancelable, false, + `"input" event should be never cancelable ${aDescription}`); + is(aEvent.bubbles, true, + `"input" event should always bubble ${aDescription}`); + } + + function checkIfInputIsEvent(aEvent, aDescription) { + ok(aEvent instanceof Event && !(aEvent instanceof UIEvent), + `"input" event should be dispatched with InputEvent interface ${aDescription}`); + is(aEvent.cancelable, false, + `"input" event should be never cancelable ${aDescription}`); + is(aEvent.bubbles, true, + `"input" event should always bubble ${aDescription}`); + } + + let textareaInput = 0, textareaBeforeInput = 0; + let textTypes = ["text", "email", "search", "tel", "url", "password"]; + let textBeforeInput = [0, 0, 0, 0, 0, 0]; + let textInput = [0, 0, 0, 0, 0, 0]; + let nonTextTypes = ["button", "submit", "image", "reset", "radio", "checkbox"]; + let nonTextBeforeInput = [0, 0, 0, 0, 0, 0]; + let nonTextInput = [0, 0, 0, 0, 0, 0]; + let rangeInput = 0, rangeBeforeInput = 0; + let numberInput = 0, numberBeforeInput = 0; + + // Don't create elements whose event listener attributes are required before enabling `beforeinput` event. + function init() { + document.getElementById("content").innerHTML = + `<input type="file" id="fileInput"> + <textarea id="textarea"></textarea> + <input type="text" id="input_text"> + <input type="email" id="input_email"> + <input type="search" id="input_search"> + <input type="tel" id="input_tel"> + <input type="url" id="input_url"> + <input type="password" id="input_password"> + + <!-- "Non-text" inputs--> + <input type="button" id="input_button"> + <input type="submit" id="input_submit"> + <input type="image" id="input_image"> + <input type="reset" id="input_reset"> + <input type="radio" id="input_radio"> + <input type="checkbox" id="input_checkbox"> + <input type="range" id="input_range"> + <input type="number" id="input_number">`; + + document.getElementById("textarea").addEventListener("beforeinput", (aEvent) => { + ++textareaBeforeInput; + checkBeforeInputEvent(aEvent, "on textarea element"); + }); + document.getElementById("textarea").addEventListener("input", (aEvent) => { + ++textareaInput; + checkIfInputIsInputEvent(aEvent, "on textarea element"); + }); + + // These are the type were the input event apply. + for (let id of ["input_text", "input_email", "input_search", "input_tel", "input_url", "input_password"]) { + document.getElementById(id).addEventListener("beforeinput", (aEvent) => { + ++textBeforeInput[textTypes.indexOf(aEvent.target.type)]; + checkBeforeInputEvent(aEvent, `on input element whose type is ${aEvent.target.type}`); + }); + document.getElementById(id).addEventListener("input", (aEvent) => { + ++textInput[textTypes.indexOf(aEvent.target.type)]; + checkIfInputIsInputEvent(aEvent, `on input element whose type is ${aEvent.target.type}`); + }); + } + + // These are the type were the input event does not apply. + for (let id of ["input_button", "input_submit", "input_image", "input_reset", "input_radio", "input_checkbox"]) { + document.getElementById(id).addEventListener("beforeinput", (aEvent) => { + ++nonTextBeforeInput[nonTextTypes.indexOf(aEvent.target.type)]; + }); + document.getElementById(id).addEventListener("input", (aEvent) => { + ++nonTextInput[nonTextTypes.indexOf(aEvent.target.type)]; + checkIfInputIsEvent(aEvent, `on input element whose type is ${aEvent.target.type}`); + }); + } + + document.getElementById("input_range").addEventListener("beforeinput", (aEvent) => { + ++rangeBeforeInput; + }); + document.getElementById("input_range").addEventListener("input", (aEvent) => { + ++rangeInput; + checkIfInputIsEvent(aEvent, "on input element whose type is range"); + }); + + document.getElementById("input_number").addEventListener("beforeinput", (aEvent) => { + ++numberBeforeInput; + }); + document.getElementById("input_number").addEventListener("input", (aEvent) => { + ++numberInput; + checkIfInputIsInputEvent(aEvent, "on input element whose type is number"); + }); + } + + var MockFilePicker = SpecialPowers.MockFilePicker; + MockFilePicker.init(window); + + function testUserInput() { + // Simulating an OK click and with a file name return. + MockFilePicker.useBlobFile(); + MockFilePicker.returnValue = MockFilePicker.returnOK; + var input = document.getElementById('fileInput'); + input.focus(); + + input.addEventListener("beforeinput", function (aEvent) { + ok(false, "beforeinput event shouldn't be dispatched on file input."); + }); + input.addEventListener("input", function (aEvent) { + ok(true, "input event should've been dispatched on file input."); + checkIfInputIsEvent(aEvent, "on file input"); + }); + + input.click(); + SimpleTest.executeSoon(testUserInput2); + } + + function testUserInput2() { + // Some generic checks for types that support the input event. + for (var i = 0; i < textTypes.length; ++i) { + input = document.getElementById("input_" + textTypes[i]); + input.focus(); + expectedInputType = "insertLineBreak"; + expectedData = null; + expectedBeforeInputCancelable = true; + synthesizeKey("KEY_Enter"); + is(textBeforeInput[i], 1, "beforeinput event should've been dispatched on " + textTypes[i] + " input element"); + is(textInput[i], 0, "input event shouldn't be dispatched on " + textTypes[i] + " input element"); + + expectedInputType = "insertText"; + expectedData = "m"; + expectedBeforeInputCancelable = true; + sendString("m"); + is(textBeforeInput[i], 2, textTypes[i] + " input element should've been dispatched beforeinput event."); + is(textInput[i], 1, textTypes[i] + " input element should've been dispatched input event."); + expectedInputType = "insertLineBreak"; + expectedData = null; + expectedBeforeInputCancelable = true; + synthesizeKey("KEY_Enter", {shiftKey: true}); + is(textBeforeInput[i], 3, "input event should've been dispatched on " + textTypes[i] + " input element"); + is(textInput[i], 1, "input event shouldn't be dispatched on " + textTypes[i] + " input element"); + + expectedInputType = "deleteContentBackward"; + expectedData = null; + expectedBeforeInputCancelable = true; + synthesizeKey("KEY_Backspace"); + is(textBeforeInput[i], 4, textTypes[i] + " input element should've been dispatched beforeinput event."); + is(textInput[i], 2, textTypes[i] + " input element should've been dispatched input event."); + } + + // Some scenarios of value changing from script and from user input. + input = document.getElementById("input_text"); + input.focus(); + expectedInputType = "insertText"; + expectedData = "f"; + expectedBeforeInputCancelable = true; + sendString("f"); + is(textBeforeInput[0], 5, "beforeinput event should've been dispatched"); + is(textInput[0], 3, "input event should've been dispatched"); + input.blur(); + is(textBeforeInput[0], 5, "input event should not have been dispatched"); + is(textInput[0], 3, "input event should not have been dispatched"); + + input.focus(); + input.value = 'foo'; + is(textBeforeInput[0], 5, "beforeinput event should not have been dispatched"); + is(textInput[0], 3, "input event should not have been dispatched"); + input.blur(); + is(textBeforeInput[0], 5, "beforeinput event should not have been dispatched"); + is(textInput[0], 3, "input event should not have been dispatched"); + + input.focus(); + expectedInputType = "insertText"; + expectedData = "f"; + expectedBeforeInputCancelable = true; + sendString("f"); + is(textBeforeInput[0], 6, "beforeinput event should've been dispatched"); + is(textInput[0], 4, "input event should've been dispatched"); + input.value = 'bar'; + is(textBeforeInput[0], 6, "beforeinput event should not have been dispatched"); + is(textInput[0], 4, "input event should not have been dispatched"); + input.blur(); + is(textBeforeInput[0], 6, "beforeinput event should not have been dispatched"); + is(textInput[0], 4, "input event should not have been dispatched"); + + // Same for textarea. + var textarea = document.getElementById("textarea"); + textarea.focus(); + expectedInputType = "insertText"; + expectedData = "f"; + expectedBeforeInputCancelable = true; + sendString("f"); + is(textareaBeforeInput, 1, "beforeinput event should've been dispatched"); + is(textareaInput, 1, "input event should've been dispatched"); + textarea.blur(); + is(textareaBeforeInput, 1, "beforeinput event should not have been dispatched"); + is(textareaInput, 1, "input event should not have been dispatched"); + + textarea.focus(); + textarea.value = 'foo'; + is(textareaBeforeInput, 1, "beforeinput event should not have been dispatched"); + is(textareaInput, 1, "input event should not have been dispatched"); + textarea.blur(); + is(textareaBeforeInput, 1, "beforeinput event should not have been dispatched"); + is(textareaInput, 1, "input event should not have been dispatched"); + + textarea.focus(); + expectedInputType = "insertText"; + expectedData = "f"; + expectedBeforeInputCancelable = true; + sendString("f"); + is(textareaBeforeInput, 2, "beforeinput event should've been dispatched"); + is(textareaInput, 2, "input event should've been dispatched"); + textarea.value = 'bar'; + is(textareaBeforeInput, 2, "beforeinput event should not have been dispatched"); + is(textareaInput, 2, "input event should not have been dispatched"); + expectedInputType = "deleteContentBackward"; + expectedData = null; + expectedBeforeInputCancelable = true; + synthesizeKey("KEY_Backspace"); + is(textareaBeforeInput, 3, "beforeinput event should've been dispatched"); + is(textareaInput, 3, "input event should've been dispatched"); + textarea.blur(); + is(textareaBeforeInput, 3, "beforeinput event should not have been dispatched"); + is(textareaInput, 3, "input event should not have been dispatched"); + + // Non-text input tests: + for (var i = 0; i < nonTextTypes.length; ++i) { + // Button, submit, image and reset input type tests. + if (i < 4) { + input = document.getElementById("input_" + nonTextTypes[i]); + input.focus(); + input.click(); + is(nonTextBeforeInput[i], 0, "beforeinput event doesn't apply"); + is(nonTextInput[i], 0, "input event doesn't apply"); + input.blur(); + is(nonTextBeforeInput[i], 0, "beforeinput event doesn't apply"); + is(nonTextInput[i], 0, "input event doesn't apply"); + } + // For radio and checkboxes, input event should be dispatched. + else { + input = document.getElementById("input_" + nonTextTypes[i]); + input.focus(); + input.click(); + is(nonTextBeforeInput[i], 0, "beforeinput event should not have been dispatched"); + is(nonTextInput[i], 1, "input event should've been dispatched"); + input.blur(); + is(nonTextBeforeInput[i], 0, "beforeinput event should not have been dispatched"); + is(nonTextInput[i], 1, "input event should not have been dispatched"); + + // Test that input event is not dispatched if click event is cancelled. + function preventDefault(e) { + e.preventDefault(); + } + input.addEventListener("click", preventDefault); + input.click(); + is(nonTextBeforeInput[i], 0, "beforeinput event shouldn't be dispatched if click event is cancelled"); + is(nonTextInput[i], 1, "input event shouldn't be dispatched if click event is cancelled"); + input.removeEventListener("click", preventDefault); + } + } + + // Type changes. + var input = document.createElement('input'); + input.type = 'text'; + input.value = 'foo'; + input.onbeforeinput = function () { + ok(false, "we shouldn't get a beforeinput event when the type changes"); + }; + input.oninput = function() { + ok(false, "we shouldn't get an input event when the type changes"); + }; + input.type = 'range'; + isnot(input.value, 'foo'); + + // Tests for type='range'. + var range = document.getElementById("input_range"); + + range.focus(); + sendString("a"); + range.blur(); + is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched on range input " + + "element for key changes that don't change its value"); + is(rangeInput, 0, "input event shouldn't be dispatched on range input " + + "element for key changes that don't change its value"); + + range.focus(); + synthesizeKey("KEY_Home"); + is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched even for key changes"); + is(rangeInput, 1, "input event should be dispatched for key changes"); + range.blur(); + is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched on blur"); + is(rangeInput, 1, "input event shouldn't be dispatched on blur"); + + range.focus(); + var bcr = range.getBoundingClientRect(); + var centerOfRangeX = bcr.width / 2; + var centerOfRangeY = bcr.height / 2; + synthesizeMouse(range, centerOfRangeX - 10, centerOfRangeY, { type: "mousedown" }); + is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched on mousedown if the value changes"); + is(rangeInput, 2, "Input event should be dispatched on mousedown if the value changes"); + synthesizeMouse(range, centerOfRangeX - 5, centerOfRangeY, { type: "mousemove" }); + is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched during a drag"); + is(rangeInput, 3, "Input event should be dispatched during a drag"); + synthesizeMouse(range, centerOfRangeX, centerOfRangeY, { type: "mouseup" }); + is(rangeBeforeInput, 0, "beforeinput event shouldn't be dispatched at the end of a drag"); + is(rangeInput, 4, "Input event should be dispatched at the end of a drag"); + + // Tests for type='number'. + // We only test key events here since input events for mouse event changes + // are tested in test_input_number_mouse_events.html + var number = document.getElementById("input_number"); + + if (isDesktop) { // up/down arrow keys not supported on android + number.value = ""; + number.focus(); + // <input type="number">'s inputType value hasn't been decided, see + // https://github.com/w3c/input-events/issues/88 + expectedInputType = "insertReplacementText"; + expectedData = "1"; + expectedBeforeInputCancelable = false; + synthesizeKey("KEY_ArrowUp"); + is(numberBeforeInput, 1, "beforeinput event should be dispatched for up/down arrow key keypress"); + is(numberInput, 1, "input event should be dispatched for up/down arrow key keypress"); + is(number.value, "1", "sanity check value of number control after keypress"); + + // `data` will be the value of the input, but we can't change + // `expectedData` and use {repeat: 3} at the same time. + skipExpectedDataCheck = true; + synthesizeKey("KEY_ArrowDown", {repeat: 3}); + is(numberBeforeInput, 4, "beforeinput event should be dispatched for each up/down arrow key keypress event, even when rapidly repeated"); + is(numberInput, 4, "input event should be dispatched for each up/down arrow key keypress event, even when rapidly repeated"); + is(number.value, "-2", "sanity check value of number control after multiple keydown events"); + skipExpectedDataCheck = false; + + number.blur(); + is(numberBeforeInput, 4, "beforeinput event shouldn't be dispatched on blur"); + is(numberInput, 4, "input event shouldn't be dispatched on blur"); + } + + MockFilePicker.cleanup(); + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + document.addEventListener("DOMContentLoaded", () => { + init(); + SimpleTest.waitForFocus(testUserInput); + }, {once: true}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_file_picker.html b/dom/html/test/forms/test_input_file_picker.html new file mode 100644 index 0000000000..296c12bb7e --- /dev/null +++ b/dom/html/test/forms/test_input_file_picker.html @@ -0,0 +1,280 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for <input type='file'> file picker</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=377624">Mozilla Bug 36619</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=377624">Mozilla Bug 377624</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=565274">Mozilla Bug 565274</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=701353">Mozilla Bug 701353</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=826176">Mozilla Bug 826176</a> +<p id="display"></p> +<div id="content"> + <input id='a' type='file' accept="image/*"> + <input id='b' type='file' accept="audio/*"> + <input id='c' type='file' accept="video/*"> + <input id='d' type='file' accept="image/*, audio/* "> + <input id='e' type='file' accept=" image/*,video/*"> + <input id='f' type='file' accept="audio/*,video/*"> + <input id='g' type='file' accept="image/*, audio/* ,video/*"> + <input id='h' type='file' accept="foo/baz,image/*,bogus/duh"> + <input id='i' type='file' accept="mime/type;parameter,video/*"> + <input id='j' type='file' accept="audio/*, audio/*, audio/*"> + <input id='k' type="file" accept="image/gif,image/png"> + <input id='l' type="file" accept="image/*,image/gif,image/png"> + <input id='m' type="file" accept="image/gif,image/gif"> + <input id='n' type="file" accept=""> + <input id='o' type="file" accept=".test"> + <input id='p' type="file" accept="image/gif,.csv"> + <input id='q' type="file" accept="image/gif,.gif"> + <input id='r' type="file" accept=".prefix,.prefixPlusSomething"> + <input id='s' type="file" accept=".xls,.xlsx"> + <input id='t' type="file" accept=".mp3,.wav,.flac"> + <input id='u' type="file" accept=".xls, .xlsx"> + <input id='v' type="file" accept=".xlsx, .xls"> + <input id='w' type="file" accept=".xlsx; .xls"> + <input id='x' type="file" accept=".xls, .xlsx"> + <input id='y' type="file" accept=".xlsx, .xls"> + <input id='z' type='file' accept="i/am,a,pathological,;,,,,test/case"> + <input id='A' type="file" accept=".xlsx, .xls*"> + <input id='mix-ref' type="file" accept="image/jpeg"> + <input id='mix' type="file" accept="image/jpeg,.jpg"> + <input id='hidden' hidden type='file'> + <input id='untrusted-click' type='file'> + <input id='prevent-default' type='file'> + <input id='prevent-default-false' type='file'> + <input id='right-click' type='file'> + <input id='middle-click' type='file'> + <input id='left-click' type='file'> + <label id='label-1'>foo<input type='file'></label> + <label id='label-2' for='labeled-2'>foo</label><input id='labeled-2' type='file'></label> + <label id='label-3'>foo<input type='file'></label> + <label id='label-4' for='labeled-4'>foo</label><input id='labeled-4' type='file'></label> + <input id='by-button' type='file'> + <button id='button-click' onclick="document.getElementById('by-button').click();">foo</button> + <button id='button-down' onclick="document.getElementById('by-button').click();">foo</button> + <button id='button-up' onclick="document.getElementById('by-button').click();">foo</button> + <div id='div-click' onclick="document.getElementById('by-button').click();" tabindex='1'>foo</div> + <div id='div-click-on-demand' onclick="var i=document.createElement('input'); i.type='file'; i.click();" tabindex='1'>foo</div> + <div id='div-keydown' onkeydown="document.getElementById('by-button').click();" tabindex='1'>foo</div> + <a id='link-click' href="javascript:document.getElementById('by-button').click();" tabindex='1'>foo</a> + <input id='show-picker' type='file'> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** + * This test checks various scenarios and make sure that a file picker is being + * shown in all of them (minus a few exceptions). + * |testData| defines the tests to do and |launchNextTest| can be used to have + * specific behaviour for some tests. Everything else should just work. + */ + +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("untriaged"); + +var MockFilePicker = SpecialPowers.MockFilePicker; +MockFilePicker.init(window); + +// The following lists are from toolkit/content/filepicker.properties which is used by filePicker +var imageExtensionList = "*.jpe; *.jpg; *.jpeg; *.gif; *.png; *.bmp; *.ico; *.svg; *.svgz; *.tif; *.tiff; *.ai; *.drw; *.pct; *.psp; *.xcf; *.psd; *.raw; *.webp; *.heic" + +var audioExtensionList = "*.aac; *.aif; *.flac; *.iff; *.m4a; *.m4b; *.mid; *.midi; *.mp3; *.mpa; *.mpc; *.oga; *.ogg; *.opus; *.ra; *.ram; *.snd; *.wav; *.wma" + +var videoExtensionList = "*.avi; *.divx; *.flv; *.m4v; *.mkv; *.mov; *.mp4; *.mpeg; *.mpg; *.ogm; *.ogv; *.ogx; *.rm; *.rmvb; *.smil; *.webm; *.wmv; *.xvid" + +// [ element name | number of filters | extension list or filter mask | filter index ] +var testData = [["a", 1, MockFilePicker.filterImages, 1], + ["b", 1, MockFilePicker.filterAudio, 1], + ["c", 1, MockFilePicker.filterVideo, 1], + ["d", 3, imageExtensionList + "; " + audioExtensionList, 1], + ["e", 3, imageExtensionList + "; " + videoExtensionList, 1], + ["f", 3, audioExtensionList + "; " + videoExtensionList, 1], + ["g", 4, imageExtensionList + "; " + audioExtensionList + "; " + videoExtensionList, 1], + ["h", 1, MockFilePicker.filterImages, 1], + ["i", 1, MockFilePicker.filterVideo, 1], + ["j", 1, MockFilePicker.filterAudio, 1], + ["k", 3, "*.gif; *.png", 1], + ["l", 4, imageExtensionList + "; " + "*.gif; *.png", 1], + ["m", 1, "*.gif", 1], + ["n", 0, undefined, 0], + ["o", 1, "*.test", 1], + ["p", 3, "*.gif; *.csv", 1], + ["q", 1, "*.gif", 1], + ["r", 3, "*.prefix; *.prefixPlusSomething", 1], + ["s", 3, "*.xls; *.xlsx", 1], + ["t", 4, "*.mp3; *.wav; *.flac", 1], + ["u", 3, "*.xls; *.xlsx", 1], + ["v", 3, "*.xlsx; *.xls", 1], + ["w", 0, undefined, 0], + ["x", 3, "*.xls; *.xlsx", 1], + ["y", 3, "*.xlsx; *.xls", 1], + ["z", 0, undefined, 0], + ["A", 1, "*.xlsx", 1], + // Note: mix and mix-ref tests extension lists are checked differently: see SimpleTest.executeSoon below + ["mix-ref", undefined, undefined, undefined], + ["mix", 1, undefined, 1], + ["hidden", 0, undefined, 0], + ["untrusted-click", 0, undefined, 0], + ["prevent-default", 0, undefined, 0, true], + ["prevent-default-false", 0, undefined, 0, true], + ["right-click", 0, undefined, 0, true], + ["middle-click", 0, undefined, 0, true], + ["left-click", 0, undefined, 0], + ["label-1", 0, undefined, 0], + ["label-2", 0, undefined, 0], + ["label-3", 0, undefined, 0], + ["label-4", 0, undefined, 0], + ["button-click", 0, undefined, 0], + ["button-down", 0, undefined, 0], + ["button-up", 0, undefined, 0], + ["div-click", 0, undefined, 0], + ["div-click-on-demand", 0, undefined, 0], + ["div-keydown", 0, undefined, 0], + ["link-click", 0, undefined, 0], + ["show-picker", 0, undefined, 0], + ]; + +var currentTest = 0; +var filterAllAdded; +var filters; +var filterIndex; +var mixRefExtensionList; + +// Make sure picker works with popup blocker enabled and no allowed events +SpecialPowers.pushPrefEnv({'set': [["dom.popup_allowed_events", ""]]}, runTests); + +function launchNextTest() { + MockFilePicker.shown = false; + filterAllAdded = false; + filters = []; + filterIndex = 0; + + // Focusing the element will scroll them into view so making sure the clicks + // will work. + document.getElementById(testData[currentTest][0]).focus(); + + if (testData[currentTest][0] == "untrusted-click") { + var e = document.createEvent('MouseEvents'); + e.initEvent('click', true, false); + document.getElementById(testData[currentTest][0]).dispatchEvent(e); + // All tests that should *NOT* show a file picker. + } else if (testData[currentTest][0] == "prevent-default" || + testData[currentTest][0] == "prevent-default-false" || + testData[currentTest][0] == "right-click" || + testData[currentTest][0] == "middle-click") { + if (testData[currentTest][0] == "right-click" || + testData[currentTest][0] == "middle-click") { + var b = testData[currentTest][0] == "middle-click" ? 1 : 2; + synthesizeMouseAtCenter(document.getElementById(testData[currentTest][0]), + { button: b }); + } else { + if (testData[currentTest][0] == "prevent-default-false") { + document.getElementById(testData[currentTest][0]).onclick = function() { + return false; + }; + } else { + document.getElementById(testData[currentTest][0]).onclick = function(event) { + event.preventDefault(); + }; + } + document.getElementById(testData[currentTest][0]).click(); + } + + // Wait a bit and assume we can continue. If the file picker shows later, + // behaviour is uncertain but that would be a random green, no big deal... + setTimeout(function() { + ok(true, "we should be there without a file picker being opened"); + ++currentTest; + launchNextTest(); + }, 500); + } else if (testData[currentTest][0] == 'label-3' || + testData[currentTest][0] == 'label-4') { + synthesizeMouse(document.getElementById(testData[currentTest][0]), 5, 5, {}); + } else if (testData[currentTest][0] == 'button-click' || + testData[currentTest][0] == 'button-down' || + testData[currentTest][0] == 'button-up' || + testData[currentTest][0] == 'div-click' || + testData[currentTest][0] == 'div-click-on-demand' || + testData[currentTest][0] == 'link-click') { + synthesizeMouseAtCenter(document.getElementById(testData[currentTest][0]), {}); + } else if (testData[currentTest][0] == 'div-keydown') { + sendString("a"); + } else if (testData[currentTest][0] == 'show-picker') { + SpecialPowers.wrap(document).notifyUserGestureActivation(); + document.getElementById(testData[currentTest][0]).showPicker(); + } else { + document.getElementById(testData[currentTest][0]).click(); + } +} + +function runTests() { + MockFilePicker.appendFilterCallback = function(filepicker, title, val) { + filters.push(val); + }; + MockFilePicker.appendFiltersCallback = function(filepicker, val) { + if (val === MockFilePicker.filterAll) { + filterAllAdded = true; + } else { + filters.push(val); + } + }; + MockFilePicker.showCallback = function(filepicker) { + if (testData[currentTest][4]) { + ok(false, "we shouldn't have a file picker showing!"); + return; + } + + filterIndex = filepicker.filterIndex; + testName = testData[currentTest][0]; + SimpleTest.executeSoon(function () { + ok(MockFilePicker.shown, + "File picker show method should have been called (" + testName + ")"); + ok(filterAllAdded, + "filterAll is missing (" + testName + ")"); + if (testName == "mix-ref") { + // Used only for reference for next test: nothing to be tested here + mixRefExtensionList = filters[0]; + if (mixRefExtensionList == undefined) { + mixRefExtensionList = ""; + } + } else { + if (testName == "mix") { + // Mixing mime type and file extension filters ("image/jpeg" and + // ".jpg" here) shouldn't restrict the list but only extend it, if file + // extension filter isn't a duplicate + ok(filters[0].includes(mixRefExtensionList), + "Mixing mime types and file extension filters shouldn't restrict extension list: " + + mixRefExtensionList + " | " + filters[0]); + ok(filters[0].includes("*.jpg"), + "Filter should contain '.jpg' extension. Filter was:" + filters[0]); + } else { + is(filters[0], testData[currentTest][2], + "Correct filters should have been added (" + testName + ")"); + is(filters.length, testData[currentTest][1], + "appendFilters not called as often as expected (" + testName + ")"); + } + is(filterIndex, testData[currentTest][3], + "File picker should show the correct filter index (" + testName + ")"); + } + + if (++currentTest == testData.length) { + MockFilePicker.cleanup(); + SimpleTest.finish(); + } else { + launchNextTest(); + } + }); + }; + + launchNextTest(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_hasBeenTypePassword.html b/dom/html/test/forms/test_input_hasBeenTypePassword.html new file mode 100644 index 0000000000..ac577ae3a9 --- /dev/null +++ b/dom/html/test/forms/test_input_hasBeenTypePassword.html @@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1330228 +--> +<head> + <title>Test input.hasBeenTypePassword</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1330228">Mozilla Bug 1330228</a> +<script type="application/javascript"> + +/** Test input.hasBeenTypePassword **/ + +var gInputTestData = [ +/* type result */ + ["tel", false], + ["text", false], + ["button", false], + ["checkbox", false], + ["file", false], + ["hidden", false], + ["reset", false], + ["image", false], + ["radio", false], + ["submit", false], + ["search", false], + ["email", false], + ["url", false], + ["number", false], + ["range", false], + ["date", false], + ["time", false], + ["color", false], + ["month", false], + ["week", false], + ["datetime-local", false], + ["", false], + // "password" must be last since we re-use the same <input>. + ["password", true], +]; + +function checkHasBeenTypePasswordValue(aInput, aResult) { + is(aInput.hasBeenTypePassword, aResult, + "hasBeenTypePassword should return " + aResult + " for " + + aInput.getAttribute("type")); +} + +// Use SpecialPowers since the API is ChromeOnly. +var input = SpecialPowers.wrap(document.createElement("input")); +// Check if the method returns the correct value on the first pass. +for (let [type, expected] of gInputTestData) { + input.type = type; + checkHasBeenTypePasswordValue(input, expected); +} + +// Now do a second pass but expect `hasBeenTypePassword` to always be true now +// that the type was 'password'. +for (let [type] of gInputTestData) { + input.type = type; + checkHasBeenTypePasswordValue(input, true); +} +</script> +</body> +</html> diff --git a/dom/html/test/forms/test_input_hasBeenTypePassword_navigation.html b/dom/html/test/forms/test_input_hasBeenTypePassword_navigation.html new file mode 100644 index 0000000000..70a0f8427e --- /dev/null +++ b/dom/html/test/forms/test_input_hasBeenTypePassword_navigation.html @@ -0,0 +1,68 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1330228 +--> +<head> + <title>Test hasBeenTypePassword is used with bfcache</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1330228">Mozilla Bug 1330228</a> +<p id="display"> + <iframe id="testframe" src="file_login_fields.html"></iframe> +</p> +<pre id="test"> +<script type="application/javascript"> + +/** Test hasBeenTypePassword is used with bfcache **/ +SimpleTest.waitForExplicitFinish(); + +function afterLoad() { + var iframeDoc = $("testframe").contentDocument; + + /* change all the form controls */ + iframeDoc.getElementById("un").value = "username"; + iframeDoc.getElementById("pw1").value = "password1"; + + // Convert pw2 to a password field temporarily to test hasBeenTypePassword. + // We don't want the initial or final value to be type=password or we may + // not test the right scenario. + iframeDoc.getElementById("pw2").type = "password"; + iframeDoc.getElementById("pw2").value = "password2"; + iframeDoc.getElementById("pw2").type = ""; + + /* navigate the page */ + $("testframe").setAttribute("onload", "afterNavigation()"); + // Use a click on an <a> so that the current page is included in session history. + iframeDoc.getElementById("navigate").click(); +} + +addLoadEvent(afterLoad); + +function afterNavigation() { + info("Navigated to a new document"); + var iframeDoc = $("testframe").contentDocument; + $("testframe").setAttribute("onload", "afterBack()"); + // Calling `history.back()` on the contentWindow from here doesn't use bfcache + // so call it from within the contentDocument. + iframeDoc.getElementById("back").click(); +} + +function afterBack() { + info("Should be back showing the first document from bfcache"); + var iframeDoc = $("testframe").contentDocument; + + is(iframeDoc.getElementById("un").value, "username", + "username field value remembered"); + is(iframeDoc.getElementById("pw1").value, "", + "type=password field value not remembered"); + is(iframeDoc.getElementById("pw2").value, "", + "former type=password field value not remembered"); + SimpleTest.finish(); +} +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_list_attribute.html b/dom/html/test/forms/test_input_list_attribute.html new file mode 100644 index 0000000000..62a07dd91a --- /dev/null +++ b/dom/html/test/forms/test_input_list_attribute.html @@ -0,0 +1,253 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=556007 +--> +<head> + <title>Test for Bug 556007</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=556007">Mozilla Bug 556007</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 556007 **/ + +function test0() { + var input = document.createElement("input"); + ok("list" in input, "list should be an input element IDL attribute"); +} + +// Default .list returns null. +function test1(aContent, aInput) { + return null; +} + +// Regular test case. +function test2(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + + aContent.appendChild(aInput); + aContent.appendChild(datalist); + aInput.setAttribute('list', 'd'); + + return datalist; +} + +// If none of the element is in doc. +function test3(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + + aInput.setAttribute('list', 'd'); + + return null; +} + +// If one of the element isn't in doc. +function test4(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + + aContent.appendChild(aInput); + aInput.setAttribute('list', 'd'); + + return null; +} + +// If one of the element isn't in doc. +function test5(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + + aContent.appendChild(datalist); + aInput.setAttribute('list', 'd'); + + return null; +} + +// If datalist is added before input. +function test6(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + + aContent.appendChild(datalist); + aContent.appendChild(aInput); + aInput.setAttribute('list', 'd'); + + return datalist; +} + +// If setAttribute is set before datalist and input are in doc. +function test7(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + + aInput.setAttribute('list', 'd'); + + aContent.appendChild(datalist); + aContent.appendChild(aInput); + + return datalist; +} + +// If setAttribute is set before datalist is in doc. +function test8(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + + aContent.appendChild(aInput); + aInput.setAttribute('list', 'd'); + + aContent.appendChild(datalist); + + return datalist; +} + +// If setAttribute is set before datalist is created. +function test9(aContent, aInput) { + aContent.appendChild(aInput); + aInput.setAttribute('list', 'd'); + + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + aContent.appendChild(datalist); + + return datalist; +} + +// If another datalist is added _after_ the first one, with the same id. +function test10(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + var datalist2 = document.createElement("datalist"); + datalist2.id = 'd'; + + aInput.setAttribute('list', 'd'); + aContent.appendChild(aInput); + aContent.appendChild(datalist); + aContent.appendChild(datalist2); + + return datalist; +} + +// If another datalist is added _before_ the first one with the same id. +function test11(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + var datalist2 = document.createElement("datalist"); + datalist2.id = 'd'; + + aInput.setAttribute('list', 'd'); + aContent.appendChild(aInput); + aContent.appendChild(datalist); + aContent.insertBefore(datalist2, datalist); + + return datalist2; +} + +// If datalist changes it's id. +function test12(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + + aInput.setAttribute('list', 'd'); + aContent.appendChild(aInput); + aContent.appendChild(datalist); + + datalist.id = 'foo'; + + return null; +} + +// If datalist is removed. +function test13(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + + aInput.setAttribute('list', 'd'); + aContent.appendChild(aInput); + aContent.appendChild(datalist); + aContent.removeChild(datalist); + + return null; +} + +// If id contain spaces. +function test14(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = 'a b c d'; + + aInput.setAttribute('list', 'a b c d'); + aContent.appendChild(aInput); + aContent.appendChild(datalist); + + return datalist; +} + +// If id is the empty string. +function test15(aContent, aInput) { + var datalist = document.createElement("datalist"); + datalist.id = ''; + + aInput.setAttribute('list', ''); + aContent.appendChild(aInput); + aContent.appendChild(datalist); + + return null; +} + +// If the id doesn't point to a datalist. +function test16(aContent, aInput) { + var input = document.createElement("input"); + input.id = 'd'; + + aInput.setAttribute('list', 'd'); + aContent.appendChild(aInput); + aContent.appendChild(input); + + return null; +} + +// If the first element with the id isn't a datalist. +function test17(aContent, aInput) { + var input = document.createElement("input"); + input.id = 'd'; + var datalist = document.createElement("datalist"); + datalist.id = 'd'; + + aInput.setAttribute('list', 'd'); + aContent.appendChild(aInput); + aContent.appendChild(input); + aContent.appendChild(datalist); + + return null; +} + +var tests = [ test1, test2, test3, test4, test5, test6, test7, test8, test9, + test10, test11, test12, test13, test14, test15, test16, test17 ]; + +test0(); + +for (var test of tests) { + var content = document.getElementById('content'); + + // Clean-up. + content.textContent = ''; + + var input = document.createElement("input"); + var res = test(content, input); + + is(input.list, res, "input.list should be " + res); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_number_data.js b/dom/html/test/forms/test_input_number_data.js new file mode 100644 index 0000000000..9ec53f136f --- /dev/null +++ b/dom/html/test/forms/test_input_number_data.js @@ -0,0 +1,54 @@ +var tests = [ + { + desc: "British English", + langTag: "en-GB", + inputWithGrouping: "123,456.78", + inputWithoutGrouping: "123456.78", + value: 123456.78, + }, + { + desc: "Farsi", + langTag: "fa", + inputWithGrouping: "۱۲۳٬۴۵۶٫۷۸", + inputWithoutGrouping: "۱۲۳۴۵۶٫۷۸", + value: 123456.78, + }, + { + desc: "French", + langTag: "fr-FR", + inputWithGrouping: "123 456,78", + inputWithoutGrouping: "123456,78", + value: 123456.78, + }, + { + desc: "German", + langTag: "de", + inputWithGrouping: "123.456,78", + inputWithoutGrouping: "123456,78", + value: 123456.78, + }, + // Bug 1509057 disables grouping separators for now, so this test isn't + // currently relevant. + // Extra german test to check that a locale that uses '.' as its grouping + // separator doesn't result in it being invalid (due to step mismatch) due + // to the de-localization code mishandling numbers that look like other + // numbers formatted for English speakers (i.e. treating this as 123.456 + // instead of 123456): + //{ desc: "German (test 2)", + // langTag: "de", inputWithGrouping: "123.456", + // inputWithoutGrouping: "123456", value: 123456 + //}, + { + desc: "Hebrew", + langTag: "he", + inputWithGrouping: "123,456.78", + inputWithoutGrouping: "123456.78", + value: 123456.78, + }, +]; + +var invalidTests = [ + // Right now this will pass in a 'de' build, but not in the 'en' build that + // are used for testing. See bug 1216831. + // { desc: "Invalid German", langTag: "de", input: "12.34" } +]; diff --git a/dom/html/test/forms/test_input_number_focus.html b/dom/html/test/forms/test_input_number_focus.html new file mode 100644 index 0000000000..4126ecc496 --- /dev/null +++ b/dom/html/test/forms/test_input_number_focus.html @@ -0,0 +1,109 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1268556 +--> +<head> + <title>Test focus behaviour for <input type='number'></title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + #input_test_style_display { + display: none; + } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1268556">Mozilla Bug 1268556</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1057858">Mozilla Bug 1057858</a> +<p id="display"></p> +<div id="content"> + <input id="input_test_redirect" type="number"> + <input id="input_test_style_display" type="number" > +</div> +<pre id="test"> +<script type="application/javascript"> + +/** + * Test for Bug 1268556. + * This test checks that when focusing on an input type=number, the focus is + * redirected to the anonymous text control, but the document.activeElement + * still returns the <input type=number>. + * + * Tests for bug 1057858. + * Checks that adding an element and immediately focusing it triggers exactly + * one "focus" event and no "blur" events. The same for switching + * `style.display` from `none` to `block`. + **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test_focus_redirects_to_text_control_but_not_for_activeElement(); + test_add_element_and_focus_check_one_focus_event(); + test_style_display_none_change_to_block_check_one_focus_event(); + SimpleTest.finish(); +}); + +function test_focus_redirects_to_text_control_but_not_for_activeElement() { + document.activeElement.blur(); + var number = document.getElementById("input_test_redirect"); + number.focus(); + + // The active element returns the input type=number. + var activeElement = document.activeElement; + is (activeElement, number, "activeElement should be the number element"); + is (activeElement.localName, "input", "activeElement should be an input element"); + is (activeElement.getAttribute("type"), "number", "activeElement should of type number"); + + // Use FocusManager to check that the actual focus is on the anonymous + // text control. + var fm = SpecialPowers.Cc["@mozilla.org/focus-manager;1"] + .getService(SpecialPowers.Ci.nsIFocusManager); + var focusedElement = fm.focusedElement; + is (focusedElement.localName, "input", "focusedElement should be an input element"); + is (focusedElement.getAttribute("type"), "number", "focusedElement should of type number"); +} + +var blurEventCounter = 0; +var focusEventCounter = 0; + +function append_input_element_with_event_listeners_to_dom() { + var inputElement = document.createElement("input"); + inputElement.type = "number"; + inputElement.addEventListener("blur", function() { ++blurEventCounter; }); + inputElement.addEventListener("focus", function() { ++focusEventCounter; }); + var content = document.getElementById("content"); + content.appendChild(inputElement); + return inputElement; +} + +function test_add_element_and_focus_check_one_focus_event() { + document.activeElement.blur(); + var inputElement = append_input_element_with_event_listeners_to_dom(); + + blurEventCounter = 0; + focusEventCounter = 0; + inputElement.focus(); + + is(blurEventCounter, 0, "After focus: no blur events observed."); + is(focusEventCounter, 1, "After focus: exactly one focus event observed."); +} + +function test_style_display_none_change_to_block_check_one_focus_event() { + document.activeElement.blur(); + var inputElement = document.getElementById("input_test_style_display"); + inputElement.addEventListener("blur", function() { ++blurEventCounter; }); + inputElement.addEventListener("focus", function() { ++focusEventCounter; }); + + blurEventCounter = 0; + focusEventCounter = 0; + inputElement.style.display = "block"; + inputElement.focus(); + + is(blurEventCounter, 0, "After focus: no blur events observed."); + is(focusEventCounter, 1, "After focus: exactly one focus event observed."); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_number_key_events.html b/dom/html/test/forms/test_input_number_key_events.html new file mode 100644 index 0000000000..eb537f5617 --- /dev/null +++ b/dom/html/test/forms/test_input_number_key_events.html @@ -0,0 +1,238 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=935506 +--> +<head> + <title>Test key events for number control</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=935506">Mozilla Bug 935506</a> +<p id="display"></p> +<div id="content"> + <input id="input" type="number"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** + * Test for Bug 935506 + * This test checks how the value of <input type=number> changes in response to + * key events while it is in various states. + **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); +const defaultMinimum = "NaN"; +const defaultMaximum = "NaN"; +const defaultStep = 1; + +// Helpers: +// For the sake of simplicity, we do not currently support fractional value, +// step, etc. + +function getMinimum(element) { + return Number(element.min || defaultMinimum); +} + +function getMaximum(element) { + return Number(element.max || defaultMaximum); +} + +function getDefaultValue(element) { + return 0; +} + +function getValue(element) { + return Number(element.value || getDefaultValue(element)); +} + +function getStep(element) { + if (element.step == "any") { + return "any"; + } + var step = Number(element.step || defaultStep); + return step <= 0 ? defaultStep : step; +} + +function getStepBase(element) { + return Number(element.getAttribute("min") || "NaN") || + Number(element.getAttribute("value") || "NaN") || 0; +} + +function hasStepMismatch(element) { + var value = element.value; + if (value == "") { + value = 0; + } + var step = getStep(element); + if (step == "any") { + return false; + } + return ((value - getStepBase(element)) % step) != 0; +} + +function floorModulo(x, y) { + return (x - y * Math.floor(x / y)); +} + +function expectedValueAfterStepUpOrDown(stepFactor, element) { + var value = getValue(element); + if (isNaN(value)) { + value = 0; + } + var step = getStep(element); + if (step == "any") { + step = 1; + } + + var minimum = getMinimum(element); + var maximum = getMaximum(element); + if (!isNaN(maximum)) { + // "max - (max - stepBase) % step" is the nearest valid value to max. + maximum = maximum - floorModulo(maximum - getStepBase(element), step); + } + + // Cases where we are clearly going in the wrong way. + // We don't use ValidityState because we can be higher than the maximal + // allowed value and still not suffer from range overflow in the case of + // of the value specified in @max isn't in the step. + if ((value <= minimum && stepFactor < 0) || + (value >= maximum && stepFactor > 0)) { + return value; + } + + if (hasStepMismatch(element) && + value != minimum && value != maximum) { + if (stepFactor > 0) { + value -= floorModulo(value - getStepBase(element), step); + } else if (stepFactor < 0) { + value -= floorModulo(value - getStepBase(element), step); + value += step; + } + } + + value += step * stepFactor; + + // When stepUp() is called and the value is below minimum, we should clamp on + // minimum unless stepUp() moves us higher than minimum. + if (element.validity.rangeUnderflow && stepFactor > 0 && + value <= minimum) { + value = minimum; + } else if (element.validity.rangeOverflow && stepFactor < 0 && + value >= maximum) { + value = maximum; + } else if (stepFactor < 0 && !isNaN(minimum)) { + value = Math.max(value, minimum); + } else if (stepFactor > 0 && !isNaN(maximum)) { + value = Math.min(value, maximum); + } + + return value; +} + +function expectedValAfterKeyEvent(key, element) { + return expectedValueAfterStepUpOrDown(key == "KEY_ArrowUp" ? 1 : -1, element); +} + +function test() { + var elem = document.getElementById("input"); + elem.focus(); + + elem.min = -5; + elem.max = 5; + elem.step = 2; + var defaultValue = 0; + var oldVal, expectedVal; + + for (key of ["KEY_ArrowUp", "KEY_ArrowDown"]) { + // Start at middle: + oldVal = elem.value = -1; + expectedVal = expectedValAfterKeyEvent(key, elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test " + key + " for number control with value set between min/max (" + oldVal + ")"); + + // Same again: + expectedVal = expectedValAfterKeyEvent(key, elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test repeat of " + key + " for number control"); + + // Start at maximum: + oldVal = elem.value = elem.max; + expectedVal = expectedValAfterKeyEvent(key, elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test " + key + " for number control with value set to the maximum (" + oldVal + ")"); + + // Same again: + expectedVal = expectedValAfterKeyEvent(key, elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test repeat of " + key + " for number control"); + + // Start at minimum: + oldVal = elem.value = elem.min; + expectedVal = expectedValAfterKeyEvent(key, elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test " + key + " for number control with value set to the minimum (" + oldVal + ")"); + + // Same again: + expectedVal = expectedValAfterKeyEvent(key, elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test repeat of " + key + " for number control"); + + // Test preventDefault(): + elem.addEventListener("keydown", evt => evt.preventDefault(), {once: true}); + oldVal = elem.value = 0; + expectedVal = 0; + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test " + key + " for number control where scripted preventDefault() should prevent the value changing"); + + // Test step="any" behavior: + var oldStep = elem.step; + elem.step = "any"; + oldVal = elem.value = 0; + expectedVal = expectedValAfterKeyEvent(key, elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test " + key + " for number control with value set to the midpoint and step='any' (" + oldVal + ")"); + elem.step = oldStep; // restore + + // Test that invalid input blocks UI initiated stepping: + oldVal = elem.value = ""; + elem.select(); + sendString("abc"); + synthesizeKey(key); + is(elem.value, "", "Test " + key + " does nothing when the input is invalid"); + + // Test that no value does not block UI initiated stepping: + oldVal = elem.value = ""; + elem.setAttribute("required", "required"); + elem.select(); + expectedVal = expectedValAfterKeyEvent(key, elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test " + key + " for number control with value set to the empty string and with the 'required' attribute set"); + + // Same again: + expectedVal = expectedValAfterKeyEvent(key, elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test repeat of " + key + " for number control"); + + // Reset 'required' attribute: + elem.removeAttribute("required"); + } + + // Test that key events are correctly dispatched + elem.max = ""; + elem.value = ""; + sendString("7837281"); + is(elem.value, "7837281", "Test keypress event dispatch for number control"); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_number_l10n.html b/dom/html/test/forms/test_input_number_l10n.html new file mode 100644 index 0000000000..c8202028ed --- /dev/null +++ b/dom/html/test/forms/test_input_number_l10n.html @@ -0,0 +1,77 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=844744 +--> +<head> + <title>Test localization of number control input</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script type="text/javascript" src="test_input_number_data.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=844744">Mozilla Bug 844744</a> +<p id="display"></p> +<div id="content"> + <input id="input" type="number" step="any"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** + * Test for Bug 844744 + * This test checks that localized input that is typed into <input type=number> + * is correctly handled. + **/ +SimpleTest.waitForExplicitFinish(); + +SimpleTest.waitForFocus(function() { + startTests(); + SimpleTest.finish(); +}); + +var elem; + +function runTest(test) { + elem.lang = test.langTag; + elem.value = 0; + elem.focus(); + elem.select(); + sendString(test.inputWithGrouping); + is(elem.value, "", "Test " + test.desc + " ('" + test.langTag + + "') localization with grouping separator"); + elem.value = 0; + elem.select(); + sendString(test.inputWithoutGrouping); + is(elem.valueAsNumber, test.value, "Test " + test.desc + " ('" + test.langTag + + "') localization without grouping separator"); + is(elem.value, String(test.value), "Test " + test.desc + " ('" + test.langTag + + "') localization without grouping separator as string"); +} + +function runInvalidInputTest(test) { + elem.lang = test.langTag; + elem.value = 0; + elem.focus(); + elem.select(); + sendString(test.input); + is(elem.value, "", "Test " + test.desc + " ('" + test.langTag + + "') with invalid input: " + test.input); +} + +function startTests() { + elem = document.getElementById("input"); + for (var test of tests) { + runTest(test, elem); + } + for (var test of invalidTests) { + runInvalidInputTest(test, elem); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_number_mouse_events.html b/dom/html/test/forms/test_input_number_mouse_events.html new file mode 100644 index 0000000000..a3e5732beb --- /dev/null +++ b/dom/html/test/forms/test_input_number_mouse_events.html @@ -0,0 +1,272 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=935501 +--> +<head> + <title>Test mouse events for number</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <style> + input { + margin: 0; + border: 0; + padding: 0; + width: 200px; + box-sizing: border-box; + } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=935501">Mozilla Bug 935501</a> +<p id="display"></p> +<div id="content"> + <input id="input" type="number"> +</div> +<pre id="test"> +<script> + +const { AppConstants } = SpecialPowers.ChromeUtils.importESModule( + "resource://gre/modules/AppConstants.sys.mjs" +); + +/** + * Test for Bug 935501 + * This test checks how the value of <input type=number> changes in response to + * various mouse events. + **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("untriaged"); +SimpleTest.waitForFocus(function() { + test(); +}); + +const kIsWin = AppConstants.platform == "win"; +const kIsLinux = AppConstants.platform == "linux"; + +var input = document.getElementById("input"); +var inputRect = input.getBoundingClientRect(); + +// Points over the input's spin-up and spin-down buttons (as offsets from the +// top-left of the input's bounding client rect): +const SPIN_UP_X = inputRect.width - 3; +const SPIN_UP_Y = 3; +const SPIN_DOWN_X = inputRect.width - 3; +const SPIN_DOWN_Y = inputRect.height - 3; + +function checkInputEvent(aEvent, aDescription) { + // Probably, key operation should fire "input" event with InputEvent interface. + // See https://github.com/w3c/input-events/issues/88 + ok(aEvent instanceof InputEvent, `"input" event should be dispatched with InputEvent interface on input element whose type is number ${aDescription}`); + is(aEvent.cancelable, false, `"input" event should be never cancelable on input element whose type is number ${aDescription}`); + is(aEvent.bubbles, true, `"input" event should always bubble on input element whose type is number ${aDescription}`); + info(`Data: ${aEvent.data}, value: ${aEvent.target.value}`); +} + +function test() { + input.value = 0; + + // Test click on spin-up button: + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" }); + is(input.value, "1", "Test step-up on mousedown on spin-up button"); + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mouseup" }); + is(input.value, "1", "Test mouseup on spin-up button"); + + // Test click on spin-down button: + synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousedown" }); + is(input.value, "0", "Test step-down on mousedown on spin-down button"); + synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mouseup" }); + is(input.value, "0", "Test mouseup on spin-down button"); + + // Test clicks with modifiers that mean we should ignore the click: + var modifiersIgnore = ["altGrKey", "fnKey"]; + if (kIsWin || kIsLinux) { + modifiersIgnore.push("metaKey"); + } + for (var modifier of modifiersIgnore) { + input.value = 0; + var eventParams = { type: "mousedown" }; + eventParams[modifier] = true; + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, eventParams); + is(input.value, "0", "We should ignore mousedown on spin-up button with modifier " + modifier); + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mouseup" }); + } + + // Test clicks with modifiers that mean we should allow the click: + var modifiersAllow = ["shiftKey", "ctrlKey", "altKey"]; + if (!modifiersIgnore.includes("metaKey")) { + modifiersAllow.push("metaKey"); + } + for (var modifier of modifiersAllow) { + input.value = 0; + var eventParams = { type: "mousedown" }; + eventParams[modifier] = true; + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, eventParams); + is(input.value, "1", "We should allow mousedown on spin-up button with modifier " + modifier); + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mouseup" }); + } + + // Test step="any" behavior: + input.value = 0; + var oldStep = input.step; + input.step = "any"; + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" }); + is(input.value, "1", "Test step-up on mousedown on spin-up button with step='any'"); + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mouseup" }); + is(input.value, "1", "Test mouseup on spin-up button with step='any'"); + synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousedown" }); + is(input.value, "0", "Test step-down on mousedown on spin-down button with step='any'"); + synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mouseup" }); + is(input.value, "0", "Test mouseup on spin-down button with step='any'"); + input.step = oldStep; // restore + + // Test that preventDefault() works: + function preventDefault(e) { + e.preventDefault(); + } + input.value = 1; + input.addEventListener("mousedown", preventDefault); + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, {}); + is(input.value, "1", "Test that preventDefault() works for click on spin-up button"); + synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, {}); + is(input.value, "1", "Test that preventDefault() works for click on spin-down button"); + input.removeEventListener("mousedown", preventDefault); + + // Test for bug 1707070. + input.style.paddingRight = "30px"; + input.getBoundingClientRect(); // flush layout + + input.value = 0; + synthesizeMouse(input, SPIN_UP_X - 30, SPIN_UP_Y, { type: "mousedown" }); + is(input.value, "1", "Spinner down works on with padding (mousedown)"); + synthesizeMouse(input, SPIN_UP_X - 30, SPIN_UP_Y, { type: "mouseup" }); + is(input.value, "1", "Spinner down works with padding (mouseup)"); + + synthesizeMouse(input, SPIN_DOWN_X - 30, SPIN_DOWN_Y, { type: "mousedown" }); + is(input.value, "0", "Spinner works with padding (mousedown)"); + synthesizeMouse(input, SPIN_DOWN_X - 30, SPIN_DOWN_Y, { type: "mouseup" }); + is(input.value, "0", "Spinner works with padding (mouseup)"); + + input.style.paddingRight = ""; + input.getBoundingClientRect(); // flush layout + + // Run the spin tests: + runNextSpinTest(); +} + +function runNextSpinTest() { + var nextTest = spinTests.shift(); + if (!nextTest) { + SimpleTest.finish(); + return; + } + nextTest(); +} + +function waitForTick() { + return new Promise(SimpleTest.executeSoon); +} + +const SETTIMEOUT_DELAY = 500; + +var spinTests = [ + // Test spining when the mouse button is kept depressed on the spin-up + // button, then moved over the spin-down button: + function() { + var inputEventCount = 0; + input.value = 0; + input.addEventListener("input", async function(evt) { + ++inputEventCount; + checkInputEvent(evt, "#1"); + if (inputEventCount == 3) { + is(input.value, "3", "Testing spin-up button"); + await waitForTick(); + synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousemove" }); + } else if (inputEventCount == 6) { + is(input.value, "0", "Testing spin direction is reversed after mouse moves from spin-up button to spin-down button"); + input.removeEventListener("input", arguments.callee); + await waitForTick(); + synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mouseup" }); + runNextSpinTest(); + } + }); + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" }); + }, + + // Test spining when the mouse button is kept depressed on the spin-down + // button, then moved over the spin-up button: + function() { + var inputEventCount = 0; + input.value = 0; + input.addEventListener("input", async function(evt) { + ++inputEventCount; + checkInputEvent(evt, "#2"); + if (inputEventCount == 3) { + is(input.value, "-3", "Testing spin-down button"); + await waitForTick(); + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousemove" }); + } else if (inputEventCount == 6) { + is(input.value, "0", "Testing spin direction is reversed after mouse moves from spin-down button to spin-up button"); + input.removeEventListener("input", arguments.callee); + await waitForTick(); + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mouseup" }); + runNextSpinTest(); + } + }); + synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousedown" }); + }, + + // Test that the spin is stopped when the mouse button is depressod on the + // spin-up button, then moved outside both buttons once the spin starts: + function() { + var inputEventCount = 0; + input.value = 0; + input.addEventListener("input", async function(evt) { + ++inputEventCount; + checkInputEvent(evt, "#3"); + if (inputEventCount == 3) { + await waitForTick(); + synthesizeMouse(input, -1, -1, { type: "mousemove" }); + var eventHandler = arguments.callee; + setTimeout(function() { + is(input.value, "3", "Testing moving the mouse outside the spin buttons stops the spin"); + is(inputEventCount, 3, "Testing moving the mouse outside the spin buttons stops the spin input events"); + input.removeEventListener("input", eventHandler); + synthesizeMouse(input, -1, -1, { type: "mouseup" }); + runNextSpinTest(); + }, SETTIMEOUT_DELAY); + } + }); + synthesizeMouse(input, SPIN_UP_X, SPIN_UP_Y, { type: "mousedown" }); + }, + + // Test that changing the input type in the middle of a spin cancels the spin: + function() { + var inputEventCount = 0; + input.value = 0; + input.addEventListener("input", function(evt) { + ++inputEventCount; + checkInputEvent(evt, "#4"); + if (inputEventCount == 3) { + input.type = "text" + var eventHandler = arguments.callee; + setTimeout(function() { + is(input.value, "-3", "Testing changing input type during a spin stops the spin"); + is(inputEventCount, 3, "Testing changing input type during a spin stops the spin input events"); + input.removeEventListener("input", eventHandler); + synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mouseup" }); + input.type = "number"; // restore + runNextSpinTest(); + }, SETTIMEOUT_DELAY); + } + }); + synthesizeMouse(input, SPIN_DOWN_X, SPIN_DOWN_Y, { type: "mousedown" }); + } +]; +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_number_placeholder_shown.html b/dom/html/test/forms/test_input_number_placeholder_shown.html new file mode 100644 index 0000000000..c9c2a7f515 --- /dev/null +++ b/dom/html/test/forms/test_input_number_placeholder_shown.html @@ -0,0 +1,30 @@ +<!doctype html> +<title>Test for :placeholder-shown on input elements and invalid values.</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<style> +input { + border: 1px solid purple; +} +input:placeholder-shown { + border-color: blue; +} +</style> +<input type="number" placeholder="foo"> +<script> + SimpleTest.waitForExplicitFinish(); + SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); + }); + + function test() { + let input = document.querySelector('input'); + input.focus(); + is(getComputedStyle(input).borderLeftColor, "rgb(0, 0, 255)", + ":placeholder-shown should apply") + sendString("x"); + isnot(getComputedStyle(input).borderLeftColor, "rgb(0, 0, 255)", + ":placeholder-shown should not apply, even though the value is invalid") + } +</script> diff --git a/dom/html/test/forms/test_input_number_rounding.html b/dom/html/test/forms/test_input_number_rounding.html new file mode 100644 index 0000000000..d162727557 --- /dev/null +++ b/dom/html/test/forms/test_input_number_rounding.html @@ -0,0 +1,120 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=783607 +--> +<head> + <title>Test rounding behaviour for <input type='number'></title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=783607">Mozilla Bug 783607</a> +<p id="display"></p> +<div id="content"> + <input id=number type=number value=0 step=0.01 max=1> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** + * Test for Bug 783607. + * This test checks that when <input type=number> has fractional step values, + * the values that a content author will see in their script will not have + * ugly rounding errors. + **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +/** + * We can _NOT_ generate these values by looping and simply incrementing a + * variable by 0.01 and stringifying it, since we'll end up with strings like + * "0.060000000000000005" due to the inability of binary floating point numbers + * to accurately represent decimal values. + */ +var stepVals = [ + "0", "0.01", "0.02", "0.03", "0.04", "0.05", "0.06", "0.07", "0.08", "0.09", + "0.1", "0.11", "0.12", "0.13", "0.14", "0.15", "0.16", "0.17", "0.18", "0.19", + "0.2", "0.21", "0.22", "0.23", "0.24", "0.25", "0.26", "0.27", "0.28", "0.29", + "0.3", "0.31", "0.32", "0.33", "0.34", "0.35", "0.36", "0.37", "0.38", "0.39", + "0.4", "0.41", "0.42", "0.43", "0.44", "0.45", "0.46", "0.47", "0.48", "0.49", + "0.5", "0.51", "0.52", "0.53", "0.54", "0.55", "0.56", "0.57", "0.58", "0.59", + "0.6", "0.61", "0.62", "0.63", "0.64", "0.65", "0.66", "0.67", "0.68", "0.69", + "0.7", "0.71", "0.72", "0.73", "0.74", "0.75", "0.76", "0.77", "0.78", "0.79", + "0.8", "0.81", "0.82", "0.83", "0.84", "0.85", "0.86", "0.87", "0.88", "0.89", + "0.9", "0.91", "0.92", "0.93", "0.94", "0.95", "0.96", "0.97", "0.98", "0.99", + "1" +]; + +var pgUpDnVals = [ + "0", "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1" +]; + +function test() { + var elem = document.getElementById("number"); + + elem.focus(); + + /** + * TODO: + * When <input type='number'> widget will have a widge we should test PAGE_UP, + * PAGE_DOWN, UP and DOWN keys. For the moment, there is no widget so those + * keys do not have any effect. + * The tests using those keys as marked as todo_is() hoping that at least part + * of them will fail when the widget will be implemented. + */ + +/* No other implementations implement this, so we don't either, for now. + Seems like it might be nice though. + + for (var i = 1; i < pgUpDnVals.length; ++i) { + synthesizeKey("KEY_PageUp"); + todo_is(elem.value, pgUpDnVals[i], "Test KEY_PageUp"); + is(elem.validity.valid, true, "Check element is valid for value " + pgUpDnVals[i]); + } + + for (var i = pgUpDnVals.length - 2; i >= 0; --i) { + synthesizeKey("KEY_PageDown"); + // TODO: this condition is there because the todo_is() below would pass otherwise. + if (stepVals[i] == 0) { continue; } + todo_is(elem.value, pgUpDnVals[i], "Test KEY_PageDown"); + is(elem.validity.valid, true, "Check element is valid for value " + pgUpDnVals[i]); + } +*/ + + for (var i = 1; i < stepVals.length; ++i) { + synthesizeKey("KEY_ArrowUp"); + is(elem.value, stepVals[i], "Test KEY_ArrowUp"); + is(elem.validity.valid, true, "Check element is valid for value " + stepVals[i]); + } + + for (var i = stepVals.length - 2; i >= 0; --i) { + synthesizeKey("KEY_ArrowDown"); + // TODO: this condition is there because the todo_is() below would pass otherwise. + if (stepVals[i] == 0) { continue; } + is(elem.value, stepVals[i], "Test KEY_ArrowDown"); + is(elem.validity.valid, true, "Check element is valid for value " + stepVals[i]); + } + + for (var i = 1; i < stepVals.length; ++i) { + elem.stepUp(); + is(elem.value, stepVals[i], "Test stepUp()"); + is(elem.validity.valid, true, "Check element is valid for value " + stepVals[i]); + } + + for (var i = stepVals.length - 2; i >= 0; --i) { + elem.stepDown(); + is(elem.value, stepVals[i], "Test stepDown()"); + is(elem.validity.valid, true, "Check element is valid for value " + stepVals[i]); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_number_validation.html b/dom/html/test/forms/test_input_number_validation.html new file mode 100644 index 0000000000..c19c1fde1c --- /dev/null +++ b/dom/html/test/forms/test_input_number_validation.html @@ -0,0 +1,139 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=827161 +--> +<head> + <title>Test validation of number control input</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script type="text/javascript" src="test_input_number_data.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=827161">Mozilla Bug 827161</a> +<p id="display"></p> +<div id="content"> + <input id="input" type="number" step="0.01" oninvalid="invalidEventHandler(event);"> + <input id="requiredinput" type="number" step="0.01" required + oninvalid="invalidEventHandler(event);"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** + * Test for Bug 827161. + * This test checks that validation works correctly for <input type=number>. + **/ +SimpleTest.waitForExplicitFinish(); + +SimpleTest.waitForFocus(function() { + startTests(); + SimpleTest.finish(); +}); + +var elem; + +function runTest(test) { + elem.lang = test.langTag; + + gInvalid = false; // reset + var desc = `${test.desc} (lang='${test.langTag}', id='${elem.id}')`; + elem.value = 0; + elem.focus(); + elem.select(); + sendString(test.inputWithGrouping); + checkIsInvalid(elem, `${desc} with grouping separator`); + sendChar("a"); + checkIsInvalid(elem, `${desc} with grouping separator`); + + gInvalid = false; // reset + elem.value = 0; + elem.select(); + sendString(test.inputWithoutGrouping); + checkIsValid(elem, `${desc} without grouping separator`); + sendChar("a"); + checkIsInvalid(elem, `${desc} without grouping separator`); +} + +function runInvalidInputTest(test) { + elem.lang = test.langTag; + + gInvalid = false; // reset + var desc = `${test.desc} (lang='${test.langTag}', id='${elem.id}')`; + elem.value = 0; + elem.focus(); + elem.select(); + sendString(test.input); + checkIsInvalid(elem, `${desc} with invalid input ${test.input}`); +} + +function startTests() { + elem = document.getElementById("input"); + for (var test of tests) { + runTest(test); + } + for (var test of invalidTests) { + runInvalidInputTest(test); + } + elem = document.getElementById("requiredinput"); + for (var test of tests) { + runTest(test); + } + + gInvalid = false; // reset + elem.value = ""; + checkIsInvalidEmptyValue(elem, "empty value"); +} + +var gInvalid = false; + +function invalidEventHandler(e) +{ + is(e.type, "invalid", "Invalid event type should be 'invalid'"); + gInvalid = true; +} + +function checkIsValid(element, infoStr) +{ + ok(!element.validity.badInput, + "Element should not suffer from bad input for " + infoStr); + ok(element.validity.valid, "Element should be valid for " + infoStr); + ok(element.checkValidity(), "checkValidity() should return true for " + infoStr); + ok(!gInvalid, "The invalid event should not have been thrown for " + infoStr); + is(element.validationMessage, '', + "Validation message should be the empty string for " + infoStr); + ok(element.matches(":valid"), ":valid pseudo-class should apply for " + infoStr); +} + +function checkIsInvalid(element, infoStr) +{ + ok(element.validity.badInput, + "Element should suffer from bad input for " + infoStr); + ok(!element.validity.valid, "Element should not be valid for " + infoStr); + ok(!element.checkValidity(), "checkValidity() should return false for " + infoStr); + ok(gInvalid, "The invalid event should have been thrown for " + infoStr); + is(element.validationMessage, "Please enter a number.", + "Validation message is not the expected message for " + infoStr); + ok(element.matches(":invalid"), ":invalid pseudo-class should apply for " + infoStr); +} + +function checkIsInvalidEmptyValue(element, infoStr) +{ + ok(!element.validity.badInput, + "Element should not suffer from bad input for " + infoStr); + ok(element.validity.valueMissing, + "Element should suffer from value missing for " + infoStr); + ok(!element.validity.valid, "Element should not be valid for " + infoStr); + ok(!element.checkValidity(), "checkValidity() should return false for " + infoStr); + ok(gInvalid, "The invalid event should have been thrown for " + infoStr); + is(element.validationMessage, "Please enter a number.", + "Validation message is not the expected message for " + infoStr); + ok(element.matches(":invalid"), ":invalid pseudo-class should apply for " + infoStr); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_password_click_show_password_button.html b/dom/html/test/forms/test_input_password_click_show_password_button.html new file mode 100644 index 0000000000..76f4e066f5 --- /dev/null +++ b/dom/html/test/forms/test_input_password_click_show_password_button.html @@ -0,0 +1,97 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=502258 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 502258</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="/tests/SimpleTest/WindowSnapshot.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> + <script> + + SimpleTest.waitForExplicitFinish(); + + async function click_show_password(aId) { + var wu = SpecialPowers.getDOMWindowUtils(window); + var element = document.getElementById(aId); + element.focus(); + await new Promise(resolve => setTimeout(resolve, 0)); + var rect = element.getBoundingClientRect(); + var x = rect.right - 8; + var y = rect.top + 8; + wu.sendMouseEvent("mousedown", x, y, 0, 1, 0); + wu.sendMouseEvent("mouseup", x, y, 0, 1, 0); + await new Promise(resolve => requestAnimationFrame(resolve)); + } + + async function test_show_password(aId) { + var wu = SpecialPowers.getDOMWindowUtils(window); + var element = document.getElementById(aId); + + var baseSnapshot = await snapshotWindow(window); + + await new Promise(resolve => setTimeout(resolve, 0)); + element.type = "text"; + await new Promise(resolve => requestAnimationFrame(resolve)); + var typeTextSnapshot = await snapshotWindow(window); + results = compareSnapshots(baseSnapshot, typeTextSnapshot, true); + ok(results[0], aId + ": type=text should render the same as type=password that is showing the password"); + + // Re-setting value shouldn't change anything. + // eslint-disable-next-line no-self-assign + element.value = element.value; + var tmpSnapshot = await snapshotWindow(window); + + results = compareSnapshots(baseSnapshot, tmpSnapshot, true); + ok(results[0], aId + ": re-setting the value should change nothing"); + } + + async function reset_show_password(aId, concealedSnapshot) { + var element = document.getElementById(aId); + element.type = "password"; + await new Promise(resolve => requestAnimationFrame(resolve)); + var typePasswordSnapshot = await snapshotWindow(window); + results = compareSnapshots(concealedSnapshot, typePasswordSnapshot, true); + ok(results[0], aId + ": changing the type attribute should conceal the password again"); + } + + async function runTest() { + await SpecialPowers.pushPrefEnv({set: [["layout.forms.reveal-password-button.enabled", true]]}); + document.getElementById("content").style.display = ""; + document.getElementById("content").getBoundingClientRect(); + var concealedSnapshot = await snapshotWindow(window); + // test1 checks that the Show Password button becomes invisible when the value becomes empty + document.getElementById('test1').value = "123"; + await click_show_password('test1'); + document.getElementById('test1').value = ""; + // test2 checks that clicking the Show Password button unmasks the value + await click_show_password('test2'); + await test_show_password('test1'); + await test_show_password('test2'); + // checks that changing the type attribute resets thhe revealed state + await reset_show_password('test2', concealedSnapshot); + SimpleTest.finish(); + } + + SimpleTest.waitForFocus(runTest); + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=502258">Mozilla Bug 502258</a> +<p id="display"></p> +<style>input {appearance:none} .ref {display:none}</style> +<div id="content" style="display: none"> + <input id="test1" type=password> + <div style="position:relative; margin: 1em 0;"> + <input id="test2" type=password value="123" style="position:absolute"> + <div style="position:absolute; top:0;left:10ch; width:20ch; height:2em; background:black; pointer-events:none"></div> + </div> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_password_show_password_button.html b/dom/html/test/forms/test_input_password_show_password_button.html new file mode 100644 index 0000000000..09bec8ae82 --- /dev/null +++ b/dom/html/test/forms/test_input_password_show_password_button.html @@ -0,0 +1,81 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=502258 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 502258</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="/tests/SimpleTest/WindowSnapshot.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> + <script> + SimpleTest.waitForExplicitFinish(); + + async function test_append_char(aId) { + let element = document.getElementById(aId); + element.focus(); + + let baseSnapshot = await snapshotWindow(window); + + element.selectionStart = element.selectionEnd = element.value.length; + + await new Promise(resolve => setTimeout(resolve, 0)); + sendString('f'); + + await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))); + + let selectionAtTheEndSnapshot = await snapshotWindow(window); + assertSnapshots(baseSnapshot, selectionAtTheEndSnapshot, /* equal = */ false, /* fuzz = */ null, "baseSnapshot", "selectionAtTheEndSnapshot"); + + // Re-setting value shouldn't change anything. + // eslint-disable-next-line no-self-assign + element.value = element.value; + let tmpSnapshot = await snapshotWindow(window); + + assertSnapshots(baseSnapshot, tmpSnapshot, /* equal = */ false, /* fuzz = */ null, "baseSnapshot", "tmpSnapshot"); + assertSnapshots(selectionAtTheEndSnapshot, tmpSnapshot, /* equal = */ true, /* fuzz = */ null, "selectionAtTheEndSnapshot", "tmpSnapshot"); + + element.selectionStart = element.selectionEnd = 0; + element.blur(); + } + + async function runTest() { + await SpecialPowers.pushPrefEnv({set: [["layout.forms.reveal-password-button.enabled", true]]}); + document.getElementById("content").style.display = ""; + document.getElementById("content").getBoundingClientRect(); + await test_append_char('test1'); + await test_append_char('test2'); + await test_append_char('test3'); + await test_append_char('test4'); + SimpleTest.finish(); + } + + SimpleTest.waitForFocus(runTest); + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=502258">Mozilla Bug 502258</a> +<p id="display"></p> +<style>input {appearance:none}</style> +<div id="content" style="display: none"> + <input id="test1" type=password> + <input id="test2" type=password value="123"> + <!-- text value masked off --> + <div style="position:relative; margin: 1em 0;"> + <input id="test3" type=password style="position:absolute"> + <div style="position:absolute; top:0;left:0; width:10ch; height:2em; background:black"></div> + </div> + <br> + <!-- Show Password button masked off --> + <div style="position:relative; margin: 1em 0;"> + <input id="test4" type=password style="position:absolute"> + <div style="position:absolute; top:0;left:10ch; width:20ch; height:2em; background:black"></div> + </div> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_radio_indeterminate.html b/dom/html/test/forms/test_input_radio_indeterminate.html new file mode 100644 index 0000000000..0fe7028b1e --- /dev/null +++ b/dom/html/test/forms/test_input_radio_indeterminate.html @@ -0,0 +1,109 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=885359 +--> +<head> + <title>Test for Bug 885359</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=885359">Mozilla Bug 343444</a> +<p id="display"></p> +<form> + <input type="radio" id='radio1'/><br/> + + <input type="radio" id="g1radio1" name="group1"/> + <input type="radio" id="g1radio2" name="group1"/></br> + <input type="radio" id="g1radio3" name="group1"/></br> + + <input type="radio" id="g2radio1" name="group2"/> + <input type="radio" id="g2radio2" name="group2" checked/></br> +</form> +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); + +var radio1 = document.getElementById("radio1"); +var g1radio1 = document.getElementById("g1radio1"); +var g1radio2 = document.getElementById("g1radio2"); +var g1radio3 = document.getElementById("g1radio3"); +var g2radio1 = document.getElementById("g2radio1"); +var g2radio2 = document.getElementById("g2radio2"); + +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +function verifyIndeterminateState(aElement, aIsIndeterminate, aMessage) { + is(aElement.mozMatchesSelector(':indeterminate'), aIsIndeterminate, aMessage); +} + +function test() { + // Initial State. + verifyIndeterminateState(radio1, true, + "Unchecked radio in its own group (no name attribute)"); + verifyIndeterminateState(g1radio1, true, "No selected radio in its group"); + verifyIndeterminateState(g1radio2, true, "No selected radio in its group"); + verifyIndeterminateState(g1radio3, true, "No selected radio in its group"); + verifyIndeterminateState(g2radio1, false, "Selected radio in its group"); + verifyIndeterminateState(g2radio2, false, "Selected radio in its group"); + + // Selecting radio buttion. + g1radio1.checked = true; + verifyIndeterminateState(g1radio1, false, + "Selecting a radio should affect all radios in the group"); + verifyIndeterminateState(g1radio2, false, + "Selecting a radio should affect all radios in the group"); + verifyIndeterminateState(g1radio3, false, + "Selecting a radio should affect all radios in the group"); + + // Changing the selected radio button. + g1radio3.checked = true; + verifyIndeterminateState(g1radio1, false, + "Selecting a radio should affect all radios in the group"); + verifyIndeterminateState(g1radio2, false, + "Selecting a radio should affect all radios in the group"); + verifyIndeterminateState(g1radio3, false, + "Selecting a radio should affect all radios in the group"); + + // Deselecting radio button. + g2radio2.checked = false; + verifyIndeterminateState(g2radio1, true, + "Deselecting a radio should affect all radios in the group"); + verifyIndeterminateState(g2radio2, true, + "Deselecting a radio should affect all radios in the group"); + + // Move a selected radio button to another group. + g1radio3.name = "group2"; + + // The radios' state in the original group becomes indeterminated. + verifyIndeterminateState(g1radio1, true, + "Removing a radio from a group should affect all radios in the group"); + verifyIndeterminateState(g1radio2, true, + "Removing a radio from a group should affect all radios in the group"); + + // The radios' state in the new group becomes determinated. + verifyIndeterminateState(g1radio3, false, + "Adding a radio from a group should affect all radios in the group"); + verifyIndeterminateState(g2radio1, false, + "Adding a radio from a group should affect all radios in the group"); + verifyIndeterminateState(g2radio2, false, + "Adding a radio from a group should affect all radios in the group"); + + // Change input type to 'text'. + g1radio3.type = "text"; + verifyIndeterminateState(g1radio3, false, + "Input type text does not have an indeterminate state"); + verifyIndeterminateState(g2radio1, true, + "Changing input type should affect all radios in the group"); + verifyIndeterminateState(g2radio2, true, + "Changing input type should affect all radios in the group"); +} +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/forms/test_input_radio_radiogroup.html b/dom/html/test/forms/test_input_radio_radiogroup.html new file mode 100644 index 0000000000..62767def72 --- /dev/null +++ b/dom/html/test/forms/test_input_radio_radiogroup.html @@ -0,0 +1,75 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=343444 +--> +<head> + <title>Test for Bug 343444</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=343444">Mozilla Bug 343444</a> +<p id="display"></p> +<form> + <fieldset id="testradio"> + <input type="radio" name="testradio" id="start"></input> + <input type="text" name="testradio"></input> + <input type="text" name="testradio"></input> + <input type="radio" name="testradio"></input> + <input type="text" name="testradio"></input> + <input type="radio" name="testradio"></input> + <input type="text" name="testradio"></input> + <input type="radio" name="testradio"></input> + <input type="radio" name="testradio"></input> + <input type="text" name="testradio"></input> + </fieldset> + + <fieldset> + <input type="radio" name="testtwo" id="start2"></input> + <input type="radio" name="testtwo"></input> + <input type="radio" name="error" id="testtwo"></input> + <input type="radio" name="testtwo" id="end"></input> + </fieldset> + + <fieldset> + <input type="radio" name="testthree" id="start3"></input> + <input type="radio" name="errorthree" id="testthree"></input> + </fieldset> +</form> +<script class="testbody" type="text/javascript"> +/** Test for Bug 343444 **/ +SimpleTest.waitForExplicitFinish(); +startTest(); +function startTest() { + document.getElementById("start").focus(); + var count=0; + while (count < 2) { + sendKey("DOWN"); + is(document.activeElement.type, "radio", "radioGroup should ignore non-radio input fields"); + if (document.activeElement.id == "start") { + count++; + } + } + + document.getElementById("start2").focus(); + count = 0; + while (count < 3) { + is(document.activeElement.name, "testtwo", + "radioGroup should only contain elements with the same @name") + sendKey("DOWN"); + count++; + } + + document.getElementById("start3").focus(); + sendKey("DOWN"); + is(document.activeElement.name, "testthree", "we don't have an infinite-loop"); + SimpleTest.finish(); +} +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/forms/test_input_radio_required.html b/dom/html/test/forms/test_input_radio_required.html new file mode 100644 index 0000000000..ae02aab2ff --- /dev/null +++ b/dom/html/test/forms/test_input_radio_required.html @@ -0,0 +1,31 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id={BUGNUMBER} +--> +<head> + <title>Test for Bug 1100535</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1100535">Mozilla Bug 1100535</a> +<p id="display"></p> +<div id="content" style="display: none"> +<form> + <input type="radio" name="a"> +</form> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + var input = document.querySelector("input"); + input.setAttribute("required", "x"); + input.setAttribute("required", "y"); + is(document.forms[0].checkValidity(), false); + input.required = false; + is(document.forms[0].checkValidity(), true); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_range_attr_order.html b/dom/html/test/forms/test_input_range_attr_order.html new file mode 100644 index 0000000000..dc3f1ac95c --- /dev/null +++ b/dom/html/test/forms/test_input_range_attr_order.html @@ -0,0 +1,48 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=841941 +--> +<head> + <title>Test @min/@max/@step order for range</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=841941">Mozilla Bug 841941</a> +<p id="display"></p> +<div id="content"> + <input type=range value=2 max=1.5 step=0.5> + <input type=range value=2 step=0.5 max=1.5> + <input type=range value=2 max=1.5 step=0.5> + <input type=range value=2 step=0.5 max=1.5> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** + * Test for Bug 841941 + * This test checks that the order in which @min/@max/@step are specified in + * markup makes no difference to the value that <input type=range> will be + * given. Basically this checks that sanitization of the value does not occur + * until after the parser has finished with the element. + */ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +function test() { + var ranges = document.querySelectorAll("input[type=range]"); + for (var i = 0; i < ranges.length; i++) { + is(ranges.item(i).value, "1.5", "Check sanitization order for range " + i); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_range_key_events.html b/dom/html/test/forms/test_input_range_key_events.html new file mode 100644 index 0000000000..6daf572916 --- /dev/null +++ b/dom/html/test/forms/test_input_range_key_events.html @@ -0,0 +1,207 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=843725 +--> +<head> + <title>Test key events for range</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=843725">Mozilla Bug 843725</a> +<p id="display"></p> +<div id="content"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** + * Test for Bug 843725 + * This test checks how the value of <input type=range> changes in response to + * various key events while it is in various states. + **/ +SimpleTest.waitForExplicitFinish(); + +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +const defaultMinimum = 0; +const defaultMaximum = 100; +const defaultStep = 1; + +// Helpers: +// For the sake of simplicity, we do not currently support fractional value, +// step, etc. + +function minimum(element) { + return Number(element.min || defaultMinimum); +} + +function maximum(element) { + return Number(element.max || defaultMaximum); +} + +function range(element) { + var max = maximum(element); + var min = minimum(element); + if (max < min) { + return 0; + } + return max - min; +} + +function defaultValue(element) { + return minimum(element) + range(element)/2; +} + +function value(element) { + return Number(element.value || defaultValue(element)); +} + +function step(element) { + var stepSize = Number(element.step || defaultStep); + return stepSize <= 0 ? defaultStep : stepSize; +} + +function clampToRange(val, element) { + var min = minimum(element); + var max = maximum(element); + if (max < min) { + return min; + } + if (val < min) { + return min; + } + if (val > max) { + return max; + } + return val; +} + +// Functions used to specify expected test results: + +function valuePlusStep(element) { + return clampToRange(value(element) + step(element), element); +} + +function valueMinusStep(element) { + return clampToRange(value(element) - step(element), element); +} + +/** + * Returns the current value of the range plus whichever is greater of either + * 10% of the range or its current step value, clamped to the range's minimum/ + * maximum. The reason for using the step if it is greater than 10% of the + * range is because otherwise the PgUp/PgDn keys would do nothing in that case. + */ +function valuePlusTenPctOrStep(element) { + var tenPct = range(element)/10; + var stp = step(element); + return clampToRange(value(element) + Math.max(tenPct, stp), element); +} + +function valueMinusTenPctOrStep(element) { + var tenPct = range(element)/10; + var stp = step(element); + return clampToRange(value(element) - Math.max(tenPct, stp), element); +} + +// Test table: + +const LTR = "ltr"; +const RTL = "rtl"; + +var testTable = [ + ["KEY_ArrowLeft", LTR, valueMinusStep], + ["KEY_ArrowLeft", RTL, valuePlusStep], + ["KEY_ArrowRight", LTR, valuePlusStep], + ["KEY_ArrowRight", RTL, valueMinusStep], + ["KEY_ArrowUp", LTR, valuePlusStep], + ["KEY_ArrowUp", RTL, valuePlusStep], + ["KEY_ArrowDown", LTR, valueMinusStep], + ["KEY_ArrowDown", RTL, valueMinusStep], + ["KEY_PageUp", LTR, valuePlusTenPctOrStep], + ["KEY_PageUp", RTL, valuePlusTenPctOrStep], + ["KEY_PageDown", LTR, valueMinusTenPctOrStep], + ["KEY_PageDown", RTL, valueMinusTenPctOrStep], + ["KEY_Home", LTR, minimum], + ["KEY_Home", RTL, minimum], + ["KEY_End", LTR, maximum], + ["KEY_End", RTL, maximum], +] + +function test() { + var elem = document.createElement("input"); + elem.type = "range"; + + var content = document.getElementById("content"); + content.appendChild(elem); + elem.focus(); + + for (test of testTable) { + var [key, dir, expectedFunc] = test; + var oldVal, expectedVal; + + elem.step = "2"; + elem.style.direction = dir; + var flush = document.body.clientWidth; + + // Start at middle: + elem.value = oldVal = defaultValue(elem); + expectedVal = expectedFunc(elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test " + key + " for " + dir + " range with value set to the midpoint (" + oldVal + ")"); + + // Same again: + expectedVal = expectedFunc(elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test repeat of " + key + " for " + dir + " range"); + + // Start at maximum: + elem.value = oldVal = maximum(elem); + expectedVal = expectedFunc(elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test " + key + " for " + dir + " range with value set to the maximum (" + oldVal + ")"); + + // Same again: + expectedVal = expectedFunc(elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test repeat of " + key + " for " + dir + " range"); + + // Start at minimum: + elem.value = oldVal = minimum(elem); + expectedVal = expectedFunc(elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test " + key + " for " + dir + " range with value set to the minimum (" + oldVal + ")"); + + // Same again: + expectedVal = expectedFunc(elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test repeat of " + key + " for " + dir + " range"); + + // Test for a step value that is greater than 10% of the range: + elem.step = 20; + elem.value = 60; + expectedVal = expectedFunc(elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test " + key + " for " + dir + " range with a step that is greater than 10% of the range (step=" + elem.step + ")"); + + // Same again: + expectedVal = expectedFunc(elem); + synthesizeKey(key); + is(elem.value, String(expectedVal), "Test repeat of " + key + " for " + dir + " range"); + + // reset step: + elem.step = 2; + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_range_mouse_and_touch_events.html b/dom/html/test/forms/test_input_range_mouse_and_touch_events.html new file mode 100644 index 0000000000..5957ede81d --- /dev/null +++ b/dom/html/test/forms/test_input_range_mouse_and_touch_events.html @@ -0,0 +1,240 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=846380 +--> +<head> + <title>Test mouse and touch events for range</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <style> + /* synthesizeMouse and synthesizeFunc uses getBoundingClientRect. We set + * the following properties to avoid fractional values in the rect returned + * by getBoundingClientRect in order to avoid rounding that would occur + * when event coordinates are internally converted to be relative to the + * top-left of the element. (Such rounding would make it difficult to + * predict exactly what value the input should take on for events at + * certain coordinates.) + */ + input { margin: 0 ! important; width: 200px ! important; } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=846380">Mozilla Bug 846380</a> +<p id="display"></p> +<div id="content"> + <input id="range" type="range"> +</div> +<pre id="test"> +<script type="application/javascript"> + +const { AppConstants } = SpecialPowers.ChromeUtils.importESModule( + "resource://gre/modules/AppConstants.sys.mjs" +); + +/** + * Test for Bug 846380 + * This test checks how the value of <input type=range> changes in response to + * various mouse and touch events. + **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(synthesizeMouse, "click", "mousedown", "mousemove", "mouseup"); + test(synthesizeTouch, "tap", "touchstart", "touchmove", "touchend"); + SimpleTest.finish(); +}); + +const kIsWin = AppConstants.platform == "win"; +const kIsLinux = AppConstants.platform == "linux"; + +const MIDDLE_OF_RANGE = "50"; +const MINIMUM_OF_RANGE = "0"; +const MAXIMUM_OF_RANGE = "100"; +const QUARTER_OF_RANGE = "25"; +const THREE_QUARTERS_OF_RANGE = "75"; + +function flush() { + // Flush style, specifically to flush the 'direction' property so that the + // browser uses the new value for thumb positioning. + document.body.clientWidth; +} + +function test(synthesizeFunc, clickOrTap, startName, moveName, endName) { + var elem = document.getElementById("range"); + elem.focus(); + flush(); + + var width = parseFloat(window.getComputedStyle(elem).width); + var height = parseFloat(window.getComputedStyle(elem).height); + var borderLeft = parseFloat(window.getComputedStyle(elem).borderLeftWidth); + var borderTop = parseFloat(window.getComputedStyle(elem).borderTopWidth); + var paddingLeft = parseFloat(window.getComputedStyle(elem).paddingLeft); + var paddingTop = parseFloat(window.getComputedStyle(elem).paddingTop); + + // Extrema for mouse/touch events: + var midY = height / 2 + borderTop + paddingTop; + var minX = borderLeft + paddingLeft; + var midX = minX + width / 2; + var maxX = minX + width; + + // Test click/tap in the middle of the range: + elem.value = QUARTER_OF_RANGE; + synthesizeFunc(elem, midX, midY, {}); + is(elem.value, MIDDLE_OF_RANGE, "Test " + clickOrTap + " in middle of range"); + + // Test mouse/touch dragging of ltr range: + elem.value = QUARTER_OF_RANGE; + synthesizeFunc(elem, midX, midY, { type: startName }); + is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of range"); + synthesizeFunc(elem, minX, midY, { type: moveName }); + is(elem.value, MINIMUM_OF_RANGE, "Test dragging of range to left of ltr range"); + + synthesizeFunc(elem, maxX, midY, { type: moveName }); + is(elem.value, MAXIMUM_OF_RANGE, "Test dragging of range to right of ltr range (" + moveName + ")"); + + synthesizeFunc(elem, maxX, midY, { type: endName }); + is(elem.value, MAXIMUM_OF_RANGE, "Test dragging of range to right of ltr range (" + endName + ")"); + + // Test mouse/touch dragging of rtl range: + elem.value = QUARTER_OF_RANGE; + elem.style.direction = "rtl"; + flush(); + synthesizeFunc(elem, midX, midY, { type: startName }); + is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of rtl range"); + synthesizeFunc(elem, minX, midY, { type: moveName }); + is(elem.value, MAXIMUM_OF_RANGE, "Test dragging of range to left of rtl range"); + + synthesizeFunc(elem, maxX, midY, { type: moveName }); + is(elem.value, MINIMUM_OF_RANGE, "Test dragging of range to right of rtl range (" + moveName + ")"); + + synthesizeFunc(elem, maxX, midY, { type: endName }); + is(elem.value, MINIMUM_OF_RANGE, "Test dragging of range to right of rtl range (" + endName + ")"); + + elem.style.direction = "ltr"; // reset direction + flush(); + + // Test mouse/touch capturing by moving pointer to a position outside the range: + elem.value = QUARTER_OF_RANGE; + synthesizeFunc(elem, midX, midY, { type: startName }); + is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of range"); + synthesizeFunc(elem, maxX+100, midY, { type: moveName }); + is(elem.value, MAXIMUM_OF_RANGE, "Test dragging of range to position outside range (" + moveName + ")"); + + synthesizeFunc(elem, maxX+100, midY, { type: endName }); + is(elem.value, MAXIMUM_OF_RANGE, "Test dragging of range to position outside range (" + endName + ")"); + + // Test mouse/touch capturing by moving pointer to a position outside a rtl range: + elem.value = QUARTER_OF_RANGE; + elem.style.direction = "rtl"; + flush(); + synthesizeFunc(elem, midX, midY, { type: startName }); + is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of rtl range"); + synthesizeFunc(elem, maxX+100, midY, { type: moveName }); + is(elem.value, MINIMUM_OF_RANGE, "Test dragging of range to position outside range (" + moveName + ")"); + + synthesizeFunc(elem, maxX+100, midY, { type: endName }); + is(elem.value, MINIMUM_OF_RANGE, "Test dragging of range to position outside range (" + endName + ")"); + + elem.style.direction = "ltr"; // reset direction + flush(); + + // Test mouse/touch events with certain modifiers are ignored: + var modifiersIgnore = ["ctrlKey", "altGrKey", "fnKey"]; + if (kIsWin || kIsLinux) { + modifiersIgnore.push("metaKey"); + } + for (var modifier of modifiersIgnore) { + elem.value = QUARTER_OF_RANGE; + var eventParams = {}; + eventParams[modifier] = true; + synthesizeFunc(elem, midX, midY, eventParams); + is(elem.value, QUARTER_OF_RANGE, "Test " + clickOrTap + " in the middle of range with " + modifier + " modifier key is ignored"); + } + + // Test mouse/touch events with certain modifiers are allowed: + var modifiersAllow = ["shiftKey", "altKey"]; + if (!modifiersIgnore.includes("metaKey")) { + modifiersAllow.push("metaKey"); + } + for (var modifier of modifiersAllow) { + elem.value = QUARTER_OF_RANGE; + var eventParams = {}; + eventParams[modifier] = true; + synthesizeFunc(elem, midX, midY, eventParams); + is(elem.value, MIDDLE_OF_RANGE, "Test " + clickOrTap + " in the middle of range with " + modifier + " modifier key is allowed"); + } + + // Test that preventDefault() works: + function preventDefault(e) { + e.preventDefault(); + } + elem.value = QUARTER_OF_RANGE; + elem.addEventListener(startName, preventDefault); + synthesizeFunc(elem, midX, midY, {}); + is(elem.value, QUARTER_OF_RANGE, "Test that preventDefault() works"); + elem.removeEventListener(startName, preventDefault); + + // Test that changing the input type in the middle of a drag cancels the drag: + elem.value = QUARTER_OF_RANGE; + synthesizeFunc(elem, midX, midY, { type: startName }); + is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of range"); + elem.type = "text"; + is(elem.value, QUARTER_OF_RANGE, "Test that changing the input type cancels a drag"); + synthesizeFunc(elem, midX, midY, { type: endName }); + is(elem.value, QUARTER_OF_RANGE, "Test that changing the input type cancels a drag (after " + endName + ")"); + elem.type = "range"; + + // Check that we do not drag when the mousedown/touchstart occurs outside the range: + elem.value = QUARTER_OF_RANGE; + synthesizeFunc(elem, maxX+100, midY, { type: startName }); + is(elem.value, QUARTER_OF_RANGE, "Test " + startName + " outside range doesn't change its value"); + synthesizeFunc(elem, midX, midY, { type: moveName }); + is(elem.value, QUARTER_OF_RANGE, "Test dragging is not occurring when " + startName + " was outside range"); + + synthesizeFunc(elem, midX, midY, { type: endName }); + is(elem.value, QUARTER_OF_RANGE, "Test dragging is not occurring when " + startName + " was outside range"); + + elem.focus(); // RESTORE FOCUS SO WE GET THE FOCUSED STYLE FOR TESTING OR ELSE minX/midX/maxX may be wrong! + + // Check what happens when a value changing key is pressed during a drag: + elem.value = QUARTER_OF_RANGE; + synthesizeFunc(elem, midX, midY, { type: startName }); + is(elem.value, MIDDLE_OF_RANGE, "Test " + startName + " in middle of range"); + synthesizeKey("KEY_Home"); + // The KEY_Home tests are disabled until I can figure out why they fail on Android -jwatt + //is(elem.value, MINIMUM_OF_RANGE, "Test KEY_Home during a drag sets the value to the minimum of the range"); + synthesizeFunc(elem, midX+100, midY, { type: moveName }); + is(elem.value, MAXIMUM_OF_RANGE, "Test " + moveName + " outside range after key press that occurred during a drag changes the value"); + synthesizeFunc(elem, midX, midY, { type: moveName }); + is(elem.value, MIDDLE_OF_RANGE, "Test " + moveName + " in middle of range"); + synthesizeKey("KEY_Home"); + //is(elem.value, MINIMUM_OF_RANGE, "Test KEY_Home during a drag sets the value to the minimum of the range (second time)"); + synthesizeFunc(elem, maxX+100, midY, { type: endName }); + is(elem.value, MAXIMUM_OF_RANGE, "Test " + endName + " outside range after key press that occurred during a drag changes the value"); + + function hideElement() { + elem.parentNode.style.display = 'none'; + elem.parentNode.offsetLeft; + } + + if (clickOrTap == "click") { + elem.addEventListener("mousedown", hideElement); + } else if (clickOrTap == "tap") { + elem.addEventListener("touchstart", hideElement); + } + synthesizeFunc(elem, midX, midY, { type: startName }); + synthesizeFunc(elem, midX, midY, { type: endName }); + elem.removeEventListener("mousedown", hideElement); + elem.removeEventListener("touchstart", hideElement); + ok(true, "Hiding the element during mousedown/touchstart shouldn't crash the process."); + elem.parentNode.style.display = "block"; + elem.parentNode.offsetLeft; +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_range_rounding.html b/dom/html/test/forms/test_input_range_rounding.html new file mode 100644 index 0000000000..9c3c21ce6e --- /dev/null +++ b/dom/html/test/forms/test_input_range_rounding.html @@ -0,0 +1,103 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=853525 +--> +<head> + <title>Test key events for range</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=853525">Mozilla Bug 853525</a> +<p id="display"></p> +<div id="content"> + <input id=range type=range value=0 step=0.01 max=1> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** + * Test for Bug 853525 + * This test checks that when <input type=range> has fractional step values, + * the values that a content author will see in their script will not have + * ugly rounding errors. + **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +/** + * We can _NOT_ generate these values by looping and simply incrementing a + * variable by 0.01 and stringifying it, since we'll end up with strings like + * "0.060000000000000005" due to the inability of binary floating point numbers + * to accurately represent decimal values. + */ +var stepVals = [ + "0", "0.01", "0.02", "0.03", "0.04", "0.05", "0.06", "0.07", "0.08", "0.09", + "0.1", "0.11", "0.12", "0.13", "0.14", "0.15", "0.16", "0.17", "0.18", "0.19", + "0.2", "0.21", "0.22", "0.23", "0.24", "0.25", "0.26", "0.27", "0.28", "0.29", + "0.3", "0.31", "0.32", "0.33", "0.34", "0.35", "0.36", "0.37", "0.38", "0.39", + "0.4", "0.41", "0.42", "0.43", "0.44", "0.45", "0.46", "0.47", "0.48", "0.49", + "0.5", "0.51", "0.52", "0.53", "0.54", "0.55", "0.56", "0.57", "0.58", "0.59", + "0.6", "0.61", "0.62", "0.63", "0.64", "0.65", "0.66", "0.67", "0.68", "0.69", + "0.7", "0.71", "0.72", "0.73", "0.74", "0.75", "0.76", "0.77", "0.78", "0.79", + "0.8", "0.81", "0.82", "0.83", "0.84", "0.85", "0.86", "0.87", "0.88", "0.89", + "0.9", "0.91", "0.92", "0.93", "0.94", "0.95", "0.96", "0.97", "0.98", "0.99", + "1" +]; + +var pgUpDnVals = [ + "0", "0.1", "0.2", "0.3", "0.4", "0.5", "0.6", "0.7", "0.8", "0.9", "1" +]; + +function test() { + var elem = document.getElementById("range"); + + elem.focus(); + + for (var i = 1; i < pgUpDnVals.length; ++i) { + synthesizeKey("KEY_PageUp"); + is(elem.value, pgUpDnVals[i], "Test KEY_PageUp"); + is(elem.validity.valid, true, "Check element is valid for value " + pgUpDnVals[i]); + } + + for (var i = pgUpDnVals.length - 2; i >= 0; --i) { + synthesizeKey("KEY_PageDown"); + is(elem.value, pgUpDnVals[i], "Test KEY_PageDown"); + is(elem.validity.valid, true, "Check element is valid for value " + pgUpDnVals[i]); + } + + for (var i = 1; i < stepVals.length; ++i) { + synthesizeKey("KEY_ArrowUp"); + is(elem.value, stepVals[i], "Test KEY_ArrowUp"); + is(elem.validity.valid, true, "Check element is valid for value " + stepVals[i]); + } + + for (var i = stepVals.length - 2; i >= 0; --i) { + synthesizeKey("KEY_ArrowDown"); + is(elem.value, stepVals[i], "Test KEY_ArrowDown"); + is(elem.validity.valid, true, "Check element is valid for value " + stepVals[i]); + } + + for (var i = 1; i < stepVals.length; ++i) { + elem.stepUp(); + is(elem.value, stepVals[i], "Test stepUp()"); + is(elem.validity.valid, true, "Check element is valid for value " + stepVals[i]); + } + + for (var i = stepVals.length - 2; i >= 0; --i) { + elem.stepDown(); + is(elem.value, stepVals[i], "Test stepDown()"); + is(elem.validity.valid, true, "Check element is valid for value " + stepVals[i]); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_sanitization.html b/dom/html/test/forms/test_input_sanitization.html new file mode 100644 index 0000000000..474ddd621d --- /dev/null +++ b/dom/html/test/forms/test_input_sanitization.html @@ -0,0 +1,585 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=549475 +--> +<head> + <title>Test for Bug 549475</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=549475">Mozilla Bug 549475</a> +<p id="display"></p> +<pre id="test"> +<div id='content'> + <form> + </form> +</div> +<script type="application/javascript"> + +SimpleTest.requestLongerTimeout(2); + +/** + * This files tests the 'value sanitization algorithm' for the various input + * types. Note that an input's value is affected by more than just its type's + * value sanitization algorithm; e.g. some type=range has actions that the user + * agent must perform to change the element's value to avoid underflow/overflow + * and step mismatch (when possible). We specifically avoid triggering these + * other actions here so that this test only tests the value sanitization + * algorithm for the various input types. + * + * XXXjwatt splitting out testing of the value sanitization algorithm and + * "other things" that affect .value makes it harder to know what we're testing + * and what we've missed, because what's included in the value sanitization + * algorithm and what's not is different from input type to input type. It + * seems to me it would be better to have a test (maybe one per type) focused + * on testing .value for permutations of all other inputs that can affect it. + * The value sanitization algorithm is just an internal spec concept after all. + */ + +// We buffer up the results of sets of sub-tests, and avoid outputting log +// entries for them all if they all pass. Otherwise, we have an enormous amount +// of test output. + +var delayedTests = []; +var anyFailedDelayedTests = false; + +function delayed_is(actual, expected, description) +{ + var result = actual == expected; + delayedTests.push({ actual, expected, description }); + if (!result) { + anyFailedDelayedTests = true; + } +} + +function flushDelayedTests(description) +{ + if (anyFailedDelayedTests) { + info("Outputting individual results for \"" + description + "\" due to failures in subtests"); + for (var test of delayedTests) { + is(test.actual, test.expected, test.description); + } + } else { + ok(true, description + " (" + delayedTests.length + " subtests)"); + } + delayedTests = []; + anyFailedDelayedTests = false; +} + +// We are excluding "file" because it's too different from the other types. +// And it has no sanitizing algorithm. +var inputTypes = +[ + "text", "password", "search", "tel", "hidden", "checkbox", "radio", + "submit", "image", "reset", "button", "email", "url", "number", "date", + "time", "range", "color", "month", "week", "datetime-local" +]; + +var valueModeValue = +[ + "text", "search", "url", "tel", "email", "password", "date", "datetime", + "month", "week", "time", "datetime-local", "number", "range", "color", +]; + +function sanitizeDate(aValue) +{ + // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-date-string + function getNumbersOfDaysInMonth(aMonth, aYear) { + if (aMonth === 2) { + return (aYear % 400 === 0 || (aYear % 100 != 0 && aYear % 4 === 0)) ? 29 : 28; + } + return (aMonth === 1 || aMonth === 3 || aMonth === 5 || aMonth === 7 || + aMonth === 8 || aMonth === 10 || aMonth === 12) ? 31 : 30; + } + + var match = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})$/.exec(aValue); + if (!match) { + return ""; + } + var year = Number(match[1]); + if (year === 0) { + return ""; + } + var month = Number(match[2]); + if (month > 12 || month < 1) { + return ""; + } + var day = Number(match[3]); + return 1 <= day && day <= getNumbersOfDaysInMonth(month, year) ? aValue : ""; +} + +function sanitizeTime(aValue) +{ + // http://www.whatwg.org/specs/web-apps/current-work/multipage/common-microsyntaxes.html#valid-time-string + var match = /^([0-9]{2}):([0-9]{2})(.*)$/.exec(aValue); + if (!match) { + return ""; + } + var hours = match[1]; + if (hours < 0 || hours > 23) { + return ""; + } + var minutes = match[2]; + if (minutes < 0 || minutes > 59) { + return ""; + } + var other = match[3]; + if (other == "") { + return aValue; + } + match = /^:([0-9]{2})(.*)$/.exec(other); + if (!match) { + return ""; + } + var seconds = match[1]; + if (seconds < 0 || seconds > 59) { + return ""; + } + var other = match[2]; + if (other == "") { + return aValue; + } + match = /^.([0-9]{1,3})$/.exec(other); + if (!match) { + return ""; + } + return aValue; +} + +function sanitizeDateTimeLocal(aValue) +{ + // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-local-date-and-time-string + if (aValue.length < 16) { + return ""; + } + + var sepIndex = aValue.indexOf("T"); + if (sepIndex == -1) { + sepIndex = aValue.indexOf(" "); + if (sepIndex == -1) { + return ""; + } + } + + var [date, time] = aValue.split(aValue[sepIndex]); + if (!sanitizeDate(date)) { + return ""; + } + + if (!sanitizeTime(time)) { + return ""; + } + + // Normalize datetime-local string. + // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-normalised-local-date-and-time-string + if (aValue[sepIndex] == " ") { + aValue = date + "T" + time; + } + + if ((aValue.length - sepIndex) == 6) { + return aValue; + } + + if ((aValue.length - sepIndex) > 9) { + var milliseconds = aValue.substring(sepIndex + 10); + if (Number(milliseconds) != 0) { + return aValue; + } + aValue = aValue.slice(0, sepIndex + 9); + } + + var seconds = aValue.substring(sepIndex + 7); + if (Number(seconds) != 0) { + return aValue; + } + aValue = aValue.slice(0, sepIndex + 6); + + return aValue; +} + +function sanitizeValue(aType, aValue) +{ + // http://www.whatwg.org/html/#value-sanitization-algorithm + switch (aType) { + case "text": + case "password": + case "search": + case "tel": + return aValue.replace(/[\n\r]/g, ""); + case "url": + case "email": + return aValue.replace(/[\n\r]/g, "").replace(/^[\u0020\u0009\t\u000a\u000c\u000d]+|[\u0020\u0009\t\u000a\u000c\u000d]+$/g, ""); + case "number": + return isNaN(Number(aValue)) ? "" : aValue; + case "range": + var defaultMinimum = 0; + var defaultMaximum = 100; + var value = Number(aValue); + if (isNaN(value)) { + return ((defaultMaximum - defaultMinimum)/2).toString(); // "50" + } + if (value < defaultMinimum) { + return defaultMinimum.toString(); + } + if (value > defaultMaximum) { + return defaultMaximum.toString(); + } + return aValue; + case "date": + return sanitizeDate(aValue); + case "time": + return sanitizeTime(aValue); + case "month": + // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-month-string + var match = /^([0-9]{4,})-([0-9]{2})$/.exec(aValue); + if (!match) { + return ""; + } + var year = Number(match[1]); + if (year === 0) { + return ""; + } + var month = Number(match[2]); + if (month > 12 || month < 1) { + return ""; + } + return aValue; + case "week": + // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-week-string + function isLeapYear(aYear) { + return ((aYear % 4 == 0) && (aYear % 100 != 0)) || (aYear % 400 == 0); + } + function getDayofWeek(aYear, aMonth, aDay) { /* 0 = Sunday */ + // Tomohiko Sakamoto algorithm. + var monthTable = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]; + aYear -= Number(aMonth < 3); + + return (aYear + parseInt(aYear / 4) - parseInt(aYear / 100) + + parseInt(aYear / 400) + monthTable[aMonth - 1] + aDay) % 7; + } + function getMaximumWeekInYear(aYear) { + var day = getDayofWeek(aYear, 1, 1); + return day == 4 || (day == 3 && isLeapYear(aYear)) ? 53 : 52; + } + + var match = /^([0-9]{4,})-W([0-9]{2})$/.exec(aValue); + if (!match) { + return ""; + } + var year = Number(match[1]); + if (year === 0) { + return ""; + } + var week = Number(match[2]); + if (week > 53 || month < 1) { + return ""; + } + return 1 <= week && week <= getMaximumWeekInYear(year) ? aValue : ""; + case "datetime-local": + return sanitizeDateTimeLocal(aValue); + case "color": + return /^#[0-9A-Fa-f]{6}$/.exec(aValue) ? aValue.toLowerCase() : "#000000"; + default: + return aValue; + } +} + +function checkSanitizing(element, inputTypeDescription) +{ + var testData = + [ + // For text, password, search, tel, email: + "\n\rfoo\n\r", + "foo\n\rbar", + " foo ", + " foo\n\r bar ", + // For url: + "\r\n foobar \n\r", + "\u000B foo \u000B", + "\u000A foo \u000A", + "\u000C foo \u000C", + "\u000d foo \u000d", + "\u0020 foo \u0020", + " \u0009 foo \u0009 ", + // For number and range: + "42", + "13.37", + "1.234567898765432", + "12foo", + "1e2", + "3E42", + // For date: + "1970-01-01", + "1234-12-12", + "1234567890-01-02", + "2012-12-31", + "2012-02-29", + "2000-02-29", + "1234", + "1234-", + "12345", + "1234-01", + "1234-012", + "1234-01-", + "12-12", + "999-01-01", + "1234-56-78-91", + "1234-567-78", + "1234--7-78", + "abcd-12-12", + "thisinotadate", + "2012-13-01", + "1234-12-42", + " 2012-13-01", + " 123-01-01", + "2012- 3-01", + "12- 10- 01", + " 12-0-1", + "2012-3-001", + "2012-12-00", + "2012-12-1r", + "2012-11-31", + "2011-02-29", + "2100-02-29", + "a2000-01-01", + "2000a-01-0'", + "20aa00-01-01", + "2000a2000-01-01", + "2000-1-1", + "2000-1-01", + "2000-01-1", + "2000-01-01 ", + "2000- 01-01", + "-1970-01-01", + "0000-00-00", + "0001-00-00", + "0000-01-01", + "1234-12 12", + "1234 12-12", + "1234 12 12", + // For time: + "1", + "10", + "10:", + "10:1", + "21:21", + ":21:21", + "-21:21", + " 21:21", + "21-21", + "21:21:", + "21:211", + "121:211", + "21:21 ", + "00:00", + "-1:00", + "24:00", + "00:60", + "01:01", + "23:59", + "99:99", + "8:30", + "19:2", + "19:a2", + "4c:19", + "10:.1", + "1.:10", + "13:37:42", + "13:37.42", + "13:37:42 ", + "13:37:42.", + "13:37:61.", + "13:37:00", + "13:37:99", + "13:37:b5", + "13:37:-1", + "13:37:.1", + "13:37:1.", + "13:37:42.001", + "13:37:42.001", + "13:37:42.abc", + "13:37:42.00c", + "13:37:42.a23", + "13:37:42.12e", + "13:37:42.1e1", + "13:37:42.e11", + "13:37:42.1", + "13:37:42.99", + "13:37:42.0", + "13:37:42.00", + "13:37:42.000", + "13:37:42.-1", + "13:37:42.1.1", + "13:37:42.1,1", + "13:37:42.", + "foo12:12", + "13:37:42.100000000000", + // For color + "#00ff00", + "#000000", + "red", + "#0f0", + "#FFFFAA", + "FFAABB", + "fFAaBb", + "FFAAZZ", + "ABCDEF", + "#7654321", + // For month + "1970-01", + "1234-12", + "123456789-01", + "2013-13", + "0000-00", + "2015-00", + "0001-01", + "1-1", + "888-05", + "2013-3", + "2013-may", + "2000-1a", + "2013-03-13", + "december", + "abcdef", + "12", + " 2013-03", + "2013 - 03", + "2013 03", + "2013/03", + // For week + "1970-W01", + "1970-W53", + "1964-W53", + "1900-W10", + "2004-W53", + "2065-W53", + "2099-W53", + "2010-W53", + "2016-W30", + "1900-W3", + "2016-w30", + "2016-30", + "16-W30", + "2016-Week30", + "2000-100", + "0000-W01", + "00-W01", + "123456-W05", + "1985-W100", + "week", + // For datetime-local + "1970-01-01T00:00", + "1970-01-01Z12:00", + "1970-01-01 00:00:00", + "1970-01-01T00:00:00.0", + "1970-01-01T00:00:00.00", + "1970-01-01T00:00:00.000", + "1970-01-01 00:00:00.20", + "1969-12-31 23:59", + "1969-12-31 23:59:00", + "1969-12-31 23:59:00.000", + "1969-12-31 23:59:00.30", + "123456-01-01T12:00", + "123456-01-01T12:00:00", + "123456-01-01T12:00:00.0", + "123456-01-01T12:00:00.00", + "123456-01-01T12:00:00.000", + "123456-01-01T12:00:30", + "123456-01-01T12:00:00.123", + "10000-12-31 20:00", + "10000-12-31 20:00:00", + "10000-12-31 20:00:00.0", + "10000-12-31 20:00:00.00", + "10000-12-31 20:00:00.000", + "10000-12-31 20:00:30", + "10000-12-31 20:00:00.123", + "2016-13-01T12:00", + "2016-12-32T12:00", + "2016-11-08 15:40:30.0", + "2016-11-08T15:40:30.00", + "2016-11-07T17:30:10", + "2016-12-1T12:45", + "2016-12-01T12:45:30.123456", + "2016-12-01T24:00", + "2016-12-01T12:88:30", + "2016-12-01T12:30:99", + "2016-12-01T12:30:100", + "2016-12-01", + "2016-12-01T", + "2016-Dec-01T00:00", + "12-05-2016T00:00", + "datetime-local" + ]; + + for (value of testData) { + element.setAttribute('value', value); + delayed_is(element.value, sanitizeValue(type, value), + "The value has not been correctly sanitized for type=" + type); + delayed_is(element.getAttribute('value'), value, + "The content value should not have been sanitized"); + + if (type in valueModeValue) { + element.setAttribute('value', 'tulip'); + element.value = value; + delayed_is(element.value, sanitizeValue(type, value), + "The value has not been correctly sanitized for type=" + type); + delayed_is(element.getAttribute('value'), 'tulip', + "The content value should not have been sanitized"); + } + + element.setAttribute('value', ''); + form.reset(); + element.type = 'checkbox'; // We know this type has no sanitizing algorithm. + element.setAttribute('value', value); + delayed_is(element.value, value, "The value should not have been sanitized"); + element.type = type; + delayed_is(element.value, sanitizeValue(type, value), + "The value has not been correctly sanitized for type=" + type); + delayed_is(element.getAttribute('value'), value, + "The content value should not have been sanitized"); + + element.setAttribute('value', ''); + form.reset(); + element.setAttribute('value', value); + form.reset(); + delayed_is(element.value, sanitizeValue(type, value), + "The value has not been correctly sanitized for type=" + type); + delayed_is(element.getAttribute('value'), value, + "The content value should not have been sanitized"); + + // Cleaning-up. + element.setAttribute('value', ''); + form.reset(); + } + + flushDelayedTests(inputTypeDescription); +} + +for (type of inputTypes) { + var form = document.forms[0]; + var element = document.createElement("input"); + element.style.display = "none"; + element.type = type; + form.appendChild(element); + + checkSanitizing(element, "type=" + type + ", no frame, no editor"); + + element.style.display = ""; + checkSanitizing(element, "type=" + type + ", frame, no editor"); + + element.focus(); + element.blur(); + checkSanitizing(element, "type=" + type + ", frame, editor"); + + element.style.display = "none"; + checkSanitizing(element, "type=" + type + ", no frame, editor"); + + form.removeChild(element); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_setting_value.html b/dom/html/test/forms/test_input_setting_value.html new file mode 100644 index 0000000000..b6ddd66d24 --- /dev/null +++ b/dom/html/test/forms/test_input_setting_value.html @@ -0,0 +1,619 @@ +<!DOCTYPE> +<html> +<head> + <title>Test for setting input value</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<div id="display"> +</div> +<div id="content"><input type="text"></div> +<pre id="test"> +</pre> + +<script class="testbody" type="application/javascript"> +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(() => { + const kSetUserInputCancelable = SpecialPowers.getBoolPref("dom.input_event.allow_to_cancel_set_user_input"); + + let input = document.querySelector("input[type=text]"); + + // Setting value during composition causes committing composition before setting the value. + input.focus(); + let description = 'Setting input value at first "compositionupdate" event: '; + input.addEventListener("compositionupdate", (aEvent) => { + is(input.value, "", `${description}input value should not have been modified at first "compositionupdate" event yet`); + input.value = "def"; + is(input.value, "def", `${description}input value should be the specified value at "compositionupdate" event (after setting the value)`); + }, {once: true}); + input.addEventListener("compositionend", (aEvent) => { + todo_is(input.value, "def", `${description}input value should be the specified value at "compositionend" event`); + }, {once: true}); + input.addEventListener("input", (aEvent) => { + todo_is(input.value, "def", `${description}input value should be the specified value at "input" event`); + }, {once: true}); + synthesizeCompositionChange( + { "composition": + { "string": "abc", + "clauses": + [ + { "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 3, "length": 0 }, + }); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + todo_is(input.value, "def", `${description}input value should be set to specified value after the last "input" event`); + + input.value = ""; + description = 'Setting input value at second "compositionupdate" event: '; + synthesizeCompositionChange( + { "composition": + { "string": "ab", + "clauses": + [ + { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 2, "length": 0 }, + }); + input.addEventListener("compositionupdate", (aEvent) => { + is(input.value, "ab", `${description}input value should not have been modified at second "compositionupdate" event yet`); + input.value = "def"; + }, {once: true}); + input.addEventListener("compositionend", (aEvent) => { + is(input.value, "def", `${description}input value should be specified value at "compositionend" event`); + }, {once: true}); + input.addEventListener("input", (aEvent) => { + is(input.value, "def", `${description}input value should be specified value at "input" event`); + }, {once: true}); + synthesizeCompositionChange( + { "composition": + { "string": "abc", + "clauses": + [ + { "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 3, "length": 0 }, + }); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "def", `${description}input value should be set to specified value after the last "input" event`); + + input.value = ""; + description = 'Setting input value at "input" event for first composition update: '; + input.addEventListener("compositionupdate", (aEvent) => { + is(input.value, "", `${description}input value should not have been modified at first "compositionupdate" event yet`); + }, {once: true}); + input.addEventListener("compositionend", (aEvent) => { + todo_is(input.value, "abc", `${description}input value should be the composition string at "compositionend" event`); + }, {once: true}); + input.addEventListener("input", (aEvent) => { + is(input.value, "abc", `${description}input value should be the composition string at "input" event`); + input.value = "def"; + is(input.value, "def", `${description}input value should be the specified value at "input" event (after setting the value)`); + }, {once: true}); + synthesizeCompositionChange( + { "composition": + { "string": "abc", + "clauses": + [ + { "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 3, "length": 0 }, + }); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "def", `${description}input value should be set to specified value after the last "input" event`); + + input.value = ""; + description = 'Setting input value at "input" event for second composition update: '; + synthesizeCompositionChange( + { "composition": + { "string": "ab", + "clauses": + [ + { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 2, "length": 0 }, + }); + input.addEventListener("compositionupdate", (aEvent) => { + is(input.value, "ab", `${description}input value should not have been modified at second "compositionupdate" event yet`); + }, {once: true}); + input.addEventListener("compositionend", (aEvent) => { + todo_is(input.value, "abc", `${description}input value should be the composition string at "compositionend" event`); + }, {once: true}); + input.addEventListener("input", (aEvent) => { + is(input.value, "abc", `${description}input value should be the composition string at "input" event`); + input.value = "def"; + is(input.value, "def", `${description}input value should be the specified value at "input" event (after setting the value)`); + }, {once: true}); + synthesizeCompositionChange( + { "composition": + { "string": "abc", + "clauses": + [ + { "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 3, "length": 0 }, + }); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "def", `${description}input value should be set to specified value after the last "input" event`); + + input.value = ""; + description = 'Setting input value and reframing at "input" event for first composition update: '; + input.addEventListener("compositionupdate", (aEvent) => { + is(input.value, "", `${description}input value should not have been modified at first "compositionupdate" event yet`); + }, {once: true}); + input.addEventListener("compositionend", (aEvent) => { + todo_is(input.value, "abc", `${description}input value should be the composition string at "compositionend" event`); + }, {once: true}); + input.addEventListener("input", (aEvent) => { + is(input.value, "abc", `${description}input value should be the composition string at "input" event`); + input.value = "def"; + input.style.width = "1000px"; + is(input.value, "def", `${description}input value should be the specified value at "input" event (after setting the value)`); + }, {once: true}); + synthesizeCompositionChange( + { "composition": + { "string": "abc", + "clauses": + [ + { "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 3, "length": 0 }, + }); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "def", `${description}input value should be set to specified value after the last "input" event`); + input.style.width = ""; + + input.value = ""; + description = 'Setting input value and reframing at "input" event for second composition update: '; + synthesizeCompositionChange( + { "composition": + { "string": "ab", + "clauses": + [ + { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 2, "length": 0 }, + }); + input.addEventListener("compositionupdate", (aEvent) => { + is(input.value, "ab", `${description}input value should not have been modified at second "compositionupdate" event yet`); + }, {once: true}); + input.addEventListener("compositionend", (aEvent) => { + todo_is(input.value, "abc", `${description}input value should be the composition string at "compositionend" event`); + }, {once: true}); + input.addEventListener("input", (aEvent) => { + is(input.value, "abc", `${description}input value should be the composition string at "input" event`); + input.value = "def"; + input.style.width = "1000px"; + is(input.value, "def", `${description}input value should be the specified value at "input" event (after setting the value)`); + }, {once: true}); + synthesizeCompositionChange( + { "composition": + { "string": "abc", + "clauses": + [ + { "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 3, "length": 0 }, + }); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "def", `${description}input value should be set to specified value after the last "input" event`); + input.style.width = ""; + + input.value = ""; + description = 'Setting input value and reframing with flushing layout at "input" event for first composition update: '; + input.addEventListener("compositionupdate", (aEvent) => { + is(input.value, "", `${description}input value should not have been modified at first "compositionupdate" event yet`); + }, {once: true}); + input.addEventListener("compositionend", (aEvent) => { + todo_is(input.value, "abc", `${description}input value should be the composition string at "compositionend" event`); + }, {once: true}); + input.addEventListener("input", (aEvent) => { + is(input.value, "abc", `${description}input value should be the composition string at "input" event`); + input.value = "def"; + input.style.width = "1000px"; + document.documentElement.scrollTop; + is(input.value, "def", `${description}input value should be the specified value at "input" event (after setting the value)`); + }, {once: true}); + synthesizeCompositionChange( + { "composition": + { "string": "abc", + "clauses": + [ + { "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 3, "length": 0 }, + }); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "def", `${description}input value should be set to specified value after the last "input" event`); + input.style.width = ""; + + input.value = ""; + description = 'Setting input value and reframing with flushing layout at "input" event for second composition update: '; + synthesizeCompositionChange( + { "composition": + { "string": "ab", + "clauses": + [ + { "length": 2, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 2, "length": 0 }, + }); + input.addEventListener("compositionupdate", (aEvent) => { + is(input.value, "ab", `${description}input value should not have been modified at second "compositionupdate" event yet`); + }, {once: true}); + input.addEventListener("compositionend", (aEvent) => { + todo_is(input.value, "abc", `${description}input value should be the composition string at "compositionend" event`); + }, {once: true}); + input.addEventListener("input", (aEvent) => { + is(input.value, "abc", `${description}input value should be the composition string at "input" event`); + input.value = "def"; + input.style.width = "1000px"; + document.documentElement.scrollTop; + is(input.value, "def", `${description}input value should be the specified value at "input" event (after setting the value)`); + }, {once: true}); + synthesizeCompositionChange( + { "composition": + { "string": "abc", + "clauses": + [ + { "length": 3, "attr": COMPOSITION_ATTR_RAW_CLAUSE } + ] + }, + "caret": { "start": 3, "length": 0 }, + }); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "def", `${description}input value should be set to specified value after the last "input" event`); + input.style.width = ""; + + // autocomplete and correcting misspelled word by spellchecker cause an "input" event with same path as setting input value. + input.value = ""; + description = 'Setting input value at "input" event whose inputType is "insertReplacementText'; + let inputEventFired = false; + input.addEventListener("input", (aEvent) => { + is(aEvent.inputType, "insertReplacementText", `${description}inputType of "input" event should be "insertReplacementText"`); + inputEventFired = true; + is(input.value, "abc", `${description}input value should be inserted value at "input" event (before setting value)`); + input.value = "def"; + is(input.value, "def", `${description}input value should be specified value at "input" event (after setting value)`); + }, {once: true}); + SpecialPowers.wrap(input).setUserInput("abc"); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "def", `${description}input value should keep the specified value after the last "input" event`); + ok(inputEventFired, `${description}"input" event should've been fired for setUserInput("abc")`); + + input.value = ""; + description = 'Setting input value and reframing at "input" event whose inputType is "insertReplacementText'; + inputEventFired = false; + input.addEventListener("input", (aEvent) => { + is(aEvent.inputType, "insertReplacementText", `${description}inputType of "input" event should be "insertReplacementText"`); + inputEventFired = true; + is(input.value, "abc", `${description}input value should be inserted value at "input" event (before setting value)`); + input.value = "def"; + input.style.width = "1000px"; + is(input.value, "def", `${description}input value should be specified value at "input" event (after setting value)`); + }, {once: true}); + SpecialPowers.wrap(input).setUserInput("abc"); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "def", `${description}input value should keep the specified value after the last "input" event`); + ok(inputEventFired, `${description}"input" event should've been fired for setUserInput("abc")`); + input.style.width = ""; + + input.value = ""; + description = 'Setting input value and reframing with flushing layout at "input" event whose inputType is "insertReplacementText'; + inputEventFired = false; + input.addEventListener("input", (aEvent) => { + is(aEvent.inputType, "insertReplacementText", `${description}inputType of "input" event should be "insertReplacementText"`); + inputEventFired = true; + is(input.value, "abc", `${description}input value should be inserted value at "input" event (before setting value)`); + input.value = "def"; + input.style.width = "1000px"; + document.documentElement.scrollTop; + is(input.value, "def", `${description}input value should be specified value at "input" event (after setting value)`); + }, {once: true}); + SpecialPowers.wrap(input).setUserInput("abc"); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "def", `${description}input value should keep the specified value after the last "input" event`); + ok(inputEventFired, `${description}"input" event should've been fired for setUserInput("abc")`); + input.style.width = ""; + + input.value = ""; + description = 'Setting input value and destroying the frame at "input" event whose inputType is "insertReplacementText'; + inputEventFired = false; + input.addEventListener("input", (aEvent) => { + is(aEvent.inputType, "insertReplacementText", `${description}inputType of "input" event should be "insertReplacementText"`); + inputEventFired = true; + is(input.value, "abc", `${description}input value should be inserted value at "input" event (before setting value)`); + input.value = "def"; + input.style.display = "none"; + is(input.value, "def", `${description}input value should be specified value at "input" event (after setting value)`); + }, {once: true}); + SpecialPowers.wrap(input).setUserInput("abc"); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "def", `${description}input value should keep the specified value after the last "input" event`); + ok(inputEventFired, `${description}"input" event should've been fired for setUserInput("abc")`); + input.style.display = "inline"; + + input.value = ""; + description = 'Changing input type at "input" event whose inputType is "insertReplacementText'; + inputEventFired = false; + input.addEventListener("input", (aEvent) => { + is(aEvent.inputType, "insertReplacementText", `${description}inputType of "input" event should be "insertReplacementText"`); + inputEventFired = true; + is(input.value, "abc", `${description}input value should be inserted value at "input" event (before changing type)`); + input.type = "button"; + is(input.value, "abc", `${description}input value should keep inserted value at "input" event (after changing type)`); + }, {once: true}); + SpecialPowers.wrap(input).setUserInput("abc"); + is(input.value, "abc", `${description}input value should keep inserted value after the last "input" event`); + is(input.type, "button", `${description}input type should be changed correctly`); + ok(inputEventFired, `${description}"input" event should've been fired for setUserInput("abc")`); + input.type = "text"; + is(input.value, "abc", `${description}input value should keep inserted value immediately after restoring the type`); + todo(SpecialPowers.wrap(input).hasEditor, `${description}restoring input type should create editor if it's focused element`); + input.blur(); + input.focus(); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "abc", `${description}input value should keep inserted value after creating editor`); + + input.value = ""; + description = 'Changing input type and flush layout at "input" event whose inputType is "insertReplacementText'; + inputEventFired = false; + input.addEventListener("input", (aEvent) => { + is(aEvent.inputType, "insertReplacementText", `${description}inputType of "input" event should be "insertReplacementText"`); + inputEventFired = true; + is(input.value, "abc", `${description}input value should be inserted value at "input" event (before changing type)`); + input.type = "button"; + input.getBoundingClientRect().height; + is(input.value, "abc", `${description}input value should keep inserted value at "input" event (after changing type)`); + }, {once: true}); + SpecialPowers.wrap(input).setUserInput("abc"); + is(input.value, "abc", `${description}input value should keep inserted value after the last "input" event`); + is(input.type, "button", `${description}input type should be changed correctly`); + ok(inputEventFired, `${description}"input" event should've been fired for setUserInput("abc")`); + input.type = "text"; + is(input.value, "abc", `${description}input value should keep inserted value immediately after restoring the type`); + todo(SpecialPowers.wrap(input).hasEditor, `${description}restoring input type should create editor if it's focused element`); + input.blur(); + input.focus(); + is(SpecialPowers.wrap(input).editor.rootElement.firstChild.wholeText, input.value, + `${description}native anonymous text node should have exactly same value as value of <input> element`); + is(input.value, "abc", `${description}input value should keep inserted value after creating editor`); + + function testSettingValueFromBeforeInput(aWithEditor, aPreventDefaultOfBeforeInput) { + let beforeInputEvents = []; + let inputEvents = []; + function recordEvent(aEvent) { + if (aEvent.type === "beforeinput") { + beforeInputEvents.push(aEvent); + } else { + inputEvents.push(aEvent); + } + } + let condition = `(${aWithEditor ? "with editor" : "without editor"}${aPreventDefaultOfBeforeInput ? ' and canceling "beforeinput" event' : ""}, the pref ${kSetUserInputCancelable ? "allows" : "disallows"} to cancel "beforeinput" event})`; + function Reset() { + beforeInputEvents = []; + inputEvents = []; + if (SpecialPowers.wrap(input).hasEditor != aWithEditor) { + if (aWithEditor) { + input.blur(); + input.focus(); // Associate `TextEditor` with input + if (!SpecialPowers.wrap(input).hasEditor) { + ok(false, `${description}Failed to associate TextEditor with the input ${condition}`); + return false; + } + } else { + input.blur(); + input.type = "button"; + input.type = "text"; + if (SpecialPowers.wrap(input).hasEditor) { + ok(false, `${description}Failed to disassociate TextEditor from the input ${condition}`); + return false; + } + } + } + return true; + } + + description = `Setting value from "beforeinput" event listener whose inputType is "insertReplacementText" ${condition}: `; + input.value = "abc"; + if (!Reset()) { + return; + } + input.addEventListener("beforeinput", (aEvent) => { + is(aEvent.inputType, "insertReplacementText", `${description}inputType of "beforeinput" event should be "insertReplacementText"`); + is(aEvent.cancelable, kSetUserInputCancelable, `${description}"beforeinput" event should be cancelable unless it's suppressed by the pref`); + is(input.value, "abc", `${description}The value shouldn't have been modified yet at "beforeinput" event listener`); + input.addEventListener("beforeinput", recordEvent); + input.addEventListener("input", recordEvent); + input.value = "hig"; + if (aPreventDefaultOfBeforeInput) { + aEvent.preventDefault(); + } + }, {once: true}); + SpecialPowers.wrap(input).setUserInput("def"); + is(beforeInputEvents.length, 0, `${description}"beforeinput" event shouldn't be fired again`); + if (aPreventDefaultOfBeforeInput && kSetUserInputCancelable) { + is(input.value, "hig", + `${description}The value should be set to the specified value in "beforeinput" event listener since "beforeinput" was canceled`); + is(inputEvents.length, 0, + `${description}"input" event shouldn't be fired since "beforeinput" was canceled`); + } else { + // XXX This result is different from Chrome (verified with spellchecker). + // Chrome inserts the new text to current value and selected range. + // It might be reasonable, but we don't touch this for now since it + // requires a lot of changes. + is(input.value, "hig", + `${description}The value should be set to the specified value in "beforeinput" event listener since the event target was already modified`); + is(inputEvents.length, 1, `${description}"input" event should be fired`); + if (inputEvents.length) { + is(inputEvents[0].inputType, + "insertReplacementText", `${description}inputType of "input" event should be "insertReplacementText"`); + is(inputEvents[0].data, "def", + `${description}data of "input" event should be the value specified by setUserInput()`); + } + } + input.removeEventListener("beforeinput", recordEvent); + input.removeEventListener("input", recordEvent); + + description = `Setting value from "beforeinput" event listener whose inputType is "insertReplacementText" and changing the type to "button" ${condition}: `; + input.value = "abc"; + if (!Reset()) { + return; + } + input.addEventListener("beforeinput", (aEvent) => { + is(aEvent.inputType, "insertReplacementText", `${description}inputType of "beforeinput" event should be "insertReplacementText"`); + is(aEvent.cancelable, kSetUserInputCancelable, `${description}"beforeinput" event should be cancelable unless it's suppressed by the pref`); + is(input.value, "abc", `${description}The value shouldn't have been modified yet at "beforeinput" event listener`); + input.addEventListener("beforeinput", recordEvent); + input.addEventListener("input", recordEvent); + input.value = "hig"; + input.type = "button"; + if (aPreventDefaultOfBeforeInput) { + aEvent.preventDefault(); + } + }, {once: true}); + SpecialPowers.wrap(input).setUserInput("def"); + is(beforeInputEvents.length, 0, `${description}"beforeinput" event shouldn't be fired again`); + if (aPreventDefaultOfBeforeInput && kSetUserInputCancelable) { + is(input.value, "hig", + `${description}The value should be set to the specified value in "beforeinput" event listener since "beforeinput" was canceled`); + is(inputEvents.length, 0, + `${description}"input" event shouldn't be fired since "beforeinput" was canceled`); + } else { + // XXX This result is same as Chrome (verified with spellchecker). + // But this behavior is not consistent with just setting the value on Chrome. + is(input.value, "hig", + `${description}The value should be set to the specified value in "beforeinput" event listener since the event target was already modified`); + // Same as Chrome + is(inputEvents.length, 0, + `${description}"input" event shouldn't be fired since the input element's type is changed`); + } + input.type = "text"; + input.removeEventListener("beforeinput", recordEvent); + input.removeEventListener("input", recordEvent); + + description = `Setting value from "beforeinput" event listener whose inputType is "insertReplacementText" and destroying the frame ${condition}: `; + input.value = "abc"; + if (!Reset()) { + return; + } + input.addEventListener("beforeinput", (aEvent) => { + is(aEvent.inputType, "insertReplacementText", `${description}inputType of "beforeinput" event should be "insertReplacementText"`); + is(aEvent.cancelable, kSetUserInputCancelable, `${description}"beforeinput" event should be cancelable unless it's suppressed by the pref`); + is(input.value, "abc", `${description}The value shouldn't have been modified yet at "beforeinput" event listener`); + input.addEventListener("beforeinput", recordEvent); + input.addEventListener("input", recordEvent); + input.value = "hig"; + input.style.display = "none"; + if (aPreventDefaultOfBeforeInput) { + aEvent.preventDefault(); + } + }, {once: true}); + SpecialPowers.wrap(input).setUserInput("def"); + is(beforeInputEvents.length, 0, `${description}"beforeinput" event shouldn't be fired again`); + if (aPreventDefaultOfBeforeInput && kSetUserInputCancelable) { + is(input.value, "hig", + `${description}The value should be set to the specified value in "beforeinput" event listener since "beforeinput" was canceled`); + is(inputEvents.length, 0, + `${description}"input" event shouldn't be fired since "beforeinput" was canceled`); + } else { + // XXX This result is same as Chrome (verified with spellchecker). + // But this behavior is not consistent with just setting the value on Chrome. + is(input.value, "hig", + `${description}The value should be set to the specified value in "beforeinput" event listener since the event target was already modified`); + // Different from Chrome + is(inputEvents.length, 1, + `${description}"input" event should be fired even if the frame of target is destroyed`); + if (inputEvents.length) { + is(inputEvents[0].inputType, + "insertReplacementText", `${description}inputType of "input" event should be "insertReplacementText"`); + is(inputEvents[0].data, "def", + `${description}data of "input" event should be the value specified by setUserInput()`); + } + } + input.style.display = "inline"; + input.removeEventListener("beforeinput", recordEvent); + input.removeEventListener("input", recordEvent); + + if (aWithEditor) { + return; + } + + description = `Setting value from "beforeinput" event listener whose inputType is "insertReplacementText and create editor" ${condition}: `; + input.value = "abc"; + if (!Reset()) { + return; + } + input.addEventListener("beforeinput", (aEvent) => { + is(aEvent.inputType, "insertReplacementText", `${description}inputType of "beforeinput" event should be "insertReplacementText"`); + is(aEvent.cancelable, kSetUserInputCancelable, `${description}"beforeinput" event should be cancelable unless it's suppressed by the pref`); + is(input.value, "abc", `${description}The value shouldn't have been modified yet at "beforeinput" event listener`); + input.addEventListener("beforeinput", recordEvent); + input.addEventListener("input", recordEvent); + input.value = "hig"; + input.focus(); + if (aPreventDefaultOfBeforeInput) { + aEvent.preventDefault(); + } + }, {once: true}); + SpecialPowers.wrap(input).setUserInput("def"); + is(beforeInputEvents.length, 0, `${description}"beforeinput" event shouldn't be fired again`); + if (aPreventDefaultOfBeforeInput && kSetUserInputCancelable) { + is(input.value, "hig", + `${description}The value should be set to the specified value in "beforeinput" event listener since "beforeinput" was canceled`); + is(inputEvents.length, 0, + `${description}"input" event shouldn't be fired since "beforeinput" was canceled`); + } else { + // XXX This result is different from Chrome (verified with spellchecker). + // Chrome inserts the new text to current value and selected range. + // It might be reasonable, but we don't touch this for now since it + // requires a lot of changes. + is(input.value, "hig", + `${description}The value should be set to the specified value in "beforeinput" event listener since the event target was already modified`); + is(inputEvents.length, 1, `${description}"input" event should be fired`); + if (inputEvents.length) { + is(inputEvents[0].inputType, + "insertReplacementText", `${description}inputType of "input" event should be "insertReplacementText"`); + is(inputEvents[0].data, "def", + `${description}data of "input" event should be the value specified by setUserInput()`); + } + } + input.removeEventListener("beforeinput", recordEvent); + input.removeEventListener("input", recordEvent); + } + // testSettingValueFromBeforeInput(true, true); + // testSettingValueFromBeforeInput(true, false); + testSettingValueFromBeforeInput(false, true); + testSettingValueFromBeforeInput(false, false); + + SimpleTest.finish(); +}); +</script> +</body> +</html> diff --git a/dom/html/test/forms/test_input_textarea_set_value_no_scroll.html b/dom/html/test/forms/test_input_textarea_set_value_no_scroll.html new file mode 100644 index 0000000000..79a0f3d15a --- /dev/null +++ b/dom/html/test/forms/test_input_textarea_set_value_no_scroll.html @@ -0,0 +1,125 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=829606 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 829606</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="/tests/SimpleTest/WindowSnapshot.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 829606 **/ + /* + * This test checks that setting .value on an text field (input or textarea) + * doesn't scroll the field to its beginning. + */ + + SimpleTest.waitForExplicitFinish(); + + var gTestRunner = null; + + async function test(aElementName) + { + var element = document.getElementsByTagName(aElementName)[0]; + element.focus(); + + var baseSnapshot = await snapshotWindow(window); + + // This is a sanity check. + var s2 = await snapshotWindow(window); + var results = compareSnapshots(baseSnapshot, await snapshotWindow(window), true); + ok(results[0], "sanity check: screenshots should be the same"); + + element.selectionStart = element.selectionEnd = element.value.length; + + setTimeout(function() { + sendString('f'); + + requestAnimationFrame(async function() { + var selectionAtTheEndSnapshot = await snapshotWindow(window); + results = compareSnapshots(baseSnapshot, selectionAtTheEndSnapshot, false); + ok(results[0], "after appending a character, string should have changed"); + + // Re-setting value shouldn't change anything. + // eslint-disable-next-line no-self-assign + element.value = element.value; + var tmpSnapshot = await snapshotWindow(window); + + results = compareSnapshots(baseSnapshot, tmpSnapshot, false); + ok(results[0], "re-setting the value should change nothing"); + + results = compareSnapshots(selectionAtTheEndSnapshot, tmpSnapshot, true); + ok(results[0], "re-setting the value should change nothing"); + + element.selectionStart = element.selectionEnd = 0; + element.blur(); + + gTestRunner.next(); + }); + }, 0); + } + + // This test checks that when a textarea has a long list of values and the + // textarea's value is then changed, the values are shown correctly. + async function testCorrectUpdateOnScroll() + { + var textarea = document.createElement('textarea'); + textarea.rows = 5; + textarea.cols = 10; + textarea.value = 'a\nb\nc\nd'; + document.getElementById('content').appendChild(textarea); + + var baseSnapshot = await snapshotWindow(window); + + textarea.value = '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n'; + textarea.selectionStart = textarea.selectionEnd = textarea.value.length; + + var fullSnapshot = await snapshotWindow(window); + var results = compareSnapshots(baseSnapshot, fullSnapshot, false); + ok(results[0], "sanity check: screenshots should not be the same"); + + textarea.value = 'a\nb\nc\nd'; + + var tmpSnapshot = await snapshotWindow(window); + results = compareSnapshots(baseSnapshot, tmpSnapshot, true); + ok(results[0], "textarea view should look like the beginning"); + + setTimeout(function() { + gTestRunner.next(); + }, 0); + } + + function* runTest() + { + test('input'); + yield undefined; + test('textarea'); + yield undefined; + testCorrectUpdateOnScroll(); + yield undefined; + SimpleTest.finish(); + } + + gTestRunner = runTest(); + + SimpleTest.waitForFocus(function() { + gTestRunner.next(); + });; + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=829606">Mozilla Bug 829606</a> +<p id="display"></p> +<div id="content"> + <textarea rows='1' cols='5' style='-moz-appearance:none;'>this is a \n long text</textarea> + <input size='5' value="this is a very long text" style='-moz-appearance:none;'> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_time_key_events.html b/dom/html/test/forms/test_input_time_key_events.html new file mode 100644 index 0000000000..c738816653 --- /dev/null +++ b/dom/html/test/forms/test_input_time_key_events.html @@ -0,0 +1,221 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1288591 +--> +<head> + <title>Test key events for time control</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1288591">Mozilla Bug 1288591</a> +<p id="display"></p> +<div id="content"> + <input id="input" type="time"> +</div> +<pre id="test"> +<script type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +var testData = [ + /** + * keys: keys to send to the input element. + * initialVal: initial value set to the input element. + * expectedVal: expected value of the input element after sending the keys. + */ + { + // Type 16 in the hour field will automatically change time to 4PM in 12-hour clock + keys: ["16"], + initialVal: "01:00", + expectedVal: "16:00" + }, + { + // Type 00 in hour field will automatically convert to 12AM in 12-hour clock + keys: ["00"], + initialVal: "03:00", + expectedVal: "00:00" + }, + { + // Type hour > 23 such as 24 will automatically convert to 2 + keys: ["24"], + initialVal: "04:00", + expectedVal: "02:00" + }, + { + // Type 1030 and select AM. + keys: ["1030"], + initialVal: "", + expectedVal: "10:30" + }, + { + // Type 3 in the hour field will automatically advance to the minute field. + keys: ["330"], + initialVal: "", + expectedVal: "03:30" + }, + { + // Type 5 in the hour field will automatically advance to the minute field. + // Type 7 in the minute field will automatically advance to the AM/PM field. + keys: ["57"], + initialVal: "", + expectedVal: "05:07" + }, + { + // Advance to AM/PM field and change to PM. + keys: ["KEY_Tab", "KEY_Tab", "KEY_ArrowDown"], + initialVal: "10:30", + expectedVal: "22:30" + }, + { + // Right key should do the same thing as TAB key. + keys: ["KEY_ArrowRight", "KEY_ArrowRight", "KEY_ArrowDown"], + initialVal: "10:30", + expectedVal: "22:30" + }, + { + // Advance to minute field then back to hour field and decrement. + keys: ["KEY_ArrowRight", "KEY_ArrowLeft", "KEY_ArrowDown"], + initialVal: "10:30", + expectedVal: "09:30" + }, + { + // Focus starts on the first field, hour in this case, and increment. + keys: ["KEY_ArrowUp"], + initialVal: "16:00", + expectedVal: "17:00" + }, + { + // Advance to minute field and decrement. + keys: ["KEY_Tab", "KEY_ArrowDown"], + initialVal: "16:00", + expectedVal: "16:59" + }, + { + // Advance to minute field and increment. + keys: ["KEY_Tab", "KEY_ArrowUp"], + initialVal: "16:59", + expectedVal: "16:00" + }, + { + // PageUp on hour field increments hour by 3. + keys: ["KEY_PageUp"], + initialVal: "05:00", + expectedVal: "08:00" + }, + { + // PageDown on hour field decrements hour by 3. + keys: ["KEY_PageDown"], + initialVal: "05:00", + expectedVal: "02:00" + }, + { + // PageUp on minute field increments minute by 10. + keys: ["KEY_Tab", "KEY_PageUp"], + initialVal: "14:00", + expectedVal: "14:10" + }, + { + // PageDown on minute field decrements minute by 10. + keys: ["KEY_Tab", "KEY_PageDown"], + initialVal: "14:00", + expectedVal: "14:50" + }, + { + // Home key on hour field sets it to the minimum hour, which is 1 in 12-hour + // clock. + keys: ["KEY_Home"], + initialVal: "03:10", + expectedVal: "01:10" + }, + { + // End key on hour field sets it to the maximum hour, which is 12PM in 12-hour + // clock. + keys: ["KEY_End"], + initialVal: "03:10", + expectedVal: "12:10" + }, + { + // Home key on minute field sets it to the minimum minute, which is 0. + keys: ["KEY_Tab", "KEY_Home"], + initialVal: "19:30", + expectedVal: "19:00" + }, + { + // End key on minute field sets it to the minimum minute, which is 59. + keys: ["KEY_Tab", "KEY_End"], + initialVal: "19:30", + expectedVal: "19:59" + }, + // Second field will show up when needed. + { + // PageUp on second field increments second by 10. + keys: ["KEY_Tab", "KEY_Tab", "KEY_PageUp"], + initialVal: "08:10:10", + expectedVal: "08:10:20" + }, + { + // PageDown on second field increments second by 10. + keys: ["KEY_Tab", "KEY_Tab", "KEY_PageDown"], + initialVal: "08:10:10", + expectedVal: "08:10:00" + }, + { + // Home key on second field sets it to the minimum second, which is 0. + keys: ["KEY_Tab", "KEY_Tab", "KEY_Home"], + initialVal: "16:00:30", + expectedVal: "16:00:00" + }, + { + // End key on second field sets it to the minimum second, which is 59. + keys: ["KEY_Tab", "KEY_Tab", "KEY_End"], + initialVal: "16:00:30", + expectedVal: "16:00:59" + }, + { + // Incomplete value maps to empty .value. + keys: ["1"], + initialVal: "", + expectedVal: "" + }, +]; + +function sendKeys(aKeys, aElem) { + for (let i = 0; i < aKeys.length; i++) { + // Force layout flush between keys to ensure focus is correct. + // This shouldn't be necessary; bug 1450219 tracks this. + aElem.clientTop; + let key = aKeys[i]; + if (key.startsWith("KEY_")) { + synthesizeKey(key); + } else { + sendString(key); + } + } +} + +function test() { + var elem = document.getElementById("input"); + + for (let { keys, initialVal, expectedVal } of testData) { + elem.focus(); + elem.value = initialVal; + sendKeys(keys, elem); + is(elem.value, expectedVal, + "Test with " + keys + ", result should be " + expectedVal); + elem.value = ""; + elem.blur(); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_time_sec_millisec_field.html b/dom/html/test/forms/test_input_time_sec_millisec_field.html new file mode 100644 index 0000000000..71db4942a9 --- /dev/null +++ b/dom/html/test/forms/test_input_time_sec_millisec_field.html @@ -0,0 +1,134 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1374967 +--> +<head> + <title>Test second and millisecond fields in input type=time</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <meta charset="UTF-8"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1374967">Mozilla Bug 1374967</a> +<p id="display"></p> +<div id="content"> + <input id="input1" type="time"> + <input id="input2" type="time" value="12:30:40"> + <input id="input3" type="time" value="12:30:40.567"> + <input id="input4" type="time" step="1"> + <input id="input5" type="time" step="61"> + <input id="input6" type="time" step="120"> + <input id="input7" type="time" step="0.01"> + <input id="input8" type="time" step="0.001"> + <input id="input9" type="time" step="1.001"> + <input id="input10" type="time" min="01:30:05"> + <input id="input11" type="time" min="01:30:05.100"> + <input id="dummy"> +</div> +<pre id="test"> +<script type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + test(); + SimpleTest.finish(); +}); + +const NUM_OF_FIELDS_DEFAULT = 3; +const NUM_OF_FIELDS_WITH_SECOND = NUM_OF_FIELDS_DEFAULT + 1; +const NUM_OF_FIELDS_WITH_MILLISEC = NUM_OF_FIELDS_WITH_SECOND + 1; + +function countNumberOfFields(aElement) { + is(aElement.type, "time", "Input element type should be 'time'"); + + let inputRect = aElement.getBoundingClientRect(); + let firstField_X = 15; + let firstField_Y = inputRect.height / 2; + + // Make sure to start on the first field. + synthesizeMouse(aElement, firstField_X, firstField_Y, {}); + is(document.activeElement, aElement, "Input element should be focused"); + + let n = 0; + while (document.activeElement == aElement) { + n++; + synthesizeKey("KEY_Tab"); + } + + return n; +} + +function test() { + // Normal input time element. + let elem = document.getElementById("input1"); + is(countNumberOfFields(elem), NUM_OF_FIELDS_DEFAULT, "Default input time"); + + // Dynamically changing the value with second part. + elem.value = "10:20:30"; + is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND, + "Input time after changing value with second part"); + + // Dynamically changing the step to 1 millisecond. + elem.step = "0.001"; + is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC, + "Input time after changing step to 1 millisecond"); + + // Input time with value with second part. + elem = document.getElementById("input2"); + is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND, + "Input time with value with second part"); + + // Input time with value with second and millisecond part. + elem = document.getElementById("input3"); + is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC, + "Input time with value with second and millisecond part"); + + // Input time with step set as 1 second. + elem = document.getElementById("input4"); + is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND, + "Input time with step set as 1 second"); + + // Input time with step set as 61 seconds. + elem = document.getElementById("input5"); + is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND, + "Input time with step set as 61 seconds"); + + // Input time with step set as 2 minutes. + elem = document.getElementById("input6"); + is(countNumberOfFields(elem), NUM_OF_FIELDS_DEFAULT, + "Input time with step set as 2 minutes"); + + // Input time with step set as 10 milliseconds. + elem = document.getElementById("input7"); + is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC, + "Input time with step set as 10 milliseconds"); + + // Input time with step set as 100 milliseconds. + elem = document.getElementById("input8"); + is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC, + "Input time with step set as 100 milliseconds"); + + // Input time with step set as 1001 milliseconds. + elem = document.getElementById("input9"); + is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC, + "Input time with step set as 1001 milliseconds"); + + // Input time with min with second part and default step (60 seconds). Note + // that step base is min, when there is a min. + elem = document.getElementById("input10"); + is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_SECOND, + "Input time with min with second part"); + + // Input time with min with second and millisecond part and default step (60 + // seconds). Note that step base is min, when there is a min. + elem = document.getElementById("input11"); + is(countNumberOfFields(elem), NUM_OF_FIELDS_WITH_MILLISEC, + "Input time with min with second and millisecond part"); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_types_pref.html b/dom/html/test/forms/test_input_types_pref.html new file mode 100644 index 0000000000..1222e88a86 --- /dev/null +++ b/dom/html/test/forms/test_input_types_pref.html @@ -0,0 +1,77 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=764481 +--> +<head> + <title>Test for Bug 764481</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=764481">Mozilla Bug 764481</a> +<p id="display"></p> +<div id="content" style="display: none" > +</div> +<pre id="test"> +<script type="application/javascript"> + + var input = document.createElement("input"); + + var testData = [ + { + prefs: [["dom.forms.datetime.others", false]], + inputType: "month", + expectedType: "text" + }, { + prefs: [["dom.forms.datetime.others", false]], + inputType: "month", + expectedType: "text" + }, { + prefs: [["dom.forms.datetime.others", true]], + inputType: "month", + expectedType: "month" + }, { + prefs: [["dom.forms.datetime.others", false]], + inputType: "week", + expectedType: "text" + }, { + prefs: [["dom.forms.datetime.others", false]], + inputType: "week", + expectedType: "text" + }, { + prefs: [["dom.forms.datetime.others", true]], + inputType: "week", + expectedType: "week" + } + ]; + + function testInputTypePreference(aData) { + return SpecialPowers.pushPrefEnv({'set': aData.prefs}) + .then(() => { + // Change the type of input to text and then back to the tested input type, + // so that HTMLInputElement::ParseAttribute gets called with the pref enabled. + input.type = "text"; + input.type = aData.inputType; + is(input.type, aData.expectedType, "input type should be '" + + aData.expectedType + "'' when pref " + aData.prefs + " is set"); + is(input.getAttribute('type'), aData.inputType, + "input 'type' attribute should not change"); + }); + } + + SimpleTest.waitForExplicitFinish(); + + let promise = Promise.resolve(); + for (let i = 0; i < testData.length; i++) { + let data = testData[i]; + promise = promise.then(() => testInputTypePreference(data)); + } + + promise.catch(error => ok(false, "Promise reject: " + error)) + .then(() => SimpleTest.finish()); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_typing_sanitization.html b/dom/html/test/forms/test_input_typing_sanitization.html new file mode 100644 index 0000000000..fef0ebed06 --- /dev/null +++ b/dom/html/test/forms/test_input_typing_sanitization.html @@ -0,0 +1,217 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=765772 +--> +<head> + <title>Test for Bug 765772</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=">Mozilla Bug 765772</a> +<p id="display"></p> +<iframe name="submit_frame" style="visibility: hidden;"></iframe> +<div id="content"> + <form id='f' target="submit_frame" action="foo"> + <input name=i id="i" step='any' > + </form> +</div> +<pre id="test"> +<script> + +/* + * This test checks that when a user types in some input types, it will not be + * in a state where the value will be un-sanitized and usable (by a script). + */ + +var input = document.getElementById('i'); +var form = document.getElementById('f'); +var submitFrame = document.getElementsByTagName('iframe')[0]; +var testData = []; +var gCurrentTest = null; +var gValidData = []; +var gInvalidData = []; + +function submitForm() { + form.submit(); +} + +function sendKeyEventToSubmitForm() { + sendKey("return"); +} + +function urlify(aStr) { + return aStr.replace(/:/g, '%3A'); +} + +function runTestsForNextInputType() +{ + let {done} = testRunner.next(); + if (done) { + SimpleTest.finish(); + } +} + +function checkValueSubmittedIsValid() +{ + is(frames.submit_frame.location.href, + `${location.origin}/tests/dom/html/test/forms/foo?i=${urlify(gValidData[valueIndex++])}`, + "The submitted value should not have been sanitized"); + + input.value = ""; + + if (valueIndex >= gValidData.length) { + if (gCurrentTest.canHaveBadInputValidityState) { + // Don't run the submission tests on the invalid input if submission + // will be blocked by invalid input. + runTestsForNextInputType(); + return; + } + valueIndex = 0; + submitFrame.onload = checkValueSubmittedIsInvalid; + testData = gInvalidData; + } + testSubmissions(); +} + +function checkValueSubmittedIsInvalid() +{ + is(frames.submit_frame.location.href, + `${location.origin}/tests/dom/html/test/forms/foo?i=`, + "The submitted value should have been sanitized"); + + valueIndex++; + input.value = ""; + + if (valueIndex >= gInvalidData.length) { + if (submitMethod == sendKeyEventToSubmitForm) { + runTestsForNextInputType(); + return; + } + valueIndex = 0; + submitMethod = sendKeyEventToSubmitForm; + submitFrame.onload = checkValueSubmittedIsValid; + testData = gValidData; + } + testSubmissions(); +} + +function testSubmissions() { + input.focus(); + sendString(testData[valueIndex]); + submitMethod(); +} + +var valueIndex = 0; +var submitMethod = submitForm; + +SimpleTest.waitForExplicitFinish(); + +function* runTest() +{ + SimpleTest.requestLongerTimeout(4); + + var data = [ + { + type: 'number', + canHaveBadInputValidityState: true, + validData: [ + "42", + "-42", // should work for negative values + "42.1234", + "123.123456789123", // double precision + "1e2", // e should be usable + "2e1", + "1e-1", // value after e can be negative + "1E2", // E can be used instead of e + ], + invalidData: [ + "e", + "e2", + "1e0.1", + "foo", + "42,13", // comma can't be used as a decimal separator + ] + }, + { + type: 'month', + validData: [ + '0001-01', + '2012-12', + '100000-01', + ], + invalidData: [ + '1-01', + '-', + 'december', + '2012-dec', + '2012/12', + '2012-99', + '2012-1', + ] + }, + { + type: 'week', + validData: [ + '0001-W01', + '1970-W53', + '100000-W52', + '2016-W30', + ], + invalidData: [ + '1-W01', + 'week', + '2016-30', + '2010-W80', + '2000/W30', + '1985-W00', + '1000-W' + ] + }, + ]; + + for (test of data) { + gCurrentTest = test; + + input.type = test.type; + gValidData = test.validData; + gInvalidData = test.invalidData; + + for (data of gValidData) { + input.value = ""; + input.focus(); + sendString(data); + input.blur(); + is(input.value, data, "valid user input should not be sanitized"); + } + + for (data of gInvalidData) { + input.value = ""; + input.focus(); + sendString(data); + input.blur(); + is(input.value, "", "invalid user input should be sanitized"); + } + + input.value = ''; + + testData = gValidData; + valueIndex = 0; + submitFrame.onload = checkValueSubmittedIsValid; + testSubmissions(); + yield undefined; + } +} + +var testRunner = runTest(); + +addLoadEvent(function () { + testRunner.next(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_untrusted_key_events.html b/dom/html/test/forms/test_input_untrusted_key_events.html new file mode 100644 index 0000000000..78e35f525f --- /dev/null +++ b/dom/html/test/forms/test_input_untrusted_key_events.html @@ -0,0 +1,90 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for untrusted DOM KeyboardEvent on input element</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content"> + <input id="input"> +</div> +<pre id="test"> +<script type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(runNextTest, window); + +const kTests = [ + { type: "text", value: "foo", key: "b", expectedNewValue: "foo" }, + { type: "number", value: "123", key: "4", expectedNewValue: "123" }, + { type: "number", value: "123", key: KeyEvent.DOM_VK_UP, expectedNewValue: "123" }, + { type: "number", value: "123", key: KeyEvent.DOM_VK_DOWN, expectedNewValue: "123" }, +]; + +function sendUntrustedKeyEvent(eventType, keyCode, target) { + var evt = new KeyboardEvent(eventType, { + bubbles: true, + cancelable: true, + view: document.defaultView, + keyCode, + charCode: 0, + }); + target.dispatchEvent(evt); +} + +var input = document.getElementById("input"); + +var gotEvents = {}; + +function handleEvent(event) { + gotEvents[event.type] = true; +} + +input.addEventListener("keydown", handleEvent); +input.addEventListener("keyup", handleEvent); +input.addEventListener("keypress", handleEvent); + +var previousTest = null; + +function runNextTest() { + if (previousTest) { + var msg = "For <input " + "type=" + previousTest.type + ">, "; + is(gotEvents.keydown, true, msg + "checking got keydown"); + is(gotEvents.keyup, true, msg + "checking got keyup"); + is(gotEvents.keypress, true, msg + "checking got keypress"); + is(input.value, previousTest.expectedNewValue, msg + "checking element " + + " after being sent '" + previousTest.key + "' key events"); + } + + // reset flags + gotEvents.keydown = false; + gotEvents.keyup = false; + gotEvents.keypress = false; + + + var test = kTests.shift(); + if (!test) { + SimpleTest.finish(); + return; // We're all done + } + + input.type = test.type; + input.focus(); // make sure we still have focus after type change + input.value = test.value; + + sendUntrustedKeyEvent("keydown", test.key, input); + sendUntrustedKeyEvent("keyup", test.key, input); + sendUntrustedKeyEvent("keypress", test.key, input); + + previousTest = test; + + SimpleTest.executeSoon(runNextTest); +}; + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_input_url.html b/dom/html/test/forms/test_input_url.html new file mode 100644 index 0000000000..3cdf1070bb --- /dev/null +++ b/dom/html/test/forms/test_input_url.html @@ -0,0 +1,91 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Tests for <input type='url'> validity</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> + <input type='url' id='i' oninvalid='invalidEventHandler(event);'> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Tests for <input type='url'> validity **/ + +// More checks are done in test_bug551670.html. + +var gInvalid = false; + +function invalidEventHandler(e) +{ + is(e.type, "invalid", "Invalid event type should be invalid"); + gInvalid = true; +} + +function checkValidURL(element) +{ + info(`Checking ${element.value}\n`); + gInvalid = false; + ok(!element.validity.typeMismatch, + "Element should not suffer from type mismatch"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "Element should be valid"); + ok(!gInvalid, "The invalid event should not have been thrown"); + is(element.validationMessage, '', + "Validation message should be the empty string"); + ok(element.matches(":valid"), ":valid pseudo-class should apply"); +} + +function checkInvalidURL(element) +{ + gInvalid = false; + ok(element.validity.typeMismatch, + "Element should suffer from type mismatch"); + ok(!element.validity.valid, "Element should not be valid"); + ok(!element.checkValidity(), "Element should not be valid"); + ok(gInvalid, "The invalid event should have been thrown"); + is(element.validationMessage, "Please enter a URL.", + "Validation message should be related to invalid URL"); + ok(element.matches(":invalid"), + ":invalid pseudo-class should apply"); +} + +var url = document.getElementById('i'); + +var values = [ + // [ value, validity ] + // The empty string should be considered as valid. + [ "", true ], + [ "foo", false ], + [ "http://mozilla.com/", true ], + [ "http://mozilla.com", true ], + [ "http://mozil\nla\r.com/", true ], + [ " http://mozilla.com/ ", true ], + [ "\r http://mozilla.com/ \n", true ], + [ "file:///usr/bin/tulip", true ], + [ "../../bar.html", false ], + [ "http://mozillá.org", true ], + [ "https://mózillä.org", true ], + [ "http://mózillä.órg", true ], + [ "ht://mózillä.órg", true ], + [ "httŭ://mózillä.órg", false ], + [ "chrome://bookmarks", true ], +]; + +values.forEach(function([value, valid]) { + url.value = value; + + if (valid) { + checkValidURL(url); + } else { + checkInvalidURL(url); + } +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_interactive_content_in_label.html b/dom/html/test/forms/test_interactive_content_in_label.html new file mode 100644 index 0000000000..b8d9c81d51 --- /dev/null +++ b/dom/html/test/forms/test_interactive_content_in_label.html @@ -0,0 +1,101 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=229925 +--> +<head> + <title>Test for Bug 229925</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=229925">Mozilla Bug 229925</a> +<p id="display"></p> +<form action="#"> + <label> + <span id="text">label</span> + <input type="button" id="target" value="target"> + + <a class="yes" href="#">a</a> + <audio class="yes" controls></audio> + <button class="yes">button</button> + <details class="yes">details</details> + <embed class="yes">embed</embed> + <iframe class="yes" src="data:text/plain," style="width: 16px; height: 16px;"></iframe> + <img class="yes" src="data:image/png," usemap="#map"> + <input class="yes" type="text" size="4"> + <keygen class="no"> + <label class="yes">label</label> + <object class="yes" usemap="#map">object</object> + <select class="yes"><option>select</option></select> + <textarea class="yes" cols="1" rows="1"></textarea> + <video class="yes" controls></video> + + <!-- Tests related to shadow tree. --> + <div id="root1"> <!-- content will be added by script below. --> </div> + <button><div id="root2"> <!-- content will be added by script below. --> </div></button> + + <a class="no">a</a> + <audio class="no"></audio> + <img class="no" src="data:image/png,"> + <input class="no" type="hidden"> + <object class="no">object</object> + <video class="no"></video> + + <span class="no" tabindex="1">tabindex</span> + <audio class="no" tabindex="1"></audio> + <img class="no" src="data:image/png," tabindex="1"> + <input class="no" type="hidden" tabindex="1"> + <object class="no" tabindex="1">object</object> + <video class="no" tabindex="1"></video> + </label> +</form> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 229925 **/ + +var target = document.getElementById("target"); + +var yes_nodes = Array.from(document.getElementsByClassName("yes")); + +var root1 = document.getElementById("root1"); +root1.attachShadow({ mode: "open" }).innerHTML = "<button class=yes>button in shadow tree</button>"; +var root2 = document.getElementById("root2"); +root2.attachShadow({ mode: "open" }).innerHTML = "<div class=yes>text in shadow tree</div>"; +var yes_nodes_in_shadow_tree = + Array.from(root1.shadowRoot.querySelectorAll(".yes")).concat( + Array.from(root2.shadowRoot.querySelectorAll(".yes"))); + +var no_nodes = Array.from(document.getElementsByClassName("no")); + +var target_clicked = false; +target.addEventListener("click", function() { + target_clicked = true; +}); + +var node; +for (node of yes_nodes) { + target_clicked = false; + node.click(); + is(target_clicked, false, "mouse click on interactive content " + node.nodeName + " shouldn't dispatch event to label target"); +} + +for (node of yes_nodes_in_shadow_tree) { + target_clicked = false; + node.click(); + is(target_clicked, false, "mouse click on content in shadow tree " + node.nodeName + " shouldn't dispatch event to label target"); +} + +for (node of no_nodes) { + target_clicked = false; + node.click(); + is(target_clicked, true, "mouse click on non interactive content " + node.nodeName + " should dispatch event to label target"); +} + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/forms/test_interactive_content_in_summary.html b/dom/html/test/forms/test_interactive_content_in_summary.html new file mode 100644 index 0000000000..f8bac77d89 --- /dev/null +++ b/dom/html/test/forms/test_interactive_content_in_summary.html @@ -0,0 +1,97 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1524893 +--> +<head> + <title>Test for Bug 1524893</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1524893">Mozilla Bug 1524893</a> + +<details id="details"> + <summary> + <a class="yes" href="#">a</a> + <audio class="yes" controls></audio> + <button class="yes">button</button> + <details class="yes">details</details> + <embed class="yes">embed</embed> + <iframe class="yes" src="data:text/plain," style="width: 16px; height: 16px;"></iframe> + <img class="yes" src="data:image/png," usemap="#map"> + <input class="yes" type="text" size="4"> + <keygen class="no"> + <label class="yes">label</label> + <object class="yes" usemap="#map">object</object> + <select class="yes"><option>select</option></select> + <textarea class="yes" cols="1" rows="1"></textarea> + <video class="yes" controls></video> + + <!-- Tests related to shadow tree. --> + <div id="root1"> <!-- content will be added by script below. --> </div> + <button><div id="root2"> <!-- content will be added by script below. --> </div></button> + + <a class="no">a</a> + <audio class="no"></audio> + <img class="no" src="data:image/png,"> + <input class="no" type="hidden"> + <object class="no">object</object> + <video class="no"></video> + + <span class="no" tabindex="1">tabindex</span> + <audio class="no" tabindex="1"></audio> + <img class="no" src="data:image/png," tabindex="1"> + <input class="no" type="hidden" tabindex="1"> + <object class="no" tabindex="1">object</object> + <video class="no" tabindex="1"></video> + </summary> + <div>This is details</div> +</details> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 1524893 **/ + +var details = document.getElementById("details"); + +var yes_nodes = Array.from(document.getElementsByClassName("yes")); + +var root1 = document.getElementById("root1"); +root1.attachShadow({ mode: "open" }).innerHTML = "<button class=yes>button in shadow tree</button>"; +var root2 = document.getElementById("root2"); +root2.attachShadow({ mode: "open" }).innerHTML = "<div class=yes>text in shadow tree</div>"; +var yes_nodes_in_shadow_tree = + Array.from(root1.shadowRoot.querySelectorAll(".yes")).concat( + Array.from(root2.shadowRoot.querySelectorAll(".yes"))); + +var no_nodes = Array.from(document.getElementsByClassName("no")); + +var node; +for (node of yes_nodes) { + details.removeAttribute('open'); + node.click(); + ok(!details.hasAttribute('open'), + "mouse click on interactive content " + node.nodeName + " shouldn't not open details"); +} + +for (node of yes_nodes_in_shadow_tree) { + details.removeAttribute('open'); + node.click(); + ok(!details.hasAttribute('open'), + "mouse click on content in shadow tree " + node.nodeName + " shouldn't open details"); +} + +for (node of no_nodes) { + details.removeAttribute('open'); + node.click(); + ok(details.hasAttribute('open'), + "mouse click on non interactive content " + node.nodeName + " should open details"); +} + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/forms/test_label_control_attribute.html b/dom/html/test/forms/test_label_control_attribute.html new file mode 100644 index 0000000000..efc04cd787 --- /dev/null +++ b/dom/html/test/forms/test_label_control_attribute.html @@ -0,0 +1,100 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=562932 +--> +<head> + <title>Test for Bug 562932</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=562932">Mozilla Bug 562932</a> +<p id="display"></p> +<div id="content" style="display: none"> + <!-- No @for, we have to check the content --> + <label id='l1'><input id='i1'></label> + <label id='l2'><input id='i2'><input></label> + <label id='l3'></label> + <label id='l4a'><fieldset id='f'>foo</fieldset></label> + <label id='l4b'><label id='l4c'><input id='i3'></label></label> + <label id='l4d'><label id='l4e'><input id='i3b'></label><input></label> + + <!-- With @for, we do no check the content --> + <label id='l5' for='i1'></label> + <label id='l6' for='i4'></label> + <label id='l7' for='i4'><input></label> + <label id='l8' for='i1 i2'></label> + <label id='l9' for='i1 i2'><input></label> + <label id='l10' for='f'></label> + <label id='l11' for='i4'></label> + <label id='l12' for='i5'></label> + <label id='l13' for=''><input></label> + <!-- <label id='l14'> is created in script --> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 562932 **/ + +function checkControl(aLabelId, aElementId, aMsg) +{ + var element = null; + + if (aElementId != null) { + element = document.getElementById(aElementId); + } + + is(document.getElementById(aLabelId).control, element, aMsg); +} + +ok('control' in document.createElement('label'), + "label element should have a control IDL attribute"); + +checkControl('l1', 'i1', "label control should be the first form element"); +checkControl('l2', 'i2', "label control should be the first form element"); +checkControl('l3', null, "label control should be null when there is no child"); +checkControl('l4a', null, "label control should be null when there is no \ + labelable form element child"); +checkControl('l4b', 'i3', "label control should be the first labelable element \ + in tree order"); +checkControl('l4c', 'i3', "label control should be the first labelable element \ + in tree order"); +checkControl('l4d', 'i3b', "label control should be the first labelable element \ + in tree order"); +checkControl('l4e', 'i3b', "label control should be the first labelable element \ + in tree order"); +checkControl('l5', 'i1', "label control should be the id in @for"); +checkControl('l6', null, + "label control should be null if the id in @for is not valid"); +checkControl('l7', null, + "label control should be null if the id in @for is not valid"); +checkControl('l8', null, + "label control should be null if there are more than one id in @for"); +checkControl('l9', null, + "label control should be null if there are more than one id in @for"); +checkControl('l10', null, "label control should be null if the id in @for \ + is not an id from a labelable form element"); + +var inputOutOfDocument = document.createElement('input'); +inputOutOfDocument.id = 'i4'; +checkControl('l11', null, "label control should be null if the id in @for \ + is not an id from an element in the document"); + +var inputInDocument = document.createElement('input'); +inputInDocument.id = 'i5'; +document.getElementById('content').appendChild(inputInDocument); +checkControl('l12', 'i5', "label control should be the id in @for"); + +checkControl('l13', null, "label control should be null if the id in @for \ + is empty"); + +var labelOutOfDocument = document.createElement('label'); +labelOutOfDocument.htmlFor = 'i1'; +is(labelOutOfDocument.control, null, "out of document label shouldn't \ + labelize a form control"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_label_input_controls.html b/dom/html/test/forms/test_label_input_controls.html new file mode 100644 index 0000000000..fe9410b608 --- /dev/null +++ b/dom/html/test/forms/test_label_input_controls.html @@ -0,0 +1,84 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=597650 +--> +<head> + <title>Test for Bug 597650</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=597650">Mozilla Bug 597650</a> + <p id="display"></p> + <div id="content"> + <label id="l"> + <input id="h"></input> + <input type="text" id="i"></input> + </label> + <label id="lh" for="h"></label> + </div> + <pre id="test"> + <script class="testbody" type="text/javascript"> + /** Test for Bug 597650 **/ + label = document.getElementById("l"); + labelForH = document.getElementById("lh"); + inputI = document.getElementById("i"); + inputH = document.getElementById("h"); + + var labelableTypes = ["text", "search", "tel", "url", "email", "password", + "datetime", "date", "month", "week", "time", + "number", "range", "color", "checkbox", "radio", + "file", "submit", "image", "reset", "button"]; + var nonLabelableTypes = ["hidden"]; + + for (var i in labelableTypes) { + test(labelableTypes[i], true); + } + + for (var i in nonLabelableTypes) { + test(nonLabelableTypes[i], false); + } + + function test(type, isLabelable) { + inputH.type = type; + if (isLabelable) { + testControl(label, inputH, type, true); + testControl(labelForH, inputH, type, true); + } else { + testControl(label, inputI, type, false); + testControl(labelForH, null, type, false); + + inputH.type = "text"; + testControl(label, inputH, "text", true); + testControl(labelForH, inputH, "text", true); + + inputH.type = type; + testControl(label, inputI, type, false); + testControl(labelForH, null, type, false); + + label.removeChild(inputH); + testControl(label, inputI, "text", true); + + var element = document.createElement('input'); + element.type = type; + label.insertBefore(element, inputI); + testControl(label, inputI, "text", true); + } + } + + function testControl(label, control, type, labelable) { + if (labelable) { + is(label.control, control, "Input controls of type " + type + + " should be labeled"); + } else { + is(label.control, control, "Input controls of type " + type + + " should be ignored by <label>"); + } + } + </script> + </pre> + </body> +</html> + diff --git a/dom/html/test/forms/test_max_attribute.html b/dom/html/test/forms/test_max_attribute.html new file mode 100644 index 0000000000..f6e9c9bd8e --- /dev/null +++ b/dom/html/test/forms/test_max_attribute.html @@ -0,0 +1,473 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=635499 +--> +<head> + <title>Test for Bug 635499</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=635499">Mozilla Bug 635499</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 635499 **/ + +var data = [ + { type: 'hidden', apply: false }, + { type: 'text', apply: false }, + { type: 'search', apply: false }, + { type: 'tel', apply: false }, + { type: 'url', apply: false }, + { type: 'email', apply: false }, + { type: 'password', apply: false }, + { type: 'date', apply: true }, + { type: 'month', apply: true }, + { type: 'week', apply: true }, + { type: 'time', apply: true }, + { type: 'datetime-local', apply: true }, + { type: 'number', apply: true }, + { type: 'range', apply: true }, + { type: 'color', apply: false }, + { type: 'checkbox', apply: false }, + { type: 'radio', apply: false }, + { type: 'file', apply: false }, + { type: 'submit', apply: false }, + { type: 'image', apply: false }, + { type: 'reset', apply: false }, + { type: 'button', apply: false }, +]; + +var input = document.createElement("input"); +document.getElementById('content').appendChild(input); + +/** + * @aValidity - boolean indicating whether the element is expected to be valid + * (aElement.validity.valid is true) or not. The value passed is ignored and + * overridden with true if aApply is false. + * @aApply - boolean indicating whether the min/max attributes apply to this + * element type. + * @aRangeApply - A boolean that's set to true if the current input type is a + * "[candidate] for constraint validation" and it "[has] range limitations" + * per http://www.whatwg.org/specs/web-apps/current-work/multipage/selectors.html#selector-in-range + * (in other words, one of the pseudo classes :in-range and :out-of-range + * should apply (which, depends on aValidity)). + * Else (neither :in-range or :out-of-range should match) set to false. + */ +function checkValidity(aElement, aValidity, aApply, aRangeApply) +{ + aValidity = aApply ? aValidity : true; + + is(aElement.validity.valid, aValidity, + "element validity should be " + aValidity); + is(aElement.validity.rangeOverflow, !aValidity, + "element overflow status should be " + !aValidity); + var overflowMsg = + (aElement.type == "date" || aElement.type == "time" || + aElement.type == "month" || aElement.type == "week" || + aElement.type == "datetime-local") ? + ("Please select a value that is no later than " + aElement.max + ".") : + ("Please select a value that is no more than " + aElement.max + "."); + is(aElement.validationMessage, + aValidity ? "" : overflowMsg, "Checking range overflow validation message"); + + is(aElement.matches(":valid"), aElement.willValidate && aValidity, + (aElement.willValidate && aValidity) ? ":valid should apply" : "valid shouldn't apply"); + is(aElement.matches(":invalid"), aElement.willValidate && !aValidity, + (aElement.wil && aValidity) ? ":invalid shouldn't apply" : "valid should apply"); + + if (!aRangeApply) { + ok(!aElement.matches(":in-range"), ":in-range should not match"); + ok(!aElement.matches(":out-of-range"), + ":out-of-range should not match"); + } else { + is(aElement.matches(":in-range"), aValidity, + ":in-range matches status should be " + aValidity); + is(aElement.matches(":out-of-range"), !aValidity, + ":out-of-range matches status should be " + !aValidity); + } +} + +for (var test of data) { + input.type = test.type; + var apply = test.apply; + + // The element should be valid. Range should not apply when @min and @max are + // undefined, except if the input type is 'range' (since that type has a + // default minimum and maximum). + if (input.type == 'range') { + checkValidity(input, true, apply, true); + } else { + checkValidity(input, true, apply, false); + } + checkValidity(input, true, apply, test.type == 'range'); + + switch (input.type) { + case 'hidden': + case 'text': + case 'search': + case 'password': + case 'url': + case 'tel': + case 'email': + case 'number': + case 'checkbox': + case 'radio': + case 'file': + case 'submit': + case 'reset': + case 'button': + case 'image': + case 'color': + input.max = '-1'; + break; + case 'date': + input.max = '2012-06-27'; + break; + case 'time': + input.max = '02:20'; + break; + case 'range': + // range is special, since setting max to -1 will make it invalid since + // it's default would then be 0, meaning it suffers from overflow. + input.max = '-1'; + checkValidity(input, false, apply, apply); + // Now make it something that won't cause an error below: + input.max = '10'; + break; + case 'month': + input.max = '2016-12'; + break; + case 'week': + input.max = '2016-W39'; + break; + case 'datetime-local': + input.max = '2016-12-31T23:59:59'; + break; + default: + ok(false, 'please, add a case for this new type (' + input.type + ')'); + } + + checkValidity(input, true, apply, apply); + + switch (input.type) { + case 'text': + case 'hidden': + case 'search': + case 'password': + case 'tel': + case 'radio': + case 'checkbox': + case 'reset': + case 'button': + case 'submit': + case 'image': + input.value = '0'; + checkValidity(input, true, apply, apply); + break; + case 'url': + input.value = 'http://mozilla.org'; + checkValidity(input, true, apply, apply); + break; + case 'email': + input.value = 'foo@bar.com'; + checkValidity(input, true, apply, apply); + break; + case 'file': + var file = new File([''], '635499_file'); + + SpecialPowers.wrap(input).mozSetFileArray([file]); + checkValidity(input, true, apply, apply); + + break; + case 'date': + input.max = '2012-06-27'; + input.value = '2012-06-26'; + checkValidity(input, true, apply, apply); + + input.value = '2012-06-27'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '2012-06-28'; + checkValidity(input, false, apply, apply); + + input.max = '2012-06-30'; + checkValidity(input, true, apply, apply); + + input.value = '2012-07-05'; + checkValidity(input, false, apply, apply); + + input.value = '1000-01-01'; + checkValidity(input, true, apply, apply); + + input.value = '20120-01-01'; + checkValidity(input, false, apply, apply); + + input.max = '0050-01-01'; + checkValidity(input, false, apply, apply); + + input.value = '0049-01-01'; + checkValidity(input, true, apply, apply); + + input.max = ''; + checkValidity(input, true, apply, false); + + input.max = 'foo'; + checkValidity(input, true, apply, false); + + break; + case 'number': + input.max = '2'; + input.value = '1'; + checkValidity(input, true, apply, apply); + + input.value = '2'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '3'; + checkValidity(input, false, apply, apply); + + input.max = '5'; + checkValidity(input, true, apply, apply); + + input.value = '42'; + checkValidity(input, false, apply, apply); + + input.max = ''; + checkValidity(input, true, apply, false); + + input.max = 'foo'; + checkValidity(input, true, apply, false); + + // Check that we correctly convert input.max to a double in validationMessage. + if (input.type == 'number') { + input.max = "4.333333333333333333333333333333333331"; + input.value = "5"; + is(input.validationMessage, + "Please select a value that is no more than 4.33333333333333.", + "validation message"); + } + + break; + case 'range': + input.max = '2'; + input.value = '1'; + checkValidity(input, true, apply, apply); + + input.value = '2'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '3'; + checkValidity(input, true, apply, apply); + + is(input.value, input.max, "the value should have been set to max"); + + input.max = '5'; + checkValidity(input, true, apply, apply); + + input.value = '42'; + checkValidity(input, true, apply, apply); + + is(input.value, input.max, "the value should have been set to max"); + + input.max = ''; + checkValidity(input, true, apply, apply); + + input.max = 'foo'; + checkValidity(input, true, apply, apply); + + // Check that we correctly convert input.max to a double in validationMessage. + input.step = 'any'; + input.min = 5; + input.max = 0.6666666666666666; + input.value = 1; + is(input.validationMessage, + "Please select a value that is no more than 0.666666666666667.", + "validation message") + + break; + case 'time': + // Don't worry about that. + input.step = 'any'; + + input.max = '10:10'; + input.value = '10:09'; + checkValidity(input, true, apply, apply); + + input.value = '10:10'; + checkValidity(input, true, apply, apply); + + input.value = '10:10:00'; + checkValidity(input, true, apply, apply); + + input.value = '10:10:00.000'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '10:11'; + checkValidity(input, false, apply, apply); + + input.value = '10:10:00.001'; + checkValidity(input, false, apply, apply); + + input.max = '01:00:00.01'; + input.value = '01:00:00.001'; + checkValidity(input, true, apply, apply); + + input.value = '01:00:00'; + checkValidity(input, true, apply, apply); + + input.value = '01:00:00.1'; + checkValidity(input, false, apply, apply); + + input.max = ''; + checkValidity(input, true, apply, false); + + input.max = 'foo'; + checkValidity(input, true, apply, false); + + break; + case 'month': + input.value = '2016-06'; + checkValidity(input, true, apply, apply); + + input.value = '2016-12'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '2017-01'; + checkValidity(input, false, apply, apply); + + input.max = '2017-07'; + checkValidity(input, true, apply, apply); + + input.value = '2017-12'; + checkValidity(input, false, apply, apply); + + input.value = '1000-01'; + checkValidity(input, true, apply, apply); + + input.value = '20160-01'; + checkValidity(input, false, apply, apply); + + input.max = '0050-01'; + checkValidity(input, false, apply, apply); + + input.value = '0049-12'; + checkValidity(input, true, apply, apply); + + input.max = ''; + checkValidity(input, true, apply, false); + + input.max = 'foo'; + checkValidity(input, true, apply, false); + + break; + case 'week': + input.value = '2016-W01'; + checkValidity(input, true, apply, apply); + + input.value = '2016-W39'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '2017-W01'; + checkValidity(input, false, apply, apply); + + input.max = '2017-W01'; + checkValidity(input, true, apply, apply); + + input.value = '2017-W52'; + checkValidity(input, false, apply, apply); + + input.value = '1000-W01'; + checkValidity(input, true, apply, apply); + + input.value = '2100-W01'; + checkValidity(input, false, apply, apply); + + input.max = '0050-W01'; + checkValidity(input, false, apply, apply); + + input.value = '0049-W52'; + checkValidity(input, true, apply, apply); + + input.max = ''; + checkValidity(input, true, apply, false); + + input.max = 'foo'; + checkValidity(input, true, apply, false); + + break; + case 'datetime-local': + input.value = '2016-01-01T12:00'; + checkValidity(input, true, apply, apply); + + input.value = '2016-12-31T23:59:59'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '2016-12-31T23:59:59.123'; + checkValidity(input, false, apply, apply); + + input.value = '2017-01-01T10:00'; + checkValidity(input, false, apply, apply); + + input.max = '2017-01-01T10:00'; + checkValidity(input, true, apply, apply); + + input.value = '2017-01-01T10:00:30'; + checkValidity(input, false, apply, apply); + + input.value = '1000-01-01T12:00'; + checkValidity(input, true, apply, apply); + + input.value = '2100-01-01T12:00'; + checkValidity(input, false, apply, apply); + + input.max = '0050-12-31T23:59:59.999'; + checkValidity(input, false, apply, apply); + + input.value = '0050-12-31T23:59:59'; + checkValidity(input, true, apply, apply); + + input.max = ''; + checkValidity(input, true, apply, false); + + input.max = 'foo'; + checkValidity(input, true, apply, false); + + break; + } + + // Cleaning up, + input.removeAttribute('max'); + input.value = ''; +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_maxlength_attribute.html b/dom/html/test/forms/test_maxlength_attribute.html new file mode 100644 index 0000000000..bd76e277e5 --- /dev/null +++ b/dom/html/test/forms/test_maxlength_attribute.html @@ -0,0 +1,129 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=345624 +--> +<head> + <title>Test for Bug 345624</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + input, textarea { background-color: rgb(0,0,0) !important; } + :-moz-any(input,textarea):valid { background-color: rgb(0,255,0) !important; } + :-moz-any(input,textarea):invalid { background-color: rgb(255,0,0) !important; } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=345624">Mozilla Bug 345624</a> +<p id="display"></p> +<div id="content"> + <input id='i'> + <textarea id='t'></textarea> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 345624 **/ + +/** + * This test is checking only tooLong related features + * related to constraint validation. + */ + +function checkTooLongValidity(element) +{ + element.value = "foo"; + ok(!element.validity.tooLong, + "Element should not be too long when maxlength is not set"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "The element should be valid"); + + element.maxLength = 1; + ok(!element.validity.tooLong, + "Element should not be too long unless the user edits it"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "The element should be valid"); + + element.focus(); + + synthesizeKey("KEY_Backspace"); + is(element.value, "fo", "value should have changed"); + ok(element.validity.tooLong, + "Element should be too long after a user edit that does not make it short enough"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(255, 0, 0)", ":invalid pseudo-class should apply"); + ok(!element.validity.valid, "Element should be invalid"); + ok(!element.checkValidity(), "The element should not be valid"); + is(element.validationMessage, + "Please shorten this text to 1 characters or less (you are currently using 2 characters).", + "The validation message text is not correct"); + + synthesizeKey("KEY_Backspace"); + is(element.value, "f", "value should have changed"); + ok(!element.validity.tooLong, + "Element should not be too long after a user edit makes it short enough"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + + element.maxLength = 2; + ok(!element.validity.tooLong, + "Element should remain valid if maxlength changes but maxlength > length"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + + element.maxLength = 1; + ok(!element.validity.tooLong, + "Element should remain valid if maxlength changes but maxlength = length"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "The element should be valid"); + + element.maxLength = 0; + ok(element.validity.tooLong, + "Element should become invalid if maxlength changes and maxlength < length"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(255, 0, 0)", ":invalid pseudo-class should apply"); + ok(!element.validity.valid, "Element should be invalid"); + ok(!element.checkValidity(), "The element should not be valid"); + is(element.validationMessage, + "Please shorten this text to 0 characters or less (you are currently using 1 characters).", + "The validation message text is not correct"); + + element.maxLength = 1; + ok(!element.validity.tooLong, + "Element should become valid if maxlength changes and maxlength = length"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "The element should be valid"); + + element.value = "test"; + ok(!element.validity.tooLong, + "Element should stay valid after programmatic edit (even if value is too long)"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "The element should be valid"); + + element.setCustomValidity("custom message"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(255, 0, 0)", ":invalid pseudo-class should apply"); + is(element.validationMessage, "custom message", + "Custom message should be shown instead of too long one"); +} + +checkTooLongValidity(document.getElementById('i')); +checkTooLongValidity(document.getElementById('t')); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_meter_element.html b/dom/html/test/forms/test_meter_element.html new file mode 100644 index 0000000000..5e1073d53d --- /dev/null +++ b/dom/html/test/forms/test_meter_element.html @@ -0,0 +1,376 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=657938 +--> +<head> + <title>Test for <meter></title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=657938">Mozilla Bug 657938</a> +<p id="display"></p> +<iframe name="submit_frame" style="visibility: hidden;"></iframe> +<div id="content" style="visibility: hidden;"> + <form id='f' method='get' target='submit_frame' action='foo'> + <meter id='m' value=0.5></meter> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for <meter> **/ + +function checkFormIDLAttribute(aElement) +{ + is('form' in aElement, false, "<meter> shouldn't have a form attribute"); +} + +function checkAttribute(aElement, aAttribute, aNewValue, aExpectedValueForIDL) +{ + var expectedValueForIDL = aNewValue; + var expectedValueForContent = String(aNewValue); + + if (aExpectedValueForIDL !== undefined) { + expectedValueForIDL = aExpectedValueForIDL; + } + + if (aNewValue != null) { + aElement.setAttribute(aAttribute, aNewValue); + is(aElement.getAttribute(aAttribute), expectedValueForContent, + aAttribute + " content attribute should be " + expectedValueForContent); + is(aElement[aAttribute], expectedValueForIDL, + aAttribute + " IDL attribute should be " + expectedValueForIDL); + + if (parseFloat(aNewValue) == aNewValue) { + aElement[aAttribute] = aNewValue; + is(aElement.getAttribute(aAttribute), expectedValueForContent, + aAttribute + " content attribute should be " + expectedValueForContent); + is(aElement[aAttribute], parseFloat(expectedValueForIDL), + aAttribute + " IDL attribute should be " + parseFloat(expectedValueForIDL)); + } + } else { + aElement.removeAttribute(aAttribute); + is(aElement.getAttribute(aAttribute), null, + aAttribute + " content attribute should be null"); + is(aElement[aAttribute], expectedValueForIDL, + aAttribute + " IDL attribute should be " + expectedValueForIDL); + } +} + +function checkValueAttribute() +{ + var tests = [ + // value has to be a valid float, its default value is 0.0 otherwise. + [ null, 0.0 ], + [ 'foo', 0.0 ], + // If value < 0.0, 0.0 is used instead. + [ -1.0, 0.0 ], + // If value >= max, max is used instead (max default value is 1.0). + [ 2.0, 1.0 ], + [ 1.0, 0.5, 0.5 ], + [ 10.0, 5.0, 5.0 ], + [ 13.37, 13.37, 42.0 ], + // If value <= min, min is used instead (min default value is 0.0). + [ 0.5, 1.0, 10.0 ,1.0 ], + [ 10.0, 13.37, 42.0 , 13.37], + // Regular reflection. + [ 0.0 ], + [ 0.5 ], + [ 1.0 ], + // Check double-precision value. + [ 0.234567898765432 ], + ]; + + var element = document.createElement('meter'); + + for (var test of tests) { + if (test[2]) { + element.setAttribute('max', test[2]); + } + + if (test[3]) { + element.setAttribute('min', test[3]); + } + + checkAttribute(element, 'value', test[0], test[1]); + + element.removeAttribute('max'); + element.removeAttribute('min'); + } +} + +function checkMinAttribute() +{ + var tests = [ + // min default value is 0.0. + [ null, 0.0 ], + [ 'foo', 0.0 ], + // Regular reflection. + [ 0.5 ], + [ 1.0 ], + [ 2.0 ], + // Check double-precision value. + [ 0.234567898765432 ], + ]; + + var element = document.createElement('meter'); + + for (var test of tests) { + checkAttribute(element, 'min', test[0], test[1]); + } +} + +function checkMaxAttribute() +{ + var tests = [ + // max default value is 1.0. + [ null, 1.0 ], + [ 'foo', 1.0 ], + // If value <= min, min is used instead. + [ -1.0, 0.0 ], + [ 0.0, 0.5, 0.5 ], + [ 10.0, 15.0, 15.0 ], + [ 42, 42, 13.37 ], + // Regular reflection. + [ 0.5 ], + [ 1.0 ], + [ 2.0 ], + // Check double-precision value. + [ 0.234567898765432 ], + ]; + + var element = document.createElement('meter'); + + for (var test of tests) { + if (test[2]) { + element.setAttribute('min', test[2]); + } + + checkAttribute(element, 'max', test[0], test[1]); + + element.removeAttribute('min'); + } +} + +function checkLowAttribute() +{ + var tests = [ + // low default value is min (min default value is 0.0). + [ null, 0.0 ], + [ 'foo', 0.0 ], + [ 'foo', 1.0, 1.0], + // If low <= min, min is used instead. + [ -1.0, 0.0 ], + [ 0.0, 0.5, 0.5 ], + [ 10.0, 15.0, 15.0, 42.0 ], + [ 42.0, 42.0, 13.37, 100.0 ], + // If low >= max, max is used instead. + [ 2.0, 1.0 ], + [ 10.0, 5.0 , 0.5, 5.0 ], + [ 13.37, 13.37, 0.0, 42.0 ], + // Regular reflection. + [ 0.0 ], + [ 0.5 ], + [ 1.0 ], + // Check double-precision value. + [ 0.234567898765432 ], + ]; + + var element = document.createElement('meter'); + + for (var test of tests) { + if (test[2]) { + element.setAttribute('min', test[2]); + } + if (test[3]) { + element.setAttribute('max', test[3]); + } + + checkAttribute(element, 'low', test[0], test[1]); + + element.removeAttribute('min'); + element.removeAttribute('max'); + } +} + +function checkHighAttribute() +{ + var tests = [ + // high default value is max (max default value is 1.0). + [ null, 1.0 ], + [ 'foo', 1.0 ], + [ 'foo', 42.0, 0.0, 42.0], + // If high <= min, min is used instead. + [ -1.0, 0.0 ], + [ 0.0, 0.5, 0.5 ], + [ 10.0, 15.0, 15.0, 42.0 ], + [ 42.0, 42.0, 13.37, 100.0 ], + // If high >= max, max is used instead. + [ 2.0, 1.0 ], + [ 10.0, 5.0 , 0.5, 5.0 ], + [ 13.37, 13.37, 0.0, 42.0 ], + // Regular reflection. + [ 0.0 ], + [ 0.5 ], + [ 1.0 ], + // Check double-precision value. + [ 0.234567898765432 ], + ]; + + var element = document.createElement('meter'); + + for (var test of tests) { + if (test[2]) { + element.setAttribute('min', test[2]); + } + if (test[3]) { + element.setAttribute('max', test[3]); + } + + checkAttribute(element, 'high', test[0], test[1]); + + element.removeAttribute('min'); + element.removeAttribute('max'); + } +} + +function checkOptimumAttribute() +{ + var tests = [ + // opt default value is (max-min)/2 (thus default value is 0.5). + [ null, 0.5 ], + [ 'foo', 0.5 ], + [ 'foo', 2.0, 1.0, 3.0], + // If opt <= min, min is used instead. + [ -1.0, 0.0 ], + [ 0.0, 0.5, 0.5 ], + [ 10.0, 15.0, 15.0, 42.0 ], + [ 42.0, 42.0, 13.37, 100.0 ], + // If opt >= max, max is used instead. + [ 2.0, 1.0 ], + [ 10.0, 5.0 , 0.5, 5.0 ], + [ 13.37, 13.37, 0.0, 42.0 ], + // Regular reflection. + [ 0.0 ], + [ 0.5 ], + [ 1.0 ], + // Check double-precision value. + [ 0.234567898765432 ], + ]; + + var element = document.createElement('meter'); + + for (var test of tests) { + if (test[2]) { + element.setAttribute('min', test[2]); + } + if (test[3]) { + element.setAttribute('max', test[3]); + } + + checkAttribute(element, 'optimum', test[0], test[1]); + + element.removeAttribute('min'); + element.removeAttribute('max'); + } +} + +function checkFormListedElement(aElement) +{ + is(document.forms[0].elements.length, 0, "the form should have no element"); +} + +function checkLabelable(aElement) +{ + var content = document.getElementById('content'); + var label = document.createElement('label'); + + content.appendChild(label); + label.appendChild(aElement); + is(label.control, aElement, "meter should be labelable"); + + // Cleaning-up. + content.removeChild(label); + content.appendChild(aElement); +} + +function checkNotResetableAndFormSubmission(aElement) +{ + // Creating an input element to check the submission worked. + var form = document.forms[0]; + var input = document.createElement('input'); + + input.name = 'a'; + input.value = 'tulip'; + form.appendChild(input); + + // Setting values. + aElement.value = 42.0; + aElement.max = 100.0; + + document.getElementsByName('submit_frame')[0].addEventListener("load", function() { + is(frames.submit_frame.location.href, + `${location.origin}/tests/dom/html/test/forms/foo?a=tulip`, + "The meter element value should not be submitted"); + + checkNotResetable(); + }, {once: true}); + + form.submit(); +} + +function checkNotResetable() +{ + // Try to reset the form. + var form = document.forms[0]; + var element = document.getElementById('m'); + + element.value = 3.0; + element.max = 42.0; + + form.reset(); + + SimpleTest.executeSoon(function() { + is(element.value, 3.0, "meter.value should not have changed"); + is(element.max, 42.0, "meter.max should not have changed"); + + SimpleTest.finish(); + }); +} + +SimpleTest.waitForExplicitFinish(); + +var m = document.getElementById('m'); + +ok(m instanceof HTMLMeterElement, + "The meter element should be instance of HTMLMeterElement"); +is(m.constructor, HTMLMeterElement, + "The meter element constructor should be HTMLMeterElement"); + +// There is no such attribute. +checkFormIDLAttribute(m); + +checkValueAttribute(); + +checkMinAttribute(); + +checkMaxAttribute(); + +checkLowAttribute(); + +checkHighAttribute(); + +checkOptimumAttribute(); + +checkFormListedElement(m); + +checkLabelable(m); + +checkNotResetableAndFormSubmission(m); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_meter_pseudo-classes.html b/dom/html/test/forms/test_meter_pseudo-classes.html new file mode 100644 index 0000000000..e317a58405 --- /dev/null +++ b/dom/html/test/forms/test_meter_pseudo-classes.html @@ -0,0 +1,169 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=660238 +--> +<head> + <title>Test for Bug 660238</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=770238">Mozilla Bug 660238</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 660238 **/ + +function checkOptimum(aElement, aValue, aOptimum, expectedResult) +{ + var errorString = expectedResult + ? "value attribute should be in the optimum region" + : "value attribute should not be in the optimum region"; + + aElement.setAttribute('value', aValue); + aElement.setAttribute('optimum', aOptimum); + is(aElement.matches(":-moz-meter-optimum"), + expectedResult, errorString); +} + +function checkSubOptimum(aElement, aValue, aOptimum, expectedResult) +{ + var errorString = "value attribute should be in the suboptimal region"; + if (!expectedResult) { + errorString = "value attribute should not be in the suboptimal region"; + } + aElement.setAttribute('value', aValue); + aElement.setAttribute('optimum', aOptimum); + is(aElement.matches(":-moz-meter-sub-optimum"), + expectedResult, errorString); +} + +function checkSubSubOptimum(aElement, aValue, aOptimum, expectedResult) +{ + var errorString = "value attribute should be in the sub-suboptimal region"; + if (!expectedResult) { + errorString = "value attribute should not be in the sub-suboptimal region"; + } + aElement.setAttribute('value', aValue); + aElement.setAttribute('optimum', aOptimum); + is(aElement.matches(":-moz-meter-sub-sub-optimum"), + expectedResult, errorString); +} + +function checkMozMatchesSelector() +{ + var element = document.createElement('meter'); + // all tests realised with default values for min and max (0 and 1) + // low = 0.3 and high = 0.7 + element.setAttribute('low', 0.3); + element.setAttribute('high', 0.7); + + var tests = [ + /* + * optimum = 0.0 => + * optimum region = [ 0.0, 0.3 [ + * suboptimal region = [ 0.3, 0.7 ] + * sub-suboptimal region = ] 0.7, 1.0 ] + */ + [ 0.0, 0.0, true, false, false ], + [ 0.1, 0.0, true, false, false ], + [ 0.3, 0.0, false, true, false ], + [ 0.5, 0.0, false, true, false ], + [ 0.7, 0.0, false, true, false ], + [ 0.8, 0.0, false, false, true ], + [ 1.0, 0.0, false, false, true ], + /* + * optimum = 0.1 => + * optimum region = [ 0.0, 0.3 [ + * suboptimal region = [ 0.3, 0.7 ] + * sub-suboptimal region = ] 0.7, 1.0 ] + */ + [ 0.0, 0.1, true, false, false ], + [ 0.1, 0.1, true, false, false ], + [ 0.3, 0.1, false, true, false ], + [ 0.5, 0.1, false, true, false ], + [ 0.7, 0.1, false, true, false ], + [ 0.8, 0.1, false, false, true ], + [ 1.0, 0.1, false, false, true ], + /* + * optimum = 0.3 => + * suboptimal region = [ 0.0, 0.3 [ + * optimum region = [ 0.3, 0.7 ] + * suboptimal region = ] 0.7, 1.0 ] + */ + [ 0.0, 0.3, false, true, false ], + [ 0.1, 0.3, false, true, false ], + [ 0.3, 0.3, true, false, false ], + [ 0.5, 0.3, true, false, false ], + [ 0.7, 0.3, true, false, false ], + [ 0.8, 0.3, false, true, false ], + [ 1.0, 0.3, false, true, false ], + /* + * optimum = 0.5 => + * suboptimal region = [ 0.0, 0.3 [ + * optimum region = [ 0.3, 0.7 ] + * suboptimal region = ] 0.7, 1.0 ] + */ + [ 0.0, 0.5, false, true, false ], + [ 0.1, 0.5, false, true, false ], + [ 0.3, 0.5, true, false, false ], + [ 0.5, 0.5, true, false, false ], + [ 0.7, 0.5, true, false, false ], + [ 0.8, 0.5, false, true, false ], + [ 1.0, 0.5, false, true, false ], + /* + * optimum = 0.7 => + * suboptimal region = [ 0.0, 0.3 [ + * optimum region = [ 0.3, 0.7 ] + * suboptimal region = ] 0.7, 1.0 ] + */ + [ 0.0, 0.7, false, true, false ], + [ 0.1, 0.7, false, true, false ], + [ 0.3, 0.7, true, false, false ], + [ 0.5, 0.7, true, false, false ], + [ 0.7, 0.7, true, false, false ], + [ 0.8, 0.7, false, true, false ], + [ 1.0, 0.7, false, true, false ], + /* + * optimum = 0.8 => + * sub-suboptimal region = [ 0.0, 0.3 [ + * suboptimal region = [ 0.3, 0.7 ] + * optimum region = ] 0.7, 1.0 ] + */ + [ 0.0, 0.8, false, false, true ], + [ 0.1, 0.8, false, false, true ], + [ 0.3, 0.8, false, true, false ], + [ 0.5, 0.8, false, true, false ], + [ 0.7, 0.8, false, true, false ], + [ 0.8, 0.8, true, false, false ], + [ 1.0, 0.8, true, false, false ], + /* + * optimum = 1.0 => + * sub-suboptimal region = [ 0.0, 0.3 [ + * suboptimal region = [ 0.3, 0.7 ] + * optimum region = ] 0.7, 1.0 ] + */ + [ 0.0, 1.0, false, false, true ], + [ 0.1, 1.0, false, false, true ], + [ 0.3, 1.0, false, true, false ], + [ 0.5, 1.0, false, true, false ], + [ 0.7, 1.0, false, true, false ], + [ 0.8, 1.0, true, false, false ], + [ 1.0, 1.0, true, false, false ], + ]; + + for (var test of tests) { + checkOptimum(element, test[0], test[1], test[2]); + checkSubOptimum(element, test[0], test[1], test[3]); + checkSubSubOptimum(element, test[0], test[1], test[4]); + } +} + +checkMozMatchesSelector(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_min_attribute.html b/dom/html/test/forms/test_min_attribute.html new file mode 100644 index 0000000000..a603a37d29 --- /dev/null +++ b/dom/html/test/forms/test_min_attribute.html @@ -0,0 +1,473 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=635553 +--> +<head> + <title>Test for Bug 635553</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=635499">Mozilla Bug 635499</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 635553 **/ + +var data = [ + { type: 'hidden', apply: false }, + { type: 'text', apply: false }, + { type: 'search', apply: false }, + { type: 'tel', apply: false }, + { type: 'url', apply: false }, + { type: 'email', apply: false }, + { type: 'password', apply: false }, + { type: 'date', apply: true }, + { type: 'month', apply: true }, + { type: 'week', apply: true }, + { type: 'time', apply: true }, + { type: 'datetime-local', apply: true }, + { type: 'number', apply: true }, + { type: 'range', apply: true }, + { type: 'color', apply: false }, + { type: 'checkbox', apply: false }, + { type: 'radio', apply: false }, + { type: 'file', apply: false }, + { type: 'submit', apply: false }, + { type: 'image', apply: false }, + { type: 'reset', apply: false }, + { type: 'button', apply: false }, +]; + +var input = document.createElement("input"); +document.getElementById('content').appendChild(input); + +/** + * @aValidity - boolean indicating whether the element is expected to be valid + * (aElement.validity.valid is true) or not. The value passed is ignored and + * overridden with true if aApply is false. + * @aApply - boolean indicating whether the min/max attributes apply to this + * element type. + * @aRangeApply - A boolean that's set to true if the current input type is a + * "[candidate] for constraint validation" and it "[has] range limitations" + * per http://www.whatwg.org/specs/web-apps/current-work/multipage/selectors.html#selector-in-range + * (in other words, one of the pseudo classes :in-range and :out-of-range + * should apply (which, depends on aValidity)). + * Else (neither :in-range or :out-of-range should match) set to false. + */ +function checkValidity(aElement, aValidity, aApply, aRangeApply) +{ + aValidity = aApply ? aValidity : true; + + is(aElement.validity.valid, aValidity, + "element validity should be " + aValidity); + is(aElement.validity.rangeUnderflow, !aValidity, + "element underflow status should be " + !aValidity); + var underflowMsg = + (aElement.type == "date" || aElement.type == "time" || + aElement.type == "month" || aElement.type == "week" || + aElement.type == "datetime-local") ? + ("Please select a value that is no earlier than " + aElement.min + ".") : + ("Please select a value that is no less than " + aElement.min + "."); + is(aElement.validationMessage, + aValidity ? "" : underflowMsg, "Checking range underflow validation message"); + + is(aElement.matches(":valid"), aElement.willValidate && aValidity, + (aElement.willValidate && aValidity) ? ":valid should apply" : "valid shouldn't apply"); + is(aElement.matches(":invalid"), aElement.willValidate && !aValidity, + (aElement.wil && aValidity) ? ":invalid shouldn't apply" : "valid should apply"); + + if (!aRangeApply) { + ok(!aElement.matches(":in-range"), ":in-range should not match"); + ok(!aElement.matches(":out-of-range"), + ":out-of-range should not match"); + } else { + is(aElement.matches(":in-range"), aValidity, + ":in-range matches status should be " + aValidity); + is(aElement.matches(":out-of-range"), !aValidity, + ":out-of-range matches status should be " + !aValidity); + } +} + +for (var test of data) { + input.type = test.type; + var apply = test.apply; + + if (test.todo) { + todo_is(input.type, test.type, test.type + " isn't implemented yet"); + continue; + } + + // The element should be valid. Range should not apply when @min and @max are + // undefined, except if the input type is 'range' (since that type has a + // default minimum and maximum). + if (input.type == 'range') { + checkValidity(input, true, apply, true); + } else { + checkValidity(input, true, apply, false); + } + + switch (input.type) { + case 'hidden': + case 'text': + case 'search': + case 'password': + case 'url': + case 'tel': + case 'email': + case 'number': + case 'checkbox': + case 'radio': + case 'file': + case 'submit': + case 'reset': + case 'button': + case 'image': + case 'color': + input.min = '999'; + break; + case 'date': + input.min = '2012-06-27'; + break; + case 'time': + input.min = '20:20'; + break; + case 'range': + // range is special, since setting min to 999 will make it invalid since + // it's default maximum is 100, its value would be 999, and it would + // suffer from overflow. + break; + case 'month': + input.min = '2016-06'; + break; + case 'week': + input.min = '2016-W39'; + break; + case 'datetime-local': + input.min = '2017-01-01T00:00'; + break; + default: + ok(false, 'please, add a case for this new type (' + input.type + ')'); + } + + // The element should still be valid and range should apply if it can. + checkValidity(input, true, apply, apply); + + switch (input.type) { + case 'text': + case 'hidden': + case 'search': + case 'password': + case 'tel': + case 'radio': + case 'checkbox': + case 'reset': + case 'button': + case 'submit': + case 'image': + case 'color': + input.value = '0'; + checkValidity(input, true, apply, apply); + break; + case 'url': + input.value = 'http://mozilla.org'; + checkValidity(input, true, apply, apply); + break; + case 'email': + input.value = 'foo@bar.com'; + checkValidity(input, true, apply, apply); + break; + case 'file': + var file = new File([''], '635499_file'); + + SpecialPowers.wrap(input).mozSetFileArray([file]); + checkValidity(input, true, apply, apply); + + break; + case 'date': + input.value = '2012-06-28'; + checkValidity(input, true, apply, apply); + + input.value = '2012-06-27'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '2012-06-26'; + checkValidity(input, false, apply, apply); + + input.min = '2012-02-29'; + checkValidity(input, true, apply, apply); + + input.value = '2012-02-28'; + checkValidity(input, false, apply, apply); + + input.value = '1000-01-01'; + checkValidity(input, false, apply, apply); + + input.value = '20120-01-01'; + checkValidity(input, true, apply, apply); + + input.min = '0050-01-01'; + checkValidity(input, true, apply, apply); + + input.value = '0049-01-01'; + checkValidity(input, false, apply, apply); + + input.min = ''; + checkValidity(input, true, apply, false); + + input.min = 'foo'; + checkValidity(input, true, apply, false); + break; + case 'number': + input.min = '0'; + input.value = '1'; + checkValidity(input, true, apply, apply); + + input.value = '0'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '-1'; + checkValidity(input, false, apply, apply); + + input.min = '-1'; + checkValidity(input, true, apply, apply); + + input.value = '-42'; + checkValidity(input, false, apply, apply); + + input.min = ''; + checkValidity(input, true, apply, false); + + input.min = 'foo'; + checkValidity(input, true, apply, false); + + // Check that we correctly convert input.min to a double in + // validationMessage. + input.min = "4.333333333333333333333333333333333331"; + input.value = "2"; + is(input.validationMessage, + "Please select a value that is no less than 4.33333333333333.", + "validation message"); + break; + case 'range': + input.min = '0'; + input.value = '1'; + checkValidity(input, true, apply, apply); + + input.value = '0'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '-1'; + checkValidity(input, true, apply, apply); + + is(input.value, input.min, "the value should have been set to min"); + + input.min = '-1'; + checkValidity(input, true, apply, apply); + + input.value = '-42'; + checkValidity(input, true, apply, apply); + + is(input.value, input.min, "the value should have been set to min"); + + input.min = ''; + checkValidity(input, true, apply, true); + + input.min = 'foo'; + checkValidity(input, true, apply, true); + + // We don't check the conversion of input.min to a double in + // validationMessage for 'range' since range will always clamp the value + // up to at least the minimum (so we will never see the min in a + // validationMessage). + + break; + case 'time': + // Don't worry about that. + input.step = 'any'; + + input.min = '20:20'; + input.value = '20:20:01'; + checkValidity(input, true, apply, apply); + + input.value = '20:20:00'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '10:00'; + checkValidity(input, false, apply, apply); + + input.min = '20:20:00.001'; + input.value = '20:20'; + checkValidity(input, false, apply, apply); + + input.value = '00:00'; + checkValidity(input, false, apply, apply); + + input.value = '23:59'; + checkValidity(input, true, apply, apply); + + input.value = '20:20:01'; + checkValidity(input, true, apply, apply); + + input.value = '20:20:00.01'; + checkValidity(input, true, apply, apply); + + input.value = '20:20:00.1'; + checkValidity(input, true, apply, apply); + + input.min = '00:00:00'; + input.value = '01:00'; + checkValidity(input, true, apply, apply); + + input.value = '00:00:00.000'; + checkValidity(input, true, apply, apply); + + input.min = ''; + checkValidity(input, true, apply, false); + + input.min = 'foo'; + checkValidity(input, true, apply, false); + break; + case 'month': + input.value = '2016-07'; + checkValidity(input, true, apply, apply); + + input.value = '2016-06'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '2016-05'; + checkValidity(input, false, apply, apply); + + input.min = '2016-01'; + checkValidity(input, true, apply, apply); + + input.value = '2015-12'; + checkValidity(input, false, apply, apply); + + input.value = '1000-01'; + checkValidity(input, false, apply, apply); + + input.value = '10000-01'; + checkValidity(input, true, apply, apply); + + input.min = '0010-01'; + checkValidity(input, true, apply, apply); + + input.value = '0001-01'; + checkValidity(input, false, apply, apply); + + input.min = ''; + checkValidity(input, true, apply, false); + + input.min = 'foo'; + checkValidity(input, true, apply, false); + break; + case 'week': + input.value = '2016-W40'; + checkValidity(input, true, apply, apply); + + input.value = '2016-W39'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '2016-W38'; + checkValidity(input, false, apply, apply); + + input.min = '2016-W01'; + checkValidity(input, true, apply, apply); + + input.value = '2015-W53'; + checkValidity(input, false, apply, apply); + + input.value = '1000-W01'; + checkValidity(input, false, apply, apply); + + input.value = '10000-01'; + checkValidity(input, true, apply, apply); + + input.min = '0010-W01'; + checkValidity(input, true, apply, apply); + + input.value = '0001-W01'; + checkValidity(input, false, apply, apply); + + input.min = ''; + checkValidity(input, true, apply, false); + + input.min = 'foo'; + checkValidity(input, true, apply, false); + break; + case 'datetime-local': + input.value = '2017-12-31T23:59'; + checkValidity(input, true, apply, apply); + + input.value = '2017-01-01T00:00'; + checkValidity(input, true, apply, apply); + + input.value = '2017-01-01T00:00:00.123'; + checkValidity(input, true, apply, apply); + + input.value = 'foo'; + checkValidity(input, true, apply, apply); + + input.value = '2016-12-31T23:59'; + checkValidity(input, false, apply, apply); + + input.min = '2016-01-01T00:00'; + checkValidity(input, true, apply, apply); + + input.value = '2015-12-31T23:59'; + checkValidity(input, false, apply, apply); + + input.value = '1000-01-01T00:00'; + checkValidity(input, false, apply, apply); + + input.value = '10000-01-01T00:00'; + checkValidity(input, true, apply, apply); + + input.min = '0010-01-01T12:00'; + checkValidity(input, true, apply, apply); + + input.value = '0010-01-01T10:00'; + checkValidity(input, false, apply, apply); + + input.min = ''; + checkValidity(input, true, apply, false); + + input.min = 'foo'; + checkValidity(input, true, apply, false); + break; + default: + ok(false, 'write tests for ' + input.type); + } + + // Cleaning up, + input.removeAttribute('min'); + input.value = ''; +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_minlength_attribute.html b/dom/html/test/forms/test_minlength_attribute.html new file mode 100644 index 0000000000..154343a512 --- /dev/null +++ b/dom/html/test/forms/test_minlength_attribute.html @@ -0,0 +1,130 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=345624 +--> +<head> + <title>Test for Bug 345624</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + input, textarea { background-color: rgb(0,0,0) !important; } + :-moz-any(input,textarea):valid { background-color: rgb(0,255,0) !important; } + :-moz-any(input,textarea):invalid { background-color: rgb(255,0,0) !important; } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=345624">Mozilla Bug 345624</a> +<p id="display"></p> +<div id="content"> + <input id='i'> + <textarea id='t'></textarea> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 345624 **/ + +/** + * This test is checking only tooShort related features + * related to constraint validation. + */ + +function checkTooShortValidity(element) +{ + element.value = "foo"; + ok(!element.validity.tooShort, + "Element should not be too short when minlength is not set"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "The element should be valid"); + + element.minLength = 5; + ok(!element.validity.tooShort, + "Element should not be too short unless the user edits it"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "The element should be valid"); + + element.focus(); + + sendString("o"); + is(element.value, "fooo", "value should have changed"); + ok(element.validity.tooShort, + "Element should be too short after a user edit that does not make it short enough"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(255, 0, 0)", ":invalid pseudo-class should apply"); + ok(!element.validity.valid, "Element should be invalid"); + ok(!element.checkValidity(), "The element should not be valid"); + is(element.validationMessage, + "Please use at least 5 characters (you are currently using 4 characters).", + "The validation message text is not correct"); + + sendString("o"); + is(element.value, "foooo", "value should have changed"); + ok(!element.validity.tooShort, + "Element should not be too short after a user edit makes it long enough"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + + element.minLength = 2; + ok(!element.validity.tooShort, + "Element should remain valid if minlength changes but minlength < length"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + + element.minLength = 1; + ok(!element.validity.tooShort, + "Element should remain valid if minlength changes but minlength = length"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "The element should be valid"); + + element.minLength = 6; + ok(element.validity.tooShort, + "Element should become invalid if minlength changes and minlength > length"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(255, 0, 0)", ":invalid pseudo-class should apply"); + ok(!element.validity.valid, "Element should be invalid"); + ok(!element.checkValidity(), "The element should not be valid"); + is(element.validationMessage, + "Please use at least 6 characters (you are currently using 5 characters).", + "The validation message text is not correct"); + + element.minLength = 5; + ok(!element.validity.tooShort, + "Element should become valid if minlength changes and minlength = length"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "The element should be valid"); + + element.value = "test"; + ok(!element.validity.tooShort, + "Element should stay valid after programmatic edit (even if value is too short)"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "The element should be valid"); + + element.setCustomValidity("custom message"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(255, 0, 0)", ":invalid pseudo-class should apply"); + is(element.validationMessage, "custom message", + "Custom message should be shown instead of too short one"); +} + +checkTooShortValidity(document.getElementById('i')); +checkTooShortValidity(document.getElementById('t')); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/forms/test_mozistextfield.html b/dom/html/test/forms/test_mozistextfield.html new file mode 100644 index 0000000000..3f92a3d05d --- /dev/null +++ b/dom/html/test/forms/test_mozistextfield.html @@ -0,0 +1,111 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=565538 +--> +<head> + <title>Test for Bug 565538</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=565538">Mozilla Bug 565538</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 565538 **/ + +var gElementTestData = [ +/* element result */ + ['input', true], + ['button', false], + ['fieldset', false], + ['label', false], + ['option', false], + ['optgroup', false], + ['output', false], + ['legend', false], + ['select', false], + ['textarea', false], + ['object', false], +]; + +var gInputTestData = [ +/* type result */ + ['password', true], + ['tel', true], + ['text', true], + ['button', false], + ['checkbox', false], + ['file', false], + ['hidden', false], + ['reset', false], + ['image', false], + ['radio', false], + ['submit', false], + ['search', true], + ['email', true], + ['url', true], + ['number', false], + ['range', false], + ['date', false], + ['time', false], + ['color', false], + ['month', false], + ['week', false], + ['datetime-local', false], +]; + +function checkMozIsTextFieldDefined(aElement, aResult) +{ + var element = document.createElement(aElement); + + var msg = "mozIsTextField should be " + if (aResult) { + msg += "defined"; + } else { + msg += "undefined"; + } + + is('mozIsTextField' in element, aResult, msg); +} + +function checkMozIsTextFieldValue(aInput, aResult) +{ + is(aInput.mozIsTextField(false), aResult, + "mozIsTextField(false) should return " + aResult); + + if (aInput.type == 'password') { + ok(!aInput.mozIsTextField(true), + "mozIsTextField(true) should return false for password"); + } else { + is(aInput.mozIsTextField(true), aResult, + "mozIsTextField(true) should return " + aResult); + } +} + +function checkMozIsTextFieldValueTodo(aInput, aResult) +{ + todo_is(aInput.mozIsTextField(false), aResult, + "mozIsTextField(false) should return " + aResult); + todo_is(aInput.mozIsTextField(true), aResult, + "mozIsTextField(true) should return " + aResult); +} + +// Check if the method is defined for the correct elements. +for (data of gElementTestData) { + checkMozIsTextFieldDefined(data[0], data[1]); +} + +// Check if the method returns the correct value. +var input = document.createElement('input'); +for (data of gInputTestData) { + input.type = data[0]; + checkMozIsTextFieldValue(input, data[1]); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_novalidate_attribute.html b/dom/html/test/forms/test_novalidate_attribute.html new file mode 100644 index 0000000000..dcea207838 --- /dev/null +++ b/dom/html/test/forms/test_novalidate_attribute.html @@ -0,0 +1,85 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=556013 +--> +<head> + <title>Test for Bug 556013</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=556013">Mozilla Bug 556013</a> +<p id="display"></p> +<iframe style='width:50px; height: 50px;' name='t'></iframe> +<div id="content"> + <form target='t' action='data:text/html,' novalidate> + <input id='av' required> + <input id='a' type='submit'> + </form> + <form target='t' action='data:text/html,' novalidate> + <input id='bv' type='checkbox' required> + <button id='b' type='submit'></button> + </form> + <form target='t' action='data:text/html,' novalidate> + <input id='c' required> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 556013 **/ + +/** + * novalidate should prevent form validation, thus not blocking form submission. + * + * NOTE: if the MozInvalidForm event doesn't get prevented default, the form + * submission will never be blocked and this test might be a false-positive but + * that should not be a problem. We will remove the check for MozInvalidForm + * event, see bug 587671. + */ +document.forms[0].addEventListener("submit", function(aEvent) { + ok(true, "novalidate has been correctly used for first form"); + document.getElementById('b').click(); +}, {once: true}); + +document.forms[1].addEventListener("submit", function(aEvent) { + ok(true, "novalidate has been correctly used for second form"); + var c = document.getElementById('c'); + c.focus(); + synthesizeKey("KEY_Enter"); +}, {once: true}); + +document.forms[2].addEventListener("submit", function(aEvent) { + ok(true, "novalidate has been correctly used for third form"); + SimpleTest.executeSoon(SimpleTest.finish); +}, {once: true}); + +/** + * We have to be sure invalid events are not send too. + * They should be sent before the submit event so we can just create a test + * failure if we got one. All of them should be catched if sent. + * At worst, we got random green which isn't harmful. + */ +function invalidHandling(aEvent) +{ + aEvent.target.removeEventListener("invalid", invalidHandling); + ok(false, "invalid event should not be sent"); +} + +document.getElementById('av').addEventListener("invalid", invalidHandling); +document.getElementById('bv').addEventListener("invalid", invalidHandling); +document.getElementById('c').addEventListener("invalid", invalidHandling); + +SimpleTest.waitForExplicitFinish(); + +// This is going to call all the tests (with a chain reaction). +SimpleTest.waitForFocus(function() { + document.getElementById('a').click(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_option_disabled.html b/dom/html/test/forms/test_option_disabled.html new file mode 100644 index 0000000000..421e4546be --- /dev/null +++ b/dom/html/test/forms/test_option_disabled.html @@ -0,0 +1,123 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=759666 +--> +<head> + <meta charset="utf-8"> + <title>Test for HTMLOptionElement disabled attribute and pseudo-class</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=759666">Mozilla Bug 759666</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLOptionElement disabled attribute and pseudo-class **/ + +var testCases = [ + // Static checks. + { html: "<option></option>", + result: { attr: null, idl: false, pseudo: false } }, + { html: "<option disabled></option>", + result: { attr: "", idl: true, pseudo: true } }, + { html: "<optgroup><option></option></otpgroup>", + result: { attr: null, idl: false, pseudo: false } }, + { html: "<optgroup><option disabled></option></optgroup>", + result: { attr: "", idl: true, pseudo: true } }, + { html: "<optgroup disabled><option disabled></option></optgroup>", + result: { attr: "", idl: true, pseudo: true } }, + { html: "<optgroup disabled><option></option></optgroup>", + result: { attr: null, idl: false, pseudo: true } }, + { html: "<optgroup><optgroup disabled><option></option></optgroup></optgroup>", + result: { attr: null, idl: false, pseudo: true } }, + { html: "<optgroup disabled><optgroup><option></option></optgroup></optgroup>", + result: { attr: null, idl: false, pseudo: false } }, + { html: "<optgroup disabled><optgroup><option disabled></option></optgroup></optgroup>", + result: { attr: "", idl: true, pseudo: true } }, + + // Dynamic checks: changing disable value. + { html: "<option></option>", + modifier(c) { c.querySelector('option').disabled = true; }, + result: { attr: "", idl: true, pseudo: true } }, + { html: "<option disabled></option>", + modifier(c) { c.querySelector('option').disabled = false; }, + result: { attr: null, idl: false, pseudo: false } }, + { html: "<optgroup><option></option></otpgroup>", + modifier(c) { c.querySelector('optgroup').disabled = true; }, + result: { attr: null, idl: false, pseudo: true } }, + { html: "<optgroup><option disabled></option></optgroup>", + modifier(c) { c.querySelector('option').disabled = false; }, + result: { attr: null, idl: false, pseudo: false } }, + { html: "<optgroup disabled><option disabled></option></optgroup>", + modifier(c) { c.querySelector('optgroup').disabled = false; }, + result: { attr: "", idl: true, pseudo: true } }, + { html: "<optgroup disabled><option disabled></option></optgroup>", + modifier(c) { c.querySelector('option').disabled = false; }, + result: { attr: null, idl: false, pseudo: true } }, + { html: "<optgroup disabled><option disabled></option></optgroup>", + modifier(c) { c.querySelector('optgroup').disabled = c.querySelector('option').disabled = false; }, + result: { attr: null, idl: false, pseudo: false } }, + { html: "<optgroup disabled><option></option></optgroup>", + modifier(c) { c.querySelector('optgroup').disabled = false; }, + result: { attr: null, idl: false, pseudo: false } }, + { html: "<optgroup><optgroup disabled><option></option></optgroup></optgroup>", + modifier(c) { c.querySelector('optgroup[disabled]').disabled = false; }, + result: { attr: null, idl: false, pseudo: false } }, + { html: "<optgroup disabled><optgroup><option></option></optgroup></optgroup>", + modifier(c) { c.querySelector('optgroup[disabled]').disabled = false; }, + result: { attr: null, idl: false, pseudo: false } }, + { html: "<optgroup disabled><optgroup><option disabled></option></optgroup></optgroup>", + modifier(c) { c.querySelector('optgroup').disabled = false; }, + result: { attr: "", idl: true, pseudo: true } }, + { html: "<optgroup disabled><optgroup><option disabled></option></optgroup></optgroup>", + modifier(c) { c.querySelector('option').disabled = false; }, + result: { attr: null, idl: false, pseudo: false } }, + { html: "<optgroup disabled><optgroup><option disabled></option></optgroup></optgroup>", + modifier(c) { c.querySelector('option').disabled = c.querySelector('option').disabled = false; }, + result: { attr: null, idl: false, pseudo: false } }, + + // Dynamic checks: moving option element. + { html: "<optgroup id='a'><option></option></optgroup><optgroup id='b'></optgroup>", + modifier(c) { c.querySelector('#b').appendChild(c.querySelector('option')); }, + result: { attr: null, idl: false, pseudo: false } }, + { html: "<optgroup id='a'><option disabled></option></optgroup><optgroup id='b'></optgroup>", + modifier(c) { c.querySelector('#b').appendChild(c.querySelector('option')); }, + result: { attr: "", idl: true, pseudo: true } }, + { html: "<optgroup id='a'><option></option></optgroup><optgroup disabled id='b'></optgroup>", + modifier(c) { c.querySelector('#b').appendChild(c.querySelector('option')); }, + result: { attr: null, idl: false, pseudo: true } }, + { html: "<optgroup disabled id='a'><option></option></optgroup><optgroup id='b'></optgroup>", + modifier(c) { c.querySelector('#b').appendChild(c.querySelector('option')); }, + result: { attr: null, idl: false, pseudo: false } }, +]; + +var content = document.getElementById('content'); + +testCases.forEach(function(testCase) { + var result = testCase.result; + + content.innerHTML = testCase.html; + + if (testCase.modifier !== undefined) { + testCase.modifier(content); + } + + var option = content.querySelector('option'); + is(option.getAttribute('disabled'), result.attr, "disabled content attribute value should be " + result.attr); + is(option.disabled, result.idl, "disabled idl attribute value should be " + result.idl); + is(option.matches(":disabled"), result.pseudo, ":disabled state should be " + result.pseudo); + is(option.matches(":enabled"), !result.pseudo, ":enabled state should be " + !result.pseudo); + + content.innerHTML = ""; +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_option_index_attribute.html b/dom/html/test/forms/test_option_index_attribute.html new file mode 100644 index 0000000000..f15520e5e6 --- /dev/null +++ b/dom/html/test/forms/test_option_index_attribute.html @@ -0,0 +1,76 @@ +<!DOCTYPE HTML> +<html> +<!-- +See those bugs: +https://bugzilla.mozilla.org/show_bug.cgi?id=720385 +--> +<head> + <meta charset="utf-8"> + <title>Test for option.index</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=720385">Mozilla Bug 720385</a> +<p id="display"></p> +<div id="content" style="display: none"> + <datalist> + <option></option> + <option></option> + </datalist> + <select> + <option></option> + <foo> + <option></option> + <optgroup> + <option></option> + </optgroup> + <option></option> + </foo> + <option></option> + </select> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 720385 **/ + +var initialIndexes = [ 0, 0, 0, 1, 2, 3, 4 ]; +var options = document.getElementsByTagName('option'); + +is(options.length, initialIndexes.length, + "Must have " + initialIndexes.length +" options"); + +for (var i=0; i<options.length; ++i) { + is(options[i].index, initialIndexes[i], "test"); +} + +var o = document.createElement('option'); +is(o.index, 0, "option outside of a document have index=0"); + +document.body.appendChild(o); +is(o.index, 0, "option outside of a select have index=0"); + +var datalist = document.getElementsByTagName('datalist')[0]; + +datalist.appendChild(o); +is(o.index, 0, "option outside of a select have index=0"); + +datalist.removeChild(o); +is(o.index, 0, "option outside of a select have index=0"); + +var select = document.getElementsByTagName('select')[0]; + +select.appendChild(o); +is(o.index, 5, "option inside a select have an index"); + +select.removeChild(select.options[0]); +is(o.index, 4, "option inside a select have an index"); + +select.insertBefore(o, select.options[0]); +is(o.index, 0, "option inside a select have an index"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_option_text.html b/dom/html/test/forms/test_option_text.html new file mode 100644 index 0000000000..3afe3e786a --- /dev/null +++ b/dom/html/test/forms/test_option_text.html @@ -0,0 +1,57 @@ +<!doctype html> +<meta charset=utf-8> +<title>HTMLOptionElement.text</title> +<link rel=author title=Ms2ger href="mailto:Ms2ger@gmail.com"> +<link rel=help href="http://www.whatwg.org/html/#dom-option-text"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id=log></div> +<script> +test(function() { + var option = document.createElement("option"); + option.appendChild(document.createElement("font")) + .appendChild(document.createTextNode(" font ")); + assert_equals(option.text, "font"); +}, "option.text should recurse"); +test(function() { + var option = document.createElement("option"); + option.appendChild(document.createTextNode(" before ")); + option.appendChild(document.createElement("script")) + .appendChild(document.createTextNode(" script ")); + option.appendChild(document.createTextNode(" after ")); + assert_equals(option.text, "before after"); +}, "option.text should not recurse into HTML script elements"); +test(function() { + var option = document.createElement("option"); + option.appendChild(document.createTextNode(" before ")); + option.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "script")) + .appendChild(document.createTextNode(" script ")); + option.appendChild(document.createTextNode(" after ")); + assert_equals(option.text, "before after"); +}, "option.text should not recurse into SVG script elements"); +test(function() { + var option = document.createElement("option"); + option.appendChild(document.createTextNode(" before ")); + option.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "script")) + .appendChild(document.createTextNode(" script ")); + option.appendChild(document.createTextNode(" after ")); + assert_equals(option.text, "before script after"); +}, "option.text should recurse into MathML script elements"); +test(function() { + var option = document.createElement("option"); + option.appendChild(document.createTextNode(" before ")); + option.appendChild(document.createElementNS(null, "script")) + .appendChild(document.createTextNode(" script ")); + option.appendChild(document.createTextNode(" after ")); + assert_equals(option.text, "before script after"); +}, "option.text should recurse into null script elements"); +test(function() { + var option = document.createElement("option"); + var span = option.appendChild(document.createElement("span")); + span.appendChild(document.createTextNode(" Some ")); + span.appendChild(document.createElement("script")) + .appendChild(document.createTextNode(" script ")); + option.appendChild(document.createTextNode(" Text ")); + assert_equals(option.text, "Some Text"); +}, "option.text should work if a child of the option ends with a script"); +</script> diff --git a/dom/html/test/forms/test_output_element.html b/dom/html/test/forms/test_output_element.html new file mode 100644 index 0000000000..ab11443d83 --- /dev/null +++ b/dom/html/test/forms/test_output_element.html @@ -0,0 +1,182 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=346485 +--> +<head> + <title>Test for Bug 346485</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="../reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + frameLoaded = function() { + is(frames.submit_frame.location.href, "about:blank", + "Blank frame loaded"); + } + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=346485">Mozilla Bug 346485</a> +<p id="display"></p> +<iframe name="submit_frame" onload="frameLoaded()" style="visibility: hidden;"></iframe> +<div id="content" style="display: none"> + <form id='f' method='get' target='submit_frame' action='foo'> + <input name='a' id='a'> + <input name='b' id='b'> + <output id='o' for='a b' name='output-name'>tulip</output> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 346485 **/ + +function checkNameAttribute(element) +{ + is(element.name, "output-name", "Output name IDL attribute is not correct"); + is(element.getAttribute('name'), "output-name", + "Output name content attribute is not correct"); +} + +function checkValueAndDefaultValueIDLAttribute(element) +{ + is(element.value, element.textContent, + "The value IDL attribute should act like the textContent IDL attribute"); + + element.value = "foo"; + is(element.value, "foo", "Value should be 'foo'"); + + is(element.defaultValue, "tulip", "Default defaultValue is 'tulip'"); + + element.defaultValue = "bar"; + is(element.defaultValue, "bar", "defaultValue should be 'bar'"); + + // More complex situation. + element.textContent = 'foo'; + var b = document.createElement('b'); + b.textContent = 'bar' + element.appendChild(b); + is(element.value, element.textContent, + "The value IDL attribute should act like the textContent IDL attribute"); +} + +function checkValueModeFlag(element) +{ + /** + * The value mode flag is the flag used to know if value should represent the + * textContent or the default value. + */ + // value mode flag should be 'value' + isnot(element.defaultValue, element.value, + "When value is set, defaultValue keeps its value"); + + var f = document.getElementById('f'); + f.reset(); + // value mode flag should be 'default' + is(element.defaultValue, element.value, "When reset, defaultValue=value"); + is(element.textContent, element.defaultValue, + "textContent should contain the defaultValue"); +} + +function checkDescendantChanged(element) +{ + /** + * Whenever a descendant is changed if the value mode flag is value, + * the default value should be the textContent value. + */ + element.defaultValue = 'tulip'; + element.value = 'foo'; + + // set value mode flag to 'default' + var f = document.getElementById('f'); + f.reset(); + + is(element.textContent, element.defaultValue, + "textContent should contain the defaultValue"); + element.textContent = "bar"; + is(element.textContent, element.defaultValue, + "textContent should contain the defaultValue"); +} + +function checkFormIDLAttribute(element) +{ + is(element.form, document.getElementById('f'), + "form IDL attribute is invalid"); +} + +function checkHtmlForIDLAttribute(element) +{ + is(String(element.htmlFor), 'a b', + "htmlFor IDL attribute should reflect the for content attribute"); + + // DOMTokenList is tested in another bug so we just test assignation + element.htmlFor.value = 'a b c'; + is(String(element.htmlFor), 'a b c', "htmlFor should have changed"); +} + +function submitForm() +{ + // Setting the values for the submit. + document.getElementById('o').value = 'foo'; + document.getElementById('a').value = 'afield'; + document.getElementById('b').value = 'bfield'; + + frameLoaded = checkFormSubmission; + + // This will call checkFormSubmission() which is going to call ST.finish(). + document.getElementById('f').submit(); +} + +function checkFormSubmission() +{ + /** + * All elements values have been set just before the submission. + * The input elements values should be in the submit url but the ouput + * element value should not appear. + */ + + is(frames.submit_frame.location.href, + `${location.origin}/tests/dom/html/test/forms/foo?a=afield&b=bfield`, + "The output element value should not be submitted"); + SimpleTest.finish(); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + reflectString({ + element: document.createElement("output"), + attribute: "name", + }); + + var o = document.getElementsByTagName('output'); + is(o.length, 1, "There should be one output element"); + + o = o[0]; + ok(o instanceof HTMLOutputElement, + "The output should be instance of HTMLOutputElement"); + + o = document.getElementById('o'); + ok(o instanceof HTMLOutputElement, + "The output should be instance of HTMLOutputElement"); + + is(o.type, "output", "Output type IDL attribute should be 'output'"); + + checkNameAttribute(o); + + checkValueAndDefaultValueIDLAttribute(o); + + checkValueModeFlag(o); + + checkDescendantChanged(o); + + checkFormIDLAttribute(o); + + checkHtmlForIDLAttribute(o); + + submitForm(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_pattern_attribute.html b/dom/html/test/forms/test_pattern_attribute.html new file mode 100644 index 0000000000..71d79c1def --- /dev/null +++ b/dom/html/test/forms/test_pattern_attribute.html @@ -0,0 +1,324 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=345512 +--> +<head> + <title>Test for Bug 345512</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + input { background-color: rgb(0,0,0) !important; } + input:valid { background-color: rgb(0,255,0) !important; } + input:invalid { background-color: rgb(255,0,0) !important; } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=345512">Mozilla Bug 345512</a> +<p id="display"></p> +<div id="content" style="display: none"> + <input id='i' pattern="tulip" oninvalid="invalidEventHandler(event);"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 345512 **/ + +var gInvalid = false; + +function invalidEventHandler(e) +{ + is(e.type, "invalid", "Invalid event type should be invalid"); + gInvalid = true; +} + +function completeValidityCheck(element, alwaysValid, isBarred) +{ + // Check when pattern matches. + if (element.type == 'email') { + element.pattern = ".*@bar.com"; + element.value = "foo@bar.com"; + } else if (element.type == 'url') { + element.pattern = "http://.*\\.com$"; + element.value = "http://mozilla.com"; + } else if (element.type == 'file') { + element.pattern = "foo"; + SpecialPowers.wrap(element).mozSetFileArray([new File(["foo"], "foo")]); + } else { + element.pattern = "foo"; + element.value = "foo"; + } + + checkValidPattern(element, true, isBarred); + + // Check when pattern does not match. + + if (element.type == 'email') { + element.pattern = ".*@bar.com"; + element.value = "foo@foo.com"; + } else if (element.type == 'url') { + element.pattern = "http://.*\\.com$"; + element.value = "http://mozilla.org"; + } else if (element.type == 'file') { + element.pattern = "foo"; + SpecialPowers.wrap(element).mozSetFileArray([new File(["bar"], "bar")]); + } else { + element.pattern = "foo"; + element.value = "bar"; + } + + if (!alwaysValid) { + checkInvalidPattern(element, true); + } else { + checkValidPattern(element, true, isBarred); + } +} + +function checkValidPattern(element, completeCheck, isBarred) +{ + if (completeCheck) { + gInvalid = false; + + ok(!element.validity.patternMismatch, + "Element should not suffer from pattern mismatch"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "Element should be valid"); + ok(!gInvalid, "Invalid event shouldn't have been thrown"); + is(element.validationMessage, '', + "Validation message should be the empty string"); + if (element.type != 'radio' && element.type != 'checkbox') { + is(window.getComputedStyle(element).getPropertyValue('background-color'), + isBarred ? "rgb(0, 0, 0)" : "rgb(0, 255, 0)", + "The pseudo-class is not correctly applied"); + } + } else { + ok(!element.validity.patternMismatch, + "Element should not suffer from pattern mismatch"); + } +} + +function checkInvalidPattern(element, completeCheck) +{ + if (completeCheck) { + gInvalid = false; + + ok(element.validity.patternMismatch, + "Element should suffer from pattern mismatch"); + ok(!element.validity.valid, "Element should not be valid"); + ok(!element.checkValidity(), "Element should not be valid"); + ok(gInvalid, "Invalid event should have been thrown"); + is(element.validationMessage, + "Please match the requested format.", + "Validation message is not valid"); + } else { + ok(element.validity.patternMismatch, + "Element should suffer from pattern mismatch"); + } + + if (element.type != 'radio' && element.type != 'checkbox') { + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(255, 0, 0)", ":invalid pseudo-class should apply"); + } +} + +function checkSyntaxError(element) +{ + ok(!element.validity.patternMismatch, + "On SyntaxError, element should not suffer"); +} + +function checkPatternValidity(element) +{ + element.pattern = "foo"; + + element.value = ''; + checkValidPattern(element); + + element.value = "foo"; + checkValidPattern(element); + + element.value = "bar"; + checkInvalidPattern(element); + + element.value = "foobar"; + checkInvalidPattern(element); + + element.value = "foofoo"; + checkInvalidPattern(element); + + element.pattern = "foo\"bar"; + element.value = "foo\"bar"; + checkValidPattern(element); + + element.value = 'foo"bar'; + checkValidPattern(element); + + element.pattern = "foo'bar"; + element.value = "foo\'bar"; + checkValidPattern(element); + + element.pattern = "foo\\(bar"; + element.value = "foo(bar"; + checkValidPattern(element); + + element.value = "foo"; + checkInvalidPattern(element); + + element.pattern = "foo\\)bar"; + element.value = "foo)bar"; + checkValidPattern(element); + + element.value = "foo"; + checkInvalidPattern(element); + + // Check for 'i' flag disabled. Should be case sensitive. + element.value = "Foo"; + checkInvalidPattern(element); + + // We can't check for the 'g' flag because we only test, we don't execute. + // We can't check for the 'm' flag because .value shouldn't contain line breaks. + + // We need '\\\\' because '\\' will produce '\\' and we want to escape the '\' + // for the regexp. + element.pattern = "foo\\\\bar"; + element.value = "foo\\bar"; + checkValidPattern(element); + + // We may want to escape the ' in the pattern, but this is a SyntaxError + // when unicode flag is set. + element.pattern = "foo\\'bar"; + element.value = "foo'bar"; + checkSyntaxError(element); + element.value = "baz"; + checkSyntaxError(element); + + // We should check the pattern attribute do not pollute |RegExp.lastParen|. + is(RegExp.lastParen, "", "RegExp.lastParen should be the empty string"); + + element.pattern = "(foo)"; + element.value = "foo"; + checkValidPattern(element); + is(RegExp.lastParen, "", "RegExp.lastParen should be the empty string"); + + // That may sound weird but the empty string is a valid pattern value. + element.pattern = ""; + element.value = ""; + checkValidPattern(element); + + element.value = "foo"; + checkInvalidPattern(element); + + // Checking some complex patterns. As we are using js regexp mechanism, these + // tests doesn't aim to test the regexp mechanism. + element.pattern = "\\d{2}\\s\\d{2}\\s\\d{4}" + element.value = "01 01 2010" + checkValidPattern(element); + + element.value = "01/01/2010" + checkInvalidPattern(element); + + element.pattern = "[0-9a-zA-Z]([\\-.\\w]*[0-9a-zA-Z_+])*@([0-9a-zA-Z][\\-\\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9}"; + element.value = "foo@bar.com"; + checkValidPattern(element); + + element.value = "...@bar.com"; + checkInvalidPattern(element); + + element.pattern = "^(?:\\w{3,})$"; + element.value = "foo"; + checkValidPattern(element); + + element.value = "f"; + checkInvalidPattern(element); + + // If @title is specified, it should be added in the validation message. + if (element.type == 'email') { + element.pattern = "foo@bar.com" + element.value = "bar@foo.com"; + } else if (element.type == 'url') { + element.pattern = "http://mozilla.com"; + element.value = "http://mozilla.org"; + } else { + element.pattern = "foo"; + element.value = "bar"; + } + element.title = "this is an explanation of the regexp"; + is(element.validationMessage, + "Please match the requested format: " + element.title + ".", + "Validation message is not valid"); + element.title = ""; + is(element.validationMessage, + "Please match the requested format.", + "Validation message is not valid"); + + element.pattern = "foo"; + if (element.type == 'email') { + element.value = "bar@foo.com"; + } else if (element.type == 'url') { + element.value = "http://mozilla.org"; + } else { + element.value = "bar"; + } + checkInvalidPattern(element); + + element.removeAttribute('pattern'); + checkValidPattern(element, true); + + // Unicode pattern + for (var pattern of ["\\u{1F438}{2}", "\u{1F438}{2}", + "\\uD83D\\uDC38{2}", "\uD83D\uDC38{2}", + "\u{D83D}\u{DC38}{2}"]) { + element.pattern = pattern; + + element.value = "\u{1F438}\u{1F438}"; + checkValidPattern(element); + + element.value = "\uD83D\uDC38\uD83D\uDC38"; + checkValidPattern(element); + + element.value = "\uD83D\uDC38\uDC38"; + checkInvalidPattern(element); + } + + element.pattern = "\\u{D83D}\\u{DC38}{2}"; + + element.value = "\u{1F438}\u{1F438}"; + checkInvalidPattern(element); + + element.value = "\uD83D\uDC38\uD83D\uDC38"; + checkInvalidPattern(element); + + element.value = "\uD83D\uDC38\uDC38"; + checkInvalidPattern(element); +} + +var input = document.getElementById('i'); + +// |validTypes| are the types which accept @pattern +// and |invalidTypes| are the ones which do not accept it. +var validTypes = Array('text', 'password', 'search', 'tel', 'email', 'url'); +var barredTypes = Array('hidden', 'reset', 'button'); +var invalidTypes = Array('checkbox', 'radio', 'file', 'number', 'range', 'date', + 'time', 'color', 'submit', 'image', 'month', 'week', + 'datetime-local'); + +for (type of validTypes) { + input.type = type; + completeValidityCheck(input, false); + checkPatternValidity(input); +} + +for (type of barredTypes) { + input.type = type; + completeValidityCheck(input, true, true); +} + +for (type of invalidTypes) { + input.type = type; + completeValidityCheck(input, true); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_preserving_metadata_between_reloads.html b/dom/html/test/forms/test_preserving_metadata_between_reloads.html new file mode 100644 index 0000000000..07ca05f7ce --- /dev/null +++ b/dom/html/test/forms/test_preserving_metadata_between_reloads.html @@ -0,0 +1,84 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test preserving metadata between page reloads</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css" /> + </head> +<body> +<p id="display"></p> +<div id="content"> + <iframe id="test-frame" width="800px" height="600px" srcdoc=' + <html> + <body> + <h3>Bug 1635224: Preserve mLastValueChangeWasInteractive between reloads</h3> + <div> + <form> + <textarea id="maxlen-textarea" maxlength="2" rows="2" cols="10"></textarea><br/> + <input id="maxlen-inputtext" type="text" maxlength="2"><br/> + <textarea id="minlen-textarea" minlength="8" rows="2" cols="10"></textarea><br/> + <input id="minlen-inputtext" type="text" minlength="8"><br/> + </form> + </div> + </body> + </html> +'></iframe> +</div> + +<pre id="test"> +<script> + SimpleTest.waitForExplicitFinish() + const Ci = SpecialPowers.Ci; + const str = "aaaaa"; + + function afterLoad() { + SimpleTest.waitForFocus(async function () { + await SpecialPowers.pushPrefEnv({"set": [["editor.truncate_user_pastes", false]]}); + var iframeDoc = $("test-frame").contentDocument; + var src = iframeDoc.getElementById("src"); + + function test(fieldId, callback) { + var field = iframeDoc.getElementById(fieldId); + field.focus(); + SimpleTest.waitForClipboard(str, + function () { + SpecialPowers.Cc["@mozilla.org/widget/clipboardhelper;1"] + .getService(Ci.nsIClipboardHelper) + .copyString(str); + }, + function () { + synthesizeKey("v", { accelKey: true }); + is(field.value, "aaaaa", "the value of " + fieldId + " was entered correctly"); + is(field.checkValidity(), false, "the validity of " + fieldId + " should be false"); + $("test-frame").contentWindow.location.reload(); + is(field.value, "aaaaa", "the value of " + fieldId + " persisted correctly"); + is(field.checkValidity(), false, "the validity of " + fieldId + " should be false after reload"); + callback(); + }, + function () { + ok(false, "Failed to copy the string"); + SimpleTest.finish(); + } + ); + } + + function runNextTest() { + if (fieldIds.length) { + var currentFieldId = fieldIds.shift(); + test(currentFieldId, runNextTest); + } else { + SimpleTest.finish(); + } + } + + var fieldIds = ["maxlen-textarea", "maxlen-inputtext", "minlen-textarea", "minlen-inputtext"]; + runNextTest(); + }); + } + addLoadEvent(afterLoad); +</script> +</pre> +</body> +</html>
\ No newline at end of file diff --git a/dom/html/test/forms/test_progress_element.html b/dom/html/test/forms/test_progress_element.html new file mode 100644 index 0000000000..065adf94ea --- /dev/null +++ b/dom/html/test/forms/test_progress_element.html @@ -0,0 +1,307 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=514437 +https://bugzilla.mozilla.org/show_bug.cgi?id=633913 +--> +<head> + <title>Test for progress element content and layout</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=514437">Mozilla Bug 514437</a> +and +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=633913">Mozilla Bug 633913</a> +<p id="display"></p> +<iframe name="submit_frame" style="visibility: hidden;"></iframe> +<div id="content" style="visibility: hidden;"> + <form id='f' method='get' target='submit_frame' action='foo'> + <progress id='p'></progress> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +SimpleTest.expectAssertions(0, 1); + +/** Test for progress element content and layout **/ + +function checkFormIDLAttribute(aElement) +{ + is("form" in aElement, false, "<progress> shouldn't have a form attribute"); +} + +function checkAttribute(aElement, aAttribute, aNewValue, aExpectedValueForIDL) +{ + var expectedValueForIDL = aNewValue; + var expectedValueForContent = String(aNewValue); + + if (aExpectedValueForIDL !== undefined) { + expectedValueForIDL = aExpectedValueForIDL; + } + + if (aNewValue != null) { + aElement.setAttribute(aAttribute, aNewValue); + is(aElement.getAttribute(aAttribute), expectedValueForContent, + aAttribute + " content attribute should be " + expectedValueForContent); + is(aElement[aAttribute], expectedValueForIDL, + aAttribute + " IDL attribute should be " + expectedValueForIDL); + + if (parseFloat(aNewValue) == aNewValue) { + aElement[aAttribute] = aNewValue; + is(aElement.getAttribute(aAttribute), expectedValueForContent, + aAttribute + " content attribute should be " + expectedValueForContent); + is(aElement[aAttribute], parseFloat(expectedValueForIDL), + aAttribute + " IDL attribute should be " + parseFloat(expectedValueForIDL)); + } + } else { + aElement.removeAttribute(aAttribute); + is(aElement.getAttribute(aAttribute), null, + aAttribute + " content attribute should be null"); + is(aElement[aAttribute], expectedValueForIDL, + aAttribute + " IDL attribute should be " + expectedValueForIDL); + } +} + +function checkValueAttribute() +{ + var tests = [ + // value has to be a valid float, its default value is 0.0 otherwise. + [ null, 0.0 ], + [ 'fo', 0.0 ], + // If value < 0.0, 0.0 is used instead. + [ -1.0, 0.0 ], + // If value >= max, max is used instead (max default value is 1.0). + [ 2.0, 1.0 ], + [ 1.0, 0.5, 0.5 ], + [ 10.0, 5.0, 5.0 ], + [ 13.37, 13.37, 42.0 ], + // Regular reflection. + [ 0.0 ], + [ 0.5 ], + [ 1.0 ], + // Check double-precision value. + [ 0.234567898765432 ], + ]; + + var element = document.createElement('progress'); + + for (var test of tests) { + if (test[2]) { + element.setAttribute('max', test[2]); + } + + checkAttribute(element, 'value', test[0], test[1]); + + element.removeAttribute('max'); + } +} + +function checkMaxAttribute() +{ + var tests = [ + // max default value is 1.0. + [ null, 1.0 ], + // If value <= 0.0, 1.0 is used instead. + [ 0.0, 1.0 ], + [ -1.0, 1.0 ], + // Regular reflection. + [ 0.5 ], + [ 1.0 ], + [ 2.0 ], + // Check double-precision value. + [ 0.234567898765432 ], + ]; + + var element = document.createElement('progress'); + + for (var test of tests) { + checkAttribute(element, 'max', test[0], test[1]); + } +} + +function checkPositionAttribute() +{ + function checkPositionValue(aElement, aValue, aMax, aExpected) { + if (aValue != null) { + aElement.setAttribute('value', aValue); + } else { + aElement.removeAttribute('value'); + } + + if (aMax != null) { + aElement.setAttribute('max', aMax); + } else { + aElement.removeAttribute('max'); + } + + is(aElement.position, aExpected, "position IDL attribute should be " + aExpected); + } + + var tests = [ + // value has to be defined (indeterminate state). + [ null, null, -1.0 ], + [ null, 1.0, -1.0 ], + // value has to be defined to a valid float (indeterminate state). + [ 'foo', 1.0, -1.0 ], + // If value < 0.0, 0.0 is used instead. + [ -1.0, 1.0, 0.0 ], + // If value >= max, max is used instead. + [ 2.0, 1.0, 1.0 ], + // If max isn't present, max is set to 1.0. + [ 1.0, null, 1.0 ], + // If max isn't a valid float, max is set to 1.0. + [ 1.0, 'foo', 1.0 ], + // If max isn't > 0, max is set to 1.0. + [ 1.0, -1.0, 1.0 ], + // A few simple and valid values. + [ 0.0, 1.0, 0.0 ], + [ 0.1, 1.0, 0.1/1.0 ], + [ 0.1, 2.0, 0.1/2.0 ], + [ 10, 50, 10/50 ], + // Values implying .position is a double. + [ 1.0, 3.0, 1.0/3.0 ], + [ 0.1, 0.7, 0.1/0.7 ], + ]; + + var element = document.createElement('progress'); + + for (var test of tests) { + checkPositionValue(element, test[0], test[1], test[2], test[3]); + } +} + +function checkIndeterminatePseudoClass() +{ + function checkIndeterminate(aElement, aValue, aMax, aIndeterminate) { + if (aValue != null) { + aElement.setAttribute('value', aValue); + } else { + aElement.removeAttribute('value'); + } + + if (aMax != null) { + aElement.setAttribute('max', aMax); + } else { + aElement.removeAttribute('max'); + } + + is(aElement.matches("progress:indeterminate"), aIndeterminate, + "<progress> indeterminate state should be " + aIndeterminate); + } + + var tests = [ + // Indeterminate state: (value is undefined, or not a float) + // value has to be defined (indeterminate state). + [ null, null, true ], + [ null, 1.0, true ], + [ 'foo', 1.0, true ], + // Determined state: + [ -1.0, 1.0, false ], + [ 2.0, 1.0, false ], + [ 1.0, null, false ], + [ 1.0, 'foo', false ], + [ 1.0, -1.0, false ], + [ 0.0, 1.0, false ], + ]; + + var element = document.createElement('progress'); + + for (var test of tests) { + checkIndeterminate(element, test[0], test[1], test[2]); + } +} + +function checkFormListedElement(aElement) +{ + is(document.forms[0].elements.length, 0, "the form should have no element"); +} + +function checkLabelable(aElement) +{ + var content = document.getElementById('content'); + var label = document.createElement('label'); + + content.appendChild(label); + label.appendChild(aElement); + is(label.control, aElement, "progress should be labelable"); + + // Cleaning-up. + content.removeChild(label); + content.appendChild(aElement); +} + +function checkNotResetableAndFormSubmission(aElement) +{ + // Creating an input element to check the submission worked. + var form = document.forms[0]; + var input = document.createElement('input'); + + input.name = 'a'; + input.value = 'tulip'; + form.appendChild(input); + + // Setting values. + aElement.value = 42.0; + aElement.max = 100.0; + + document.getElementsByName('submit_frame')[0].addEventListener("load", function() { + is(frames.submit_frame.location.href, + `${location.origin}/tests/dom/html/test/forms/foo?a=tulip`, + "The progress element value should not be submitted"); + + checkNotResetable(); + }, {once: true}); + + form.submit(); +} + +function checkNotResetable() +{ + // Try to reset the form. + var form = document.forms[0]; + var element = document.getElementById('p'); + + element.value = 3.0; + element.max = 42.0; + + form.reset(); + + SimpleTest.executeSoon(function() { + is(element.value, 3.0, "progress.value should not have changed"); + is(element.max, 42.0, "progress.max should not have changed"); + + SimpleTest.finish(); + }); +} + +SimpleTest.waitForExplicitFinish(); + +var p = document.getElementById('p'); + +ok(p instanceof HTMLProgressElement, + "The progress element should be instance of HTMLProgressElement"); +is(p.constructor, HTMLProgressElement, + "The progress element constructor should be HTMLProgressElement"); + +checkFormIDLAttribute(p); + +checkValueAttribute(); + +checkMaxAttribute(); + +checkPositionAttribute(); + +checkIndeterminatePseudoClass(); + +checkFormListedElement(p); + +checkLabelable(p); + +checkNotResetableAndFormSubmission(p); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_radio_in_label.html b/dom/html/test/forms/test_radio_in_label.html new file mode 100644 index 0000000000..7e8a232cc3 --- /dev/null +++ b/dom/html/test/forms/test_radio_in_label.html @@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=229925 +--> +<head> + <title>Test for Bug 229925</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=229925">Mozilla Bug 229925</a> +<p id="display"></p> +<form> + <label> + <span id="s1">LABEL</span> + <input type="radio" name="rdo" value="1" id="r1" onmousedown="document.body.appendChild(document.createTextNode('down'));"> + <input type="radio" name="rdo" value="2" id="r2" checked="checked"> + </label> +</form> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 229925 **/ +SimpleTest.waitForExplicitFinish(); +var r1 = document.getElementById("r1"); +var r2 = document.getElementById("r2"); +var s1 = document.getElementById("s1"); +startTest(); +function startTest() { + r1.click(); + ok(r1.checked, + "The first radio input element should be checked by clicking the element"); + r2.click(); + ok(r2.checked, + "The second radio input element should be checked by clicking the element"); + s1.click(); + ok(r1.checked, + "The first radio input element should be checked by clicking other element"); + + r1.focus(); + synthesizeKey("KEY_ArrowLeft"); + ok(r2.checked, + "The second radio input element should be checked by key"); + synthesizeKey("KEY_ArrowLeft"); + ok(r1.checked, + "The first radio input element should be checked by key"); + SimpleTest.finish(); +} +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_radio_radionodelist.html b/dom/html/test/forms/test_radio_radionodelist.html new file mode 100644 index 0000000000..8761c22b58 --- /dev/null +++ b/dom/html/test/forms/test_radio_radionodelist.html @@ -0,0 +1,57 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=779723 +--> +<head> + <title>Test for Bug 779723</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=779723">Mozilla Bug 779723</a> +<p id="display"></p> +<form> + <input type="checkbox" name="rdo" value="0" id="r0" checked="checked"> + <input type="radio" name="rdo" id="r1"> + <input type="radio" name="rdo" id="r2" value="2"> +</form> +<script class="testbody" type="text/javascript"> +/** Test for Bug 779723 **/ + +var rdoList = document.forms[0].elements.namedItem('rdo'); +is(rdoList.value, "", "The value attribute should be empty"); + +document.getElementById('r2').checked = true; +is(rdoList.value, "2", "The value attribute should be 2"); + +document.getElementById('r1').checked = true; +is(rdoList.value, "on", "The value attribute should be on"); + +document.getElementById('r1').value = 1; +is(rdoList.value, "1", "The value attribute should be 1"); + +is(rdoList.value, document.getElementById('r1').value, + "The value attribute should be equal to the first checked radio input element's value"); +ok(!document.getElementById('r2').checked, + "The second radio input element should not be checked"); + +rdoList.value = '2'; +is(rdoList.value, document.getElementById('r2').value, + "The value attribute should be equal to the second radio input element's value"); +ok(document.getElementById('r2').checked, + "The second radio input element should be checked"); + +rdoList.value = '3'; +is(rdoList.value, document.getElementById('r2').value, + "The value attribute should be the second radio input element's value"); +ok(document.getElementById('r2').checked, + "The second radio input element should be checked"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/forms/test_reportValidation_preventDefault.html b/dom/html/test/forms/test_reportValidation_preventDefault.html new file mode 100644 index 0000000000..3f3b99d140 --- /dev/null +++ b/dom/html/test/forms/test_reportValidation_preventDefault.html @@ -0,0 +1,89 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1088761 +--> +<head> + <title>Test for Bug 1088761</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + input, textarea, fieldset, button, select, output, object { background-color: rgb(0,0,0) !important; } + :valid { background-color: rgb(0,255,0) !important; } + :invalid { background-color: rgb(255,0,0) !important; } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1088761">Mozilla Bug 1088761</a> +<p id="display"></p> +<div id="content" style="display: none"> + <fieldset id='f' oninvalid="invalidEventHandler(event, true);"></fieldset> + <input id='i' required oninvalid="invalidEventHandler(event, true);"> + <button id='b' oninvalid="invalidEventHandler(event, true);"></button> + <select id='s' required oninvalid="invalidEventHandler(event, true);"></select> + <textarea id='t' required oninvalid="invalidEventHandler(event, true);"></textarea> + <output id='o' oninvalid="invalidEventHandler(event, true);"></output> + <object id='obj' oninvalid="invalidEventHandler(event, true);"></object> +</div> +<div id="content2" style="display: none"> + <fieldset id='f2' oninvalid="invalidEventHandler(event, false);"></fieldset> + <input id='i2' required oninvalid="invalidEventHandler(event, false);"> + <button id='b2' oninvalid="invalidEventHandler(event, false);"></button> + <select id='s2' required oninvalid="invalidEventHandler(event, false);"></select> + <textarea id='t2' required oninvalid="invalidEventHandler(event, false);"></textarea> + <output id='o2' oninvalid="invalidEventHandler(event, false);"></output> + <object id='obj2' oninvalid="invalidEventHandler(event, false);"></object> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 1088761 **/ + +var gInvalid = false; + +function invalidEventHandler(aEvent, isPreventDefault) +{ + if (isPreventDefault) { + aEvent.preventDefault(); + } + + is(aEvent.type, "invalid", "Invalid event type should be invalid"); + ok(!aEvent.bubbles, "Invalid event should not bubble"); + ok(aEvent.cancelable, "Invalid event should be cancelable"); + gInvalid = true; +} + +function checkReportValidityForInvalid(element) +{ + gInvalid = false; + ok(!element.reportValidity(), "reportValidity() should return false when the element is not valid"); + ok(gInvalid, "Invalid event should have been handled"); +} + +function checkReportValidityForValid(element) +{ + gInvalid = false; + ok(element.reportValidity(), "reportValidity() should return true when the element is valid"); + ok(!gInvalid, "Invalid event shouldn't have been handled"); +} + +checkReportValidityForInvalid(document.getElementById('i')); +checkReportValidityForInvalid(document.getElementById('s')); +checkReportValidityForInvalid(document.getElementById('t')); + +checkReportValidityForInvalid(document.getElementById('i2')); +checkReportValidityForInvalid(document.getElementById('s2')); +checkReportValidityForInvalid(document.getElementById('t2')); + +checkReportValidityForValid(document.getElementById('o')); +checkReportValidityForValid(document.getElementById('obj')); +checkReportValidityForValid(document.getElementById('f')); + +checkReportValidityForValid(document.getElementById('o2')); +checkReportValidityForValid(document.getElementById('obj2')); +checkReportValidityForValid(document.getElementById('f2')); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_required_attribute.html b/dom/html/test/forms/test_required_attribute.html new file mode 100644 index 0000000000..a95a5cc339 --- /dev/null +++ b/dom/html/test/forms/test_required_attribute.html @@ -0,0 +1,416 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=345822 +--> +<head> + <title>Test for Bug 345822</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=345822">Mozilla Bug 345822</a> +<p id="display"></p> +<div id="content"> + <form> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 345822 **/ + +function checkNotSufferingFromBeingMissing(element, doNotApply) +{ + ok(!element.validity.valueMissing, + "Element should not suffer from value missing"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "Element should be valid"); + is(element.validationMessage, "", + "Validation message should be the empty string"); + + if (doNotApply) { + ok(!element.matches(':valid'), ":valid should not apply"); + ok(!element.matches(':invalid'), ":invalid should not apply"); + } else { + ok(element.matches(':valid'), ":valid should apply"); + ok(!element.matches(':invalid'), ":invalid should not apply"); + } +} + +function checkSufferingFromBeingMissing(element) +{ + ok(element.validity.valueMissing, "Element should suffer from value missing"); + ok(!element.validity.valid, "Element should not be valid"); + ok(!element.checkValidity(), "Element should not be valid"); + + if (element.type == 'checkbox') + { + is(element.validationMessage, + "Please check this box if you want to proceed.", + "Validation message is wrong"); + } + else if (element.type == 'radio') + { + is(element.validationMessage, + "Please select one of these options.", + "Validation message is wrong"); + } + else if (element.type == 'file') + { + is(element.validationMessage, + "Please select a file.", + "Validation message is wrong"); + } + else if (element.type == 'number') + { + is(element.validationMessage, + "Please enter a number.", + "Validation message is wrong"); + } + else // text fields + { + is(element.validationMessage, + "Please fill out this field.", + "Validation message is wrong"); + } + + ok(!element.matches(':valid'), ":valid should apply"); + ok(element.matches(':invalid'), ":invalid should not apply"); +} + +function checkTextareaRequiredValidity() +{ + var element = document.createElement('textarea'); + document.forms[0].appendChild(element); + + SpecialPowers.wrap(element).value = ''; + element.required = false; + checkNotSufferingFromBeingMissing(element); + + element.required = true; + checkSufferingFromBeingMissing(element); + + element.readOnly = true; + checkNotSufferingFromBeingMissing(element, true); + + element.readOnly = false; + checkSufferingFromBeingMissing(element); + + SpecialPowers.wrap(element).value = 'foo'; + checkNotSufferingFromBeingMissing(element); + + SpecialPowers.wrap(element).value = ''; + checkSufferingFromBeingMissing(element); + + element.required = false; + checkNotSufferingFromBeingMissing(element); + + element.focus(); + element.required = true; + SpecialPowers.wrap(element).value = 'foobar'; + element.blur(); + element.form.reset(); + checkSufferingFromBeingMissing(element); + + SpecialPowers.wrap(element).value = ''; + element.form.reportValidity(); + checkSufferingFromBeingMissing(element); + + element.form.reset(); + checkSufferingFromBeingMissing(element); + + // TODO: for the moment, a textarea outside of a document is mutable. + SpecialPowers.wrap(element).value = ''; // To make -moz-ui-valid apply. + element.required = false; + document.forms[0].removeChild(element); + checkNotSufferingFromBeingMissing(element); +} + +function checkInputRequiredNotApply(type, isBarred) +{ + var element = document.createElement('input'); + element.type = type; + document.forms[0].appendChild(element); + + SpecialPowers.wrap(element).value = ''; + element.required = false; + checkNotSufferingFromBeingMissing(element, isBarred); + + element.required = true; + checkNotSufferingFromBeingMissing(element, isBarred); + + element.required = false; + + document.forms[0].removeChild(element); + checkNotSufferingFromBeingMissing(element, isBarred); +} + +function checkInputRequiredValidity(type) +{ + var element = document.createElement('input'); + element.type = type; + document.forms[0].appendChild(element); + + SpecialPowers.wrap(element).value = ''; + element.required = false; + checkNotSufferingFromBeingMissing(element); + + element.required = true; + checkSufferingFromBeingMissing(element); + + element.readOnly = true; + checkNotSufferingFromBeingMissing(element, true); + + element.readOnly = false; + checkSufferingFromBeingMissing(element); + + if (element.type == 'email') { + SpecialPowers.wrap(element).value = 'foo@bar.com'; + } else if (element.type == 'url') { + SpecialPowers.wrap(element).value = 'http://mozilla.org/'; + } else if (element.type == 'number') { + SpecialPowers.wrap(element).value = '42'; + } else if (element.type == 'date') { + SpecialPowers.wrap(element).value = '2010-10-10'; + } else if (element.type == 'time') { + SpecialPowers.wrap(element).value = '21:21'; + // TODO: Bug 1864327. This test is wrong, and needs fixing properly. + // eslint-disable-next-line no-cond-assign + } else if (element.type = 'month') { + SpecialPowers.wrap(element).value = '2010-10'; + } else { + SpecialPowers.wrap(element).value = 'foo'; + } + checkNotSufferingFromBeingMissing(element); + + SpecialPowers.wrap(element).value = ''; + checkSufferingFromBeingMissing(element); + + element.focus(); + element.required = true; + SpecialPowers.wrap(element).value = 'foobar'; + element.blur(); + element.form.reset(); + checkSufferingFromBeingMissing(element); + + SpecialPowers.wrap(element).value = ''; + element.form.reportValidity(); + checkSufferingFromBeingMissing(element); + + element.form.reset(); + checkSufferingFromBeingMissing(element); + + element.required = true; + SpecialPowers.wrap(element).value = ''; // To make :-moz-ui-valid apply. + checkSufferingFromBeingMissing(element); + document.forms[0].removeChild(element); + // Removing the child changes nothing about whether it's valid + checkSufferingFromBeingMissing(element); +} + +function checkInputRequiredValidityForCheckbox() +{ + var element = document.createElement('input'); + element.type = 'checkbox'; + document.forms[0].appendChild(element); + + element.checked = false; + element.required = false; + checkNotSufferingFromBeingMissing(element); + + element.required = true; + checkSufferingFromBeingMissing(element); + + element.checked = true; + checkNotSufferingFromBeingMissing(element); + + element.checked = false; + checkSufferingFromBeingMissing(element); + + element.required = false; + checkNotSufferingFromBeingMissing(element); + + element.focus(); + element.required = true; + element.checked = true; + element.blur(); + element.form.reset(); + checkSufferingFromBeingMissing(element); + + element.required = true; + element.checked = false; + element.form.reportValidity(); + checkSufferingFromBeingMissing(element); + + element.form.reset(); + checkSufferingFromBeingMissing(element); + + element.required = true; + element.checked = false; + document.forms[0].removeChild(element); + checkSufferingFromBeingMissing(element); +} + +function checkInputRequiredValidityForRadio() +{ + var element = document.createElement('input'); + element.type = 'radio'; + element.name = 'test' + document.forms[0].appendChild(element); + + element.checked = false; + element.required = false; + checkNotSufferingFromBeingMissing(element); + + element.required = true; + checkSufferingFromBeingMissing(element); + + element.checked = true; + checkNotSufferingFromBeingMissing(element); + + element.checked = false; + checkSufferingFromBeingMissing(element); + + // A required radio button should not suffer from value missing if another + // radio button from the same group is checked. + var element2 = document.createElement('input'); + element2.type = 'radio'; + element2.name = 'test'; + + element2.checked = true; + element2.required = false; + document.forms[0].appendChild(element2); + + // Adding a checked radio should make required radio in the group not + // suffering from being missing. + checkNotSufferingFromBeingMissing(element); + + element.checked = false; + element2.checked = false; + checkSufferingFromBeingMissing(element); + + // The other radio button should not be disabled. + // A disabled checked radio button in the radio group + // is enough to not suffer from value missing. + element2.checked = true; + element2.disabled = true; + checkNotSufferingFromBeingMissing(element); + + // If a radio button is not required but another radio button is required in + // the same group, the not required radio button should suffer from value + // missing. + element2.disabled = false; + element2.checked = false; + element.required = false; + element2.required = true; + checkSufferingFromBeingMissing(element); + checkSufferingFromBeingMissing(element2); + + element.checked = true; + checkNotSufferingFromBeingMissing(element2); + + // The checked radio is not in the group anymore, element2 should be invalid. + element.form.removeChild(element); + checkNotSufferingFromBeingMissing(element); + checkSufferingFromBeingMissing(element2); + + element2.focus(); + element2.required = true; + element2.checked = true; + element2.blur(); + element2.form.reset(); + checkSufferingFromBeingMissing(element2); + + element2.required = true; + element2.checked = false; + element2.form.reportValidity(); + checkSufferingFromBeingMissing(element2); + + element2.form.reset(); + checkSufferingFromBeingMissing(element2); + + element2.required = true; + element2.checked = false; + document.forms[0].removeChild(element2); + checkSufferingFromBeingMissing(element2); +} + +function checkInputRequiredValidityForFile() +{ + var element = document.createElement('input'); + element.type = 'file' + document.forms[0].appendChild(element); + + var file = new File([""], "345822_file"); + + SpecialPowers.wrap(element).value = ""; + element.required = false; + checkNotSufferingFromBeingMissing(element); + + element.required = true; + checkSufferingFromBeingMissing(element); + + SpecialPowers.wrap(element).mozSetFileArray([file]); + checkNotSufferingFromBeingMissing(element); + + SpecialPowers.wrap(element).value = ""; + checkSufferingFromBeingMissing(element); + + element.required = false; + checkNotSufferingFromBeingMissing(element); + + element.focus(); + SpecialPowers.wrap(element).mozSetFileArray([file]); + element.required = true; + element.blur(); + element.form.reset(); + checkSufferingFromBeingMissing(element); + + element.required = true; + SpecialPowers.wrap(element).value = ''; + element.form.reportValidity(); + checkSufferingFromBeingMissing(element); + + element.form.reset(); + checkSufferingFromBeingMissing(element); + + element.required = true; + SpecialPowers.wrap(element).value = ''; + document.forms[0].removeChild(element); + checkSufferingFromBeingMissing(element); +} + +checkTextareaRequiredValidity(); + +// The require attribute behavior depend of the input type. +// First of all, checks for types that make the element barred from +// constraint validation. +var typeBarredFromConstraintValidation = ["hidden", "button", "reset"]; +for (type of typeBarredFromConstraintValidation) { + checkInputRequiredNotApply(type, true); +} + +// Then, checks for the types which do not use the required attribute. +var typeRequireNotApply = ['range', 'color', 'submit', 'image']; +for (type of typeRequireNotApply) { + checkInputRequiredNotApply(type, false); +} + +// Now, checking for all types which accept the required attribute. +var typeRequireApply = ["text", "password", "search", "tel", "email", "url", + "number", "date", "time", "month", "week", + "datetime-local"]; + +for (type of typeRequireApply) { + checkInputRequiredValidity(type); +} + +checkInputRequiredValidityForCheckbox(); +checkInputRequiredValidityForRadio(); +checkInputRequiredValidityForFile(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_restore_form_elements.html b/dom/html/test/forms/test_restore_form_elements.html new file mode 100644 index 0000000000..be22a29b7b --- /dev/null +++ b/dom/html/test/forms/test_restore_form_elements.html @@ -0,0 +1,174 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=737851 +--> +<head> + <meta charset="utf-8"> + + <title>Test for Bug 737851</title> + + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<body> + +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=737851">Mozilla Bug 737851</a> + +<p id="display"></p> + + +<div id="content"> + + <iframe id="frame" width="800px" height="600px" srcdoc=' + <html> + <body style="display:none;"> + + <h3>Checking persistence of inputs through js inserts and moves</h3> + <div id="test"> + <input id="a"/> + <input id="b"/> + <form id="form1"> + <input id="c"/> + <input id="d"/> + </form> + <form id="form2"> + <input id="radio1" type="radio" name="radio"/> + <input type="radio" name="radio"/> + <input type="radio" name="radio"/> + <input type="radio" name="radio"/> + </form> + <input id="e"/> + </div> + + <h3>Bug 728798: checking persistence of inputs when forward-using @form</h3> + <div> + <input id="728798-a" form="728798-form" name="a"/> + <form id="728798-form"> + <input id="728798-b" form="728798-form" name="b"/> + <input id="728798-c" name="c"/> + </form> + <input id="728798-d" form="728798-form" name="d"/> + </div> + + </body> + </html> + '></iframe> + +</div> + + +<pre id="test"> +<script type="text/javascript"> + +var frameElem = document.getElementById("frame"); +var frame = frameElem.contentWindow; + + +/* -- Main test run -- */ + +SimpleTest.waitForExplicitFinish(); + +addLoadEvent(function() { + shuffle(); + fill(); + frameElem.addEventListener("load", function() { + shuffle(); + checkAllFields(); + SimpleTest.finish(); + }); + frame.location.reload(); +}) + + +/* -- Input fields js changes and moves -- */ + +function shuffle() { + var framedoc = frame.document; + + // Insert a button (toplevel) + var btn = framedoc.createElement("button"); + var testdiv = framedoc.getElementById("test"); + testdiv.insertBefore(btn, framedoc.getElementById("b")); + + // Insert a dynamically generated input (in a form) + var newInput = framedoc.createElement("input"); + newInput.setAttribute("id","c0"); + var form1 = framedoc.getElementById("form1"); + form1.insertBefore(newInput, form1.firstChild); + + // Move an input around + var inputD = framedoc.getElementById("d"); + var form2 = framedoc.getElementById("form2"); + form2.insertBefore(inputD, form2.firstChild) + + // Clone an existing input + var inputE2 = framedoc.getElementById("e").cloneNode(true); + inputE2.setAttribute("id","e2"); + testdiv.appendChild(inputE2); +} + + +/* -- Input fields fill & check -- */ + +/* Values entered in the input fields (by id) */ + +var fieldValues = { + 'a':'simple input', + 'b':'moved by inserting a button before (no form)', + 'c0':'dynamically generated input', + 'c':'moved by inserting an input before (in a form)', + 'd':'moved from a form to another', + 'e':'the original', + 'e2':'the clone', + '728798-a':'before the form', + '728798-b':'from within the form', + '728798-c':'no form attribute in the form', + '728798-d':'after the form' +} + +/* Fields for which the input is changed, and corresponding value + (clone and creation, same behaviour as webkit) */ + +var changedFields = { + // dynamically generated input field not preserved + 'c0':'', + // cloned input field is restored with the value of the original + 'e2':fieldValues.e +} + +/* Simulate user input by entering the values */ + +function fill() { + for (id in fieldValues) { + frame.document.getElementById(id).value = fieldValues[id]; + } + // an input is inserted before the radios (that may move the selected one by 1) + frame.document.getElementById('radio1').checked = true; +} + +/* Check that all the fields are as they have been entered */ + +function checkAllFields() { + + for (id in fieldValues) { + var fieldValue = frame.document.getElementById(id).value; + if (changedFields[id] === undefined) { + is(fieldValue, fieldValues[id], + "Field "+id+" should be restored after reload"); + } else { + is(fieldValue, changedFields[id], + "Field "+id+" normally gets a different value after reload"); + } + } + + ok(frame.document.getElementById('radio1').checked, + "Radio button radio1 should be restored after reload") + +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_save_restore_custom_elements.html b/dom/html/test/forms/test_save_restore_custom_elements.html new file mode 100644 index 0000000000..489ad0ca2f --- /dev/null +++ b/dom/html/test/forms/test_save_restore_custom_elements.html @@ -0,0 +1,90 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1556358 +--> + +<head> + <title>Test for Bug 1556358</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> + +<body> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1556358">Mozilla Bug 1556358</a> + <p id="display"></p> + <div id="content"> + <iframe src="save_restore_custom_elements_sample.html"></iframe> + </div> + <script type="application/javascript"> + /** Test for Bug 1556358 **/ + + function formDataWith(...entries) { + const formData = new FormData(); + for (let [key, value] of entries) { + formData.append(key, value); + } + return formData; + } + + const states = [ + "test state", + new File(["state"], "state.txt"), + formDataWith(["1", "state"], ["2", new Blob(["state_blob"])]), + null, + undefined, + ]; + const values = [ + "test value", + new File(["value"], "value.txt"), + formDataWith(["1", "value"], ["2", new Blob(["value_blob"])]), + "null state", + "both value and state", + ]; + + add_task(async () => { + const frame = document.querySelector("iframe"); + const elementTags = ["c-e", "upgraded-ce"]; + + // Set the custom element values. + for (const tags of elementTags) { + [...frame.contentDocument.querySelectorAll(tags)] + .forEach((e, i) => { + e.set(states[i], values[i]); + }); + } + + await new Promise(resolve => { + frame.addEventListener("load", resolve); + frame.contentWindow.location.reload(); + }); + + for (const tag of elementTags) { + // Retrieve the restored values. + const ceStates = + [...frame.contentDocument.querySelectorAll(tag)].map((e) => e.state); + is(ceStates.length, 5, "Should have 5 custom element states"); + + const [restored, original] = [ceStates, states]; + is(restored[0], original[0], "Value should be restored"); + + const file = restored[1]; + isnot(file, original[1], "Restored file object differs from original object."); + is(file.name, original[1].name, "File name should be restored"); + is(await file.text(), await original[1].text(), "File text should be restored"); + + const formData = restored[2]; + isnot(formData, original[2], "Restored formdata object differs from original object."); + is(formData.get("1"), original[2].get("1"), "Form data string should be restored"); + is(await formData.get("2").text(), await original[2].get("2").text(), "Form data blob should be restored"); + + isnot(restored[3], original[3], "Null values don't get restored"); + is(restored[3], undefined, "Null values don't get restored"); + + is(restored[4], "both value and state", "Undefined state should be set to value"); + } + }); + </script> +</body> + +</html> diff --git a/dom/html/test/forms/test_save_restore_radio_groups.html b/dom/html/test/forms/test_save_restore_radio_groups.html new file mode 100644 index 0000000000..c5ef924a0e --- /dev/null +++ b/dom/html/test/forms/test_save_restore_radio_groups.html @@ -0,0 +1,70 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=350022 +--> +<head> + <title>Test for Bug 350022</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=350022">Mozilla Bug 350022</a> +<p id="display"></p> +<div id="content"><!-- style="display: none">--> + <iframe src="save_restore_radio_groups.sjs"></iframe> + <iframe src="save_restore_radio_groups.sjs"></iframe> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 350022 **/ + +function checkRadioGroup(aFrame, aResults) +{ + var radios = frames[aFrame].document.getElementsByTagName('input'); + + is(radios.length, aResults.length, + "Radio group should have " + aResults.length + "elements"); + + for (var i=0; i<aResults.length; ++i) { + is(radios[i].checked, aResults[i], + "Radio checked state should be " + aResults[i]); + } +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + /** + * We have two iframes each containing one radio button group. + * We are going to change the selected radio button in one group. + * Then, both iframes will be reloaded and the new groups will have another + * radio checked by default. + * For the first group (which had a selection change), nothing should change. + * For the second, the selected radio button should change. + */ + checkRadioGroup(0, [true, false, false]); + checkRadioGroup(1, [true, false, false]); + + frames[0].document.getElementsByTagName('input')[2].checked = true; + checkRadioGroup(0, [false, false, true]); + + framesElts = document.getElementsByTagName('iframe'); + framesElts[0].addEventListener("load", function() { + checkRadioGroup(0, [false, false, true]); + + framesElts[1].addEventListener("load", function() { + checkRadioGroup(1, [false, true, false]); + SimpleTest.finish(); + }, {once: true}); + + frames[1].location.reload(); + }, {once: true}); + + frames[0].location.reload(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_select_change_event.html b/dom/html/test/forms/test_select_change_event.html new file mode 100644 index 0000000000..ec3ed58c5e --- /dev/null +++ b/dom/html/test/forms/test_select_change_event.html @@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1265968 +--> +<head> + <title>Test for Bug 1265968</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1265968">Mozilla Bug 1265968</a> +<p id="display"></p> +<div id="content"> + <select id="select" onchange="++selectChange;"> + <option>one</option> + <option>two</option> + <option>three</option> + <option>four</option> + <option>five</option> + </select> +</div> +<pre id="test"> +<script type="application/javascript"> + var select = document.getElementById("select"); + var selectChange = 0; + var expectedChange = 0; + + select.focus(); + for (var i = 1; i < select.length; i++) { + synthesizeKey("KEY_ArrowDown"); + is(select.options[i].selected, true, "Option should be selected"); + is(selectChange, ++expectedChange, "Down key should fire change event."); + } + + // We are at the end of the list, going down should not fire change event. + synthesizeKey("KEY_ArrowDown"); + is(selectChange, expectedChange, "Down key should not fire change event when reaching end of the list."); + + for (var i = select.length - 2; i >= 0; i--) { + synthesizeKey("KEY_ArrowUp"); + is(select.options[i].selected, true, "Option should be selected"); + is(selectChange, ++expectedChange, "Up key should fire change event."); + } + + // We are at the top of the list, going up should not fire change event. + synthesizeKey("KEY_ArrowUp"); + is(selectChange, expectedChange, "Up key should not fire change event when reaching top of the list."); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_select_input_change_event.html b/dom/html/test/forms/test_select_input_change_event.html new file mode 100644 index 0000000000..fcf384e423 --- /dev/null +++ b/dom/html/test/forms/test_select_input_change_event.html @@ -0,0 +1,122 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1265968 +--> +<head> + <title>Test for Bug 1024350</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1024350">Mozilla Bug 1024350</a> +<p id="display"></p> +<div id="content"> + <select oninput='++selectInput;' onchange="++selectChange;"> + <option>one</option> + </select> + <select oninput='++selectInput;' onchange="++selectChange;"> + <option>one</option> + <option>two</option> + </select> + <select multiple size='1' oninput='++selectInput;' onchange="++selectChange;"> + <option>one</option> + </select> + <select multiple oninput='++selectInput;' onchange="++selectChange;"> + <option>one</option> + <option>two</option> + </select> +</div> +<pre id="test"> +<script type="application/javascript"> + var selectSingleOneItem = document.getElementsByTagName('select')[0]; + var selectSingle = document.getElementsByTagName('select')[1]; + var selectMultipleOneItem = document.getElementsByTagName('select')[2]; + var selectMultiple = document.getElementsByTagName('select')[3]; + + var selectChange = 0; + var selectInput = 0; + var expectedChange = 0; + var expectedInput = 0; + + selectSingleOneItem.focus(); + synthesizeKey("KEY_ArrowDown"); + is(selectInput, expectedInput, "Down key should not fire input event when reaching end of the list."); + is(selectChange, expectedChange, "Down key should not fire change event when reaching end of the list."); + + synthesizeKey("KEY_ArrowUp"); + is(selectInput, expectedInput, "Up key should not fire input event when reaching top of the list."); + is(selectChange, expectedChange, "Up key should not fire change event when reaching top of the list."); + + selectSingle.focus(); + for (var i = 1; i < selectSingle.length; i++) { + synthesizeKey("KEY_ArrowDown"); + + is(selectSingle.options[i].selected, true, "Option should be selected"); + is(selectInput, ++expectedInput, "Down key should fire input event."); + is(selectChange, ++expectedChange, "Down key should fire change event."); + } + + // We are at the end of the list, going down should not fire change event. + synthesizeKey("KEY_ArrowDown"); + is(selectInput, expectedInput, "Down key should not fire input event when reaching end of the list."); + is(selectChange, expectedChange, "Down key should not fire change event when reaching end of the list."); + + for (var i = selectSingle.length - 2; i >= 0; i--) { + synthesizeKey("KEY_ArrowUp"); + + is(selectSingle.options[i].selected, true, "Option should be selected"); + is(selectInput, ++expectedInput, "Up key should fire input event."); + is(selectChange, ++expectedChange, "Up key should fire change event."); + } + + // We are at the top of the list, going up should not fire change event. + synthesizeKey("KEY_ArrowUp"); + is(selectInput, expectedInput, "Up key should not fire input event when reaching top of the list."); + is(selectChange, expectedChange, "Up key should not fire change event when reaching top of the list."); + + selectMultipleOneItem.focus(); + synthesizeKey("KEY_ArrowDown"); + is(selectInput, ++expectedInput, "Down key should fire input event when reaching end of the list."); + is(selectChange, ++expectedChange, "Down key should fire change event when reaching end of the list."); + + synthesizeKey("KEY_ArrowDown"); + is(selectInput, expectedInput, "Down key should not fire input event when reaching end of the list."); + is(selectChange, expectedChange, "Down key should not fire change event when reaching end of the list."); + + synthesizeKey("KEY_ArrowUp"); + is(selectInput, expectedInput, "Up key should not fire input event when reaching top of the list."); + is(selectChange, expectedChange, "Up key should not fire change event when reaching top of the list."); + + selectMultiple.focus(); + for (var i = 0; i < selectMultiple.length; i++) { + synthesizeKey("KEY_ArrowDown"); + + is(selectMultiple.options[i].selected, true, "Option should be selected"); + is(selectInput, ++expectedInput, "Down key should fire input event."); + is(selectChange, ++expectedChange, "Down key should fire change event."); + } + + // We are at the end of the list, going down should not fire change event. + synthesizeKey("KEY_ArrowDown"); + is(selectInput, expectedInput, "Down key should not fire input event when reaching end of the list."); + is(selectChange, expectedChange, "Down key should not fire change event when reaching end of the list."); + + for (var i = selectMultiple.length - 2; i >= 0; i--) { + synthesizeKey("KEY_ArrowUp"); + + is(selectMultiple.options[i].selected, true, "Option should be selected"); + is(selectInput, ++expectedInput, "Up key should fire input event."); + is(selectChange, ++expectedChange, "Up key should fire change event."); + } + + // We are at the top of the list, going up should not fire change event. + synthesizeKey("KEY_ArrowUp"); + is(selectInput, expectedInput, "Up key should not fire input event when reaching top of the list."); + is(selectChange, expectedChange, "Up key should not fire change event when reaching top of the list."); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_select_selectedOptions.html b/dom/html/test/forms/test_select_selectedOptions.html new file mode 100644 index 0000000000..745e0ba4f3 --- /dev/null +++ b/dom/html/test/forms/test_select_selectedOptions.html @@ -0,0 +1,119 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=596681 +--> +<head> + <title>Test for HTMLSelectElement.selectedOptions</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=596681">Mozilla Bug 596681</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLSelectElement's selectedOptions attribute. + * + * selectedOptions is a live list of the options that have selectedness of true + * (not the selected content attribute). + * + * See http://www.whatwg.org/html/#dom-select-selectedoptions + **/ + +function checkSelectedOptions(size, elements) +{ + is(selectedOptions.length, size, + "select should have " + size + " selected options"); + for (let i = 0; i < size; ++i) { + ok(selectedOptions[i], "selected option is valid"); + if (selectedOptions[i]) { + is(selectedOptions[i].value, elements[i].value, "selected options are correct"); + } + } +} + +let select = document.createElement("select"); +document.body.appendChild(select); +let selectedOptions = select.selectedOptions; + +ok("selectedOptions" in select, + "select element should have a selectedOptions IDL attribute"); + +ok(select.selectedOptions instanceof HTMLCollection, + "selectedOptions should be an HTMLCollection instance"); + +let option1 = document.createElement("option"); +let option2 = document.createElement("option"); +let option3 = document.createElement("option"); +option1.id = "option1"; +option1.value = "option1"; +option2.value = "option2"; +option3.value = "option3"; + +checkSelectedOptions(0, null); + +select.add(option1, null); +is(selectedOptions.namedItem("option1").value, "option1", "named getter works"); +checkSelectedOptions(1, [option1]); + +select.add(option2, null); +checkSelectedOptions(1, [option1]); + +select.options[1].selected = true; +checkSelectedOptions(1, [option2]); + +select.multiple = true; +checkSelectedOptions(1, [option2]); + +select.options[0].selected = true; +checkSelectedOptions(2, [option1, option2]); + +option1.selected = false; +// Usinig selected directly on the option should work. +checkSelectedOptions(1, [option2]); + +select.remove(1); +select.add(option2, 0); +select.options[0].selected = true; +select.options[1].selected = true; +// Should be in tree order. +checkSelectedOptions(2, [option2, option1]); + +select.add(option3, null); +checkSelectedOptions(2, [option2, option1]); + +select.options[2].selected = true; +checkSelectedOptions(3, [option2, option1, option3]); + +select.length = 0; +option1.selected = false; +option2.selected = false; +option3.selected = false; +var optgroup1 = document.createElement("optgroup"); +optgroup1.appendChild(option1); +optgroup1.appendChild(option2); +select.add(optgroup1) +var optgroup2 = document.createElement("optgroup"); +optgroup2.appendChild(option3); +select.add(optgroup2); + +checkSelectedOptions(0, null); + +option2.selected = true; +checkSelectedOptions(1, [option2]); + +option3.selected = true; +checkSelectedOptions(2, [option2, option3]); + +optgroup1.removeChild(option2); +checkSelectedOptions(1, [option3]); + +document.body.removeChild(select); +option1.selected = true; +checkSelectedOptions(2, [option1, option3]); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_select_validation.html b/dom/html/test/forms/test_select_validation.html new file mode 100644 index 0000000000..6d02aa0746 --- /dev/null +++ b/dom/html/test/forms/test_select_validation.html @@ -0,0 +1,39 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=942321 +--> +<head> + <title>Test for Bug 942321</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=942321">Mozilla Bug 942321</a> +<p id="display"></p> +<form id="form" href=""> + <select required id="testselect"> + <option id="placeholder" value="" selected>placeholder</option> + <option value="test" id="actualvalue">test</option> + <select> + <input type="submit" /> +</form> +<script class="testbody" type="text/javascript"> +/** Test for Bug 942321 **/ +var option = document.getElementById("actualvalue"); +option.selected = true; +is(form.checkValidity(), true, "Select is required and should be valid"); + +var placeholder = document.getElementById("placeholder"); +placeholder.selected = true; +is(form.checkValidity(), false, "Select is required and should be invalid"); + +placeholder.value = "not-invalid-anymore"; +is(form.checkValidity(), true, "Select is required and should be valid when option's value is changed by javascript"); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/forms/test_set_range_text.html b/dom/html/test/forms/test_set_range_text.html new file mode 100644 index 0000000000..f85014ae77 --- /dev/null +++ b/dom/html/test/forms/test_set_range_text.html @@ -0,0 +1,242 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=850364 +--> +<head> +<title>Tests for Bug 850364 && Bug 918940</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=850364">Mozilla Bug 850364</a> +<p id="display"></p> +<div id="content"> + +<!-- "SetRangeText() supported types"--> +<input type="text" id="input_text"></input> +<input type="search" id="input_search"></input> +<input type="url" id="input_url"></input> +<input type="tel" id="input_tel"></input> +<input type="password" id="input_password"></input> +<textarea id="input_textarea"></textarea> + +<!-- "SetRangeText() non-supported types" --> +<input type="button" id="input_button"></input> +<input type="submit" id="input_submit"></input> +<input type="image" id="input_image"></input> +<input type="reset" id="input_reset"></input> +<input type="radio" id="input_radio"></input> +<input type="checkbox" id="input_checkbox"></input> +<input type="range" id="input_range"></input> +<input type="file" id="input_file"></input> +<input type="email" id="input_email"></input> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + + /** Tests for Bug 850364 && Bug 918940**/ + + var SupportedTypes = ["text", "search", "url", "tel", "password", "textarea"]; + var NonSupportedTypes = ["button", "submit", "image", "reset", "radio", + "checkbox", "range", "file", "email"]; + + SimpleTest.waitForExplicitFinish(); + + function TestInputs() { + + var opThrows, elem, i, msg; + + //Non-supported types should throw + for (i = 0; i < NonSupportedTypes.length; ++i) { + opThrows = false; + msg = "input_" + NonSupportedTypes[i]; + elem = document.getElementById(msg); + elem.focus(); + try { + elem.setRangeText("abc"); + } catch (ex) { + opThrows = true; + } + ok(opThrows, msg + " should throw InvalidStateError"); + } + + var numOfSelectCalls = 0, expectedNumOfSelectCalls = 0; + //Supported types should not throw + for (i = 0; i < SupportedTypes.length; ++i) { + opThrows = false; + msg = "input_" + SupportedTypes[i]; + elem = document.getElementById(msg); + elem.focus(); + try { + elem.setRangeText("abc"); + } catch (ex) { + opThrows = true; + } + is(opThrows, false, msg + " should not throw InvalidStateError"); + + elem.addEventListener("select", function (aEvent) { + ok(true, "select event should be fired for " + aEvent.target.id); + if (++numOfSelectCalls == expectedNumOfSelectCalls) { + SimpleTest.finish(); + } else if (numOfSelectCalls > expectedNumOfSelectCalls) { + ok(false, "Too many select events were fired"); + } + }); + + elem.addEventListener("input", function (aEvent) { + ok(false, "input event should NOT be fired for " + + aEvent.target.id); + }); + + var test = " setRange(replacement), shrink"; + elem.value = "0123456789ABCDEF"; + elem.setSelectionRange(1, 6); + elem.setRangeText("xyz"); + is(elem.value, "0xyz6789ABCDEF", msg + test); + is(elem.selectionStart, 1, msg + test); + is(elem.selectionEnd, 4, msg + test); + elem.setRangeText("mnk"); + is(elem.value, "0mnk6789ABCDEF", msg + test); + expectedNumOfSelectCalls += 2; + + test = " setRange(replacement), expand"; + elem.value = "0123456789ABCDEF"; + elem.setSelectionRange(1, 2); + elem.setRangeText("xyz"); + is(elem.value, "0xyz23456789ABCDEF", msg + test); + is(elem.selectionStart, 1, msg + test); + is(elem.selectionEnd, 4, msg + test); + elem.setRangeText("mnk"); + is(elem.value, "0mnk23456789ABCDEF", msg + test); + expectedNumOfSelectCalls += 2; + + test = " setRange(replacement) pure insertion at start"; + elem.value = "0123456789ABCDEF"; + elem.setSelectionRange(0, 0); + elem.setRangeText("xyz"); + is(elem.value, "xyz0123456789ABCDEF", msg + test); + is(elem.selectionStart, 0, msg + test); + is(elem.selectionEnd, 0, msg + test); + elem.setRangeText("mnk"); + is(elem.value, "mnkxyz0123456789ABCDEF", msg + test); + expectedNumOfSelectCalls += 1; + + test = " setRange(replacement) pure insertion in the middle"; + elem.value = "0123456789ABCDEF"; + elem.setSelectionRange(4, 4); + elem.setRangeText("xyz"); + is(elem.value, "0123xyz456789ABCDEF", msg + test); + is(elem.selectionStart, 4, msg + test); + is(elem.selectionEnd, 4, msg + test); + elem.setRangeText("mnk"); + is(elem.value, "0123mnkxyz456789ABCDEF", msg + test); + expectedNumOfSelectCalls += 1; + + test = " setRange(replacement) pure insertion at the end"; + elem.value = "0123456789ABCDEF"; + elem.setSelectionRange(16, 16); + elem.setRangeText("xyz"); + is(elem.value, "0123456789ABCDEFxyz", msg + test); + is(elem.selectionStart, 16, msg + test); + is(elem.selectionEnd, 16, msg + test); + elem.setRangeText("mnk"); + is(elem.value, "0123456789ABCDEFmnkxyz", msg + test); + + //test SetRange(replacement, start, end, mode) with start > end + try { + elem.setRangeText("abc", 20, 4); + } catch (ex) { + opThrows = (ex.name == "IndexSizeError" && ex.code == DOMException.INDEX_SIZE_ERR); + } + is(opThrows, true, msg + " should throw IndexSizeError"); + + //test SelectionMode 'select' + elem.value = "0123456789ABCDEF"; + elem.setRangeText("xyz", 4, 9, "select"); + is(elem.value, "0123xyz9ABCDEF", msg + ".value == \"0123xyz9ABCDEF\""); + is(elem.selectionStart, 4, msg + ".selectionStart == 4, with \"select\""); + is(elem.selectionEnd, 7, msg + ".selectionEnd == 7, with \"select\""); + expectedNumOfSelectCalls += 1; + + elem.setRangeText("pqm", 6, 25, "select"); + is(elem.value, "0123xypqm", msg + ".value == \"0123xypqm\""); + is(elem.selectionStart, 6, msg + ".selectionStart == 6, with \"select\""); + is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"select\""); + expectedNumOfSelectCalls += 1; + + //test SelectionMode 'start' + elem.value = "0123456789ABCDEF"; + elem.setRangeText("xyz", 4, 9, "start"); + is(elem.value, "0123xyz9ABCDEF", msg + ".value == \"0123xyz9ABCDEF\""); + is(elem.selectionStart, 4, msg + ".selectionStart == 4, with \"start\""); + is(elem.selectionEnd, 4, msg + ".selectionEnd == 4, with \"start\""); + expectedNumOfSelectCalls += 1; + + elem.setRangeText("pqm", 6, 25, "start"); + is(elem.value, "0123xypqm", msg + ".value == \"0123xypqm\""); + is(elem.selectionStart, 6, msg + ".selectionStart == 6, with \"start\""); + is(elem.selectionEnd, 6, msg + ".selectionEnd == 6, with \"start\""); + expectedNumOfSelectCalls += 1; + + //test SelectionMode 'end' + elem.value = "0123456789ABCDEF"; + elem.setRangeText("xyz", 4, 9, "end"); + is(elem.value, "0123xyz9ABCDEF", msg + ".value == \"0123xyz9ABCDEF\""); + is(elem.selectionStart, 7, msg + ".selectionStart == 7, with \"end\""); + is(elem.selectionEnd, 7, msg + ".selectionEnd == 7, with \"end\""); + expectedNumOfSelectCalls += 1; + + elem.setRangeText("pqm", 6, 25, "end"); + is(elem.value, "0123xypqm", msg + ".value == \"0123xypqm\""); + is(elem.selectionStart, 9, msg + ".selectionStart == 9, with \"end\""); + is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"end\""); + expectedNumOfSelectCalls += 1; + + //test SelectionMode 'preserve' (default) + + //subcase: selection{Start|End} > end + elem.value = "0123456789"; + elem.setSelectionRange(6, 9); + elem.setRangeText("Z", 1, 2, "preserve"); + is(elem.value, "0Z23456789", msg + ".value == \"0Z23456789\""); + is(elem.selectionStart, 6, msg + ".selectionStart == 6, with \"preserve\""); + is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"preserve\""); + expectedNumOfSelectCalls += 1; + + //subcase: selection{Start|End} < end + elem.value = "0123456789"; + elem.setSelectionRange(4, 5); + elem.setRangeText("QRST", 2, 9, "preserve"); + is(elem.value, "01QRST9", msg + ".value == \"01QRST9\""); + is(elem.selectionStart, 2, msg + ".selectionStart == 2, with \"preserve\""); + is(elem.selectionEnd, 6, msg + ".selectionEnd == 6, with \"preserve\""); + expectedNumOfSelectCalls += 2; + + //subcase: selectionStart > end, selectionEnd < end + elem.value = "0123456789"; + elem.setSelectionRange(8, 4); + elem.setRangeText("QRST", 1, 5); + is(elem.value, "0QRST56789", msg + ".value == \"0QRST56789\""); + is(elem.selectionStart, 1, msg + ".selectionStart == 1, with \"default\""); + is(elem.selectionEnd, 5, msg + ".selectionEnd == 5, with \"default\""); + expectedNumOfSelectCalls += 2; + + //subcase: selectionStart < end, selectionEnd > end + elem.value = "0123456789"; + elem.setSelectionRange(4, 9); + elem.setRangeText("QRST", 2, 6); + is(elem.value, "01QRST6789", msg + ".value == \"01QRST6789\""); + is(elem.selectionStart, 2, msg + ".selectionStart == 2, with \"default\""); + is(elem.selectionEnd, 9, msg + ".selectionEnd == 9, with \"default\""); + expectedNumOfSelectCalls += 2; + } + } + + addLoadEvent(TestInputs); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_step_attribute.html b/dom/html/test/forms/test_step_attribute.html new file mode 100644 index 0000000000..f0af250c06 --- /dev/null +++ b/dom/html/test/forms/test_step_attribute.html @@ -0,0 +1,1060 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=635553 +--> +<head> + <title>Test for Bug 635553</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=635499">Mozilla Bug 635499</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 635553 **/ + +var data = [ + { type: 'hidden', apply: false }, + { type: 'text', apply: false }, + { type: 'search', apply: false }, + { type: 'tel', apply: false }, + { type: 'url', apply: false }, + { type: 'email', apply: false }, + { type: 'password', apply: false }, + { type: 'date', apply: true }, + { type: 'month', apply: true }, + { type: 'week', apply: true }, + { type: 'time', apply: true }, + { type: 'datetime-local', apply: true }, + { type: 'number', apply: true }, + { type: 'range', apply: true }, + { type: 'color', apply: false }, + { type: 'checkbox', apply: false }, + { type: 'radio', apply: false }, + { type: 'file', apply: false }, + { type: 'submit', apply: false }, + { type: 'image', apply: false }, + { type: 'reset', apply: false }, + { type: 'button', apply: false }, +]; + +function getFreshElement(type) { + var elmt = document.createElement('input'); + elmt.type = type; + return elmt; +} + +function checkValidity(aElement, aValidity, aApply, aData) +{ + aValidity = aApply ? aValidity : true; + + is(aElement.validity.valid, aValidity, + "element validity should be " + aValidity); + is(aElement.validity.stepMismatch, !aValidity, + "element step mismatch status should be " + !aValidity); + + if (aValidity) { + is(aElement.validationMessage, "", "There should be no validation message."); + } else { + if (aElement.validity.rangeUnderflow) { + var underflowMsg = + (aElement.type == "date" || aElement.type == "time") ? + ("Please select a value that is no earlier than " + aElement.min + ".") : + ("Please select a value that is no less than " + aElement.min + "."); + is(aElement.validationMessage, underflowMsg, + "Checking range underflow validation message."); + } else if (aData.low == aData.high) { + is(aElement.validationMessage, "Please select a valid value. " + + "The nearest valid value is " + aData.low + ".", + "There should be a validation message."); + } else { + is(aElement.validationMessage, "Please select a valid value. " + + "The two nearest valid values are " + aData.low + " and " + aData.high + ".", + "There should be a validation message."); + } + } + + is(aElement.matches(":valid"), aElement.willValidate && aValidity, + (aElement.willValidate && aValidity) ? ":valid should apply" : "valid shouldn't apply"); + is(aElement.matches(":invalid"), aElement.willValidate && !aValidity, + (aElement.wil && aValidity) ? ":invalid shouldn't apply" : "valid should apply"); +} + +for (var test of data) { + var input = getFreshElement(test.type); + var apply = test.apply; + + if (test.todo) { + todo_is(input.type, test.type, test.type + " isn't implemented yet"); + continue; + } + + // The element should be valid, there should be no step mismatch. + checkValidity(input, true, apply); + + // Checks to do for all types that support step: + // - check for @step=0, + // - check for @step behind removed, + // - check for @step being 'any' with different case variations. + switch (input.type) { + case 'text': + case 'hidden': + case 'search': + case 'password': + case 'tel': + case 'radio': + case 'checkbox': + case 'reset': + case 'button': + case 'submit': + case 'image': + case 'color': + input.value = '0'; + checkValidity(input, true, apply); + break; + case 'url': + input.value = 'http://mozilla.org'; + checkValidity(input, true, apply); + break; + case 'email': + input.value = 'foo@bar.com'; + checkValidity(input, true, apply); + break; + case 'file': + var file = new File([''], '635499_file'); + + SpecialPowers.wrap(input).mozSetFileArray([file]); + checkValidity(input, true, apply); + + break; + case 'date': + // For date, the step is calulated on the timestamp since 1970-01-01 + // which mean that for all dates prior to the epoch, this timestamp is < 0 + // and the behavior might differ, therefore we have to test for these cases. + + // When step is invalid, every date is valid + input.step = 0; + input.value = '2012-07-05'; + checkValidity(input, true, apply); + + input.step = 'foo'; + input.value = '1970-01-01'; + checkValidity(input, true, apply); + + input.step = '-1'; + input.value = '1969-12-12'; + checkValidity(input, true, apply); + + input.removeAttribute('step'); + input.value = '1500-01-01'; + checkValidity(input, true, apply); + + input.step = 'any'; + input.value = '1966-12-12'; + checkValidity(input, true, apply); + + input.step = 'ANY'; + input.value = '2013-02-03'; + checkValidity(input, true, apply); + + // When min is set to a valid date, there is a step base. + input.min = '2008-02-28'; + input.step = '2'; + input.value = '2008-03-01'; + checkValidity(input, true, apply); + + input.value = '2008-02-29'; + checkValidity(input, false, apply, { low: "2008-02-28", high: "2008-03-01" }); + + input.min = '2008-02-27'; + input.value = '2008-02-28'; + checkValidity(input, false, apply, { low: "2008-02-27", high: "2008-02-29" }); + + input.min = '2009-02-27'; + input.value = '2009-02-28'; + checkValidity(input, false, apply, { low: "2009-02-27", high: "2009-03-01" }); + + input.min = '2009-02-01'; + input.step = '1.1'; + input.value = '2009-02-02'; + checkValidity(input, true, apply); + + // Without any step attribute the date is valid + input.removeAttribute('step'); + checkValidity(input, true, apply); + + input.min = '1950-01-01'; + input.step = '366'; + input.value = '1951-01-01'; + checkValidity(input, false, apply, { low: "1950-01-01", high: "1951-01-02" }); + + input.min = '1951-01-01'; + input.step = '365'; + input.value = '1952-01-01'; + checkValidity(input, true, apply); + + input.step = '0.9'; + input.value = '1951-01-02'; + is(input.step, '0.9', "check that step value is unchanged"); + checkValidity(input, true, apply); + + input.step = '0.4'; + input.value = '1951-01-02'; + is(input.step, '0.4', "check that step value is unchanged"); + checkValidity(input, true, apply); + + input.step = '1.5'; + input.value = '1951-01-02'; + is(input.step, '1.5', "check that step value is unchanged"); + checkValidity(input, false, apply, { low: "1951-01-01", high: "1951-01-03" }); + + input.value = '1951-01-08'; + checkValidity(input, false, apply, { low: "1951-01-07", high: "1951-01-09" }); + + input.step = '3000'; + input.min= '1968-01-01'; + input.value = '1968-05-12'; + checkValidity(input, false, apply, { low: "1968-01-01", high: "1976-03-19" }); + + input.value = '1971-01-01'; + checkValidity(input, false, apply, { low: "1968-01-01", high: "1976-03-19" }); + + input.value = '1991-01-01'; + checkValidity(input, false, apply, { low: "1984-06-05", high: "1992-08-22" }); + + input.value = '1984-06-05'; + checkValidity(input, true, apply); + + input.value = '1992-08-22'; + checkValidity(input, true, apply); + + input.step = '2.1'; + input.min = '1991-01-01'; + input.value = '1991-01-01'; + checkValidity(input, true, apply); + + input.value = '1991-01-02'; + checkValidity(input, false, apply, { low: "1991-01-01", high: "1991-01-03" }); + + input.value = '1991-01-03'; + checkValidity(input, true, apply); + + input.step = '2.1'; + input.min = '1969-12-20'; + input.value = '1969-12-20'; + checkValidity(input, true, apply); + + input.value = '1969-12-21'; + checkValidity(input, false, apply, { low: "1969-12-20", high: "1969-12-22" }); + + input.value = '1969-12-22'; + checkValidity(input, true, apply); + + break; + case 'number': + // When step=0, the allowed step is 1. + input.step = '0'; + input.value = '1.2'; + checkValidity(input, false, apply, { low: 1, high: 2 }); + + input.value = '1'; + checkValidity(input, true, apply); + + input.value = '0'; + checkValidity(input, true, apply); + + // When step is NaN, the allowed step value is 1. + input.step = 'foo'; + input.value = '1'; + checkValidity(input, true, apply); + + input.value = '1.5'; + checkValidity(input, false, apply, { low: 1, high: 2 }); + + // When step is negative, the allowed step value is 1. + input.step = '-0.1'; + checkValidity(input, false, apply, { low: 1, high: 2 }); + + input.value = '1'; + checkValidity(input, true, apply); + + // When step is missing, the allowed step value is 1. + input.removeAttribute('step'); + input.value = '1.5'; + checkValidity(input, false, apply, { low: 1, high: 2 }); + + input.value = '1'; + checkValidity(input, true, apply); + + // When step is 'any', all values are fine wrt to step. + input.step = 'any'; + checkValidity(input, true, apply); + + input.step = 'aNy'; + input.value = '1337'; + checkValidity(input, true, apply); + + input.step = 'AnY'; + input.value = '0.1'; + checkValidity(input, true, apply); + + input.step = 'ANY'; + input.value = '-13.37'; + checkValidity(input, true, apply); + + // When min is set to a valid float, there is a step base. + input.min = '1'; + input.step = '2'; + input.value = '3'; + checkValidity(input, true, apply); + + input.value = '2'; + checkValidity(input, false, apply, { low: 1, high: 3 }); + + input.removeAttribute('step'); // step = 1 + input.min = '0.5'; + input.value = '5.5'; + checkValidity(input, true, apply); + + input.value = '1'; + checkValidity(input, false, apply, { low: 0.5, high: 1.5 }); + + input.min = '-0.1'; + input.step = '1'; + input.value = '0.9'; + checkValidity(input, true, apply); + + input.value = '0.1'; + checkValidity(input, false, apply, { low: -0.1, high: 0.9 }); + + // When min is set to NaN, there is no step base (step base=0 actually). + input.min = 'foo'; + input.step = '1'; + input.value = '1'; + checkValidity(input, true, apply); + + input.value = '0.5'; + checkValidity(input, false, apply, { low: 0, high: 1 }); + + input.min = ''; + input.value = '1'; + checkValidity(input, true, apply); + + input.value = '0.5'; + checkValidity(input, false, apply, { low: 0, high: 1 }); + + input.removeAttribute('min'); + + // If value isn't a number, the element isn't invalid. + input.value = ''; + checkValidity(input, true, apply); + + // Regular situations. + input.step = '2'; + input.value = '1.5'; + checkValidity(input, false, apply, { low: 0, high: 2 }); + + input.value = '42.0'; + checkValidity(input, true, apply); + + input.step = '0.1'; + input.value = '-0.1'; + checkValidity(input, true, apply); + + input.step = '2'; + input.removeAttribute('min'); + input.max = '10'; + input.value = '-9'; + checkValidity(input, false, apply, {low: -10, high: -8}); + + // If there is a value defined but no min, the step base is the value. + input = getFreshElement(test.type); + input.setAttribute('value', '1'); + input.step = 2; + checkValidity(input, true, apply); + + input.value = 3; + checkValidity(input, true, apply); + + input.value = 2; + checkValidity(input, false, apply, {low: 1, high: 3}); + + // Should also work with defaultValue. + input = getFreshElement(test.type); + input.defaultValue = 1; + input.step = 2; + checkValidity(input, true, apply); + + input.value = 3; + checkValidity(input, true, apply); + + input.value = 2; + checkValidity(input, false, apply, {low: 1, high: 3}); + + // Rounding issues. + input = getFreshElement(test.type); + input.min = 0.1; + input.step = 0.2; + input.value = 0.3; + checkValidity(input, true, apply); + + // Check that when the higher value is higher than max, we don't show it. + input = getFreshElement(test.type); + input.step = '2'; + input.min = '1'; + input.max = '10.9'; + input.value = '10'; + + is(input.validationMessage, "Please select a valid value. " + + "The nearest valid value is 9.", + "The validation message should not include the higher value."); + break; + case 'range': + // Range is special in that it clamps to valid values, so it is much + // rarer for it to be invalid. + + // When step=0, the allowed value step is 1. + input.step = '0'; + input.value = '1.2'; + is(input.value, '1', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + input.value = '1'; + is(input.value, '1', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + input.value = '0'; + is(input.value, '0', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + // When step is NaN, the allowed step value is 1. + input.step = 'foo'; + input.value = '1'; + is(input.value, '1', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + input.value = '1.5'; + is(input.value, '2', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + // When step is negative, the allowed step value is 1. + input.step = '-0.1'; + is(input.value, '2', "check that the value still coincides with a step"); + checkValidity(input, true, apply); + + input.value = '1'; + is(input.value, '1', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + // When step is missing, the allowed step value is 1. + input.removeAttribute('step'); + input.value = '1.5'; + is(input.value, '2', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + input.value = '1'; + is(input.value, '1', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + // When step is 'any', all values are fine wrt to step. + input.step = 'any'; + checkValidity(input, true, apply); + + input.step = 'aNy'; + input.value = '97'; + is(input.value, '97', "check that the value for step=aNy is unchanged"); + checkValidity(input, true, apply); + + input.step = 'AnY'; + input.value = '0.1'; + is(input.value, '0.1', "check that a positive fractional value with step=AnY is unchanged"); + checkValidity(input, true, apply); + + input.step = 'ANY'; + input.min = -100; + input.value = '-13.37'; + is(input.value, '-13.37', "check that a negative fractional value with step=ANY is unchanged"); + checkValidity(input, true, apply); + + // When min is set to a valid float, there is a step base. + input.min = '1'; // the step base + input.step = '2'; + input.value = '3'; + is(input.value, '3', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + input.value = '2'; + is(input.value, '3', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + input.value = '1.99'; + is(input.value, '1', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + input.removeAttribute('step'); // step = 1 + input.min = '0.5'; // step base + input.value = '5.5'; + is(input.value, '5.5', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + input.value = '1'; + is(input.value, '1.5', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + input.min = '-0.1'; // step base + input.step = '1'; + input.value = '0.9'; + is(input.value, '0.9', "the value should be a valid step"); + checkValidity(input, true, apply); + + input.value = '0.1'; + is(input.value, '-0.1', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + // When min is set to NaN, the step base is the value. + input.min = 'foo'; + input.step = '1'; + input.value = '1'; + is(input.value, '1', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + input.value = '0.5'; + is(input.value, '1', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + input.min = ''; + input.value = '1'; + is(input.value, '1', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + input.value = '0.5'; + is(input.value, '1', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + input.removeAttribute('min'); + + // Test when the value isn't a number + input.value = ''; + is(input.value, '50', "value be should default to the value midway between the minimum (0) and the maximum (100)"); + checkValidity(input, true, apply); + + // Regular situations. + input.step = '2'; + input.value = '1.5'; + is(input.value, '2', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + input.value = '42.0'; + is(input.value, '42.0', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + input.step = '0.1'; + input.value = '-0.1'; + is(input.value, '0', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + input.step = '2'; + input.removeAttribute('min'); + input.max = '10'; + input.value = '-9'; + is(input.value, '0', "check the value is clamped to the minimum's default of zero"); + checkValidity(input, true, apply); + + // If @value is defined but not @min, the step base is @value. + input = getFreshElement(test.type); + input.setAttribute('value', '1'); + input.step = 2; + is(input.value, '1', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + input.value = 3; + is(input.value, '3', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + input.value = 2; + is(input.value, '3', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + // Should also work with defaultValue. + input = getFreshElement(test.type); + input.defaultValue = 1; + input.step = 2; + is(input.value, '1', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + input.value = 3; + is(input.value, '3', "check that the value coincides with a step"); + checkValidity(input, true, apply); + + input.value = 2; + is(input.value, '3', "check that the value changes to the nearest valid step, choosing the higher step if both are equally close"); + checkValidity(input, true, apply); + + // Check contrived error case where there are no valid steps in range: + // No @min, so the step base is the default minimum, zero, the valid + // range is 0-1, -1 gets clamped to zero. + input = getFreshElement(test.type); + input.step = '3'; + input.max = '1'; + input.defaultValue = '-1'; + is(input.value, '0', "the value should have been clamped to the default minimum, zero"); + checkValidity(input, false, apply, {low: -1, high: -1}); + + // Check that when the closest of the two steps that the value is between + // is greater than the maximum we sanitize to the lower step. + input = getFreshElement(test.type); + input.step = '2'; + input.min = '1'; + input.max = '10.9'; + input.value = '10.8'; // closest step in 11, but 11 > maximum + is(input.value, '9', "check that the value coincides with a step"); + + // The way that step base is defined, the converse (the value not being + // on a step, and the nearest step being a value that would be underflow) + // is not possible, so nothing to test there. + + is(input.validationMessage, "", + "The validation message should be empty."); + break; + case 'time': + // Tests invalid step values. That defaults to step = 1 minute (60). + var values = [ '0', '-1', 'foo', 'any', 'ANY', 'aNy' ]; + for (var value of values) { + input.step = value; + input.value = '19:06:00'; + checkValidity(input, true, apply); + input.value = '19:06:51'; + if (value.toLowerCase() != 'any') { + checkValidity(input, false, apply, {low: '19:06', high: '19:07'}); + } else { + checkValidity(input, true, apply); + } + } + + // No step means that we use the default step value. + input.removeAttribute('step'); + input.value = '19:06:00'; + checkValidity(input, true, apply); + input.value = '19:06:51'; + checkValidity(input, false, apply, {low: '19:06', high: '19:07'}); + + var tests = [ + // With step=1, we allow values by the second. + { step: '1', value: '19:11:01', min: '00:00', result: true }, + { step: '1', value: '19:11:01.001', min: '00:00', result: false, + low: '19:11:01', high: '19:11:02' }, + { step: '1', value: '19:11:01.1', min: '00:00', result: false, + low: '19:11:01', high: '19:11:02' }, + // When step >= 86400000, only the minimum value is valid. + // This is actually @value if there is no @min. + { step: '86400000', value: '00:00', result: true }, + { step: '86400000', value: '00:01', result: true }, + { step: '86400000', value: '00:00', min: '00:01', result: false }, + { step: '86400000', value: '00:01', min: '00:00', result: false, + low: '00:00', high: '00:00' }, + // When step < 1, it should just work. + { step: '0.1', value: '15:05:05.1', min: '00:00', result: true }, + { step: '0.1', value: '15:05:05.101', min: '00:00', result: false, + low: '15:05:05.100', high: '15:05:05.200' }, + { step: '0.2', value: '15:05:05.2', min: '00:00', result: true }, + { step: '0.2', value: '15:05:05.1', min: '00:00', result: false, + low: '15:05:05', high: '15:05:05.200' }, + { step: '0.01', value: '15:05:05.01', min: '00:00', result: true }, + { step: '0.01', value: '15:05:05.011', min: '00:00', result: false, + low: '15:05:05.010', high: '15:05:05.020' }, + { step: '0.02', value: '15:05:05.02', min: '00:00', result: true }, + { step: '0.02', value: '15:05:05.01', min: '00:00', result: false, + low: '15:05:05', high: '15:05:05.020' }, + { step: '0.002', value: '15:05:05.002', min: '00:00', result: true }, + { step: '0.002', value: '15:05:05.001', min: '00:00', result: false, + low: '15:05:05', high: '15:05:05.002' }, + // When step<=0.001, any value is allowed. + { step: '0.001', value: '15:05:05.001', min: '00:00', result: true }, + { step: '0.001', value: '15:05:05', min: '00:00', result: true }, + { step: '0.000001', value: '15:05:05', min: '00:00', result: true }, + // This value has conversion to double issues. + { step: '0.0000001', value: '15:05:05', min: '00:00', result: true }, + // Some random values. + { step: '100', value: '15:06:40', min: '00:00', result: true }, + { step: '100', value: '15:05:05.010', min: '00:00', result: false, + low: '15:05', high: '15:06:40' }, + { step: '3600', value: '15:00', min: '00:00', result: true }, + { step: '3600', value: '15:14', min: '00:00', result: false, + low: '15:00', high: '16:00' }, + { step: '7200', value: '14:00', min: '00:00', result: true }, + { step: '7200', value: '15:14', min: '00:00', result: false, + low: '14:00', high: '16:00' }, + { step: '7260', value: '14:07', min: '00:00', result: true }, + { step: '7260', value: '15:14', min: '00:00', result: false, + low: '14:07', high: '16:08' }, + ]; + + var type = test.type; + for (var test of tests) { + var input = getFreshElement(type); + input.step = test.step; + input.setAttribute('value', test.value); + if (test.min !== undefined) { + input.min = test.min; + } + + if (test.todo) { + todo(input.validity.valid, test.result, + "This test should fail for the moment because of precission issues"); + continue; + } + + if (test.result) { + checkValidity(input, true, apply); + } else { + checkValidity(input, false, apply, + { low: test.low, high: test.high }); + } + } + + break; + case 'month': + // When step is invalid, every date is valid + input.step = 0; + input.value = '2016-07'; + checkValidity(input, true, apply); + + input.step = 'foo'; + input.value = '1970-01'; + checkValidity(input, true, apply); + + input.step = '-1'; + input.value = '1970-01'; + checkValidity(input, true, apply); + + input.removeAttribute('step'); + input.value = '1500-01'; + checkValidity(input, true, apply); + + input.step = 'any'; + input.value = '1966-12'; + checkValidity(input, true, apply); + + input.step = 'ANY'; + input.value = '2013-02'; + checkValidity(input, true, apply); + + // When min is set to a valid month, there is a step base. + input.min = '2000-01'; + input.step = '2'; + input.value = '2000-03'; + checkValidity(input, true, apply); + + input.value = '2000-02'; + checkValidity(input, false, apply, { low: "2000-01", high: "2000-03" }); + + input.min = '2012-12'; + input.value = '2013-01'; + checkValidity(input, false, apply, { low: "2012-12", high: "2013-02" }); + + input.min = '2010-10'; + input.value = '2010-11'; + checkValidity(input, false, apply, { low: "2010-10", high: "2010-12" }); + + input.min = '2010-01'; + input.step = '1.1'; + input.value = '2010-02'; + checkValidity(input, true, apply); + + input.min = '2010-05'; + input.step = '1.9'; + input.value = '2010-06'; + checkValidity(input, false, apply, { low: "2010-05", high: "2010-07" }); + + // Without any step attribute the date is valid + input.removeAttribute('step'); + checkValidity(input, true, apply); + + input.min = '1950-01'; + input.step = '13'; + input.value = '1951-01'; + checkValidity(input, false, apply, { low: "1950-01", high: "1951-02" }); + + input.min = '1951-01'; + input.step = '12'; + input.value = '1952-01'; + checkValidity(input, true, apply); + + input.step = '0.9'; + input.value = '1951-02'; + checkValidity(input, true, apply); + + input.step = '1.5'; + input.value = '1951-04'; + checkValidity(input, false, apply, { low: "1951-03", high: "1951-05" }); + + input.value = '1951-08'; + checkValidity(input, false, apply, { low: "1951-07", high: "1951-09" }); + + input.step = '300'; + input.min= '1968-01'; + input.value = '1968-05'; + checkValidity(input, false, apply, { low: "1968-01", high: "1993-01" }); + + input.value = '1971-01'; + checkValidity(input, false, apply, { low: "1968-01", high: "1993-01" }); + + input.value = '1994-01'; + checkValidity(input, false, apply, { low: "1993-01", high: "2018-01" }); + + input.value = '2018-01'; + checkValidity(input, true, apply); + + input.value = '2043-01'; + checkValidity(input, true, apply); + + input.step = '2.1'; + input.min = '1991-01'; + input.value = '1991-01'; + checkValidity(input, true, apply); + + input.value = '1991-02'; + checkValidity(input, false, apply, { low: "1991-01", high: "1991-03" }); + + input.value = '1991-03'; + checkValidity(input, true, apply); + + input.step = '2.1'; + input.min = '1969-12'; + input.value = '1969-12'; + checkValidity(input, true, apply); + + input.value = '1970-01'; + checkValidity(input, false, apply, { low: "1969-12", high: "1970-02" }); + + input.value = '1970-02'; + checkValidity(input, true, apply); + + break; + case 'week': + // When step is invalid, every week is valid + input.step = 0; + input.value = '2016-W30'; + checkValidity(input, true, apply); + + input.step = 'foo'; + input.value = '1970-W01'; + checkValidity(input, true, apply); + + input.step = '-1'; + input.value = '1970-W01'; + checkValidity(input, true, apply); + + input.removeAttribute('step'); + input.value = '1500-W01'; + checkValidity(input, true, apply); + + input.step = 'any'; + input.value = '1966-W52'; + checkValidity(input, true, apply); + + input.step = 'ANY'; + input.value = '2013-W10'; + checkValidity(input, true, apply); + + // When min is set to a valid week, there is a step base. + input.min = '2000-W01'; + input.step = '2'; + input.value = '2000-W03'; + checkValidity(input, true, apply); + + input.value = '2000-W02'; + checkValidity(input, false, apply, { low: "2000-W01", high: "2000-W03" }); + + input.min = '2012-W52'; + input.value = '2013-W01'; + checkValidity(input, false, apply, { low: "2012-W52", high: "2013-W02" }); + + input.min = '2010-W01'; + input.step = '1.1'; + input.value = '2010-W02'; + checkValidity(input, true, apply); + + input.min = '2010-W05'; + input.step = '1.9'; + input.value = '2010-W06'; + checkValidity(input, false, apply, { low: "2010-W05", high: "2010-W07" }); + + // Without any step attribute the week is valid + input.removeAttribute('step'); + checkValidity(input, true, apply); + + input.min = '1950-W01'; + input.step = '53'; + input.value = '1951-W01'; + checkValidity(input, false, apply, { low: "1950-W01", high: "1951-W02" }); + + input.min = '1951-W01'; + input.step = '52'; + input.value = '1952-W01'; + checkValidity(input, true, apply); + + input.step = '0.9'; + input.value = '1951-W02'; + checkValidity(input, true, apply); + + input.step = '1.5'; + input.value = '1951-W04'; + checkValidity(input, false, apply, { low: "1951-W03", high: "1951-W05" }); + + input.value = '1951-W20'; + checkValidity(input, false, apply, { low: "1951-W19", high: "1951-W21" }); + + input.step = '300'; + input.min= '1968-W01'; + input.value = '1968-W05'; + checkValidity(input, false, apply, { low: "1968-W01", high: "1973-W40" }); + + input.value = '1971-W01'; + checkValidity(input, false, apply, { low: "1968-W01", high: "1973-W40" }); + + input.value = '1975-W01'; + checkValidity(input, false, apply, { low: "1973-W40", high: "1979-W27" }); + + input.value = '1985-W14'; + checkValidity(input, true, apply); + + input.step = '2.1'; + input.min = '1991-W01'; + input.value = '1991-W01'; + checkValidity(input, true, apply); + + input.value = '1991-W02'; + checkValidity(input, false, apply, { low: "1991-W01", high: "1991-W03" }); + + input.value = '1991-W03'; + checkValidity(input, true, apply); + + input.step = '2.1'; + input.min = '1969-W52'; + input.value = '1969-W52'; + checkValidity(input, true, apply); + + input.value = '1970-W01'; + checkValidity(input, false, apply, { low: "1969-W52", high: "1970-W02" }); + + input.value = '1970-W02'; + checkValidity(input, true, apply); + + break; + case 'datetime-local': + // When step is invalid, every datetime is valid + input.step = 0; + input.value = '2017-02-06T12:00'; + checkValidity(input, true, apply); + + input.step = 'foo'; + input.value = '1970-01-01T00:00'; + checkValidity(input, true, apply); + + input.step = '-1'; + input.value = '1969-12-12 00:10'; + checkValidity(input, true, apply); + + input.removeAttribute('step'); + input.value = '1500-01-01T12:00'; + checkValidity(input, true, apply); + + input.step = 'any'; + input.value = '1966-12-12T12:00'; + checkValidity(input, true, apply); + + input.step = 'ANY'; + input.value = '2017-01-01 12:00'; + checkValidity(input, true, apply); + + // When min is set to a valid datetime, there is a step base. + input.min = '2017-01-01T00:00:00'; + input.step = '2'; + input.value = '2017-01-01T00:00:02'; + checkValidity(input, true, apply); + + input.value = '2017-01-01T00:00:03'; + checkValidity(input, false, apply, + { low: "2017-01-01T00:00:02", high: "2017-01-01T00:00:04" }); + + input.min = '2017-01-01T00:00:05'; + input.value = '2017-01-01T00:00:08'; + checkValidity(input, false, apply, + { low: "2017-01-01T00:00:07", high: "2017-01-01T00:00:09" }); + + input.min = '2000-01-01T00:00'; + input.step = '120'; + input.value = '2000-01-01T00:02'; + checkValidity(input, true, apply); + + // Without any step attribute the datetime is valid + input.removeAttribute('step'); + checkValidity(input, true, apply); + + input.min = '1950-01-01T00:00'; + input.step = '129600'; // 1.5 day + input.value = '1950-01-02T00:00'; + checkValidity(input, false, apply, + { low: "1950-01-01T00:00", high: "1950-01-02T12:00" }); + + input.step = '259200'; // 3 days + input.value = '1950-01-04T12:00'; + checkValidity(input, false, apply, + { low: "1950-01-04T00:00", high: "1950-01-07T00:00" }); + + input.value = '1950-01-10T00:00'; + checkValidity(input, true, apply); + + input.step = '0.5'; // half a second + input.value = '1950-01-01T00:00:00.123'; + checkValidity(input, false, apply, + { low: "1950-01-01T00:00", high: "1950-01-01T00:00:00.500" }); + + input.value = '2000-01-01T12:30:30.600'; + checkValidity(input, false, apply, + { low: "2000-01-01T12:30:30.500", high: "2000-01-01T12:30:31" }); + + input.value = '1950-01-05T00:00:00.500'; + checkValidity(input, true, apply); + + input.step = '2.1'; + input.min = '1991-01-01T12:00'; + input.value = '1991-01-01T12:00'; + checkValidity(input, true, apply); + + input.value = '1991-01-01T12:00:03'; + checkValidity(input, false, apply, + { low: "1991-01-01T12:00:02.100", high: "1991-01-01T12:00:04.200" }); + + input.value = '1991-01-01T12:00:06.3'; + checkValidity(input, true, apply); + + input.step = '2.1'; + input.min = '1969-12-20T10:00:05'; + input.value = '1969-12-20T10:00:05'; + checkValidity(input, true, apply); + + input.value = '1969-12-20T10:00:08'; + checkValidity(input, false, apply, + { low: "1969-12-20T10:00:07.100", high: "1969-12-20T10:00:09.200" }); + + input.value = '1969-12-20T10:00:09.200'; + checkValidity(input, true, apply); + + break; + default: + ok(false, "Implement the tests for <input type='" + test.type + " >"); + break; + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_stepup_stepdown.html b/dom/html/test/forms/test_stepup_stepdown.html new file mode 100644 index 0000000000..8ad7fbfeee --- /dev/null +++ b/dom/html/test/forms/test_stepup_stepdown.html @@ -0,0 +1,1137 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=636627 +--> +<head> + <title>Test for Bug 636627</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=636627">Mozilla Bug 636627</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 636627 **/ + +/** + * This test is testing stepDown() and stepUp(). + */ + +function checkPresence() +{ + var input = document.createElement('input'); + is('stepDown' in input, true, 'stepDown() should be an input function'); + is('stepUp' in input, true, 'stepUp() should be an input function'); +} + +function checkAvailability() +{ + var testData = + [ + ["text", false], + ["password", false], + ["search", false], + ["telephone", false], + ["email", false], + ["url", false], + ["hidden", false], + ["checkbox", false], + ["radio", false], + ["file", false], + ["submit", false], + ["image", false], + ["reset", false], + ["button", false], + ["number", true], + ["range", true], + ["date", true], + ["time", true], + ["month", true], + ["week", true], + ["datetime-local", true], + ["color", false], + ]; + + var element = document.createElement("input"); + element.setAttribute('value', '0'); + + for (data of testData) { + var exceptionCaught = false; + element.type = data[0]; + try { + element.stepDown(); + } catch (e) { + exceptionCaught = true; + } + is(exceptionCaught, !data[1], "stepDown() availability is not correct"); + + exceptionCaught = false; + try { + element.stepUp(); + } catch (e) { + exceptionCaught = true; + } + is(exceptionCaught, !data[1], "stepUp() availability is not correct"); + } +} + +function checkStepDown() +{ + // This testData is very similar to the one in checkStepUp with some changes + // relative to stepDown. + var testData = [ + /* Initial value | step | min | max | stepDown arg | final value | exception */ + { type: 'number', data: [ + // Regular case. + [ '1', null, null, null, null, '0', false ], + // Argument testing. + [ '1', null, null, null, 1, '0', false ], + [ '9', null, null, null, 9, '0', false ], + [ '1', null, null, null, -1, '2', false ], + [ '1', null, null, null, 0, '1', false ], + // Float values are rounded to integer (1.1 -> 1). + [ '1', null, null, null, 1.1, '0', false ], + // With step values. + [ '1', '0.5', null, null, null, '0.5', false ], + [ '1', '0.25', null, null, 4, '0', false ], + // step = 0 isn't allowed (-> step = 1). + [ '1', '0', null, null, null, '0', false ], + // step < 0 isn't allowed (-> step = 1). + [ '1', '-1', null, null, null, '0', false ], + // step = NaN isn't allowed (-> step = 1). + [ '1', 'foo', null, null, null, '0', false ], + // Min values testing. + [ '1', '1', 'foo', null, null, '0', false ], + [ '1', null, '-10', null, null, '0', false ], + [ '1', null, '0', null, null, '0', false ], + [ '1', null, '10', null, null, '1', false ], + [ '1', null, '2', null, null, '1', false ], + [ '1', null, '1', null, null, '1', false ], + // Max values testing. + [ '1', '1', null, 'foo', null, '0', false ], + [ '1', null, null, '10', null, '0', false ], + [ '1', null, null, '0', null, '0', false ], + [ '1', null, null, '-10', null, '-10', false ], + [ '1', null, null, '1', null, '0', false ], + [ '5', null, null, '3', '3', '2', false ], + [ '5', '2', '-6', '3', '2', '2', false ], + [ '-3', '5', '-10', '-3', null, '-5', false ], + // Step mismatch. + [ '1', '2', '-2', null, null, '0', false ], + [ '3', '2', '-2', null, null, '2', false ], + [ '3', '2', '-2', null, '2', '0', false ], + [ '3', '2', '-2', null, '-2', '6', false ], + [ '1', '2', '-6', null, null, '0', false ], + [ '1', '2', '-2', null, null, '0', false ], + [ '1', '3', '-6', null, null, '0', false ], + [ '2', '3', '-6', null, null, '0', false ], + [ '2', '3', '1', null, null, '1', false ], + [ '5', '3', '1', null, null, '4', false ], + [ '3', '2', '-6', null, null, '2', false ], + [ '5', '2', '-6', null, null, '4', false ], + [ '6', '2', '1', null, null, '5', false ], + [ '8', '3', '1', null, null, '7', false ], + [ '9', '2', '-10', null, null, '8', false ], + [ '7', '3', '-10', null, null, '5', false ], + [ '-2', '3', '-10', null, null, '-4', false ], + // Clamping. + [ '0', '2', '-1', null, null, '-1', false ], + [ '10', '2', '0', '4', '10', '0', false ], + [ '10', '2', '0', '4', '5', '0', false ], + // value = "" (NaN). + [ '', null, null, null, null, '-1', false ], + [ '', '2', null, null, null, '-2', false ], + [ '', '2', '3', null, null, '3', false ], + [ '', null, '3', null, null, '3', false ], + [ '', '2', '3', '8', null, '3', false ], + [ '', null, '-10', '10', null, '-1', false ], + [ '', '3', '-10', '10', null, '-1', false ], + // With step = 'any'. + [ '0', 'any', null, null, 1, null, true ], + [ '0', 'ANY', null, null, 1, null, true ], + [ '0', 'AnY', null, null, 1, null, true ], + [ '0', 'aNy', null, null, 1, null, true ], + // With @value = step base. + [ '1', '2', null, null, null, '-1', false ], + ]}, + { type: 'range', data: [ + // Regular case. + [ '1', null, null, null, null, '0', false ], + // Argument testing. + [ '1', null, null, null, 1, '0', false ], + [ '9', null, null, null, 9, '0', false ], + [ '1', null, null, null, -1, '2', false ], + [ '1', null, null, null, 0, '1', false ], + // Float values are rounded to integer (1.1 -> 1). + [ '1', null, null, null, 1.1, '0', false ], + // With step values. + [ '1', '0.5', null, null, null, '0.5', false ], + [ '1', '0.25', null, null, 4, '0', false ], + // step = 0 isn't allowed (-> step = 1). + [ '1', '0', null, null, null, '0', false ], + // step < 0 isn't allowed (-> step = 1). + [ '1', '-1', null, null, null, '0', false ], + // step = NaN isn't allowed (-> step = 1). + [ '1', 'foo', null, null, null, '0', false ], + // Min values testing. + [ '1', '1', 'foo', null, null, '0', false ], + [ '1', null, '-10', null, null, '0', false ], + [ '1', null, '0', null, null, '0', false ], + [ '1', null, '10', null, null, '10', false ], + [ '1', null, '2', null, null, '2', false ], + [ '1', null, '1', null, null, '1', false ], + // Max values testing. + [ '1', '1', null, 'foo', null, '0', false ], + [ '1', null, null, '10', null, '0', false ], + [ '1', null, null, '0', null, '0', false ], + [ '1', null, null, '-10', null, '0', false ], + [ '1', null, null, '1', null, '0', false ], + [ '5', null, null, '3', '3', '0', false ], + [ '5', '2', '-6', '3', '2', '-2', false ], + [ '-3', '5', '-10', '-3', null, '-10', false ], + // Step mismatch. + [ '1', '2', '-2', null, null, '0', false ], + [ '3', '2', '-2', null, null, '2', false ], + [ '3', '2', '-2', null, '2', '0', false ], + [ '3', '2', '-2', null, '-2', '8', false ], + [ '1', '2', '-6', null, null, '0', false ], + [ '1', '2', '-2', null, null, '0', false ], + [ '1', '3', '-6', null, null, '-3', false ], + [ '2', '3', '-6', null, null, '0', false ], + [ '2', '3', '1', null, null, '1', false ], + [ '5', '3', '1', null, null, '1', false ], + [ '3', '2', '-6', null, null, '2', false ], + [ '5', '2', '-6', null, null, '4', false ], + [ '6', '2', '1', null, null, '5', false ], + [ '8', '3', '1', null, null, '4', false ], + [ '9', '2', '-10', null, null, '8', false ], + [ '7', '3', '-10', null, null, '5', false ], + [ '-2', '3', '-10', null, null, '-4', false ], + // Clamping. + [ '0', '2', '-1', null, null, '-1', false ], + [ '10', '2', '0', '4', '10', '0', false ], + [ '10', '2', '0', '4', '5', '0', false ], + // value = "" (default will be 50). + [ '', null, null, null, null, '49', false ], + // With step = 'any'. + [ '0', 'any', null, null, 1, null, true ], + [ '0', 'ANY', null, null, 1, null, true ], + [ '0', 'AnY', null, null, 1, null, true ], + [ '0', 'aNy', null, null, 1, null, true ], + // With @value = step base. + [ '1', '2', null, null, null, '1', false ], + ]}, + { type: 'date', data: [ + // Regular case. + [ '2012-07-09', null, null, null, null, '2012-07-08', false ], + // Argument testing. + [ '2012-07-09', null, null, null, 1, '2012-07-08', false ], + [ '2012-07-09', null, null, null, 5, '2012-07-04', false ], + [ '2012-07-09', null, null, null, -1, '2012-07-10', false ], + [ '2012-07-09', null, null, null, 0, '2012-07-09', false ], + // Month/Year wrapping. + [ '2012-08-01', null, null, null, 1, '2012-07-31', false ], + [ '1969-01-02', null, null, null, 4, '1968-12-29', false ], + [ '1969-01-01', null, null, null, -365, '1970-01-01', false ], + [ '2012-02-29', null, null, null, -1, '2012-03-01', false ], + // Float values are rounded to integer (1.1 -> 1). + [ '2012-01-02', null, null, null, 1.1, '2012-01-01', false ], + [ '2012-01-02', null, null, null, 1.9, '2012-01-01', false ], + // With step values. + [ '2012-01-03', '0.5', null, null, null, '2012-01-02', false ], + [ '2012-01-02', '0.5', null, null, null, '2012-01-01', false ], + [ '2012-01-01', '2', null, null, null, '2011-12-30', false ], + [ '2012-01-02', '0.25',null, null, 4, '2011-12-29', false ], + [ '2012-01-15', '1.1', '2012-01-01', null, 1, '2012-01-14', false ], + [ '2012-01-12', '1.1', '2012-01-01', null, 2, '2012-01-10', false ], + [ '2012-01-23', '1.1', '2012-01-01', null, 10, '2012-01-13', false ], + [ '2012-01-23', '1.1', '2012-01-01', null, 11, '2012-01-12', false ], + [ '1968-01-12', '1.1', '1968-01-01', null, 8, '1968-01-04', false ], + // step = 0 isn't allowed (-> step = 1). + [ '2012-01-02', '0', null, null, null, '2012-01-01', false ], + // step < 0 isn't allowed (-> step = 1). + [ '2012-01-02', '-1', null, null, null, '2012-01-01', false ], + // step = NaN isn't allowed (-> step = 1). + [ '2012-01-02', 'foo', null, null, null, '2012-01-01', false ], + // Min values testing. + [ '2012-01-03', '1', 'foo', null, 2, '2012-01-01', false ], + [ '2012-01-02', '1', '2012-01-01', null, null, '2012-01-01', false ], + [ '2012-01-01', '1', '2012-01-01', null, null, '2012-01-01', false ], + [ '2012-01-01', '1', '2012-01-10', null, 1, '2012-01-01', false ], + [ '2012-01-05', '3', '2012-01-01', null, null, '2012-01-04', false ], + [ '1969-01-01', '5', '1969-01-01', '1969-01-02', null, '1969-01-01', false ], + // Max values testing. + [ '2012-01-02', '1', null, 'foo', null, '2012-01-01', false ], + [ '2012-01-02', null, null, '2012-01-05', null, '2012-01-01', false ], + [ '2012-01-03', null, null, '2012-01-03', null, '2012-01-02', false ], + [ '2012-01-07', null, null, '2012-01-04', 4, '2012-01-03', false ], + [ '2012-01-07', '2', null, '2012-01-04', 3, '2012-01-01', false ], + // Step mismatch. + [ '2012-01-04', '2', '2012-01-01', null, null, '2012-01-03', false ], + [ '2012-01-06', '2', '2012-01-01', null, 2, '2012-01-03', false ], + [ '2012-01-05', '2', '2012-01-04', '2012-01-08', null, '2012-01-04', false ], + [ '1970-01-04', '2', null, null, null, '1970-01-02', false ], + [ '1970-01-09', '3', null, null, null, '1970-01-06', false ], + // Clamping. + [ '2012-05-01', null, null, '2012-01-05', null, '2012-01-05', false ], + [ '1970-01-05', '2', '1970-01-02', '1970-01-05', null, '1970-01-04', false ], + [ '1970-01-01', '5', '1970-01-02', '1970-01-09', 10, '1970-01-01', false ], + [ '1970-01-07', '5', '1969-12-27', '1970-01-06', 2, '1970-01-01', false ], + [ '1970-03-08', '3', '1970-02-01', '1970-02-07', 15, '1970-02-01', false ], + [ '1970-01-10', '3', '1970-01-01', '1970-01-06', 2, '1970-01-04', false ], + // value = "" (NaN). + [ '', null, null, null, null, '1969-12-31', false ], + // With step = 'any'. + [ '2012-01-01', 'any', null, null, 1, null, true ], + [ '2012-01-01', 'ANY', null, null, 1, null, true ], + [ '2012-01-01', 'AnY', null, null, 1, null, true ], + [ '2012-01-01', 'aNy', null, null, 1, null, true ], + ]}, + { type: 'time', data: [ + // Regular case. + [ '16:39', null, null, null, null, '16:38', false ], + // Argument testing. + [ '16:40', null, null, null, 1, '16:39', false ], + [ '16:40', null, null, null, 5, '16:35', false ], + [ '16:40', null, null, null, -1, '16:41', false ], + [ '16:40', null, null, null, 0, '16:40', false ], + // hour/minutes/seconds wrapping. + [ '05:00', null, null, null, null, '04:59', false ], + [ '05:00:00', 1, null, null, null, '04:59:59', false ], + [ '05:00:00', 0.1, null, null, null, '04:59:59.900', false ], + [ '05:00:00', 0.01, null, null, null, '04:59:59.990', false ], + [ '05:00:00', 0.001, null, null, null, '04:59:59.999', false ], + // stepDown() on '00:00' gives '23:59'. + [ '00:00', null, null, null, 1, '23:59', false ], + [ '00:00', null, null, null, 3, '23:57', false ], + // Some random step values.. + [ '16:56', '0.5', null, null, null, '16:55:59.500', false ], + [ '16:56', '2', null, null, null, '16:55:58', false ], + [ '16:56', '0.25',null, null, 4, '16:55:59', false ], + [ '16:57', '1.1', '16:00', null, 1, '16:56:59.900', false ], + [ '16:57', '1.1', '16:00', null, 2, '16:56:58.800', false ], + [ '16:57', '1.1', '16:00', null, 10, '16:56:50', false ], + [ '16:57', '1.1', '16:00', null, 11, '16:56:48.900', false ], + [ '16:57', '1.1', '16:00', null, 8, '16:56:52.200', false ], + // Invalid @step, means that we use the default value. + [ '17:01', '0', null, null, null, '17:00', false ], + [ '17:01', '-1', null, null, null, '17:00', false ], + [ '17:01', 'foo', null, null, null, '17:00', false ], + // Min values testing. + [ '17:02', '60', 'foo', null, 2, '17:00', false ], + [ '17:10', '60', '17:09', null, null, '17:09', false ], + [ '17:10', '60', '17:10', null, null, '17:10', false ], + [ '17:10', '60', '17:30', null, 1, '17:10', false ], + [ '17:10', '180', '17:05', null, null, '17:08', false ], + [ '17:10', '300', '17:10', '17:11', null, '17:10', false ], + // Max values testing. + [ '17:15', '60', null, 'foo', null, '17:14', false ], + [ '17:15', null, null, '17:20', null, '17:14', false ], + [ '17:15', null, null, '17:15', null, '17:14', false ], + [ '17:15', null, null, '17:13', 4, '17:11', false ], + [ '17:15', '120', null, '17:13', 3, '17:09', false ], + // Step mismatch. + [ '17:19', '120', '17:10', null, null, '17:18', false ], + [ '17:19', '120', '17:10', null, 2, '17:16', false ], + [ '17:19', '120', '17:18', '17:25', null, '17:18', false ], + [ '17:19', '120', null, null, null, '17:17', false ], + [ '17:19', '180', null, null, null, '17:16', false ], + // Clamping. + [ '17:22', null, null, '17:11', null, '17:11', false ], + [ '17:22', '120', '17:20', '17:22', null, '17:20', false ], + [ '17:22', '300', '17:12', '17:20', 10, '17:12', false ], + [ '17:22', '300', '17:18', '17:20', 2, '17:18', false ], + [ '17:22', '180', '17:00', '17:20', 15, '17:00', false ], + [ '17:22', '180', '17:10', '17:20', 2, '17:16', false ], + // value = "" (NaN). + [ '', null, null, null, null, '23:59', false ], + // With step = 'any'. + [ '17:26', 'any', null, null, 1, null, true ], + [ '17:26', 'ANY', null, null, 1, null, true ], + [ '17:26', 'AnY', null, null, 1, null, true ], + [ '17:26', 'aNy', null, null, 1, null, true ], + ]}, + { type: 'month', data: [ + // Regular case. + [ '2016-08', null, null, null, null, '2016-07', false ], + // Argument testing. + [ '2016-08', null, null, null, 1, '2016-07', false ], + [ '2016-08', null, null, null, 5, '2016-03', false ], + [ '2016-08', null, null, null, -1, '2016-09', false ], + [ '2016-08', null, null, null, 0, '2016-08', false ], + // Month/Year wrapping. + [ '2016-01', null, null, null, 1, '2015-12', false ], + [ '1969-02', null, null, null, 4, '1968-10', false ], + [ '1969-01', null, null, null, -12, '1970-01', false ], + // Float values are rounded to integer (1.1 -> 1). + [ '2016-08', null, null, null, 1.1, '2016-07', false ], + [ '2016-01', null, null, null, 1.9, '2015-12', false ], + // With step values. + [ '2016-03', '0.5', null, null, null, '2016-02', false ], + [ '2016-03', '2', null, null, null, '2016-01', false ], + [ '2016-03', '0.25',null, null, 4, '2015-11', false ], + [ '2016-12', '1.1', '2016-01', null, 1, '2016-11', false ], + [ '2016-12', '1.1', '2016-01', null, 2, '2016-10', false ], + [ '2016-12', '1.1', '2016-01', null, 10, '2016-02', false ], + [ '2016-12', '1.1', '2016-01', null, 12, '2016-01', false ], + [ '1968-12', '1.1', '1968-01', null, 8, '1968-04', false ], + // step = 0 isn't allowed (-> step = 1). + [ '2016-02', '0', null, null, null, '2016-01', false ], + // step < 0 isn't allowed (-> step = 1). + [ '2016-02', '-1', null, null, null, '2016-01', false ], + // step = NaN isn't allowed (-> step = 1). + [ '2016-02', 'foo', null, null, null, '2016-01', false ], + // Min values testing. + [ '2016-03', '1', 'foo', null, 2, '2016-01', false ], + [ '2016-02', '1', '2016-01', null, null, '2016-01', false ], + [ '2016-01', '1', '2016-01', null, null, '2016-01', false ], + [ '2016-01', '1', '2016-01', null, 1, '2016-01', false ], + [ '2016-05', '3', '2016-01', null, null, '2016-04', false ], + [ '1969-01', '5', '1969-01', '1969-02', null, '1969-01', false ], + // Max values testing. + [ '2016-02', '1', null, 'foo', null, '2016-01', false ], + [ '2016-02', null, null, '2016-05', null, '2016-01', false ], + [ '2016-03', null, null, '2016-03', null, '2016-02', false ], + [ '2016-07', null, null, '2016-04', 4, '2016-03', false ], + [ '2016-07', '2', null, '2016-04', 3, '2016-01', false ], + // Step mismatch. + [ '2016-04', '2', '2016-01', null, null, '2016-03', false ], + [ '2016-06', '2', '2016-01', null, 2, '2016-03', false ], + [ '2016-05', '2', '2016-04', '2016-08', null, '2016-04', false ], + [ '1970-04', '2', null, null, null, '1970-02', false ], + [ '1970-09', '3', null, null, null, '1970-06', false ], + // Clamping. + [ '2016-05', null, null, '2016-01', null, '2016-01', false ], + [ '1970-05', '2', '1970-02', '1970-05', null, '1970-04', false ], + [ '1970-01', '5', '1970-02', '1970-09', 10, '1970-01', false ], + [ '1970-07', '5', '1969-12', '1970-10', 2, '1969-12', false ], + [ '1970-08', '3', '1970-01', '1970-07', 15, '1970-01', false ], + [ '1970-10', '3', '1970-01', '1970-06', 2, '1970-04', false ], + // value = "" (NaN). + [ '', null, null, null, null, '1969-12', false ], + // With step = 'any'. + [ '2016-01', 'any', null, null, 1, null, true ], + [ '2016-01', 'ANY', null, null, 1, null, true ], + [ '2016-01', 'AnY', null, null, 1, null, true ], + [ '2016-01', 'aNy', null, null, 1, null, true ], + ]}, + { type: 'week', data: [ + // Regular case. + [ '2016-W40', null, null, null, null, '2016-W39', false ], + // Argument testing. + [ '2016-W40', null, null, null, 1, '2016-W39', false ], + [ '2016-W40', null, null, null, 5, '2016-W35', false ], + [ '2016-W40', null, null, null, -1, '2016-W41', false ], + [ '2016-W40', null, null, null, 0, '2016-W40', false ], + // Week/Year wrapping. + [ '2016-W01', null, null, null, 1, '2015-W53', false ], + [ '1969-W02', null, null, null, 4, '1968-W50', false ], + [ '1969-W01', null, null, null, -52, '1970-W01', false ], + // Float values are rounded to integer (1.1 -> 1). + [ '2016-W40', null, null, null, 1.1, '2016-W39', false ], + [ '2016-W01', null, null, null, 1.9, '2015-W53', false ], + // With step values. + [ '2016-W03', '0.5', null, null, null, '2016-W02', false ], + [ '2016-W03', '2', null, null, null, '2016-W01', false ], + [ '2016-W03', '0.25', null, null, 4, '2015-W52', false ], + [ '2016-W52', '1.1', '2016-W01', null, 1, '2016-W51', false ], + [ '2016-W52', '1.1', '2016-W01', null, 2, '2016-W50', false ], + [ '2016-W52', '1.1', '2016-W01', null, 10, '2016-W42', false ], + [ '2016-W52', '1.1', '2016-W01', null, 52, '2016-W01', false ], + [ '1968-W52', '1.1', '1968-W01', null, 8, '1968-W44', false ], + // step = 0 isn't allowed (-> step = 1). + [ '2016-W02', '0', null, null, null, '2016-W01', false ], + // step < 0 isn't allowed (-> step = 1). + [ '2016-W02', '-1', null, null, null, '2016-W01', false ], + // step = NaN isn't allowed (-> step = 1). + [ '2016-W02', 'foo', null, null, null, '2016-W01', false ], + // Min values testing. + [ '2016-W03', '1', 'foo', null, 2, '2016-W01', false ], + [ '2016-W02', '1', '2016-01', null, null, '2016-W01', false ], + [ '2016-W01', '1', '2016-W01', null, null, '2016-W01', false ], + [ '2016-W01', '1', '2016-W01', null, 1, '2016-W01', false ], + [ '2016-W05', '3', '2016-W01', null, null, '2016-W04', false ], + [ '1969-W01', '5', '1969-W01', '1969-W02', null, '1969-W01', false ], + // Max values testing. + [ '2016-W02', '1', null, 'foo', null, '2016-W01', false ], + [ '2016-W02', null, null, '2016-W05', null, '2016-W01', false ], + [ '2016-W03', null, null, '2016-W03', null, '2016-W02', false ], + [ '2016-W07', null, null, '2016-W04', 4, '2016-W03', false ], + [ '2016-W07', '2', null, '2016-W04', 3, '2016-W01', false ], + // Step mismatch. + [ '2016-W04', '2', '2016-W01', null, null, '2016-W03', false ], + [ '2016-W06', '2', '2016-W01', null, 2, '2016-W03', false ], + [ '2016-W05', '2', '2016-W04', '2016-W08', null, '2016-W04', false ], + [ '1970-W04', '2', null, null, null, '1970-W02', false ], + [ '1970-W09', '3', null, null, null, '1970-W06', false ], + // Clamping. + [ '2016-W05', null, null, '2016-W01', null, '2016-W01', false ], + [ '1970-W05', '2', '1970-W02', '1970-W05', null, '1970-W04', false ], + [ '1970-W01', '5', '1970-W02', '1970-W09', 10, '1970-W01', false ], + [ '1970-W07', '5', '1969-W52', '1970-W10', 2, '1969-W52', false ], + [ '1970-W08', '3', '1970-W01', '1970-W07', 15, '1970-W01', false ], + [ '1970-W10', '3', '1970-W01', '1970-W06', 2, '1970-W04', false ], + // value = "" (NaN). + [ '', null, null, null, null, '1970-W01', false ], + // With step = 'any'. + [ '2016-W01', 'any', null, null, 1, null, true ], + [ '2016-W01', 'ANY', null, null, 1, null, true ], + [ '2016-W01', 'AnY', null, null, 1, null, true ], + [ '2016-W01', 'aNy', null, null, 1, null, true ], + ]}, + { type: 'datetime-local', data: [ + // Regular case. + [ '2017-02-07T09:30', null, null, null, null, '2017-02-07T09:29', false ], + // Argument testing. + [ '2017-02-07T09:30', null, null, null, 1, '2017-02-07T09:29', false ], + [ '2017-02-07T09:30', null, null, null, 5, '2017-02-07T09:25', false ], + [ '2017-02-07T09:30', null, null, null, -1, '2017-02-07T09:31', false ], + [ '2017-02-07T09:30', null, null, null, 0, '2017-02-07T09:30', false ], + // hour/minutes/seconds wrapping. + [ '2000-01-01T05:00', null, null, null, null, '2000-01-01T04:59', false ], + [ '2000-01-01T05:00:00', 1, null, null, null, '2000-01-01T04:59:59', false ], + [ '2000-01-01T05:00:00', 0.1, null, null, null, '2000-01-01T04:59:59.900', false ], + [ '2000-01-01T05:00:00', 0.01, null, null, null, '2000-01-01T04:59:59.990', false ], + [ '2000-01-01T05:00:00', 0.001, null, null, null, '2000-01-01T04:59:59.999', false ], + // month/year wrapping. + [ '2012-08-01T12:00', null, null, null, 1440, '2012-07-31T12:00', false ], + [ '1969-01-02T12:00', null, null, null, 5760, '1968-12-29T12:00', false ], + [ '1969-12-31T00:00', null, null, null, -1440, '1970-01-01T00:00', false ], + [ '2012-02-29T00:00', null, null, null, -1440, '2012-03-01T00:00', false ], + // stepDown() on '00:00' gives '23:59'. + [ '2017-02-07T00:00', null, null, null, 1, '2017-02-06T23:59', false ], + [ '2017-02-07T00:00', null, null, null, 3, '2017-02-06T23:57', false ], + // Some random step values.. + [ '2017-02-07T16:07', '0.5', null, null, null, '2017-02-07T16:06:59.500', false ], + [ '2017-02-07T16:07', '2', null, null, null, '2017-02-07T16:06:58', false ], + [ '2017-02-07T16:07', '0.25', null, null, 4, '2017-02-07T16:06:59', false ], + [ '2017-02-07T16:07', '1.1', '2017-02-07T16:00', null, 1, '2017-02-07T16:06:59.100', false ], + [ '2017-02-07T16:07', '1.1', '2017-02-07T16:00', null, 2, '2017-02-07T16:06:58', false ], + [ '2017-02-07T16:07', '1.1', '2017-02-07T16:00', null, 10, '2017-02-07T16:06:49.200', false ], + [ '2017-02-07T16:07', '129600', '2017-02-01T00:00', null, 2, '2017-02-05T12:00', false ], + // step = 0 isn't allowed (-> step = 1). + [ '2017-02-07T10:15', '0', null, null, null, '2017-02-07T10:14', false ], + // step < 0 isn't allowed (-> step = 1). + [ '2017-02-07T10:15', '-1', null, null, null, '2017-02-07T10:14', false ], + // step = NaN isn't allowed (-> step = 1). + [ '2017-02-07T10:15', 'foo', null, null, null, '2017-02-07T10:14', false ], + // Min values testing. + [ '2012-02-02T17:02', '60', 'foo', null, 2, '2012-02-02T17:00', false ], + [ '2012-02-02T17:10', '60', '2012-02-02T17:09', null, null, '2012-02-02T17:09', false ], + [ '2012-02-02T17:10', '60', '2012-02-02T17:10', null, null, '2012-02-02T17:10', false ], + [ '2012-02-02T17:10', '60', '2012-02-02T17:30', null, 1, '2012-02-02T17:10', false ], + [ '2012-02-02T17:10', '180', '2012-02-02T17:05', null, null, '2012-02-02T17:08', false ], + [ '2012-02-03T20:05', '86400', '2012-02-02T17:05', null, null, '2012-02-03T17:05', false ], + [ '2012-02-03T18:00', '129600', '2012-02-01T00:00', null, null, '2012-02-02T12:00', false ], + // Max values testing. + [ '2012-02-02T17:15', '60', null, 'foo', null, '2012-02-02T17:14', false ], + [ '2012-02-02T17:15', null, null, '2012-02-02T17:20', null, '2012-02-02T17:14', false ], + [ '2012-02-02T17:15', null, null, '2012-02-02T17:15', null, '2012-02-02T17:14', false ], + [ '2012-02-02T17:15', null, null, '2012-02-02T17:13', 4, '2012-02-02T17:11', false ], + [ '2012-02-02T17:15', '120', null, '2012-02-02T17:13', 3, '2012-02-02T17:09', false ], + [ '2012-02-03T20:05', '86400', null, '2012-02-03T20:05', null, '2012-02-02T20:05', false ], + [ '2012-02-03T18:00', '129600', null, '2012-02-03T20:00', null, '2012-02-02T06:00', false ], + // Step mismatch. + [ '2017-02-07T17:19', '120', '2017-02-07T17:10', null, null, '2017-02-07T17:18', false ], + [ '2017-02-07T17:19', '120', '2017-02-07T17:10', null, 2, '2017-02-07T17:16', false ], + [ '2017-02-07T17:19', '120', '2017-02-07T17:18', '2017-02-07T17:25', null, '2017-02-07T17:18', false ], + [ '2017-02-07T17:19', '120', null, null, null, '2017-02-07T17:17', false ], + [ '2017-02-07T17:19', '180', null, null, null, '2017-02-07T17:16', false ], + [ '2017-02-07T17:19', '172800', '2017-02-02T17:19', '2017-02-10T17:19', null, '2017-02-06T17:19', false ], + // Clamping. + [ '2017-02-07T17:22', null, null, '2017-02-07T17:11', null, '2017-02-07T17:11', false ], + [ '2017-02-07T17:22', '120', '2017-02-07T17:20', '2017-02-07T17:22', null, '2017-02-07T17:20', false ], + [ '2017-02-07T17:22', '300', '2017-02-07T17:12', '2017-02-07T17:20', 10, '2017-02-07T17:12', false ], + [ '2017-02-07T17:22', '300', '2017-02-07T17:18', '2017-02-07T17:20', 2, '2017-02-07T17:18', false ], + [ '2017-02-07T17:22', '600', '2017-02-02T17:00', '2017-02-07T17:00', 15, '2017-02-07T15:00', false ], + [ '2017-02-07T17:22', '600', '2017-02-02T17:00', '2017-02-07T17:00', 2, '2017-02-07T17:00', false ], + // value = "" (NaN). + [ '', null, null, null, null, '1969-12-31T23:59', false ], + // With step = 'any'. + [ '2017-02-07T15:20', 'any', null, null, 1, null, true ], + [ '2017-02-07T15:20', 'ANY', null, null, 1, null, true ], + [ '2017-02-07T15:20', 'AnY', null, null, 1, null, true ], + [ '2017-02-07T15:20', 'aNy', null, null, 1, null, true ], + ]}, + ]; + + for (var test of testData) { + for (var data of test.data) { + var element = document.createElement("input"); + element.type = test.type; + + if (data[1] != null) { + element.step = data[1]; + } + + if (data[2] != null) { + element.min = data[2]; + } + + if (data[3] != null) { + element.max = data[3]; + } + + // Set 'value' last for type=range, because the final sanitized value + // after setting 'step', 'min' and 'max' can be affected by the order in + // which those attributes are set. Setting 'value' last makes it simpler + // to reason about what the final value should be. + if (data[0] != null) { + element.setAttribute('value', data[0]); + } + + var exceptionCaught = false; + try { + if (data[4] != null) { + element.stepDown(data[4]); + } else { + element.stepDown(); + } + + is(element.value, data[5], "The value for type=" + test.type + " should be " + data[5]); + } catch (e) { + exceptionCaught = true; + is(element.value, data[0], e.name + "The value should not have changed"); + is(e.name, 'InvalidStateError', + "It should be a InvalidStateError exception."); + } finally { + is(exceptionCaught, data[6], "exception status should be " + data[6]); + } + } + } +} + +function checkStepUp() +{ + // This testData is very similar to the one in checkStepDown with some changes + // relative to stepUp. + var testData = [ + /* Initial value | step | min | max | stepUp arg | final value | exception */ + { type: 'number', data: [ + // Regular case. + [ '1', null, null, null, null, '2', false ], + // Argument testing. + [ '1', null, null, null, 1, '2', false ], + [ '9', null, null, null, 9, '18', false ], + [ '1', null, null, null, -1, '0', false ], + [ '1', null, null, null, 0, '1', false ], + // Float values are rounded to integer (1.1 -> 1). + [ '1', null, null, null, 1.1, '2', false ], + // With step values. + [ '1', '0.5', null, null, null, '1.5', false ], + [ '1', '0.25', null, null, 4, '2', false ], + // step = 0 isn't allowed (-> step = 1). + [ '1', '0', null, null, null, '2', false ], + // step < 0 isn't allowed (-> step = 1). + [ '1', '-1', null, null, null, '2', false ], + // step = NaN isn't allowed (-> step = 1). + [ '1', 'foo', null, null, null, '2', false ], + // Min values testing. + [ '1', '1', 'foo', null, null, '2', false ], + [ '1', null, '-10', null, null, '2', false ], + [ '1', null, '0', null, null, '2', false ], + [ '1', null, '10', null, null, '10', false ], + [ '1', null, '2', null, null, '2', false ], + [ '1', null, '1', null, null, '2', false ], + [ '0', null, '4', null, '5', '5', false ], + [ '0', '2', '5', null, '3', '5', false ], + // Max values testing. + [ '1', '1', null, 'foo', null, '2', false ], + [ '1', null, null, '10', null, '2', false ], + [ '1', null, null, '0', null, '1', false ], + [ '1', null, null, '-10', null, '1', false ], + [ '1', null, null, '1', null, '1', false ], + [ '-3', '5', '-10', '-3', null, '-3', false ], + // Step mismatch. + [ '1', '2', '0', null, null, '2', false ], + [ '1', '2', '0', null, '2', '4', false ], + [ '8', '2', null, '9', null, '8', false ], + [ '-3', '2', '-6', null, null, '-2', false ], + [ '9', '3', '-10', null, null, '11', false ], + [ '7', '3', '-10', null, null, '8', false ], + [ '7', '3', '5', null, null, '8', false ], + [ '9', '4', '3', null, null, '11', false ], + [ '-2', '3', '-6', null, null, '0', false ], + [ '7', '3', '6', null, null, '9', false ], + // Clamping. + [ '1', '2', '0', '3', null, '2', false ], + [ '0', '5', '1', '8', '10', '6', false ], + [ '-9', '3', '-8', '-1', '5', '-2', false ], + [ '-9', '3', '8', '15', '15', '14', false ], + [ '-1', '3', '-1', '4', '3', '2', false ], + [ '-3', '2', '-6', '-2', null, '-2', false ], + [ '-3', '2', '-6', '-1', null, '-2', false ], + // value = "" (NaN). + [ '', null, null, null, null, '1', false ], + [ '', null, null, null, null, '1', false ], + [ '', '2', null, null, null, '2', false ], + [ '', '2', '3', null, null, '3', false ], + [ '', null, '3', null, null, '3', false ], + [ '', '2', '3', '8', null, '3', false ], + [ '', null, '-10', '10', null, '1', false ], + [ '', '3', '-10', '10', null, '2', false ], + // With step = 'any'. + [ '0', 'any', null, null, 1, null, true ], + [ '0', 'ANY', null, null, 1, null, true ], + [ '0', 'AnY', null, null, 1, null, true ], + [ '0', 'aNy', null, null, 1, null, true ], + // With @value = step base. + [ '1', '2', null, null, null, '3', false ], + ]}, + { type: 'range', data: [ + // Regular case. + [ '1', null, null, null, null, '2', false ], + // Argument testing. + [ '1', null, null, null, 1, '2', false ], + [ '9', null, null, null, 9, '18', false ], + [ '1', null, null, null, -1, '0', false ], + [ '1', null, null, null, 0, '1', false ], + // Float values are rounded to integer (1.1 -> 1). + [ '1', null, null, null, 1.1, '2', false ], + // With step values. + [ '1', '0.5', null, null, null, '1.5', false ], + [ '1', '0.25', null, null, 4, '2', false ], + // step = 0 isn't allowed (-> step = 1). + [ '1', '0', null, null, null, '2', false ], + // step < 0 isn't allowed (-> step = 1). + [ '1', '-1', null, null, null, '2', false ], + // step = NaN isn't allowed (-> step = 1). + [ '1', 'foo', null, null, null, '2', false ], + // Min values testing. + [ '1', '1', 'foo', null, null, '2', false ], + [ '1', null, '-10', null, null, '2', false ], + [ '1', null, '0', null, null, '2', false ], + [ '1', null, '10', null, null, '11', false ], + [ '1', null, '2', null, null, '3', false ], + [ '1', null, '1', null, null, '2', false ], + [ '0', null, '4', null, '5', '9', false ], + [ '0', '2', '5', null, '3', '11', false ], + // Max values testing. + [ '1', '1', null, 'foo', null, '2', false ], + [ '1', null, null, '10', null, '2', false ], + [ '1', null, null, '0', null, '0', false ], + [ '1', null, null, '-10', null, '0', false ], + [ '1', null, null, '1', null, '1', false ], + [ '-3', '5', '-10', '-3', null, '-5', false ], + // Step mismatch. + [ '1', '2', '0', null, null, '4', false ], + [ '1', '2', '0', null, '2', '6', false ], + [ '8', '2', null, '9', null, '8', false ], + [ '-3', '2', '-6', null, null, '0', false ], + [ '9', '3', '-10', null, null, '11', false ], + [ '7', '3', '-10', null, null, '11', false ], + [ '7', '3', '5', null, null, '11', false ], + [ '9', '4', '3', null, null, '15', false ], + [ '-2', '3', '-6', null, null, '0', false ], + [ '7', '3', '6', null, null, '9', false ], + // Clamping. + [ '1', '2', '0', '3', null, '2', false ], + [ '0', '5', '1', '8', '10', '6', false ], + [ '-9', '3', '-8', '-1', '5', '-2', false ], + [ '-9', '3', '8', '15', '15', '14', false ], + [ '-1', '3', '-1', '4', '3', '2', false ], + [ '-3', '2', '-6', '-2', null, '-2', false ], + [ '-3', '2', '-6', '-1', null, '-2', false ], + // value = "" (default will be 50). + [ '', null, null, null, null, '51', false ], + // With step = 'any'. + [ '0', 'any', null, null, 1, null, true ], + [ '0', 'ANY', null, null, 1, null, true ], + [ '0', 'AnY', null, null, 1, null, true ], + [ '0', 'aNy', null, null, 1, null, true ], + // With @value = step base. + [ '1', '2', null, null, null, '3', false ], + ]}, + { type: 'date', data: [ + // Regular case. + [ '2012-07-09', null, null, null, null, '2012-07-10', false ], + // Argument testing. + [ '2012-07-09', null, null, null, 1, '2012-07-10', false ], + [ '2012-07-09', null, null, null, 9, '2012-07-18', false ], + [ '2012-07-09', null, null, null, -1, '2012-07-08', false ], + [ '2012-07-09', null, null, null, 0, '2012-07-09', false ], + // Month/Year wrapping. + [ '2012-07-31', null, null, null, 1, '2012-08-01', false ], + [ '1968-12-29', null, null, null, 4, '1969-01-02', false ], + [ '1970-01-01', null, null, null, -365, '1969-01-01', false ], + [ '2012-03-01', null, null, null, -1, '2012-02-29', false ], + // Float values are rounded to integer (1.1 -> 1). + [ '2012-01-01', null, null, null, 1.1, '2012-01-02', false ], + [ '2012-01-01', null, null, null, 1.9, '2012-01-02', false ], + // With step values. + [ '2012-01-01', '0.5', null, null, null, '2012-01-02', false ], + [ '2012-01-01', '2', null, null, null, '2012-01-03', false ], + [ '2012-01-01', '0.25', null, null, 4, '2012-01-05', false ], + [ '2012-01-01', '1.1', '2012-01-01', null, 1, '2012-01-02', false ], + [ '2012-01-01', '1.1', '2012-01-01', null, 2, '2012-01-03', false ], + [ '2012-01-01', '1.1', '2012-01-01', null, 10, '2012-01-11', false ], + [ '2012-01-01', '1.1', '2012-01-01', null, 11, '2012-01-12', false ], + // step = 0 isn't allowed (-> step = 1). + [ '2012-01-01', '0', null, null, null, '2012-01-02', false ], + // step < 0 isn't allowed (-> step = 1). + [ '2012-01-01', '-1', null, null, null, '2012-01-02', false ], + // step = NaN isn't allowed (-> step = 1). + [ '2012-01-01', 'foo', null, null, null, '2012-01-02', false ], + // Min values testing. + [ '2012-01-01', '1', 'foo', null, null, '2012-01-02', false ], + [ '2012-01-01', null, '2011-12-01', null, null, '2012-01-02', false ], + [ '2012-01-01', null, '2012-01-02', null, null, '2012-01-02', false ], + [ '2012-01-01', null, '2012-01-01', null, null, '2012-01-02', false ], + [ '2012-01-01', null, '2012-01-04', null, 4, '2012-01-05', false ], + [ '2012-01-01', '2', '2012-01-04', null, 3, '2012-01-06', false ], + // Max values testing. + [ '2012-01-01', '1', null, 'foo', 2, '2012-01-03', false ], + [ '2012-01-01', '1', null, '2012-01-10', 1, '2012-01-02', false ], + [ '2012-01-02', null, null, '2012-01-01', null, '2012-01-02', false ], + [ '2012-01-02', null, null, '2012-01-02', null, '2012-01-02', false ], + [ '1969-01-02', '5', '1969-01-01', '1969-01-02', null, '1969-01-02', false ], + // Step mismatch. + [ '2012-01-02', '2', '2012-01-01', null, null, '2012-01-03', false ], + [ '2012-01-02', '2', '2012-01-01', null, 2, '2012-01-05', false ], + [ '2012-01-05', '2', '2012-01-01', '2012-01-06', null, '2012-01-05', false ], + [ '1970-01-02', '2', null, null, null, '1970-01-04', false ], + [ '1970-01-05', '3', null, null, null, '1970-01-08', false ], + [ '1970-01-03', '3', null, null, null, '1970-01-06', false ], + [ '1970-01-03', '3', '1970-01-02', null, null, '1970-01-05', false ], + // Clamping. + [ '2012-01-01', null, '2012-01-31', null, null, '2012-01-31', false ], + [ '1970-01-02', '2', '1970-01-01', '1970-01-04', null, '1970-01-03', false ], + [ '1970-01-01', '5', '1970-01-02', '1970-01-09', 10, '1970-01-07', false ], + [ '1969-12-28', '5', '1969-12-29', '1970-01-06', 3, '1970-01-03', false ], + [ '1970-01-01', '3', '1970-02-01', '1970-02-07', 15, '1970-02-07', false ], + [ '1970-01-01', '3', '1970-01-01', '1970-01-06', 2, '1970-01-04', false ], + // value = "" (NaN). + [ '', null, null, null, null, '1970-01-02', false ], + // With step = 'any'. + [ '2012-01-01', 'any', null, null, 1, null, true ], + [ '2012-01-01', 'ANY', null, null, 1, null, true ], + [ '2012-01-01', 'AnY', null, null, 1, null, true ], + [ '2012-01-01', 'aNy', null, null, 1, null, true ], + ]}, + { type: 'time', data: [ + // Regular case. + [ '16:39', null, null, null, null, '16:40', false ], + // Argument testing. + [ '16:40', null, null, null, 1, '16:41', false ], + [ '16:40', null, null, null, 5, '16:45', false ], + [ '16:40', null, null, null, -1, '16:39', false ], + [ '16:40', null, null, null, 0, '16:40', false ], + // hour/minutes/seconds wrapping. + [ '04:59', null, null, null, null, '05:00', false ], + [ '04:59:59', 1, null, null, null, '05:00', false ], + [ '04:59:59.900', 0.1, null, null, null, '05:00', false ], + [ '04:59:59.990', 0.01, null, null, null, '05:00', false ], + [ '04:59:59.999', 0.001, null, null, null, '05:00', false ], + // stepUp() on '23:59' gives '00:00'. + [ '23:59', null, null, null, 1, '00:00', false ], + [ '23:59', null, null, null, 3, '00:02', false ], + // Some random step values.. + [ '16:56', '0.5', null, null, null, '16:56:00.500', false ], + [ '16:56', '2', null, null, null, '16:56:02', false ], + [ '16:56', '0.25',null, null, 4, '16:56:01', false ], + [ '16:57', '1.1', '16:00', null, 1, '16:57:01', false ], + [ '16:57', '1.1', '16:00', null, 2, '16:57:02.100', false ], + [ '16:57', '1.1', '16:00', null, 10, '16:57:10.900', false ], + [ '16:57', '1.1', '16:00', null, 11, '16:57:12', false ], + [ '16:57', '1.1', '16:00', null, 8, '16:57:08.700', false ], + // Invalid @step, means that we use the default value. + [ '17:01', '0', null, null, null, '17:02', false ], + [ '17:01', '-1', null, null, null, '17:02', false ], + [ '17:01', 'foo', null, null, null, '17:02', false ], + // Min values testing. + [ '17:02', '60', 'foo', null, 2, '17:04', false ], + [ '17:10', '60', '17:09', null, null, '17:11', false ], + [ '17:10', '60', '17:10', null, null, '17:11', false ], + [ '17:10', '60', '17:30', null, 1, '17:30', false ], + [ '17:10', '180', '17:05', null, null, '17:11', false ], + [ '17:10', '300', '17:10', '17:11', null,'17:10', false ], + // Max values testing. + [ '17:15', '60', null, 'foo', null, '17:16', false ], + [ '17:15', null, null, '17:20', null, '17:16', false ], + [ '17:15', null, null, '17:15', null, '17:15', false ], + [ '17:15', null, null, '17:13', 4, '17:15', false ], + [ '17:15', '120', null, '17:13', 3, '17:15', false ], + // Step mismatch. + [ '17:19', '120', '17:10', null, null, '17:20', false ], + [ '17:19', '120', '17:10', null, 2, '17:22', false ], + [ '17:19', '120', '17:18', '17:25', null, '17:20', false ], + [ '17:19', '120', null, null, null, '17:21', false ], + [ '17:19', '180', null, null, null, '17:22', false ], + // Clamping. + [ '17:22', null, null, '17:11', null, '17:22', false ], + [ '17:22', '120', '17:20', '17:22', null, '17:22', false ], + [ '17:22', '300', '17:12', '17:20', 10, '17:22', false ], + [ '17:22', '300', '17:18', '17:20', 2, '17:22', false ], + [ '17:22', '180', '17:00', '17:20', 15, '17:22', false ], + [ '17:22', '180', '17:10', '17:20', 2, '17:22', false ], + // value = "" (NaN). + [ '', null, null, null, null, '00:01', false ], + // With step = 'any'. + [ '17:26', 'any', null, null, 1, null, true ], + [ '17:26', 'ANY', null, null, 1, null, true ], + [ '17:26', 'AnY', null, null, 1, null, true ], + [ '17:26', 'aNy', null, null, 1, null, true ], + ]}, + { type: 'month', data: [ + // Regular case. + [ '2016-08', null, null, null, null, '2016-09', false ], + // Argument testing. + [ '2016-08', null, null, null, 1, '2016-09', false ], + [ '2016-08', null, null, null, 9, '2017-05', false ], + [ '2016-08', null, null, null, -1, '2016-07', false ], + [ '2016-08', null, null, null, 0, '2016-08', false ], + // Month/Year wrapping. + [ '2015-12', null, null, null, 1, '2016-01', false ], + [ '1968-12', null, null, null, 4, '1969-04', false ], + [ '1970-01', null, null, null, -12, '1969-01', false ], + // Float values are rounded to integer (1.1 -> 1). + [ '2016-01', null, null, null, 1.1, '2016-02', false ], + [ '2016-01', null, null, null, 1.9, '2016-02', false ], + // With step values. + [ '2016-01', '0.5', null, null, null, '2016-02', false ], + [ '2016-01', '2', null, null, null, '2016-03', false ], + [ '2016-01', '0.25', null, null, 4, '2016-05', false ], + [ '2016-01', '1.1', '2016-01', null, 1, '2016-02', false ], + [ '2016-01', '1.1', '2016-01', null, 2, '2016-03', false ], + [ '2016-01', '1.1', '2016-01', null, 10, '2016-11', false ], + [ '2016-01', '1.1', '2016-01', null, 11, '2016-12', false ], + // step = 0 isn't allowed (-> step = 1). + [ '2016-01', '0', null, null, null, '2016-02', false ], + // step < 0 isn't allowed (-> step = 1). + [ '2016-01', '-1', null, null, null, '2016-02', false ], + // step = NaN isn't allowed (-> step = 1). + [ '2016-01', 'foo', null, null, null, '2016-02', false ], + // Min values testing. + [ '2016-01', '1', 'foo', null, null, '2016-02', false ], + [ '2016-01', null, '2015-12', null, null, '2016-02', false ], + [ '2016-01', null, '2016-02', null, null, '2016-02', false ], + [ '2016-01', null, '2016-01', null, null, '2016-02', false ], + [ '2016-01', null, '2016-04', null, 4, '2016-05', false ], + [ '2016-01', '2', '2016-04', null, 3, '2016-06', false ], + // Max values testing. + [ '2016-01', '1', null, 'foo', 2, '2016-03', false ], + [ '2016-01', '1', null, '2016-02', 1, '2016-02', false ], + [ '2016-02', null, null, '2016-01', null, '2016-02', false ], + [ '2016-02', null, null, '2016-02', null, '2016-02', false ], + [ '1969-02', '5', '1969-01', '1969-02', null, '1969-02', false ], + // Step mismatch. + [ '2016-02', '2', '2016-01', null, null, '2016-03', false ], + [ '2016-02', '2', '2016-01', null, 2, '2016-05', false ], + [ '2016-05', '2', '2016-01', '2016-06', null, '2016-05', false ], + [ '1970-02', '2', null, null, null, '1970-04', false ], + [ '1970-05', '3', null, null, null, '1970-08', false ], + [ '1970-03', '3', null, null, null, '1970-06', false ], + [ '1970-03', '3', '1970-02', null, null, '1970-05', false ], + // Clamping. + [ '2016-01', null, '2016-12', null, null, '2016-12', false ], + [ '1970-02', '2', '1970-01', '1970-04', null, '1970-03', false ], + [ '1970-01', '5', '1970-02', '1970-09', 10, '1970-07', false ], + [ '1969-11', '5', '1969-12', '1970-06', 3, '1970-05', false ], + [ '1970-01', '3', '1970-02', '1971-07', 15, '1971-05', false ], + [ '1970-01', '3', '1970-01', '1970-06', 2, '1970-04', false ], + // value = "" (NaN). + [ '', null, null, null, null, '1970-02', false ], + // With step = 'any'. + [ '2016-01', 'any', null, null, 1, null, true ], + [ '2016-01', 'ANY', null, null, 1, null, true ], + [ '2016-01', 'AnY', null, null, 1, null, true ], + [ '2016-01', 'aNy', null, null, 1, null, true ], + ]}, + { type: 'week', data: [ + // Regular case. + [ '2016-W40', null, null, null, null, '2016-W41', false ], + // Argument testing. + [ '2016-W40', null, null, null, 1, '2016-W41', false ], + [ '2016-W40', null, null, null, 20, '2017-W08', false ], + [ '2016-W40', null, null, null, -1, '2016-W39', false ], + [ '2016-W40', null, null, null, 0, '2016-W40', false ], + // Week/Year wrapping. + [ '2015-W53', null, null, null, 1, '2016-W01', false ], + [ '1968-W52', null, null, null, 4, '1969-W04', false ], + [ '1970-W01', null, null, null, -52, '1969-W01', false ], + // Float values are rounded to integer (1.1 -> 1). + [ '2016-W01', null, null, null, 1.1, '2016-W02', false ], + [ '2016-W01', null, null, null, 1.9, '2016-W02', false ], + // With step values. + [ '2016-W01', '0.5', null, null, null, '2016-W02', false ], + [ '2016-W01', '2', null, null, null, '2016-W03', false ], + [ '2016-W01', '0.25', null, null, 4, '2016-W05', false ], + [ '2016-W01', '1.1', '2016-01', null, 1, '2016-W02', false ], + [ '2016-W01', '1.1', '2016-01', null, 2, '2016-W03', false ], + [ '2016-W01', '1.1', '2016-01', null, 10, '2016-W11', false ], + [ '2016-W01', '1.1', '2016-01', null, 20, '2016-W21', false ], + // step = 0 isn't allowed (-> step = 1). + [ '2016-W01', '0', null, null, null, '2016-W02', false ], + // step < 0 isn't allowed (-> step = 1). + [ '2016-W01', '-1', null, null, null, '2016-W02', false ], + // step = NaN isn't allowed (-> step = 1). + [ '2016-W01', 'foo', null, null, null, '2016-W02', false ], + // Min values testing. + [ '2016-W01', '1', 'foo', null, null, '2016-W02', false ], + [ '2016-W01', null, '2015-W53', null, null, '2016-W02', false ], + [ '2016-W01', null, '2016-W02', null, null, '2016-W02', false ], + [ '2016-W01', null, '2016-W01', null, null, '2016-W02', false ], + [ '2016-W01', null, '2016-W04', null, 4, '2016-W05', false ], + [ '2016-W01', '2', '2016-W04', null, 3, '2016-W06', false ], + // Max values testing. + [ '2016-W01', '1', null, 'foo', 2, '2016-W03', false ], + [ '2016-W01', '1', null, '2016-W02', 1, '2016-W02', false ], + [ '2016-W02', null, null, '2016-W01', null, '2016-W02', false ], + [ '2016-W02', null, null, '2016-W02', null, '2016-W02', false ], + [ '1969-W02', '5', '1969-W01', '1969-W02', null, '1969-W02', false ], + // Step mismatch. + [ '2016-W02', '2', '2016-W01', null, null, '2016-W03', false ], + [ '2016-W02', '2', '2016-W01', null, 2, '2016-W05', false ], + [ '2016-W05', '2', '2016-W01', '2016-W06', null, '2016-W05', false ], + [ '1970-W02', '2', null, null, null, '1970-W04', false ], + [ '1970-W05', '3', null, null, null, '1970-W08', false ], + [ '1970-W03', '3', null, null, null, '1970-W06', false ], + [ '1970-W03', '3', '1970-W02', null, null, '1970-W05', false ], + // Clamping. + [ '2016-W01', null, '2016-W52', null, null, '2016-W52', false ], + [ '1970-W02', '2', '1970-W01', '1970-W04', null, '1970-W03', false ], + [ '1970-W01', '5', '1970-W02', '1970-W09', 10, '1970-W07', false ], + [ '1969-W50', '5', '1969-W52', '1970-W06', 3, '1970-W05', false ], + [ '1970-W01', '3', '1970-W02', '1971-W07', 15, '1970-W44', false ], + [ '1970-W01', '3', '1970-W01', '1970-W06', 2, '1970-W04', false ], + // value = "" (NaN). + [ '', null, null, null, null, '1970-W02', false ], + // With step = 'any'. + [ '2016-W01', 'any', null, null, 1, null, true ], + [ '2016-W01', 'ANY', null, null, 1, null, true ], + [ '2016-W01', 'AnY', null, null, 1, null, true ], + [ '2016-W01', 'aNy', null, null, 1, null, true ], + ]}, + { type: 'datetime-local', data: [ + // Regular case. + [ '2017-02-07T17:09', null, null, null, null, '2017-02-07T17:10', false ], + // Argument testing. + [ '2017-02-07T17:10', null, null, null, 1, '2017-02-07T17:11', false ], + [ '2017-02-07T17:10', null, null, null, 5, '2017-02-07T17:15', false ], + [ '2017-02-07T17:10', null, null, null, -1, '2017-02-07T17:09', false ], + [ '2017-02-07T17:10', null, null, null, 0, '2017-02-07T17:10', false ], + // hour/minutes/seconds wrapping. + [ '2000-01-01T04:59', null, null, null, null, '2000-01-01T05:00', false ], + [ '2000-01-01T04:59:59', 1, null, null, null, '2000-01-01T05:00', false ], + [ '2000-01-01T04:59:59.900', 0.1, null, null, null, '2000-01-01T05:00', false ], + [ '2000-01-01T04:59:59.990', 0.01, null, null, null, '2000-01-01T05:00', false ], + [ '2000-01-01T04:59:59.999', 0.001, null, null, null, '2000-01-01T05:00', false ], + // month/year wrapping. + [ '2012-07-31T12:00', null, null, null, 1440, '2012-08-01T12:00', false ], + [ '1968-12-29T12:00', null, null, null, 5760, '1969-01-02T12:00', false ], + [ '1970-01-01T00:00', null, null, null, -1440, '1969-12-31T00:00', false ], + [ '2012-03-01T00:00', null, null, null, -1440, '2012-02-29T00:00', false ], + // stepUp() on '23:59' gives '00:00'. + [ '2017-02-07T23:59', null, null, null, 1, '2017-02-08T00:00', false ], + [ '2017-02-07T23:59', null, null, null, 3, '2017-02-08T00:02', false ], + // Some random step values.. + [ '2017-02-07T17:40', '0.5', null, null, null, '2017-02-07T17:40:00.500', false ], + [ '2017-02-07T17:40', '2', null, null, null, '2017-02-07T17:40:02', false ], + [ '2017-02-07T17:40', '0.25', null, null, 4, '2017-02-07T17:40:01', false ], + [ '2017-02-07T17:40', '1.1', '2017-02-07T17:00', null, 1, '2017-02-07T17:40:00.200', false ], + [ '2017-02-07T17:40', '1.1', '2017-02-07T17:00', null, 2, '2017-02-07T17:40:01.300', false ], + [ '2017-02-07T17:40', '1.1', '2017-02-07T17:00', null, 10, '2017-02-07T17:40:10.100', false ], + [ '2017-02-07T17:40', '129600', '2017-02-01T00:00', null, 2, '2017-02-10T00:00', false ], + // step = 0 isn't allowed (-> step = 1). + [ '2017-02-07T17:39', '0', null, null, null, '2017-02-07T17:40', false ], + // step < 0 isn't allowed (-> step = 1). + [ '2017-02-07T17:39', '-1', null, null, null, '2017-02-07T17:40', false ], + // step = NaN isn't allowed (-> step = 1). + [ '2017-02-07T17:39', 'foo', null, null, null, '2017-02-07T17:40', false ], + // Min values testing. + [ '2012-02-02T17:00', '60', 'foo', null, 2, '2012-02-02T17:02', false ], + [ '2012-02-02T17:10', '60', '2012-02-02T17:10', null, null, '2012-02-02T17:11', false ], + [ '2012-02-02T17:10', '60', '2012-02-02T17:30', null, 1, '2012-02-02T17:30', false ], + [ '2012-02-02T17:10', '180', '2012-02-02T17:05', null, null, '2012-02-02T17:11', false ], + [ '2012-02-02T17:10', '86400', '2012-02-02T17:05', null, null, '2012-02-03T17:05', false ], + [ '2012-02-02T17:10', '129600', '2012-02-01T00:00', null, null, '2012-02-04T00:00', false ], + // Max values testing. + [ '2012-02-02T17:15', '60', null, 'foo', null, '2012-02-02T17:16', false ], + [ '2012-02-02T17:15', null, null, '2012-02-02T17:20', null, '2012-02-02T17:16', false ], + [ '2012-02-02T17:15', null, null, '2012-02-02T17:15', null, '2012-02-02T17:15', false ], + [ '2012-02-02T17:15', null, null, '2012-02-02T17:13', 4, '2012-02-02T17:15', false ], + [ '2012-02-02T20:05', '86400', null, '2012-02-03T20:05', null, '2012-02-03T20:05', false ], + [ '2012-02-02T18:00', '129600', null, '2012-02-04T20:00', null, '2012-02-04T06:00', false ], + // Step mismatch. + [ '2017-02-07T17:19', '120', '2017-02-07T17:10', null, null, '2017-02-07T17:20', false ], + [ '2017-02-07T17:19', '120', '2017-02-07T17:10', null, 2, '2017-02-07T17:22', false ], + [ '2017-02-07T17:19', '120', '2017-02-07T17:18', '2017-02-07T17:25', null, '2017-02-07T17:20', false ], + [ '2017-02-07T17:19', '120', null, null, null, '2017-02-07T17:21', false ], + [ '2017-02-07T17:19', '180', null, null, null, '2017-02-07T17:22', false ], + [ '2017-02-03T17:19', '172800', '2017-02-02T17:19', '2017-02-10T17:19', null, '2017-02-04T17:19', false ], + // Clamping. + [ '2017-02-07T17:22', null, null, '2017-02-07T17:11', null, '2017-02-07T17:22', false ], + [ '2017-02-07T17:22', '120', '2017-02-07T17:20', '2017-02-07T17:22', null, '2017-02-07T17:22', false ], + [ '2017-02-07T17:22', '300', '2017-02-07T17:12', '2017-02-07T17:20', 10, '2017-02-07T17:22', false ], + [ '2017-02-07T17:22', '300', '2017-02-07T17:18', '2017-02-07T17:20', 2, '2017-02-07T17:22', false ], + [ '2017-02-06T17:22', '600', '2017-02-02T17:00', '2017-02-07T17:20', 15, '2017-02-06T19:50', false ], + [ '2017-02-06T17:22', '600', '2017-02-02T17:10', '2017-02-07T17:20', 2, '2017-02-06T17:40', false ], + // value = "" (NaN). + [ '', null, null, null, null, '1970-01-01T00:01', false ], + // With step = 'any'. + [ '2017-02-07T17:30', 'any', null, null, 1, null, true ], + [ '2017-02-07T17:30', 'ANY', null, null, 1, null, true ], + [ '2017-02-07T17:30', 'AnY', null, null, 1, null, true ], + [ '2017-02-07T17:30', 'aNy', null, null, 1, null, true ], + ]}, + ]; + + for (var test of testData) { + for (var data of test.data) { + var element = document.createElement("input"); + element.type = test.type; + + if (data[1] != null) { + element.step = data[1]; + } + + if (data[2] != null) { + element.min = data[2]; + } + + if (data[3] != null) { + element.max = data[3]; + } + + // Set 'value' last for type=range, because the final sanitized value + // after setting 'step', 'min' and 'max' can be affected by the order in + // which those attributes are set. Setting 'value' last makes it simpler + // to reason about what the final value should be. + if (data[0] != null) { + element.setAttribute('value', data[0]); + } + + var exceptionCaught = false; + try { + if (data[4] != null) { + element.stepUp(data[4]); + } else { + element.stepUp(); + } + + is(element.value, data[5], "The value for type=" + test.type + " should be " + data[5]); + } catch (e) { + exceptionCaught = true; + is(element.value, data[0], e.name + "The value should not have changed"); + is(e.name, 'InvalidStateError', + "It should be a InvalidStateError exception."); + } finally { + is(exceptionCaught, data[6], "exception status should be " + data[6]); + } + } + } +} + +checkPresence(); +checkAvailability(); + +checkStepDown(); +checkStepUp(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_submit_invalid_file.html b/dom/html/test/forms/test_submit_invalid_file.html new file mode 100644 index 0000000000..68b5e44877 --- /dev/null +++ b/dom/html/test/forms/test_submit_invalid_file.html @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=702949 +--> +<head> + <meta charset="utf-8"> + <title>Test invalid file submission</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=702949">Mozilla Bug 702949</a> +<p id="display"></p> +<div id="content" style="display: none"> + <form action='http://mochi.test:8888/chrome/dom/html/test/forms/submit_invalid_file.sjs' method='post' target='result' + enctype='multipart/form-data'> + <input type='file' name='file'> + </form> + <iframe name='result'></iframe> +</div> +<pre id="test"> +</pre> +<script type="application/javascript"> + /* + * Test invalid file submission by submitting a file that has been deleted + * from the file system before the form has been submitted. + * The form submission triggers a sjs file that shows its output in a frame. + * That means the test might time out if it fails. + */ + + SimpleTest.waitForExplicitFinish(); + addLoadEvent(function() { + var { FileUtils } = SpecialPowers.ChromeUtils.importESModule( + "resource://gre/modules/FileUtils.sys.mjs" + ); + + var i = document.getElementsByTagName('input')[0]; + + var file = FileUtils.getDir("TmpD", []); + file.append("testfile"); + file.createUnique(SpecialPowers.Ci.nsIFile.NORMAL_FILE_TYPE, 0o644); + + SpecialPowers.wrap(i).value = file.path; + file.remove(/* recursive = */ false); + + document.getElementsByName('result')[0].addEventListener('load', function() { + is(window.frames[0].document.body.textContent, "SUCCESS"); + SimpleTest.finish(); + }); + document.forms[0].submit(); + }); +</script> +</body> +</html> diff --git a/dom/html/test/forms/test_textarea_attributes_reflection.html b/dom/html/test/forms/test_textarea_attributes_reflection.html new file mode 100644 index 0000000000..925f97e751 --- /dev/null +++ b/dom/html/test/forms/test_textarea_attributes_reflection.html @@ -0,0 +1,107 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLTextAreaElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="../reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLTextAreaElement attributes reflection **/ + +// .autofocus +reflectBoolean({ + element: document.createElement("textarea"), + attribute: "autofocus", +}); + +//.cols +reflectUnsignedInt({ + element: document.createElement("textarea"), + attribute: "cols", + nonZero: true, + defaultValue: 20, + fallback: true, +}); + +//.dirname +reflectString({ + element: document.createElement("textarea"), + attribute: "dirName" +}) + +// .disabled +reflectBoolean({ + element: document.createElement("textarea"), + attribute: "disabled", +}); + +// TODO: form (HTMLFormElement) + +// .maxLength +reflectInt({ + element: document.createElement("textarea"), + attribute: "maxLength", + nonNegative: true, +}); + +// .name +reflectString({ + element: document.createElement("textarea"), + attribute: "name", + otherValues: [ "isindex", "_charset_" ], +}); + +// .placeholder +reflectString({ + element: document.createElement("textarea"), + attribute: "placeholder", + otherValues: [ "foo\nbar", "foo\rbar", "foo\r\nbar" ], +}); + +// .readOnly +reflectBoolean({ + element: document.createElement("textarea"), + attribute: "readOnly", +}); + +// .required +reflectBoolean({ + element: document.createElement("textarea"), + attribute: "required", +}); + +// .rows +reflectUnsignedInt({ + element: document.createElement("textarea"), + attribute: "rows", + nonZero: true, + defaultValue: 2, + fallback: true, +}); + +// .wrap +// TODO: make it an enumerated attributes limited to only known values, bug 670869. +reflectString({ + element: document.createElement("textarea"), + attribute: "wrap", + otherValues: [ "soft", "hard" ], +}); + +// .type doesn't reflect a content attribute. +// .defaultValue doesn't reflect a content attribute. +// .value doesn't reflect a content attribute. +// .textLength doesn't reflect a content attribute. +// .willValidate doesn't reflect a content attribute. +// .validity doesn't reflect a content attribute. +// .validationMessage doesn't reflect a content attribute. +// .labels doesn't reflect a content attribute. + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_validation.html b/dom/html/test/forms/test_validation.html new file mode 100644 index 0000000000..666d4a45c0 --- /dev/null +++ b/dom/html/test/forms/test_validation.html @@ -0,0 +1,343 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=345624 +--> +<head> + <title>Test for Bug 345624</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + input, textarea, fieldset, button, select, output, object { background-color: rgb(0,0,0) !important; } + :valid { background-color: rgb(0,255,0) !important; } + :invalid { background-color: rgb(255,0,0) !important; } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=345624">Mozilla Bug 345624</a> +<p id="display"></p> +<div id="content" style="display: none"> + <fieldset id='f'></fieldset> + <input id='i' oninvalid="invalidEventHandler(event);"> + <button id='b' oninvalid="invalidEventHandler(event);"></button> + <select id='s' oninvalid="invalidEventHandler(event);"></select> + <textarea id='t' oninvalid="invalidEventHandler(event);"></textarea> + <output id='o' oninvalid="invalidEventHandler(event);"></output> + <object id='obj'></object> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 345624 **/ + +var gInvalid = false; + +function invalidEventHandler(aEvent) +{ + function checkInvalidEvent(event) + { + is(event.type, "invalid", "Invalid event type should be invalid"); + ok(!event.bubbles, "Invalid event should not bubble"); + ok(event.cancelable, "Invalid event should be cancelable"); + } + + checkInvalidEvent(aEvent); + + gInvalid = true; +} + +function checkConstraintValidationAPIExist(element) +{ + ok('willValidate' in element, "willValidate is not available in the DOM"); + ok('validationMessage' in element, "validationMessage is not available in the DOM"); + ok('validity' in element, "validity is not available in the DOM"); + + if ('validity' in element) { + validity = element.validity; + ok('valueMissing' in validity, "validity.valueMissing is not available in the DOM"); + ok('typeMismatch' in validity, "validity.typeMismatch is not available in the DOM"); + ok('badInput' in validity, "validity.badInput is not available in the DOM"); + ok('patternMismatch' in validity, "validity.patternMismatch is not available in the DOM"); + ok('tooLong' in validity, "validity.tooLong is not available in the DOM"); + ok('rangeUnderflow' in validity, "validity.rangeUnderflow is not available in the DOM"); + ok('rangeOverflow' in validity, "validity.rangeOverflow is not available in the DOM"); + ok('stepMismatch' in validity, "validity.stepMismatch is not available in the DOM"); + ok('customError' in validity, "validity.customError is not available in the DOM"); + ok('valid' in validity, "validity.valid is not available in the DOM"); + } +} + +function checkConstraintValidationAPIDefaultValues(element) +{ + // Not checking willValidate because the default value depends of the element + + is(element.validationMessage, "", "validationMessage default value should be empty string"); + + ok(!element.validity.valueMissing, "The element should not suffer from a constraint validation"); + ok(!element.validity.typeMismatch, "The element should not suffer from a constraint validation"); + ok(!element.validity.badInput, "The element should not suffer from a constraint validation"); + ok(!element.validity.patternMismatch, "The element should not suffer from a constraint validation"); + ok(!element.validity.tooLong, "The element should not suffer from a constraint validation"); + ok(!element.validity.rangeUnderflow, "The element should not suffer from a constraint validation"); + ok(!element.validity.rangeOverflow, "The element should not suffer from a constraint validation"); + ok(!element.validity.stepMismatch, "The element should not suffer from a constraint validation"); + ok(!element.validity.customError, "The element should not suffer from a constraint validation"); + ok(element.validity.valid, "The element should be valid by default"); + + ok(element.checkValidity(), "The element should be valid by default"); +} + +function checkDefaultPseudoClass() +{ + is(window.getComputedStyle(document.getElementById('f')) + .getPropertyValue('background-color'), "rgb(0, 255, 0)", + ":valid should apply"); + + is(window.getComputedStyle(document.getElementById('o')) + .getPropertyValue('background-color'), "rgb(0, 0, 0)", + "Nor :valid and :invalid should apply"); + + is(window.getComputedStyle(document.getElementById('obj')) + .getPropertyValue('background-color'), "rgb(0, 0, 0)", + "Nor :valid and :invalid should apply"); + + is(window.getComputedStyle(document.getElementById('s')) + .getPropertyValue('background-color'), "rgb(0, 255, 0)", + ":valid pseudo-class should apply"); + + is(window.getComputedStyle(document.getElementById('i')) + .getPropertyValue('background-color'), "rgb(0, 255, 0)", + ":valid pseudo-class should apply"); + + is(window.getComputedStyle(document.getElementById('t')) + .getPropertyValue('background-color'), "rgb(0, 255, 0)", + ":valid pseudo-class should apply"); + + is(window.getComputedStyle(document.getElementById('b')) + .getPropertyValue('background-color'), "rgb(0, 255, 0)", + ":valid pseudo-class should apply"); +} + +function checkSpecificWillValidate() +{ + // fieldset, output, object (TODO) and select elements + ok(!document.getElementById('f').willValidate, "Fielset element should be barred from constraint validation"); + ok(!document.getElementById('obj').willValidate, "Object element should be barred from constraint validation"); + ok(!document.getElementById('o').willValidate, "Output element should be barred from constraint validation"); + ok(document.getElementById('s').willValidate, "Select element should not be barred from constraint validation"); + + // input element + i = document.getElementById('i'); + i.type = "hidden"; + ok(!i.willValidate, "Hidden state input should be barred from constraint validation"); + is(window.getComputedStyle(i).getPropertyValue('background-color'), + "rgb(0, 0, 0)", "Nor :valid and :invalid should apply"); + i.type = "reset"; + ok(!i.willValidate, "Reset button state input should be barred from constraint validation"); + is(window.getComputedStyle(i).getPropertyValue('background-color'), + "rgb(0, 0, 0)", "Nor :valid and :invalid should apply"); + i.type = "button"; + ok(!i.willValidate, "Button state input should be barred from constraint validation"); + is(window.getComputedStyle(i).getPropertyValue('background-color'), + "rgb(0, 0, 0)", "Nor :valid and :invalid should apply"); + i.type = "image"; + ok(i.willValidate, "Image state input should not be barred from constraint validation"); + is(window.getComputedStyle(i).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid and :invalid should apply"); + i.type = "submit"; + ok(i.willValidate, "Submit state input should not be barred from constraint validation"); + is(window.getComputedStyle(i).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid and :invalid should apply"); + i.type = "number"; + ok(i.willValidate, "Number state input should not be barred from constraint validation"); + is(window.getComputedStyle(i).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + i.type = ""; + i.readOnly = 'true'; + ok(!i.willValidate, "Readonly input should be barred from constraint validation"); + is(window.getComputedStyle(i).getPropertyValue('background-color'), + "rgb(0, 0, 0)", "Nor :valid and :invalid should apply"); + i.removeAttribute('readOnly'); + ok(i.willValidate, "Default input element should not be barred from constraint validation"); + is(window.getComputedStyle(i).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + + // button element + b = document.getElementById('b'); + b.type = "reset"; + ok(!b.willValidate, "Reset state button should be barred from constraint validation"); + is(window.getComputedStyle(b).getPropertyValue('background-color'), + "rgb(0, 0, 0)", "Nor :valid and :invalid should apply"); + b.type = "button"; + ok(!b.willValidate, "Button state button should be barred from constraint validation"); + is(window.getComputedStyle(b).getPropertyValue('background-color'), + "rgb(0, 0, 0)", "Nor :valid and :invalid should apply"); + b.type = "submit"; + ok(b.willValidate, "Submit state button should not be barred from constraint validation"); + is(window.getComputedStyle(b).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid and :invalid should apply"); + b.type = ""; + ok(b.willValidate, "Default button element should not be barred from constraint validation"); + is(window.getComputedStyle(b).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + + // textarea element + t = document.getElementById('t'); + t.readOnly = true; + ok(!t.willValidate, "Readonly textarea should be barred from constraint validation"); + is(window.getComputedStyle(t).getPropertyValue('background-color'), + "rgb(0, 0, 0)", "Nor :valid and :invalid should apply"); + t.removeAttribute('readOnly'); + ok(t.willValidate, "Default textarea element should not be barred from constraint validation"); + is(window.getComputedStyle(t).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); + + // TODO: PROGRESS + // TODO: METER +} + +function checkCommonWillValidate(element) +{ + // Not checking the default value because it has been checked previously. + + element.disabled = true; + ok(!element.willValidate, "Disabled element should be barred from constraint validation"); + + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 0, 0)", "Nor :valid and :invalid should apply"); + + element.removeAttribute('disabled'); + + // TODO: If an element has a datalist element ancestor, it is barred from constraint validation. +} + +function checkCustomError(element, isBarred) +{ + element.setCustomValidity("message"); + if (!isBarred) { + is(element.validationMessage, "message", + "When the element has a custom validity message, validation message should return it"); + } else { + is(element.validationMessage, "", + "An element barred from constraint validation can't have a validation message"); + } + ok(element.validity.customError, "The element should suffer from a custom error"); + ok(!element.validity.valid, "The element should not be valid with a custom error"); + + if (element.tagName == "FIELDSET") { + is(window.getComputedStyle(element).getPropertyValue('background-color'), + isBarred ? "rgb(0, 255, 0)" : "rgb(255, 0, 0)", + ":invalid pseudo-classs should apply to " + element.tagName); + } + else { + is(window.getComputedStyle(element).getPropertyValue('background-color'), + isBarred ? "rgb(0, 0, 0)" : "rgb(255, 0, 0)", + ":invalid pseudo-classs should apply to " + element.tagName); + } + + element.setCustomValidity(""); + is(element.validationMessage, "", "The element should not have a validation message when reseted"); + ok(!element.validity.customError, "The element should not suffer anymore from a custom error"); + ok(element.validity.valid, "The element should now be valid"); + + is(window.getComputedStyle(element).getPropertyValue('background-color'), + isBarred && element.tagName != "FIELDSET" ? "rgb(0, 0, 0)" : "rgb(0, 255, 0)", + ":valid pseudo-classs should apply"); +} + +function checkCheckValidity(element) +{ + element.setCustomValidity("message"); + ok(!element.checkValidity(), "checkValidity() should return false when the element is not valid"); + + ok(gInvalid, "Invalid event should have been handled"); + + gInvalid = false; + element.setCustomValidity(""); + + ok(element.checkValidity(), "Element should be valid"); + ok(!gInvalid, "Invalid event should not have been handled"); +} + +function checkValidityStateObjectAliveWithoutElement(element) +{ + // We are creating a temporary element and getting it's ValidityState object. + // Then, we make sure it is removed by the garbage collector and we check the + // ValidityState default values (it should not crash). + + var v = document.createElement(element).validity; + SpecialPowers.gc(); + + ok(!v.valueMissing, + "When the element is not alive, it shouldn't suffer from constraint validation"); + ok(!v.typeMismatch, + "When the element is not alive, it shouldn't suffer from constraint validation"); + ok(!v.badInput, + "When the element is not alive, it shouldn't suffer from constraint validation"); + ok(!v.patternMismatch, + "When the element is not alive, it shouldn't suffer from constraint validation"); + ok(!v.tooLong, + "When the element is not alive, it shouldn't suffer from constraint validation"); + ok(!v.rangeUnderflow, + "When the element is not alive, it shouldn't suffer from constraint validation"); + ok(!v.rangeOverflow, + "When the element is not alive, it shouldn't suffer from constraint validation"); + ok(!v.stepMismatch, + "When the element is not alive, it shouldn't suffer from constraint validation"); + ok(!v.customError, + "When the element is not alive, it shouldn't suffer from constraint validation"); + ok(v.valid, "When the element is not alive, it should be valid"); +} + +checkConstraintValidationAPIExist(document.getElementById('f')); +checkConstraintValidationAPIExist(document.getElementById('i')); +checkConstraintValidationAPIExist(document.getElementById('b')); +checkConstraintValidationAPIExist(document.getElementById('s')); +checkConstraintValidationAPIExist(document.getElementById('t')); +checkConstraintValidationAPIExist(document.getElementById('o')); +checkConstraintValidationAPIExist(document.getElementById('obj')); + +checkConstraintValidationAPIDefaultValues(document.getElementById('f')); +checkConstraintValidationAPIDefaultValues(document.getElementById('i')); +checkConstraintValidationAPIDefaultValues(document.getElementById('b')); +checkConstraintValidationAPIDefaultValues(document.getElementById('s')); +checkConstraintValidationAPIDefaultValues(document.getElementById('t')); +checkConstraintValidationAPIDefaultValues(document.getElementById('o')); +checkConstraintValidationAPIDefaultValues(document.getElementById('obj')); + +checkDefaultPseudoClass(); + +checkSpecificWillValidate(); + +// Not checking button, fieldset, output and object +// because they are always barred from constraint validation. +checkCommonWillValidate(document.getElementById('i')); +checkCommonWillValidate(document.getElementById('s')); +checkCommonWillValidate(document.getElementById('t')); + +checkCustomError(document.getElementById('i'), false); +checkCustomError(document.getElementById('s'), false); +checkCustomError(document.getElementById('t'), false); +checkCustomError(document.getElementById('o'), true); +checkCustomError(document.getElementById('b'), false); +checkCustomError(document.getElementById('f'), true); +checkCustomError(document.getElementById('obj'), true); + +// Not checking button, fieldset, output and object +// because they are always barred from constraint validation. +checkCheckValidity(document.getElementById('i')); +checkCheckValidity(document.getElementById('s')); +checkCheckValidity(document.getElementById('t')); + +checkValidityStateObjectAliveWithoutElement("fieldset"); +checkValidityStateObjectAliveWithoutElement("input"); +checkValidityStateObjectAliveWithoutElement("button"); +checkValidityStateObjectAliveWithoutElement("select"); +checkValidityStateObjectAliveWithoutElement("textarea"); +checkValidityStateObjectAliveWithoutElement("output"); +checkValidityStateObjectAliveWithoutElement("object"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_validation_not_in_doc.html b/dom/html/test/forms/test_validation_not_in_doc.html new file mode 100644 index 0000000000..1500c60869 --- /dev/null +++ b/dom/html/test/forms/test_validation_not_in_doc.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Test for constraint validation of form controls not in documents</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var input = document.createElement('input'); + input.required = true; + assert_false(input.checkValidity()); +}, "Should validate input not in document"); + +test(function() { + var textarea = document.createElement('textarea'); + textarea.required = true; + assert_false(textarea.checkValidity()); +}, "Should validate textarea not in document"); +</script> diff --git a/dom/html/test/forms/test_valueasdate_attribute.html b/dom/html/test/forms/test_valueasdate_attribute.html new file mode 100644 index 0000000000..9055879a85 --- /dev/null +++ b/dom/html/test/forms/test_valueasdate_attribute.html @@ -0,0 +1,751 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=769370 +--> +<head> + <title>Test for input.valueAsDate</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=769370">Mozilla Bug 769370</a> +<iframe name="testFrame" style="display: none"></iframe> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 769370**/ + +/** + * This test is checking .valueAsDate. + */ + +var element = document.createElement("input"); + +var validTypes = +[ + ["text", false], + ["password", false], + ["search", false], + ["tel", false], + ["email", false], + ["url", false], + ["hidden", false], + ["checkbox", false], + ["radio", false], + ["file", false], + ["submit", false], + ["image", false], + ["reset", false], + ["button", false], + ["number", false], + ["range", false], + ["date", true], + ["time", true], + ["color", false], + ["month", true], + ["week", true], + ["datetime-local", true], +]; + +function checkAvailability() +{ + for (let data of validTypes) { + var exceptionCatched = false; + element.type = data[0]; + try { + element.valueAsDate; + } catch (e) { + exceptionCatched = true; + } + is(exceptionCatched, false, + "valueAsDate shouldn't throw exception on getting"); + + exceptionCatched = false; + try { + element.valueAsDate = new Date(); + } catch (e) { + exceptionCatched = true; + } + is(exceptionCatched, !data[1], "valueAsDate for " + data[0] + + " availability is not correct"); + } +} + +function checkGarbageValues() +{ + for (let type of validTypes) { + if (!type[1]) { + continue; + } + type = type[0]; + + var inputElement = document.createElement('input'); + inputElement.type = type; + + inputElement.value = "test"; + inputElement.valueAsDate = null; + is(inputElement.value, "", "valueAsDate should set the value to the empty string"); + + inputElement.value = "test"; + inputElement.valueAsDate = undefined; + is(inputElement.value, "", "valueAsDate should set the value to the empty string"); + + inputElement.value = "test"; + inputElement.valueAsDate = new Date(NaN); + is(inputElement.value, "", "valueAsDate should set the value to the empty string"); + + var illegalValues = [ + "foobar", 42, {}, function() { return 42; }, function() { return Date(); } + ]; + + for (let value of illegalValues) { + try { + var caught = false; + inputElement.valueAsDate = value; + } catch(e) { + is(e.name, "TypeError", "Exception should be 'TypeError'."); + caught = true; + } + ok(caught, "Assigning " + value + " to .valueAsDate should throw"); + } + } +} + +function checkDateGet() +{ + var validData = + [ + [ "2012-07-12", 1342051200000 ], + [ "1970-01-01", 0 ], + [ "1970-01-02", 86400000 ], + [ "1969-12-31", -86400000 ], + [ "0311-01-31", -52350451200000 ], + [ "275760-09-13", 8640000000000000 ], + [ "0001-01-01", -62135596800000 ], + [ "2012-02-29", 1330473600000 ], + [ "2011-02-28", 1298851200000 ], + ]; + + var invalidData = + [ + [ "invaliddate" ], + [ "-001-12-31" ], + [ "901-12-31" ], + [ "1901-13-31" ], + [ "1901-12-32" ], + [ "1901-00-12" ], + [ "1901-01-00" ], + [ "1900-02-29" ], + [ "0000-01-01" ], + [ "" ], + // This date is valid for the input element, but is out of + // the date object range. In this case, on getting valueAsDate, + // a Date object will be created, but it will have a NaN internal value, + // and will return the string "Invalid Date". + [ "275760-09-14", true ], + ]; + + element.type = "date"; + for (let data of validData) { + element.value = data[0]; + is(element.valueAsDate.valueOf(), data[1], + "valueAsDate should return the " + + "valid date object representing this date"); + } + + for (let data of invalidData) { + element.value = data[0]; + if (data[1]) { + is(String(element.valueAsDate), "Invalid Date", + "valueAsDate should return an invalid Date object " + + "when the element value is not a valid date"); + } else { + is(element.valueAsDate, null, + "valueAsDate should return null " + + "when the element value is not a valid date"); + } + } +} + +function checkDateSet() +{ + var testData = + [ + [ 1342051200000, "2012-07-12" ], + [ 0, "1970-01-01" ], + // Maximum valid date (limited by the ecma date object range). + [ 8640000000000000, "275760-09-13" ], + // Minimum valid date (limited by the input element minimum valid value). + [ -62135596800000 , "0001-01-01" ], + [ 1330473600000, "2012-02-29" ], + [ 1298851200000, "2011-02-28" ], + // "Values must be truncated to valid dates" + [ 42.1234, "1970-01-01" ], + [ 123.123456789123, "1970-01-01" ], + [ 1e-1, "1970-01-01" ], + [ 1298851200010, "2011-02-28" ], + [ -1, "1969-12-31" ], + [ -86400000, "1969-12-31" ], + [ 86400000, "1970-01-02" ], + // Negative years, this is out of range for the input element, + // the corresponding date string is the empty string + [ -62135596800001, "" ], + // Invalid dates. + ]; + + element.type = "date"; + for (let data of testData) { + element.valueAsDate = new Date(data[0]); + is(element.value, data[1], "valueAsDate should set the value to " + + data[1]); + element.valueAsDate = new testFrame.Date(data[0]); + is(element.value, data[1], "valueAsDate with other-global date should " + + "set the value to " + data[1]); + } +} + +function checkTimeGet() +{ + var tests = [ + // Some invalid values to begin. + { value: "", result: null }, + { value: "foobar", result: null }, + { value: "00:", result: null }, + { value: "24:00", result: null }, + { value: "00:99", result: null }, + { value: "00:00:", result: null }, + { value: "00:00:99", result: null }, + { value: "00:00:00:", result: null }, + { value: "00:00:00.", result: null }, + { value: "00:00:00.0000", result: null }, + // Some simple valid values. + { value: "00:00", result: { time: 0, hours: 0, minutes: 0, seconds: 0, ms: 0 } }, + { value: "00:01", result: { time: 60000, hours: 0, minutes: 1, seconds: 0, ms: 0 } }, + { value: "01:00", result: { time: 3600000, hours: 1, minutes: 0, seconds: 0, ms: 0 } }, + { value: "01:01", result: { time: 3660000, hours: 1, minutes: 1, seconds: 0, ms: 0 } }, + { value: "13:37", result: { time: 49020000, hours: 13, minutes: 37, seconds: 0, ms: 0 } }, + // Valid values including seconds. + { value: "00:00:01", result: { time: 1000, hours: 0, minutes: 0, seconds: 1, ms: 0 } }, + { value: "13:37:42", result: { time: 49062000, hours: 13, minutes: 37, seconds: 42, ms: 0 } }, + // Valid values including seconds fractions. + { value: "00:00:00.001", result: { time: 1, hours: 0, minutes: 0, seconds: 0, ms: 1 } }, + { value: "00:00:00.123", result: { time: 123, hours: 0, minutes: 0, seconds: 0, ms: 123 } }, + { value: "00:00:00.100", result: { time: 100, hours: 0, minutes: 0, seconds: 0, ms: 100 } }, + { value: "00:00:00.000", result: { time: 0, hours: 0, minutes: 0, seconds: 0, ms: 0 } }, + { value: "20:17:31.142", result: { time: 73051142, hours: 20, minutes: 17, seconds: 31, ms: 142 } }, + // Highest possible value. + { value: "23:59:59.999", result: { time: 86399999, hours: 23, minutes: 59, seconds: 59, ms: 999 } }, + // Some values with one or two digits for the fraction of seconds. + { value: "00:00:00.1", result: { time: 100, hours: 0, minutes: 0, seconds: 0, ms: 100 } }, + { value: "00:00:00.14", result: { time: 140, hours: 0, minutes: 0, seconds: 0, ms: 140 } }, + { value: "13:37:42.7", result: { time: 49062700, hours: 13, minutes: 37, seconds: 42, ms: 700 } }, + { value: "23:31:12.23", result: { time: 84672230, hours: 23, minutes: 31, seconds: 12, ms: 230 } }, + ]; + + var inputElement = document.createElement('input'); + inputElement.type = 'time'; + + for (let test of tests) { + inputElement.value = test.value; + if (test.result === null) { + is(inputElement.valueAsDate, null, "element.valueAsDate should return null"); + } else { + var date = inputElement.valueAsDate; + isnot(date, null, "element.valueAsDate should not be null"); + + is(date.getTime(), test.result.time); + is(date.getUTCHours(), test.result.hours); + is(date.getUTCMinutes(), test.result.minutes); + is(date.getUTCSeconds(), test.result.seconds); + is(date.getUTCMilliseconds(), test.result.ms); + } + } +} + +function checkTimeSet() +{ + var tests = [ + // Simple tests. + { value: 0, result: "00:00" }, + { value: 1, result: "00:00:00.001" }, + { value: 100, result: "00:00:00.100" }, + { value: 1000, result: "00:00:01" }, + { value: 60000, result: "00:01" }, + { value: 3600000, result: "01:00" }, + { value: 83622234, result: "23:13:42.234" }, + // Some edge cases. + { value: 86400000, result: "00:00" }, + { value: 86400001, result: "00:00:00.001" }, + { value: 170022234, result: "23:13:42.234" }, + { value: 432000000, result: "00:00" }, + { value: -1, result: "23:59:59.999" }, + { value: -86400000, result: "00:00" }, + { value: -86400001, result: "23:59:59.999" }, + { value: -56789, result: "23:59:03.211" }, + { value: 0.9, result: "00:00" }, + ]; + + var inputElement = document.createElement('input'); + inputElement.type = 'time'; + + for (let test of tests) { + inputElement.valueAsDate = new Date(test.value); + is(inputElement.value, test.result, + "element.value should have been changed by setting valueAsDate"); + } +} + +function checkWithBustedPrototype() +{ + for (let type of validTypes) { + if (!type[1]) { + continue; + } + + type = type[0]; + + var inputElement = document.createElement('input'); + inputElement.type = type; + + var backupPrototype = {}; + backupPrototype.getUTCFullYear = Date.prototype.getUTCFullYear; + backupPrototype.getUTCMonth = Date.prototype.getUTCMonth; + backupPrototype.getUTCDate = Date.prototype.getUTCDate; + backupPrototype.getTime = Date.prototype.getTime; + backupPrototype.setUTCFullYear = Date.prototype.setUTCFullYear; + + Date.prototype.getUTCFullYear = function() { return {}; }; + Date.prototype.getUTCMonth = function() { return {}; }; + Date.prototype.getUTCDate = function() { return {}; }; + Date.prototype.getTime = function() { return {}; }; + Date.prototype.setUTCFullYear = function(y,m,d) { }; + + inputElement.valueAsDate = new Date(); + + isnot(inputElement.valueAsDate, null, ".valueAsDate should not return null"); + // The object returned by element.valueAsDate should return a Date object + // with the same prototype: + is(inputElement.valueAsDate.getUTCFullYear, Date.prototype.getUTCFullYear, + "prototype is the same"); + is(inputElement.valueAsDate.getUTCMonth, Date.prototype.getUTCMonth, + "prototype is the same"); + is(inputElement.valueAsDate.getUTCDate, Date.prototype.getUTCDate, + "prototype is the same"); + is(inputElement.valueAsDate.getTime, Date.prototype.getTime, + "prototype is the same"); + is(inputElement.valueAsDate.setUTCFullYear, Date.prototype.setUTCFullYear, + "prototype is the same"); + + // However the Date should have the correct information. + // Skip type=month for now, since .valueAsNumber returns number of months + // and not milliseconds. + if (type != "month") { + var witnessDate = new Date(inputElement.valueAsNumber); + is(inputElement.valueAsDate.valueOf(), witnessDate.valueOf(), "correct Date"); + } + + // Same test as above but using NaN instead of {}. + + Date.prototype.getUTCFullYear = function() { return NaN; }; + Date.prototype.getUTCMonth = function() { return NaN; }; + Date.prototype.getUTCDate = function() { return NaN; }; + Date.prototype.getTime = function() { return NaN; }; + Date.prototype.setUTCFullYear = function(y,m,d) { }; + + inputElement.valueAsDate = new Date(); + + isnot(inputElement.valueAsDate, null, ".valueAsDate should not return null"); + // The object returned by element.valueAsDate should return a Date object + // with the same prototype: + is(inputElement.valueAsDate.getUTCFullYear, Date.prototype.getUTCFullYear, + "prototype is the same"); + is(inputElement.valueAsDate.getUTCMonth, Date.prototype.getUTCMonth, + "prototype is the same"); + is(inputElement.valueAsDate.getUTCDate, Date.prototype.getUTCDate, + "prototype is the same"); + is(inputElement.valueAsDate.getTime, Date.prototype.getTime, + "prototype is the same"); + is(inputElement.valueAsDate.setUTCFullYear, Date.prototype.setUTCFullYear, + "prototype is the same"); + + // However the Date should have the correct information. + // Skip type=month for now, since .valueAsNumber returns number of months + // and not milliseconds. + if (type != "month") { + var witnessDate = new Date(inputElement.valueAsNumber); + is(inputElement.valueAsDate.valueOf(), witnessDate.valueOf(), "correct Date"); + } + + Date.prototype.getUTCFullYear = backupPrototype.getUTCFullYear; + Date.prototype.getUTCMonth = backupPrototype.getUTCMonth; + Date.prototype.getUTCDate = backupPrototype.getUTCDate; + Date.prototype.getTime = backupPrototype.getTime; + Date.prototype.setUTCFullYear = backupPrototype.setUTCFullYear; + } +} + +function checkMonthGet() +{ + var validData = + [ + [ "2016-07", 1467331200000 ], + [ "1970-01", 0 ], + [ "1970-02", 2678400000 ], + [ "1969-12", -2678400000 ], + [ "0001-01", -62135596800000 ], + [ "275760-09", 8639998963200000 ], + ]; + + var invalidData = + [ + [ "invalidmonth" ], + [ "0000-01" ], + [ "2016-00" ], + [ "123-01" ], + [ "2017-13" ], + [ "" ], + // This month is valid for the input element, but is out of + // the date object range. In this case, on getting valueAsDate, + // a Date object will be created, but it will have a NaN internal value, + // and will return the string "Invalid Date". + [ "275760-10", true ], + ]; + + element.type = "month"; + for (let data of validData) { + element.value = data[0]; + is(element.valueAsDate.valueOf(), data[1], + "valueAsDate should return the " + + "valid date object representing this month"); + } + + for (let data of invalidData) { + element.value = data[0]; + if (data[1]) { + is(String(element.valueAsDate), "Invalid Date", + "valueAsDate should return an invalid Date object " + + "when the element value is not a valid month"); + } else { + is(element.valueAsDate, null, + "valueAsDate should return null " + + "when the element value is not a valid month"); + } + } +} + +function checkMonthSet() +{ + var testData = + [ + [ 1342051200000, "2012-07" ], + [ 0, "1970-01" ], + // Maximum valid month (limited by the ecma date object range). + [ 8640000000000000, "275760-09" ], + // Minimum valid month (limited by the input element minimum valid value). + [ -62135596800000 , "0001-01" ], + [ 1330473600000, "2012-02" ], + [ 1298851200000, "2011-02" ], + // "Values must be truncated to valid months" + [ 42.1234, "1970-01" ], + [ 123.123456789123, "1970-01" ], + [ 1e-1, "1970-01" ], + [ 1298851200010, "2011-02" ], + [ -1, "1969-12" ], + [ -86400000, "1969-12" ], + [ 86400000, "1970-01" ], + // Negative years, this is out of range for the input element, + // the corresponding month string is the empty string + [ -62135596800001, "" ], + ]; + + element.type = "month"; + for (let data of testData) { + element.valueAsDate = new Date(data[0]); + is(element.value, data[1], "valueAsDate should set the value to " + + data[1]); + element.valueAsDate = new testFrame.Date(data[0]); + is(element.value, data[1], "valueAsDate with other-global date should " + + "set the value to " + data[1]); + } +} + +function checkWeekGet() +{ + var validData = + [ + // Common years starting on different days of week. + [ "2007-W01", Date.UTC(2007, 0, 1) ], // Mon + [ "2013-W01", Date.UTC(2012, 11, 31) ], // Tue + [ "2014-W01", Date.UTC(2013, 11, 30) ], // Wed + [ "2015-W01", Date.UTC(2014, 11, 29) ], // Thu + [ "2010-W01", Date.UTC(2010, 0, 4) ], // Fri + [ "2011-W01", Date.UTC(2011, 0, 3) ], // Sat + [ "2017-W01", Date.UTC(2017, 0, 2) ], // Sun + // Common years ending on different days of week. + [ "2007-W52", Date.UTC(2007, 11, 24) ], // Mon + [ "2013-W52", Date.UTC(2013, 11, 23) ], // Tue + [ "2014-W52", Date.UTC(2014, 11, 22) ], // Wed + [ "2015-W53", Date.UTC(2015, 11, 28) ], // Thu + [ "2010-W52", Date.UTC(2010, 11, 27) ], // Fri + [ "2011-W52", Date.UTC(2011, 11, 26) ], // Sat + [ "2017-W52", Date.UTC(2017, 11, 25) ], // Sun + // Leap years starting on different days of week. + [ "1996-W01", Date.UTC(1996, 0, 1) ], // Mon + [ "2008-W01", Date.UTC(2007, 11, 31) ], // Tue + [ "2020-W01", Date.UTC(2019, 11, 30) ], // Wed + [ "2004-W01", Date.UTC(2003, 11, 29) ], // Thu + [ "2016-W01", Date.UTC(2016, 0, 4) ], // Fri + [ "2000-W01", Date.UTC(2000, 0, 3) ], // Sat + [ "2012-W01", Date.UTC(2012, 0, 2) ], // Sun + // Leap years ending on different days of week. + [ "2012-W52", Date.UTC(2012, 11, 24) ], // Mon + [ "2024-W52", Date.UTC(2024, 11, 23) ], // Tue + [ "1980-W52", Date.UTC(1980, 11, 22) ], // Wed + [ "1992-W53", Date.UTC(1992, 11, 28) ], // Thu + [ "2004-W53", Date.UTC(2004, 11, 27) ], // Fri + [ "1988-W52", Date.UTC(1988, 11, 26) ], // Sat + [ "2000-W52", Date.UTC(2000, 11, 25) ], // Sun + // Other normal cases. + [ "2016-W36", 1473033600000 ], + [ "1969-W52", -864000000 ], + [ "1970-W01", -259200000 ], + [ "275760-W37", 8639999568000000 ], + ]; + + var invalidData = + [ + [ "invalidweek" ], + [ "0000-W01" ], + [ "2016-W00" ], + [ "123-W01" ], + [ "2016-W53" ], + [ "" ], + // This week is valid for the input element, but is out of + // the date object range. In this case, on getting valueAsDate, + // a Date object will be created, but it will have a NaN internal value, + // and will return the string "Invalid Date". + [ "275760-W38", true ], + ]; + + element.type = "week"; + for (let data of validData) { + element.value = data[0]; + is(element.valueAsDate.valueOf(), data[1], + "valueAsDate should return the " + + "valid date object representing this week"); + } + + for (let data of invalidData) { + element.value = data[0]; + if (data[1]) { + is(String(element.valueAsDate), "Invalid Date", + "valueAsDate should return an invalid Date object " + + "when the element value is not a valid week"); + } else { + is(element.valueAsDate, null, + "valueAsDate should return null " + + "when the element value is not a valid week"); + } + } +} + +function checkWeekSet() +{ + var testData = + [ + // Common years starting on different days of week. + [ Date.UTC(2007, 0, 1), "2007-W01" ], // Mon + [ Date.UTC(2013, 0, 1), "2013-W01" ], // Tue + [ Date.UTC(2014, 0, 1), "2014-W01" ], // Wed + [ Date.UTC(2015, 0, 1), "2015-W01" ], // Thu + [ Date.UTC(2010, 0, 1), "2009-W53" ], // Fri + [ Date.UTC(2011, 0, 1), "2010-W52" ], // Sat + [ Date.UTC(2017, 0, 1), "2016-W52" ], // Sun + // Common years ending on different days of week. + [ Date.UTC(2007, 11, 31), "2008-W01" ], // Mon + [ Date.UTC(2013, 11, 31), "2014-W01" ], // Tue + [ Date.UTC(2014, 11, 31), "2015-W01" ], // Wed + [ Date.UTC(2015, 11, 31), "2015-W53" ], // Thu + [ Date.UTC(2010, 11, 31), "2010-W52" ], // Fri + [ Date.UTC(2011, 11, 31), "2011-W52" ], // Sat + [ Date.UTC(2017, 11, 31), "2017-W52" ], // Sun + // Leap years starting on different days of week. + [ Date.UTC(1996, 0, 1), "1996-W01" ], // Mon + [ Date.UTC(2008, 0, 1), "2008-W01" ], // Tue + [ Date.UTC(2020, 0, 1), "2020-W01" ], // Wed + [ Date.UTC(2004, 0, 1), "2004-W01" ], // Thu + [ Date.UTC(2016, 0, 1), "2015-W53" ], // Fri + [ Date.UTC(2000, 0, 1), "1999-W52" ], // Sat + [ Date.UTC(2012, 0, 1), "2011-W52" ], // Sun + // Leap years ending on different days of week. + [ Date.UTC(2012, 11, 31), "2013-W01" ], // Mon + [ Date.UTC(2024, 11, 31), "2025-W01" ], // Tue + [ Date.UTC(1980, 11, 31), "1981-W01" ], // Wed + [ Date.UTC(1992, 11, 31), "1992-W53" ], // Thu + [ Date.UTC(2004, 11, 31), "2004-W53" ], // Fri + [ Date.UTC(1988, 11, 31), "1988-W52" ], // Sat + [ Date.UTC(2000, 11, 31), "2000-W52" ], // Sun + // Other normal cases. + [ Date.UTC(2016, 8, 9), "2016-W36" ], + [ Date.UTC(2010, 0, 3), "2009-W53" ], + [ Date.UTC(2010, 0, 4), "2010-W01" ], + [ Date.UTC(2010, 0, 10), "2010-W01" ], + [ Date.UTC(2010, 0, 11), "2010-W02" ], + [ 0, "1970-W01" ], + // Maximum valid month (limited by the ecma date object range). + [ 8640000000000000, "275760-W37" ], + // Minimum valid month (limited by the input element minimum valid value). + [ -62135596800000 , "0001-W01" ], + // "Values must be truncated to valid week" + [ 42.1234, "1970-W01" ], + [ 123.123456789123, "1970-W01" ], + [ 1e-1, "1970-W01" ], + [ -1.1, "1970-W01" ], + [ -345600000, "1969-W52" ], + // Negative years, this is out of range for the input element, + // the corresponding week string is the empty string + [ -62135596800001, "" ], + ]; + + element.type = "week"; + for (let data of testData) { + element.valueAsDate = new Date(data[0]); + is(element.value, data[1], "valueAsDate should set the value to " + + data[1]); + element.valueAsDate = new testFrame.Date(data[0]); + is(element.value, data[1], "valueAsDate with other-global date should " + + "set the value to " + data[1]); + } +} + +function checkDatetimeLocalGet() +{ + var validData = + [ + // Simple cases. + [ "2016-12-27T10:30", Date.UTC(2016, 11, 27, 10, 30, 0) ], + [ "2016-12-27T10:30:40", Date.UTC(2016, 11, 27, 10, 30, 40) ], + [ "2016-12-27T10:30:40.567", Date.UTC(2016, 11, 27, 10, 30, 40, 567) ], + [ "1969-12-31T12:00:00", Date.UTC(1969, 11, 31, 12, 0, 0) ], + [ "1970-01-01T00:00", 0 ], + // Leap years. + [ "1804-02-29 12:34", Date.UTC(1804, 1, 29, 12, 34, 0) ], + [ "2016-02-29T12:34", Date.UTC(2016, 1, 29, 12, 34, 0) ], + [ "2016-12-31T12:34:56", Date.UTC(2016, 11, 31, 12, 34, 56) ], + [ "2016-01-01T12:34:56.789", Date.UTC(2016, 0, 1, 12, 34, 56, 789) ], + [ "2017-01-01 12:34:56.789", Date.UTC(2017, 0, 1, 12, 34, 56, 789) ], + // Maximum valid datetime-local (limited by the ecma date object range). + [ "275760-09-13T00:00", 8640000000000000 ], + // Minimum valid datetime-local (limited by the input element minimum valid value). + [ "0001-01-01T00:00", -62135596800000 ], + ]; + + var invalidData = + [ + [ "invaliddateime-local" ], + [ "0000-01-01T00:00" ], + [ "2016-12-25T00:00Z" ], + [ "2015-02-29T12:34" ], + [ "1-1-1T12:00" ], + [ "" ], + // This datetime-local is valid for the input element, but is out of the + // date object range. In this case, on getting valueAsDate, a Date object + // will be created, but it will have a NaN internal value, and will return + // the string "Invalid Date". + [ "275760-09-13T12:00", true ], + ]; + + element.type = "datetime-local"; + for (let data of validData) { + element.value = data[0]; + is(element.valueAsDate.valueOf(), data[1], + "valueAsDate should return the " + + "valid date object representing this datetime-local"); + } + + for (let data of invalidData) { + element.value = data[0]; + if (data[1]) { + is(String(element.valueAsDate), "Invalid Date", + "valueAsDate should return an invalid Date object " + + "when the element value is not a valid datetime-local"); + } else { + is(element.valueAsDate, null, + "valueAsDate should return null " + + "when the element value is not a valid datetime-local"); + } + } +} + +function checkDatetimeLocalSet() +{ + var testData = + [ + // Simple cases. + [ Date.UTC(2016, 11, 27, 10, 30, 0), "2016-12-27T10:30" ], + [ Date.UTC(2016, 11, 27, 10, 30, 30), "2016-12-27T10:30:30" ], + [ Date.UTC(1999, 11, 31, 23, 59, 59), "1999-12-31T23:59:59" ], + [ Date.UTC(1999, 11, 31, 23, 59, 59, 999), "1999-12-31T23:59:59.999" ], + [ Date.UTC(123456, 7, 8, 9, 10), "123456-08-08T09:10" ], + [ 0, "1970-01-01T00:00" ], + // Maximum valid datetime-local (limited by the ecma date object range). + [ 8640000000000000, "275760-09-13T00:00" ], + // Minimum valid datetime-local (limited by the input element minimum valid value). + [ -62135596800000, "0001-01-01T00:00" ], + // Leap years. + [ Date.UTC(1804, 1, 29, 12, 34, 0), "1804-02-29T12:34" ], + [ Date.UTC(2016, 1, 29, 12, 34, 0), "2016-02-29T12:34" ], + [ Date.UTC(2016, 11, 31, 12, 34, 56), "2016-12-31T12:34:56" ], + [ Date.UTC(2016, 0, 1, 12, 34, 56, 789), "2016-01-01T12:34:56.789" ], + [ Date.UTC(2017, 0, 1, 12, 34, 56, 789), "2017-01-01T12:34:56.789" ], + // "Values must be truncated to valid datetime-local" + [ 123.123456789123, "1970-01-01T00:00:00.123" ], + [ 1e-1, "1970-01-01T00:00" ], + [ -1.1, "1969-12-31T23:59:59.999" ], + [ -345600000, "1969-12-28T00:00" ], + // Negative years, this is out of range for the input element, + // the corresponding datetime-local string is the empty string + [ -62135596800001, "" ], + ]; + + element.type = "datetime-local"; + for (let data of testData) { + element.valueAsDate = new Date(data[0]); + is(element.value, data[1], "valueAsDate should set the value to " + + data[1]); + element.valueAsDate = new testFrame.Date(data[0]); + is(element.value, data[1], "valueAsDate with other-global date should " + + "set the value to " + data[1]); + } +} + +checkAvailability(); +checkGarbageValues(); +checkWithBustedPrototype(); + +// Test <input type='date'>. +checkDateGet(); +checkDateSet(); + +// Test <input type='time'>. +checkTimeGet(); +checkTimeSet(); + +// Test <input type='month'>. +checkMonthGet(); +checkMonthSet(); + +// Test <input type='week'>. +checkWeekGet(); +checkWeekSet(); + +// Test <input type='datetime-local'>. +checkDatetimeLocalGet(); +checkDatetimeLocalSet(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/test_valueasnumber_attribute.html b/dom/html/test/forms/test_valueasnumber_attribute.html new file mode 100644 index 0000000000..5f7537f7a8 --- /dev/null +++ b/dom/html/test/forms/test_valueasnumber_attribute.html @@ -0,0 +1,858 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=636737 +--> +<head> + <title>Test for Bug input.valueAsNumber</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=636737">Mozilla Bug 636737</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 636737 **/ + +/** + * This test is checking .valueAsNumber. + */ + +function checkAvailability() +{ + var testData = + [ + ["text", false], + ["password", false], + ["search", false], + ["tel", false], + ["email", false], + ["url", false], + ["hidden", false], + ["checkbox", false], + ["radio", false], + ["file", false], + ["submit", false], + ["image", false], + ["reset", false], + ["button", false], + ["number", true], + ["range", true], + ["date", true], + ["time", true], + ["color", false], + ["month", true], + ["week", true], + ["datetime-local", true], + ]; + + var element = document.createElement('input'); + + for (let data of testData) { + var exceptionCatched = false; + element.type = data[0]; + try { + element.valueAsNumber; + } catch (e) { + exceptionCatched = true; + } + is(exceptionCatched, false, + "valueAsNumber shouldn't throw exception on getting"); + + exceptionCatched = false; + try { + element.valueAsNumber = 42; + } catch (e) { + exceptionCatched = true; + } + is(exceptionCatched, !data[1], "valueAsNumber for " + data[0] + + " availability is not correct"); + } +} + +function checkNumberGet() +{ + var testData = + [ + ["42", 42], + ["-42", -42], // should work for negative values + ["42.1234", 42.1234], + ["123.123456789123", 123.123456789123], // double precision + ["1e2", 100], // e should be usable + ["2e1", 20], + ["1e-1", 0.1], // value after e can be negative + ["1E2", 100], // E can be used instead of e + ["e", null], + ["e2", null], + ["1e0.1", null], + ["", null], // the empty string is not a number + ["foo", null], + ["42,13", null], // comma can't be used as a decimal separator + ]; + + var element = document.createElement('input'); + element.type = "number"; + for (let data of testData) { + element.value = data[0]; + + // Given that NaN != NaN, we have to use null when the expected value is NaN. + if (data[1] != null) { + is(element.valueAsNumber, data[1], "valueAsNumber should return the " + + "floating point representation of the value"); + } else { + ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " + + "when the element value is not a number"); + } + } +} + +function checkNumberSet() +{ + var testData = + [ + [42, "42"], + [-42, "-42"], // should work for negative values + [42.1234, "42.1234"], + [123.123456789123, "123.123456789123"], // double precision + [1e2, "100"], // e should be usable + [2e1, "20"], + [1e-1, "0.1"], // value after e can be negative + [1E2, "100"], // E can be used instead of e + // Setting a string will set NaN. + ["foo", ""], + // "" is converted to 0. + ["", "0"], + [42, "42"], // Keep this here, it is used by the next test. + // Setting Infinity should throw and not change the current value. + [Infinity, "42", true], + [-Infinity, "42", true], + // Setting NaN should change the value to the empty string. + [NaN, ""], + ]; + + var element = document.createElement('input'); + element.type = "number"; + for (let data of testData) { + var caught = false; + try { + element.valueAsNumber = data[0]; + is(element.value, data[1], + "valueAsNumber should be able to set the value"); + } catch (e) { + caught = true; + } + + if (data[2]) { + ok(caught, "valueAsNumber should have thrown"); + is(element.value, data[1], "value should not have changed"); + } else { + ok(!caught, "valueAsNumber should not have thrown"); + } + } +} + +function checkRangeGet() +{ + // For type=range we should never get NaN since the user agent is required + // to fix up the input's value to be something sensible. + + var min = -200; + var max = 200; + var defaultValue = min + (max - min)/2; + + var testData = + [ + ["42", 42], + ["-42", -42], // should work for negative values + ["42.1234", 42.1234], + ["123.123456789123", 123.123456789123], // double precision + ["1e2", 100], // e should be usable + ["2e1", 20], + ["1e-1", 0.1], // value after e can be negative + ["1E2", 100], // E can be used instead of e + ["e", defaultValue], + ["e2", defaultValue], + ["1e0.1", defaultValue], + ["", defaultValue], + ["foo", defaultValue], + ["42,13", defaultValue], + ]; + + var element = document.createElement('input'); + element.type = "range"; + element.setAttribute("min", min); // avoids out of range sanitization + element.setAttribute("max", max); + element.setAttribute("step", "any"); // avoids step mismatch sanitization + for (let data of testData) { + element.value = data[0]; + + // Given that NaN != NaN, we have to use null when the expected value is NaN. + is(element.valueAsNumber, data[1], "valueAsNumber should return the " + + "floating point representation of the value"); + } +} + +function checkRangeSet() +{ + var min = -200; + var max = 200; + var defaultValue = String(min + (max - min)/2); + + var testData = + [ + [42, "42"], + [-42, "-42"], // should work for negative values + [42.1234, "42.1234"], + [123.123456789123, "123.123456789123"], // double precision + [1e2, "100"], // e should be usable + [2e1, "20"], + [1e-1, "0.1"], // value after e can be negative + [1E2, "100"], // E can be used instead of e + ["foo", defaultValue], + ["", defaultValue], + [42, "42"], // Keep this here, it is used by the next test. + // Setting Infinity should throw and not change the current value. + [Infinity, "42", true], + [-Infinity, "42", true], + // Setting NaN should change the value to the empty string. + [NaN, defaultValue], + ]; + + var element = document.createElement('input'); + element.type = "range"; + element.setAttribute("min", min); // avoids out of range sanitization + element.setAttribute("max", max); + element.setAttribute("step", "any"); // avoids step mismatch sanitization + for (let data of testData) { + var caught = false; + try { + element.valueAsNumber = data[0]; + is(element.value, data[1], + "valueAsNumber should be able to set the value"); + } catch (e) { + caught = true; + } + + if (data[2]) { + ok(caught, "valueAsNumber should have thrown"); + is(element.value, data[1], "value should not have changed"); + } else { + ok(!caught, "valueAsNumber should not have thrown"); + } + } +} + +function checkDateGet() +{ + var validData = + [ + [ "2012-07-12", 1342051200000 ], + [ "1970-01-01", 0 ], + // We are supposed to support at least until this date. + // (corresponding to the date object maximal value) + [ "275760-09-13", 8640000000000000 ], + // Minimum valid date (limited by the input element minimum valid value) + [ "0001-01-01", -62135596800000 ], + [ "2012-02-29", 1330473600000 ], + [ "2011-02-28", 1298851200000 ], + ]; + + var invalidData = + [ + "invaliddate", + "", + "275760-09-14", + "999-12-31", + "-001-12-31", + "0000-01-01", + "2011-02-29", + "1901-13-31", + "1901-12-32", + "1901-00-12", + "1901-01-00", + "1900-02-29", + ]; + + var element = document.createElement('input'); + element.type = "date"; + for (let data of validData) { + element.value = data[0]; + is(element.valueAsNumber, data[1], "valueAsNumber should return the " + + "timestamp representing this date"); + } + + for (let data of invalidData) { + element.value = data; + ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " + + "when the element value is not a valid date"); + } +} + +function checkDateSet() +{ + var testData = + [ + [ 1342051200000, "2012-07-12" ], + [ 0, "1970-01-01" ], + // Maximum valid date (limited by the ecma date object range). + [ 8640000000000000, "275760-09-13" ], + // Minimum valid date (limited by the input element minimum valid value) + [ -62135596800000, "0001-01-01" ], + [ 1330473600000, "2012-02-29" ], + [ 1298851200000, "2011-02-28" ], + // "Values must be truncated to valid dates" + [ 42.1234, "1970-01-01" ], + [ 123.123456789123, "1970-01-01" ], + [ 1e2, "1970-01-01" ], + [ 1E9, "1970-01-12" ], + [ 1e-1, "1970-01-01" ], + [ 2e10, "1970-08-20" ], + [ 1298851200010, "2011-02-28" ], + [ -1, "1969-12-31" ], + [ -86400000, "1969-12-31" ], + [ 86400000, "1970-01-02" ], + // Invalid numbers. + // Those are implicitly converted to numbers + [ "", "1970-01-01" ], + [ true, "1970-01-01" ], + [ false, "1970-01-01" ], + [ null, "1970-01-01" ], + // Those are converted to NaN, the corresponding date string is the empty string + [ "invaliddatenumber", "" ], + [ NaN, "" ], + [ undefined, "" ], + // Out of range, the corresponding date string is the empty string + [ -62135596800001, "" ], + // Infinity will keep the current value and throw (so we need to set a current value). + [ 1298851200010, "2011-02-28" ], + [ Infinity, "2011-02-28", true ], + [ -Infinity, "2011-02-28", true ], + ]; + + var element = document.createElement('input'); + element.type = "date"; + for (let data of testData) { + var caught = false; + + try { + element.valueAsNumber = data[0]; + is(element.value, data[1], "valueAsNumber should set the value to " + data[1]); + } catch(e) { + caught = true; + } + + if (data[2]) { + ok(caught, "valueAsNumber should have thrown"); + is(element.value, data[1], "the value should not have changed"); + } else { + ok(!caught, "valueAsNumber should not have thrown"); + } + } + +} + +function checkTimeGet() +{ + var tests = [ + // Some invalid values to begin. + { value: "", result: NaN }, + { value: "foobar", result: NaN }, + { value: "00:", result: NaN }, + { value: "24:00", result: NaN }, + { value: "00:99", result: NaN }, + { value: "00:00:", result: NaN }, + { value: "00:00:99", result: NaN }, + { value: "00:00:00:", result: NaN }, + { value: "00:00:00.", result: NaN }, + { value: "00:00:00.0000", result: NaN }, + // Some simple valid values. + { value: "00:00", result: 0 }, + { value: "00:01", result: 60000 }, + { value: "01:00", result: 3600000 }, + { value: "01:01", result: 3660000 }, + { value: "13:37", result: 49020000 }, + // Valid values including seconds. + { value: "00:00:01", result: 1000 }, + { value: "13:37:42", result: 49062000 }, + // Valid values including seconds fractions. + { value: "00:00:00.001", result: 1 }, + { value: "00:00:00.123", result: 123 }, + { value: "00:00:00.100", result: 100 }, + { value: "00:00:00.000", result: 0 }, + { value: "20:17:31.142", result: 73051142 }, + // Highest possible value. + { value: "23:59:59.999", result: 86399999 }, + // Some values with one or two digits for the fraction of seconds. + { value: "00:00:00.1", result: 100 }, + { value: "00:00:00.14", result: 140 }, + { value: "13:37:42.7", result: 49062700 }, + { value: "23:31:12.23", result: 84672230 }, + ]; + + var element = document.createElement('input'); + element.type = 'time'; + + for (let test of tests) { + element.value = test.value; + if (isNaN(test.result)) { + ok(isNaN(element.valueAsNumber), + "invalid value should have .valueAsNumber return NaN"); + } else { + is(element.valueAsNumber, test.result, + ".valueAsNumber should return " + test.result); + } + } +} + +function checkTimeSet() +{ + var tests = [ + // Some NaN values (should set to empty string). + { value: NaN, result: "" }, + { value: "foobar", result: "" }, + { value() {}, result: "" }, + // Inifinity (should throw). + { value: Infinity, throw: true }, + { value: -Infinity, throw: true }, + // "" converts to 0... JS is fun :) + { value: "", result: "00:00" }, + // Simple tests. + { value: 0, result: "00:00" }, + { value: 1, result: "00:00:00.001" }, + { value: 100, result: "00:00:00.100" }, + { value: 1000, result: "00:00:01" }, + { value: 60000, result: "00:01" }, + { value: 3600000, result: "01:00" }, + { value: 83622234, result: "23:13:42.234" }, + // Some edge cases. + { value: 86400000, result: "00:00" }, + { value: 86400001, result: "00:00:00.001" }, + { value: 170022234, result: "23:13:42.234" }, + { value: 432000000, result: "00:00" }, + { value: -1, result: "23:59:59.999" }, + { value: -86400000, result: "00:00" }, + { value: -86400001, result: "23:59:59.999" }, + { value: -56789, result: "23:59:03.211" }, + { value: 0.9, result: "00:00" }, + ]; + + var element = document.createElement('input'); + element.type = 'time'; + + for (let test of tests) { + try { + var caught = false; + element.valueAsNumber = test.value; + is(element.value, test.result, "value should return " + test.result); + } catch(e) { + caught = true; + } + + if (!test.throw) { + test.throw = false; + } + + is(caught, test.throw, "the test throwing status should be " + test.throw); + } +} + +function checkMonthGet() +{ + var validData = + [ + [ "2016-07", 558 ], + [ "1970-01", 0 ], + [ "1969-12", -1 ], + [ "0001-01", -23628 ], + [ "10000-12", 96371 ], + [ "275760-09", 3285488 ], + ]; + + var invalidData = + [ + "invalidmonth", + "0000-01", + "2000-00", + "2012-13", + // Out of range. + "275760-10", + ]; + + var element = document.createElement('input'); + element.type = "month"; + for (let data of validData) { + element.value = data[0]; + is(element.valueAsNumber, data[1], "valueAsNumber should return the " + + "integer value representing this month"); + } + + for (let data of invalidData) { + element.value = data; + ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " + + "when the element value is not a valid month"); + } +} + +function checkMonthSet() +{ + var testData = + [ + [ 558, "2016-07" ], + [ 0, "1970-01" ], + [ -1, "1969-12" ], + [ 96371, "10000-12" ], + [ 12, "1971-01" ], + [ -12, "1969-01" ], + // Maximum valid month (limited by the ecma date object range) + [ 3285488, "275760-09" ], + // Minimum valid month (limited by the input element minimum valid value) + [ -23628, "0001-01" ], + // "Values must be truncated to valid months" + [ 0.3, "1970-01" ], + [ -1.1, "1969-11" ], + [ 1e2, "1978-05" ], + [ 1e-1, "1970-01" ], + // Invalid numbers. + // Those are implicitly converted to numbers + [ "", "1970-01" ], + [ true, "1970-02" ], + [ false, "1970-01" ], + [ null, "1970-01" ], + // Those are converted to NaN, the corresponding month string is the empty string + [ "invalidmonth", "" ], + [ NaN, "" ], + [ undefined, "" ], + // Out of range, the corresponding month string is the empty string + [ -23629, "" ], + [ 3285489, "" ], + // Infinity will keep the current value and throw (so we need to set a current value) + [ 558, "2016-07" ], + [ Infinity, "2016-07", true ], + [ -Infinity, "2016-07", true ], + ]; + + var element = document.createElement('input'); + element.type = "month"; + for (let data of testData) { + var caught = false; + + try { + element.valueAsNumber = data[0]; + is(element.value, data[1], "valueAsNumber should set the value to " + data[1]); + } catch(e) { + caught = true; + } + + if (data[2]) { + ok(caught, "valueAsNumber should have thrown"); + is(element.value, data[1], "the value should not have changed"); + } else { + ok(!caught, "valueAsNumber should not have thrown"); + } + } +} + +function checkWeekGet() +{ + var validData = + [ + // Common years starting on different days of week. + [ "2007-W01", Date.UTC(2007, 0, 1) ], // Mon + [ "2013-W01", Date.UTC(2012, 11, 31) ], // Tue + [ "2014-W01", Date.UTC(2013, 11, 30) ], // Wed + [ "2015-W01", Date.UTC(2014, 11, 29) ], // Thu + [ "2010-W01", Date.UTC(2010, 0, 4) ], // Fri + [ "2011-W01", Date.UTC(2011, 0, 3) ], // Sat + [ "2017-W01", Date.UTC(2017, 0, 2) ], // Sun + // Common years ending on different days of week. + [ "2007-W52", Date.UTC(2007, 11, 24) ], // Mon + [ "2013-W52", Date.UTC(2013, 11, 23) ], // Tue + [ "2014-W52", Date.UTC(2014, 11, 22) ], // Wed + [ "2015-W53", Date.UTC(2015, 11, 28) ], // Thu + [ "2010-W52", Date.UTC(2010, 11, 27) ], // Fri + [ "2011-W52", Date.UTC(2011, 11, 26) ], // Sat + [ "2017-W52", Date.UTC(2017, 11, 25) ], // Sun + // Leap years starting on different days of week. + [ "1996-W01", Date.UTC(1996, 0, 1) ], // Mon + [ "2008-W01", Date.UTC(2007, 11, 31) ], // Tue + [ "2020-W01", Date.UTC(2019, 11, 30) ], // Wed + [ "2004-W01", Date.UTC(2003, 11, 29) ], // Thu + [ "2016-W01", Date.UTC(2016, 0, 4) ], // Fri + [ "2000-W01", Date.UTC(2000, 0, 3) ], // Sat + [ "2012-W01", Date.UTC(2012, 0, 2) ], // Sun + // Leap years ending on different days of week. + [ "2012-W52", Date.UTC(2012, 11, 24) ], // Mon + [ "2024-W52", Date.UTC(2024, 11, 23) ], // Tue + [ "1980-W52", Date.UTC(1980, 11, 22) ], // Wed + [ "1992-W53", Date.UTC(1992, 11, 28) ], // Thu + [ "2004-W53", Date.UTC(2004, 11, 27) ], // Fri + [ "1988-W52", Date.UTC(1988, 11, 26) ], // Sat + [ "2000-W52", Date.UTC(2000, 11, 25) ], // Sun + // Other normal cases. + [ "2015-W53", Date.UTC(2015, 11, 28) ], + [ "2016-W36", Date.UTC(2016, 8, 5) ], + [ "1970-W01", Date.UTC(1969, 11, 29) ], + [ "275760-W37", Date.UTC(275760, 8, 8) ], + ]; + + var invalidData = + [ + "invalidweek", + "0000-W01", + "2016-W00", + "2016-W53", + // Out of range. + "275760-W38", + ]; + + var element = document.createElement('input'); + element.type = "week"; + for (let data of validData) { + element.value = data[0]; + is(element.valueAsNumber, data[1], "valueAsNumber should return the " + + "integer value representing this week"); + } + + for (let data of invalidData) { + element.value = data; + ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " + + "when the element value is not a valid week"); + } +} + +function checkWeekSet() +{ + var testData = + [ + // Common years starting on different days of week. + [ Date.UTC(2007, 0, 1), "2007-W01" ], // Mon + [ Date.UTC(2013, 0, 1), "2013-W01" ], // Tue + [ Date.UTC(2014, 0, 1), "2014-W01" ], // Wed + [ Date.UTC(2015, 0, 1), "2015-W01" ], // Thu + [ Date.UTC(2010, 0, 1), "2009-W53" ], // Fri + [ Date.UTC(2011, 0, 1), "2010-W52" ], // Sat + [ Date.UTC(2017, 0, 1), "2016-W52" ], // Sun + // Common years ending on different days of week. + [ Date.UTC(2007, 11, 31), "2008-W01" ], // Mon + [ Date.UTC(2013, 11, 31), "2014-W01" ], // Tue + [ Date.UTC(2014, 11, 31), "2015-W01" ], // Wed + [ Date.UTC(2015, 11, 31), "2015-W53" ], // Thu + [ Date.UTC(2010, 11, 31), "2010-W52" ], // Fri + [ Date.UTC(2011, 11, 31), "2011-W52" ], // Sat + [ Date.UTC(2017, 11, 31), "2017-W52" ], // Sun + // Leap years starting on different days of week. + [ Date.UTC(1996, 0, 1), "1996-W01" ], // Mon + [ Date.UTC(2008, 0, 1), "2008-W01" ], // Tue + [ Date.UTC(2020, 0, 1), "2020-W01" ], // Wed + [ Date.UTC(2004, 0, 1), "2004-W01" ], // Thu + [ Date.UTC(2016, 0, 1), "2015-W53" ], // Fri + [ Date.UTC(2000, 0, 1), "1999-W52" ], // Sat + [ Date.UTC(2012, 0, 1), "2011-W52" ], // Sun + // Leap years ending on different days of week. + [ Date.UTC(2012, 11, 31), "2013-W01" ], // Mon + [ Date.UTC(2024, 11, 31), "2025-W01" ], // Tue + [ Date.UTC(1980, 11, 31), "1981-W01" ], // Wed + [ Date.UTC(1992, 11, 31), "1992-W53" ], // Thu + [ Date.UTC(2004, 11, 31), "2004-W53" ], // Fri + [ Date.UTC(1988, 11, 31), "1988-W52" ], // Sat + [ Date.UTC(2000, 11, 31), "2000-W52" ], // Sun + // Other normal cases. + [ Date.UTC(2008, 8, 26), "2008-W39" ], + [ Date.UTC(2016, 0, 4), "2016-W01" ], + [ Date.UTC(2016, 0, 10), "2016-W01" ], + [ Date.UTC(2016, 0, 11), "2016-W02" ], + // Maximum valid week (limited by the ecma date object range). + [ 8640000000000000, "275760-W37" ], + // Minimum valid week (limited by the input element minimum valid value) + [ -62135596800000, "0001-W01" ], + // "Values must be truncated to valid weeks" + [ 0.3, "1970-W01" ], + [ 1e-1, "1970-W01" ], + [ -1.1, "1970-W01" ], + [ -345600000, "1969-W52" ], + // Invalid numbers. + // Those are implicitly converted to numbers + [ "", "1970-W01" ], + [ true, "1970-W01" ], + [ false, "1970-W01" ], + [ null, "1970-W01" ], + // Those are converted to NaN, the corresponding week string is the empty string + [ "invalidweek", "" ], + [ NaN, "" ], + [ undefined, "" ], + // Infinity will keep the current value and throw (so we need to set a current value). + [ Date.UTC(2016, 8, 8), "2016-W36" ], + [ Infinity, "2016-W36", true ], + [ -Infinity, "2016-W36", true ], + ]; + + var element = document.createElement('input'); + element.type = "week"; + for (let data of testData) { + var caught = false; + + try { + element.valueAsNumber = data[0]; + is(element.value, data[1], "valueAsNumber should set the value to " + + data[1]); + } catch(e) { + caught = true; + } + + if (data[2]) { + ok(caught, "valueAsNumber should have thrown"); + is(element.value, data[1], "the value should not have changed"); + } else { + ok(!caught, "valueAsNumber should not have thrown"); + } + } +} + +function checkDatetimeLocalGet() { + var validData = + [ + // Simple cases. + [ "2016-12-20T09:58", Date.UTC(2016, 11, 20, 9, 58) ], + [ "2016-12-20T09:58:30", Date.UTC(2016, 11, 20, 9, 58, 30) ], + [ "2016-12-20T09:58:30.123", Date.UTC(2016, 11, 20, 9, 58, 30, 123) ], + [ "2017-01-01T10:00", Date.UTC(2017, 0, 1, 10, 0, 0) ], + [ "1969-12-31T12:00:00", Date.UTC(1969, 11, 31, 12, 0, 0) ], + [ "1970-01-01T00:00", 0 ], + // Leap years. + [ "1804-02-29 12:34", Date.UTC(1804, 1, 29, 12, 34, 0) ], + [ "2016-02-29T12:34", Date.UTC(2016, 1, 29, 12, 34, 0) ], + [ "2016-12-31T12:34:56", Date.UTC(2016, 11, 31, 12, 34, 56) ], + [ "2016-01-01T12:34:56.789", Date.UTC(2016, 0, 1, 12, 34, 56, 789) ], + [ "2017-01-01 12:34:56.789", Date.UTC(2017, 0, 1, 12, 34, 56, 789) ], + // Maximum valid datetime-local (limited by the ecma date object range). + [ "275760-09-13T00:00", 8640000000000000 ], + // Minimum valid datetime-local (limited by the input element minimum valid value). + [ "0001-01-01T00:00", -62135596800000 ], + ]; + + var invalidData = + [ + "invaliddatetime-local", + "0000-01-01T00:00", + "2016-12-25T00:00Z", + "2015-02-29T12:34", + "1-1-1T12:00", + // Out of range. + "275760-09-13T12:00", + ]; + + var element = document.createElement('input'); + element.type = "datetime-local"; + for (let data of validData) { + element.value = data[0]; + is(element.valueAsNumber, data[1], "valueAsNumber should return the " + + "integer value representing this datetime-local"); + } + + for (let data of invalidData) { + element.value = data; + ok(isNaN(element.valueAsNumber), "valueAsNumber should return NaN " + + "when the element value is not a valid datetime-local"); + } +} + +function checkDatetimeLocalSet() +{ + var testData = + [ + // Simple cases. + [ Date.UTC(2016, 11, 20, 9, 58, 0), "2016-12-20T09:58", ], + [ Date.UTC(2016, 11, 20, 9, 58, 30), "2016-12-20T09:58:30" ], + [ Date.UTC(2016, 11, 20, 9, 58, 30, 123), "2016-12-20T09:58:30.123" ], + [ Date.UTC(2017, 0, 1, 10, 0, 0), "2017-01-01T10:00" ], + [ Date.UTC(1969, 11, 31, 12, 0, 0), "1969-12-31T12:00" ], + [ 0, "1970-01-01T00:00" ], + // Maximum valid week (limited by the ecma date object range). + [ 8640000000000000, "275760-09-13T00:00" ], + // Minimum valid datetime-local (limited by the input element minimum valid value). + [ -62135596800000, "0001-01-01T00:00" ], + // Leap years. + [ Date.UTC(1804, 1, 29, 12, 34, 0), "1804-02-29T12:34" ], + [ Date.UTC(2016, 1, 29, 12, 34, 0), "2016-02-29T12:34" ], + [ Date.UTC(2016, 11, 31, 12, 34, 56), "2016-12-31T12:34:56" ], + [ Date.UTC(2016, 0, 1, 12, 34, 56, 789), "2016-01-01T12:34:56.789" ], + [ Date.UTC(2017, 0, 1, 12, 34, 56, 789), "2017-01-01T12:34:56.789" ], + // "Values must be truncated to valid datetime-local" + [ 0.3, "1970-01-01T00:00" ], + [ 1e-1, "1970-01-01T00:00" ], + [ -1 , "1969-12-31T23:59:59.999" ], + [ -345600000, "1969-12-28T00:00" ], + // Invalid numbers. + // Those are implicitly converted to numbers + [ "", "1970-01-01T00:00" ], + [ true, "1970-01-01T00:00:00.001" ], + [ false, "1970-01-01T00:00" ], + [ null, "1970-01-01T00:00" ], + // Those are converted to NaN, the corresponding week string is the empty string + [ "invaliddatetime-local", "" ], + [ NaN, "" ], + [ undefined, "" ], + // Infinity will keep the current value and throw (so we need to set a current value). + [ Date.UTC(2016, 11, 27, 15, 10, 0), "2016-12-27T15:10" ], + [ Infinity, "2016-12-27T15:10", true ], + [ -Infinity, "2016-12-27T15:10", true ], + ]; + + var element = document.createElement('input'); + element.type = "datetime-local"; + for (let data of testData) { + var caught = false; + + try { + element.valueAsNumber = data[0]; + is(element.value, data[1], "valueAsNumber should set the value to " + + data[1]); + } catch(e) { + caught = true; + } + + if (data[2]) { + ok(caught, "valueAsNumber should have thrown"); + is(element.value, data[1], "the value should not have changed"); + } else { + ok(!caught, "valueAsNumber should not have thrown"); + } + } +} + +checkAvailability(); + +// <input type='number'> test +checkNumberGet(); +checkNumberSet(); + +// <input type='range'> test +checkRangeGet(); +checkRangeSet(); + +// <input type='date'> test +checkDateGet(); +checkDateSet(); + +// <input type='time'> test +checkTimeGet(); +checkTimeSet(); + +// <input type='month'> test +checkMonthGet(); +checkMonthSet(); + +// <input type='week'> test +checkWeekGet(); +checkWeekSet(); + +// <input type='datetime-local'> test +checkDatetimeLocalGet(); +checkDatetimeLocalSet(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/forms/without_selectionchange/mochitest.toml b/dom/html/test/forms/without_selectionchange/mochitest.toml new file mode 100644 index 0000000000..8f019d8d80 --- /dev/null +++ b/dom/html/test/forms/without_selectionchange/mochitest.toml @@ -0,0 +1,5 @@ +[DEFAULT] +prefs = ["dom.select_events.textcontrols.enabled=false"] + +["test_select.html"] + diff --git a/dom/html/test/forms/without_selectionchange/test_select.html b/dom/html/test/forms/without_selectionchange/test_select.html new file mode 100644 index 0000000000..3d11611b1b --- /dev/null +++ b/dom/html/test/forms/without_selectionchange/test_select.html @@ -0,0 +1,21 @@ +<!DOCTYPE HTML> +<meta charset="utf-8"> +<title>Test for Bug 1717435</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" href="/tests/SimpleTest/test.css" /> +</head> + +<textarea id="textarea">foo</textarea> +<script> + SimpleTest.waitForExplicitFinish(); + + textarea.addEventListener("select", ev => { + ok(true, "A select event must fire regardless of dom.select_events.textcontrols.enabled"); + SimpleTest.finish(); + }); + + textarea.focus(); + textarea.select(); + is(textarea.selectionStart, 0, "selectionStart") + is(textarea.selectionEnd, 3, "selectionEnd") +</script> diff --git a/dom/html/test/head.js b/dom/html/test/head.js new file mode 100644 index 0000000000..1e3b435d0c --- /dev/null +++ b/dom/html/test/head.js @@ -0,0 +1,65 @@ +function pushPrefs(...aPrefs) { + return SpecialPowers.pushPrefEnv({ set: aPrefs }); +} + +function promiseWaitForEvent( + object, + eventName, + capturing = false, + chrome = false +) { + return new Promise(resolve => { + function listener(event) { + info("Saw " + eventName); + object.removeEventListener(eventName, listener, capturing, chrome); + resolve(event); + } + + info("Waiting for " + eventName); + object.addEventListener(eventName, listener, capturing, chrome); + }); +} + +/** + * Waits for the next load to complete in any browser or the given browser. + * If a <tabbrowser> is given it waits for a load in any of its browsers. + * + * @return promise + */ +function waitForDocLoadComplete(aBrowser = gBrowser) { + return new Promise(resolve => { + let listener = { + onStateChange(webProgress, req, flags, status) { + let docStop = + Ci.nsIWebProgressListener.STATE_IS_NETWORK | + Ci.nsIWebProgressListener.STATE_STOP; + info( + "Saw state " + + flags.toString(16) + + " and status " + + status.toString(16) + ); + // When a load needs to be retargetted to a new process it is cancelled + // with NS_BINDING_ABORTED so ignore that case + if ((flags & docStop) == docStop && status != Cr.NS_BINDING_ABORTED) { + aBrowser.removeProgressListener(this); + waitForDocLoadComplete.listeners.delete(this); + let chan = req.QueryInterface(Ci.nsIChannel); + info("Browser loaded " + chan.originalURI.spec); + resolve(); + } + }, + QueryInterface: ChromeUtils.generateQI([ + "nsIWebProgressListener", + "nsISupportsWeakReference", + ]), + }; + aBrowser.addProgressListener(listener); + waitForDocLoadComplete.listeners.add(listener); + info("Waiting for browser load"); + }); +} +// Keep a set of progress listeners for waitForDocLoadComplete() to make sure +// they're not GC'ed before we saw the page load. +waitForDocLoadComplete.listeners = new Set(); +registerCleanupFunction(() => waitForDocLoadComplete.listeners.clear()); diff --git a/dom/html/test/image-allow-credentials.png b/dom/html/test/image-allow-credentials.png Binary files differnew file mode 100644 index 0000000000..df24ac6d34 --- /dev/null +++ b/dom/html/test/image-allow-credentials.png diff --git a/dom/html/test/image-allow-credentials.png^headers^ b/dom/html/test/image-allow-credentials.png^headers^ new file mode 100644 index 0000000000..a03f99a9c0 --- /dev/null +++ b/dom/html/test/image-allow-credentials.png^headers^ @@ -0,0 +1,2 @@ +Access-Control-Allow-Origin: http://mochi.test:8888 +Access-Control-Allow-Credentials: true diff --git a/dom/html/test/image.png b/dom/html/test/image.png Binary files differnew file mode 100644 index 0000000000..d26878c9f2 --- /dev/null +++ b/dom/html/test/image.png diff --git a/dom/html/test/image_yellow.png b/dom/html/test/image_yellow.png Binary files differnew file mode 100644 index 0000000000..51e8aaf38c --- /dev/null +++ b/dom/html/test/image_yellow.png diff --git a/dom/html/test/mochitest.toml b/dom/html/test/mochitest.toml new file mode 100644 index 0000000000..d1dd78705b --- /dev/null +++ b/dom/html/test/mochitest.toml @@ -0,0 +1,990 @@ +[DEFAULT] +prefs = ["gfx.font_loader.delay=0"] +support-files = [ + "347174transform.xsl", + "347174transformable.xml", + "allowMedia.sjs", + "bug100533_iframe.html", + "bug100533_load.html", + "bug196523-subframe.html", + "bug199692-nested-d2.html", + "bug199692-nested.html", + "bug199692-popup.html", + "bug199692-scrolled.html", + "bug242709_iframe.html", + "bug242709_load.html", + "bug277724_iframe1.html", + "bug277724_iframe2.xhtml", + "bug277890_iframe.html", + "bug277890_load.html", + "bug340800_iframe.txt", + "bug369370-popup.png", + "bug372098-link-target.html", + "bug441930_iframe.html", + "bug445004-inner.html", + "bug445004-inner.js", + "bug445004-outer-abs.html", + "bug445004-outer-rel.html", + "bug445004-outer-write.html", + "bug446483-iframe.html", + "bug448564-echo.sjs", + "bug448564-iframe-1.html", + "bug448564-iframe-2.html", + "bug448564-iframe-3.html", + "bug448564-submit.js", + "bug499092.html", + "bug499092.xml", + "bug514856_iframe.html", + "bug1260704_iframe.html", + "bug1260704_iframe_empty.html", + "bug1292522_iframe.html", + "bug1292522_page.html", + "bug1315146-iframe.html", + "bug1315146-main.html", + "dummy_page.html", + "test_non-ascii-cookie.html^headers^", + "file_bug209275_1.html", + "file_bug209275_2.html", + "file_bug209275_3.html", + "file_bug297761.html", + "file_bug417760.png", + "file_bug893537.html", + "file_bug1260704.png", + "file_formSubmission_img.jpg", + "file_formSubmission_text.txt", + "file_iframe_sandbox_a_if1.html", + "file_iframe_sandbox_a_if10.html", + "file_iframe_sandbox_a_if11.html", + "file_iframe_sandbox_a_if12.html", + "file_iframe_sandbox_a_if13.html", + "file_iframe_sandbox_a_if14.html", + "file_iframe_sandbox_a_if15.html", + "file_iframe_sandbox_a_if16.html", + "file_iframe_sandbox_a_if17.html", + "file_iframe_sandbox_a_if18.html", + "file_iframe_sandbox_a_if19.html", + "file_iframe_sandbox_a_if2.html", + "file_iframe_sandbox_a_if3.html", + "file_iframe_sandbox_a_if4.html", + "file_iframe_sandbox_a_if5.html", + "file_iframe_sandbox_a_if6.html", + "file_iframe_sandbox_a_if7.html", + "file_iframe_sandbox_a_if8.html", + "file_iframe_sandbox_a_if9.html", + "file_iframe_sandbox_b_if1.html", + "file_iframe_sandbox_b_if2.html", + "file_iframe_sandbox_b_if3.html", + "file_iframe_sandbox_c_if1.html", + "file_iframe_sandbox_c_if2.html", + "file_iframe_sandbox_c_if3.html", + "file_iframe_sandbox_c_if4.html", + "file_iframe_sandbox_c_if5.html", + "file_iframe_sandbox_c_if6.html", + "file_iframe_sandbox_c_if7.html", + "file_iframe_sandbox_c_if8.html", + "file_iframe_sandbox_c_if9.html", + "file_iframe_sandbox_close.html", + "file_iframe_sandbox_d_if1.html", + "file_iframe_sandbox_d_if10.html", + "file_iframe_sandbox_d_if11.html", + "file_iframe_sandbox_d_if12.html", + "file_iframe_sandbox_d_if13.html", + "file_iframe_sandbox_d_if14.html", + "file_iframe_sandbox_d_if15.html", + "file_iframe_sandbox_d_if16.html", + "file_iframe_sandbox_d_if17.html", + "file_iframe_sandbox_d_if18.html", + "file_iframe_sandbox_d_if19.html", + "file_iframe_sandbox_d_if2.html", + "file_iframe_sandbox_d_if20.html", + "file_iframe_sandbox_d_if21.html", + "file_iframe_sandbox_d_if22.html", + "file_iframe_sandbox_d_if23.html", + "file_iframe_sandbox_d_if3.html", + "file_iframe_sandbox_d_if4.html", + "file_iframe_sandbox_d_if5.html", + "file_iframe_sandbox_d_if6.html", + "file_iframe_sandbox_d_if7.html", + "file_iframe_sandbox_d_if8.html", + "file_iframe_sandbox_d_if9.html", + "file_iframe_sandbox_e_if1.html", + "file_iframe_sandbox_e_if10.html", + "file_iframe_sandbox_e_if11.html", + "file_iframe_sandbox_e_if12.html", + "file_iframe_sandbox_e_if13.html", + "file_iframe_sandbox_e_if14.html", + "file_iframe_sandbox_e_if15.html", + "file_iframe_sandbox_e_if16.html", + "file_iframe_sandbox_e_if2.html", + "file_iframe_sandbox_e_if3.html", + "file_iframe_sandbox_e_if4.html", + "file_iframe_sandbox_e_if5.html", + "file_iframe_sandbox_e_if6.html", + "file_iframe_sandbox_e_if7.html", + "file_iframe_sandbox_e_if8.html", + "file_iframe_sandbox_e_if9.html", + "file_iframe_sandbox_fail.js", + "file_iframe_sandbox_form_fail.html", + "file_iframe_sandbox_form_pass.html", + "file_iframe_sandbox_g_if1.html", + "file_iframe_sandbox_h_if1.html", + "file_iframe_sandbox_k_if1.html", + "file_iframe_sandbox_k_if2.html", + "file_iframe_sandbox_k_if3.html", + "file_iframe_sandbox_k_if4.html", + "file_iframe_sandbox_k_if5.html", + "file_iframe_sandbox_k_if6.html", + "file_iframe_sandbox_k_if7.html", + "file_iframe_sandbox_k_if8.html", + "file_iframe_sandbox_k_if9.html", + "file_iframe_sandbox_navigation_fail.html", + "file_iframe_sandbox_navigation_pass.html", + "file_iframe_sandbox_navigation_start.html", + "file_iframe_sandbox_open_window_fail.html", + "file_iframe_sandbox_open_window_pass.html", + "file_iframe_sandbox_pass.js", + "file_iframe_sandbox_redirect.html", + "file_iframe_sandbox_redirect.html^headers^", + "file_iframe_sandbox_redirect_target.html", + "file_iframe_sandbox_refresh.html", + "file_iframe_sandbox_refresh.html^headers^", + "file_iframe_sandbox_srcdoc_allow_scripts.html", + "file_iframe_sandbox_srcdoc_no_allow_scripts.html", + "file_iframe_sandbox_top_navigation_fail.html", + "file_iframe_sandbox_top_navigation_pass.html", + "file_iframe_sandbox_window_form_fail.html", + "file_iframe_sandbox_window_form_pass.html", + "file_iframe_sandbox_window_navigation_fail.html", + "file_iframe_sandbox_window_navigation_pass.html", + "file_iframe_sandbox_window_top_navigation_pass.html", + "file_iframe_sandbox_window_top_navigation_fail.html", + "file_iframe_sandbox_worker.js", + "file_srcdoc-2.html", + "file_srcdoc.html", + "file_srcdoc_iframe3.html", + "file_window_open_close_outer.html", + "file_window_open_close_inner.html", + "formSubmission_chrome.js", + "form_submit_server.sjs", + "formData_worker.js", + "formData_test.js", + "image.png", + "image-allow-credentials.png", + "image-allow-credentials.png^headers^", + "nnc_lockup.gif", + "reflect.js", + "simpleFileOpener.js", + "file_bug1166138_1x.png", + "file_bug1166138_2x.png", + "file_bug1166138_def.png", + "script_fakepath.js", + "sw_formSubmission.js", + "object_bug287465_o1.html", + "object_bug287465_o2.html", + "object_bug556645.html", + "file.webm", + "!/gfx/layers/apz/test/mochitest/apz_test_utils.js", +] + +["test_a_text.html"] + +["test_allowMedia.html"] +skip-if = [ + "verify && (os == 'linux' || os == 'win')", + "!debug && os == 'mac' && bits == 64", + "debug && os == 'win'", + "debug && os == 'linux' && os_version == '18.04'", #Bug 1434744 +] + +["test_anchor_href_cache_invalidation.html"] + +["test_base_attributes_reflection.html"] + +["test_bug589.html"] + +["test_bug691.html"] + +["test_bug694.html"] + +["test_bug696.html"] + +["test_bug1297.html"] + +["test_bug1366.html"] + +["test_bug1400.html"] + +["test_bug1682.html"] + +["test_bug1823.html"] + +["test_bug2082.html"] + +["test_bug3348.html"] + +["test_bug6296.html"] + +["test_bug24958.html"] + +["test_bug57600.html"] + +["test_bug95530.html"] + +["test_bug100533.html"] + +["test_bug109445.html"] + +["test_bug109445.xhtml"] + +["test_bug143220.html"] + +["test_bug182279.html"] + +["test_bug196523.html"] +skip-if = [ + "http3", + "http2", +] + +["test_bug199692.html"] + +["test_bug209275.xhtml"] +skip-if = ["os == 'android'"] #TIMED_OUT + +["test_bug237071.html"] + +["test_bug242709.html"] + +["test_bug255820.html"] + +["test_bug259332.html"] + +["test_bug274626.html"] + +["test_bug277724.html"] + +["test_bug277890.html"] + +["test_bug287465.html"] + +["test_bug295561.html"] + +["test_bug297761.html"] + +["test_bug300691-1.html"] + +["test_bug300691-2.html"] + +["test_bug300691-3.xhtml"] + +["test_bug311681.html"] + +["test_bug311681.xhtml"] + +["test_bug324378.html"] + +["test_bug330705-1.html"] + +["test_bug332246.html"] + +["test_bug332848.xhtml"] + +["test_bug332893-1.html"] + +["test_bug332893-2.html"] + +["test_bug332893-3.html"] + +["test_bug332893-4.html"] + +["test_bug332893-5.html"] + +["test_bug332893-6.html"] + +["test_bug332893-7.html"] + +["test_bug340017.xhtml"] + +["test_bug340800.html"] + +["test_bug347174.html"] + +["test_bug347174_write.html"] + +["test_bug347174_xsl.html"] + +["test_bug347174_xslp.html"] + +["test_bug353415-1.html"] + +["test_bug353415-2.html"] + +["test_bug359657.html"] + +["test_bug369370.html"] +skip-if = [ + "os == 'android'", + "os == 'linux'", # disabled on linux bug 1258103 +] + +["test_bug371375.html"] + +["test_bug372098.html"] + +["test_bug373589.html"] + +["test_bug375003-1.html"] + +["test_bug375003-2.html"] + +["test_bug377624.html"] + +["test_bug380383.html"] + +["test_bug383383.html"] + +["test_bug383383_2.xhtml"] + +["test_bug384419.html"] + +["test_bug386496.html"] + +["test_bug386728.html"] + +["test_bug386996.html"] + +["test_bug388558.html"] + +["test_bug388746.html"] + +["test_bug388794.html"] + +["test_bug389797.html"] + +["test_bug390975.html"] + +["test_bug391994.html"] + +["test_bug394700.html"] + +["test_bug395107.html"] + +["test_bug401160.xhtml"] + +["test_bug402680.html"] + +["test_bug403868.html"] + +["test_bug403868.xhtml"] + +["test_bug405242.html"] + +["test_bug406596.html"] + +["test_bug417760.html"] + +["test_bug421640.html"] + +["test_bug424698.html"] + +["test_bug428135.xhtml"] + +["test_bug430351.html"] +skip-if = ["os == 'android'"] # Bug 1525959 + +["test_bug435128.html"] +skip-if = ["true"] # Disabled for timeouts. + +["test_bug441930.html"] + +["test_bug442801.html"] + +["test_bug445004.html"] +skip-if = ["true"] # Disabled permanently (bug 559932). + +["test_bug446483.html"] + +["test_bug448166.html"] + +["test_bug448564.html"] + +["test_bug456229.html"] + +["test_bug458037.xhtml"] +allow_xul_xbl = true +skip-if = [ + "http3", + "http2", +] + +["test_bug460568.html"] + +["test_bug463104.html"] + +["test_bug478251.html"] + +["test_bug481335.xhtml"] +skip-if = ["os == 'android'"] #TIMED_OUT + +["test_bug481440.html"] + +["test_bug481647.html"] + +["test_bug482659.html"] + +["test_bug486741.html"] + +["test_bug489532.html"] + +["test_bug497242.xhtml"] + +["test_bug499092.html"] + +["test_bug500885.html"] + +["test_bug512367.html"] + +["test_bug514856.html"] + +["test_bug518122.html"] + +["test_bug519987.html"] + +["test_bug523771.html"] + +["test_bug529819.html"] + +["test_bug529859.html"] + +["test_bug535043.html"] + +["test_bug536891.html"] + +["test_bug536895.html"] + +["test_bug546995.html"] + +["test_bug547850.html"] + +["test_bug551846.html"] + +["test_bug555567.html"] + +["test_bug556645.html"] + +["test_bug557087-1.html"] + +["test_bug557087-2.html"] + +["test_bug557087-3.html"] + +["test_bug557087-4.html"] + +["test_bug557087-5.html"] + +["test_bug557087-6.html"] + +["test_bug557620.html"] + +["test_bug558788-1.html"] + +["test_bug558788-2.html"] + +["test_bug560112.html"] + +["test_bug561634.html"] + +["test_bug561636.html"] + +["test_bug561640.html"] + +["test_bug564001.html"] + +["test_bug566046.html"] + +["test_bug567938-1.html"] + +["test_bug567938-2.html"] + +["test_bug567938-3.html"] + +["test_bug567938-4.html"] + +["test_bug569955.html"] + +["test_bug573969.html"] + +["test_bug579079.html"] + +["test_bug582412-1.html"] + +["test_bug582412-2.html"] + +["test_bug583514.html"] + +["test_bug583533.html"] + +["test_bug586763.html"] + +["test_bug586786.html"] + +["test_bug587469.html"] + +["test_bug590353-1.html"] + +["test_bug590353-2.html"] + +["test_bug590363.html"] + +["test_bug592802.html"] + +["test_bug593689.html"] + +["test_bug595429.html"] + +["test_bug595447.html"] + +["test_bug595449.html"] + +["test_bug596350.html"] + +["test_bug596511.html"] + +["test_bug598643.html"] + +["test_bug598833-1.html"] + +["test_bug600155.html"] + +["test_bug601030.html"] + +["test_bug605124-1.html"] + +["test_bug605124-2.html"] + +["test_bug605125-1.html"] + +["test_bug605125-2.html"] + +["test_bug606817.html"] + +["test_bug607145.html"] +skip-if = [ + "http3", + "http2", +] + +["test_bug610212.html"] + +["test_bug610687.html"] + +["test_bug611189.html"] + +["test_bug612730.html"] +skip-if = ["os == 'android'"] # form control not selected/checked with synthesizeMouse + +["test_bug613019.html"] + +["test_bug613113.html"] + +["test_bug613722.html"] + +["test_bug613979.html"] + +["test_bug615595.html"] +fail-if = ["xorigin"] + +["test_bug615833.html"] +skip-if = [ + "os == 'android'", + "os == 'mac'", #TIMED_OUT # form control not selected/checked with synthesizeMouse, osx(bug 1275664) +] + +["test_bug618948.html"] + +["test_bug619278.html"] + +["test_bug622597.html"] + +["test_bug623291.html"] + +["test_bug629801.html"] + +["test_bug633058.html"] + +["test_bug636336.html"] + +["test_bug641219.html"] + +["test_bug643051.html"] + +["test_bug646157.html"] + +["test_bug649134.html"] +# This extra subdirectory is needed due to the nature of this test. +# With the bug, the test loads the base URL of the bug649134/file_*.sjs +# files, and the mochitest server responds with the contents of index.html if +# it exists in that case, which we use to detect failure. +# We cannot have index.html in this directory because it would prevent +# running the tests here. +support-files = [ + "bug649134/file_bug649134-1.sjs", + "bug649134/file_bug649134-2.sjs", + "bug649134/index.html", +] +skip-if = [ + "http3", + "http2", +] + +["test_bug651956.html"] + +["test_bug658746.html"] + +["test_bug659596.html"] + +["test_bug659743.xml"] + +["test_bug660663.html"] + +["test_bug660959-1.html"] + +["test_bug660959-2.html"] + +["test_bug660959-3.html"] + +["test_bug666200.html"] + +["test_bug666666.html"] + +["test_bug669012.html"] + +["test_bug674558.html"] + +["test_bug674927.html"] + +["test_bug677495-1.html"] + +["test_bug677495.html"] + +["test_bug677658.html"] + +["test_bug682886.html"] + +["test_bug694503.html"] +skip-if = ["os == 'android'"] # Bug 1525959 + +["test_bug717819.html"] + +["test_bug741266.html"] +skip-if = [ + "os == 'android'", # Android: needs control of popup window size + "display == 'wayland' && os_version == '22.04' && debug", # Bug 1856975 +] + +["test_bug742030.html"] + +["test_bug742549.html"] + +["test_bug745685.html"] + +["test_bug763626.html"] + +["test_bug765780.html"] + +["test_bug780993.html"] + +["test_bug787134.html"] + +["test_bug797113.html"] + +["test_bug803677.html"] + +["test_bug821307.html"] + +["test_bug827126.html"] + +["test_bug838582.html"] + +["test_bug839371.html"] + +["test_bug839913.html"] + +["test_bug841466.html"] + +["test_bug845057.html"] + +["test_bug869040.html"] + +["test_bug870787.html"] + +["test_bug871161.html"] +support-files = [ + "file_bug871161-1.html", + "file_bug871161-2.html", +] +skip-if = [ + "http3", + "http2", +] + +["test_bug874758.html"] + +["test_bug879319.html"] + +["test_bug885024.html"] + +["test_bug893537.html"] + +["test_bug969346.html"] + +["test_bug982039.html"] + +["test_bug1003539.html"] + +["test_bug1013316.html"] + +["test_bug1045270.html"] + +["test_bug1089326.html"] + +["test_bug1146116.html"] + +["test_bug1166138.html"] + +["test_bug1203668.html"] + +["test_bug1230665.html"] + +["test_bug1250401.html"] + +["test_bug1260664.html"] + +["test_bug1260704.html"] +skip-if = [ + "http3", + "http2", +] + +["test_bug1261673.html"] +skip-if = [ + "os == 'android'", + "os == 'mac'", +] + +["test_bug1261674-1.html"] +skip-if = [ + "os == 'android'", + "os == 'mac'", +] + +["test_bug1261674-2.html"] +skip-if = ["os == 'mac'"] + +["test_bug1264157.html"] + +["test_bug1279218.html"] + +["test_bug1287321.html"] + +["test_bug1292522_same_domain_with_different_port_number.html"] +skip-if = [ + "http3", + "http2", +] + +["test_bug1295719_event_sequence_for_arrow_keys.html"] +skip-if = ["os == 'android'"] # up/down arrow keys not supported on android + +["test_bug1295719_event_sequence_for_number_keys.html"] + +["test_bug1310865.html"] + +["test_bug1315146.html"] +skip-if = [ + "http3", + "http2", +] + +["test_bug1322678.html"] +skip-if = ["os == 'android'"] + +["test_bug1323815.html"] + +["test_bug1472426.html"] + +["test_bug1785739.html"] + +["test_change_crossorigin.html"] +skip-if = [ + "http3", + "http2", +] + +["test_checked.html"] + +["test_dir_attributes_reflection.html"] + +["test_dl_attributes_reflection.html"] + +["test_document-element-inserted.html"] + +["test_documentAll.html"] + +["test_element_prototype.html"] + +["test_embed_attributes_reflection.html"] + +["test_fakepath.html"] + +["test_filepicker_default_directory.html"] + +["test_focusshift_button.html"] + +["test_form-parsing.html"] + +["test_formData.html"] + +["test_formSubmission.html"] +skip-if = ["os == 'android'"] #TIMED_OUT + +["test_formSubmission2.html"] +skip-if = ["os == 'android'"] + +["test_formelements.html"] + +["test_fragment_form_pointer.html"] + +["test_frame_count_with_synthetic_doc.html"] + +["test_getElementsByName_after_mutation.html"] + +["test_hidden.html"] + +["test_html_attributes_reflection.html"] + +["test_htmlcollection.html"] + +["test_iframe_sandbox_general.html"] +tags = "openwindow" +skip-if = [ + "http3", + "http2", +] + +["test_iframe_sandbox_inheritance.html"] +tags = "openwindow" + +["test_iframe_sandbox_navigation.html"] +tags = "openwindow" + +["test_iframe_sandbox_navigation2.html"] +tags = "openwindow" + +["test_iframe_sandbox_popups.html"] +tags = "openwindow" + +["test_iframe_sandbox_popups_inheritance.html"] +tags = "openwindow" + +["test_iframe_sandbox_redirect.html"] + +["test_iframe_sandbox_refresh.html"] + +["test_iframe_sandbox_same_origin.html"] + +["test_iframe_sandbox_workers.html"] + +["test_imageSrcSet.html"] + +["test_image_clone_load.html"] +skip-if = [ + "http3", + "http2", +] + +["test_img_attributes_reflection.html"] + +["test_input_file_cancel_event.html"] + +["test_input_files_not_nsIFile.html"] + +["test_input_lastInteractiveValue.html"] + +["test_inputmode.html"] + +["test_li_attributes_reflection.html"] + +["test_link_attributes_reflection.html"] + +["test_link_sizes.html"] + +["test_map_attributes_reflection.html"] + +["test_meta_attributes_reflection.html"] + +["test_mod_attributes_reflection.html"] + +["test_multipleFilePicker.html"] + +["test_named_options.html"] + +["test_nested_invalid_fieldsets.html"] + +["test_nestediframe.html"] + +["test_non-ascii-cookie.html"] +support-files = ["file_cookiemanager.js"] +skip-if = [ + "xorigin", + "http3", + "http2", +] + +["test_object_attributes_reflection.html"] + +["test_ol_attributes_reflection.html"] + +["test_option_defaultSelected.html"] + +["test_option_selected_state.html"] + +["test_param_attributes_reflection.html"] + +["test_q_attributes_reflection.html"] + +["test_restore_from_parser_fragment.html"] + +["test_rowscollection.html"] + +["test_script_module.html"] +support-files = ["file_script_module.html"] + +["test_set_input_files.html"] + +["test_srcdoc-2.html"] + +["test_srcdoc.html"] + +["test_style_attributes_reflection.html"] + +["test_track.html"] + +["test_ul_attributes_reflection.html"] + +["test_viewport_resize.html"] + +["test_window_open_close.html"] +tags = "openwindow" +skip-if = [ + "os == 'android' && debug", + "os == 'linux'", + "os == 'win' && debug && bits == 64", # Bug 1533759 +] + +["test_window_open_from_closing.html"] +skip-if = ["os == 'android'"] # test does not function on android due to aggressive background tab freezing +support-files = [ + "file_window_close_and_open.html", + "file_broadcast_load.html", +] diff --git a/dom/html/test/nnc_lockup.gif b/dom/html/test/nnc_lockup.gif Binary files differnew file mode 100644 index 0000000000..f746bb71d9 --- /dev/null +++ b/dom/html/test/nnc_lockup.gif diff --git a/dom/html/test/object_bug287465_o1.html b/dom/html/test/object_bug287465_o1.html new file mode 100644 index 0000000000..0a65a7f9e1 --- /dev/null +++ b/dom/html/test/object_bug287465_o1.html @@ -0,0 +1 @@ +<svg xmlns='http://www.w3.org/2000/svg'></svg> diff --git a/dom/html/test/object_bug287465_o2.html b/dom/html/test/object_bug287465_o2.html new file mode 100644 index 0000000000..18ecdcb795 --- /dev/null +++ b/dom/html/test/object_bug287465_o2.html @@ -0,0 +1 @@ +<html></html> diff --git a/dom/html/test/object_bug556645.html b/dom/html/test/object_bug556645.html new file mode 100644 index 0000000000..773837502a --- /dev/null +++ b/dom/html/test/object_bug556645.html @@ -0,0 +1 @@ +<body><button>Child</button></body> diff --git a/dom/html/test/post_action_page.html b/dom/html/test/post_action_page.html new file mode 100644 index 0000000000..ba6ae514f2 --- /dev/null +++ b/dom/html/test/post_action_page.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"/> + <title>Submission Flush Test Post Action Page</title> + </head> + <body> + <h1>Post Action Page</h1> + </body> +</html> diff --git a/dom/html/test/reflect.js b/dom/html/test/reflect.js new file mode 100644 index 0000000000..44f73ae4a2 --- /dev/null +++ b/dom/html/test/reflect.js @@ -0,0 +1,1078 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * reflect.js is a collection of methods to test HTML attribute reflection. + * Each of attribute is reflected differently, depending on various parameters, + * see: + * http://www.whatwg.org/html/#reflecting-content-attributes-in-idl-attributes + * + * Do not forget to add these line at the beginning of each new reflect* method: + * ok(attr in element, attr + " should be an IDL attribute of this element"); + * is(typeof element[attr], <type>, attr + " IDL attribute should be a <type>"); + */ + +/** + * Checks that a given attribute is correctly reflected as a string. + * + * @param aParameters Object object containing the parameters, which are: + * - element Element node to test + * - attribute String name of the attribute + * OR + * attribute Object object containing two attributes, 'content' and 'idl' + * - otherValues Array [optional] other values to test in addition of the default ones + * - extendedAttributes Object object which can have 'TreatNullAs': "EmptyString" + */ +function reflectString(aParameters) { + var element = aParameters.element; + var contentAttr = + typeof aParameters.attribute === "string" + ? aParameters.attribute + : aParameters.attribute.content; + var idlAttr = + typeof aParameters.attribute === "string" + ? aParameters.attribute + : aParameters.attribute.idl; + var otherValues = + aParameters.otherValues !== undefined ? aParameters.otherValues : []; + var treatNullAs = aParameters.extendedAttributes + ? aParameters.extendedAttributes.TreatNullAs + : null; + + ok( + idlAttr in element, + idlAttr + " should be an IDL attribute of this element" + ); + is( + typeof element[idlAttr], + "string", + "'" + idlAttr + "' IDL attribute should be a string" + ); + + // Tests when the attribute isn't set. + is( + element.getAttribute(contentAttr), + null, + "When not set, the content attribute should be null." + ); + is( + element[idlAttr], + "", + "When not set, the IDL attribute should return the empty string" + ); + + /** + * TODO: as long as null stringification doesn't follow the WebIDL + * specifications, don't add it to the loop below and keep it here. + */ + element.setAttribute(contentAttr, null); + is( + element.getAttribute(contentAttr), + "null", + "null should have been stringified to 'null' for '" + contentAttr + "'" + ); + is( + element[idlAttr], + "null", + "null should have been stringified to 'null' for '" + idlAttr + "'" + ); + element.removeAttribute(contentAttr); + + element[idlAttr] = null; + if (treatNullAs == "EmptyString") { + is( + element.getAttribute(contentAttr), + "", + "null should have been stringified to '' for '" + contentAttr + "'" + ); + is( + element[idlAttr], + "", + "null should have been stringified to '' for '" + idlAttr + "'" + ); + } else { + is( + element.getAttribute(contentAttr), + "null", + "null should have been stringified to 'null' for '" + contentAttr + "'" + ); + is( + element[idlAttr], + "null", + "null should have been stringified to 'null' for '" + contentAttr + "'" + ); + } + element.removeAttribute(contentAttr); + + // Tests various strings. + var stringsToTest = [ + // [ test value, expected result ] + ["", ""], + ["null", "null"], + ["undefined", "undefined"], + ["foo", "foo"], + [contentAttr, contentAttr], + [idlAttr, idlAttr], + // TODO: uncomment this when null stringification will follow the specs. + // [ null, "null" ], + [undefined, "undefined"], + [true, "true"], + [false, "false"], + [42, "42"], + // ES5, verse 8.12.8. + [ + { + toString() { + return "foo"; + }, + }, + "foo", + ], + [ + { + valueOf() { + return "foo"; + }, + }, + "[object Object]", + ], + [ + { + valueOf() { + return "quux"; + }, + toString: undefined, + }, + "quux", + ], + [ + { + valueOf() { + return "foo"; + }, + toString() { + return "bar"; + }, + }, + "bar", + ], + ]; + + otherValues.forEach(function (v) { + stringsToTest.push([v, v]); + }); + + stringsToTest.forEach(function ([v, r]) { + element.setAttribute(contentAttr, v); + is( + element[idlAttr], + r, + "IDL attribute '" + + idlAttr + + "' should return the value it has been set to." + ); + is( + element.getAttribute(contentAttr), + r, + "Content attribute '" + + contentAttr + + "'should return the value it has been set to." + ); + element.removeAttribute(contentAttr); + + element[idlAttr] = v; + is( + element[idlAttr], + r, + "IDL attribute '" + + idlAttr + + "' should return the value it has been set to." + ); + is( + element.getAttribute(contentAttr), + r, + "Content attribute '" + + contentAttr + + "' should return the value it has been set to." + ); + element.removeAttribute(contentAttr); + }); + + // Tests after removeAttribute() is called. Should be equivalent with not set. + is( + element.getAttribute(contentAttr), + null, + "When not set, the content attribute should be null." + ); + is( + element[idlAttr], + "", + "When not set, the IDL attribute should return the empty string" + ); +} + +/** + * Checks that a given attribute name for a given element is correctly reflected + * as an unsigned int. + * + * @param aParameters Object object containing the parameters, which are: + * - element Element node to test on + * - attribute String name of the attribute + * - nonZero Boolean whether the attribute should be non-null + * - defaultValue Integer [optional] default value, if different from the default one + */ +function reflectUnsignedInt(aParameters) { + var element = aParameters.element; + var attr = aParameters.attribute; + var nonZero = aParameters.nonZero; + var defaultValue = aParameters.defaultValue; + var fallback = aParameters.fallback; + + if (defaultValue === undefined) { + if (nonZero) { + defaultValue = 1; + } else { + defaultValue = 0; + } + } + + if (fallback === undefined) { + fallback = false; + } + + ok(attr in element, attr + " should be an IDL attribute of this element"); + is( + typeof element[attr], + "number", + attr + " IDL attribute should be a number" + ); + + // Check default value. + is(element[attr], defaultValue, "default value should be " + defaultValue); + ok(!element.hasAttribute(attr), attr + " shouldn't be present"); + + var values = [1, 3, 42, 2147483647]; + + for (var value of values) { + element[attr] = value; + is(element[attr], value, "." + attr + " should be equals " + value); + is( + element.getAttribute(attr), + String(value), + "@" + attr + " should be equals " + value + ); + + element.setAttribute(attr, value); + is(element[attr], value, "." + attr + " should be equals " + value); + is( + element.getAttribute(attr), + String(value), + "@" + attr + " should be equals " + value + ); + } + + // -3000000000 is equivalent to 1294967296 when using the IDL attribute. + element[attr] = -3000000000; + is(element[attr], 1294967296, "." + attr + " should be equals to 1294967296"); + is( + element.getAttribute(attr), + "1294967296", + "@" + attr + " should be equals to 1294967296" + ); + + // When setting the content attribute, it's a string so it will be invalid. + element.setAttribute(attr, -3000000000); + is( + element.getAttribute(attr), + "-3000000000", + "@" + attr + " should be equals to " + -3000000000 + ); + is( + element[attr], + defaultValue, + "." + attr + " should be equals to " + defaultValue + ); + + // When interpreted as unsigned 32-bit integers, all of these fall between + // 2^31 and 2^32 - 1, so per spec they return the default value. + var nonValidValues = [-2147483648, -1, 3147483647]; + + for (var value of nonValidValues) { + element[attr] = value; + is( + element.getAttribute(attr), + String(defaultValue), + "@" + attr + " should be equals to " + defaultValue + ); + is( + element[attr], + defaultValue, + "." + attr + " should be equals to " + defaultValue + ); + } + + for (var values of nonValidValues) { + element.setAttribute(attr, values[0]); + is( + element.getAttribute(attr), + String(values[0]), + "@" + attr + " should be equals to " + values[0] + ); + is( + element[attr], + defaultValue, + "." + attr + " should be equals to " + defaultValue + ); + } + + // Setting to 0 should throw an error if nonZero is true. + var caught = false; + try { + element[attr] = 0; + } catch (e) { + caught = true; + is(e.name, "IndexSizeError", "exception should be IndexSizeError"); + is( + e.code, + DOMException.INDEX_SIZE_ERR, + "exception code should be INDEX_SIZE_ERR" + ); + } + + if (nonZero && !fallback) { + ok(caught, "an exception should have been caught"); + } else { + ok(!caught, "no exception should have been caught"); + } + + // If 0 is set in @attr, it will be ignored when calling .attr. + element.setAttribute(attr, "0"); + is(element.getAttribute(attr), "0", "@" + attr + " should be equals to 0"); + if (nonZero) { + is( + element[attr], + defaultValue, + "." + attr + " should be equals to " + defaultValue + ); + } else { + is(element[attr], 0, "." + attr + " should be equals to 0"); + } +} + +/** + * Checks that a given attribute is correctly reflected as limited to known + * values enumerated attribute. + * + * @param aParameters Object object containing the parameters, which are: + * - element Element node to test on + * - attribute String name of the attribute + * OR + * attribute Object object containing two attributes, 'content' and 'idl' + * - validValues Array valid values we support + * - invalidValues Array invalid values + * - defaultValue String [optional] default value when no valid value is set + * OR + * defaultValue Object [optional] object containing two attributes, 'invalid' and 'missing' + * - unsupportedValues Array [optional] valid values we do not support + * - nullable boolean [optional] whether the attribute is nullable + */ +function reflectLimitedEnumerated(aParameters) { + var element = aParameters.element; + var contentAttr = + typeof aParameters.attribute === "string" + ? aParameters.attribute + : aParameters.attribute.content; + var idlAttr = + typeof aParameters.attribute === "string" + ? aParameters.attribute + : aParameters.attribute.idl; + var validValues = aParameters.validValues; + var invalidValues = aParameters.invalidValues; + var defaultValueInvalid = + aParameters.defaultValue === undefined + ? "" + : typeof aParameters.defaultValue === "string" + ? aParameters.defaultValue + : aParameters.defaultValue.invalid; + var defaultValueMissing = + aParameters.defaultValue === undefined + ? "" + : typeof aParameters.defaultValue === "string" + ? aParameters.defaultValue + : aParameters.defaultValue.missing; + var unsupportedValues = + aParameters.unsupportedValues !== undefined + ? aParameters.unsupportedValues + : []; + var nullable = aParameters.nullable; + + ok( + idlAttr in element, + idlAttr + " should be an IDL attribute of this element" + ); + if (nullable) { + // The missing value default is null, which is typeof == "object" + is( + typeof element[idlAttr], + "object", + "'" + + idlAttr + + "' IDL attribute should be null, which has typeof == object" + ); + is( + element[idlAttr], + null, + "'" + idlAttr + "' IDL attribute should be null" + ); + } else { + is( + typeof element[idlAttr], + "string", + "'" + idlAttr + "' IDL attribute should be a string" + ); + } + + if (nullable) { + element.setAttribute(contentAttr, "something"); + // Now it will be a string + is( + typeof element[idlAttr], + "string", + "'" + idlAttr + "' IDL attribute should be a string" + ); + } + + // Explicitly check the default value. + element.removeAttribute(contentAttr); + is( + element[idlAttr], + defaultValueMissing, + "When no attribute is set, the value should be the default value." + ); + + // Check valid values. + validValues.forEach(function (v) { + element.setAttribute(contentAttr, v); + is( + element[idlAttr], + v, + "'" + v + "' should be accepted as a valid value for " + idlAttr + ); + is( + element.getAttribute(contentAttr), + v, + "Content attribute should return the value it has been set to." + ); + element.removeAttribute(contentAttr); + + element.setAttribute(contentAttr, v.toUpperCase()); + is( + element[idlAttr], + v, + "Enumerated attributes should be case-insensitive." + ); + is( + element.getAttribute(contentAttr), + v.toUpperCase(), + "Content attribute should not be lower-cased." + ); + element.removeAttribute(contentAttr); + + element[idlAttr] = v; + is( + element[idlAttr], + v, + "'" + v + "' should be accepted as a valid value for " + idlAttr + ); + is( + element.getAttribute(contentAttr), + v, + "Content attribute should return the value it has been set to." + ); + element.removeAttribute(contentAttr); + + element[idlAttr] = v.toUpperCase(); + is( + element[idlAttr], + v, + "Enumerated attributes should be case-insensitive." + ); + is( + element.getAttribute(contentAttr), + v.toUpperCase(), + "Content attribute should not be lower-cased." + ); + element.removeAttribute(contentAttr); + }); + + // Check invalid values. + invalidValues.forEach(function (v) { + element.setAttribute(contentAttr, v); + is( + element[idlAttr], + defaultValueInvalid, + "When the content attribute is set to an invalid value, the default value should be returned." + ); + is( + element.getAttribute(contentAttr), + v, + "Content attribute should not have been changed." + ); + element.removeAttribute(contentAttr); + + element[idlAttr] = v; + is( + element[idlAttr], + defaultValueInvalid, + "When the value is set to an invalid value, the default value should be returned." + ); + is( + element.getAttribute(contentAttr), + v, + "Content attribute should not have been changed." + ); + element.removeAttribute(contentAttr); + }); + + // Check valid values we currently do not support. + // Basically, it's like the checks for the valid values but with some todo's. + unsupportedValues.forEach(function (v) { + element.setAttribute(contentAttr, v); + todo_is( + element[idlAttr], + v, + "'" + v + "' should be accepted as a valid value for " + idlAttr + ); + is( + element.getAttribute(contentAttr), + v, + "Content attribute should return the value it has been set to." + ); + element.removeAttribute(contentAttr); + + element.setAttribute(contentAttr, v.toUpperCase()); + todo_is( + element[idlAttr], + v, + "Enumerated attributes should be case-insensitive." + ); + is( + element.getAttribute(contentAttr), + v.toUpperCase(), + "Content attribute should not be lower-cased." + ); + element.removeAttribute(contentAttr); + + element[idlAttr] = v; + todo_is( + element[idlAttr], + v, + "'" + v + "' should be accepted as a valid value for " + idlAttr + ); + is( + element.getAttribute(contentAttr), + v, + "Content attribute should return the value it has been set to." + ); + element.removeAttribute(contentAttr); + + element[idlAttr] = v.toUpperCase(); + todo_is( + element[idlAttr], + v, + "Enumerated attributes should be case-insensitive." + ); + is( + element.getAttribute(contentAttr), + v.toUpperCase(), + "Content attribute should not be lower-cased." + ); + element.removeAttribute(contentAttr); + }); + + if (nullable) { + is( + defaultValueMissing, + null, + "Missing default value should be null for nullable attributes" + ); + ok(validValues.length, "We better have at least one valid value"); + element.setAttribute(contentAttr, validValues[0]); + ok( + element.hasAttribute(contentAttr), + "Should have content attribute: we just set it" + ); + element[idlAttr] = null; + ok( + !element.hasAttribute(contentAttr), + "Should have removed content attribute" + ); + } +} + +/** + * Checks that a given attribute is correctly reflected as a boolean. + * + * @param aParameters Object object containing the parameters, which are: + * - element Element node to test on + * - attribute String name of the attribute + * OR + * attribute Object object containing two attributes, 'content' and 'idl' + */ +function reflectBoolean(aParameters) { + var element = aParameters.element; + var contentAttr = + typeof aParameters.attribute === "string" + ? aParameters.attribute + : aParameters.attribute.content; + var idlAttr = + typeof aParameters.attribute === "string" + ? aParameters.attribute + : aParameters.attribute.idl; + + ok( + idlAttr in element, + idlAttr + " should be an IDL attribute of this element" + ); + is( + typeof element[idlAttr], + "boolean", + idlAttr + " IDL attribute should be a boolean" + ); + + // Tests when the attribute isn't set. + is( + element.getAttribute(contentAttr), + null, + "When not set, the content attribute should be null." + ); + is( + element[idlAttr], + false, + "When not set, the IDL attribute should return false" + ); + + /** + * Test various values. + * Each value to test is actually an object containing a 'value' property + * containing the value to actually test, a 'stringified' property containing + * the stringified value and a 'result' property containing the expected + * result when the value is set to the IDL attribute. + */ + var valuesToTest = [ + { value: true, stringified: "true", result: true }, + { value: false, stringified: "false", result: false }, + { value: "true", stringified: "true", result: true }, + { value: "false", stringified: "false", result: true }, + { value: "foo", stringified: "foo", result: true }, + { value: idlAttr, stringified: idlAttr, result: true }, + { value: contentAttr, stringified: contentAttr, result: true }, + { value: "null", stringified: "null", result: true }, + { value: "undefined", stringified: "undefined", result: true }, + { value: "", stringified: "", result: false }, + { value: undefined, stringified: "undefined", result: false }, + { value: null, stringified: "null", result: false }, + { value: +0, stringified: "0", result: false }, + { value: -0, stringified: "0", result: false }, + { value: NaN, stringified: "NaN", result: false }, + { value: 42, stringified: "42", result: true }, + { value: Infinity, stringified: "Infinity", result: true }, + { value: -Infinity, stringified: "-Infinity", result: true }, + // ES5, verse 9.2. + { + value: { + toString() { + return "foo"; + }, + }, + stringified: "foo", + result: true, + }, + { + value: { + valueOf() { + return "foo"; + }, + }, + stringified: "[object Object]", + result: true, + }, + { + value: { + valueOf() { + return "quux"; + }, + toString: undefined, + }, + stringified: "quux", + result: true, + }, + { + value: { + valueOf() { + return "foo"; + }, + toString() { + return "bar"; + }, + }, + stringified: "bar", + result: true, + }, + { + value: { + valueOf() { + return false; + }, + }, + stringified: "[object Object]", + result: true, + }, + { + value: { foo: false, bar: false }, + stringified: "[object Object]", + result: true, + }, + { value: {}, stringified: "[object Object]", result: true }, + ]; + + valuesToTest.forEach(function (v) { + element.setAttribute(contentAttr, v.value); + is( + element[idlAttr], + true, + "IDL attribute should return always return 'true' if the content attribute has been set" + ); + is( + element.getAttribute(contentAttr), + v.stringified, + "Content attribute should return the stringified value it has been set to." + ); + element.removeAttribute(contentAttr); + + element[idlAttr] = v.value; + is(element[idlAttr], v.result, "IDL attribute should return " + v.result); + is( + element.getAttribute(contentAttr), + v.result ? "" : null, + v.result + ? "Content attribute should return the empty string." + : "Content attribute should return null." + ); + is( + element.hasAttribute(contentAttr), + v.result, + v.result + ? contentAttr + " should not be present" + : contentAttr + " should be present" + ); + element.removeAttribute(contentAttr); + }); + + // Tests after removeAttribute() is called. Should be equivalent with not set. + is( + element.getAttribute(contentAttr), + null, + "When not set, the content attribute should be null." + ); + is( + element[contentAttr], + false, + "When not set, the IDL attribute should return false" + ); +} + +/** + * Checks that a given attribute name for a given element is correctly reflected + * as an signed integer. + * + * @param aParameters Object object containing the parameters, which are: + * - element Element node to test on + * - attribute String name of the attribute + * - nonNegative Boolean true if the attribute is limited to 'non-negative numbers', false otherwise + * - defaultValue Integer [optional] default value, if one exists + */ +function reflectInt(aParameters) { + // Expected value returned by .getAttribute() when |value| has been previously passed to .setAttribute(). + function expectedGetAttributeResult(value) { + return String(value); + } + + function stringToInteger(value, nonNegative, defaultValue) { + // Parse: Ignore leading whitespace, find [+/-][numbers] + var result = /^[ \t\n\f\r]*([\+\-]?[0-9]+)/.exec(value); + if (result) { + var resultInt = parseInt(result[1], 10); + if ( + (nonNegative ? 0 : -0x80000000) <= resultInt && + resultInt <= 0x7fffffff + ) { + // If the value is within allowed value range for signed/unsigned + // integer, return it -- but add 0 to it to convert a possible -0 into + // +0, the only zero present in the signed integer range. + return resultInt + 0; + } + } + return defaultValue; + } + + // Expected value returned by .getAttribute(attr) or .attr if |value| has been set via the IDL attribute. + function expectedIdlAttributeResult(value) { + // This returns the result of calling the ES ToInt32 algorithm on value. + return value << 0; + } + + var element = aParameters.element; + var attr = aParameters.attribute; + var nonNegative = aParameters.nonNegative; + + var defaultValue = + aParameters.defaultValue !== undefined + ? aParameters.defaultValue + : nonNegative + ? -1 + : 0; + + ok(attr in element, attr + " should be an IDL attribute of this element"); + is( + typeof element[attr], + "number", + attr + " IDL attribute should be a number" + ); + + // Check default value. + is(element[attr], defaultValue, "default value should be " + defaultValue); + ok(!element.hasAttribute(attr), attr + " shouldn't be present"); + + /** + * Test various values. + * value: The test value that will be set using both setAttribute(value) and + * element[attr] = value + */ + var valuesToTest = [ + // Test numeric inputs up to max signed integer + 0, + 1, + 55555, + 2147483647, + +42, + // Test string inputs up to max signed integer + "0", + "1", + "777777", + "2147483647", + "+42", + // Test negative numeric inputs up to min signed integer + -0, + -1, + -3333, + -2147483648, + // Test negative string inputs up to min signed integer + "-0", + "-1", + "-222", + "-2147483647", + "-2147483648", + // Test numeric inputs that are outside legal 32 bit signed values + -2147483649, + -3000000000, + -4294967296, + 2147483649, + 4000000000, + -4294967297, + // Test string inputs with extra padding + " 1111111", + " 23456 ", + // Test non-numeric string inputs + "", + " ", + "+", + "-", + "foo", + "+foo", + "-foo", + "+ foo", + "- foo", + "+-2", + "-+2", + "++2", + "--2", + "hello1234", + "1234hello", + "444 world 555", + "why 567 what", + "-3 nots", + "2e5", + "300e2", + "42+-$", + "+42foo", + "-514not", + "\vblah", + "0x10FFFF", + "-0xABCDEF", + // Test decimal numbers + 1.2345, + 42.0, + 3456789.1, + -2.3456, + -6789.12345, + -2147483649.1234, + // Test decimal strings + "1.2345", + "42.0", + "3456789.1", + "-2.3456", + "-6789.12345", + "-2147483649.1234", + // Test special values + undefined, + null, + NaN, + Infinity, + -Infinity, + ]; + + valuesToTest.forEach(function (v) { + var intValue = stringToInteger(v, nonNegative, defaultValue); + + element.setAttribute(attr, v); + + is( + element.getAttribute(attr), + expectedGetAttributeResult(v), + element.localName + + ".setAttribute(" + + attr + + ", " + + v + + "), " + + element.localName + + ".getAttribute(" + + attr + + ") " + ); + + is( + element[attr], + intValue, + element.localName + + ".setAttribute(" + + attr + + ", " + + v + + "), " + + element.localName + + "[" + + attr + + "] " + ); + element.removeAttribute(attr); + + if (nonNegative && expectedIdlAttributeResult(v) < 0) { + try { + element[attr] = v; + ok( + false, + element.localName + + "[" + + attr + + "] = " + + v + + " should throw IndexSizeError" + ); + } catch (e) { + is( + e.name, + "IndexSizeError", + element.localName + + "[" + + attr + + "] = " + + v + + " should throw IndexSizeError" + ); + is( + e.code, + DOMException.INDEX_SIZE_ERR, + element.localName + + "[" + + attr + + "] = " + + v + + " should throw INDEX_SIZE_ERR" + ); + } + } else { + element[attr] = v; + is( + element[attr], + expectedIdlAttributeResult(v), + element.localName + + "[" + + attr + + "] = " + + v + + ", " + + element.localName + + "[" + + attr + + "] " + ); + is( + element.getAttribute(attr), + String(expectedIdlAttributeResult(v)), + element.localName + + "[" + + attr + + "] = " + + v + + ", " + + element.localName + + ".getAttribute(" + + attr + + ") " + ); + } + element.removeAttribute(attr); + }); + + // Tests after removeAttribute() is called. Should be equivalent with not set. + is( + element.getAttribute(attr), + null, + "When not set, the content attribute should be null." + ); + is( + element[attr], + defaultValue, + "When not set, the IDL attribute should return default value." + ); +} + +/** + * Checks that a given attribute is correctly reflected as a url. + * + * @param aParameters Object object containing the parameters, which are: + * - element Element node to test + * - attribute String name of the attribute + * OR + * attribute Object object containing two attributes, 'content' and 'idl' + */ +function reflectURL(aParameters) { + var element = aParameters.element; + var contentAttr = + typeof aParameters.attribute === "string" + ? aParameters.attribute + : aParameters.attribute.content; + var idlAttr = + typeof aParameters.attribute === "string" + ? aParameters.attribute + : aParameters.attribute.idl; + + element[idlAttr] = ""; + is( + element[idlAttr], + document.URL, + "Empty string should resolve to document URL" + ); +} diff --git a/dom/html/test/script_fakepath.js b/dom/html/test/script_fakepath.js new file mode 100644 index 0000000000..f95ac493d2 --- /dev/null +++ b/dom/html/test/script_fakepath.js @@ -0,0 +1,16 @@ +/* eslint-env mozilla/chrome-script */ + +// eslint-disable-next-line mozilla/reject-importGlobalProperties +Cu.importGlobalProperties(["File"]); + +addMessageListener("file.open", function (e) { + var tmpFile = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIDirectoryService) + .QueryInterface(Ci.nsIProperties) + .get("ProfD", Ci.nsIFile); + tmpFile.append("prefs.js"); + + File.createFromNsIFile(tmpFile).then(file => { + sendAsyncMessage("file.opened", { data: [file] }); + }); +}); diff --git a/dom/html/test/simpleFileOpener.js b/dom/html/test/simpleFileOpener.js new file mode 100644 index 0000000000..cb98f0c64e --- /dev/null +++ b/dom/html/test/simpleFileOpener.js @@ -0,0 +1,38 @@ +/* eslint-env mozilla/chrome-script */ + +// eslint-disable-next-line mozilla/reject-importGlobalProperties +Cu.importGlobalProperties(["File"]); + +var file; + +addMessageListener("file.open", function (stem) { + try { + if (!file) { + file = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties) + .get("TmpD", Ci.nsIFile); + file.append(stem); + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); + } + + File.createFromNsIFile(file).then(function (domFile) { + sendAsyncMessage("file.opened", { + fullPath: file.path, + leafName: file.leafName, + domFile, + }); + }); + } catch (e) { + sendAsyncMessage("fail", e.toString()); + } +}); + +addMessageListener("file.remove", function () { + try { + file.remove(/* recursive: */ false); + file = undefined; + sendAsyncMessage("file.removed", null); + } catch (e) { + sendAsyncMessage("fail", e.toString()); + } +}); diff --git a/dom/html/test/submission_flush.html b/dom/html/test/submission_flush.html new file mode 100644 index 0000000000..f70884c66a --- /dev/null +++ b/dom/html/test/submission_flush.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"/> + <title>Submission Flush Test</title> + </head> + <body> + <form id="test_form" action="post_action_page.html" target="form_target" method="POST" onsubmit="return false;"> + <button type="submit" id="submit_button">Submit</button> + </form> + <iframe name="form_target" id="test_frame"></iframe> + </body> +</html> diff --git a/dom/html/test/sw_formSubmission.js b/dom/html/test/sw_formSubmission.js new file mode 100644 index 0000000000..2e102ac74c --- /dev/null +++ b/dom/html/test/sw_formSubmission.js @@ -0,0 +1,36 @@ +/** + * We are used by test_formSubmission.html to immediately activate and start + * controlling its page. We operate in 3 modes, conveyed via ?MODE appended to + * our URL. + * + * - "no-fetch": Don't register a fetch listener so that the optimized fetch + * event bypass happens. + * - "reset-fetch": Do register a fetch listener, reset every interception. + * - "proxy-fetch": Do register a fetch listener, resolve every interception + * with fetch(event.request). + */ + +const mode = location.search.slice(1); + +// Fetch handling. +if (mode !== "no-fetch") { + addEventListener("fetch", function (event) { + if (mode === "reset-fetch") { + // Don't invoke respondWith, resetting the interception. + return; + } + if (mode === "proxy-fetch") { + // Per the spec, there's an automatic waitUntil() on this too. + event.respondWith(fetch(event.request)); + } + }); +} + +// Go straight to activation, bypassing waiting. +addEventListener("install", function (event) { + event.waitUntil(skipWaiting()); +}); +// Control the test document ASAP. +addEventListener("activate", function (event) { + event.waitUntil(clients.claim()); +}); diff --git a/dom/html/test/test_a_text.html b/dom/html/test/test_a_text.html new file mode 100644 index 0000000000..5ffc1995f8 --- /dev/null +++ b/dom/html/test/test_a_text.html @@ -0,0 +1,44 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for a.text</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> + <link rel="help" href="http://www.whatwg.org/html/#dom-a-text"/> +</head> +<body> +<div id="content"> +<a href="a">a b c</a> +<a href="b">a <!--b--> c</a> +<a href="c">a <b>b</b> c</a> +</div> +<pre id="test"> +<script> +var d = document.getElementById("content") + .appendChild(document.createElement("a")); +d.href = "d"; +d.appendChild(document.createTextNode("a ")); +d.appendChild(document.createTextNode("b ")); +d.appendChild(document.createTextNode("c ")); +var expected = ["a b c", "a c", "a b c", "a b c "]; +var list = document.getElementById("content").getElementsByTagName("a"); +for (var i = 0, il = list.length; i < il; ++i) { + is(list[i].text, list[i].textContent); + is(list[i].text, expected[i]); + + list[i].text = "x"; + is(list[i].text, "x"); + is(list[i].textContent, "x"); + is(list[i].firstChild.data, "x"); + is(list[i].childNodes.length, 1); + + list[i].textContent = "y"; + is(list[i].text, "y"); + is(list[i].textContent, "y"); + is(list[i].firstChild.data, "y"); + is(list[i].childNodes.length, 1); +} +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_allowMedia.html b/dom/html/test/test_allowMedia.html new file mode 100644 index 0000000000..46a692283a --- /dev/null +++ b/dom/html/test/test_allowMedia.html @@ -0,0 +1,97 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=759964 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 759964</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 759964 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runNextTest); + +var SJS = `${location.origin}/tests/dom/html/test/allowMedia.sjs`; +var TEST_PAGE = "data:text/html,<audio src='" + SJS + "?audio'></audio>"; + +function runNextTest() { + var test = tests.shift(); + if (!test) { + SimpleTest.finish(); + return; + } + test(); +} + +var tests = [ + + // Set allowMedia = false, load a page with <audio>, verify the <audio> + // doesn't load its source. + function basic() { + var iframe = insertIframe(); + SpecialPowers.allowMedia(iframe.contentWindow, false); + loadIframe(iframe, TEST_PAGE, function () { + verifyPass(); + iframe.remove(); + runNextTest(); + }); + }, + + // Set allowMedia = false on parent docshell, load a page with <audio> in a + // child iframe, verify the <audio> doesn't load its source. + function inherit() { + SpecialPowers.allowMedia(window, false); + + var iframe = insertIframe(); + loadIframe(iframe, TEST_PAGE, function () { + verifyPass(); + iframe.remove(); + SpecialPowers.allowMedia(window, true); + runNextTest(); + }); + }, + + // In a display:none iframe, set allowMedia = false, load a page with <audio>, + // verify the <audio> doesn't load its source. + function displayNone() { + var iframe = insertIframe(); + iframe.style.display = "none"; + SpecialPowers.allowMedia(iframe.contentWindow, false); + loadIframe(iframe, TEST_PAGE, function () { + verifyPass(); + iframe.remove(); + runNextTest(); + }); + }, +]; + +function insertIframe() { + var iframe = document.createElement("iframe"); + document.body.appendChild(iframe); + return iframe; +} + +function loadIframe(iframe, url, onDone) { + iframe.setAttribute("src", url); + iframe.addEventListener("load", onDone); +} + +function verifyPass() { + var xhr = new XMLHttpRequest(); + xhr.open("GET", SJS, false); + xhr.send(); + is(xhr.responseText, "PASS", "<audio> source should not have been loaded."); +} + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=759964">Mozilla Bug 759964</a> +<p id="display"> +</p> +</body> +</html> diff --git a/dom/html/test/test_anchor_href_cache_invalidation.html b/dom/html/test/test_anchor_href_cache_invalidation.html new file mode 100644 index 0000000000..c1a8327e62 --- /dev/null +++ b/dom/html/test/test_anchor_href_cache_invalidation.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for anchor cache invalidation</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> + <a id="x" href="http://example.com"></a> +</div> +<pre id="test"> +<script type="application/javascript"> + +is($("x").href, "http://example.com/"); +is($("x").host, "example.com"); + +$("x").href = "http://www.example.com"; + +is($("x").href, "http://www.example.com/"); +is($("x").host, "www.example.com"); + +$("x").setAttribute("href", "http://www.example.net/"); +is($("x").host, "www.example.net"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_anchor_ping.html b/dom/html/test/test_anchor_ping.html new file mode 100644 index 0000000000..513e5ee05f --- /dev/null +++ b/dom/html/test/test_anchor_ping.html @@ -0,0 +1,304 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=786347 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 786347</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 786347 **/ + +SimpleTest.waitForExplicitFinish(); + +const {NetUtil} = ChromeUtils.importESModule( + "resource://gre/modules/NetUtil.sys.mjs" +); +const {HttpServer} = ChromeUtils.importESModule( + "resource://testing-common/httpd.sys.mjs" +); + +addLoadEvent(function () { + (async function run_tests() { + while (tests.length) { + let test = tests.shift(); + info("-- running " + test.name); + await test(); + } + + SimpleTest.finish(); + })(); +}); + +let tests = [ + + // Ensure that sending pings is enabled. + function setup() { + Services.prefs.setBoolPref("browser.send_pings", true); + Services.prefs.setIntPref("browser.send_pings.max_per_link", -1); + + SimpleTest.registerCleanupFunction(() => { + Services.prefs.clearUserPref("browser.send_pings"); + Services.prefs.clearUserPref("browser.send_pings.max_per_link"); + }); + }, + + // If both the address of the document containing the hyperlink being audited + // and ping URL have the same origin then the request must include a Ping-From + // HTTP header with, as its value, the address of the document containing the + // hyperlink, and a Ping-To HTTP header with, as its value, the target URL. + // The request must not include a Referer (sic) HTTP header. + async function same_origin() { + let from = "/ping-from/" + Math.random(); + let to = "/ping-to/" + Math.random(); + let ping = "/ping/" + Math.random(); + + let base; + let server = new HttpServer(); + + // The page that contains the link. + createFromPathHandler(server, from, to, () => ping); + + // The page that the link's href points to. + let promiseHref = createToPathHandler(server, to); + + // The ping we want to receive. + let promisePing = createPingPathHandler(server, ping, () => { + return {from: base + from, to: base + to}; + }); + + // Start the server, get its base URL and run the test. + server.start(-1); + base = "http://localhost:" + server.identity.primaryPort; + navigate(base + from); + + // Wait until the target and ping url have loaded. + await Promise.all([promiseHref, promisePing]); + + // Cleanup. + await stopServer(server); + }, + + // If the origins are different, but the document containing the hyperlink + // being audited was not retrieved over an encrypted connection then the + // request must include a Referer (sic) HTTP header with, as its value, the + // address of the document containing the hyperlink, a Ping-From HTTP header + // with the same value, and a Ping-To HTTP header with, as its value, target + // URL. + async function diff_origin() { + let from = "/ping-from/" + Math.random(); + let to = "/ping-to/" + Math.random(); + let ping = "/ping/" + Math.random(); + + // We will use two servers to simulate two different origins. + let base, base2; + let server = new HttpServer(); + let server2 = new HttpServer(); + + // The page that contains the link. + createFromPathHandler(server, from, to, () => base2 + ping); + + // The page that the link's href points to. + let promiseHref = createToPathHandler(server, to); + + // Start the first server and get its base URL. + server.start(-1); + base = "http://localhost:" + server.identity.primaryPort; + + // The ping we want to receive. + let promisePing = createPingPathHandler(server2, ping, () => { + return {referrer: base + from, from: base + from, to: base + to}; + }); + + // Start the second server, get its base URL and run the test. + server2.start(-1); + base2 = "http://localhost:" + server2.identity.primaryPort; + navigate(base + from); + + // Wait until the target and ping url have loaded. + await Promise.all([promiseHref, promisePing]); + + // Cleanup. + await stopServer(server); + await stopServer(server2); + }, + + // If the origins are different and the document containing the hyperlink + // being audited was retrieved over an encrypted connection then the request + // must include a Ping-To HTTP header with, as its value, target URL. The + // request must neither include a Referer (sic) HTTP header nor include a + // Ping-From HTTP header. + async function diff_origin_secure_referrer() { + let ping = "/ping/" + Math.random(); + let server = new HttpServer(); + + // The ping we want to receive. + let promisePing = createPingPathHandler(server, ping, () => { + return {to: "https://example.com/"}; + }); + + // Start the server and run the test. + server.start(-1); + + // The referrer will be loaded using a secure channel. + navigate("https://example.com/chrome/dom/html/test/" + + "file_anchor_ping.html?" + "http://127.0.0.1:" + + server.identity.primaryPort + ping); + + // Wait until the ping has been sent. + await promisePing; + + // Cleanup. + await stopServer(server); + }, + + // Test that the <a ping> attribute is properly tokenized using ASCII white + // space characters as separators. + async function tokenize_white_space() { + let from = "/ping-from/" + Math.random(); + let to = "/ping-to/" + Math.random(); + + let base; + let server = new HttpServer(); + + let pings = [ + "/ping1/" + Math.random(), + "/ping2/" + Math.random(), + "/ping3/" + Math.random(), + "/ping4/" + Math.random() + ]; + + // The page that contains the link. + createFromPathHandler(server, from, to, () => { + return " " + pings[0] + " \r " + pings[1] + " \t " + + pings[2] + " \n " + pings[3] + " "; + }); + + // The page that the link's href points to. + let promiseHref = createToPathHandler(server, to); + + // The pings we want to receive. + let pingPathHandlers = createPingPathHandlers(server, pings, () => { + return {from: base + from, to: base + to}; + }); + + // Start the server, get its base URL and run the test. + server.start(-1); + base = "http://localhost:" + server.identity.primaryPort; + navigate(base + from); + + // Wait until the target and ping url have loaded. + await Promise.all([promiseHref, ...pingPathHandlers]); + + // Cleanup. + await stopServer(server); + } +]; + +// Navigate the iframe used for testing to a new URL. +function navigate(uri) { + document.getElementById("frame").src = uri; +} + +// Registers a path handler for the given server that will serve a page +// containing an <a ping> element. The page will automatically simulate +// clicking the link after it has loaded. +function createFromPathHandler(server, path, href, lazyPing) { + server.registerPathHandler(path, function (request, response) { + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/html;charset=utf-8", false); + response.setHeader("Cache-Control", "no-cache", false); + + let body = '<body onload="document.body.firstChild.click()">' + + '<a href="' + href + '" ping="' + lazyPing() + '"></a></body>'; + response.write(body); + }); +} + +// Registers a path handler for the given server that will serve a simple empty +// page we can use as the href attribute for links. It returns a promise that +// will be resolved once the page has been requested. +function createToPathHandler(server, path) { + return new Promise(resolve => { + + server.registerPathHandler(path, function (request, response) { + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/html;charset=utf-8", false); + response.setHeader("Cache-Control", "no-cache", false); + response.write("OK"); + + resolve(); + }); + + }); +} + +// Register multiple path handlers for the given server that will receive +// pings as sent when an <a ping> element is clicked. This method uses +// createPingPathHandler() defined below to ensure all headers are sent +// and received as expected. +function createPingPathHandlers(server, paths, lazyHeaders) { + return Array.from(paths, (path) => createPingPathHandler(server, path, lazyHeaders)); +} + +// Registers a path handler for the given server that will receive pings as +// sent when an <a ping> element has been clicked. It will check that the +// correct http method has been used, the post data is correct and all headers +// are given as expected. It returns a promise that will be resolved once the +// ping has been received. +function createPingPathHandler(server, path, lazyHeaders) { + return new Promise(resolve => { + + server.registerPathHandler(path, function (request, response) { + let headers = lazyHeaders(); + + is(request.method, "POST", "correct http method used"); + is(request.getHeader("Ping-To"), headers.to, "valid ping-to header"); + + if ("from" in headers) { + is(request.getHeader("Ping-From"), headers.from, "valid ping-from header"); + } else { + ok(!request.hasHeader("Ping-From"), "no ping-from header"); + } + + if ("referrer" in headers) { + let expectedReferrer = headers.referrer.match(/https?:\/\/[^\/]+\/?/i)[0]; + is(request.getHeader("Referer"), expectedReferrer, "valid referer header"); + } else { + ok(!request.hasHeader("Referer"), "no referer header"); + } + + let bs = request.bodyInputStream; + let body = NetUtil.readInputStreamToString(bs, bs.available()); + is(body, "PING", "correct body sent"); + + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/html;charset=utf-8", false); + response.setHeader("Cache-Control", "no-cache", false); + response.write("OK"); + + resolve(); + }); + + }); +} + +// Returns a promise that is resolved when the given http server instance has +// been stopped. +function stopServer(server) { + return new Promise(resolve => { + server.stop(resolve); + }); +} + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=786347">Mozilla Bug 786347</a> +<p id="display"></p> +<iframe id="frame" /> +</body> +</html> diff --git a/dom/html/test/test_base_attributes_reflection.html b/dom/html/test/test_base_attributes_reflection.html new file mode 100644 index 0000000000..cbb8955d5c --- /dev/null +++ b/dom/html/test/test_base_attributes_reflection.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLBaseElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLBaseElement attributes reflection **/ + +// .href is sort of like a URL reflection, but with some special rules. Watch +// out for that! +reflectURL({ + element: document.createElement("base"), + attribute: "href" +}); + +// .target +reflectString({ + element: document.createElement("base"), + attribute: "target" +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug1003539.html b/dom/html/test/test_bug1003539.html new file mode 100644 index 0000000000..cbdc1e9fbe --- /dev/null +++ b/dom/html/test/test_bug1003539.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1003539 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1003539</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 1003539 **/ +// Refering to this specification: http://www.whatwg.org/specs/web-apps/current-work/multipage/tabular-data.html#dom-table-insertrow +var tab; +tab = document.createElement("table"); +tab.createTHead(); +tab.insertRow(); +is(tab.innerHTML, '<thead></thead><tbody><tr></tr></tbody>', "Row should be inserted in the tbody."); + +tab = document.createElement("table"); +tab.createTBody(); +tab.createTBody(); +tab.insertRow(); +is(tab.innerHTML, '<tbody></tbody><tbody><tr></tr></tbody>', "Row should be inserted in the last tbody."); + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1003539">Mozilla Bug 1003539</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug100533.html b/dom/html/test/test_bug100533.html new file mode 100644 index 0000000000..29c52f4f0a --- /dev/null +++ b/dom/html/test/test_bug100533.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=100533 +--> +<head> + <title>Test for Bug 100533</title> + <script type="text/javascript" src="/MochiKit/Base.js"></script> + <script type="text/javascript" src="/MochiKit/DOM.js"></script> + <script type="text/javascript" src="/MochiKit/Style.js"></script> + <script type="text/javascript" src="/MochiKit/Signal.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=100533">Mozilla Bug 100533</a> +<p id="display"></p> +<div id="content" > + +<button id="thebutton">Test</button> +<iframe style='display: none;' src='bug100533_iframe.html' id='a'></iframe> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); + +/** Test for Bug 100533 **/ +var submitIframeForm = function() { + $('a').contentDocument.getElementById('b').submit(); +} + +submitted = function() { + ok(true, "Finished. Form submits when located in iframe set to display:none;"); + SimpleTest.finish(); +}; + +addLoadEvent(function() { + connect("thebutton", "click", submitIframeForm); + signal("thebutton", "click"); +}); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug1013316.html b/dom/html/test/test_bug1013316.html new file mode 100644 index 0000000000..fdb9e5363d --- /dev/null +++ b/dom/html/test/test_bug1013316.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1013316 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1013316</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 1013316 **/ + SimpleTest.waitForExplicitFinish(); + addLoadEvent(function() { + is(Object.keys(document.all).length, 15, "We have 15 indexed props"); + var props = Object.getOwnPropertyNames(document.all); + is(props.length, 20, "Should have five names"); + is(props[15], "display", "display first"); + is(props[16], "content", "content second"); + is(props[17], "bar", "bar third"); + is(props[18], "foo", "foo fourth"); + is(props[19], "test", "test fifth"); + + is(Object.keys(document.images).length, 2, "We have 2 indexed props"); + props = Object.getOwnPropertyNames(document.images); + is(props.length, 5, "Should have 3 names"); + is(props[2], "display", "display first on document.images"); + is(props[3], "bar", "bar second on document.images"); + is(props[4], "foo", "foo third on document.images"); + SimpleTest.finish(); + }) + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1013316">Mozilla Bug 1013316</a> +<p id="display"></p> +<div id="content" style="display: none"> + <img id="display"> + <img name="foo" id="bar"> + <div name="baz"> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug1045270.html b/dom/html/test/test_bug1045270.html new file mode 100644 index 0000000000..b0c81daf61 --- /dev/null +++ b/dom/html/test/test_bug1045270.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML> +<html> + <!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1045270 +--> + <head> + <title>Test for Bug 583514</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + </head> + <body> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1045270">Mozilla Bug 1045270</a> + <p id="display"></p> + <div id="content"> + <input type=number> + </div> + <pre id="test"> + <script type="application/javascript"> + + /** Test for Bug 1045270 **/ + + var input = document.querySelector("input"); + SimpleTest.waitForExplicitFinish(); + SimpleTest.waitForFocus(function() { + input.focus(); + input.addEventListener("input", function() { + // reframe + document.body.style.display = "none"; + document.body.style.display = ""; + document.body.offsetLeft; // flush + }); + sendString("1"); + SimpleTest.executeSoon(function() { + sendString("2"); + SimpleTest.executeSoon(function() { + is(input.value, "12", "Reframe should restore focus and selection properly"); + SimpleTest.finish(); + }); + }); + }); + + </script> + </pre> + </body> +</html> diff --git a/dom/html/test/test_bug1089326.html b/dom/html/test/test_bug1089326.html new file mode 100644 index 0000000000..fed0a467cd --- /dev/null +++ b/dom/html/test/test_bug1089326.html @@ -0,0 +1,108 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1089326 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1089326</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 1089326 **/ + function test() { + var b = document.getElementById("button"); + var b_rect = b.getBoundingClientRect(); + var a = document.getElementById("anchor"); + var a_rect = a.getBoundingClientRect(); + + is(document.elementFromPoint(b_rect.x + 1, b_rect.y + 1), b, + "Should find button when doing hit test on top of it."); + is(document.elementFromPoint(a_rect.x + 1, a_rect.y + 1), a, + "Should find anchor when doing hit test on top of it."); + + var expectedTarget; + var clickCount = 0; + var container = document.getElementById("interactiveContentContainer"); + container.addEventListener("click", function(event) { + is(event.target, expectedTarget, "Got expected click event target."); + ++clickCount; + }, true); + var i1 = document.getElementById("interactiveContent1"); + var s11 = document.getElementById("s11"); + var s12 = document.getElementById("s12"); + + var i2 = document.getElementById("interactiveContent2"); + var s21 = document.getElementById("s21"); + + expectedTarget = i1; + synthesizeMouseAtCenter(s11, { type: "mousedown" }); + synthesizeMouseAtCenter(s12, { type: "mouseup" }); + is(clickCount, 1, "Should have got a click event."); + + expectedTarget = container; + synthesizeMouseAtCenter(s11, { type: "mousedown" }); + synthesizeMouseAtCenter(s21, { type: "mouseup" }); + is(clickCount, 2, "Should not have got a click event."); + + expectedTarget = container; + synthesizeMouseAtCenter(s21, { type: "mousedown" }); + synthesizeMouseAtCenter(s11, { type: "mouseup" }); + is(clickCount, 3, "Should not have got a click event."); + + var span1 = document.getElementById("span1"); + var span2 = document.getElementById("span2"); + expectedTarget = container; + synthesizeMouseAtCenter(span1, { type: "mousedown" }); + synthesizeMouseAtCenter(span2, { type: "mouseup" }); + is(clickCount, 4, "Should not have got a click event."); + + button.addEventListener("click", function(event) { + is(event.target, expectedTarget, "Got expected click event target."); + ++clickCount; + }, true); + + expectedTarget = a; + synthesizeMouseAtCenter(a, { type: "mousedown" }); + synthesizeMouseAtCenter(a, { type: "mouseup" }); + is(clickCount, 5, "Should have got a click event."); + + expectedTarget = a; + synthesizeMouseAtCenter(b, { type: "mousedown" }); + synthesizeMouseAtCenter(b, { type: "mouseup" }); + is(clickCount, 6, "Should have got a click event."); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + SimpleTest.waitForFocus(test); + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1089326">Mozilla Bug 1089326</a> +<p id="display"></p> +<button id="button">button <a id="anchor" href="#">anchor</a>button</button> + +<div id="interactiveContentContainer"> + <a id="interactiveContent1" href="#">foo <span id="s11">s11</span><span id="s12">s12</span> bar</a> + <a id="interactiveContent2" href="#">foo <span id="s21">s21</span><span id="s22">s22</span> bar</a> + + <div> + <span> + <span id="span1">span1</span> + </span> + </div> + + <div> + <span> + <span id="span2">span2</span> + </span> + </div> +</div> + +</body> +</html> diff --git a/dom/html/test/test_bug109445.html b/dom/html/test/test_bug109445.html new file mode 100644 index 0000000000..27ffe22948 --- /dev/null +++ b/dom/html/test/test_bug109445.html @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=109445 +--> +<head> + <title>Test for Bug 109445</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=109445">Mozilla Bug 109445</a> +<p id="display"> +<map name=a> +<area shape=rect coords=25,25,75,75 href=#x> +</map> +<map id=b> +<area shape=rect coords=25,25,75,75 href=#y> +</map> +<map name=a> +<area shape=rect coords=25,25,75,75 href=#FAIL> +</map> +<map id=b> +<area shape=rect coords=25,25,75,75 href=#FAIL> +</map> + +<img usemap=#a src=image.png> +<img usemap=#b src=image.png> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 109445 **/ +SimpleTest.waitForExplicitFinish(); +var images = document.getElementsByTagName("img"); +var second = false; +onhashchange = function() { + if (!second) { + second = true; + is(location.hash, "#x", "First map"); + SimpleTest.waitForFocus(() => synthesizeMouse(images[1], 50, 50, {})); + } else { + is(location.hash, "#y", "Second map"); + SimpleTest.finish(); + } +}; +SimpleTest.waitForFocus(() => synthesizeMouse(images[0], 50, 50, {})); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug109445.xhtml b/dom/html/test/test_bug109445.xhtml new file mode 100644 index 0000000000..b1524c8ead --- /dev/null +++ b/dom/html/test/test_bug109445.xhtml @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=109445 +--> +<head> + <title>Test for Bug 109445</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=109445">Mozilla Bug 109445</a> +<p id="display"> +<map name="a"> +<area shape="rect" coords="25,25,75,75" href="#x"/> +</map> +<map id="b"> +<area shape="rect" coords="25,25,75,75" href="#y"/> +</map> +<map name="a"> +<area shape="rect" coords="25,25,75,75" href="#FAIL"/> +</map> +<map id="b"> +<area shape="rect" coords="25,25,75,75" href="#FAIL"/> +</map> + +<img usemap="#a" src="image.png"/> +<img usemap="#b" src="image.png"/> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 109445 **/ +SimpleTest.waitForExplicitFinish(); +var images = document.getElementsByTagName("img"); +var second = false; +onhashchange = function() { + if (!second) { + second = true; + is(location.hash, "#x", "First map"); + SimpleTest.waitForFocus(() => synthesizeMouse(images[1], 50, 50, {})); + } else { + is(location.hash, "#y", "Second map"); + SimpleTest.finish(); + } +}; +SimpleTest.waitForFocus(() => synthesizeMouse(images[0], 50, 50, {})); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug1146116.html b/dom/html/test/test_bug1146116.html new file mode 100644 index 0000000000..95d52af9eb --- /dev/null +++ b/dom/html/test/test_bug1146116.html @@ -0,0 +1,59 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1146116 +--> +<head> + <title>Test for Bug 1146116</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1146116">Mozilla Bug 1146116</a> +<p id="display"> + <input type="file" id="file"> +</p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +/** Test for bug 1146116 **/ + +SimpleTest.waitForExplicitFinish(); + +const helperURL = SimpleTest.getTestFileURL("simpleFileOpener.js"); +const helper = SpecialPowers.loadChromeScript(helperURL); +helper.addMessageListener("fail", function onFail(message) { + is(message, null, "chrome script failed"); + SimpleTest.finish(); +}); +helper.addMessageListener("file.opened", onFileOpened); +helper.sendAsyncMessage("file.open", "test_bug1146116.txt"); + +function getGlobal(thing) { + return SpecialPowers.unwrap(SpecialPowers.Cu.getGlobalForObject(thing)); +} + +function onFileOpened(message) { + const file = message.domFile; + const elem = document.getElementById("file"); + is(getGlobal(elem), window, + "getGlobal() works as expected"); + is(getGlobal(file), window, + "File from MessageManager is not wrapped"); + SpecialPowers.wrap(elem).mozSetFileArray([file]); + is(getGlobal(elem.files[0]), window, + "File read back from input element is not wrapped"); + helper.addMessageListener("file.removed", onFileRemoved); + helper.sendAsyncMessage("file.remove", null); +} + +function onFileRemoved() { + helper.destroy(); + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug1166138.html b/dom/html/test/test_bug1166138.html new file mode 100644 index 0000000000..5b65db6c04 --- /dev/null +++ b/dom/html/test/test_bug1166138.html @@ -0,0 +1,130 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1166138 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1166138</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1166138">Mozilla Bug 1166138</a> + <p id="display"></p> + <div id="content" style="display: none"> + </div> + + <script type="application/javascript"> + var img1x = `${location.origin}/tests/dom/html/test/file_bug1166138_1x.png`; + var img2x = `${location.origin}/tests/dom/html/test/file_bug1166138_2x.png`; + var imgdef = `${location.origin}/tests/dom/html/test/file_bug1166138_def.png`; + var onLoadCallback = null; + var done = false; + + var startPromise = new Promise((a) => { + onLoadCallback = () => { + var image = document.querySelector('img'); + // If we aren't starting at 2x scale, resize to 2x scale, and wait for a load + if (image.currentSrc != img2x) { + onLoadCallback = a; + SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 2]]}); + } else { + a(); + } + }; + }); + + // if aLoad is true, waits for a load event. Otherwise, spins the event loop twice to + // ensure that no events were queued to be fired. + function spin(aLoad) { + if (aLoad) { + return new Promise((a) => { + ok(!onLoadCallback, "Shouldn't be an existing callback"); + onLoadCallback = a; + }); + } else { + return new Promise((a) => SimpleTest.executeSoon(() => SimpleTest.executeSoon(a))); + } + } + + function onLoad() { + if (done) return; + ok(onLoadCallback, "Expected a load event"); + if (onLoadCallback) { + var cb = onLoadCallback; + onLoadCallback = null; + cb(); + } + } + + add_task(async function() { + await startPromise; + var image = document.querySelector('img'); + is(image.currentSrc, img2x, "initial scale must be 2x"); + + SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 1]]}); + await spin(true); + is(image.currentSrc, img1x, "pre-existing img tag to 1x"); + + SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 2]]}); + await spin(true); + is(image.currentSrc, img2x, "pre-existing img tag to 2x"); + + // Try removing & re-adding the image + document.body.removeChild(image); + + SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 1]]}); + await spin(false); // No load should occur because the element is unbound + + document.body.appendChild(image); + await spin(true); + is(image.currentSrc, img1x, "remove and re-add tag after changing to 1x"); + + document.body.removeChild(image); + SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 2]]}); + await spin(false); // No load should occur because the element is unbound + + document.body.appendChild(image); + await spin(true); + is(image.currentSrc, img2x, "remove and re-add tag after changing to 2x"); + + // get rid of the srcset attribute! It should become the default + image.removeAttribute('srcset'); + await spin(true); + is(image.currentSrc, imgdef, "remove srcset attribute"); + + // Setting srcset again should return it to the correct value + image.setAttribute('srcset', "file_bug1166138_1x.png 1x, file_bug1166138_2x.png 2x"); + await spin(true); + is(image.currentSrc, img2x, "restore srcset attribute"); + + // Create a new image + var newImage = document.createElement('img'); + // Switch load listening over to newImage + newImage.addEventListener('load', onLoad); + image.removeEventListener('load', onLoad); + + document.body.appendChild(newImage); + await spin(false); // no load event should fire - as the image has no attributes + is(newImage.currentSrc, "", "New element with no attributes"); + newImage.setAttribute('srcset', "file_bug1166138_1x.png 1x, file_bug1166138_2x.png 2x"); + await spin(true); + is(newImage.currentSrc, img2x, "Adding srcset attribute"); + + SpecialPowers.pushPrefEnv({'set': [['layout.css.devPixelsPerPx', 1]]}); + await spin(true); + is(newImage.currentSrc, img1x, "new image after switching to 1x"); + is(image.currentSrc, img1x, "old image after switching to 1x"); + + // Clear the listener + done = true; + }); + </script> + + <img srcset="file_bug1166138_1x.png 1x, file_bug1166138_2x.png 2x" + src="file_bug1166138_def.png" + onload="onLoad()"> + +</body> +</html> diff --git a/dom/html/test/test_bug1203668.html b/dom/html/test/test_bug1203668.html new file mode 100644 index 0000000000..41249d90ab --- /dev/null +++ b/dom/html/test/test_bug1203668.html @@ -0,0 +1,62 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1203668 +--> +<head> + <title>Test for Bug 1203668</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1203668">Mozilla Bug 1203668</a> +<p id="display"></p> +<div id="content"> + <select class="select" multiple> + <option value="foo" selected>foo</option> + <option value="bar" selected>bar</option> + </select> + <select class="select" multiple> + <option value="foo">foo</option> + <option value="bar" selected>bar</option> + </select> + <select class="select" multiple> + <option value="foo">foo</option> + <option value="bar">bar</option> + </select> + <select class="select" size=1> + <option value="foo">foo</option> + <option value="bar" selected>bar</option> + </select> + <select class="select" size=1> + <option value="foo">foo</option> + <option value="bar">bar</option> + </select> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 1203668 **/ + +SimpleTest.waitForExplicitFinish(); + +function runTest() +{ + var selects = document.querySelectorAll('.select'); + for (i=0; i < selects.length; i++) { + var select = selects[i]; + select.value = "bogus" + is(select.selectedIndex, -1, "no option is selected"); + is(select.children[0].selected, false, "first option is not selected"); + is(select.children[1].selected, false, "second option is not selected"); + } + + SimpleTest.finish(); +} + +SimpleTest.waitForFocus(runTest); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug1230665.html b/dom/html/test/test_bug1230665.html new file mode 100644 index 0000000000..cbe9c91d30 --- /dev/null +++ b/dom/html/test/test_bug1230665.html @@ -0,0 +1,46 @@ +<html> +<head> + <title>Test for Bug 1230665</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script> +SimpleTest.waitForExplicitFinish(); + +SimpleTest.waitForFocus(function() { + document.getElementById("flexbutton1").focus(); + synthesizeKey("KEY_Tab"); + var e = document.getElementById("flexbutton2"); + is(document.activeElement, e, "focus in flexbutton2 after TAB"); + + document.getElementById("gridbutton1").focus(); + synthesizeKey("KEY_Tab"); + e = document.getElementById("gridbutton2"); + is(document.activeElement, e, "focus in gridbutton2 after TAB"); + + SimpleTest.finish(); +}); + +</script> + +<div tabindex="0" style="display:flex"> + <button id="flexbutton1"></button> + text <!-- this text will force a :-moz-anonymous-flex-item frame --> + <div style=""> + <button id="flexbutton2"></button> + </div> +</div> + + +<div tabindex="0" style="display:grid"> + <button id="gridbutton1"></button> + text <!-- this text will force a :-moz-anonymous-grid-item frame --> + <div style=""> + <button id="gridbutton2"></button> + </div> +</div> + +</body> +</html> diff --git a/dom/html/test/test_bug1250401.html b/dom/html/test/test_bug1250401.html new file mode 100644 index 0000000000..d4a1073856 --- /dev/null +++ b/dom/html/test/test_bug1250401.html @@ -0,0 +1,97 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1250401 +--> +<head> + <title>Test for Bug 1250401</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1250401">Bug 1250401</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 1250401 **/ +function test_add() { + var select = document.createElement("select"); + + var g1 = document.createElement("optgroup"); + var o1 = document.createElement("option"); + g1.appendChild(o1); + select.appendChild(g1); + + var g2 = document.createElement("optgroup"); + var o2 = document.createElement("option"); + g2.appendChild(o2); + select.add(g2, 0); + + is(select.children.length, 1, "Select has 1 item"); + is(select.firstChild, g1, "First item is g1"); + is(select.firstChild.children.length, 2, "g2 has 2 children"); + is(select.firstChild.children[0], g2, "g1 has 2 children: g2"); + is(select.firstChild.children[1], o1, "g1 has 2 children: o1"); + is(o1.index, 0, "o1.index should be 0"); + is(o2.index, 0, "o2.index should be 0"); +} + +function test_append() { + var select = document.createElement("select"); + + var g1 = document.createElement("optgroup"); + var o1 = document.createElement("option"); + g1.appendChild(o1); + select.appendChild(g1); + + var g2 = document.createElement("optgroup"); + var o2 = document.createElement("option"); + g2.appendChild(o2); + g1.appendChild(g2); + + is(select.children.length, 1, "Select has 1 item"); + is(select.firstChild, g1, "First item is g1"); + is(select.firstChild.children.length, 2, "g2 has 2 children"); + is(select.firstChild.children[0], o1, "g1 has 2 children: o1"); + is(select.firstChild.children[1], g2, "g1 has 2 children: g1"); + is(o1.index, 0, "o1.index should be 0"); + is(o2.index, 0, "o2.index should be 0"); +} + +function test_no_select() { + var g1 = document.createElement("optgroup"); + var o1 = document.createElement("option"); + g1.appendChild(o1); + + var g2 = document.createElement("optgroup"); + var o2 = document.createElement("option"); + g2.appendChild(o2); + g1.appendChild(g2); + + is(g1.children.length, 2, "g2 has 2 children"); + is(g1.children[0], o1, "g1 has 2 children: o1"); + is(g1.children[1], g2, "g1 has 2 children: g1"); + is(o1.index, 0, "o1.index should be 0"); + is(o2.index, 0, "o2.index should be 0"); +} + +function test_no_parent() { + var o1 = document.createElement("option"); + var o2 = document.createElement("option"); + + is(o1.index, 0, "o1.index should be 0"); + is(o2.index, 0, "o2.index should be 0"); +} + +test_add(); +test_append(); +test_no_select(); +test_no_parent(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug1260664.html b/dom/html/test/test_bug1260664.html new file mode 100644 index 0000000000..99878a46b6 --- /dev/null +++ b/dom/html/test/test_bug1260664.html @@ -0,0 +1,51 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1260664 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1260664</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1260664">Mozilla Bug 1260664</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 1260664 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(runTests); + +function runTests() { + var elements = [ "iframe", "img", "a", "area", "link", "script"]; + + for (var i = 0; i < elements.length; ++i) { + reflectLimitedEnumerated({ + element: document.createElement(elements[i]), + attribute: { content: "referrerpolicy", idl: "referrerPolicy" }, + validValues: [ "no-referrer", + "origin", + /** These 2 below values are still invalid, please see + Bug 1178337 - Valid referrer attribute values **/ + /** "no-referrer-when-downgrade", + "origin-when-cross-origin", **/ + "unsafe-url" ], + invalidValues: [ + "", " orIgin ", " unsafe-uRl ", " No-RefeRRer ", " fOoBaR " + ], + defaultValue: "", + }); + } + + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug1260704.html b/dom/html/test/test_bug1260704.html new file mode 100644 index 0000000000..ca576051b0 --- /dev/null +++ b/dom/html/test/test_bug1260704.html @@ -0,0 +1,90 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1260704 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1260704</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="text/javascript"> + /** Test for Bug 1260704 **/ + +function runTests() { + let testIdx = -1; + let testUrls = [ + "bug1260704_iframe.html?noDefault=true&isMap=true", + "bug1260704_iframe.html?noDefault=true&isMap=false", + "bug1260704_iframe.html?noDefault=false&isMap=true", + "bug1260704_iframe.html?noDefault=false&isMap=false" + ]; + + let runningTest = false; + let iframe = document.getElementById("testFrame"); + let iframeWin = iframe.contentWindow; + let rect; + let x; + let y; + + window.addEventListener("message", event => { + if (event.data == "started") { + ok(!runningTest, "Start to test " + testIdx); + runningTest = true; + rect = iframeWin.document.getElementById("testImage").getBoundingClientRect(); + x = rect.width / 2; + y = rect.height / 2; + synthesizeMouseAtPoint(rect.left + x, rect.top + y, { type: 'mousedown' }, iframeWin); + synthesizeMouseAtPoint(rect.left + x, rect.top + y, { type: 'mouseup' }, iframeWin); + } + else if (runningTest && event.data == "empty_frame_loaded") { + ok(testUrls[testIdx].includes("noDefault=false"), "Page unload"); + let search = iframeWin.location.search; + if (testUrls[testIdx].includes("isMap=true")) { + // url trigger by image with ismap attribute should contains coordinates + // try to parse coordinates and check them with small tolerance + let coorStr = search.split("?"); + let coordinates = coorStr[1].split(","); + ok(Math.abs(coordinates[0] - x) <= 1, "expect X=" + x + " got " + coordinates[0]); + ok(Math.abs(coordinates[1] - y) <= 1, "expect Y=" + y + " got " + coordinates[1]); + } else { + ok(search == "", "expect empty search string got:" + search); + } + nextTest(); + } + else if (runningTest && event.data == "finished") { + ok(testUrls[testIdx].includes("noDefault=true"), "Page should not leave"); + nextTest(); + } + }); + + function nextTest() { + testIdx++; + runningTest = false; + if (testIdx >= testUrls.length) { + SimpleTest.finish(); + } else { + ok(true, "Test " + testIdx + " - Set url to " + testUrls[testIdx]); + iframeWin.location.href = testUrls[testIdx]; + } + } + nextTest(); +} + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(runTests); + + </script> +</head> +<body> + +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<iframe id="testFrame" src="about:blank" width="400" height="400"> +</iframe> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug1261673.html b/dom/html/test/test_bug1261673.html new file mode 100644 index 0000000000..c574967dd7 --- /dev/null +++ b/dom/html/test/test_bug1261673.html @@ -0,0 +1,72 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1261673 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1261673</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="/tests/SimpleTest/paint_listener.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1261673">Mozilla Bug 1261673</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<input id="test_number" type="number" value=5> +<script type="text/javascript"> + +/** Test for Bug 1261673 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(runTests); + +function runTests() { + let input = window.document.getElementById("test_number"); + + // focus: whether the target input element is focused + // deltaY: deltaY of WheelEvent + // deltaMode: deltaMode of WheelEvent + // valueChanged: expected value changes after input element handled the wheel event + let params = [ + {focus: true, deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_LINE, valueChanged: -1}, + {focus: true, deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_LINE, valueChanged: 1}, + {focus: true, deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_PAGE, valueChanged: -1}, + {focus: true, deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_PAGE, valueChanged: 1}, + {focus: true, deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_PIXEL, valueChanged: 0}, + {focus: true, deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_PIXEL, valueChanged: 0}, + {focus: false, deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_LINE, valueChanged: 0}, + {focus: false, deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_LINE, valueChanged: 0} + ]; + + let testIdx = 0; + let result = parseInt(input.value); + let numberChange = 0; + let expectChange = 0; + + input.addEventListener("change", () => { + ++numberChange; + }); + + function runNext() { + let p = params[testIdx]; + (p.focus) ? input.focus() : input.blur(); + expectChange = p.valueChanged == 0 ? expectChange : expectChange + 1; + result += parseInt(p.valueChanged); + sendWheelAndPaint(input, 1, 1, { deltaY: p.deltaY, deltaMode: p.deltaMode }, () => { + ok(input.value == result, + "Handle wheel in number input test-" + testIdx + " expect " + result + + " get " + input.value); + ok(numberChange == expectChange, + "UA should fire change event when input's value changed, expect " + expectChange + " get " + numberChange); + (++testIdx >= params.length) ? SimpleTest.finish() : runNext(); + }); + } + runNext(); +} + +</script> +</body> +</html> diff --git a/dom/html/test/test_bug1261674-1.html b/dom/html/test/test_bug1261674-1.html new file mode 100644 index 0000000000..a9042be733 --- /dev/null +++ b/dom/html/test/test_bug1261674-1.html @@ -0,0 +1,77 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1261674 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1261674</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="/tests/SimpleTest/paint_listener.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1261674">Mozilla Bug 1261674</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<input id="test_input" type="range" value=5 max=10 min=0> +<script type="text/javascript"> + +/** Test for Bug 1261674 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(runTests); + +function runTests() { + let input = window.document.getElementById("test_input"); + + // focus: whether the target input element is focused + // deltaY: deltaY of WheelEvent + // deltaMode: deltaMode of WheelEvent + // valueChanged: expected value changes after input element handled the wheel event + let params = [ + {focus: true, deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_LINE, valueChanged: -1}, + {focus: true, deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_LINE, valueChanged: 1}, + {focus: true, deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_PAGE, valueChanged: -1}, + {focus: true, deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_PAGE, valueChanged: 1}, + {focus: true, deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_PIXEL, valueChanged: 0}, + {focus: true, deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_PIXEL, valueChanged: 0}, + {focus: false, deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_LINE, valueChanged: 0}, + {focus: false, deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_LINE, valueChanged: 0} + ]; + + let testIdx = 0; + let result = parseInt(input.value); + let rangeChange = 0; + let expectChange = 0; + + input.addEventListener("change", () => { + ++rangeChange; + }); + + function runNext() { + let p = params[testIdx]; + (p.focus) ? input.focus() : input.blur(); + expectChange = p.valueChanged == 0 ? expectChange : expectChange + 1; + result += parseInt(p.valueChanged); + sendWheelAndPaint(input, 1, 1, { deltaY: p.deltaY, deltaMode: p.deltaMode }, () => { + ok(input.value == result, + "Handle wheel in range input test-" + testIdx + " expect " + result + " get " + input.value); + ok(rangeChange == expectChange, + "UA should fire change event when input's value changed, expect " + expectChange + " get " + rangeChange); + (++testIdx >= params.length) ? SimpleTest.finish() : runNext(); + }); + } + + input.addEventListener("input", () => { + ok(input.value == result, + "Test-" + testIdx + " receive input event, expect " + result + " get " + input.value); + }); + + runNext(); +} + +</script> +</body> +</html> diff --git a/dom/html/test/test_bug1261674-2.html b/dom/html/test/test_bug1261674-2.html new file mode 100644 index 0000000000..cfda243749 --- /dev/null +++ b/dom/html/test/test_bug1261674-2.html @@ -0,0 +1,70 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1261674 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1261674</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="/tests/SimpleTest/paint_listener.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1261674">Mozilla Bug 1261674</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<input id="test_input" type="range" max=0 min=10> +<script type="text/javascript"> + +/** Test for Bug 1261674 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(runTests); + +function runTests() { + let input = window.document.getElementById("test_input"); + + // deltaY: deltaY of WheelEvent + // deltaMode: deltaMode of WheelEvent + let params = [ + {deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_LINE}, + {deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_LINE}, + {deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_PAGE}, + {deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_PAGE}, + {deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_PIXEL}, + {deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_PIXEL}, + {deltaY: 1.0, deltaMode: WheelEvent.DOM_DELTA_LINE}, + {deltaY: -1.0, deltaMode: WheelEvent.DOM_DELTA_LINE} + ]; + + let testIdx = 0; + let result = parseInt(input.value); + let rangeChange = 0; + + input.addEventListener("change", () => { + ++rangeChange; + }); + + function runNext() { + let p = params[testIdx]; + (p.focus) ? input.focus() : input.blur(); + sendWheelAndPaint(input, 1, 1, { deltaY: p.deltaY, deltaMode: p.deltaMode }, () => { + ok(input.value == result, + "Handle wheel in range input test-" + testIdx + " expect " + result + " get " + input.value); + ok(rangeChange == 0, "Wheel event should not trigger change event when max < min"); + testIdx++; + (testIdx >= params.length) ? SimpleTest.finish() : runNext(); + }); + } + + input.addEventListener("input", () => { + ok(false, "Wheel event should be no effect to range input element with max < min"); + }); + + runNext(); +} +</script> +</body> +</html> diff --git a/dom/html/test/test_bug1264157.html b/dom/html/test/test_bug1264157.html new file mode 100644 index 0000000000..1bede807da --- /dev/null +++ b/dom/html/test/test_bug1264157.html @@ -0,0 +1,90 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=535043 +--> +<head> + <title>Test for Bug 535043</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + input { + outline: 2px solid lime; + } + input:in-range { + outline: 2px solid red; + } + input:out-of-range { + outline: 2px solid orange; + } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=535043">Mozilla Bug 535043</a> +<p id="display"></p> +<div id="content"> + +</head> +<body> + <input type="number" value=0 min=0 max=10> Active in-range + <br><br> + <input type="number" value=0 min=0 max=10 disabled> Disabled in-range + <br><br> + <input type="number" value=0 min=0 max=10 readonly> Read-only in-range + <br><br> + <input type="number" value=11 min=0 max=10> Active out-of-range + <br><br> + <input type="number" value=11 min=0 max=10 disabled> Disabled out-of-range + <br><br> + <input type="number" value=11 min=0 max=10 readonly> Read-only out-of-range +</div> +<pre id="test"> +<script> + +/** Test for Bug 1264157 **/ +SimpleTest.waitForFocus(function() { + // Check the initial values. + let active = [].slice.call(document.querySelectorAll("input:not(:disabled):not(:read-only)")); + let disabled = [].slice.call(document.querySelectorAll("input:disabled")); + let readonly = [].slice.call(document.querySelectorAll("input:read-only:not(:disabled)")); + is(active.length, 2, "Test is messed up: missing non-disabled/non-readonly inputs"); + is(disabled.length, 2, "Test is messed up: missing disabled inputs"); + is(readonly.length, 2, "Test is messed up: missing readonly inputs"); + + is(document.querySelectorAll("input:in-range").length, 1, + "Wrong number of in-range elements selected."); + is(document.querySelectorAll("input:out-of-range").length, 1, + "Wrong number of out-of-range elements selected."); + + // Dynamically change the values to see if that works too. + active[0].value = -1; + is(document.querySelectorAll("input:in-range").length, 0, + "Wrong number of in-range elements selected after value changed."); + is(document.querySelectorAll("input:out-of-range").length, 2, + "Wrong number of out-of-range elements selected after value changed."); + active[0].value = 0; + is(document.querySelectorAll("input:in-range").length, 1, + "Wrong number of in-range elements selected after value changed back."); + is(document.querySelectorAll("input:out-of-range").length, 1, + "Wrong number of out-of-range elements selected after value changed back."); + + // Dynamically change the attributes to see if that works too. + disabled.forEach(function(e) { e.removeAttribute("disabled"); }); + readonly.forEach(function(e) { e.removeAttribute("readonly"); }); + active.forEach(function(e) { e.setAttribute("readonly", true); }); + + is(document.querySelectorAll("input:in-range").length, 2, + "Wrong number of in-range elements selected after attribute changed."); + is(document.querySelectorAll("input:out-of-range").length, 2, + "Wrong number of out-of-range elements selected after attribute changed."); + + SimpleTest.finish(); +}); + +SimpleTest.waitForExplicitFinish(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug1279218.html b/dom/html/test/test_bug1279218.html new file mode 100644 index 0000000000..0d8386280d --- /dev/null +++ b/dom/html/test/test_bug1279218.html @@ -0,0 +1,23 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>Test for Bug 1279218</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <script type="text/javascript"> + function load() { + let applets = document.applets; + is(applets.length, 0, "Applet list length should be 0, even with applet tag in body"); + SimpleTest.finish(); + } + + window.onload=load; + + SimpleTest.waitForExplicitFinish(); + </script> + </head> + <body> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1279218">Mozilla Bug 1279218</a> + <applet id="applet-test"></applet> + </body> +</html> diff --git a/dom/html/test/test_bug1287321.html b/dom/html/test/test_bug1287321.html new file mode 100644 index 0000000000..142b06d104 --- /dev/null +++ b/dom/html/test/test_bug1287321.html @@ -0,0 +1,57 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1287321 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1287321</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 1287321 **/ + + function test() { + var r = document.getElementById("range"); + var rect = r.getBoundingClientRect(); + var y = parseInt((rect.height / 2)); + var movement = parseInt(rect.width / 10); + var x = movement; + synthesizeMouse(r, x, y, { type: "mousedown" }); + x += movement; + var eventCount = 0; + r.oninput = function() { + ++eventCount; + } + synthesizeMouse(r, x, y, { type: "mousemove" }); + is(eventCount, 1, "Got the expected input event"); + + x += movement; + synthesizeMouse(r, x, y, { type: "mousemove" }); + is(eventCount, 2, "Got the expected input event"); + + synthesizeMouse(r, x, y, { type: "mousemove" }); + is(eventCount, 2, "Got the expected input event"); + + x += movement; + synthesizeMouse(r, x, y, { type: "mousemove" }); + is(eventCount, 3, "Got the expected input event"); + + synthesizeMouse(r, x, y, { type: "mouseup" }); + is(eventCount, 3, "Got the expected input event"); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + SimpleTest.waitForFocus(test); + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1287321">Mozilla Bug 1287321</a> +<input type="range" id="range"> +</body> +</html> diff --git a/dom/html/test/test_bug1292522_same_domain_with_different_port_number.html b/dom/html/test/test_bug1292522_same_domain_with_different_port_number.html new file mode 100644 index 0000000000..b7a443f6a7 --- /dev/null +++ b/dom/html/test/test_bug1292522_same_domain_with_different_port_number.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1292522 +If we set domain using document.domain = "...", a page and iframe must be +treated as the same domain if they differ in port number, +e.g. test1.example.org:8000 and test2.example.org:80 are the same domain if +document.domain = "example.org". +--> +<head> + <title>Test for Bug 1292522</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> + <body> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1292522">Mozilla Bug 1292522</a> + <p id="display"></p> + + <pre id="test"> + <script class="testbody" type="text/javascript"> + + if (navigator.platform.startsWith("Linux")) { + SimpleTest.expectAssertions(0, 1); + } + SimpleTest.waitForExplicitFinish(); + window.addEventListener("message", onMessageReceived); + + var page; + + function onMessageReceived(event) + { + is(event.data, "testiframe", "Must be able to access the variable," + + " because page and iframe are the " + + "same domain."); + page.close(); + SimpleTest.finish(); + } + + page = window.open("http://test1.example.org:8000/tests/dom/html/test/bug1292522_page.html"); + </script> + </pre> + </body> +</html> diff --git a/dom/html/test/test_bug1295719_event_sequence_for_arrow_keys.html b/dom/html/test/test_bug1295719_event_sequence_for_arrow_keys.html new file mode 100644 index 0000000000..4e622391e8 --- /dev/null +++ b/dom/html/test/test_bug1295719_event_sequence_for_arrow_keys.html @@ -0,0 +1,66 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1295719 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1295719</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1295719">Mozilla Bug 1295719</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<input id="test_number" type="number" value=50> +<input id="test_range" type="range" value=50 max=100 min=0> +<script type="text/javascript"> + +/** Test for Bug 1295719 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(runTests); + +function runTests() { + let number = window.document.getElementById("test_number"); + let range = window.document.getElementById("test_range"); + let waiting_event_sequence = ["keydown", "input", "change"]; + let waiting_event_idx = 0; + waiting_event_sequence.forEach((eventType) => { + number.addEventListener(eventType, (event) => { + let waiting_event = waiting_event_sequence[waiting_event_idx]; + is(waiting_event, eventType, "Waiting " + waiting_event + " get " + eventType); + // Input element will fire input and change events when handling keypress + // with keycode=arrows. When user press and hold the keyboard, we expect + // that input element repeatedly fires "keydown"(, "keypress"), "input", and + // "change" events until user release the keyboard. Using + // waiting_event_sequence as a circular buffer and reset waiting_event_idx + // when it point to the end of buffer. + waiting_event_idx = waiting_event_idx == waiting_event_sequence.length -1 ? 0 : waiting_event_idx + 1; + }); + range.addEventListener(eventType, (event) => { + let waiting_event = waiting_event_sequence[waiting_event_idx]; + is(waiting_event, eventType, "Waiting " + waiting_event + " get " + eventType); + waiting_event_idx = waiting_event_idx == waiting_event_sequence.length - 1 ? 0 : waiting_event_idx + 1; + }); + }); + + number.focus(); + synthesizeKey("KEY_ArrowDown", {type: "keydown"}); + synthesizeKey("KEY_ArrowDown", {type: "keydown"}); + synthesizeKey("KEY_ArrowDown", {type: "keyup"}); + number.blur(); + range.focus(); + waiting_event_idx = 0; + synthesizeKey("KEY_ArrowDown", {type: "keydown"}); + synthesizeKey("KEY_ArrowDown", {type: "keydown"}); + synthesizeKey("KEY_ArrowDown", {type: "keyup"}); + + SimpleTest.finish(); +} + +</script> +</body> +</html> diff --git a/dom/html/test/test_bug1295719_event_sequence_for_number_keys.html b/dom/html/test/test_bug1295719_event_sequence_for_number_keys.html new file mode 100644 index 0000000000..f8f0537ddb --- /dev/null +++ b/dom/html/test/test_bug1295719_event_sequence_for_number_keys.html @@ -0,0 +1,65 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1295719 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1295719</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1295719">Mozilla Bug 1295719</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<input id="test_number" type="number" value=50> +<script type="text/javascript"> + +/** Test for Bug 1295719 **/ +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(runTests); + +function runTests() { + let number = window.document.getElementById("test_number"); + let waiting_event_sequence = ["keydown", "keypress", "input"]; + let change_event_of_number = 0; + let keyup_event_of_number = 0; + let waiting_event_idx = 0; + waiting_event_sequence.forEach((eventType) => { + number.addEventListener(eventType, (event) => { + let waiting_event = waiting_event_sequence[waiting_event_idx]; + is(eventType, waiting_event, "Waiting " + waiting_event + " get " + eventType); + // Input element will fire input event when handling keypress with + // keycode=numbers. When user press and hold the keyboard, we expect that + // input element repeatedly fires "keydown", "keypress", and "input" until + // user release the keyboard. Input element will fire change event when + // it's blurred. Using waiting_event_sequence as a circular buffer and + // reset waiting_event_idx when it point to the end of buffer. + waiting_event_idx = waiting_event_idx == waiting_event_sequence.length - 1 ? 0 : waiting_event_idx + 1; + }); + }); + number.addEventListener("change", (event) => { + is(keyup_event_of_number, 1, "change event should be fired after blurred"); + ++change_event_of_number; + }); + number.addEventListener("keyup", (event) => { + is(keyup_event_of_number, 0, "keyup event should be fired once"); + is(change_event_of_number, 0, "keyup event should be fired before change event"); + ++keyup_event_of_number; + }); + number.focus(); + synthesizeKey("5", {type: "keydown"}); + synthesizeKey("5", {type: "keydown"}); + synthesizeKey("5", {type: "keyup"}); + is(change_event_of_number, 0, "change event shouldn't be fired when input element is focused"); + number.blur(); + is(change_event_of_number, 1, "change event should be fired when input element is blurred"); + SimpleTest.finish(); +} + +</script> +</body> +</html> diff --git a/dom/html/test/test_bug1297.html b/dom/html/test/test_bug1297.html new file mode 100644 index 0000000000..d0c96c87d4 --- /dev/null +++ b/dom/html/test/test_bug1297.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1297 +--> +<head> + <title>Test for Bug 1297</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1297">Mozilla Bug 1297</a> +<p id="display"></p> +<div id="content" style="display: none"> +<table border=1> +<tr> +<td id="td1" onmousedown="alert(this.cellIndex)">cellIndex=0</td> +<td id="td2" onmousedown="alert(this.cellIndex)">cellIndex=1</td> +<td id="td3" onmousedown="alert(this.cellIndex)">cellIndex=2</td> +<tr id="tr1" +onmousedown="alert(this.rowIndex)"><td>rowIndex=1<td>rowIndex=1<td>rowIndex=1</t +r> +<tr id="tr2" +onmousedown="alert(this.rowIndex)"><td>rowIndex=2<td>rowIndex=2<td>rowIndex=2</t +r> +</tr> +</table> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 1297 **/ +is($('td1').cellIndex, 0, "cellIndex / rowIndex working td1"); +is($('td2').cellIndex, 1, "cellIndex / rowIndex working td2"); +is($('td3').cellIndex, 2, "cellIndex / rowIndex working td3"); +is($('tr1').rowIndex, 1, "cellIndex / rowIndex working tr1"); +is($('tr2').rowIndex, 2, "cellIndex / rowIndex working tr2"); + + + + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug1310865.html b/dom/html/test/test_bug1310865.html new file mode 100644 index 0000000000..4dcccbfa0d --- /dev/null +++ b/dom/html/test/test_bug1310865.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<title>Test for Bug 1310865</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<link rel="stylesheet" href="/tests/SimpleTest/test.css"> +<input value="a +b" type="hidden"> +<input type="hidden" value="a +b"> +<script> +var input1 = document.querySelector("input"); +var input2 = document.querySelector("input + input"); +var clone1 = input1.cloneNode(false); +var clone2 = input2.cloneNode(false); +// Newlines must not be stripped +is(clone1.value, "a\nb"); +is(clone2.value, "a\nb"); +</script> diff --git a/dom/html/test/test_bug1315146.html b/dom/html/test/test_bug1315146.html new file mode 100644 index 0000000000..0cf25b36bf --- /dev/null +++ b/dom/html/test/test_bug1315146.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1315146 +--> +<head> + <title>Test for Bug 1315146</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1315146">Mozilla Bug 1315146</a> +<p id="display"></p> +<div id="content"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 1315146 **/ + +SimpleTest.waitForExplicitFinish(); +onmessage = function(e) { + win.close(); + is(e.data.start, 2, "Correct start offset expected"); + is(e.data.end, 2, "Correct end offset expected"); + SimpleTest.finish(); +}; +let win = window.open("http://test1.example.org/tests/dom/html/test/bug1315146-main.html", "_blank"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug1322678.html b/dom/html/test/test_bug1322678.html new file mode 100644 index 0000000000..57b43f039c --- /dev/null +++ b/dom/html/test/test_bug1322678.html @@ -0,0 +1,113 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1322678 +--> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<title>Test for Bug 1322678</title> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script type="text/javascript"> + +const CUSTOM_TITLE = "Custom Title"; + +async function openNewWindowForTest() { + let win = window.open("bug369370-popup.png", "bug1322678", + "width=400,height=300,scrollbars=no"); + ok(win, "opened child window"); + + await new Promise(resolve => { + win.onload = function() { + ok(true, "window loaded"); + resolve(); + }; + }); + + return win; +} + +async function testCustomTitle(aWin, aTitle) { + let doc = aWin.document; + let elements = doc.getElementsByTagName("img"); + is(elements.length, 1, "looking for img in ImageDocument"); + let img = elements[0]; + + // Click to zoom in + synthesizeMouse(img, 25, 25, { }, aWin); + is(doc.title, aTitle, "Checking title"); + + // Click there again to zoom out + synthesizeMouse(img, 25, 25, { }, aWin); + is(doc.title, aTitle, "Checking title"); + + // Now try resizing the window so the image fits vertically and horizontally. + await new Promise(resolve => { + aWin.addEventListener("resize", function() { + // Give the image document time to respond + SimpleTest.executeSoon(function() { + is(doc.title, aTitle, "Checking title"); + resolve(); + }); + }, {once: true}); + + let decorationSize = aWin.outerHeight - aWin.innerHeight; + aWin.resizeTo(800 + 50 + decorationSize, 600 + 50 + decorationSize); + }); + + // Now try resizing the window so the image no longer fits. + await new Promise(resolve => { + aWin.addEventListener("resize", function() { + // Give the image document time to respond + SimpleTest.executeSoon(function() { + is(doc.title, aTitle, "Checking title"); + resolve(); + }); + }, {once: true}); + + aWin.resizeTo(400, 300); + }); +} + +// eslint-disable-next-line mozilla/no-addtask-setup +add_task(async function setup() { + await SpecialPowers.pushPrefEnv({"set": [ + ["browser.enable_automatic_image_resizing", true], + ]}); +}); + +add_task(async function testUpdateDocumentTitle() { + let win = await openNewWindowForTest(); + // Set custom title. + win.document.title = CUSTOM_TITLE; + await testCustomTitle(win, CUSTOM_TITLE); + win.close(); +}); + +add_task(async function testUpdateTitleElement() { + let win = await openNewWindowForTest(); + // Set custom title. + let title = win.document.getElementsByTagName("title")[0]; + title.text = CUSTOM_TITLE; + await testCustomTitle(win, CUSTOM_TITLE); + win.close(); +}); + +add_task(async function testAppendNewTitleElement() { + let win = await openNewWindowForTest(); + // Set custom title. + let doc = win.document; + doc.getElementsByTagName("title")[0].remove(); + let title = doc.createElement("title"); + title.text = CUSTOM_TITLE; + doc.head.appendChild(title); + await testCustomTitle(win, CUSTOM_TITLE); + win.close(); +}); + +</script> +</body> +</html> diff --git a/dom/html/test/test_bug1323815.html b/dom/html/test/test_bug1323815.html new file mode 100644 index 0000000000..47e223aa7b --- /dev/null +++ b/dom/html/test/test_bug1323815.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1323815 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1323815</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 1323815 **/ + +SimpleTest.waitForExplicitFinish(); +function test() { + var n = document.getElementById("number"); + var t = document.getElementById("text"); + t.focus(); + var gotBlur = false; + t.onblur = function(e) { + try { + is(e.relatedTarget.localName, "input"); + } catch(ex) { + ok(false, "Accessing properties on the relatedTarget shouldn't throw! " + ex); + } + gotBlur = true; + } + + n.focus(); + ok(gotBlur); + SimpleTest.finish(); +} + +SimpleTest.waitForFocus(test); + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1323815">Mozilla Bug 1323815</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> + +<input type="number" id="number"><input type="text" id="text"> +</body> +</html> diff --git a/dom/html/test/test_bug1366.html b/dom/html/test/test_bug1366.html new file mode 100644 index 0000000000..f29179509f --- /dev/null +++ b/dom/html/test/test_bug1366.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1366 +--> +<head> + <title>Test for Bug 1366</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1366">Mozilla Bug 1366</a> +<p id="display"></p> +<div id="content" style="display: none"> +<table id="testtable" width=150 border> + <tbody id="testbody"> + <tr> + <td>cell content</td> + </tr> + </tbody> +</table> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 1366 **/ +$('testtable').removeChild($('testbody')); +$('display').innerHTML = "SCRIPT: deleted first ROWGROUP\n"; +is($('testbody'), null, "deleting tbody works"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug1400.html b/dom/html/test/test_bug1400.html new file mode 100644 index 0000000000..38e87a56da --- /dev/null +++ b/dom/html/test/test_bug1400.html @@ -0,0 +1,42 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1400 +--> +<head> + <title>Test for Bug 1400</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1400">Mozilla Bug 1400</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 1400 **/ + +table = document.createElement("TABLE"); +thead = table.createTHead(); +thead2 = table.createTHead(); + +table.appendChild(thead); +table.appendChild(thead); +table.appendChild(thead); +table.appendChild(thead2); +table.appendChild(thead2); +table.appendChild(thead2); +table.appendChild(thead); +table.appendChild(thead2); + +is(table.childNodes.length, 1, + "adding multiple theads results in one thead child"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug1414077.html b/dom/html/test/test_bug1414077.html new file mode 100644 index 0000000000..aa430c2737 --- /dev/null +++ b/dom/html/test/test_bug1414077.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1414077 +--> +<head> +<meta charset="utf-8"> +<title>Test for Bug 1414077</title> +<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> +<script type="application/javascript"> + +/** Test for Bug 1414077 **/ + +add_task(async function() { + await SpecialPowers.pushPrefEnv({"set": [["browser.enable_automatic_image_resizing", true]]}); + + return new Promise(resolve => { + var testWin = document.querySelector("iframe"); + testWin.src = "image.png"; + testWin.onload = function() { + var testDoc = testWin.contentDocument; + + // testDoc should be a image document. + ok(testDoc.imageIsOverflowing, "image is overflowing"); + ok(testDoc.imageIsResized, "image is resized to fit visible area by default"); + + // Restore image to original size. + testDoc.restoreImage(); + ok(testDoc.imageIsOverflowing, "image is overflowing"); + ok(!testDoc.imageIsResized, "image is restored to original size"); + + // Resize the image to fit visible area + testDoc.shrinkToFit(); + ok(testDoc.imageIsOverflowing, "image is overflowing"); + ok(testDoc.imageIsResized, "image is resized to fit visible area"); + + resolve(); + }; + }) +}); + +</script> +</head> + +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1414077">Mozilla Bug 1414077</a> +<iframe width="0" height="0"></iframe> +</body> +</html> diff --git a/dom/html/test/test_bug143220.html b/dom/html/test/test_bug143220.html new file mode 100644 index 0000000000..f94ec5571e --- /dev/null +++ b/dom/html/test/test_bug143220.html @@ -0,0 +1,72 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=143220 +--> +<head> + <title>Test for Bug 143220</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=143220">Mozilla Bug 143220</a> +<p id="display"> + <input type="file" id="i1"> + <input type="file" id="i2"> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 143220 **/ +SimpleTest.waitForExplicitFinish(); +const helperURL = SimpleTest.getTestFileURL("simpleFileOpener.js"); +const helper = SpecialPowers.loadChromeScript(helperURL); +helper.addMessageListener("fail", function onFail(message) { + is(message, null, "chrome script failed"); + SimpleTest.finish(); +}); +helper.addMessageListener("file.opened", onFileOpened); +helper.sendAsyncMessage("file.open", "test_bug143220.txt"); + +function onFileOpened(message) { + const { leafName, fullPath, domFile } = message; + + function initControl1() { + SpecialPowers.wrap($("i1")).mozSetFileArray([domFile]); + } + + function initControl2() { + SpecialPowers.wrap($("i2")).mozSetFileArray([domFile]); + } + + // Check that we can't just set the value + try { + $("i1").value = fullPath; + is(0, 1, "Should have thrown exception on set!"); + } catch(e) { + is($("i1").value, "", "Shouldn't have value here"); + } + + initControl1(); + initControl2(); + + is($("i1").value, 'C:\\fakepath\\' + leafName, "Leaking full value?"); + is($("i2").value, 'C:\\fakepath\\' + leafName, "Leaking full value?"); + + helper.addMessageListener("file.removed", onFileRemoved); + helper.sendAsyncMessage("file.remove", null); +} + +function onFileRemoved() { + helper.destroy(); + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug1472426.html b/dom/html/test/test_bug1472426.html new file mode 100644 index 0000000000..6f891184b8 --- /dev/null +++ b/dom/html/test/test_bug1472426.html @@ -0,0 +1,120 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1472426 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 1472426</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 1472426 **/ + + var shadowIframe; + var targetIframe; + var form; + var sr; + + function checkMPSubmission(sub, expected, test) { + function getPropCount(o) { + var x, l = 0; + for (x in o) ++l; + return l; + } + function mpquote(s) { + return s.replace(/\r\n/g, " ") + .replace(/\r/g, " ") + .replace(/\n/g, " ") + .replace(/\"/g, "\\\""); + } + + is(sub.length, expected.length, + "Correct number of multipart items in " + test); + + if (sub.length != expected.length) { + alert(JSON.stringify(sub)); + } + + var i; + for (i = 0; i < expected.length; ++i) { + if (!("fileName" in expected[i])) { + is(sub[i].headers["Content-Disposition"], + "form-data; name=\"" + mpquote(expected[i].name) + "\"", + "Correct name in " + test); + is (getPropCount(sub[i].headers), 1, + "Wrong number of headers in " + test); + is(sub[i].body, + expected[i].value.replace(/\r\n|\r|\n/, "\r\n"), + "Correct value in " + test); + } + else { + is(sub[i].headers["Content-Disposition"], + "form-data; name=\"" + mpquote(expected[i].name) + "\"; filename=\"" + + mpquote(expected[i].fileName) + "\"", + "Correct name in " + test); + is(sub[i].headers["Content-Type"], + expected[i].contentType, + "Correct content type in " + test); + is (getPropCount(sub[i].headers), 2, + "Wrong number of headers in " + test); + is(sub[i].body, + expected[i].value, + "Correct value in " + test); + } + } + } + + function testFormSubmissionInShadowDOM() { + targetIframe = document.getElementById("target_iframe"); + shadowIframe = document.createElement("iframe"); + shadowIframe.src = "about:blank"; + shadowIframe.onload = shadowFrameCreated; + document.body.appendChild(shadowIframe); + } + + function shadowFrameCreated() { + var doc = shadowIframe.contentDocument; + var body = doc.body; + var host = doc.createElement("div"); + body.appendChild(host); + sr = host.attachShadow({ mode: "open" }); + sr.appendChild(document.getElementById('template').content.cloneNode(true)); + targetIframe.onload = checkSubmitValues; + sr.getElementById("form").submit(); + } + + function checkSubmitValues() { + submission = JSON.parse(targetIframe.contentDocument.documentElement.textContent); + var expected = [ + { name: "text", value: "textvalue" }, + { name: "hidden", value: "hiddenvalue" }, + { name: "select", value: "selectvalue" }, + { name: "textarea", value: "textareavalue" } + ]; + checkMPSubmission(submission, expected, "form submission inside shadow DOM"); + SimpleTest.finish(); + } + + window.onload = function() { + SimpleTest.waitForExplicitFinish(); + testFormSubmissionInShadowDOM(); + } + + </script> + <template id="template"> + <form action="form_submit_server.sjs" target="target_iframe" id="form" + method="POST" enctype="multipart/form-data"> + <input name="text" value="textvalue"> + <input name="hidden" value="hiddenvalue" type="hidden"> + <select name="select"><option selected>selectvalue</option></select> + <textarea name="textarea">textareavalue</textarea> + </form> + </template> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1472426">Mozilla Bug 1472426</a> +<iframe name="target_iframe" id="target_iframe"></iframe> +</body> +</html> diff --git a/dom/html/test/test_bug1682.html b/dom/html/test/test_bug1682.html new file mode 100644 index 0000000000..8a0b7abf19 --- /dev/null +++ b/dom/html/test/test_bug1682.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1682 +--> +<head> + <title>Test for Bug 1682</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1682">Mozilla Bug 1682</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 1682 **/ +var count = 1; + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function () { + is(count, 1, "onload executes once"); + ++count; +}); +addLoadEvent(SimpleTest.finish); + + + + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug1785739.html b/dom/html/test/test_bug1785739.html new file mode 100644 index 0000000000..2c87c57bd0 --- /dev/null +++ b/dom/html/test/test_bug1785739.html @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>nsFind::Find() should initialize the editor</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" href="/tests/SimpleTest/test.css"> +<input value="1abc1 + 2abc2 + 3abc3 + 4abc4 + 5abc5 + 6abc6 + 7abc7 + 8abc8 + 9abc9" id="input"> +<script> + SimpleTest.waitForExplicitFinish(); + + // The current window.find() impl does not support text controls, so import the internal component + const finder = + SpecialPowers + .Cc["@mozilla.org/typeaheadfind;1"] + .getService(SpecialPowers.Ci.nsITypeAheadFind); + + finder.init(SpecialPowers.wrap(window).docShell); + + function find() { + return finder.find( + "abc", + false, + SpecialPowers.Ci.nsITypeAheadFind.FIND_NEXT, + true); + } + + async function runTests() { + finder.find("abc", false, SpecialPowers.Ci.nsITypeAheadFind.FIND_FIRST, true); + // Wait until layout flush as the bug repro needs it + await new Promise(requestAnimationFrame); + + for (let i = 0; i < 9; i++) { + find(); + await new Promise(requestAnimationFrame); + is(input.selectionStart, (i * 19) + 1); + } + + SimpleTest.finish(); + } + window.addEventListener("load", runTests); +</script> diff --git a/dom/html/test/test_bug182279.html b/dom/html/test/test_bug182279.html new file mode 100644 index 0000000000..1421c86ee0 --- /dev/null +++ b/dom/html/test/test_bug182279.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=182279 +--> +<head> + <title>Test for Bug 182279</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=182279">Moozilla Bug 182279</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +/** Test for Bug 182279 **/ +var sel = document.createElement("select"); +var opt1 = new Option(); +var opt2 = new Option(); +var opt3 = new Option(); +opt1.value = 1; +opt2.value = 2; +opt3.value = 3; +sel.add(opt1, null); +sel.add(opt2, opt1); +sel.add(opt3); +is(sel[0], opt2, "1st item should be 2"); +is(sel[1], opt1, "2nd item should be 1"); +is(sel[2], opt3, "3rd item should be 3"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug1823.html b/dom/html/test/test_bug1823.html new file mode 100644 index 0000000000..0f42b49980 --- /dev/null +++ b/dom/html/test/test_bug1823.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1823 +--> +<head> + <title>Test for Bug 1823</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1823">Mozilla Bug 1823</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 1823 **/ +ok(!(document.location + "").includes("["), "location object has a toString()"); + + + + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug196523.html b/dom/html/test/test_bug196523.html new file mode 100644 index 0000000000..edd71247a7 --- /dev/null +++ b/dom/html/test/test_bug196523.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=196523 +--> +<head> + <title>Test for Bug 196523</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=196523">Mozilla Bug 196523</a> +<script> + var expectedMessages = 2; + SimpleTest.waitForExplicitFinish(); + window.addEventListener("message", function(e) { + --expectedMessages; + var str = e.data; + var idx = str.indexOf(';'); + var val = str.substring(0, idx); + var msg = str.substring(idx+1); + ok(val == "true", msg); + if (!expectedMessages) { SimpleTest.finish(); } + }); +</script> +<p id="display"> + <iframe src="http://test1.example.org/tests/dom/html/test/bug196523-subframe.html"></iframe> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 196523 **/ + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug199692.html b/dom/html/test/test_bug199692.html new file mode 100644 index 0000000000..0be6d7ed47 --- /dev/null +++ b/dom/html/test/test_bug199692.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=199692 +--> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <title>Test for Bug 199692</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> + <script type="text/javascript"> + SimpleTest.waitForExplicitFinish(); + + // The popup calls MochiTest methods in this window through window.opener + window.open("bug199692-popup.html", "bug199692", "width=600,height=600"); + </script> +</body> +</html> + diff --git a/dom/html/test/test_bug2082.html b/dom/html/test/test_bug2082.html new file mode 100644 index 0000000000..5c1ec8f8ec --- /dev/null +++ b/dom/html/test/test_bug2082.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=2082 +--> +<head> + <title>Test for Bug 2082</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=2082">Mozilla Bug 2082</a> +<p id="display"></p> +<div id="content" style="display: none"> +<FORM name="gui" id="gui"> +<INPUT TYPE="text" NAME="field" VALUE="some value"> +</FORM> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 2082 **/ +var guiform = document.getElementById("gui"); +ok(document.getElementById("gui").hasChildNodes(), "form elements should be treated as form's children"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug209275.xhtml b/dom/html/test/test_bug209275.xhtml new file mode 100644 index 0000000000..0cdb64ea00 --- /dev/null +++ b/dom/html/test/test_bug209275.xhtml @@ -0,0 +1,258 @@ +<!DOCTYPE html [ +<!ATTLIST foo:base + id ID #IMPLIED +> +]> +<html xmlns:foo="http://foo.com" xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=209275 +--> +<head> + <title>Test for Bug 209275</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + + <style> + @namespace svg url("http://www.w3.org/2000/svg"); + svg|a { fill:blue; } + svg|a:visited { fill:purple; } + </style> + + <!-- + base0 should be ignored because it's not in the XHTML namespace + --> + <foo:base id="base0" href="http://www.foo.com" /> + + <!-- + baseEmpty should be ignored because it has no href and never gets one. + --> + <base id="baseEmpty" /> + + <!-- + baseWrongAttrNS should be ignored because its href attribute isn't in the empty + namespace. + --> + <base id="baseWrongAttrNS" foo:href="http://foo.com" /> + + <base id="base1" /> + <base id="base2" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=209275">Mozilla Bug 209275</a> +<p id="display"> +</p> +<div id="content"> + <a href="/" id="link1">link1</a> + <div style="display:none"> + <a href="/" id="link2">link2</a> + </div> + <a href="/" id="link3" style="display:none">link3</a> + <a href="#" id="link4">link4</a> + <a href="" id="colorlink">colorlink</a> + <a href="#" id="link5">link5</a> + <iframe id="iframe"></iframe> + + <svg width="5cm" height="3cm" viewBox="0 0 5 3" version="1.1" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink"> + <a xlink:href="" id="ellipselink"> + <ellipse cx="2.5" cy="1.5" rx="2" ry="1" id="ellipse" /> + </a> + </svg> + +</div> +<pre id="test"> +<script type="text/javascript"> +<![CDATA[ + +/** Test for Bug 209275 **/ +SimpleTest.waitForExplicitFinish(); + +function link123HrefIs(href, testNum) { + is($('link1').href, href, "link1 test " + testNum); + is($('link2').href, href, "link2 test " + testNum); + is($('link3').href, href, "link3 test " + testNum); +} + +var gGen; + +function visitedDependentComputedStyle(win, elem, property) { + var utils = SpecialPowers.getDOMWindowUtils(window); + return utils.getVisitedDependentComputedStyle(elem, "", property); +} + +function getColor(elem) { + return visitedDependentComputedStyle(document.defaultView, elem, "color"); +} + +function getFill(elem) { + return visitedDependentComputedStyle(document.defaultView, elem, "fill"); +} + +function setXlinkHref(elem, href) { + elem.setAttributeNS("http://www.w3.org/1999/xlink", "href", href); +} + +function continueTest() { + gGen.next(); +} + +function* run() { + var iframe = document.getElementById("iframe"); + var iframeCw = iframe.contentWindow; + + // First, set the visited/unvisited link/ellipse colors. + const unvisitedColor = "rgb(0, 0, 238)"; + const visitedColor = "rgb(85, 26, 139)"; + const unvisitedFill = "rgb(0, 0, 255)"; + const visitedFill = "rgb(128, 0, 128)"; + + const rand = Date.now() + "-" + Math.random(); + + // Now we can start the tests in earnest. + + var loc = location; + // everything from the location up to and including the final forward slash + var path = /(.*\/)[^\/]*/.exec(location)[1]; + + // Set colorlink's href so we can check that it changes colors after we + // change the base href. + $('colorlink').href = "http://example.com/" + rand; + setXlinkHref($("ellipselink"), "http://example.com/" + rand); + + // Load http://example.com/${rand} into a new window so we can test that + // changing the document's base changes the visitedness of our links. + // + // cross-origin window.open'd windows don't fire load / error events, so we + // wait to close it until we observed the visited color. + let win = window.open("http://example.com/" + rand, "_blank"); + + // Make sure things are what as we expect them at the beginning. + link123HrefIs(`${location.origin}/`, 1); + is($('link4').href, loc + "#", "link 4 test 1"); + is($('link5').href, loc + "#", "link 5 test 1"); + + // Remove link5 from the document. We're going to test that its href changes + // properly when we change our base. + var link5 = $('link5'); + link5.remove(); + + $('base1').href = "http://example.com"; + + // Were the links' hrefs updated after the base change? + link123HrefIs("http://example.com/", 2); + is($('link4').href, "http://example.com/#", "link 4 test 2"); + is(link5.href, "http://example.com/#", "link 5 test 2"); + + // Were colorlink's color and ellipse's fill updated appropriately? + // Because link coloring is asynchronous, we wait until it is updated (or we + // timeout and fail anyway). + while (getColor($('colorlink')) != visitedColor) { + requestIdleCallback(continueTest); + yield undefined; + } + is(getColor($('colorlink')), visitedColor, + "Wrong link color after base change."); + while (getFill($('ellipselink')) != visitedFill) { + requestIdleCallback(continueTest); + yield undefined; + } + is(getFill($('ellipselink')), visitedFill, + "Wrong ellipse fill after base change."); + + win.close(); + + $('base1').href = "foo/"; + // Should be interpreted relative to current URI (not the current base), so + // base should now be http://mochi.test:8888/foo/ + + link123HrefIs(`${location.origin}/`, 3); + is($('link4').href, path + "foo/#", "link 4 test 3"); + + // Changing base2 shouldn't affect anything, because it's not the first base + // tag. + $('base2').href = "http://example.org/bar/"; + link123HrefIs(`${location.origin}/`, 4); + is($('link4').href, path + "foo/#", "link 4 test 4"); + + // If we unset base1's href attribute, the document's base should come from + // base2, whose href is http://example.org/bar/. + $('base1').removeAttribute("href"); + link123HrefIs("http://example.org/", 5); + is($('link4').href, "http://example.org/bar/#", "link 4 test 5"); + + // If we remove base1, base2 should become the first base tag, and the hrefs + // of all the links should change accordingly. + $('base1').remove(); + link123HrefIs("http://example.org/", 6); + is($('link4').href, "http://example.org/bar/#", "link 4 test 6"); + + // If we add a new base after base2, nothing should change. + var base3 = document.createElement("base"); + base3.href = "http://base3.example.org/"; + $('base2').parentNode.insertBefore(base3, $('base2').nextSibling); + link123HrefIs("http://example.org/", 7); + is($('link4').href, "http://example.org/bar/#", "link 4 test 7"); + + // But now if we add a new base before base 2, it should become the primary + // base. + var base4 = document.createElement("base"); + base4.href = "http://base4.example.org/"; + $('base2').parentNode.insertBefore(base4, $('base2')); + link123HrefIs("http://base4.example.org/", 8); + is($('link4').href, "http://base4.example.org/#", "link 4 test 8"); + + // Now if we remove all the base tags, the base should become the page's URI + // again. + $('base2').remove(); + base3.remove(); + base4.remove(); + + link123HrefIs(`${location.origin}/`, 9); + is($('link4').href, loc + "#", "link 4 test 9"); + + // Setting the href of base0 shouldn't do anything because it's not in the + // XHTML namespace. + $('base0').href = "http://bar.com"; + link123HrefIs(`${location.origin}/`, 10); + is($('link4').href, loc + "#", "link 4 test 10"); + + // We load into an iframe a document with a <base href="...">, then remove + // the document element. Then we add an <html>, <body>, and <a>, and make + // sure that the <a> is resolved relative to the page's location, not its + // original base. We do this twice, rebuilding the document in a different + // way each time. + + iframeCw.location = "file_bug209275_1.html"; + yield undefined; // wait for our child to call us back. + is(iframeCw.document.getElementById("link").href, + path + "file_bug209275_1.html#", + "Wrong href after nuking document."); + + iframeCw.location = "file_bug209275_2.html"; + yield undefined; // wait for callback from child + is(iframeCw.document.getElementById("link").href, + `${location.origin}/`, + "Wrong href after nuking document second time."); + + // Make sure that document.open() makes the document forget about any <base> + // tags it has. + iframeCw.location = "file_bug209275_3.html"; + yield undefined; // wait for callback from child + is(iframeCw.document.getElementById("link").href, + "http://mochi.test:8888/", + "Wrong href after document.open()."); + + SimpleTest.finish(); +} + +window.addEventListener("load", function() { + gGen = run(); + gGen.next(); +}); + +]]> +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug237071.html b/dom/html/test/test_bug237071.html new file mode 100644 index 0000000000..8360c1eb86 --- /dev/null +++ b/dom/html/test/test_bug237071.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=237071 +--> +<head> + <title>Test for Bug 237071</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=237071">Mozilla Bug 237071</a> +<p id="display"></p> +<div id="content" > + <ol id="theOL" start="22"> + <li id="foo" >should be 22</li> + <li id="foo23">should be 23</li> + </ol> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +/** Test for Bug 237071 **/ +is($('theOL').start, 22, "OL start attribute mapped to .start, not just text attribute"); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug242709.html b/dom/html/test/test_bug242709.html new file mode 100644 index 0000000000..7dde04713d --- /dev/null +++ b/dom/html/test/test_bug242709.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=242709 +--> +<head> + <title>Test for Bug 242709</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=242709">Mozilla Bug 242709</a> +<p id="display"></p> +<div id="content"> +<iframe src="bug242709_iframe.html" id="a"></iframe> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 242709 **/ + +SimpleTest.waitForExplicitFinish(); + +var submitted = function() { + ok(true, "Disabling button after form submission doesn't prevent submitting"); + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug24958.html b/dom/html/test/test_bug24958.html new file mode 100644 index 0000000000..a6a077aefe --- /dev/null +++ b/dom/html/test/test_bug24958.html @@ -0,0 +1,31 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=24958 +--> +<head> + <title>Test for Bug 24958</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <SCRIPT id="foo" TYPE="text/javascript">/*This space intentionally left blank*/</SCRIPT> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=24958">Mozilla Bug 24958</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 24958 **/ +is($("foo").text, "\/*This space intentionally left blank*\/", "HTMLScriptElement.text should return text") + + + + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug255820.html b/dom/html/test/test_bug255820.html new file mode 100644 index 0000000000..5de2fca7c0 --- /dev/null +++ b/dom/html/test/test_bug255820.html @@ -0,0 +1,99 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=255820 +--> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <title>Test for Bug 255820</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=255820">Mozilla Bug 255820</a> +<p id="display"> + <iframe id="f1"></iframe> + <iframe id="f2"></iframe> + <iframe id="f3"></iframe> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 255820 **/ +SimpleTest.waitForExplicitFinish(); + +is(document.characterSet, "UTF-8", + "Unexpected character set for our document"); + +var testsLeft = 3; + +function testFinished() { + --testsLeft; + if (testsLeft == 0) { + SimpleTest.finish(); + } +} + +function charsetTestFinished(id, doc, charsetTarget) { + is(doc.characterSet, charsetTarget, "Unexpected charset for subframe " + id); + testFinished(); +} + +function f3Continue() { + var doc = $("f3").contentDocument; + is(doc.defaultView.getComputedStyle(doc.body).color, "rgb(0, 180, 0)", + "Wrong color"); + charsetTestFinished('f3', doc, "UTF-8"); +} + +function runTest() { + var doc = $("f1").contentDocument; + is(doc.characterSet, "UTF-8", + "Unexpected initial character set for first frame"); + doc.open(); + doc.write('<html></html>'); + doc.close(); + charsetTestFinished("f1", doc, "UTF-8"); + + doc = $("f2").contentDocument; + is(doc.characterSet, "UTF-8", + "Unexpected initial character set for second frame"); + doc.open(); + var str = '<html><head>'; + str += '<script src="data:application/javascript,"><'+'/script>'; + str += '<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">'; + str += '</head><body>'; + str += '</body></html>'; + doc.write(str); + doc.close(); + is(doc.characterSet, "UTF-8", + "Unexpected character set for second frame after write"); + $("f2"). + setAttribute("onload", + "charsetTestFinished('f2', this.contentDocument, 'UTF-8');"); + + doc = $("f3").contentDocument; + is(doc.characterSet, "UTF-8", + "Unexpected initial character set for third frame"); + doc.open(); + var str = '<html><head>'; + str += '<style>body { color: rgb(255, 0, 0) }</style>'; + str += '<link type="text/css" rel="stylesheet" href="data:text/css, body { color: rgb(0, 180, 0) }">'; + str += '</head><body>'; + str += '</body></html>'; + doc.write(str); + doc.close(); + is(doc.characterSet, "UTF-8", + "Unexpected character set for third frame after write"); + $("f3").setAttribute("onload", "f3Continue()"); +} + +addLoadEvent(runTest); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug259332.html b/dom/html/test/test_bug259332.html new file mode 100644 index 0000000000..f41f88930c --- /dev/null +++ b/dom/html/test/test_bug259332.html @@ -0,0 +1,64 @@ +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=259332 +--> +<head> + <title>Test for Bug 259332</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=259332">Mozilla Bug 259332</a> +<p id="display"></p> +<div id="content"> + <div id="a">a + <div id="a">a</div> + <input name="a" value="a"> + <div id="b">b</div> + <input name="b" value="b"> + <div id="c">c</div> + </div> + <input name="write"> + <input name="write"> + <input id="write"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 259332 **/ + +list = document.all.a; +ok(list.length == 3, "initial a length"); + +blist = document.all.b; +ok(document.all.b.length == 2, "initial b length"); +document.getElementById('b').id = 'a'; +ok(document.all.b.nodeName == "INPUT", "just one b"); + +ok(blist.length == 1, "just one b"); +ok(list.length == 4, "one more a"); + +newDiv = document.createElement('div'); +newDiv.id = 'a'; +newDiv.innerHTML = 'a'; +list[0].appendChild(newDiv); +ok(list.length == 5, "two more a"); + +ok(document.all.c.textContent == 'c', "one c"); +document.all.c.id = 'a'; +ok(!document.all.c, "no c"); +ok(list.length == 6, "three more a"); + +ok(document.all.write.length == 3, "name is write"); + +newDiv = document.createElement('div'); +newDiv.id = 'd'; +newDiv.innerHTML = 'd'; +list[0].appendChild(newDiv); +ok(document.all.d.textContent == 'd', "new d"); + + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug274626.html b/dom/html/test/test_bug274626.html new file mode 100644 index 0000000000..6003722bef --- /dev/null +++ b/dom/html/test/test_bug274626.html @@ -0,0 +1,97 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=274626 +--> +<head> + <title>Test for Bug 274626</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=274626">Mozilla Bug 274626</a> +<br> + +<input id='textbox_enabled' title='hello' value='hello' /> +<input id='textbox_disabled' title='hello' value='hello' disabled/> + +<br> +<input id='input_button_enabled' title='hello' value='hello' type='button' /> +<input id='input_button_disabled' title='hello' value='hello' type='button' disabled /> + +<br> +<input id='checkbox_enabled' title='hello' type='checkbox'>hello</input> +<input id='checkbox_disabled' title='hello' type='checkbox' disabled >hello</input> + +<br> +<button id='button_enabled' title='hello' value='hello' type='button'>test</button> +<button id='button_disabled' title='hello' value='hello' type='button' disabled>test</button> + +<br> +<textarea id='textarea_enabled' title='hello' value='hello' onclick="alert('click event');"> </textarea> +<textarea id='textarea_disabled' title='hello' value='hello' onclick="alert('click event');" disabled></textarea> + + +<br> +<select id='select_enabled' title='hello' onclick="alert('click event');"> + <option value='item1'>item1</option> + <option value='item2'>item2</option> +</select> +<select id='select_disabled' title='hello' onclick="alert('click event');" disabled> + <option value='item1'>item1</option> + <option value='item2'>item2</option> +</select> + +<br> +<form> + <fieldset id='fieldset_enabled' title='hello' onclick="alert('click event');"> + <legend>Enabled fieldset:</legend> + Name: <input type='text' size='30' /><br /> + Email: <input type='text' size='30' /><br /> + Date of birth: <input type='text' size='10' /> + </fieldset> +</form> +<form> + <fieldset id='fieldset_disabled' title='hello' onclick="alert('click event');" disabled> + <legend>Disabled fieldset:</legend> + Name: <input type='text' size='30' /><br /> + Email: <input type='text' size='30' /><br /> + Date of birth: <input type='text' size='10' /> + </fieldset> +</form> + +<script class="testbody" type="application/javascript"> + +/** Test for Bug 274626 **/ + + function HandlesMouseMove(evt) { + evt.target.handlesMouseMove = true; + } + + var controls=["textbox_enabled","textbox_disabled", + "input_button_enabled", "input_button_disabled", "checkbox_enabled", + "checkbox_disabled", "button_enabled", "button_disabled", + "textarea_enabled", "textarea_disabled", "select_enabled", + "select_disabled", "fieldset_enabled", "fieldset_disabled"]; + + for (id of controls) { + var ctrl = document.getElementById(id); + ctrl.addEventListener('mousemove', HandlesMouseMove); + ctrl.handlesMouseMove = false; + var evt = document.createEvent("MouseEvents"); + evt.initMouseEvent("mousemove", true, true, window, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + ctrl.dispatchEvent(evt); + + // Mouse move events are what causes tooltips to show up. + // Before this fix we would not allow mouse move events to go through + // which in turn did not allow tooltips to be displayed. + // This test will ensure that all HTML elements handle mouse move events + // so that tooltips can be displayed + ok(ctrl.handlesMouseMove, "Disabled element need mouse move for tooltips"); + } + +</script> +</body> +</html> diff --git a/dom/html/test/test_bug277724.html b/dom/html/test/test_bug277724.html new file mode 100644 index 0000000000..0732a4cf9a --- /dev/null +++ b/dom/html/test/test_bug277724.html @@ -0,0 +1,141 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=277724 +--> +<head> + <title>Test for Bug 277724</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=277724">Mozilla Bug 277724</a> +<p id="display"></p> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 277724 **/ + +var childUnloaded = false; + +var nodes = [ + [ "select", HTMLSelectElement ], + [ "textarea", HTMLTextAreaElement ], + [ "text", HTMLInputElement ], + [ "password", HTMLInputElement ], + [ "checkbox", HTMLInputElement ], + [ "radio", HTMLInputElement ], + [ "image", HTMLInputElement ], + [ "submit", HTMLInputElement ], + [ "reset", HTMLInputElement ], + [ "button input", HTMLInputElement ], + [ "hidden", HTMLInputElement ], + [ "file", HTMLInputElement ], + [ "submit button", HTMLButtonElement ], + [ "reset button", HTMLButtonElement ], + [ "button", HTMLButtonElement ] +]; + +function soon(f) { + return function() { setTimeout(f, 0); } +} + +function startTest(frameid) { + is(childUnloaded, false, "Child not unloaded yet"); + + var doc = $(frameid).contentDocument; + var win = $(frameid).contentWindow; + ok(doc instanceof win.Document, "doc should be a document"); + + for (var i = 0; i < nodes.length; ++i) { + var id = nodes[i][0]; + var node = doc.getElementById(id); + ok(node instanceof win[nodes[i][1].name], id + " should be a " + nodes[i][1]); + is(node.disabled, false, "check for " + id + " state"); + node.disabled = true; + is(node.disabled, true, "check for " + id + " state change"); + } + + $(frameid).onload = soon(function() { continueTest(frameid) }); + + // Do this off a timeout so it's not treated like a replace load. + function loadBlank() { + $(frameid).contentWindow.location = "about:blank"; + } + setTimeout(loadBlank, 0); +} + +function continueTest(frameid) { + is(childUnloaded, true, "Unload handler should have fired"); + var doc = $(frameid).contentDocument; + var win = $(frameid).contentWindow; + ok(doc instanceof win.Document, "doc should be a document"); + + for (var i = 0; i < nodes.length; ++i) { + var id = nodes[i][0]; + var node = doc.getElementById(id); + ok(node === null, id + " should be null"); + } + + $(frameid).onload = soon(function() { finishTest(frameid); }); + + // Do this off a timeout too. Why, I'm not sure. Something in session + // history creates another history state if we don't. :( + function goBack() { + $(frameid).contentWindow.history.back(); + } + setTimeout(goBack, 0); +} + +// XXXbz this is a nasty hack to work around the XML content sink not being +// incremental, so that the _first_ control we test is ok but others are not. +var testIs = is; +var once = false; +function flipper(a, b, c) { + if (once) { + todo(a == b, c); + } else { + once = true; + is(a, b, c); + } +} + +function finishTest(frameid) { + var doc = $(frameid).contentDocument; + var win = $(frameid).contentWindow; + ok(doc instanceof win.Document, "doc should be a document"); + + for (var i = 0; i < nodes.length; ++i) { + var id = nodes[i][0]; + var node = doc.getElementById(id); + ok(node instanceof win[nodes[i][1].name], id + " should be a " + nodes[i][1]); + //testIs(node.disabled, true, "check for " + id + " state restore"); + } + + if (frameid == "frame2") { + SimpleTest.finish(); + } else { + childUnloaded = false; + + // XXXbz this is a nasty hack to deal with the content sink. See above. + testIs = flipper; + + $("frame2").onload = soon(function() { startTest("frame2"); }); + $("frame2").src = "bug277724_iframe2.xhtml"; + } +} + +SimpleTest.waitForExplicitFinish(); +</script> +</pre> + +<!-- Don't use display:none, since we don't support framestate restoration + without a frame tree --> +<div id="content" style="visibility: hidden"> + <iframe src="bug277724_iframe1.html" id="frame1" + onload="setTimeout(function() { startTest('frame1') }, 0)"></iframe> + <iframe src="" id="frame2"></iframe> +</div> +</body> +</html> + diff --git a/dom/html/test/test_bug277890.html b/dom/html/test/test_bug277890.html new file mode 100644 index 0000000000..69bc820880 --- /dev/null +++ b/dom/html/test/test_bug277890.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=277890 +--> +<head> + <title>Test for Bug 277890</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=277890">Mozilla Bug 277890</a> +<p id="display"></p> +<div id="content"> +<iframe src="bug277890_iframe.html" id="a"></iframe> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 277890 **/ + +SimpleTest.waitForExplicitFinish(); + +var submitted = function() { + ok(true, "Disabling button after form submission doesn't prevent submitting"); + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug287465.html b/dom/html/test/test_bug287465.html new file mode 100644 index 0000000000..bc6307423e --- /dev/null +++ b/dom/html/test/test_bug287465.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=287465 +--> +<head> + <title>Test for Bug 287465</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=287465">Mozilla Bug 287465</a> +<p id="display"></p> +<div id="content" style="display:none"> + +<iframe id="i1" srcdoc="<svg xmlns='http://www.w3.org/2000/svg'></svg>"></iframe> +<object id="o1" data="object_bug287465_o1.html"></object> +<iframe id="i2" srcdoc="<html></html>"></iframe> +<object id="o2" data="object_bug287465_o2.html"></object> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(doTest); + +function doTest() { + function checkSVGDocument(id) { + var e = document.getElementById(id); + ok(e.contentDocument != null, "check nonnull contentDocument '" + id + "'"); + is(e.contentDocument, e.getSVGDocument(), "check documents match '" + id + "'"); + } + + checkSVGDocument("o1"); + checkSVGDocument("i1"); + checkSVGDocument("o2"); + checkSVGDocument("i2"); + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug295561.html b/dom/html/test/test_bug295561.html new file mode 100644 index 0000000000..456985f731 --- /dev/null +++ b/dom/html/test/test_bug295561.html @@ -0,0 +1,86 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=295561 +--> +<head> + <title>Test for Bug 295561</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=295561">Mozilla Bug 295561</a> +<p id="display"></p> +<div id="content" style="display: none"> + +<table id="testTable"> +<thead> +<tr id="headRow"><td></td></tr> +</thead> +<tfoot> +<tr id="footRow"><td></td></tr> +</tfoot> +<tbody id="tBody" name="namedTBody"> +<tr id="trow" name="namedTRow"> +<td id="tcell" name="namedTCell"></td> +<th id="tcellh" name="namedTH"></th> +</tr> +<tr><td></td></tr> +</tbody> +<tbody id="tBody2" name="namedTBody2"> +<tr id="trow2" name="namedTRow2"> +<td id="tcell2" name="namedTCell2"></td> +<th id="tcellh2" name="namedTH2"></th> +</tr> +</table> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +function testItById(id, collection, collectionName) { + is(collection[id], $(id), + "Should be able to get by id '" + id + "' from " + collectionName + + " collection using square brackets.") + is(collection.namedItem(id), $(id), + "Should be able to get by id '" + id + "' from " + collectionName + + " collection using namedItem.") +} + +function testItByName(name, id, collection, collectionName) { + is(collection[name], $(id), + "Should be able to get by name '" + name + "' from " + collectionName + + " collection using square brackets.") + is(collection.namedItem(name), $(id), + "Should be able to get by name '" + name + "' from " + collectionName + + " collection using namedItem.") +} + +function testIt(name, id, collection, collectionName) { + testItByName(name, id, collection, collectionName); + testItById(id, collection, collectionName); +} + +var table = $("testTable") +testIt("namedTBody", "tBody", table.tBodies, "tBodies") +testIt("namedTRow", "trow", table.rows, "table rows") +testIt("namedTRow", "trow", $("tBody").rows, "tbody rows") +testIt("namedTCell", "tcell", $("trow").cells, "cells") +testIt("namedTH", "tcellh", $("trow").cells, "cells") +testIt("namedTBody2", "tBody2", table.tBodies, "tBodies") +testIt("namedTRow2", "trow2", table.rows, "table rows") +testIt("namedTRow2", "trow2", $("tBody2").rows, "tbody rows") +testIt("namedTCell2", "tcell2", $("trow2").cells, "cells") +testIt("namedTH2", "tcellh2", $("trow2").cells, "cells") +is(table.tBodies.length, 2, "Incorrect tBodies length"); +is(table.rows.length, 5, "Incorrect rows length"); +is(table.rows[0], $("headRow"), "THead row in wrong spot"); +is(table.rows[1], $("trow"), "First tbody row in wrong spot"); +is(table.rows[3], $("trow2"), "Second tbody row in wrong spot"); +is(table.rows[4], $("footRow"), "TFoot row in wrong spot"); + + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug297761.html b/dom/html/test/test_bug297761.html new file mode 100644 index 0000000000..0d4532827d --- /dev/null +++ b/dom/html/test/test_bug297761.html @@ -0,0 +1,77 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=297761 +--> +<head> + <title>Test for Bug 297761</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=297761">Mozilla Bug 297761</a> +<p id="display"></p> +<div id="content"> + <iframe src="file_bug297761.html"></iframe> + <iframe src="file_bug297761.html"></iframe> + <iframe src="file_bug297761.html"></iframe> + <iframe src="file_bug297761.html"></iframe> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 297761 **/ + +SimpleTest.waitForExplicitFinish(); + +var nbTests = 4; +var curTest = 0; + +function nextTest() +{ + if (curTest == 3) { + frames[curTest].document.forms[0].submit(); + } else { + var el = null; + if (curTest == 2) { + el = frames[curTest].document.getElementById('i'); + } else { + el = frames[curTest].document.forms[0].elements[curTest]; + } + + el.focus(); + el.click(); + } +} + +function frameLoaded(aFrame) +{ + var documentLocation = location.href.replace(/\.html.*/, "\.html"); + is(aFrame.contentWindow.location.href.replace(/\?x=0&y=0/, "?"), + documentLocation.replace(/test_bug/, "file_bug") + "?", + "form should have been submitted to the document location"); + + if (++curTest == nbTests) { + SimpleTest.finish(); + } else { + nextTest(); + } +} + +function runTest() +{ + // Initialize event handlers. + var frames = document.getElementsByTagName('iframe'); + for (var i=0; i<nbTests; ++i) { + frames[i].setAttribute('onload', "frameLoaded(this);"); + } + + nextTest(); +} + +addLoadEvent(runTest); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug300691-1.html b/dom/html/test/test_bug300691-1.html new file mode 100644 index 0000000000..44418e8f3a --- /dev/null +++ b/dom/html/test/test_bug300691-1.html @@ -0,0 +1,126 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=300691 +--> +<head> + <title>Test for Bug 300691</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=300691">Mozilla Bug 300691</a> +<p id="display"> + <textarea id="target"></textarea> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +var t = $("target"); + +// FIXME(bug 1838346): This shouldn't need to be async probably? +SimpleTest.waitForExplicitFinish(); +onload = function() { + +/** Test for Bug 300691 **/ +function valueIs(arg, reason) { + is(t.value, arg, reason); +} + +function defValueIs(arg, reason) { + is(t.defaultValue, arg, reason); +} + +valueIs("", "Nothing in the textarea"); +defValueIs("", "Nothing in the textarea 2"); + +t.appendChild(document.createTextNode("ab")); +valueIs("ab", "Appended textnode"); +defValueIs("ab", "Appended textnode 2"); + +t.firstChild.data = "abcd"; +valueIs("abcd", "Modified textnode text"); +defValueIs("abcd", "Modified textnode text 2"); + +t.appendChild(document.createTextNode("efgh")); +valueIs("abcdefgh", "Appended another textnode"); +defValueIs("abcdefgh", "Appended another textnode 2"); + +t.removeChild(t.lastChild); +valueIs("abcd", "Removed textnode"); +defValueIs("abcd", "Removed textnode 2"); + +t.appendChild(document.createTextNode("efgh")); +valueIs("abcdefgh", "Appended yet another textnode"); +defValueIs("abcdefgh", "Appended yet another textnode 2"); + +t.normalize(); +valueIs("abcdefgh", "Normalization changes nothing for the value"); +defValueIs("abcdefgh", "Normalization changes nothing for the value 2"); + +t.defaultValue = "abc"; +valueIs("abc", "Just set the default value on non-edited textarea"); +defValueIs("abc", "Just set the default value on non-edited textarea 2"); + +t.appendChild(document.createTextNode("defgh")); +valueIs("abcdefgh", "Appended another textnode again"); +defValueIs("abcdefgh", "Appended another textnode again 2"); + +t.focus(); // This puts the caret at the end of the textarea, and doing + // something like "home" in a cross-platform way is kinda hard. +sendKey("left"); +sendKey("left"); +sendKey("left"); +sendString("Test"); + +valueIs("abcdeTestfgh", "Typed 'Test' after three left-arrows starting from end"); +defValueIs("abcdefgh", "Typing 'Test' shouldn't affect default value"); + +sendKey("right"); +sendKey("right"); +sendKey("back_space"); +sendKey("back_space"); + +valueIs("abcdeTesth", + "Backspaced twice after two right-arrows starting from end of typing"); +defValueIs("abcdefgh", "Deleting shouldn't affect default value"); + +t.appendChild(document.createTextNode("ijk")); +valueIs("abcdeTesth", + "Appending textnode shouldn't affect value in edited textarea"); +defValueIs("abcdefghijk", "Appended textnode 3"); + +t.lastChild.data = "lmno"; +valueIs("abcdeTesth", + "Modifying textnode text shouldn't affect value in edited textarea"); +defValueIs("abcdefghlmno", "Modified textnode text 3"); + +t.firstChild.remove(); +valueIs("abcdeTesth", + "Removing child textnode shouldn't affect value in edited textarea"); +defValueIs("defghlmno", "Removed textnode 3"); + +t.insertBefore(document.createTextNode("abc"), t.firstChild); +valueIs("abcdeTesth", + "Inserting child textnode shouldn't affect value in edited textarea"); +defValueIs("abcdefghlmno", "Inserted a text node"); + +t.normalize(); +valueIs("abcdeTesth", "Normalization changes nothing for the value 3"); +defValueIs("abcdefghlmno", "Normalization changes nothing for the value 4"); + +t.defaultValue = "abc"; +valueIs("abcdeTesth", "Setting default value shouldn't affect edited textarea"); +defValueIs("abc", "Just set the default value textarea"); +SimpleTest.finish(); + +}; +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug300691-2.html b/dom/html/test/test_bug300691-2.html new file mode 100644 index 0000000000..0dbc5be79a --- /dev/null +++ b/dom/html/test/test_bug300691-2.html @@ -0,0 +1,142 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=300691 +--> +<head> + <title>Test for Bug 300691</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=300691">Mozilla Bug 300691</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript"> + // First, setup. We'll be toggling these variables as we go. + var test1Ran = false; + var test2Ran = false; + var test3Ran = false; + var test4Ran = false; + var test5Ran = false; + var test6Ran = false; + var test7Ran = false; + var test8Ran = false; + var test9Ran = false; + var test10Ran = false; + var test11Ran = false; + var test12Ran = false; + var test13Ran = false; + var test14aRan = false; + var test14bRan = false; + var test15aRan = false; + var test15bRan = false; +</script> +<script id="test1" type="text/javascript">test1Ran = true;</script> +<script id="test2" type="text/javascript"></script> +<script id="test3" type="text/javascript">;</script> +<script id="test4" type="text/javascript"> </script> +<script id="test5" type="text/javascript"></script> +<script id="test6" type="text/javascript"></script> +<script id="test7" type="text/javascript"></script> +<script id="test8" type="text/javascript"></script> +<script id="test9" type="text/javascript"></script> +<script id="test10" type="text/javascript" src="data:text/javascript,"> + test10Ran = true; +</script> +<script id="test11" type="text/javascript" + src="data:text/javascript,test11Ran = true"> + test11Ran = false; +</script> +<script id="test12" type="text/javascript"></script> +<script id="test13" type="text/javascript"></script> +<script id="test14" type="text/javascript"></script> +<script id="test15" type="text/javascript"></script> +<script class="testbody" type="text/javascript"> + /** Test for Bug 300691 **/ + $("test2").appendChild(document.createTextNode("test2Ran = true")); + is(test2Ran, true, "Should be 2!"); + + $("test3").appendChild(document.createTextNode("test3Ran = true")); + is(test3Ran, false, "Should have run already 3!"); + + $("test4").appendChild(document.createTextNode("test4Ran = true")); + is(test4Ran, false, "Should have run already 4!"); + + $("test5").appendChild(document.createTextNode(" ")); + $("test5").appendChild(document.createTextNode("test5Ran = true")); + is(test5Ran, false, "Should have run already 5!"); + + $("test6").appendChild(document.createTextNode(" ")); + + $("test7").appendChild(document.createTextNode("")); + + $("test8").appendChild(document.createTextNode("")); + + $("test9").appendChild(document.createTextNode("")); + + $("test12").src = "data:text/javascript,test12Ran = true;"; + is(test12Ran, false, "Not yet 12!"); + + $("test13").setAttribute("src", "data:text/javascript,test13Ran = true;"); + is(test13Ran, false, "Not yet 13!"); + + $("test14").src = "data:text/javascript,test14aRan = true;"; + $("test14").appendChild(document.createTextNode("test14bRan = true")); + is(test14aRan, false, "Not yet 14a!"); + is(test14bRan, false, "Not yet 14b!"); + + $("test15").src = "data:text/javascript,test15aRan = true;"; + $("test15").appendChild(document.createTextNode("test15bRan = true")); + $("test15").removeAttribute("src"); + is(test15aRan, false, "Not yet 15a!"); + is(test15bRan, false, "Not yet 15b!"); +</script> +<script type="text/javascript"> + // Follow up on some of those + $("test6").appendChild(document.createTextNode("test6Ran = true")); + is(test6Ran, false, "Should have run already 6!"); + + $("test7").appendChild(document.createTextNode("test7Ran = true")); + is(test7Ran, true, "Should be 7!"); + + $("test8").insertBefore(document.createTextNode("test8Ran = true"), + $("test8").firstChild); + is(test8Ran, true, "Should be 8!"); + + $("test9").firstChild.data = "test9Ran = true"; + is(test9Ran, true, "Should be 9!"); +</script> +<script type="text/javascript"> +function done() { + is(test1Ran, true, "Should have run!"); + is(test3Ran, false, "Already executed test3 script once"); + is(test4Ran, false, + "Should have executed whitespace-only script already"); + is(test5Ran, false, + "Should have executed once the whitespace node was added"); + is(test6Ran, false, + "Should have executed once the whitespace node was added 2"); + is(test10Ran, false, "Has an src; inline part shouldn't run"); + is(test11Ran, true, "Script with src should have run"); + is(test12Ran, true, "Setting src should execute script"); + is(test13Ran, true, "Setting src attribute should execute script"); + is(test14aRan, true, "src attribute takes precedence over inline content"); + is(test14bRan, false, "src attribute takes precedence over inline content 2"); + is(test15aRan, true, + "src attribute load should have started before the attribute got removed"); + is(test15bRan, false, + "src attribute still got executed, so this shouldn't have been"); + SimpleTest.finish(); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(done); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug300691-3.xhtml b/dom/html/test/test_bug300691-3.xhtml new file mode 100644 index 0000000000..788ca2160d --- /dev/null +++ b/dom/html/test/test_bug300691-3.xhtml @@ -0,0 +1,48 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=300691 +--> +<head> + <title>Test for Bug 300691</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=300691">Mozilla Bug 300691</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="text/javascript"> + // First, setup. We'll be toggling these variables as we go. + // Note that scripts don't execute immediately when you put text in them -- + // they wait for the currently-running script to finish. + var test1Ran = false; + var test2Ran = false; + var test3Ran = false; +</script> +<script id="test1" type="text/javascript">test1Ran = true;</script> +<script id="test2" type="text/javascript"></script> +<script id="test3" type="text/javascript"></script> +<script class="testbody" type="text/javascript"> +<![CDATA[ + /** Test for Bug 300691 **/ + $("test2").appendChild(document.createCDATASection("test2Ran = true")); + is(test2Ran, true, "Should be 2!"); + + $("test3").appendChild(document.createCDATASection("")); +]]> +</script> +<script type="text/javascript"> + // Follow up on some of those + $("test3").firstChild.data = "test3Ran = true"; + is(test3Ran, true, "Should be 3!"); +</script> +<script type="text/javascript"> + is(test1Ran, true, "Should have run!"); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug311681.html b/dom/html/test/test_bug311681.html new file mode 100644 index 0000000000..7c74f7664b --- /dev/null +++ b/dom/html/test/test_bug311681.html @@ -0,0 +1,99 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=311681 +--> +<head> + <title>Test for Bug 311681</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=311681">Mozilla Bug 311681</a> +<script class="testbody" type="text/javascript"> + // Setup script + SimpleTest.waitForExplicitFinish(); + + // Make sure to trigger the hashtable case by asking for enough elements + // by ID. + for (var i = 0; i < 256; ++i) { + var x = document.getElementById(i); + } + + // save off the document.getElementById function, since getting it as a + // property off the document it causes a content flush. + var fun = document.getElementById; + + // Slot for our initial element with id "content" + var testNode; + + function getCont() { + return fun.call(document, "content"); + } + + function testClone() { + // Test to make sure that if we have multiple nodes with the same ID in + // a document we don't forget about one of them when the other is + // removed. + var newParent = $("display"); + var node = testNode.cloneNode(true); + isnot(node, testNode, "Clone should be a different node"); + + newParent.appendChild(node); + + // Check what getElementById returns, no flushing + is(getCont(), node, "Should be getting new node pre-flush 1"); + + // Trigger a layout flush, just in case. + var itemHeight = newParent.offsetHeight/10; + + // Check what getElementById returns now. + is(getCont(), node, "Should be getting new node post-flush 1"); + + clear(newParent); + + // Check what getElementById returns, no flushing + is(getCont(), testNode, "Should be getting orig node pre-flush 2"); + + // Trigger a layout flush, just in case. + var itemHeight = newParent.offsetHeight/10; + + // Check what getElementById returns now. + is(getCont(), testNode, "Should be getting orig node post-flush 2"); + + node = testNode.cloneNode(true); + newParent.appendChild(node); + testNode.remove(); + + // Check what getElementById returns, no flushing + is(getCont(), node, "Should be getting clone pre-flush"); + + // Trigger a layout flush, just in case. + var itemHeight = newParent.offsetHeight/10; + + // Check what getElementById returns now. + is(getCont(), node, "Should be getting clone post-flush"); + + } + + function clear(node) { + while (node.hasChildNodes()) { + node.firstChild.remove(); + } + } + + addLoadEvent(testClone); + addLoadEvent(SimpleTest.finish); +</script> +<p id="display"></p> +<div id="content" style="display: none"> + <script class="testbody" type="text/javascript"> + testNode = fun.call(document, "content"); + isnot(testNode, null, "Should have node here"); + </script> +</div> +<pre id="test"> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug311681.xhtml b/dom/html/test/test_bug311681.xhtml new file mode 100644 index 0000000000..15019fa644 --- /dev/null +++ b/dom/html/test/test_bug311681.xhtml @@ -0,0 +1,102 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=311681 +--> +<head> + <title>Test for Bug 311681</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=311681">Mozilla Bug 311681</a> +<script class="testbody" type="text/javascript"> +<![CDATA[ + // Setup script + SimpleTest.waitForExplicitFinish(); + + // Make sure to trigger the hashtable case by asking for enough elements + // by ID. + for (var i = 0; i < 256; ++i) { + var x = document.getElementById(i); + } + + // save off the document.getElementById function, since getting it as a + // property off the document it causes a content flush. + var fun = document.getElementById; + + // Slot for our initial element with id "content" + var testNode; + + function getCont() { + return fun.call(document, "content"); + } + + function testClone() { + // Test to make sure that if we have multiple nodes with the same ID in + // a document we don't forget about one of them when the other is + // removed. + var newParent = $("display"); + var node = testNode.cloneNode(true); + isnot(node, testNode, "Clone should be a different node"); + + newParent.appendChild(node); + + // Check what getElementById returns, no flushing + is(getCont(), node, "Should be getting new node pre-flush 1"); + + // Trigger a layout flush, just in case. + var itemHeight = newParent.offsetHeight/10; + + // Check what getElementById returns now. + is(getCont(), node, "Should be getting new node post-flush 1"); + + clear(newParent); + + // Check what getElementById returns, no flushing + is(getCont(), testNode, "Should be getting orig node pre-flush 2"); + + // Trigger a layout flush, just in case. + var itemHeight = newParent.offsetHeight/10; + + // Check what getElementById returns now. + is(getCont(), testNode, "Should be getting orig node post-flush 2"); + + node = testNode.cloneNode(true); + newParent.appendChild(node); + testNode.remove(); + + // Check what getElementById returns, no flushing + is(getCont(), node, "Should be getting clone pre-flush"); + + // Trigger a layout flush, just in case. + var itemHeight = newParent.offsetHeight/10; + + // Check what getElementById returns now. + is(getCont(), node, "Should be getting clone post-flush"); + + } + + function clear(node) { + while (node.hasChildNodes()) { + node.firstChild.remove(); + } + } + + addLoadEvent(testClone); + addLoadEvent(SimpleTest.finish); +]]> +</script> +<p id="display"></p> +<div id="content" style="display: none"> + <script class="testbody" type="text/javascript"> + <![CDATA[ + testNode = fun.call(document, "content"); + ok(testNode != null, "Should have node here"); + ]]> + </script> +</div> +<pre id="test"> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug324378.html b/dom/html/test/test_bug324378.html new file mode 100644 index 0000000000..8bab3feaf4 --- /dev/null +++ b/dom/html/test/test_bug324378.html @@ -0,0 +1,76 @@ +<!DOCTYPE HTML> +<html id="a" id="b"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=324378 +--> +<head id="c" id="d"> + <head id="j" foo="k" foo="l"> + <title>Test for Bug 324378</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body id="e" id="f"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=324378">Mozilla Bug 324378</a> +<script> + var html = document.documentElement; + is(document.getElementsByTagName("html").length, 1, + "Unexpected number of htmls"); + is(document.getElementsByTagName("html")[0], html, + "Unexpected <html> element"); + is(document.getElementsByTagName("head").length, 1, + "Unexpected number of heads"); + is(html.getElementsByTagName("head").length, 1, + "Unexpected number of heads in <html>"); + is(document.getElementsByTagName("body").length, 1, + "Unexpected number of bodies"); + is(html.getElementsByTagName("body").length, 1, + "Unexpected number of bodies in <html>"); + var head = document.getElementsByTagName("head")[0]; + var body = document.getElementsByTagName("body")[0]; +</script> +<p id="display"></p> +<div id="content" style="display: none"> + <html id="g" foo="h" foo="i"> + <body id="m" foo="n" foo="o"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 324378 **/ + is(document.getElementsByTagName("html").length, 1, + "Unexpected number of htmls after additions"); + is(document.getElementsByTagName("html")[0], html, + "Unexpected <html> element"); + is(document.documentElement, html, + "Unexpected root node"); + is(document.getElementsByTagName("head").length, 1, + "Unexpected number of heads after additions"); + is(document.getElementsByTagName("head")[0], head, + "Unexpected <head> element"); + is(document.getElementsByTagName("body").length, 1, + "Unexpected number of bodies after additions"); + is(document.getElementsByTagName("body")[0], body, + "Unexpected <body> element"); + + is(html.id, "a", "Unexpected <html> id"); + is(head.id, "c", "Unexpected <head> id"); + is(body.id, "e", "Unexpected <body> id"); + is($("a"), html, "Unexpected node with id=a"); + is($("b"), null, "Unexpected node with id=b"); + is($("c"), head, "Unexpected node with id=c"); + is($("d"), null, "Unexpected node with id=d"); + is($("e"), body, "Unexpected node with id=e"); + is($("f"), null, "Unexpected node with id=f"); + is($("g"), null, "Unexpected node with id=g"); + is($("j"), null, "Unexpected node with id=j"); + is($("m"), null, "Unexpected node with id=m"); + + is(html.getAttribute("foo"), "h", "Unexpected 'foo' value on <html>"); + is(head.getAttribute("foo"), null, "Unexpected 'foo' value on <head>"); + is(body.getAttribute("foo"), "n", "Unexpected 'foo' value on <body>"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug330705-1.html b/dom/html/test/test_bug330705-1.html new file mode 100644 index 0000000000..64b6e89b29 --- /dev/null +++ b/dom/html/test/test_bug330705-1.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=330705 +--> +<head> + <title>Test for Bug 330705</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <script> + /* variable is true if the element is focused, false otherwise */ + var inputFocused = false; + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=330705">Mozilla Bug 330705</a> +<p id="display"> + <input onfocus="inputFocused = true" onblur="inputFocused = false" type="text"> + <button></button> +</p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +/** Test for Bug 330705 **/ + SimpleTest.waitForExplicitFinish(); + var isFocused = false; + + function onLoad() { + document.getElementsByTagName('input')[0].focus(); + document.getElementsByTagName('button')[0].blur(); + ok(inputFocused == true, "the input element is still focused after blur() has been called on the unfocused element"); + SimpleTest.finish(); + } + + addLoadEvent(onLoad); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug332246.html b/dom/html/test/test_bug332246.html new file mode 100644 index 0000000000..e4fbd20bec --- /dev/null +++ b/dom/html/test/test_bug332246.html @@ -0,0 +1,75 @@ +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=332246 +--> +<head> + <title>Test for Bug 332246 - scrollIntoView(false) doesn't work correctly for inline elements that wrap at multiple lines</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=332246">Mozilla Bug 332246</a> +<p id="display"></p> +<div id="content"> + +<div id="a1" style="height: 100px; width: 100px; overflow: hidden; outline:1px dotted black;"> +<div style="height: 100px"></div> +<a id="a2" href="#" style="display:block; background:yellow; height:200px;">Top</a> +<div style="height: 100px"></div> +</div> + +<div id="b1" style="height: 100px; width: 100px; overflow: hidden; outline:1px dotted black;"> +<div style="height: 100px"></div> +<div id="b2" href="#" style="border:10px solid black; background:yellow; height:200px;"></div> +<div style="height: 100px"></div> +</div> + +<br> + +<div id="c1" style="height: 100px; width: 100px; overflow: hidden; position: relative; outline:1px dotted black;"> +<div id="c2" style="border: 10px solid black; height: 200px; width: 50px; position: absolute; top: 100px;"></div> +<div style="height: 100px"></div> +</div> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 332246 **/ + +function isWithFuzz(itIs, itShouldBe, fuzz, description) { + ok(Math.abs(itIs - itShouldBe) <= fuzz, `${description} - expected a value between ${itShouldBe - fuzz} and ${itShouldBe + fuzz}, got ${itIs}`); +} + +var a1 = document.getElementById('a1'); +var a2 = document.getElementById('a2'); +isWithFuzz(a1.scrollHeight, 400, 1, "Wrong a1.scrollHeight"); +is(a1.offsetHeight, 100, "Wrong a1.offsetHeight"); +a2.scrollIntoView(true); +is(a1.scrollTop, 100, "Wrong scrollTop value after a2.scrollIntoView(true)"); +a2.scrollIntoView(false); +is(a1.scrollTop, 200, "Wrong scrollTop value after a2.scrollIntoView(false)"); + +var b1 = document.getElementById('b1'); +var b2 = document.getElementById('b2'); +isWithFuzz(b1.scrollHeight, 420, 1, "Wrong b1.scrollHeight"); +is(b1.offsetHeight, 100, "Wrong b1.offsetHeight"); +b2.scrollIntoView(true); +is(b1.scrollTop, 100, "Wrong scrollTop value after b2.scrollIntoView(true)"); +b2.scrollIntoView(false); +is(b1.scrollTop, 220, "Wrong scrollTop value after b2.scrollIntoView(false)"); + +var c1 = document.getElementById('c1'); +var c2 = document.getElementById('c2'); +isWithFuzz(c1.scrollHeight, 320, 1, "Wrong c1.scrollHeight"); +is(c1.offsetHeight, 100, "Wrong c1.offsetHeight"); +c2.scrollIntoView(true); +is(c1.scrollTop, 100, "Wrong scrollTop value after c2.scrollIntoView(true)"); +c2.scrollIntoView(false); +isWithFuzz(c1.scrollTop, 220, 1, "Wrong scrollTop value after c2.scrollIntoView(false)"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug332848.xhtml b/dom/html/test/test_bug332848.xhtml new file mode 100644 index 0000000000..a7a1950125 --- /dev/null +++ b/dom/html/test/test_bug332848.xhtml @@ -0,0 +1,86 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=332848 +--> +<head> + <title>Test for Bug 332848</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=332848">Mozilla Bug 332848</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +<![CDATA[ + +/** Test for Bug 332848 **/ + +// parseChecker will become true if we keep parsing after calling close(). +var parseChecker = false; + +function test() { + try { + document.open(); + is(0, 1, "document.open succeeded"); + } catch (e) { + is (e.name, "InvalidStateError", + "Wrong exception from document.open"); + is (e.code, DOMException.INVALID_STATE_ERR, + "Wrong exception from document.open"); + } + + try { + document.write("aaa"); + is(0, 1, "document.write succeeded"); + } catch (e) { + is (e.name, "InvalidStateError", + "Wrong exception from document.write"); + is (e.code, DOMException.INVALID_STATE_ERR, + "Wrong exception from document.write"); + } + + try { + document.writeln("aaa"); + is(0, 1, "document.write succeeded"); + } catch (e) { + is (e.name, "InvalidStateError", + "Wrong exception from document.write"); + is (e.code, DOMException.INVALID_STATE_ERR, + "Wrong exception from document.write"); + } + + try { + document.close(); + is(0, 1, "document.close succeeded"); + } catch (e) { + is (e.name, "InvalidStateError", + "Wrong exception from document.close"); + is (e.code, DOMException.INVALID_STATE_ERR, + "Wrong exception from document.close"); + } +} + +function loadTest() { + is(parseChecker, true, "Parsing stopped"); + test(); + SimpleTest.finish(); +} + +window.onload = loadTest; + +SimpleTest.waitForExplicitFinish(); + +test(); +]]> +</script> +<script> + parseChecker = true; +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug332893-1.html b/dom/html/test/test_bug332893-1.html new file mode 100644 index 0000000000..552da95c28 --- /dev/null +++ b/dom/html/test/test_bug332893-1.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> + +<form id="form1"> + <input id="F1I1" type="input" value="11"/> + <input id="F1I2" type="input" value="12"/> +</form> +<form id="form2"> + <input id="F2I1" type="input" value="21"/> + <input id="F2I2" type="input" value="22"/> +</form> +<script> +<!-- Create a new input, add it to the first form, move it to the 2nd form, then move it back to the first --> + var form1 = document.getElementById("form1"); + var form2 = document.getElementById("form2"); + var newInput = document.createElement("input"); + newInput.value = "13"; + form1.insertBefore(newInput, form1.firstChild); + var F2I2 = document.getElementById("F2I2"); + form2.insertBefore(newInput, F2I2); + form1.insertBefore(newInput, form1.firstChild); + + is(form1.elements.length, 3, "Form 1 has the correct length"); + is(form1.elements[0].value, "13", "Form 1 element 1 is correct"); + is(form1.elements[1].value, "11", "Form 1 element 2 is correct"); + is(form1.elements[2].value, "12", "Form 1 element 3 is correct"); + + is(form2.elements.length, 2, "Form 2 has the correct length"); + is(form2.elements[0].value, "21", "Form 2 element 1 is correct"); + is(form2.elements[1].value, "22", "Form 2 element 2 is correct"); +</script> +</body> +</html> diff --git a/dom/html/test/test_bug332893-2.html b/dom/html/test/test_bug332893-2.html new file mode 100644 index 0000000000..d24b746566 --- /dev/null +++ b/dom/html/test/test_bug332893-2.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> + + +<form id="form1"> + <table> + <tbody id="table1"> + <tr id="F1I0"><td><input form='form1' type="input" value="10"/></td></tr> + <tr id="F1I1"><td><input type="input" value="11"/></td></tr> + <tr id="F1I2"><td><input type="input" value="12"/></td></tr> + </tbody> + </table> +</form> +<form id="form2"> + <table> + <tbody id="table2"> + <tr id="F2I1"><td><input type="input" value="21"/></td></tr> + <tr id="F2I2"><td><input type="input" value="22"/></td></tr> + </tbody> + </table> +</form> + +<script> + var table1 = document.getElementById("table1"); + var F1I0 = table1.getElementsByTagName("tr")[0]; + var F1I1 = table1.getElementsByTagName("tr")[1]; + table1.removeChild(F1I0); + table1.removeChild(F1I1); + + var table2 = document.getElementById("table2"); + table2.insertBefore(F1I0, table2.firstChild); + table2.insertBefore(F1I1, table2.firstChild); + + var form1 = document.getElementById("form1"); + var form2 = document.getElementById("form2"); + + is(form1.elements.length, 2, "Form 1 length is correct"); + is(form1.elements[0].value, "12", "Form 1 first element is correct"); + is(form1.elements[1].value, "10", "Form 2 second element is correct"); + is(form2.elements.length, 3, "Form 2 length is correct"); + is(form2.elements[0].value, "11", "Form 2 element 1 is correct"); + is(form2.elements[1].value, "21", "Form 2 element 2 is correct"); + is(form2.elements[2].value, "22", "Form 2 element 3 is correct"); + +</script> + +</body> +</html> diff --git a/dom/html/test/test_bug332893-3.html b/dom/html/test/test_bug332893-3.html new file mode 100644 index 0000000000..247607dcb2 --- /dev/null +++ b/dom/html/test/test_bug332893-3.html @@ -0,0 +1,58 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> +<form id="form1"> + <table> + <tbody> + <tr> + <td> + <table> + <tbody id="table1"> + <tr id="F1I0"><td><input form='form1' type="input" value="10"/></td></tr> + <tr id="F1I1"><td><input type="input" value="11"/></td></tr> + <tr id="F1I2"><td><input type="input" value="12"/></td></tr> + </tbody> + </table> + </td> + </tr> + </tbody> + </table> +</form> +<form id="form2"> + <table> + <tbody id="table2"> + <tr id="F2I1"><td><input type="input" value="21"/></td></tr> + <tr id="F2I2"><td><input type="input" value="22"/></td></tr> + </tbody> + </table> +</form> + +<script> + var table1 = document.getElementById("table1"); + var F1I0 = table1.getElementsByTagName("tr")[0]; + var F1I1 = table1.getElementsByTagName("tr")[1]; + table1.removeChild(F1I0); + table1.removeChild(F1I1); + + var table2 = document.getElementById("table2"); + table2.insertBefore(F1I0, table2.firstChild); + table2.insertBefore(F1I1, table2.firstChild); + + var form1 = document.getElementById("form1"); + var form2 = document.getElementById("form2"); + + is(form1.elements.length, 2, "Form 1 has the correct length"); + is(form1.elements[0].value, "12", "Form 1 element 1 is correct"); + is(form1.elements[1].value, "10", "Form 1 element 2 is correct"); + + is(form2.elements.length, 3, "Form 2 has the correct length"); + is(form2.elements[0].value, "11", "Form 2 element 1 is correct"); + is(form2.elements[1].value, "21", "Form 2 element 2 is correct"); + is(form2.elements[2].value, "22", "Form 2 element 2 is correct"); +</script> +</body> +</html> diff --git a/dom/html/test/test_bug332893-4.html b/dom/html/test/test_bug332893-4.html new file mode 100644 index 0000000000..72a0239a5d --- /dev/null +++ b/dom/html/test/test_bug332893-4.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> +<form id="form1"> + <input id="input1" type="input" name="input" value="1"/> + <input id="input2" type="input" name="input" value="2"/> + <input id="input3" type="input" name="input" value="3"/> +</form> +<script> + var input1 = document.getElementById("input1"); + var input2 = document.getElementById("input2"); + var form1 = document.getElementById("form1"); + form1.insertBefore(input2, input1); + + is(form1.elements.input.length, 3, "Form 1 'input' has the correct length"); + is(form1.elements.input[0].value, "2", "Form 1 element 1 is correct"); + is(form1.elements.input[1].value, "1", "Form 1 element 2 is correct"); + is(form1.elements.input[2].value, "3", "Form 1 element 3 is correct"); + + is(form1.elements.input[0].id, "input2", "Form 1 element 1 id is correct"); + is(form1.elements.input[1].id, "input1", "Form 1 element 2 id is correct"); + is(form1.elements.input[2].id, "input3", "Form 1 element 3 id is correct"); +</script> +</body> +</html> diff --git a/dom/html/test/test_bug332893-5.html b/dom/html/test/test_bug332893-5.html new file mode 100644 index 0000000000..e5fb9b94d6 --- /dev/null +++ b/dom/html/test/test_bug332893-5.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> +<form id="form1"> + <input id="input1" type="input" name="input" value="1"/> + <input id="input" type="input" name="input_other" value="2"/> + <input id="input3" type="input" name="input" value="3"/> +</form> +<script> + var input1 = document.getElementById("input1"); + var input2 = document.getElementById("input"); + var form1 = document.getElementById("form1"); + form1.insertBefore(input2, input1); + + is(form1.elements.input.length, 3, "Form 1 'input' has the correct length"); + is(form1.elements.input[0].value, "2", "Form 1 element 1 is correct"); + is(form1.elements.input[1].value, "1", "Form 1 element 2 is correct"); + is(form1.elements.input[2].value, "3", "Form 1 element 3 is correct"); + + is(form1.elements.input[0].id, "input", "Form 1 element 1 id is correct"); + is(form1.elements.input[1].id, "input1", "Form 1 element 2 id is correct"); + is(form1.elements.input[2].id, "input3", "Form 1 element 3 id is correct"); +</script> +</body> +</html> diff --git a/dom/html/test/test_bug332893-6.html b/dom/html/test/test_bug332893-6.html new file mode 100644 index 0000000000..b12e7a0c3a --- /dev/null +++ b/dom/html/test/test_bug332893-6.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> +<form id="form1"> + <input id="input1" type="input" name="input" value="1"/> + <input id="input" type="input" name="input_other" value="2"/> + <input id="input3" type="input" name="input" value="3"/> +</form> +<script> + var input1 = document.getElementById("input1"); + var input2 = document.getElementById("input"); + var form1 = document.getElementById("form1"); + form1.insertBefore(input2, input1); + + is(form1.elements.input.length, 3, "Form 1 'input' has the correct length"); + is(form1.elements.input[0].value, "2", "Form 1 element 1 is correct"); + is(form1.elements.input[1].value, "1", "Form 1 element 2 is correct"); + + is(form1.elements.input[0].id, "input", "Form 1 element 1 id is correct"); + is(form1.elements.input[1].id, "input1", "Form 1 element 2 id is correct"); +</script> +</body> +</html> diff --git a/dom/html/test/test_bug332893-7.html b/dom/html/test/test_bug332893-7.html new file mode 100644 index 0000000000..15672d2d20 --- /dev/null +++ b/dom/html/test/test_bug332893-7.html @@ -0,0 +1,69 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> +<form id="form1"> + <input id="input1" type="input" name="input" value="1"/> + <input id="input2" type="input" name="input" value="2"/> + <input id="input3" type="input" name="input" value="3"/> + <input id="input4" type="input" name="input" value="4"/> + <input id="input5" type="input" name="input" value="5"/> + <input id="input6" type="input" name="input" value="6"/> + <input id="input7" type="input" name="input" value="7"/> + <input id="input8" type="input" name="input" value="8"/> + <input id="input9" type="input" name="input" value="9"/> + <input id="input10" type="input" name="input" value="10"/> + + + + +</form> +<script> + var input1 = document.getElementById("input1"); + var input2 = document.getElementById("input2"); + var input3 = document.getElementById("input3"); + var input4 = document.getElementById("input4"); + var input5 = document.getElementById("input5"); + var input6 = document.getElementById("input6"); + var input7 = document.getElementById("input7"); + var input8 = document.getElementById("input8"); + var input9 = document.getElementById("input9"); + var input10 = document.getElementById("input10"); + + + var form1 = document.getElementById("form1"); + + form1.insertBefore(input2, input1); + form1.insertBefore(input10, input6); + form1.insertBefore(input8, input4); + form1.insertBefore(input9, input2); + + is(form1.elements.input.length, 10, "Form 1 'input' has the correct length"); + is(form1.elements.input[0].value, "9", "Form 1 element 1 is correct"); + is(form1.elements.input[1].value, "2", "Form 1 element 2 is correct"); + is(form1.elements.input[2].value, "1", "Form 1 element 3 is correct"); + is(form1.elements.input[3].value, "3", "Form 1 element 4 is correct"); + is(form1.elements.input[4].value, "8", "Form 1 element 5 is correct"); + is(form1.elements.input[5].value, "4", "Form 1 element 6 is correct"); + is(form1.elements.input[6].value, "5", "Form 1 element 7 is correct"); + is(form1.elements.input[7].value, "10", "Form 1 element 8 is correct"); + is(form1.elements.input[8].value, "6", "Form 1 element 9 is correct"); + is(form1.elements.input[9].value, "7", "Form 1 element 10 is correct"); + + is(form1.elements.input[0].id, "input9", "Form 1 element 1 id is correct"); + is(form1.elements.input[1].id, "input2", "Form 1 element 2 id is correct"); + is(form1.elements.input[2].id, "input1", "Form 1 element 3 id is correct"); + is(form1.elements.input[3].id, "input3", "Form 1 element 4 id is correct"); + is(form1.elements.input[4].id, "input8", "Form 1 element 5 id is correct"); + is(form1.elements.input[5].id, "input4", "Form 1 element 6 id is correct"); + is(form1.elements.input[6].id, "input5", "Form 1 element 7 id is correct"); + is(form1.elements.input[7].id, "input10", "Form 1 element 8 id is correct"); + is(form1.elements.input[8].id, "input6", "Form 1 element 9 id is correct"); + is(form1.elements.input[9].id, "input7", "Form 1 element 10 id is correct"); + +</script> +</body> +</html> diff --git a/dom/html/test/test_bug3348.html b/dom/html/test/test_bug3348.html new file mode 100644 index 0000000000..a0f99d9c43 --- /dev/null +++ b/dom/html/test/test_bug3348.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=3348 +--> +<head> + <title>Test for Bug 3348</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=3348">Mozilla Bug 3348</a> +<p id="display"></p> +<div id="content" style="display: none"> + +<form id="form1"> +<input type="button" value="click here" onclick="buttonClick();"> +</form> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 3348 **/ + +var oForm = document.getElementById("form1"); +is(oForm.tagName, "FORM", "tagName of HTML element gives tag in upper case"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug340017.xhtml b/dom/html/test/test_bug340017.xhtml new file mode 100644 index 0000000000..69de021e41 --- /dev/null +++ b/dom/html/test/test_bug340017.xhtml @@ -0,0 +1,27 @@ +<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=340017
+-->
+<head>
+ <title>Test for Bug 340017</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=340017">Mozilla Bug 340017</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+ <form id="frmfoo" name="foo" action="" />
+</div>
+<pre id="test">
+<script type="application/javascript">
+<![CDATA[
+
+/** Test for Bug 340017 **/
+is(document.foo, document.getElementById("frmfoo"),
+ "The form with name 'foo' should be a document accessible property");
+]]>
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/html/test/test_bug340800.html b/dom/html/test/test_bug340800.html new file mode 100644 index 0000000000..bcb5b2de08 --- /dev/null +++ b/dom/html/test/test_bug340800.html @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=340800 +--> +<head> + <title>Test for Bug 340800</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=340800">Mozilla Bug 340800</a> +<p id="display"></p> +<div id="content" style="display: none"> + <h1>iframe text/plain as DOM test</h1> + + <div> + + <iframe name="iframe1" width="100%" height="200" + src="bug340800_iframe.txt"></iframe> + </div> + + <div> + <h2>textarea with iframe content</h2> + <textarea rows="10" cols="80" id="textarea1"></textarea> + </div> + + <div> + <h2>div with white-space: pre and iframe content</h2> + <div id="div1"></div> + </div> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 340800 **/ +function populateIframes () { + var iframe, iframeBody; + if ((iframe = window.frames.iframe1) && (iframeBody = iframe.document.body)) { + $('div1').innerHTML = iframeBody.innerHTML; + $('textarea1').value = iframeBody.innerHTML; + } + is($('div1').firstChild.tagName, "PRE", "innerHTML from txt iframe works with div"); + ok($('textarea1').value.indexOf("<pre>") > -1, "innerHTML from txt iframe works with textarea.value"); + SimpleTest.finish(); +} + +addLoadEvent(populateIframes); +SimpleTest.waitForExplicitFinish(); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug347174.html b/dom/html/test/test_bug347174.html new file mode 100644 index 0000000000..a453627f06 --- /dev/null +++ b/dom/html/test/test_bug347174.html @@ -0,0 +1,64 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=347174 +--> +<head> + <title>Test for Bug 347174</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=347174">Mozilla Bug 347174</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 347174 **/ +// simple test of readyState during loading, DOMContentLoaded, and complete +// this test passes in IE7 +window.readyStateText = []; +window.readyStateText.push("script tag: " + document.readyState); +is(document.readyState, "loading", "document.readyState should be 'loading' when scripts runs initially"); + +function attachCustomEventListener(element, eventName, command) { + if (window.addEventListener && !window.opera) + element.addEventListener(eventName, command, true); + else if (window.attachEvent) + element.attachEvent("on" + eventName, command); +} + +function showMessage(msg) { + window.readyStateText.push(msg); + document.getElementById("display").innerHTML = readyStateText.join("<br>"); +} + +function load() { + is(document.readyState, "complete", "document.readyState should be 'complete' on load"); + showMessage("load: " + document.readyState); + SimpleTest.finish(); +} + +function readyStateChange() { + showMessage("readyStateChange: " + document.readyState); +} + +function DOMContentLoaded() { + is(document.readyState, "interactive", "document.readyState should be 'interactive' on DOMContentLoaded"); + showMessage("DOMContentLoaded: " + document.readyState); +} + +window.onload=load; + +attachCustomEventListener(document, "readystatechange", readyStateChange); +attachCustomEventListener(document, "DOMContentLoaded", DOMContentLoaded); + +SimpleTest.waitForExplicitFinish(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug347174_write.html b/dom/html/test/test_bug347174_write.html new file mode 100644 index 0000000000..75912b59a9 --- /dev/null +++ b/dom/html/test/test_bug347174_write.html @@ -0,0 +1,71 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=347174 +--> +<head> + <title>Test for Bug 347174</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=347174">Mozilla Bug 347174</a> +<p id="display"></p> + +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 347174 **/ +// simple test of readyState during loading, DOMContentLoaded, and complete +// this test passes in IE7 +window.readyStateText = []; +window.loaded = false; +function attachCustomEventListener(element, eventName, command) { + if (window.addEventListener && !window.opera) + element.addEventListener(eventName, command, true); + else if (window.attachEvent) + element.attachEvent("on" + eventName, command); +} + +function showMessage(msg) { + window.readyStateText.push(msg); + document.getElementById("display").innerHTML = readyStateText.join("<br>"); +} + +function frameLoad() { + var doc = $('iframe').contentWindow.document; + is(doc.readyState, "complete", "frame document.readyState should be 'complete' on load"); + showMessage("frame load: " + doc.readyState); + if (window.loaded) SimpleTest.finish(); +} + +function load() { + window.loaded = true; + + var imgsrc = "<img onload ='window.parent.imgLoad()' src='image.png?noCache=" + + (new Date().getTime()) + "'>\n"; + var doc = $('iframe').contentWindow.document; + doc.writeln(imgsrc); + doc.close(); + showMessage("frame after document.write: " + doc.readyState); + isnot(doc.readyState, "complete", "frame document.readyState should not be 'complete' after document.write"); +} + +function imgLoad() { + var doc = $('iframe').contentWindow.document; + showMessage("frame after imgLoad: " + doc.readyState); + is(doc.readyState, "interactive", "frame document.readyState should still be 'interactive' after img loads"); +} + +window.onload=load; + +SimpleTest.waitForExplicitFinish(); + +</script> +</pre> +<iframe src="404doesnotexist" id="iframe" onload="frameLoad();"></iframe> +</body> +</html> diff --git a/dom/html/test/test_bug347174_xsl.html b/dom/html/test/test_bug347174_xsl.html new file mode 100644 index 0000000000..e396e8b721 --- /dev/null +++ b/dom/html/test/test_bug347174_xsl.html @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=347174 +--> +<head> + <title>Test for Bug 347174</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=347174">Mozilla Bug 347174</a> +<p id="display"></p> +<div id="content" style="display: none"> + <iframe src="347174transformable.xml" id="iframe"></iframe> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 347174 **/ +// Test of readyState of XML document transformed via XSLT to HTML +// this test passes in IE7 +window.readyStateText = []; + +function showMessage(msg) { + window.readyStateText.push(msg); + document.getElementById("display").innerHTML = readyStateText.join("<br>"); +} + +function frameScriptTag(readyState) { + isnot(readyState, "complete", "document.readyState should not be 'complete' when scripts run initially"); + showMessage("script tag: " + readyState); +} + +function frameLoad(readyState) { + is(readyState, "complete", "document.readyState should be 'complete' on load"); + showMessage("load: " + readyState); + SimpleTest.finish(); +} + +function frameReadyStateChange(readyState) { + showMessage("readyStateChange: " + readyState); +} + +function frameDOMContentLoaded(readyState) { + is(readyState, "interactive", "document.readyState should be 'interactive' on DOMContentLoaded"); + showMessage("DOMContentLoaded: " + readyState); +} + +SimpleTest.waitForExplicitFinish(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug347174_xslp.html b/dom/html/test/test_bug347174_xslp.html new file mode 100644 index 0000000000..313e96d1d0 --- /dev/null +++ b/dom/html/test/test_bug347174_xslp.html @@ -0,0 +1,61 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=347174 +--> +<head> + <title>Test for Bug 347174</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> + +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=347174">Mozilla Bug 347174</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 347174 **/ +// verifies that documents created with createDocument are born in "complete" state +// (so we don't accidentally leave them in "interactive" state) +window.readyStateText = []; + +function runTest() { + var xhr = new XMLHttpRequest(); + xhr.responseType = "document"; + xhr.open("GET", "347174transform.xsl"); + xhr.send(); + xhr.onload = function() { + var xslDoc = xhr.responseXML.documentElement; + + var processor = new XSLTProcessor(); + processor.importStylesheet(xslDoc); + + window.transformedDoc = processor.transformToDocument(xmlDoc); + + showMessage("loaded: " + xmlDoc.readyState); + is(xmlDoc.readyState, "complete", "XML document.readyState should be 'complete' after transform"); + SimpleTest.finish(); + }; +} + +var xmlDoc = document.implementation.createDocument("", "test", null); +showMessage("createDocument: " + xmlDoc.readyState); +is(xmlDoc.readyState, "complete", "created document readyState should be 'complete' before being associated with a parser"); + +runTest(); + +function showMessage(msg) { + window.readyStateText.push(msg); + $("display").innerHTML = readyStateText.join("<br>"); +} + +SimpleTest.waitForExplicitFinish(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug353415-1.html b/dom/html/test/test_bug353415-1.html new file mode 100644 index 0000000000..5cb93e0577 --- /dev/null +++ b/dom/html/test/test_bug353415-1.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> +<iframe name="submit_frame"></iframe> +<form method="get" id="form1" target="submit_frame" action="../../../../../blah"> +<input type="text" name="field1" value="teststring"><br> +<input type="radio" name="field2" value="0" checked> 0 +<input type="radio" name="field3" value="1"> 1<br> +<input type="checkbox" name="field4" value="1" checked> 1 +<input type="checkbox" name="field5" value="2"> 2 +<input type="checkbox" name="field6" value="3" checked> 3 +<select name="field7"> +<option value="1">1</option> +<option value="2" selected>2</option> +<option value="3">3</option> +<option value="4">4</option> +</select> +<input name="field8" value="8"> +<input name="field9" value="9"> +<input type="image" name="field10"> +<label name="field11"> +<input name="field12"> +<input type="button" name="field13" value="button"> +</form> +<script> + SimpleTest.waitForExplicitFinish(); + + addLoadEvent(function() { + document.getElementsByName('submit_frame')[0].onload = function() { + is(frames.submit_frame.location.href, `${location.origin}/blah?field1=teststring&field2=0&field4=1&field6=3&field7=2&field8=8&field9=9&field12=`, "Submit string was correct."); + SimpleTest.finish(); + }; + + document.forms[0].submit(); + }); +</script> +</body> +</html> diff --git a/dom/html/test/test_bug353415-2.html b/dom/html/test/test_bug353415-2.html new file mode 100644 index 0000000000..d27480dff4 --- /dev/null +++ b/dom/html/test/test_bug353415-2.html @@ -0,0 +1,67 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> +<iframe name="submit_frame"></iframe> +<form method="get" id="form1" target="submit_frame" action="../../../../../blah"> +<table> +<tr><td> +<input type="text" name="field1" value="teststring"><br> +<input type="radio" name="field2" value="0" checked> 0 +<input type="radio" name="field3" value="1"> 1<br> +<input type="checkbox" name="field4" value="1" checked> 1 +<input type="checkbox" name="field5" value="2"> 2 +<input type="checkbox" name="field6" value="3" checked> 3 +<select name="field7"> +<option value="1">1</option> +<option value="2" selected>2</option> +<option value="3">3</option> +<option value="4">4</option> +</select> +<input name="field8" value="8"> +<input name="field9" value="9"> +<input type="image" name="field10"> +<label name="field11"></label> +<input name="field12"> +<input type="button" name="field13" value="button"> +<input type="hidden" name="field14" value="14"> +</td> +<input type="text" name="field1-2" value="teststring"><br> +<input type="radio" name="field2-2" value="0" checked> 0 +<input type="radio" name="field3-2" value="1"> 1<br> +<input type="checkbox" name="field4-2" value="1" checked> 1 +<input type="checkbox" name="field5-2" value="2"> 2 +<input type="checkbox" name="field6-2" value="3" checked> 3 +<select name="field7-2"> +<option value="1">1</option> +<option value="2" selected>2</option> +<option value="3">3</option> +<option value="4">4</option> +</select> +<input name="field8-2" value="8"> +<input name="field9-2" value="9"> +<input type="image" name="field10-2"> +<label name="field11-2"></label> +<input name="field12-2"> +<input type="button" name="field13-2" value="button"> +<input type="hidden" name="field14-2" value="14"> +</tr> +</table> +</form> +<script> + SimpleTest.waitForExplicitFinish(); + + addLoadEvent(function() { + document.getElementsByName('submit_frame')[0].onload = function() { + is(frames.submit_frame.location.href, `${location.origin}/blah?field1-2=teststring&field2-2=0&field4-2=1&field6-2=3&field7-2=2&field8-2=8&field9-2=9&field12-2=&field1=teststring&field2=0&field4=1&field6=3&field7=2&field8=8&field9=9&field12=&field14=14&field14-2=14`, "Submit string was correct."); + SimpleTest.finish(); + }; + + document.forms[0].submit(); + }); +</script> +</body> +</html> diff --git a/dom/html/test/test_bug359657.html b/dom/html/test/test_bug359657.html new file mode 100644 index 0000000000..fe24eace2e --- /dev/null +++ b/dom/html/test/test_bug359657.html @@ -0,0 +1,40 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=359657 +--> +<head> + <title>Test for Bug 359657</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=359657">Mozilla Bug 359657</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); + +/** Test for Bug 359657 **/ +function runTest() { + var span = document.createElement("span"); + $("test").insertBefore(span, $("test").firstChild); + ok(true, "Reachability, we should get here without crashing"); + is($("test").firstChild, span, "First child is correct"); + SimpleTest.finish(); +} +</script> +<div> + <iframe src=""></iframe> + <!-- Important: This test needs to run async at this point. The actual test + is not crashing while running this test! --> + <script type="text/javascript" src="data:text/javascript,runTest()"></script> +</div> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug369370.html b/dom/html/test/test_bug369370.html new file mode 100644 index 0000000000..c39e6e3243 --- /dev/null +++ b/dom/html/test/test_bug369370.html @@ -0,0 +1,153 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=369370 +--> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <title>Test for Bug 369370</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> + <script type="text/javascript"> + /* + * Test strategy: + */ + function makeClickFor(x, y) { + var event = kidDoc.createEvent("mouseevent"); + event.initMouseEvent("click", + true, true, kidWin, 1, // bubbles, cancelable, view, single-click + x, y, x, y, // screen X/Y, client X/Y + false, false, false, false, // no key modifiers + 0, null); // left click, not relatedTarget + return event; + } + + function childLoaded() { + kidDoc = kidWin.document; + ok(true, "Child window loaded"); + + var elements = kidDoc.getElementsByTagName("img"); + is(elements.length, 1, "looking for imagedoc img"); + var img = elements[0]; + + // Need to use innerWidth/innerHeight of the window + // since the containing image is absolutely positioned, + // causing clientHeight to be zero. + is(kidWin.innerWidth, 400, "Checking doc width"); + is(kidWin.innerHeight, 300, "Checking doc height"); + + // Image just loaded and is scaled to window size. + is(img.width, 400, "image width"); + is(img.height, 300, "image height"); + is(kidDoc.body.scrollLeft, 0, "Checking scrollLeft"); + is(kidDoc.body.scrollTop, 0, "Checking scrollTop"); + + // ========== test 1 ========== + // Click in the upper left to zoom in + var event = makeClickFor(25,25); + img.dispatchEvent(event); + ok(true, "----- click 1 -----"); + + is(img.width, 800, "image width"); + is(img.height, 600, "image height"); + is(kidDoc.body.scrollLeft, 0, "Checking scrollLeft"); + is(kidDoc.body.scrollTop, 0, "Checking scrollTop"); + + // ========== test 2 ========== + // Click there again to zoom out + event = makeClickFor(25,25); + img.dispatchEvent(event); + ok(true, "----- click 2 -----"); + + is(img.width, 400, "image width"); + is(img.height, 300, "image height"); + is(kidDoc.body.scrollLeft, 0, "Checking scrollLeft"); + is(kidDoc.body.scrollTop, 0, "Checking scrollTop"); + + // ========== test 3 ========== + // Click in the lower right to zoom in + event = makeClickFor(350, 250); + img.dispatchEvent(event); + ok(true, "----- click 3 -----"); + + is(img.width, 800, "image width"); + is(img.height, 600, "image height"); + is(kidDoc.body.scrollLeft, + kidDoc.body.scrollLeftMax, "Checking scrollLeft"); + is(kidDoc.body.scrollTop, + kidDoc.body.scrollTopMax, "Checking scrollTop"); + + // ========== test 4 ========== + // Click there again to zoom out + event = makeClickFor(350, 250); + img.dispatchEvent(event); + ok(true, "----- click 4 -----"); + + is(img.width, 400, "image width"); + is(img.height, 300, "image height"); + is(kidDoc.body.scrollLeft, 0, "Checking scrollLeft"); + is(kidDoc.body.scrollTop, 0, "Checking scrollTop"); + + // ========== test 5 ========== + // Click in the upper left to zoom in again + event = makeClickFor(25, 25); + img.dispatchEvent(event); + ok(true, "----- click 5 -----"); + is(img.width, 800, "image width"); + is(img.height, 600, "image height"); + is(kidDoc.body.scrollLeft, 0, "Checking scrollLeft"); + is(kidDoc.body.scrollTop, 0, "Checking scrollTop"); + is(img.getBoundingClientRect().top, 0, "Image is in view vertically"); + + // ========== test 6 ========== + // Now try resizing the window so the image fits vertically. + function test6() { + kidWin.addEventListener("resize", function() { + // Give the image document time to respond + SimpleTest.executeSoon(function() { + is(img.height, 600, "image height"); + var bodyHeight = kidDoc.documentElement.scrollHeight; + var imgRect = img.getBoundingClientRect(); + is(imgRect.top, bodyHeight - imgRect.bottom, "Image is vertically centered"); + test7(); + }); + }, {once: true}); + + var decorationSize = kidWin.outerHeight - kidWin.innerHeight; + kidWin.resizeTo(400, 600 + 50 + decorationSize); + } + + // ========== test 7 ========== + // Now try resizing the window so the image no longer fits vertically. + function test7() { + kidWin.addEventListener("resize", function() { + // Give the image document time to respond + SimpleTest.executeSoon(function() { + is(img.height, 600, "image height"); + is(img.getBoundingClientRect().top, 0, "Image is at top again"); + kidWin.close(); + SimpleTest.finish(); + }); + }, {once: true}); + + var decorationSize = kidWin.outerHeight - kidWin.innerHeight; + kidWin.resizeTo(400, 300 + decorationSize); + } + + test6(); + } + var kidWin; + var kidDoc; + + SimpleTest.waitForExplicitFinish(); + SpecialPowers.pushPrefEnv({"set":[["browser.enable_automatic_image_resizing", true]]}, function() { + kidWin = window.open("bug369370-popup.png", "bug369370", "width=400,height=300"); + // will init onload + ok(kidWin, "opened child window"); + kidWin.onload = childLoaded; + }); + </script> +</body> +</html> diff --git a/dom/html/test/test_bug371375.html b/dom/html/test/test_bug371375.html new file mode 100644 index 0000000000..1cd0865293 --- /dev/null +++ b/dom/html/test/test_bug371375.html @@ -0,0 +1,58 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=371375 +--> +<head> + <title>Test for Bug 371375</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=371375">Mozilla Bug 371375</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + + /** Test for Bug 371375 **/ + var load1Called = false; + var error1Called = false; + var s = document.createElement('script'); + s.type = 'text/javascript'; + s.onload = function() { load1Called = true; }; + s.onerror = function(event) { error1Called = true; event.stopPropagation(); }; + s.src = 'about:cache-entry?client=image&sb=0&key=http://www.google.com'; + document.body.appendChild(s); + + var load2Called = false; + var error2Called = false; + var s2 = document.createElement('script'); + s2.type = 'text/javascript'; + s2.onload = function() { load2Called = true; }; + s2.onerror = function(event) { error2Called = true; event.stopPropagation(); }; + s2.src = 'data:text/plain, var x = 1;' + document.body.appendChild(s2); + + SimpleTest.waitForExplicitFinish(); + addLoadEvent(function() { + is(load1Called, false, "Load handler should not be called"); + is(error1Called, true, "Error handler should be called"); + is(load2Called, true, "Load handler for valid script should be called"); + is(error2Called, false, + "Error handler for valid script should not be called"); + SimpleTest.finish(); + }); +</script> +</body> +</html> + + + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug372098.html b/dom/html/test/test_bug372098.html new file mode 100644 index 0000000000..900b20100d --- /dev/null +++ b/dom/html/test/test_bug372098.html @@ -0,0 +1,68 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=372098 +--> +<head> + <title>Test for Bug 372098</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <base target="bug372098"></base> +</head> +<body> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=372098">Mozilla Bug 372098</a> + <p id="display"></p> + <div id="content" style="display:none;"> + <iframe name="bug372098"></iframe> + <a id="a" href="bug372098-link-target.html?a" target="">link</a> + <map> + <area id="area" shape="default" href="bug372098-link-target.html?area" target=""/> + </map> + </div> + <pre id="test"> + <script class="testbody" type="text/javascript"> + +var a_passed = false; +var area_passed = false; + +/* Start the test */ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(handle_load); + +function handle_load() +{ + sendMouseEvent({type:'click'}, 'a'); +} + +/* Finish the test */ + +function finish_test() +{ + ok(a_passed, "The 'a' element used the correct target."); + ok(area_passed, "The 'area' element used the correct target."); + SimpleTest.finish(); +} + +/* Callback function used by the linked document */ + +function callback(tag) +{ + switch (tag) { + case 'a': + a_passed = true; + sendMouseEvent({type:'click'}, 'area'); + return; + case 'area': + area_passed = true; + finish_test(); + return; + } + throw new Error("Eh??? We only test the 'a', 'link' and 'area' elements."); +} + + </script> + </pre> + +</body> +</html> diff --git a/dom/html/test/test_bug373589.html b/dom/html/test/test_bug373589.html new file mode 100644 index 0000000000..f494370f3d --- /dev/null +++ b/dom/html/test/test_bug373589.html @@ -0,0 +1,29 @@ +<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=373589
+-->
+<head>
+ <title>Test for Bug 373589</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=373589">Mozilla Bug 373589</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 373589 **/
+ var docElem = document.documentElement;
+ var body = document.body;
+ var numChildren = docElem.childNodes.length;
+ docElem.removeChild(body);
+ ok(numChildren > docElem.childNodes.length, "body was removed");
+ body.link;
+ ok(true, "didn't crash");
+ docElem.appendChild(body);
+ is(numChildren, docElem.childNodes.length, "body re-added");
+</script>
+</pre>
+</body>
+</html>
diff --git a/dom/html/test/test_bug375003-1.html b/dom/html/test/test_bug375003-1.html new file mode 100644 index 0000000000..2a5e6b911e --- /dev/null +++ b/dom/html/test/test_bug375003-1.html @@ -0,0 +1,157 @@ +<!DOCTYPE HTML> +<html id="html"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=375003 +--> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <title>Test 1 for bug 375003</title> + + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + + <style type="text/css"> + + html,body { + color:black; background-color:white; font-size:16px; padding:0; margin:0; + } + + .s { display:block; width:20px; height:20px; background-color:lime; } + table { background:pink; } + #td5,#td6 { border:7px solid blue;} + </style> + +<script> +var x = [ 'Left','Top','Width','Height' ]; +function test(id,s,expected) { + var el = document.getElementById(id); + for(var i = 0; i < x.length; ++i) { + // eslint-disable-next-line no-eval + var actual = eval('el.'+s+x[i]); + if (expected[i] != -1 && s+x[i]!='scrollHeight') + is(actual, expected[i], id+"."+s+x[i]); + } +} +function t3(id,c,o,s,pid) { + test(id,'client',c); + test(id,'offset',o); + test(id,'scroll',s); + var p = document.getElementById(id).offsetParent; + is(p.id, pid, id+".offsetParent"); +} + +function run_test() { + t3('span1',[0,0,20,20],[12,12,20,20],[0,0,20,20],'td1'); + t3('td1' ,[1,1,69,44],[16,16,71,46],[0,0,69,46],'table1'); + t3('tr1' ,[0,0,71,46],[16,16,71,46],[0,0,71,44],'table1'); + t3('span2',[10,0,20,20],[27,12,30,20],[0,0,20,20],'td2'); + t3('table1',[0,0,103,131],[10,10,103,131],[0,0,103,131],'body'); + t3('div1',[10,10,-1,131],[0,0,-1,151],[0,0,-1,85],'body'); + + t3('span2b',[10,0,20,20],[25,-1,30,20],[0,0,20,20],'body'); + // XXX not sure how to make reliable cross-platform tests for replaced-inline, inline + // t3('span2c',[10,2,18,2],[25,-1,30,6],[0,0,30,20],'body'); + // t3('span2d',[0,0,0,0],[25,-1,10,19],[0,0,10,20],'body'); + + t3('span3' ,[0,0,20,20],[15,0,20,20],[0,0,20,20],'td3'); + t3('td3' ,[0,0,35,20],[0,0,35,20],[0,0,35,20],'table3'); + t3('tr3' ,[0,0,35,20],[0,0,35,20],[0,0,35,22],'table3'); + t3('span4' ,[0,0,20,20],[0,0,20,20],[0,0,20,20],'td4'); + t3('table3',[0,0,35,40],[0,0,35,40],[0,0,35,40],'div3'); + t3('div3',[10,10,-1,40],[0,151,-1,60],[0,0,-1,70],'body'); + + t3('span5' ,[0,0,20,20],[1,1,20,20],[0,0,20,20],'td5'); + t3('td5' ,[7,7,22,22],[2,2,36,36],[0,0,22,36],'table5'); + t3('tr5' ,[0,0,36,36],[2,2,36,36],[0,0,36,22],'table5'); + t3('span6' ,[0,0,20,20],[20,58,20,20],[0,0,20,20],'div5'); + t3('table5',[0,0,40,78],[0,0,40,78],[0,0,40,78],'div5'); + t3('div5',[10,10,-1,78],[0,211,-1,98],[0,0,-1,70],'body'); + + t3('span7' ,[0,0,20,20],[1,1,20,20],[0,0,20,20],'td7'); + t3('td7' ,[1,1,37,22],[2,2,39,24],[0,0,37,22],'table7'); + t3('tr7' ,[0,0,39,24],[2,2,39,24],[0,0,39,22],'table7'); + t3('span8' ,[0,0,20,20],[19,30,20,20],[0,0,20,20],'table7'); + t3('table7',[0,0,57,68],[10,319,57,68],[0,0,57,68],'body'); + t3('div7',[10,10,-1,68],[0,309,-1,88],[0,0,-1,70],'body'); + + t3('span9' ,[0,0,20,20],[1,1,20,20],[0,0,20,20],'td9'); + t3('td9' ,[1,1,22,22],[2,2,24,24],[0,0,22,24],'table9'); + t3('tr9' ,[0,0,24,24],[2,2,24,24],[0,0,24,22],'table9'); + t3('span10' ,[0,0,20,20],[17,43,20,20],[0,0,20,20],'table9'); + t3('table9',[0,0,54,60],[10,407,54,60],[0,0,54,60],'body'); + t3('div9',[10,10,-1,0],[0,397,-1,20],[0,0,-1,70],'body'); + + t3('span11' ,[0,0,20,20],[1,1,20,20],[0,0,20,20],'td11'); + t3('td11' ,[0,0,22,22],[2,2,22,22],[0,0,22,22],'table11'); + t3('tr11' ,[0,0,22,22],[2,2,22,22],[0,0,22,22],'table11'); + t3('span12' ,[0,0,20,20],[28,454,20,20],[0,0,20,20],'body'); + t3('table11',[0,0,26,30],[10,427,26,30],[0,0,26,30],'body'); + t3('div11',[10,10,-1,30],[0,417,-1,50],[0,0,-1,70],'body'); +} +</script> +</head> +<body id="body"> + +<div id="content"> +<div id="div1" style="border:10px solid black"> +<table id="table1" cellspacing="7" cellpadding="12" border="9"> + <tbody id="tbody1"><tr id="tr1"><td id="td1"><div class="s" id="span1"></div></td></tr></tbody> + <tbody id="tbody2"><tr id="tr2"><td id="td2"><div class="s" id="span2" style="margin-left:15px; border-left:10px solid blue;"></div></td></tr></tbody> +</table> +</div> + +<div id="div3" style="border:10px solid black; position:relative"> +<table id="table3" cellpadding="0" cellspacing="0" border="0"> + <tbody id="tbody3"><tr id="tr3"><td id="td3"><div class="s" id="span3" style="margin-left:15px"></div></td></tr></tbody> + <tbody id="tbody4"><tr id="tr4"><td id="td4"><div class="s" id="span4"></div></td></tr></tbody> +</table> +</div> + +<div id="div5" style="border:10px solid black; position:relative"> +<table id="table5"> + <tbody id="tbody5"><tr id="tr5"><td id="td5"><div class="s" id="span5"></div></td></tr></tbody> + <tbody id="tbody6"><tr id="tr6"><td id="td6"><div class="s" id="span6" style="left:10px; top:10px; position:relative"></div></td></tr></tbody> +</table> +</div> + +<div id="div7" style="border:10px solid black;"> +<table id="table7" style="position:relative" border=7> + <tbody id="tbody7"><tr id="tr7"><td id="td7"><div class="s" id="span7"></div></td></tr></tbody> + <tbody id="tbody8"><tr id="tr8"><td id="td8"><div class="s" id="span8" style="position:relative; margin-left:15px"></div></td></tr></tbody> +</table> +</div> + +<div id="div9" style="border:10px solid black;"> +<table id="table9" style="position:absolute" border="13"> + <tbody id="tbody9"><tr id="tr9"><td id="td9"><div class="s" id="span9"></div></td></tr></tbody> + <tbody id="tbody10"><tr id="tr10"><td id="td10"><div class="s" id="span10" style="position:absolute"></div></td></tr></tbody> +</table> +</div> + +<div id="div11" style="border:10px solid black; "> +<table id="table11"> + <tbody id="tbody11"><tr id="tr11"><td id="td11"><div class="s" id="span11"></div></td></tr></tbody> + <tbody id="tbody12"><tr id="tr12"><td id="td12"><div class="s" id="span12" style="position:absolute;margin-left:15px"></div></td></tr></tbody> +</table> +</div> + +<div style="border:10px solid black"> +<div class="s" id="span2b" style="margin-left:15px; border-left:10px solid blue;"></div></div> + +<div style="border:10px solid black"> +<button id="span2c" style="margin-left:15px; border-left:10px solid blue;"></button></div> + +<div style="border:10px solid black"> +<span id="span2d" style="margin-left:15px; border-left:10px solid blue;"></span></div> +</div> + +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=375003">Mozilla Bug 375003</a> + +<pre id="test"> +<script class="testbody" type="text/javascript"> +run_test(); +</script> +</pre> + +</body> +</html> diff --git a/dom/html/test/test_bug375003-2.html b/dom/html/test/test_bug375003-2.html new file mode 100644 index 0000000000..b8b985846c --- /dev/null +++ b/dom/html/test/test_bug375003-2.html @@ -0,0 +1,110 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=375003 +--> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <title>Test 2 for bug 375003</title> + + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + + <style type="text/css"> + + html { + padding:0; margin:0; + } + body { + color:black; background-color:white; font-size:12px; padding:10px; margin:0; + } + + #div1,#abs1,#table1 { + border: 20px solid lime; + padding: 30px; + width: 100px; + height: 60px; + overflow:scroll; + } + #abs1,#table2parent { + position:absolute; + left:500px; + } + #table3parent { + position:fixed; + left:300px; + top:100px; + } + .content { + display:block; + width:200px; + height:200px; + background:yellow; + border: 0px dotted black; + } +</style> + + +<script type="text/javascript"> +var x = [ 'Left','Top','Width','Height' ]; +function test(id,s,expected) { + var el = document.getElementById(id); + for(var i = 0; i < x.length; ++i) { + // eslint-disable-next-line no-eval + var actual = eval('el.'+s+x[i]); + if (expected[i] != -1 && s+x[i]!='scrollHeight') + is(actual, expected[i], id+"."+s+x[i]); + } +} +function t3(id,c,o,s,pid) { + test(id,'client',c); + test(id,'offset',o); + test(id,'scroll',s); + var p = document.getElementById(id).offsetParent; + is(p.id, pid, id+".offsetParent"); +} + +function run_test() { + // XXX how test clientWidth/clientHeight (the -1 below) in cross-platform manner + // without hard-coding the scrollbar width? + t3('div1',[20,20,-1,-1],[10,10,200,160],[0,0,230,20],'body'); + t3('abs1',[20,20,-1,-1],[500,170,200,160],[0,0,230,20],'body'); + t3('table1',[0,0,306,306],[10,170,306,306],[0,0,306,306],'body'); + t3('table2',[0,0,206,206],[0,0,206,206],[0,0,206,20],'table2parent'); + t3('table3',[0,0,228,228],[0,0,228,228],[0,0,228,228],'table3parent'); + t3('table3parent',[0,0,228,228],[300,100,228,228],[0,0,228,228],'body'); +} +</script> + +</head> +<body id="body"> +<div id="content"> +<div id="div1parent"> + <div id="div1"><span class="content">DIV</span></div> +</div> + +<div id="abs1parent"> + <div id="abs1"><span class="content">abs.pos.DIV</span></div> +</div> + +<div id="table1parent"> + <table id="table1"><tbody><tr><td id="td1"><span class="content">TABLE</span></td></tr></tbody></table> +</div> + +<div id="table2parent"> + <table id="table2"><tbody><tr><td id="td2"><span class="content">TABLE in abs</span></td></tr></tbody></table> +</div> + +<div id="table3parent"> + <table id="table3" border="10"><tbody><tr><td id="td3"><span class="content">TABLE in fixed</span></td></tr></tbody></table> +</div> +</div> + +<pre id="test"> +<script class="testbody" type="text/javascript"> +run_test(); +</script> +</pre> + +</body> +</html> diff --git a/dom/html/test/test_bug377624.html b/dom/html/test/test_bug377624.html new file mode 100644 index 0000000000..d385708c5e --- /dev/null +++ b/dom/html/test/test_bug377624.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=377624 +--> +<head> + <title>Test for Bug 377624</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=377624">Mozilla Bug 377624</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 377624 **/ + +var input = document.createElement('input'); +ok("accept" in input, "'accept' is a valid input property"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug380383.html b/dom/html/test/test_bug380383.html new file mode 100644 index 0000000000..4ec632c0d6 --- /dev/null +++ b/dom/html/test/test_bug380383.html @@ -0,0 +1,39 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=380383 +--> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> + <title>Test for Bug 380383</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=380383">Mozilla Bug 380383</a> +<p id="display"> + <iframe id="f1" name="f1"></iframe> + <iframe id="f2" name="f2"></iframe> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + /** Test for Bug 380383 **/ + is($("f1").contentDocument.characterSet, "UTF-8", + "Unexpected charset for f1"); + + function runTest() { + is($("f2").contentDocument.characterSet, "UTF-8", + "Unexpected charset for f2"); + } + + addLoadEvent(runTest); + addLoadEvent(SimpleTest.finish); + SimpleTest.waitForExplicitFinish(); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug383383.html b/dom/html/test/test_bug383383.html new file mode 100644 index 0000000000..a518f426cf --- /dev/null +++ b/dom/html/test/test_bug383383.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=383383 +--> +<head> + <title>Test for Bug 383383</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=383383">Mozilla Bug 383383</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript" for=" window " event=" onload() "> + +var foo = "bar"; + +</script> + +<script class="testbody" type="text/javascript" for="object" event="handler"> + +// This script should fail to run +foo = "baz"; + +isnot(foo, "baz", "test failed"); + +</script> + +<script class="testbody" type="text/javascript"> + +ok(foo == "bar", "test passed"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug383383_2.xhtml b/dom/html/test/test_bug383383_2.xhtml new file mode 100644 index 0000000000..4dccd381c4 --- /dev/null +++ b/dom/html/test/test_bug383383_2.xhtml @@ -0,0 +1,20 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <title>Test for bug 383383</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> + <script> + SimpleTest.waitForExplicitFinish() + </script> + <script for="window" event="bar"> + // This script should not run, but should not cause a parse error either. + ok(false, "Script was unexpectedly run") + </script> + <script> + ok(true, "Script was run as it should") + SimpleTest.finish() + </script> +</body> +</html> diff --git a/dom/html/test/test_bug384419.html b/dom/html/test/test_bug384419.html new file mode 100644 index 0000000000..72ed15ef87 --- /dev/null +++ b/dom/html/test/test_bug384419.html @@ -0,0 +1,56 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=384419 +--> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <title>Test for bug 384419</title> + + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + + <style type="text/css"> + html,body { + color:black; background-color:white; font-size:16px; padding:0; margin:0; + } + body { margin: 10px; } + table { border:15px solid black; margin-left:100px; } +</style> + + +<script type="text/javascript"> +function t3(id,expected,pid) { + var el = document.getElementById(id); + var actual = el.offsetLeft; + is(actual, expected, id+".offsetLeft"); + + var p = document.getElementById(id).offsetParent; + is(p.id, pid, id+".offsetParent"); +} + +function run_test() { + t3('rel384419',135,'body'); + t3('abs384419',135,'body'); + t3('fix384419',135,'body'); +} +</script> + +</head> +<body id="body"> +<!-- It's important for the test that the tables below are directly inside body --> +<table cellpadding="7" cellspacing="3"><tr><td width="100"><div id="rel384419" style="position:relative;border:1px solid blue">X</div> relative</table> +<table cellpadding="7" cellspacing="3"><tr><td width="100"><div id="abs384419" style="position:absolute;border:1px solid blue">X</div> absolute</table> +<table cellpadding="7" cellspacing="3"><tr><td width="100"><div id="fix384419" style="position:fixed;border:1px solid blue">X</div> fixed</table> + + +<pre id="test"> +<script class="testbody" type="text/javascript"> +run_test(); +</script> +</pre> + +<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=384419">bug 384419</a> + +</body> +</html> diff --git a/dom/html/test/test_bug386496.html b/dom/html/test/test_bug386496.html new file mode 100644 index 0000000000..47c48592e8 --- /dev/null +++ b/dom/html/test/test_bug386496.html @@ -0,0 +1,53 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=386496 +--> +<head> + <title>Test for Bug 386496</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <SCRIPT Type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=386496">Mozilla Bug 386496</a> +<p id="display"></p> +<div id="content"> + <iframe style='display: block;' id="testIframe" + srcdoc="<div><a id='a' href='http://a.invalid/'>Link</a></div>"> + </iframe> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 386496 **/ + +var frame = document.getElementById("testIframe"); + +function testDesignMode() { + var unloadRequested = false; + + frame.contentDocument.designMode = "on"; + + frame.contentWindow.addEventListener("beforeunload", function() { + unloadRequested = true; + }); + + synthesizeMouseAtCenter(frame.contentDocument.getElementById("a"), {}, + frame.contentWindow); + + // The click has been sent. If 'beforeunload' event has been caught when we go + // back from the event loop that means the link has been activated. + setTimeout(function() { + ok(!unloadRequested, "The link should not be activated in designMode"); + SimpleTest.finish(); + }, 0); +} + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(testDesignMode); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug386728.html b/dom/html/test/test_bug386728.html new file mode 100644 index 0000000000..5562ce6712 --- /dev/null +++ b/dom/html/test/test_bug386728.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=386728 +--> +<head> + <title>Test for Bug 386728</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=386728">Mozilla Bug 386728</a> +<p id="display"></p> +<div id="content"> + <div id="frameContent"> + <div id="edit">This text is editable</div> + <button id="button_on" onclick="document.getElementById('edit').setAttribute('contenteditable', 'true')"></button> + </div> + <iframe id="testIframe"></iframe> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 386728 **/ + +var frame = document.getElementById("testIframe"); + +function testContentEditable() { + frame.style.display = 'block'; + var frameContent = frame.contentDocument.adoptNode(document.getElementById("frameContent")); + frame.contentDocument.body.appendChild(frameContent); + frame.contentDocument.getElementById("edit").contentEditable = "true"; + frame.contentDocument.getElementById("edit").contentEditable = "false"; + frame.contentDocument.getElementById("button_on").click(); + is(frame.contentDocument.getElementById("edit").contentEditable, "true"); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(testContentEditable); +addLoadEvent(SimpleTest.finish); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug386996.html b/dom/html/test/test_bug386996.html new file mode 100644 index 0000000000..a3068c2c2e --- /dev/null +++ b/dom/html/test/test_bug386996.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=386996 +--> +<head> + <title>Test for Bug 386996</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=386996">Mozilla Bug 386996</a> +<p id="display"></p> +<div id="content"> + <input id="input1"><input disabled><input id="input2"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 386996 **/ + +var frame = document.getElementById("testIframe"); + +function testContentEditable() { + var focusedElement; + document.getElementById("input1").onfocus = function() { focusedElement = this }; + document.getElementById("input2").onfocus = function() { focusedElement = this }; + + document.getElementById("input1").focus(); + synthesizeKey("KEY_Tab"); + + is(focusedElement.id, "input2"); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(testContentEditable); +addLoadEvent(SimpleTest.finish); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug388558.html b/dom/html/test/test_bug388558.html new file mode 100644 index 0000000000..a86bab8d1a --- /dev/null +++ b/dom/html/test/test_bug388558.html @@ -0,0 +1,76 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=388558 +--> +<head> + <title>Test for Bug 388558</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=388558">Mozilla Bug 388558</a> +<p id="display"></p> +<div id="content"> + <input type="text" id="input" onchange="++inputChange;"> + <textarea id="textarea" onchange="++textareaChange;"></textarea> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 388558 **/ +var inputChange = 0; +var textareaChange = 0; + +function testUserInput() { + var input = document.getElementById("input"); + var textarea = SpecialPowers.wrap(document.getElementById("textarea")); + + input.focus(); + SpecialPowers.wrap(input).setUserInput("foo"); + input.blur(); + is(inputChange, 1, "Input element should have got one change event."); + + input.focus(); + input.value = "bar"; + input.blur(); + is(inputChange, 1, + "Change event dispatched when setting the value of the input element"); + + input.value = ""; + is(inputChange, 1, + "Change event dispatched when setting the value of the input element (2)."); + + SpecialPowers.wrap(input).setUserInput("foo"); + is(inputChange, 2, + "Change event dispatched when input element doesn't have focus."); + + textarea.focus(); + textarea.setUserInput("foo"); + textarea.blur(); + is(textareaChange, 1, "Textarea element should have got one change event."); + + textarea.focus(); + textarea.value = "bar"; + textarea.blur(); + is(textareaChange, 1, + "Change event dispatched when setting the value of the textarea element."); + + textarea.value = ""; + is(textareaChange, 1, + "Change event dispatched when setting the value of the textarea element (2)."); + + textarea.setUserInput("foo"); + is(textareaChange, 1, + "Change event dispatched when textarea element doesn't have focus."); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(testUserInput); +addLoadEvent(SimpleTest.finish); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug388746.html b/dom/html/test/test_bug388746.html new file mode 100644 index 0000000000..38c73ee0b5 --- /dev/null +++ b/dom/html/test/test_bug388746.html @@ -0,0 +1,62 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=388746 +--> +<head> + <title>Test for Bug 388746</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=388746">Mozilla Bug 388746</a> +<p id="display"></p> +<div id="content"> + <input> + <textarea></textarea> + <select> + <option>option1</option> + <optgroup label="optgroup"> + <option>option2</option> + </optgroup> + </select> + <button>Button</button> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 388746 **/ + +var previousEventTarget = ""; + +function handler(evt) { + if (evt.eventPhase == 2) { + previousEventTarget = evt.target.localName.toLowerCase(); + } +} + +function testElementType(type) { + var el = document.getElementsByTagName(type)[0]; + el.addEventListener("DOMAttrModified", handler, true); + el.setAttribute("foo", "bar"); + ok(previousEventTarget == type, + type + " element should have got DOMAttrModified event."); +} + +function test() { + testElementType("input"); + testElementType("textarea"); + testElementType("select"); + testElementType("option"); + testElementType("optgroup"); + testElementType("button"); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(test); +addLoadEvent(SimpleTest.finish); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug388794.html b/dom/html/test/test_bug388794.html new file mode 100644 index 0000000000..06388547d7 --- /dev/null +++ b/dom/html/test/test_bug388794.html @@ -0,0 +1,107 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=388794 +--> +<head> + <title>Test for Bug 388794</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + input { padding: 0; margin: 0; border: none; } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=388794">Mozilla Bug 388794</a> +<p id="display"> + <form action="dummy_page.html" target="test1" method="GET"> + <input id="test1image" type="image" name="testImage"> + </form> + <form action="dummy_page.html" target="test2" method="GET"> + <input id="test2image" type="image"> + </form> + <form action="dummy_page.html" target="test3" method="GET"> + <input id="test3image" type="image" src="nnc_lockup.gif" name="testImage"> + </form> + <form action="dummy_page.html" target="test4" method="GET"> + <input id="test4image" type="image" src="nnc_lockup.gif"> + </form> + <form action="dummy_page.html" target="test5" method="GET"> + <input id="test5image" type="image" src="nnc_lockup.gif" name="testImage"> + </form> + <form action="dummy_page.html" target="test6" method="GET"> + <input id="test6image" type="image" src="nnc_lockup.gif"> + </form> + <iframe name="test1" id="test1"></iframe> + <iframe name="test2" id="test2"></iframe> + <iframe name="test3" id="test3"></iframe> + <iframe name="test4" id="test4"></iframe> + <iframe name="test5" id="test5"></iframe> + <iframe name="test6" id="test6"></iframe> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 388794 **/ +SimpleTest.waitForExplicitFinish(); + +var pendingLoads = 0; +/* Use regex due to rounding error in Fennec with C++APZ enabled */ +var hrefs = { + test1: /\?testImage\.x=0&testImage\.y=0/, + test2: /\?x=0&y=0/, + test3: /\?testImage\.x=0&testImage\.y=0/, + test4: /\?x=0&y=0/, + test5: /\?testImage\.x=[4-6]&testImage\.y=[4-6]/, + test6: /\?x=[4-6]&y=[4-6]/, +}; + +function submitForm(idNum) { + $("test"+idNum).setAttribute("onload", "frameLoaded(this)"); + $("test" + idNum + "image").focus(); + sendKey("return"); +} + +function submitFormMouse(idNum) { + $("test"+idNum).setAttribute("onload", "frameLoaded(this)"); + // Use 4.99 instead of 5 to guard against the possibility that the + // image's 'top' is exactly N + 0.5 pixels from the root. In that case + // we'd round up the widget mouse coordinate to N + 6, which relative + // to the image would be 5.5, which would get rounded up to 6 when + // submitting the form. Instead we round the widget mouse coordinate to + // N + 5, which relative to the image would be 4.5 which gets rounded up + // to 5. + synthesizeMouse($("test" + idNum + "image"), 4.99, 4.99, {}); +} + +addLoadEvent(function() { + // Need the timeout so painting has a chance to be unsuppressed. + setTimeout(function() { + submitForm(++pendingLoads); + submitForm(++pendingLoads); + submitForm(++pendingLoads); + submitForm(++pendingLoads); + submitFormMouse(++pendingLoads); + submitFormMouse(++pendingLoads); + }, 0); +}); + +function frameLoaded(frame) { + ok( + hrefs[frame.name].test(frame.contentWindow.location.href), + "Unexpected href for frame " + frame.name + " - " + + "expected to match: " + hrefs[frame.name].toString() + " got: " + frame.contentWindow.location.href + ); + if (--pendingLoads == 0) { + SimpleTest.finish(); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug389797.html b/dom/html/test/test_bug389797.html new file mode 100644 index 0000000000..701d6e65c9 --- /dev/null +++ b/dom/html/test/test_bug389797.html @@ -0,0 +1,243 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=389797 +--> +<head> + <title>Test for Bug 389797</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=389797">Mozilla Bug 389797</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 389797 **/ +var allTags = []; +var classInfos = {}; +var interfaces = {}; +var interfacesNonClassinfo = {}; + +function getClassName(tag) { + return "HTML" + classInfos[tag] + "Element"; +} + +function HTML_TAG(aTagName, aImplClass) { + allTags.push(aTagName); + classInfos[aTagName] = aImplClass; + interfaces[aTagName] = []; + + // Some interfaces don't appear in classinfo because other interfaces that + // inherit from them do. + interfacesNonClassinfo[aTagName] = [ ]; + + if (arguments.length > 2) { + for (var i = 0; i < arguments[2].length; ++i) { + interfaces[aTagName].push(arguments[2][i]); + } + } + + if (arguments.length > 3) { + for (i = 0; i < arguments[3].length; ++i) { + interfacesNonClassinfo[aTagName].push(arguments[3][i]); + } + } +} + +const objectIfaces = [ + "nsIRequestObserver", + "nsIStreamListener", + "nsIObjectLoadingContent", + "nsIChannelEventSink", +]; + +/* List copy/pasted from nsHTMLTagList.h, with the second field modified to the + correct classinfo (instead of the impl class) in the following cases: + + base + blockquote + dir + dl + embed + menu + ol + param + q + ul + wbr + head + html + */ + +HTML_TAG("a", "Anchor"); +HTML_TAG("abbr", ""); +HTML_TAG("acronym", ""); +HTML_TAG("address", ""); +HTML_TAG("area", "Area"); +HTML_TAG("article", ""); +HTML_TAG("aside", ""); +HTML_TAG("b", ""); +HTML_TAG("base", "Base"); +HTML_TAG("bdi", "") +HTML_TAG("bdo", ""); +HTML_TAG("bgsound", "Unknown"); +HTML_TAG("big", ""); +HTML_TAG("blockquote", "Quote"); +HTML_TAG("body", "Body"); +HTML_TAG("br", "BR"); +HTML_TAG("button", "Button"); +HTML_TAG("canvas", "Canvas"); +HTML_TAG("caption", "TableCaption"); +HTML_TAG("center", ""); +HTML_TAG("cite", ""); +HTML_TAG("code", ""); +HTML_TAG("col", "TableCol"); +HTML_TAG("colgroup", "TableCol"); +HTML_TAG("data", "Data"); +HTML_TAG("datalist", "DataList"); +HTML_TAG("dd", ""); +HTML_TAG("del", "Mod"); +HTML_TAG("dfn", ""); +HTML_TAG("dir", "Directory"); +HTML_TAG("div", "Div"); +HTML_TAG("dl", "DList"); +HTML_TAG("dt", ""); +HTML_TAG("em", ""); +HTML_TAG("embed", "Embed", [], objectIfaces); +HTML_TAG("fieldset", "FieldSet"); +HTML_TAG("figcaption", "") +HTML_TAG("figure", "") +HTML_TAG("font", "Font"); +HTML_TAG("footer", "") +HTML_TAG("form", "Form"); +HTML_TAG("frame", "Frame", [ "nsIDOMMozBrowserFrame" ]); +HTML_TAG("frameset", "FrameSet"); +HTML_TAG("h1", "Heading"); +HTML_TAG("h2", "Heading"); +HTML_TAG("h3", "Heading"); +HTML_TAG("h4", "Heading"); +HTML_TAG("h5", "Heading"); +HTML_TAG("h6", "Heading"); +HTML_TAG("head", "Head"); +HTML_TAG("header", "") +HTML_TAG("hgroup", "") +HTML_TAG("hr", "HR"); +HTML_TAG("html", "Html"); +HTML_TAG("i", ""); +HTML_TAG("iframe", "IFrame", [ "nsIDOMMozBrowserFrame" ]); +HTML_TAG("image", ""); +HTML_TAG("img", "Image", [ "nsIImageLoadingContent" ], []); +HTML_TAG("input", "Input", [], [ "imgINotificationObserver", + "nsIImageLoadingContent" ]); +HTML_TAG("ins", "Mod"); +HTML_TAG("kbd", ""); +HTML_TAG("keygen", "Unknown"); +HTML_TAG("label", "Label"); +HTML_TAG("legend", "Legend"); +HTML_TAG("li", "LI"); +HTML_TAG("link", "Link"); +HTML_TAG("listing", "Pre"); +HTML_TAG("main", ""); +HTML_TAG("map", "Map"); +HTML_TAG("mark", ""); +HTML_TAG("marquee", "Marquee"); +HTML_TAG("menu", "Menu"); +HTML_TAG("meta", "Meta"); +HTML_TAG("meter", "Meter"); +HTML_TAG("multicol", "Unknown"); +HTML_TAG("nav", "") +HTML_TAG("nobr", ""); +HTML_TAG("noembed", ""); +HTML_TAG("noframes", ""); +HTML_TAG("noscript", ""); +HTML_TAG("object", "Object", [], objectIfaces); +HTML_TAG("ol", "OList"); +HTML_TAG("optgroup", "OptGroup"); +HTML_TAG("option", "Option"); +HTML_TAG("p", "Paragraph"); +HTML_TAG("param", "Param"); +HTML_TAG("plaintext", ""); +HTML_TAG("pre", "Pre"); +HTML_TAG("q", "Quote"); +HTML_TAG("rb", ""); +HTML_TAG("rp", ""); +HTML_TAG("rt", ""); +HTML_TAG("rtc", ""); +HTML_TAG("ruby", ""); +HTML_TAG("s", ""); +HTML_TAG("samp", ""); +HTML_TAG("script", "Script", [ "nsIScriptLoaderObserver" ], []); +HTML_TAG("section", "") +HTML_TAG("select", "Select"); +HTML_TAG("small", ""); +HTML_TAG("span", "Span"); +HTML_TAG("strike", ""); +HTML_TAG("strong", ""); +HTML_TAG("style", "Style"); +HTML_TAG("sub", ""); +HTML_TAG("sup", ""); +HTML_TAG("table", "Table"); +HTML_TAG("tbody", "TableSection"); +HTML_TAG("td", "TableCell"); +HTML_TAG("textarea", "TextArea"); +HTML_TAG("tfoot", "TableSection"); +HTML_TAG("th", "TableCell"); +HTML_TAG("thead", "TableSection"); +HTML_TAG("template", "Template"); +HTML_TAG("time", "Time"); +HTML_TAG("title", "Title"); +HTML_TAG("tr", "TableRow"); +HTML_TAG("tt", ""); +HTML_TAG("u", ""); +HTML_TAG("ul", "UList"); +HTML_TAG("var", ""); +HTML_TAG("wbr", ""); +HTML_TAG("xmp", "Pre"); + +function tagName(aTag) { + return "<" + aTag + ">"; +} + +for (var tag of allTags) { + var node = document.createElement(tag); + + // Have to use the proto's toString(), since HTMLAnchorElement and company + // override toString(). + var nodeString = HTMLElement.prototype.toString.apply(node); + + // Debug builds have extra info, so chop off after "Element" if it's followed + // by ' ' or ']' + nodeString = nodeString.replace(/Element[\] ].*/, "Element"); + + var classInfoString = getClassName(tag); + is(nodeString, "[object " + classInfoString, + "Unexpected classname for " + tagName(tag)); + is(node instanceof window[classInfoString], true, + tagName(tag) + " not an instance of " + classInfos[tag]); + + if (classInfoString != 'HTMLUnknownElement') { + is(node instanceof HTMLUnknownElement, false, + tagName(tag) + " is an instance of HTMLUnknownElement"); + } else { + is(node instanceof HTMLUnknownElement, true, + tagName(tag) + " is an instance of HTMLUnknownElement"); + } + + // Check that each node QIs to all the things we expect it to QI to + for (var iface of interfaces[tag].concat(interfacesNonClassinfo[tag])) { + is(iface in SpecialPowers.Ci, true, + iface + " not in Components.interfaces"); + is(node instanceof SpecialPowers.Ci[iface], true, + tagName(tag) + " does not QI to " + iface); + } +} +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug390975.html b/dom/html/test/test_bug390975.html new file mode 100644 index 0000000000..8a7e09b807 --- /dev/null +++ b/dom/html/test/test_bug390975.html @@ -0,0 +1,61 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=390975 +--> +<head> + <title>Test for Bug 390975</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=390975">Mozilla Bug 390975</a> +<p id="display"></p> +<div id="content" style="display: none"> + <table id="table1"> + <form id="form1"> + <input> + <input> + <tr><td> + <input> + <input> + <input> + </td></tr> + </form> + </table> + + <table id="table2"> + <form id="form2"> + <input> + <input> + <tr id="row2"><td> + <input> + <input> + <input> + </td></tr> + </form> + </table> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 390975 **/ +var form = $("form1"); +is(form.elements.length, 5, "Unexpected elements length"); + +$("table1").remove(); +is(form.elements.length, 3, "Should have lost control outside table"); + +form.remove(); +is(form.elements.length, 0, "Should have lost control outside form"); + +form = $("form2"); +is(form.elements.length, 5, "Unexpected elements length"); + +$("row2").remove(); +is(form.elements.length, 2, "Should have lost controls inside table row"); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug391994.html b/dom/html/test/test_bug391994.html new file mode 100644 index 0000000000..8dfa6cc772 --- /dev/null +++ b/dom/html/test/test_bug391994.html @@ -0,0 +1,184 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=391994 +--> +<head> + <title>Test for Bug 391994</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=391994">Mozilla Bug 391994</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 391994 **/ +var testNumber = 0; + +function assertSelected(aOption, aExpectDefaultSelected, aExpectSelected) { + ++testNumber; + is(aOption.defaultSelected, aExpectDefaultSelected, + "Asserting default-selected state for option " + testNumber); + is(aOption.selected, aExpectSelected, + "Asserting selected state for option " + testNumber); +} + +function assertSame(aSel1, aSel2Str, aTestNumber) { + var div = document.createElement("div"); + div.innerHTML = aSel2Str; + sel2 = div.firstChild; + is(aSel1.options.length, sel2.options.length, + "Length should be same in select test " + aTestNumber); + is(aSel1.selectedIndex, sel2.selectedIndex, + "Selected index should be same in select test " + aTestNumber); + for (var i = 0; i < aSel1.options.length; ++i) { + is(aSel1.options[i].selected, sel2.options[i].selected, + "Options[" + i + "].selected should be the same in select test " + + aTestNumber); + is(aSel1.options[i].defaultSelected, sel2.options[i].defaultSelected, + "Options[" + i + + "].defaultSelected should be the same in select test " + + aTestNumber); + } +} + +// Creation methods +var opt = document.createElement("option"); +assertSelected(opt, false, false); + +opt = new Option(); +assertSelected(opt, false, false); + +// Setting of defaultSelected +opt = new Option(); +opt.setAttribute("selected", "selected"); +assertSelected(opt, true, true); + +opt = new Option(); +opt.defaultSelected = true; +assertSelected(opt, true, true); +is(opt.hasAttribute("selected"), true, "Attribute should be set"); +is(opt.getAttribute("selected"), "", + "Attribute should be set to empty string"); + +// Setting of selected +opt = new Option(); +opt.selected = false; +assertSelected(opt, false, false); + +opt = new Option(); +opt.selected = true; +assertSelected(opt, false, true); + +// Interaction of selected and defaultSelected +opt = new Option(); +opt.selected; +opt.setAttribute("selected", "selected"); +assertSelected(opt, true, true); + +opt = new Option(); +opt.selected = false; +opt.setAttribute("selected", "selected"); +assertSelected(opt, true, false); + +opt = new Option(); +opt.setAttribute("selected", "selected"); +opt.selected = true; +opt.removeAttribute("selected"); +assertSelected(opt, false, true); + +// First test of putting things in a <select>: Adding default-selected option +// should select it. +var sel = document.createElement("select"); +sel.appendChild(new Option()); +is(sel.selectedIndex, 0, "First option should be selected"); +assertSelected(sel.firstChild, false, true); + +sel.appendChild(new Option()); +is(sel.selectedIndex, 0, "First option should still be selected"); +assertSelected(sel.firstChild, false, true); +assertSelected(sel.firstChild.nextSibling, false, false); + +opt = new Option(); +opt.defaultSelected = true; +sel.appendChild(opt); +assertSelected(sel.firstChild, false, false); +assertSelected(sel.firstChild.nextSibling, false, false); +assertSelected(opt, true, true); +is(opt, sel.firstChild.nextSibling.nextSibling, "What happened here?"); +is(sel.options[0], sel.firstChild, "Unexpected option 0"); +is(sel.options[1], sel.firstChild.nextSibling, "Unexpected option 1"); +is(sel.options[2], opt, "Unexpected option 2"); +is(sel.selectedIndex, 2, "Unexpected selectedIndex in select test 1"); + +assertSame(sel, "<select><option><option><option selected></select>", 1); + +// Second test of putting things in a <select>: Adding two default-selected +// options should select the second one. +sel = document.createElement("select"); +sel.appendChild(new Option()); +sel.appendChild(new Option()); +opt = new Option(); +opt.defaultSelected = true; +sel.appendChild(opt); +opt = new Option(); +opt.defaultSelected = true; +sel.appendChild(opt); +assertSelected(sel.options[0], false, false); +assertSelected(sel.options[1], false, false); +assertSelected(sel.options[2], true, false); +assertSelected(sel.options[3], true, true); +is(sel.selectedIndex, 3, "Unexpected selectedIndex in select test 2"); + +assertSame(sel, + "<select><option><option><option selected><option selected></select>", 2); + +// Third test of putting things in a <select>: adding a selected option earlier +// than another selected option should make the new option selected. +sel = document.createElement("select"); +sel.appendChild(new Option()); +sel.appendChild(new Option()); +opt = new Option(); +opt.defaultSelected = true; +sel.appendChild(opt); +opt = new Option(); +opt.defaultSelected = true; +sel.options[0] = opt; +assertSelected(sel.options[0], true, true); +assertSelected(sel.options[1], false, false); +assertSelected(sel.options[2], true, false); +is(sel.selectedIndex, 0, "Unexpected selectedIndex in select test 3"); + +// Fourth test of putting things in a <select>: Just like second test, but with +// a <select multiple> +sel = document.createElement("select"); +sel.multiple = true; +sel.appendChild(new Option()); +sel.appendChild(new Option()); +opt = new Option(); +opt.defaultSelected = true; +sel.appendChild(opt); +opt = new Option(); +opt.defaultSelected = true; +sel.appendChild(opt); +assertSelected(sel.options[0], false, false); +assertSelected(sel.options[1], false, false); +assertSelected(sel.options[2], true, true); +assertSelected(sel.options[3], true, true); +is(sel.selectedIndex, 2, "Unexpected selectedIndex in select test 4"); + +assertSame(sel, + "<select multiple><option><option>" + + "<option selected><option selected></select>", + 4); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug394700.html b/dom/html/test/test_bug394700.html new file mode 100644 index 0000000000..fb6a54421b --- /dev/null +++ b/dom/html/test/test_bug394700.html @@ -0,0 +1,49 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=394700 +--> +<head> + <title>Test for Bug 394700</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=394700">Mozilla Bug 394700</a> +<p id="display"></p> +<div id="content"> + <select><option id="A">A</option><option id="B">B</option></select> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 394700 **/ + +function remove(q1) { q1.remove(); } + +function testSelectedIndex() +{ + document.addEventListener("DOMNodeRemoved", foo); + remove(document.getElementById("B")); + document.removeEventListener("DOMNodeRemoved", foo); + + function foo() + { + document.removeEventListener("DOMNodeRemoved", foo); + remove(document.getElementById("A")); + } + var selectElement = document.getElementsByTagName("select")[0]; + is(selectElement.selectedIndex, -1, "Wrong selected index!"); + is(selectElement.length, 0, "Select shouldn't have any options!"); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(testSelectedIndex); +addLoadEvent(SimpleTest.finish); + + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug395107.html b/dom/html/test/test_bug395107.html new file mode 100644 index 0000000000..8273cd6c6e --- /dev/null +++ b/dom/html/test/test_bug395107.html @@ -0,0 +1,108 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=395107 +--> +<head> + <title>Test for Bug 395107</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=395107">Mozilla Bug 395107</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 395107 **/ +var testNumber = 0; + +function assertSelected(aOption, aExpectDefaultSelected, aExpectSelected) { + ++testNumber; + is(aOption.defaultSelected, aExpectDefaultSelected, + "Asserting default-selected state for option " + testNumber); + is(aOption.selected, aExpectSelected, + "Asserting selected state for option " + testNumber); +} + +function assertSame(aSel1, aSel2Str, aTestNumber) { + var div = document.createElement("div"); + div.innerHTML = aSel2Str; + sel2 = div.firstChild; + is(aSel1.options.length, sel2.options.length, + "Length should be same in select test " + aTestNumber); + is(aSel1.selectedIndex, sel2.selectedIndex, + "Selected index should be same in select test " + aTestNumber); + for (var i = 0; i < aSel1.options.length; ++i) { + is(aSel1.options[i].selected, sel2.options[i].selected, + "Options[" + i + "].selected should be the same in select test " + + aTestNumber); + is(aSel1.options[i].defaultSelected, sel2.options[i].defaultSelected, + "Options[" + i + + "].defaultSelected should be the same in select test " + + aTestNumber); + } +} + +// In a single-select, setting an option selected should deselect an +// existing selected option. +var sel = document.createElement("select"); +sel.appendChild(new Option()); +is(sel.selectedIndex, 0, "First option should be selected"); +assertSelected(sel.firstChild, false, true); +sel.appendChild(new Option()); +is(sel.selectedIndex, 0, "First option should still be selected"); +assertSelected(sel.firstChild, false, true); +assertSelected(sel.firstChild.nextSibling, false, false); + +opt = new Option(); +sel.appendChild(opt); +opt.defaultSelected = true; +assertSelected(sel.firstChild, false, false); +assertSelected(sel.firstChild.nextSibling, false, false); +assertSelected(opt, true, true); +is(opt, sel.firstChild.nextSibling.nextSibling, "What happened here?"); +is(sel.options[0], sel.firstChild, "Unexpected option 0"); +is(sel.options[1], sel.firstChild.nextSibling, "Unexpected option 1"); +is(sel.options[2], opt, "Unexpected option 2"); +is(sel.selectedIndex, 2, "Unexpected selectedIndex in select test 1"); + +assertSame(sel, "<select><option><option><option selected></select>", 1); + +// Same, but with the option that gets set selected earlier in the select +sel = document.createElement("select"); +sel.appendChild(new Option()); +sel.appendChild(new Option()); +opt = new Option(); +opt.defaultSelected = true; +sel.appendChild(opt); +opt = new Option(); +sel.options[0] = opt; +opt.defaultSelected = true; +assertSelected(sel.options[0], true, true); +assertSelected(sel.options[1], false, false); +assertSelected(sel.options[2], true, false); +is(sel.selectedIndex, 0, "Unexpected selectedIndex in select test 2"); + +// And now try unselecting options +sel = document.createElement("select"); +sel.appendChild(new Option()); +opt = new Option(); +opt.defaultSelected = true; +sel.appendChild(opt); +sel.appendChild(new Option()); +opt.defaultSelected = false; + +assertSelected(sel.options[0], false, true); +assertSelected(sel.options[1], false, false); +assertSelected(sel.options[2], false, false); +is(sel.selectedIndex, 0, "Unexpected selectedIndex in select test 2"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug401160.xhtml b/dom/html/test/test_bug401160.xhtml new file mode 100644 index 0000000000..bb9fe47111 --- /dev/null +++ b/dom/html/test/test_bug401160.xhtml @@ -0,0 +1,27 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=401160 +--> +<head> + <title>Test for Bug 401160</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=401160">Mozilla Bug 401160</a> +<label id="label" contenteditable="true"><legend></legend><div></div></label> + +<pre id="test"> +<script type="text/javascript"> + +function do_test() { + document.getElementById('label').focus(); + ok(true, "This is crash test - the test succeeded if we reach this line") +} + +do_test(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug402680.html b/dom/html/test/test_bug402680.html new file mode 100644 index 0000000000..517942772e --- /dev/null +++ b/dom/html/test/test_bug402680.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=402680 +--> +<head> + <title>Test for Bug 402680</title> + <script> + var activeElementIsNull = (document.activeElement == null); + </script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=402680">Mozilla Bug 402680</a> +<p id="display"></p> +<div id="content"> + <input type="text"> + <textarea></textarea> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 402680 **/ + +ok(activeElementIsNull, + "Before document has body, active element should be null"); + +function testActiveElement() { + ok(document.body == document.activeElement, + "After page load body element should be the active element!"); + var input = document.getElementsByTagName("input")[0]; + input.focus(); + ok(document.activeElement == input, + "Input element isn't the active element!"); + var textarea = document.getElementsByTagName("textarea")[0]; + textarea.focus(); + ok(document.activeElement == textarea, + "Textarea element isn't the active element!"); + SimpleTest.finish(); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(testActiveElement); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug403868.html b/dom/html/test/test_bug403868.html new file mode 100644 index 0000000000..43118a0683 --- /dev/null +++ b/dom/html/test/test_bug403868.html @@ -0,0 +1,87 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=403868 +--> +<head> + <title>Test for Bug 403868</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=403868">Mozilla Bug 403868</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 403868 **/ +function createSpan(id, insertionPoint) { + var s = document.createElement("span"); + s.id = id; + $("content").insertBefore(s, insertionPoint); + return s; +} + +var s1a = createSpan("test1", null); +is(document.getElementById("test1"), s1a, + "Only one span with id=test1 in the tree; should work!"); + +var s2a = createSpan("test1", null); +is(document.getElementById("test1"), s1a, + "Appending span with id=test1 doesn't change which one comes first"); + +var s3a = createSpan("test1", s2a); +is(document.getElementById("test1"), s1a, + "Inserting span with id=test1 not at the beginning; doesn't matter"); + +var s4a = createSpan("test1", s1a); +is(document.getElementById("test1"), s4a, + "Inserting span with id=test1 at the beginning changes which one is first"); + +s4a.remove(); +is(document.getElementById("test1"), s1a, + "First-created span with id=test1 is first again"); + +s1a.remove(); +is(document.getElementById("test1"), s3a, + "Third-created span with id=test1 is first now"); + +// Start the id hashtable +for (var i = 0; i < 256; ++i) { + document.getElementById("no-such-id-in-the-document" + i); +} + +var s1b = createSpan("test2", null); +is(document.getElementById("test2"), s1b, + "Only one span with id=test2 in the tree; should work!"); + +var s2b = createSpan("test2", null); +is(document.getElementById("test2"), s1b, + "Appending span with id=test2 doesn't change which one comes first"); + +var s3b = createSpan("test2", s2b); +is(document.getElementById("test2"), s1b, + "Inserting span with id=test2 not at the beginning; doesn't matter"); + +var s4b = createSpan("test2", s1b); +is(document.getElementById("test2"), s4b, + "Inserting span with id=test2 at the beginning changes which one is first"); + +s4b.remove(); +is(document.getElementById("test2"), s1b, + "First-created span with id=test2 is first again"); + +s1b.remove(); +is(document.getElementById("test2"), s3b, + "Third-created span with id=test2 is first now"); + + + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug403868.xhtml b/dom/html/test/test_bug403868.xhtml new file mode 100644 index 0000000000..53c2a24d57 --- /dev/null +++ b/dom/html/test/test_bug403868.xhtml @@ -0,0 +1,86 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=403868 +--> +<head> + <title>Test for Bug 403868</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=403868">Mozilla Bug 403868</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +<![CDATA[ + +/** Test for Bug 403868 **/ +function createSpan(id, insertionPoint) { + var s = document.createElementNS("http://www.w3.org/1999/xhtml", "span"); + s.id = id; + $("content").insertBefore(s, insertionPoint); + return s; +} + +var s1a = createSpan("test1", null); +is(document.getElementById("test1"), s1a, + "Only one span with id=test1 in the tree; should work!"); + +var s2a = createSpan("test1", null); +is(document.getElementById("test1"), s1a, + "Appending span with id=test1 doesn't change which one comes first"); + +var s3a = createSpan("test1", s2a); +is(document.getElementById("test1"), s1a, + "Inserting span with id=test1 not at the beginning; doesn't matter"); + +var s4a = createSpan("test1", s1a); +is(document.getElementById("test1"), s4a, + "Inserting span with id=test1 at the beginning changes which one is first"); + +s4a.remove(); +is(document.getElementById("test1"), s1a, + "First-created span with id=test1 is first again"); + +s1a.remove(); +is(document.getElementById("test1"), s3a, + "Third-created span with id=test1 is first now"); + +// Start the id hashtable +for (var i = 0; i < 256; ++i) { + document.getElementById("no-such-id-in-the-document" + i); +} + +var s1b = createSpan("test2", null); +is(document.getElementById("test2"), s1b, + "Only one span with id=test2 in the tree; should work!"); + +var s2b = createSpan("test2", null); +is(document.getElementById("test2"), s1b, + "Appending span with id=test2 doesn't change which one comes first"); + +var s3b = createSpan("test2", s2b); +is(document.getElementById("test2"), s1b, + "Inserting span with id=test2 not at the beginning; doesn't matter"); + +var s4b = createSpan("test2", s1b); +is(document.getElementById("test2"), s4b, + "Inserting span with id=test2 at the beginning changes which one is first"); + +s4b.remove(); +is(document.getElementById("test2"), s1b, + "First-created span with id=test2 is first again"); + +s1b.remove(); +is(document.getElementById("test2"), s3b, + "Third-created span with id=test2 is first now"); + +]]> +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug405242.html b/dom/html/test/test_bug405242.html new file mode 100644 index 0000000000..b8999dc9f6 --- /dev/null +++ b/dom/html/test/test_bug405242.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=405242 +--> +<head> + <title>Test for Bug 405252</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=405242">Mozilla Bug 405242</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +/** Test for Bug 405242 **/ +var sel = document.createElement("select"); +sel.appendChild(new Option()); +sel.appendChild(new Option()); +sel.appendChild(new Option()); +opt = new Option(); +opt.value = 10; +sel.appendChild(opt); +sel.options.remove(0); +sel.options.remove(1000); +sel.options.remove(-1); +is(sel.length, 3, "Unexpected option collection length"); +is(sel[2].value, "10", "Unexpected remained option"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug406596.html b/dom/html/test/test_bug406596.html new file mode 100644 index 0000000000..6886d078be --- /dev/null +++ b/dom/html/test/test_bug406596.html @@ -0,0 +1,83 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=406596 +--> +<head> + <title>Test for Bug 406596</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=406596">Mozilla Bug 406596</a> +<div id="content"> + <div id="edit" contenteditable="true">This text is editable, you can change its content <a href="#" id="a" tabindex="0">ABCDEFGHIJKLMNOPQRSTUV</a> <input type="submit" value="abcd" id="b"></input> <img src="foo.png" id="c"></div> + <div tabindex="0">This text is not editable but is focusable</div> + <div tabindex="0">This text is not editable but is focusable</div> + <a href="#" id="d" contenteditable="true">ABCDEFGHIJKLMNOPQRSTUV</a> + <div tabindex="0">This text is not editable but is focusable</div> + <div tabindex="0">This text is not editable but is focusable</div> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 406596 **/ + +function testTabbing(click, focus, selectionOffset) { + var wu = SpecialPowers.getDOMWindowUtils(window); + + var elem = document.getElementById(click); + var rect = elem.getBoundingClientRect(); + var selection = window.getSelection(); + + var x = (rect.left + rect.right) / 4; + var y = (rect.top + rect.bottom) / 2; + wu.sendMouseEvent("mousedown", x, y, 0, 1, 0); + wu.sendMouseEvent("mousemove", x + selectionOffset, y, 0, 1, 0); + wu.sendMouseEvent("mouseup", x + selectionOffset, y, 0, 1, 0); + if (selectionOffset) { + is(selection.rangeCount, 1, "there should be one range in the selection"); + var range = selection.getRangeAt(0); + } + var focusedElement = document.activeElement; + is(focusedElement, document.getElementById(focus), + "clicking should move focus to the contentEditable node"); + synthesizeKey("KEY_Tab"); + synthesizeKey("KEY_Tab"); + synthesizeKey("KEY_Tab", {shiftKey: true}); + synthesizeKey("KEY_Tab", {shiftKey: true}); + is(document.activeElement, focusedElement, + "tab/shift-tab should move focus back to the contentEditable node"); + if (selectionOffset) { + is(selection.rangeCount, 1, + "there should still be one range in the selection"); + var newRange = selection.getRangeAt(0); + is(newRange.compareBoundaryPoints(Range.START_TO_START, range), 0, + "the selection should be the same as before the tabbing"); + is(newRange.compareBoundaryPoints(Range.END_TO_END, range), 0, + "the selection should be the same as before the tabbing"); + } +} + +function test() { + window.getSelection().removeAllRanges(); + testTabbing("edit", "edit", 0); + testTabbing("a", "edit", 0); + testTabbing("d", "d", 0); + testTabbing("edit", "edit", 10); + testTabbing("a", "edit", 10); + testTabbing("d", "d", 10); + + SimpleTest.finish(); +} + +window.onload = function() { + SimpleTest.waitForExplicitFinish(); + setTimeout(test, 0); +}; + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug417760.html b/dom/html/test/test_bug417760.html new file mode 100644 index 0000000000..52a3c1b425 --- /dev/null +++ b/dom/html/test/test_bug417760.html @@ -0,0 +1,71 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=417760 +--> +<head> + <title>cannot focus() img with tabindex="-1"</title> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <style type="text/css"> + img { + border: 5px solid white; + } + img:focus { + border: 5px solid black; + } + </style> + + + <script src="/tests/SimpleTest/SimpleTest.js"></script> + + <script type="text/javascript"> + function checkFocus(aExpected, aTabIndex) + { + elemCurr = document.activeElement.getAttribute("id"); + is(elemCurr, aExpected, "Element with tabIndex " + aTabIndex + + " did not receive focus!"); + } + + function doTest() + { + // First, test img with tabindex = 0 + document.getElementById("img-tabindex-0").focus(); + checkFocus("img-tabindex-0", 0); + + // now test the img with tabindex = -1 + document.getElementById("img-tabindex-minus-1").focus(); + checkFocus("img-tabindex-minus-1", -1); + + // now test the img without tabindex, should NOT receive focus! + document.getElementById("img-no-tabindex").focus(); + checkFocus("img-tabindex-minus-1", null); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addLoadEvent(doTest); + </script> +</head> + +<body> + + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=417760">Mozilla Bug 417760</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + <br>img tabindex="0": + <img id="img-tabindex-0" + src="file_bug417760.png" + alt="MoCo logo" tabindex="0"/> + <br>img tabindex="-1": + <img id="img-tabindex-minus-1" + src="file_bug417760.png" + alt="MoCo logo" tabindex="-1"/> + <br>img without tabindex: + <img id="img-no-tabindex" + src="file_bug417760.png" + alt="MoCo logo"/> +</body> +</html> diff --git a/dom/html/test/test_bug421640.html b/dom/html/test/test_bug421640.html new file mode 100644 index 0000000000..c63d026d1f --- /dev/null +++ b/dom/html/test/test_bug421640.html @@ -0,0 +1,56 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=421640 +--> +<head> + <title>Test for Bug 421640</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=421640">Mozilla Bug 421640</a> +<div id="content"> + <div id="edit" contenteditable="true">This text is editable</div> + <div><button id="button">Test</button></div> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 421640 **/ + +function test(click, focus, nextFocus) { + var wu = SpecialPowers.getDOMWindowUtils(window); + + var selection = window.getSelection(); + var edit = document.getElementById("edit"); + var text = edit.firstChild; + + selection.removeAllRanges(); + + var rect = edit.getBoundingClientRect(); + wu.sendMouseEvent("mousedown", rect.left + 1, rect.top + 1, 0, 1, 0); + wu.sendMouseEvent("mousemove", rect.right - 1, rect.top + 1, 0, 1, 0); + wu.sendMouseEvent("mouseup", rect.right - 1, rect.top + 1, 0, 1, 0); + + is(selection.anchorNode, text, ""); + + rect = document.getElementById("button").getBoundingClientRect(); + wu.sendMouseEvent("mousedown", rect.left + 10, rect.top + 1, 0, 1, 0); + wu.sendMouseEvent("mouseup", rect.left + 10, rect.top + 1, 0, 1, 0); + + is(selection.anchorNode, text, ""); + + SimpleTest.finish(); +} + +window.onload = function() { + SimpleTest.waitForExplicitFinish(); + setTimeout(test, 0); +}; + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug424698.html b/dom/html/test/test_bug424698.html new file mode 100644 index 0000000000..b59190e53d --- /dev/null +++ b/dom/html/test/test_bug424698.html @@ -0,0 +1,94 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=424698 +--> +<head> + <title>Test for Bug 424698</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=424698">Mozilla Bug 424698</a> +<p id="display"> +<input id="i1"> +<input id="target"> +<textarea id="i2"></textarea> +<textarea id="target2"></textarea> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 424698 **/ +var i = $("i1"); +is(i.value, "", "Value should be empty string"); +i.defaultValue = "test"; +is(i.value, "test", "Setting defaultValue should work"); +i.defaultValue = "test2"; +is(i.value, "test2", "Setting defaultValue multiple times should work"); + +// Now let's hide and reshow things +i.style.display = "none"; +is(i.offsetWidth, 0, "Input didn't hide?"); +i.style.display = ""; +isnot(i.offsetWidth, 0, "Input didn't show?"); +is(i.value, "test2", "Hiding/showing should not affect value"); +i.defaultValue = "test3"; +is(i.value, "test3", "Setting defaultValue after hide/show should work"); + +// Make sure typing works ok +i = $("target"); +i.focus(); // Otherwise editor gets confused when we send the key events +is(i.value, "", "Value should be empty string in second control"); +sendString("2test2"); +is(i.value, "2test2", 'We just typed the string "2test2"'); +i.defaultValue = "2test3"; +is(i.value, "2test2", "Setting defaultValue after typing should not work"); +i.style.display = "none"; +is(i.offsetWidth, 0, "Second input didn't hide?"); +i.style.display = ""; +isnot(i.offsetWidth, 0, "Second input didn't show?"); +is(i.value, "2test2", "Hiding/showing second input should not affect value"); +i.defaultValue = "2test4"; +is(i.value, "2test2", "Setting defaultValue after hide/show should not work if we typed"); + +i = $("i2"); +is(i.value, "", "Textarea value should be empty string"); +i.defaultValue = "test"; +is(i.value, "test", "Setting textarea defaultValue should work"); +i.defaultValue = "test2"; +is(i.value, "test2", "Setting textarea defaultValue multiple times should work"); + +// Now let's hide and reshow things +i.style.display = "none"; +is(i.offsetWidth, 0, "Textarea didn't hide?"); +i.style.display = ""; +isnot(i.offsetWidth, 0, "Textarea didn't show?"); +is(i.value, "test2", "Hiding/showing textarea should not affect value"); +i.defaultValue = "test3"; +is(i.value, "test3", "Setting textarea defaultValue after hide/show should work"); + +// Make sure typing works ok +i = $("target2"); +i.focus(); // Otherwise editor gets confused when we send the key events +is(i.value, "", "Textarea value should be empty string in second control"); +sendString("2test2"); +is(i.value, "2test2", 'We just typed the string "2test2"'); +i.defaultValue = "2test3"; +is(i.value, "2test2", "Setting textarea defaultValue after typing should not work"); +i.style.display = "none"; +is(i.offsetWidth, 0, "Second textarea didn't hide?"); +i.style.display = ""; +isnot(i.offsetWidth, 0, "Second textarea didn't show?"); +is(i.value, "2test2", "Hiding/showing second textarea should not affect value"); +i.defaultValue = "2test4"; +is(i.value, "2test2", "Setting textarea defaultValue after hide/show should not work if we typed"); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug428135.xhtml b/dom/html/test/test_bug428135.xhtml new file mode 100644 index 0000000000..ce269e2f8c --- /dev/null +++ b/dom/html/test/test_bug428135.xhtml @@ -0,0 +1,156 @@ +<?xml version="1.0"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=428135 +--> +<head> + <title>Test for Bug 428135</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=428135">Mozilla Bug 428135</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +<![CDATA[ + +/** Test for Bug 428135 **/ + +var expectedCurrentTargets = new Array(); + +function d(el, ename) { + var e = document.createEvent("Events"); + e.initEvent(ename, true, true); + el.dispatchEvent(e); +} + +function testListener(e) { + e.preventDefault(); + var expected = expectedCurrentTargets.shift(); + ok(expected == e.currentTarget, + "Unexpected current target [" + e.currentTarget + "], event=" + e.type + + ", phase=" + e.eventPhase + ", target should have been " + expected); +} + +function getAndAddListeners(elname) { + var el = document; + if (elname) { + el = document.getElementById(elname); + } + el.addEventListener("submit", testListener, true); + el.addEventListener("submit", testListener); + el.addEventListener("reset", testListener, true); + el.addEventListener("reset", testListener); + el.addEventListener("fooEvent", testListener, true); + el.addEventListener("fooEvent", testListener); + return el; +} + +function testSubmitResetEvents() { + getAndAddListeners(null); + var outerForm = getAndAddListeners("outerForm"); + var outerSubmit = getAndAddListeners("outerSubmit"); + var outerReset = getAndAddListeners("outerReset"); + var outerSubmitDispatcher = getAndAddListeners("outerSubmitDispatcher"); + var outerResetDispatcher = getAndAddListeners("outerResetDispatcher"); + var outerChild = getAndAddListeners("outerChild"); + var innerForm = getAndAddListeners("innerForm"); + var innerSubmit = getAndAddListeners("innerSubmit"); + var innerReset = getAndAddListeners("innerReset"); + var innerSubmitDispatcher = getAndAddListeners("innerSubmitDispatcher"); + var innerResetDispatcher = getAndAddListeners("innerResetDispatcher"); + + expectedCurrentTargets = new Array(document, outerForm, outerForm, document); + outerSubmit.click(); + ok(!expectedCurrentTargets.length, + "(1) expectedCurrentTargets isn't empty!"); + + expectedCurrentTargets = new Array(document, outerForm, outerForm, document); + outerReset.click(); + ok(!expectedCurrentTargets.length, + "(2) expectedCurrentTargets isn't empty!"); + + // Because of bug 428135, submit shouldn't propagate + // back to outerForm and document! + expectedCurrentTargets = + new Array(document, outerForm, outerSubmitDispatcher, outerSubmitDispatcher); + outerSubmitDispatcher.click(); + ok(!expectedCurrentTargets.length, + "(3) expectedCurrentTargets isn't empty!"); + + // Because of bug 428135, reset shouldn't propagate + // back to outerForm and document! + expectedCurrentTargets = + new Array(document, outerForm, outerResetDispatcher, outerResetDispatcher); + outerResetDispatcher.click(); + ok(!expectedCurrentTargets.length, + "(4) expectedCurrentTargets isn't empty!"); + + // Because of bug 428135, submit shouldn't propagate + // back to outerForm and document! + expectedCurrentTargets = + new Array(document, outerForm, outerChild, innerForm, innerForm, outerChild); + innerSubmit.click(); + ok(!expectedCurrentTargets.length, + "(5) expectedCurrentTargets isn't empty!"); + + // Because of bug 428135, reset shouldn't propagate + // back to outerForm and document! + expectedCurrentTargets = + new Array(document, outerForm, outerChild, innerForm, innerForm, outerChild); + innerReset.click(); + ok(!expectedCurrentTargets.length, + "(6) expectedCurrentTargets isn't empty!"); + + // Because of bug 428135, submit shouldn't propagate + // back to inner/outerForm or document! + expectedCurrentTargets = + new Array(document, outerForm, outerChild, innerForm, innerSubmitDispatcher, + innerSubmitDispatcher); + innerSubmitDispatcher.click(); + ok(!expectedCurrentTargets.length, + "(7) expectedCurrentTargets isn't empty!"); + + // Because of bug 428135, reset shouldn't propagate + // back to inner/outerForm or document! + expectedCurrentTargets = + new Array(document, outerForm, outerChild, innerForm, innerResetDispatcher, + innerResetDispatcher); + innerResetDispatcher.click(); + ok(!expectedCurrentTargets.length, + "(8) expectedCurrentTargets isn't empty!"); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(testSubmitResetEvents); +addLoadEvent(SimpleTest.finish); + + +]]> +</script> +</pre> +<form id="outerForm"> + <input type="submit" value="outer" id="outerSubmit"/> + <input type="reset" value="reset outer" id="outerReset"/> + <input type="button" value="dispatch submit" onclick="d(this, 'submit')" + id="outerSubmitDispatcher"/> + <input type="button" value="dispatch reset" onclick="d(this, 'reset')" + id="outerResetDispatcher"/> + <div id="outerChild"> + <form id="innerForm"> + <input type="submit" value="inner" id="innerSubmit"/> + <input type="reset" value="reset inner" id="innerReset"/> + <input type="button" value="dispatch submit" onclick="d(this, 'submit')" + id="innerSubmitDispatcher"/> + <input type="button" value="dispatch reset" onclick="d(this, 'reset')" + id="innerResetDispatcher"/> + </form> + </div> +</form> +</body> +</html> + diff --git a/dom/html/test/test_bug430351.html b/dom/html/test/test_bug430351.html new file mode 100644 index 0000000000..8cee4fe24f --- /dev/null +++ b/dom/html/test/test_bug430351.html @@ -0,0 +1,523 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=430351 +--> +<head> + <title>Test for Bug 430351</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=430351">Mozilla Bug 430351</a> +<p id="display"></p> +<div id="content"> + <div id="parent"></div> + <div id="editableParent" contenteditable="true"></div> + <iframe id="frame"></iframe> + <map name="map"><area></map> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 430351 **/ + +var focusableElements = [ + "<a tabindex=\"-1\"></a>", + "<a tabindex=\"0\"></a>", + "<a tabindex=\"0\" disabled></a>", + "<a tabindex=\"1\"></a>", + "<a contenteditable=\"true\"></a>", + + "<a href=\"#\"></a>", + "<a href=\"#\" tabindex=\"-1\"></a>", + "<a href=\"#\" tabindex=\"0\"></a>", + "<a href=\"#\" tabindex=\"0\" disabled></a>", + "<a href=\"#\" tabindex=\"1\"></a>", + "<a href=\"#\" contenteditable=\"true\"></a>", + "<a href=\"#\" disabled></a>", + + "<button></button>", + "<button tabindex=\"-1\"></button>", + "<button tabindex=\"0\"></button>", + "<button tabindex=\"1\"></button>", + "<button contenteditable=\"true\"></button>", + + "<button type=\"reset\"></button>", + "<button type=\"reset\" tabindex=\"-1\"></button>", + "<button type=\"reset\" tabindex=\"0\"></button>", + "<button type=\"reset\" tabindex=\"1\"></button>", + "<button type=\"reset\" contenteditable=\"true\"></button>", + + "<button type=\"submit\"></button>", + "<button type=\"submit\" tabindex=\"-1\"></button>", + "<button type=\"submit\" tabindex=\"0\"></button>", + "<button type=\"submit\" tabindex=\"1\"></button>", + "<button type=\"submit\" contenteditable=\"true\"></button>", + + "<div tabindex=\"-1\"></div>", + "<div tabindex=\"0\"></div>", + "<div tabindex=\"1\"></div>", + "<div contenteditable=\"true\"></div>", + "<div tabindex=\"0\" disabled></div>", + + "<embed>", + "<embed tabindex=\"-1\">", + "<embed tabindex=\"0\">", + "<embed tabindex=\"0\" disabled>", + "<embed tabindex=\"1\">", + "<embed disabled>", + "<embed contenteditable=\"true\">", + + "<iframe contenteditable=\"true\"></iframe>", + + "<iframe src=\"about:blank\"></iframe>", + "<iframe src=\"about:blank\" disabled></iframe>", + "<iframe src=\"about:blank\" tabindex=\"-1\"></iframe>", + "<iframe src=\"about:blank\" tabindex=\"0\"></iframe>", + "<iframe src=\"about:blank\" tabindex=\"0\" disabled></iframe>", + "<iframe src=\"about:blank\" tabindex=\"1\"></iframe>", + "<iframe src=\"about:blank\" contenteditable=\"true\"></iframe>", + + "<iframe></iframe>", + "<iframe tabindex=\"-1\"></iframe>", + "<iframe tabindex=\"0\"></iframe>", + "<iframe tabindex=\"0\" disabled></iframe>", + "<iframe tabindex=\"1\"></iframe>", + "<iframe disabled></iframe>", + + "<img tabindex=\"-1\">", + "<img tabindex=\"0\">", + "<img tabindex=\"0\" disabled>", + "<img tabindex=\"1\">", + + "<input>", + "<input tabindex=\"-1\">", + "<input tabindex=\"0\">", + "<input tabindex=\"1\">", + "<input contenteditable=\"true\">", + + "<input type=\"button\">", + "<input type=\"button\" tabindex=\"-1\">", + "<input type=\"button\" tabindex=\"0\">", + "<input type=\"button\" tabindex=\"1\">", + "<input type=\"button\" contenteditable=\"true\">", + + "<input type=\"checkbox\">", + "<input type=\"checkbox\" tabindex=\"-1\">", + "<input type=\"checkbox\" tabindex=\"0\">", + "<input type=\"checkbox\" tabindex=\"1\">", + "<input type=\"checkbox\" contenteditable=\"true\">", + + "<input type=\"image\">", + "<input type=\"image\" tabindex=\"-1\">", + "<input type=\"image\" tabindex=\"0\">", + "<input type=\"image\" tabindex=\"1\">", + "<input type=\"image\" contenteditable=\"true\">", + + "<input type=\"password\">", + "<input type=\"password\" tabindex=\"-1\">", + "<input type=\"password\" tabindex=\"0\">", + "<input type=\"password\" tabindex=\"1\">", + "<input type=\"password\" contenteditable=\"true\">", + + "<input type=\"radio\">", + "<input type=\"radio\" tabindex=\"-1\">", + "<input type=\"radio\" tabindex=\"0\">", + "<input type=\"radio\" tabindex=\"1\">", + "<input type=\"radio\" contenteditable=\"true\">", + "<input type=\"radio\" checked>", + "<form><input type=\"radio\" name=\"foo\"></form>", + + "<input type=\"reset\">", + "<input type=\"reset\" tabindex=\"-1\">", + "<input type=\"reset\" tabindex=\"0\">", + "<input type=\"reset\" tabindex=\"1\">", + "<input type=\"reset\" contenteditable=\"true\">", + + "<input type=\"submit\">", + "<input type=\"submit\" tabindex=\"-1\">", + "<input type=\"submit\" tabindex=\"0\">", + "<input type=\"submit\" tabindex=\"1\">", + "<input type=\"submit\" contenteditable=\"true\">", + + "<input type=\"text\">", + "<input type=\"text\" tabindex=\"-1\">", + "<input type=\"text\" tabindex=\"0\">", + "<input type=\"text\" tabindex=\"1\">", + "<input type=\"text\" contenteditable=\"true\">", + + "<input type=\"number\">", + "<input type=\"number\" tabindex=\"-1\">", + "<input type=\"number\" tabindex=\"0\">", + "<input type=\"number\" tabindex=\"1\">", + "<input type=\"number\" contenteditable=\"true\">", + + "<object tabindex=\"-1\"></object>", + "<object tabindex=\"0\"></object>", + "<object tabindex=\"1\"></object>", + "<object contenteditable=\"true\"></object>", + + "<object classid=\"java:a\"></object>", + "<object classid=\"java:a\" tabindex=\"-1\"></object>", + "<object classid=\"java:a\" tabindex=\"0\"></object>", + "<object classid=\"java:a\" tabindex=\"0\" disabled></object>", + "<object classid=\"java:a\" tabindex=\"1\"></object>", + "<object classid=\"java:a\" disabled></object>", + "<object classid=\"java:a\" contenteditable=\"true\"></object>", + + "<select></select>", + "<select tabindex=\"-1\"></select>", + "<select tabindex=\"0\"></select>", + "<select tabindex=\"1\"></select>", + "<select contenteditable=\"true\"></select>", + + "<option tabindex='-1'></option>", + "<option tabindex='0'></option>", + "<option tabindex='1'></option>", + "<option contenteditable></option>", + + "<optgroup tabindex='-1'></optgroup>", + "<optgroup tabindex='0'></optgroup>", + "<optgroup tabindex='1'></optgroup>", + "<optgroup contenteditable></optgroup>" +]; + +var nonFocusableElements = [ + "<a></a>", + "<a disabled></a>", + + "<button tabindex=\"0\" disabled></button>", + "<button disabled></button>", + + "<button type=\"reset\" tabindex=\"0\" disabled></button>", + "<button type=\"reset\" disabled></button>", + + "<button type=\"submit\" tabindex=\"0\" disabled></button>", + "<button type=\"submit\" disabled></button>", + + "<div></div>", + "<div disabled></div>", + + "<img>", + "<img disabled>", + "<img contenteditable=\"true\">", + + "<img usemap=\"#map\">", + "<img usemap=\"#map\" tabindex=\"-1\">", + "<img usemap=\"#map\" tabindex=\"0\">", + "<img usemap=\"#map\" tabindex=\"0\" disabled>", + "<img usemap=\"#map\" tabindex=\"1\">", + "<img usemap=\"#map\" disabled>", + "<img usemap=\"#map\" contenteditable=\"true\">", + + "<input tabindex=\"0\" disabled>", + "<input disabled>", + + "<input type=\"button\" tabindex=\"0\" disabled>", + "<input type=\"button\" disabled>", + + "<input type=\"checkbox\" tabindex=\"0\" disabled>", + "<input type=\"checkbox\" disabled>", + + "<input type=\"file\" tabindex=\"0\" disabled>", + "<input type=\"file\" disabled>", + + "<input type=\"hidden\">", + "<input type=\"hidden\" tabindex=\"-1\">", + "<input type=\"hidden\" tabindex=\"0\">", + "<input type=\"hidden\" tabindex=\"0\" disabled>", + "<input type=\"hidden\" tabindex=\"1\">", + "<input type=\"hidden\" disabled>", + "<input type=\"hidden\" contenteditable=\"true\">", + + "<input type=\"image\" tabindex=\"0\" disabled>", + "<input type=\"image\" disabled>", + + "<input type=\"password\" tabindex=\"0\" disabled>", + "<input type=\"password\" disabled>", + + "<input type=\"radio\" tabindex=\"0\" disabled>", + "<input type=\"radio\" disabled>", + + "<input type=\"reset\" tabindex=\"0\" disabled>", + "<input type=\"reset\" disabled>", + + "<input type=\"submit\" tabindex=\"0\" disabled>", + "<input type=\"submit\" disabled>", + + "<input type=\"text\" tabindex=\"0\" disabled>", + "<input type=\"text\" disabled>", + + "<object></object>", + + "<select tabindex=\"0\" disabled></select>", + "<select disabled></select>", + + "<option></option>", + "<option tabindex='1' disabled></option>", + + "<optgroup></optgroup>", + "<optgroup tabindex='1' disabled></optgroup>" +]; + +var focusableInContentEditable = [ + "<button></button>", + "<button tabindex=\"-1\"></button>", + "<button tabindex=\"0\"></button>", + "<button tabindex=\"1\"></button>", + "<button contenteditable=\"true\"></button>", + + "<button type=\"reset\"></button>", + "<button type=\"reset\" tabindex=\"-1\"></button>", + "<button type=\"reset\" tabindex=\"0\"></button>", + "<button type=\"reset\" tabindex=\"1\"></button>", + "<button type=\"reset\" contenteditable=\"true\"></button>", + + "<button type=\"submit\"></button>", + "<button type=\"submit\" tabindex=\"-1\"></button>", + "<button type=\"submit\" tabindex=\"0\"></button>", + "<button type=\"submit\" tabindex=\"1\"></button>", + "<button type=\"submit\" contenteditable=\"true\"></button>", + + "<div tabindex=\"-1\"></div>", + "<div tabindex=\"0\"></div>", + "<div tabindex=\"1\"></div>", + "<div tabindex=\"0\" disabled></div>", + + "<embed>", + "<embed tabindex=\"-1\">", + "<embed tabindex=\"0\">", + "<embed tabindex=\"0\" disabled>", + "<embed tabindex=\"1\">", + "<embed disabled>", + "<embed contenteditable=\"true\">", + + "<iframe src=\"about:blank\"></iframe>", + "<iframe></iframe>", + "<iframe src=\"about:blank\" disabled></iframe>", + "<iframe disabled></iframe>", + "<iframe src=\"about:blank\" tabindex=\"-1\"></iframe>", + "<iframe tabindex=\"-1\"></iframe>", + "<iframe src=\"about:blank\" tabindex=\"0\"></iframe>", + "<iframe tabindex=\"0\"></iframe>", + "<iframe src=\"about:blank\" tabindex=\"0\" disabled></iframe>", + "<iframe tabindex=\"0\" disabled></iframe>", + "<iframe src=\"about:blank\" tabindex=\"1\"></iframe>", + "<iframe tabindex=\"1\"></iframe>", + "<iframe src=\"about:blank\" contenteditable=\"true\"></iframe>", + "<iframe contenteditable=\"true\"></iframe>", + + "<img tabindex=\"-1\">", + "<img tabindex=\"0\">", + "<img tabindex=\"0\" disabled>", + "<img tabindex=\"1\">", + + "<input>", + "<input tabindex=\"-1\">", + "<input tabindex=\"0\">", + "<input tabindex=\"1\">", + "<input contenteditable=\"true\">", + + "<input type=\"button\">", + "<input type=\"button\" tabindex=\"-1\">", + "<input type=\"button\" tabindex=\"0\">", + "<input type=\"button\" tabindex=\"1\">", + "<input type=\"button\" contenteditable=\"true\">", + + "<input type=\"file\">", + "<input type=\"file\" tabindex=\"-1\">", + "<input type=\"file\" tabindex=\"0\">", + "<input type=\"file\" tabindex=\"1\">", + "<input type=\"file\" contenteditable=\"true\">", + + "<input type=\"checkbox\">", + "<input type=\"checkbox\" tabindex=\"-1\">", + "<input type=\"checkbox\" tabindex=\"0\">", + "<input type=\"checkbox\" tabindex=\"1\">", + "<input type=\"checkbox\" contenteditable=\"true\">", + + "<input type=\"image\">", + "<input type=\"image\" tabindex=\"-1\">", + "<input type=\"image\" tabindex=\"0\">", + "<input type=\"image\" tabindex=\"1\">", + "<input type=\"image\" contenteditable=\"true\">", + + "<input type=\"password\">", + "<input type=\"password\" tabindex=\"-1\">", + "<input type=\"password\" tabindex=\"0\">", + "<input type=\"password\" tabindex=\"1\">", + "<input type=\"password\" contenteditable=\"true\">", + + "<input type=\"radio\">", + "<input type=\"radio\" tabindex=\"-1\">", + "<input type=\"radio\" tabindex=\"0\">", + "<input type=\"radio\" tabindex=\"1\">", + "<input type=\"radio\" contenteditable=\"true\">", + "<input type=\"radio\" checked>", + "<form><input type=\"radio\" name=\"foo\"></form>", + + "<input type=\"reset\">", + "<input type=\"reset\" tabindex=\"-1\">", + "<input type=\"reset\" tabindex=\"0\">", + "<input type=\"reset\" tabindex=\"1\">", + "<input type=\"reset\" contenteditable=\"true\">", + + "<input type=\"submit\">", + "<input type=\"submit\" tabindex=\"-1\">", + "<input type=\"submit\" tabindex=\"0\">", + "<input type=\"submit\" tabindex=\"1\">", + "<input type=\"submit\" contenteditable=\"true\">", + + "<input type=\"text\">", + "<input type=\"text\" tabindex=\"-1\">", + "<input type=\"text\" tabindex=\"0\">", + "<input type=\"text\" tabindex=\"1\">", + "<input type=\"text\" contenteditable=\"true\">", + + "<input type=\"number\">", + "<input type=\"number\" tabindex=\"-1\">", + "<input type=\"number\" tabindex=\"0\">", + "<input type=\"number\" tabindex=\"1\">", + "<input type=\"number\" contenteditable=\"true\">", + + "<object tabindex=\"-1\"></object>", + "<object tabindex=\"0\"></object>", + "<object tabindex=\"1\"></object>", + + // Disabled doesn't work for <object>. + "<object tabindex=\"0\" disabled></object>", + "<object disabled></object>", + + "<select></select>", + "<select tabindex=\"-1\"></select>", + "<select tabindex=\"0\"></select>", + "<select tabindex=\"1\"></select>", + "<select contenteditable=\"true\"></select>", + + "<option tabindex='-1'></option>", + "<option tabindex='0'></option>", + "<option tabindex='1'></option>", + + "<optgroup tabindex='-1'></optgroup>", + "<optgroup tabindex='0'></optgroup>", + "<optgroup tabindex='1'></optgroup>" +]; + +var focusableInDesignMode = [ + "<embed>", + "<embed tabindex=\"-1\">", + "<embed tabindex=\"0\">", + "<embed tabindex=\"0\" disabled>", + "<embed tabindex=\"1\">", + "<embed disabled>", + "<embed contenteditable=\"true\">", + + "<img tabindex=\"-1\">", + "<img tabindex=\"0\">", + "<img tabindex=\"0\" disabled>", + "<img tabindex=\"1\">", +]; + +// Can't currently test these, need a plugin. +var focusableElementsTODO = [ + "<object classid=\"java:a\"></object>", + "<object classid=\"java:a\" tabindex=\"-1\"></object>", + "<object classid=\"java:a\" tabindex=\"0\"></object>", + "<object classid=\"java:a\" tabindex=\"0\" disabled></object>", + "<object classid=\"java:a\" tabindex=\"1\"></object>", + "<object classid=\"java:a\" disabled></object>", + "<object classid=\"java:a\" contenteditable=\"true\"></object>", +]; + +var serializer = new XMLSerializer(); + +function testElements(parent, tags, shouldBeFocusable) +{ + var focusable, errorSuffix = ""; + if (parent.ownerDocument.designMode == "on") { + focusable = focusableInDesignMode; + errorSuffix = " in a document with designMode=on"; + } + else if (parent.contentEditable == "true") { + focusable = focusableInContentEditable; + } + + for (var tag of tags) { + parent.ownerDocument.body.focus(); + + if (focusableElementsTODO.indexOf(tag) > -1) { + todo_is(parent.ownerDocument.activeElement, parent.firstChild, + tag + " should be focusable" + errorSuffix); + continue; + } + + parent.innerHTML = tag; + + // Focus the deepest descendant. + var descendant = parent; + while ((descendant = descendant.firstChild)) + element = descendant; + + if (element.nodeName == "IFRAME") + var foo = element.contentDocument; + + element.focus(); + + var errorPrefix = serializer.serializeToString(element) + " in " + + serializer.serializeToString(parent); + + try { + // Make sure activeElement doesn't point to a + // native anonymous element. + parent.ownerDocument.activeElement.localName; + } catch (ex) { + ok(false, ex + errorPrefix + errorSuffix); + } + if (focusable ? focusable.indexOf(tag) > -1 : shouldBeFocusable) { + is(parent.ownerDocument.activeElement, element, + errorPrefix + " should be focusable" + errorSuffix); + } + else { + isnot(parent.ownerDocument.activeElement, element, + errorPrefix + " should not be focusable" + errorSuffix); + } + + parent.innerHTML = ""; + } +} + +function test() +{ + var parent = document.getElementById("parent"); + var editableParent = document.getElementById("editableParent"); + + testElements(parent, focusableElements, true); + testElements(parent, nonFocusableElements, false); + + testElements(editableParent, focusableElements, true); + testElements(editableParent, nonFocusableElements, false); + + var frame = document.getElementById("frame"); + frame.contentDocument.body.innerHTML = document.getElementById("content").innerHTML; + frame.contentDocument.designMode = "on"; + parent = frame.contentDocument.getElementById("parent"); + editableParent = frame.contentDocument.getElementById("editableParent"); + + testElements(parent, focusableElements, false); + testElements(parent, nonFocusableElements, false); + + testElements(editableParent, focusableElements, false); + testElements(editableParent, nonFocusableElements, false); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(test); +addLoadEvent(SimpleTest.finish); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug435128.html b/dom/html/test/test_bug435128.html new file mode 100644 index 0000000000..0f4cf7cdb0 --- /dev/null +++ b/dom/html/test/test_bug435128.html @@ -0,0 +1,42 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=435128 +--> +<head> + <title>Test for Bug 435128</title> + <script type="application/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=435128">Mozilla Bug 435128</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<iframe id="content" src="data:text/html;charset=utf-8,%3Chtml%3E%3Chead%3E%3C/head%3E%3Cbody%3E%0A%3Ciframe%20id%3D%22a%22%3E%3C/iframe%3E%0A%3Cscript%3E%0Afunction%20doe%28%29%20%7B%0Avar%20x%20%3D%20window.frames%5B0%5D.document%3B%0A%0Avar%20y%3Ddocument.getElementById%28%27a%27%29%3B%0Ay.parentNode.removeChild%28y%29%3B%0A%0Atry%20%7Bx.write%28%27t%27%29%3B%7D%20catch%28e%29%20%7B%7D%0Atry%20%7Bx.write%28%27t%27%29%3B%7D%20catch%28e%29%20%7B%7D%0Atry%20%7Bx.write%28%27t%27%29%3B%7D%20catch%28e%29%20%7B%7D%0Atry%20%7Bx.write%28%27t%27%29%3B%7D%20catch%28e%29%20%7B%7D%0Atry%20%7Bx.write%28%27t%27%29%3B%7D%20catch%28e%29%20%7B%7D%0Atry%20%7Bx.write%28%27t%27%29%3B%7D%20catch%28e%29%20%7B%7D%0Atry%20%7Bx.write%28%27t%27%29%3B%7D%20catch%28e%29%20%7B%7D%0Atry%20%7Bx.write%28%27t%27%29%3B%7D%20catch%28e%29%20%7B%7D%0Atry%20%7Bx.write%28%27t%27%29%3B%7D%20catch%28e%29%20%7B%7D%0Atry%20%7Bx.write%28%27t%27%29%3B%7D%20catch%28e%29%20%7B%7D%0A%7D%0AsetTimeout%28%27doe%28%29%27%2C20%29%3B%0A%3C/script%3E%0A%3C/body%3E%3C/html%3E" style="width: 1000px; height: 200px;"></iframe> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 435128 **/ + +SimpleTest.waitForExplicitFinish(); + +setTimeout(finish, 60000); + +function doe2() { + document.getElementById('content').src = document.getElementById('content').src; +} +setInterval(doe2, 400); + +function finish() +{ + ok(true, "This is a mochikit version of a crash test. To complete is to pass."); + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug441930.html b/dom/html/test/test_bug441930.html new file mode 100644 index 0000000000..dcb7926734 --- /dev/null +++ b/dom/html/test/test_bug441930.html @@ -0,0 +1,29 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=441930 +--> +<head> + <title>Test for Bug 441930</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=441930">Mozilla Bug 441930</a> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 441930: see bug441930_iframe.html **/ + +SimpleTest.waitForExplicitFinish(); + +</script> +</pre> +<p id="display"> + <iframe src="bug441930_iframe.html"></iframe> +</p> +<div id="content" style="display: none"> +</div> +</body> +</html> + diff --git a/dom/html/test/test_bug442801.html b/dom/html/test/test_bug442801.html new file mode 100644 index 0000000000..1a93d94f14 --- /dev/null +++ b/dom/html/test/test_bug442801.html @@ -0,0 +1,63 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=442801 +--> +<head> + <title>Test for Bug 442801</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=442801">Mozilla Bug 442801</a> +<p id="display"></p> +<div id="content" style="display: none"> + +<div contenteditable="true"> +<p id="ce_true" contenteditable="true">contenteditable true</p> +</div> + +<div contenteditable="true"> +<p id="ce_false" contenteditable="false">contenteditable false</p> +</div> + +<div contenteditable="true"> +<p id="ce_empty" contenteditable="">contenteditable empty</p> +</div> + +<div contenteditable="true"> +<p id="ce_inherit" contenteditable="inherit">contenteditable inherit</p> +</div> + +<div contenteditable="true"> +<p id="ce_none" >contenteditable none</p> +</div> + + + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 442801 **/ + +is(window.getComputedStyle($("ce_true")).getPropertyValue("-moz-user-modify"), + "read-write", + "parent contenteditable is true, contenteditable is true; user-modify should be read-write"); +is(window.getComputedStyle($("ce_false")).getPropertyValue("-moz-user-modify"), + "read-only", + "parent contenteditable is true, contenteditable is false; user-modify should be read-only"); +is(window.getComputedStyle($("ce_empty")).getPropertyValue("-moz-user-modify"), + "read-write", + "parent contenteditable is true, contenteditable is empty; user-modify should be read-write"); +is(window.getComputedStyle($("ce_inherit")).getPropertyValue("-moz-user-modify"), + "read-write", + "parent contenteditable is true, contenteditable is inherit; user-modify should be read-write"); +is(window.getComputedStyle($("ce_none")).getPropertyValue("-moz-user-modify"), + "read-write", + "parent contenteditable is true, contenteditable is none; user-modify should be read-write"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug445004.html b/dom/html/test/test_bug445004.html new file mode 100644 index 0000000000..02fc79f425 --- /dev/null +++ b/dom/html/test/test_bug445004.html @@ -0,0 +1,138 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=445004 +--> +<head> + <title>Test for Bug 445004</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=445004">Mozilla Bug 445004</a> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 445004 **/ +is(window.location.hostname, "mochi.test", "Unexpected hostname"); +is(window.location.port, "8888", "Unexpected port; fix testcase"); + +SimpleTest.waitForExplicitFinish(); + +var loads = 1; + +function loadStarted() { + ++loads; +} +function loadEnded() { + --loads; + if (loads == 0) { + doTest(); + } +} + +window.onload = loadEnded; + +function getMessage(evt) { + ok(evt.data == "start" || evt.data == "end", "Must have start or end"); + if (evt.data == "start") + loadStarted(); + else + loadEnded(); +} + +window.addEventListener("message", getMessage); + +function checkURI(uri, name, type) { + var host = uri.match(/^http:\/\/([a-z.0-9]*)/)[1]; + var file = uri.match(/([^\/]*).png$/)[1]; + is(host, file, "Unexpected base URI for test " + name + + " when testing " + type); +} + +function checkFrame(num) { + // Just snarf our data + var outer = SpecialPowers.wrap(window.frames[num]); + name = outer.name; + + is(outer.document.baseURI, + "http://example.org/tests/dom/html/test/bug445004-outer.html", + "Unexpected base URI for " + name); + + var iswrite = name.match(/write/); + + var inner = outer.frames[0]; + if (iswrite) { + is(inner.document.baseURI, + "http://example.org/tests/dom/html/test/bug445004-outer.html", + "Unexpected inner base URI for " + name); + } else { + is(inner.document.baseURI, + "http://test1.example.org/tests/dom/html/test/bug445004-inner.html", + "Unexpected inner base URI for " + name); + } + + var isrel = name.match(/rel/); + var offsite = name.match(/offsite/); + + if (!iswrite) { + if ((isrel && !offsite) || (!isrel && offsite)) { + is(inner.location.hostname, outer.location.hostname, + "Unexpected hostnames for " + name); + } else { + isnot(inner.location.hostname, outer.location.hostname, + "Unexpected hostnames for " + name); + } + } + + checkURI(inner.frames[0].location.href, name, "direct location"); + checkURI(inner.frames[1].document.getElementsByTagName("img")[0].src, + name, "direct write"); + if (!iswrite) { + is(inner.frames[1].location.hostname, inner.location.hostname, + "Incorrect hostname for " + name + " direct write") + } + checkURI(inner.frames[2].location.href, name, "indirect location"); + checkURI(inner.frames[3].document.getElementsByTagName("img")[0].src, + name, "indirect write"); + if (!iswrite) { + is(inner.frames[3].location.hostname, outer.location.hostname, + "Incorrect hostname for " + name + " indirect write") + } + checkURI(inner.document.getElementsByTagName("img")[0].src, + name, "direct image load"); +} + + +function doTest() { + for (var num = 0; num < 5; ++num) { + checkFrame(num); + } + + SimpleTest.finish(); +} + +</script> +</pre> +<p id="display"> + <iframe + src="http://example.org/tests/dom/html/test/bug445004-outer-rel.html" + name="bug445004-outer-rel.html"></iframe> + <iframe + src="http://test1.example.org/tests/dom/html/test/bug445004-outer-rel.html" + name="bug445004-outer-rel.html offsite"></iframe> + <iframe + src="http://example.org/tests/dom/html/test/bug445004-outer-abs.html" + name="bug445004-outer-abs.html"></iframe> + <iframe + src="http://test1.example.org/tests/dom/html/test/bug445004-outer-abs.html" + name="bug445004-outer-abs.html offsite"></iframe> + <iframe + src="http://example.org/tests/dom/html/test/bug445004-outer-write.html" + name="bug445004-outer-write.html"></iframe> +</p> +</body> +</html> diff --git a/dom/html/test/test_bug446483.html b/dom/html/test/test_bug446483.html new file mode 100644 index 0000000000..9821670da7 --- /dev/null +++ b/dom/html/test/test_bug446483.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=446483 +--> +<head> + <title>Test for Bug 446483</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=446483">Mozilla Bug 446483</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 446483 **/ + +function gc() { + SpecialPowers.gc(); +} + +function runTest() { + document.getElementById('display').innerHTML = + '<iframe src="bug446483-iframe.html"><\/iframe>\n' + + '<iframe src="bug446483-iframe.html"><\/iframe>\n'; + + setInterval(gc, 1000); + + setTimeout(function() { + document.getElementById('display').innerHTML = ''; + ok(true, ''); + SimpleTest.finish(); + }, 4000); +} + +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("untriaged"); +addLoadEvent(runTest); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug448166.html b/dom/html/test/test_bug448166.html new file mode 100644 index 0000000000..45b47fcb3f --- /dev/null +++ b/dom/html/test/test_bug448166.html @@ -0,0 +1,39 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=448166 +--> +<head> + <meta charset="utf-8" /> + <title>Test for Bug 448166</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=448166">Mozilla Bug 448166</a> +<p id="display"> + <a id="test" href="http://www.moz�illa.org">should not be Mozilla</a> + <a id="control" href="http://www.mozilla.org">should not be Mozilla</a> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 448166 **/ +isnot($("test").href, "http://www.mozilla.org/", + "Should notice unpaired surrogate"); +is($("test").href, "http://www.moz�illa.org", + "URL parser fails. Href returns original input string"); + +SimpleTest.doesThrow(() => { new URL($("test").href);}, "URL parser rejects input"); + +is($("control").href, "http://www.mozilla.org/", + "Just making sure .href works"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug448564.html b/dom/html/test/test_bug448564.html new file mode 100644 index 0000000000..bfb61af8dd --- /dev/null +++ b/dom/html/test/test_bug448564.html @@ -0,0 +1,53 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=448564 +--> +<head> + <title>Test for Bug 448564</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=448564">Mozilla Bug 448564</a> +<p id="display"> + <iframe src="bug448564-iframe-1.html"></iframe> + <iframe src="bug448564-iframe-2.html"></iframe> + <iframe src="bug448564-iframe-3.html"></iframe> +</p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 448564 **/ + +/** + * The three iframes are going to be loaded with some dirty constructed forms. + * Each of them will be submitted before the load event and a SJS will replace + * the frame content with the query string. + * Then, on the load event, our test file will check the content of each iframes + * and check if the query string were correctly formatted (implying that all + * iframes were correctly submitted. + */ + +function checkQueryString(frame) { + var queryString = frame.document.body.textContent; + is(queryString.split("&").sort().join("&"), + "a=aval&b=bval&c=cval&d=dval", + "Not all form fields were properly submitted."); +} + +SimpleTest.waitForExplicitFinish(); + +addLoadEvent(function() { + checkQueryString(frames[0]); + checkQueryString(frames[1]); + checkQueryString(frames[2]); + SimpleTest.finish(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug456229.html b/dom/html/test/test_bug456229.html new file mode 100644 index 0000000000..c9d6c36054 --- /dev/null +++ b/dom/html/test/test_bug456229.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=456229 +--> +<head> + <title>Test for Bug 456229</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=456229">Mozilla Bug 456229</a> +<p id="display"></p> +<div id="content" style="display: none"> + <input id='i' type="search"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 456229 **/ + +// More checks are done in test_bug551670.html. + +var i = document.getElementById('i'); +is(i.type, 'search', "Search state should be recognized"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug458037.xhtml b/dom/html/test/test_bug458037.xhtml new file mode 100644 index 0000000000..c8ae3e1191 --- /dev/null +++ b/dom/html/test/test_bug458037.xhtml @@ -0,0 +1,112 @@ +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=458037 +--> +<head> + <title>Test for Bug 458037</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=458037">Mozilla Bug 458037</a> +<p id="display"></p> +<div id="content" > +<div id="a"></div> +<div id="b" contenteditable="true"></div> +<div id="c" contenteditable="false"></div> +<div id="d" contenteditable="inherit"></div> +<div contenteditable="true"> + <div id="e"></div> +</div> +<div contenteditable="false"> + <div id="f"></div> +</div> +<div contenteditable="true"> + <div id="g" contenteditable="false"></div> +</div> +<div contenteditable="false"> + <div id="h" contenteditable="true"></div> +</div> +<div contenteditable="true"> + <div id="i" contenteditable="inherit"></div> +</div> +<div contenteditable="false"> + <div id="j" contenteditable="inherit"></div> +</div> +<div contenteditable="true"> + <xul:box> + <div id="k"></div> + </xul:box> +</div> +<div contenteditable="false"> + <xul:box> + <div id="l"></div> + </xul:box> +</div> +<div contenteditable="true"> + <xul:box> + <div id="m" contenteditable="inherit"></div> + </xul:box> +</div> +<div contenteditable="false"> + <xul:box> + <div id="n" contenteditable="inherit"></div> + </xul:box> +</div> +<div id="x"></div> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 458037 **/ + +function test(id, expected) { + is(document.getElementById(id).isContentEditable, expected, + "Element " + id + " should " + (expected ? "" : "not ") + "be editable"); +} + +document.addEventListener("DOMContentLoaded", function() { + test("a", false); + test("b", true); + test("c", false); + test("d", false); + test("e", true); + test("f", false); + test("g", false); + test("h", true); + test("i", true); + test("j", false); + test("k", true); + test("l", false); + test("m", true); + test("n", false); + + var d = document.getElementById("x"); + test("x", false); + d.setAttribute("contenteditable", "true"); + test("x", true); + d.setAttribute("contenteditable", "false"); + test("x", false); + d.setAttribute("contenteditable", "inherit"); + test("x", false); + d.removeAttribute("contenteditable"); + test("x", false); + d.contentEditable = "true"; + test("x", true); + d.contentEditable = "false"; + test("x", false); + d.contentEditable = "inherit"; + test("x", false); + + // Make sure that isContentEditable is read-only + var origValue = d.isContentEditable; + d.isContentEditable = !origValue; + is(d.isContentEditable, origValue, "isContentEditable should be read only"); +}); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug460568.html b/dom/html/test/test_bug460568.html new file mode 100644 index 0000000000..db379e6fcc --- /dev/null +++ b/dom/html/test/test_bug460568.html @@ -0,0 +1,144 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=460568 +--> +<head> + <title>Test for Bug 460568</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=460568">Mozilla Bug 460568</a> +<p id="display"><a href="" id="anchor">a[href]</a></p> +<div id="editor"> + <a href="" id="anchorInEditor">a[href] in editor</a> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 460568 **/ + +function runTest() +{ + var editor = document.getElementById("editor"); + var anchor = document.getElementById("anchor"); + var anchorInEditor = document.getElementById("anchorInEditor"); + + var focused; + anchorInEditor.onfocus = function() { focused = true; }; + + function isReallyEditable() + { + editor.focus(); + var range = document.createRange(); + range.selectNodeContents(editor); + var prevStr = range.toString(); + + var docShell = SpecialPowers.wrap(window).docShell; + var controller = + docShell.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor) + .getInterface(SpecialPowers.Ci.nsISelectionDisplay) + .QueryInterface(SpecialPowers.Ci.nsISelectionController); + var sel = controller.getSelection(controller.SELECTION_NORMAL); + sel.collapse(anchorInEditor, 0); + sendString("a"); + range.selectNodeContents(editor); + return prevStr != range.toString(); + } + + focused = false; + anchor.focus(); + editor.setAttribute("contenteditable", "true"); + anchorInEditor.focus(); + is(focused, false, "focus moved to element in contenteditable=true"); + is(isReallyEditable(), true, "cannot edit by a key event"); + + // for bug 502273 + focused = false; + anchor.focus(); + editor.setAttribute("dummy", "dummy"); + editor.removeAttribute("dummy"); + anchorInEditor.focus(); + is(focused, false, "focus moved to element in contenteditable=true (after dummy attribute was removed)"); + is(isReallyEditable(), true, "cannot edit by a key event"); + + focused = false; + anchor.focus(); + editor.setAttribute("contenteditable", "false"); + anchorInEditor.focus(); + is(focused, true, "focus didn't move to element in contenteditable=false"); + is(isReallyEditable(), false, "can edit by a key event"); + + // for bug 502273 + focused = false; + anchor.focus(); + editor.setAttribute("dummy", "dummy"); + editor.removeAttribute("dummy"); + anchorInEditor.focus(); + is(focused, true, "focus moved to element in contenteditable=true (after dummy attribute was removed)"); + is(isReallyEditable(), false, "cannot edit by a key event"); + + focused = false; + anchor.focus(); + editor.setAttribute("contenteditable", "true"); + anchorInEditor.focus(); + is(focused, false, "focus moved to element in contenteditable=true"); + is(isReallyEditable(), true, "cannot edit by a key event"); + + // for bug 502273 + focused = false; + anchor.focus(); + editor.setAttribute("dummy", "dummy"); + editor.removeAttribute("dummy"); + anchorInEditor.focus(); + is(focused, false, "focus moved to element in contenteditable=true (after dummy attribute was removed)"); + is(isReallyEditable(), true, "cannot edit by a key event"); + + focused = false; + anchor.focus(); + editor.removeAttribute("contenteditable"); + anchorInEditor.focus(); + is(focused, true, "focus didn't move to element in contenteditable removed element"); + is(isReallyEditable(), false, "can edit by a key event"); + + focused = false; + anchor.focus(); + editor.contentEditable = true; + anchorInEditor.focus(); + is(focused, false, "focus moved to element in contenteditable=true by property"); + is(isReallyEditable(), true, "cannot edit by a key event"); + + focused = false; + anchor.focus(); + editor.contentEditable = false; + anchorInEditor.focus(); + is(focused, true, "focus didn't move to element in contenteditable=false by property"); + is(isReallyEditable(), false, "can edit by a key event"); + + focused = false; + anchor.focus(); + editor.setAttribute("contenteditable", "true"); + anchorInEditor.focus(); + is(focused, false, "focus moved to element in contenteditable=true"); + is(isReallyEditable(), true, "cannot edit by a key event"); + + // for bug 502273 + focused = false; + anchor.focus(); + editor.setAttribute("dummy", "dummy"); + editor.removeAttribute("dummy"); + anchorInEditor.focus(); + is(focused, false, "focus moved to element in contenteditable=true (after dummy attribute was removed)"); + is(isReallyEditable(), true, "cannot edit by a key event"); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTest); +addLoadEvent(SimpleTest.finish); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug463104.html b/dom/html/test/test_bug463104.html new file mode 100644 index 0000000000..c44419120d --- /dev/null +++ b/dom/html/test/test_bug463104.html @@ -0,0 +1,25 @@ +<!DOCTYPE html>
+<html>
+<head>
+<title>Noninteger coordinates test</title>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<div id="a" style="position: fixed; left: 5.5px; top: 5.5px; width: 100px; height: 100px; background: blue"></div>
+<p style="margin-top: 110px">
+<script>
+var a = document.getElementById("a");
+isnot(a, document.elementFromPoint(5, 5), "a shouldn't be found");
+isnot(a, document.elementFromPoint(5.25, 5.25), "a shouldn't be found");
+is(a, document.elementFromPoint(5.5, 5.5), "a should be found");
+is(a, document.elementFromPoint(5.75, 5.75), "a should be found");
+is(a, document.elementFromPoint(6, 6), "a should be found");
+is(a, document.elementFromPoint(105, 105), "a should be found");
+is(a, document.elementFromPoint(105.25, 105.25), "a should be found");
+isnot(a, document.elementFromPoint(105.5, 105.5), "a shouldn't be found");
+isnot(a, document.elementFromPoint(105.75, 105.75), "a shouldn't be found");
+isnot(a, document.elementFromPoint(106, 106), "a shouldn't be found");
+</script>
+</body>
+</html>
diff --git a/dom/html/test/test_bug478251.html b/dom/html/test/test_bug478251.html new file mode 100644 index 0000000000..e33e7b04e2 --- /dev/null +++ b/dom/html/test/test_bug478251.html @@ -0,0 +1,74 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=478251 +--> +<head> + <title>Test for Bug 478251</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=478251">Mozilla Bug 478251</a> +<p id="display"><iframe id="t"></iframe></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 478251 **/ +var doc = $("t").contentDocument; +doc.open(); +doc.write(); +doc.close(); +is(doc.documentElement.textContent, "", "Writing || failed"); + +doc.open(); +doc.write(null); +doc.close(); +is(doc.documentElement.textContent, "null", "Writing |null| failed"); + +doc.open(); +doc.write(null, null); +doc.close(); +is(doc.documentElement.textContent, "nullnull", "Writing |null, null| failed"); + +doc.open(); +doc.write(undefined); +doc.close(); +is(doc.documentElement.textContent, "undefined", "Writing |undefined| failed"); + +doc.open(); +doc.write(undefined, undefined); +doc.close(); +is(doc.documentElement.textContent, "undefinedundefined", "Writing |undefined, undefined| failed"); + +doc.open(); +doc.writeln(); +doc.close(); +ok(doc.documentElement.textContent == "\n" || doc.documentElement.textContent == "", "Writing |\\n| failed"); + +doc.open(); +doc.writeln(null); +doc.close(); +is(doc.documentElement.textContent, "null\n", "Writing |null\\n| failed"); + +doc.open(); +doc.writeln(null, null); +doc.close(); +is(doc.documentElement.textContent, "nullnull\n", "Writing |null, null\\n| failed"); + +doc.open(); +doc.writeln(undefined); +doc.close(); +is(doc.documentElement.textContent, "undefined\n", "Writing |undefined\\n| failed"); + +doc.open(); +doc.writeln(undefined, undefined); +doc.close(); +is(doc.documentElement.textContent, "undefinedundefined\n", "Writing |undefined, undefined\\n| failed"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug481335.xhtml b/dom/html/test/test_bug481335.xhtml new file mode 100644 index 0000000000..8fdd145222 --- /dev/null +++ b/dom/html/test/test_bug481335.xhtml @@ -0,0 +1,122 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=481335 +--> +<head> + <title>Test for Bug 481335</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style type="text/css"> + a { color:blue; } + a:visited { color:red; } + </style> + <base href="https://example.com/" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=481335">Mozilla Bug 481335</a> +<p id="display"> + <a id="t">A link</a> + <iframe id="i"></iframe> +</p> +<p id="newparent"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript"> +<![CDATA[ + +/** Test for Bug 481335 **/ +SimpleTest.waitForExplicitFinish(); +var rand = Date.now() + "-" + Math.random(); + +is($("t").href, "", + "Unexpected href before set"); +is($("t").href, "", + "Unexpected cached href before set"); + +$("t").setAttribute("href", rand); +is($("t").href, "https://example.com/" + rand, + "Unexpected href after set"); +is($("t").href, "https://example.com/" + rand, + "Unexpected cached href after set"); +const unvisitedColor = "rgb(0, 0, 255)"; +const visitedColor = "rgb(255, 0, 0)"; + +let tests = testIterator(); +function continueTest() { + tests.next(); +} + +function checkLinkColor(aElmId, aExpectedColor, aMessage) { + // Because link coloring is asynchronous, we wait until we get the right + // result, or we will time out (resulting in a failure). + function getColor() { + var utils = SpecialPowers.getDOMWindowUtils(window); + return utils.getVisitedDependentComputedStyle($(aElmId), "", "color"); + } + while (getColor() != aExpectedColor) { + requestIdleCallback(continueTest); + return false; + } + is(getColor(), aExpectedColor, aMessage); + return true; +} + +let win; + +function* testIterator() { + // After first load + $("newparent").appendChild($("t")); + is($("t").href, "https://example.com/" + rand, + "Unexpected href after move"); + is($("t").href, "https://example.com/" + rand, + "Unexpected cached href after move"); + while (!checkLinkColor("t", unvisitedColor, "Should be unvisited now")) + yield undefined; + + win.close(); + win = window.open($("t").href, "_blank"); + + // After second load + while (!checkLinkColor("t", visitedColor, "Should be visited now")) + yield undefined; + $("t").pathname = rand; + while (!checkLinkColor("t", visitedColor, + "Should still be visited after setting pathname to its existing value")) { + yield undefined; + } + + /* TODO uncomment this test with the landing of bug 534526. See + * https://bugzilla.mozilla.org/show_bug.cgi?id=461199#c167 + $("t").pathname += "x"; + while (!checkLinkColor("t", unvisitedColor, + "Should not be visited after changing pathname")) { + yield undefined; + } + $("t").pathname = $("t").pathname; + while (!checkLinkColor("t", unvisitedColor, + "Should not be visited after setting unvisited pathname to existing value")) { + yield undefined; + } + */ + + win.close(); + win = window.open($("t").href, "_blank"); + + // After third load + while (!checkLinkColor("t", visitedColor, + "Should be visited now after third load")) { + yield undefined; + } + win.close(); + SimpleTest.finish(); +} + +addLoadEvent(function() { + win = window.open($("t").href, "_blank"); + requestIdleCallback(continueTest); +}); +]]> +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug481440.html b/dom/html/test/test_bug481440.html new file mode 100644 index 0000000000..ab26b63e97 --- /dev/null +++ b/dom/html/test/test_bug481440.html @@ -0,0 +1,30 @@ +<!--Test must be in quirks mode for document.all to work--> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=481440 +--> +<head> + <title>Test for Bug 481440</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=481440">Mozilla Bug 481440</a> +<p id="display"></p> +<div id="content" style="display: none"> + <input name="x" id="y"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 481440 **/ +// Do a bunch of getElementById calls to catch hashtables auto-going live +for (var i = 0; i < 500; ++i) { + document.getElementById(i); +} +is(document.all.x, document.getElementById("y"), + "Unexpected node"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug481647.html b/dom/html/test/test_bug481647.html new file mode 100644 index 0000000000..b74fb7997e --- /dev/null +++ b/dom/html/test/test_bug481647.html @@ -0,0 +1,42 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=481647 +--> +<head> + <title>Test for Bug 481647</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=481647">Mozilla Bug 481647</a> +<p id="display"> + <iframe src="javascript:'aaa'"></iframe> + <iframe src="javascript:document.write('aaa'); document.close();"></iframe> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 481647 **/ +SimpleTest.waitForExplicitFinish() + +function testFrame(num) { + is(window.frames[num].document.baseURI, document.baseURI, + "Unexpected base URI in frame " + num); +} + +addLoadEvent(function() { + for (var i = 0; i < 2; ++i) { + testFrame(i); + } + + SimpleTest.finish(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug482659.html b/dom/html/test/test_bug482659.html new file mode 100644 index 0000000000..df2c66a747 --- /dev/null +++ b/dom/html/test/test_bug482659.html @@ -0,0 +1,64 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=482659 +--> +<head> + <title>Test for Bug 482659</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=482659">Mozilla Bug 482659</a> +<p id="display"> + <iframe></iframe> + <iframe src="about:blank"></iframe> + <iframe></iframe> + <iframe src="about:blank"></iframe> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 482659 **/ +SimpleTest.waitForExplicitFinish() + +function testFrame(num) { + is(window.frames[num].document.baseURI, document.baseURI, + "Unexpected base URI in frame " + num); + is(window.frames[num].document.documentURI, "about:blank", + "Unexpected document URI in frame " + num); +} + +function appendScript(doc) { + var s = doc.createElement("script"); + s.textContent = "document.write('executed'); document.close()"; + doc.body.appendChild(s); +} + +function verifyScriptRan(num) { + is(window.frames[num].document.documentElement.textContent, "executed", + "write didn't happen in frame " + num); +} + +addLoadEvent(function() { +/* document.write part of test disabled due to bug 483818 + appendScript(window.frames[2].document); + appendScript(window.frames[3].document); + + verifyScriptRan(2); + verifyScriptRan(3); +*/ + for (var i = 0; i < 4; ++i) { + testFrame(i); + } + + SimpleTest.finish(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug486741.html b/dom/html/test/test_bug486741.html new file mode 100644 index 0000000000..a20cd44e5e --- /dev/null +++ b/dom/html/test/test_bug486741.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=486741 +--> +<head> + <title>Test for Bug 486741</title> + <script type="application/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=486741">Mozilla Bug 486741</a> +<p id="display"><iframe id="f"></iframe></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 486741 **/ +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + var d = $("f").contentDocument; + var root = d.documentElement; + is(root.tagName, "HTML", "Unexpected root"); + + d.open(); + isnot(d.documentElement, root, "Shouldn't have the old root element"); + + d.write("Test"); + d.close(); + + isnot(d.documentElement, root, "Still shouldn't have the old root element"); + is(d.documentElement.tagName, "HTML", "Unexpected new root after write"); + + SimpleTest.finish(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug489532.html b/dom/html/test/test_bug489532.html new file mode 100644 index 0000000000..ac28c35482 --- /dev/null +++ b/dom/html/test/test_bug489532.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=489532 +--> +<head> + <title>Test for Bug 489532</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=489532">Mozilla Bug 489532</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script> +/** Test for Bug 489532 **/ +try { + document.createElement("<div>"); + ok(false, "Should throw.") +} catch (e) { + is(e.name, "InvalidCharacterError", + "Expected InvalidCharacterError."); + ok(e instanceof DOMException, "Expected DOMException."); + is(e.code, DOMException.INVALID_CHARACTER_ERR, + "Expected INVALID_CHARACTER_ERR."); +} +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug497242.xhtml b/dom/html/test/test_bug497242.xhtml new file mode 100644 index 0000000000..943c46ddc9 --- /dev/null +++ b/dom/html/test/test_bug497242.xhtml @@ -0,0 +1,41 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=497242 +--> +<head> + <title>Test for Bug 497242</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=497242">Mozilla Bug 497242</a> +<p id="display"></p> +<div id="content" style="display: none"> + <form name="foo"/> + <form name="foo"/> + <form name="bar"/> + <form name="bar" xmlns=""/> +</div> +<pre id="test"> +<script type="application/javascript"> +<![CDATA[ + +/** Test for Bug 497242 **/ +is(document.getElementsByName("foo").length, 2, + "Should find both forms with name 'foo'"); +is(document.getElementsByName("foo")[0], + document.getElementsByTagName("form")[0], + "Unexpected first foo"); +is(document.getElementsByName("foo")[1], + document.getElementsByTagName("form")[1], + "Unexpected second foo"); +is(document.getElementsByName("bar").length, 1, + "Should find only the HTML form with name 'bar'"); +is(document.getElementsByName("bar")[0], + document.getElementsByTagName("form")[2], + "Unexpected bar"); +]]> +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug499092.html b/dom/html/test/test_bug499092.html new file mode 100644 index 0000000000..d5d019bc54 --- /dev/null +++ b/dom/html/test/test_bug499092.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=499092 +--> +<head> + <title>Test for Bug 499092</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=499092">Mozilla Bug 499092</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> +/** Test for Bug 499092 **/ +SimpleTest.waitForExplicitFinish(); +var content = document.getElementById("content"); + +function testHtml() { + is(this.contentDocument.title, "HTML OK"); + SimpleTest.finish(); +} + +function testXml() { + is(this.contentDocument.title, "XML OK"); + var iframeHtml = document.createElement("iframe"); + iframeHtml.onload = testHtml; + iframeHtml.src = "bug499092.html"; + content.appendChild(iframeHtml); +} + +var iframeXml = document.createElement("iframe"); +iframeXml.onload = testXml; +iframeXml.src = "bug499092.xml"; +content.appendChild(iframeXml); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug500885.html b/dom/html/test/test_bug500885.html new file mode 100644 index 0000000000..3ab9225a4c --- /dev/null +++ b/dom/html/test/test_bug500885.html @@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=500885 +--> +<head> + <title>Test for Bug 500885</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="/tests/SimpleTest/paint_listener.js"></script> + <script type="text/javascript" src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=500885">Mozilla Bug 500885</a> +<div> + <input id="file" type="file" /> +</div> +<script type="text/javascript"> + +var MockFilePicker = SpecialPowers.MockFilePicker; +MockFilePicker.init(window); +MockFilePicker.returnValue = MockFilePicker.returnOK; + +async function test() { + // SpecialPowers.DOMWindowUtils doesn't appear to fire mouseEvents correctly + var wu = SpecialPowers.getDOMWindowUtils(window); + + try { + var domActivateEvents; + var fileInput = document.getElementById("file"); + var rect = fileInput.getBoundingClientRect(); + + fileInput.addEventListener ("DOMActivate", function (e) { + ok("detail" in e, "DOMActivate should have .detail"); + is(e.detail, 1, ".detail should be 1"); + domActivateEvents++; + }); + + fileInput.scrollIntoView({ behaviour: "smooth" }); + await promiseApzFlushedRepaints(); + + domActivateEvents = 0; + wu.sendMouseEvent("mousedown", rect.left + 5, rect.top + 5, 0, 1, 0); + wu.sendMouseEvent("mouseup", rect.left + 5, rect.top + 5, 0, 1, 0); + is(domActivateEvents, 1, "click on button should fire 1 DOMActivate event"); + + domActivateEvents = 0; + wu.sendMouseEvent("mousedown", rect.right - 5, rect.top + 5, 0, 1, 0); + wu.sendMouseEvent("mouseup", rect.right - 5, rect.top + 5, 0, 1, 0); + is(domActivateEvents, 1, "click on text field should fire 1 DOMActivate event"); + } finally { + SimpleTest.executeSoon(function() { + MockFilePicker.cleanup(); + SimpleTest.finish(); + }); + } +} + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(test); + +</script> +</body> + +</html> diff --git a/dom/html/test/test_bug512367.html b/dom/html/test/test_bug512367.html new file mode 100644 index 0000000000..35af18a5a1 --- /dev/null +++ b/dom/html/test/test_bug512367.html @@ -0,0 +1,40 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=512367 +--> +<head> + <title>Test for Bug 512367</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=512367">Mozilla Bug 512367</a> +<p id="display"> + <iframe src="bug369370-popup.png" id="i" style="width:200px; height:200px"></iframe> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +var frame = document.getElementById("i"); + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + SpecialPowers.setFullZoom(frame.contentWindow, 1.5); + + setTimeout(function() { + synthesizeMouse(frame, 30, 30, {}); + + is(SpecialPowers.getFullZoom(frame.contentWindow), 1.5, "Zoom in the image frame should not have been reset"); + + SimpleTest.finish(); + }, 0); +}); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug514856.html b/dom/html/test/test_bug514856.html new file mode 100644 index 0000000000..77b8feecbd --- /dev/null +++ b/dom/html/test/test_bug514856.html @@ -0,0 +1,61 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=514856 +--> +<head> + <title>Test for Bug 514856</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=514856">Mozilla Bug 514856</a> +<p id="display"></p> +<div id="content"> + <iframe id="testFrame" src="bug514856_iframe.html"></iframe> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 514856 **/ + +function beginTest() { + var ifr = document.getElementById("testFrame"); + var win = ifr.contentWindow; + + // After the click, the load event should be fired. + ifr.addEventListener('load', function() { + testDone(); + }); + + // synthesizeMouse adds getBoundingClientRect left and top to the offsets but + // in that particular case, we don't want that. + var rect = ifr.getBoundingClientRect(); + var left = rect.left; + var top = rect.top; + + synthesizeMouse(ifr, 10 - left, 10 - top, { type: "mousemove" }, win); + synthesizeMouse(ifr, 12 - left, 12 - top, { type: "mousemove" }, win); + synthesizeMouse(ifr, 14 - left, 14 - top, { type: "mousemove" }, win); + synthesizeMouse(ifr, 16 - left, 16 - top, { }, win); +} + +function testDone() { + var ifr = document.getElementById("testFrame"); + var url = new String(ifr.contentWindow.location); + + is(url.indexOf("?10,10"), -1, "Shouldn't have ?10,10 in the URL!"); + is(url.indexOf("?12,12"), -1, "Shouldn't have ?12,12 in the URL!"); + is(url.indexOf("?14,14"), -1, "Shouldn't have ?14,14 in the URL!"); + isnot(url.indexOf("?16,16"), -1, "Should have ?16,16 in the URL!"); + SimpleTest.finish(); +} + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(beginTest); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug518122.html b/dom/html/test/test_bug518122.html new file mode 100644 index 0000000000..acb9d78d0a --- /dev/null +++ b/dom/html/test/test_bug518122.html @@ -0,0 +1,126 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=518122 +--> +<head> + <title>Test for Bug 518122</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=518122">Mozilla Bug 518122</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 518122 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTests); + +var simple_tests = [ ["foo", "foo"], + ["", ""], + [null, ""], + [undefined , "undefined"], + ["\n", "\n"], + ["\r", "\n"], + ["\rfoo", "\nfoo"], + ["foo\r", "foo\n"], + ["foo\rbar", "foo\nbar"], + ["foo\rbar\r", "foo\nbar\n"], + ["\r\n", "\n"], + ["\r\nfoo", "\nfoo"], + ["foo\r\n", "foo\n"], + ["foo\r\nbar", "foo\nbar"], + ["foo\r\nbar\r\n", "foo\nbar\n"] ]; + +var value_append_tests = [ ["foo", "bar", "foobar"], + ["foo", "foo", "foofoo"], + ["foobar", "bar", "foobarbar"], + ["foobar", "foo", "foobarfoo"], + ["foo\n", "foo", "foo\nfoo"], + ["foo\r", "foo", "foo\nfoo"], + ["foo\r\n", "foo", "foo\nfoo"], + ["\n", "\n", "\n\n"], + ["\r", "\r", "\n\n"], + ["\r\n", "\r\n", "\n\n"], + ["\r", "\r\n", "\n\n"], + ["\r\n", "\r", "\n\n"], + [null, null, "null"], + [null, undefined, "undefined"], + ["", "", ""] + ]; + + +var simple_tests_for_input = [ ["foo", "foo"], + ["", ""], + [null, ""], + [undefined , "undefined"], + ["\n", ""], + ["\r", ""], + ["\rfoo", "foo"], + ["foo\r", "foo"], + ["foo\rbar", "foobar"], + ["foo\rbar\r", "foobar"], + ["\r\n", ""], + ["\r\nfoo", "foo"], + ["foo\r\n", "foo"], + ["foo\r\nbar", "foobar"], + ["foo\r\nbar\r\n", "foobar"] ]; + +var value_append_tests_for_input = [ ["foo", "bar", "foobar"], + ["foo", "foo", "foofoo"], + ["foobar", "bar", "foobarbar"], + ["foobar", "foo", "foobarfoo"], + ["foo\n", "foo", "foofoo"], + ["foo\r", "foo", "foofoo"], + ["foo\r\n", "foo", "foofoo"], + ["\n", "\n", ""], + ["\r", "\r", ""], + ["\r\n", "\r\n", ""], + ["\r", "\r\n", ""], + ["\r\n", "\r", ""], + [null, null, "null"], + [null, undefined, "undefined"], + ["", "", ""] + ]; +function runTestsFor(el, simpleTests, appendTests) { + for(var i = 0; i < simpleTests.length; ++i) { + el.value = simpleTests[i][0]; + is(el.value, simpleTests[i][1], "Wrong value (wrap=" + el.getAttribute('wrap') + ", simple_test=" + i + ")"); + } + for (var j = 0; j < appendTests.length; ++j) { + el.value = appendTests[j][0]; + el.value += appendTests[j][1]; + is(el.value, appendTests[j][2], "Wrong value (wrap=" + el.getAttribute('wrap') + ", value_append_test=" + j + ")"); + } +} + +function runTests() { + var textareas = document.getElementsByTagName("textarea"); + for (var i = 0; i < textareas.length; ++i) { + runTestsFor(textareas[i], simple_tests, value_append_tests); + } + var input = document.getElementsByTagName("input")[0]; + runTestsFor(input, simple_tests_for_input, value_append_tests_for_input); + // initialize the editor + input.focus(); + input.blur(); + runTestsFor(input, simple_tests_for_input, value_append_tests_for_input); + SimpleTest.finish(); +} + + +</script> +</pre> +<textarea cols="30" rows="7" wrap="none"></textarea> +<textarea cols="30" rows="7" wrap="off"></textarea><br> +<textarea cols="30" rows="7" wrap="soft"></textarea> +<textarea cols="30" rows="7" wrap="hard"></textarea> +<input type="text"> +</body> +</html> diff --git a/dom/html/test/test_bug519987.html b/dom/html/test/test_bug519987.html new file mode 100644 index 0000000000..875368c9b0 --- /dev/null +++ b/dom/html/test/test_bug519987.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=519987 +--> +<head> + <title>Test for Bug 519987</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=519987">Mozilla Bug 519987</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 519987 **/ +var xmlns = 'http://www.w3.org/1999/xhtml'; +is((new Image()).namespaceURI, xmlns, "Unexpected namespace for new Image()"); +is((new Audio()).namespaceURI, xmlns, "Unexpected namespace for new Audio()"); +var titles = document.getElementsByTagName("title"); +var t = titles[0]; +t.remove(); +document.title = "abcdefg"; +is(titles[0].namespaceURI, xmlns, "Unexpected namespace for new <title>"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug523771.html b/dom/html/test/test_bug523771.html new file mode 100644 index 0000000000..9f6af3de76 --- /dev/null +++ b/dom/html/test/test_bug523771.html @@ -0,0 +1,106 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=523771 +--> +<head> + <title>Test for Bug 523771</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=523771">Mozilla Bug 523771</a> +<p id="display"></p> +<iframe name="target_iframe" id="target_iframe"></iframe> +<form action="form_submit_server.sjs" target="target_iframe" id="form" +method="POST" enctype="multipart/form-data"> + <input id=singleFile name=singleFile type=file> + <input id=multiFile name=multiFile type=file multiple> +</form> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +singleFileInput = document.getElementById('singleFile'); +multiFileInput = document.getElementById('multiFile'); +var input1File = { name: "523771_file1", type: "", body: "file1 contents"}; +var input2Files = + [{ name: "523771_file2", type: "", body: "second file contents" }, + { name: "523771_file3.txt", type: "text/plain", body: "123456" }, + { name: "523771_file4.html", type: "text/html", body: "<html>content</html>" } + ]; + +SimpleTest.waitForExplicitFinish(); + +function setFileInputs () { + var f = createFileWithData(input1File.name, input1File.body, input1File.type); + SpecialPowers.wrap(singleFileInput).mozSetFileArray([f]); + + var input2FileNames = []; + for (file of input2Files) { + f = createFileWithData(file.name, file.body, file.type); + input2FileNames.push(f); + } + SpecialPowers.wrap(multiFileInput).mozSetFileArray(input2FileNames); +} + +function createFileWithData(fileName, fileData, fileType) { + return new File([fileData], fileName, { type: fileType }); +} + +function cleanupFiles() { + singleFileInput.value = ""; + multiFileInput.value = ""; +} + +is(singleFileInput.files.length, 0, "single-file .files.length"); // bug 524421 +is(multiFileInput.files.length, 0, "multi-file .files.length"); // bug 524421 + +setFileInputs(); + +is(singleFileInput.multiple, false, "single-file input .multiple"); +is(multiFileInput.multiple, true, "multi-file input .multiple"); +is(singleFileInput.value, 'C:\\fakepath\\' + input1File.name, "single-file input .value"); +is(multiFileInput.value, 'C:\\fakepath\\' + input2Files[0].name, "multi-file input .value"); +is(singleFileInput.files[0].name, input1File.name, "single-file input .files[n].name"); +is(singleFileInput.files[0].size, input1File.body.length, "single-file input .files[n].size"); +is(singleFileInput.files[0].type, input1File.type, "single-file input .files[n].type"); +for(i = 0; i < input2Files.length; ++i) { + is(multiFileInput.files[i].name, input2Files[i].name, "multi-file input .files[n].name"); + is(multiFileInput.files[i].size, input2Files[i].body.length, "multi-file input .files[n].size"); + is(multiFileInput.files[i].type, input2Files[i].type, "multi-file input .files[n].type"); +} + +document.getElementById('form').submit(); +iframe = document.getElementById('target_iframe'); +iframe.onload = function() { + response = JSON.parse(iframe.contentDocument.documentElement.textContent); + is(response[0].headers["Content-Disposition"], + "form-data; name=\"singleFile\"; filename=\"" + input1File.name + + "\"", + "singleFile Content-Disposition"); + is(response[0].headers["Content-Type"], input1File.type || "application/octet-stream", + "singleFile Content-Type"); + is(response[0].body, input1File.body, "singleFile body"); + + for(i = 0; i < input2Files.length; ++i) { + is(response[i + 1].headers["Content-Disposition"], + "form-data; name=\"multiFile\"; filename=\"" + input2Files[i].name + + "\"", + "multiFile Content-Disposition"); + is(response[i + 1].headers["Content-Type"], input2Files[i].type || "application/octet-stream", + "multiFile Content-Type"); + is(response[i + 1].body, input2Files[i].body, "multiFile body"); + } + + cleanupFiles(); + + is(singleFileInput.files.length, 0, "single-file .files.length"); // bug 524421 + is(multiFileInput.files.length, 0, "multi-file .files.length"); // bug 524421 + + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug529819.html b/dom/html/test/test_bug529819.html new file mode 100644 index 0000000000..4147a341b2 --- /dev/null +++ b/dom/html/test/test_bug529819.html @@ -0,0 +1,32 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=529819 +--> +<head> + <title>Test for Bug 529819</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=529819">Mozilla Bug 529819</a> +<p id="display"></p> +<div id="content" style="display: none"> +<form id="form"> + <input name="foo" id="foo"> + <input name="bar" type="radio"> + <input name="bar" id="bar" type="radio"> +</form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 529819 **/ +is($("form").elements.foo instanceof HTMLInputElement, true, "Should have an element here"); +is($("form").elements.bar instanceof HTMLInputElement, false, "Should have a list here"); +is($("form").elements.bar.length, 2, "Should have a list with two elements here"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug529859.html b/dom/html/test/test_bug529859.html new file mode 100644 index 0000000000..9d607c8a22 --- /dev/null +++ b/dom/html/test/test_bug529859.html @@ -0,0 +1,42 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=529859 +--> +<head> + <title>Test for Bug 529859</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=529859">Mozilla Bug 529859</a> +<div id="content"> + <iframe name="target_iframe" id="target_iframe"></iframe> + <form action="form_submit_server.sjs" target="target_iframe" id="form" + method="POST" enctype="multipart/form-data"> + <input id="emptyFileInput" name="emptyFileInput" type="file"> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 529859 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + $("target_iframe").onload = function() { + var response = JSON.parse(this.contentDocument.documentElement.textContent); + is(response.length, 1, "Unexpected number of inputs"); + is(response[0].headers["Content-Disposition"], + "form-data; name=\"emptyFileInput\"; filename=\"\"", + "Incorrect content-disposition"); + is(response[0].headers["Content-Type"], "application/octet-stream", + "Unexpected content-type"); + SimpleTest.finish(); + } + $("form").submit(); +}); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug535043.html b/dom/html/test/test_bug535043.html new file mode 100644 index 0000000000..3eb046b3c5 --- /dev/null +++ b/dom/html/test/test_bug535043.html @@ -0,0 +1,90 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=535043 +--> +<head> + <title>Test for Bug 535043</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=535043">Mozilla Bug 535043</a> +<p id="display"></p> +<div id="content"> + <textarea></textarea> + <textarea maxlength="-1"></textarea> + <textarea maxlength="0"></textarea> + <textarea maxlength="2"></textarea> +</div> +<pre id="test"> +<script type="text/javascript"> + +/** Test for Bug 535043 **/ +function checkTextArea(textArea) { + textArea.value = ''; + textArea.focus(); + for (var j = 0; j < 3; j++) { + sendString("x"); + } + var htmlMaxLength = textArea.getAttribute('maxlength'); + var domMaxLength = textArea.maxLength; + if (htmlMaxLength == null) { + is(domMaxLength, -1, + 'maxlength is unset but maxLength DOM attribute is not -1'); + } else if (htmlMaxLength < 0) { + // Per the HTML5 spec, out-of-range values are supposed to translate to -1, + // not 0, but they don't? + is(domMaxLength, -1, + 'maxlength is out of range but maxLength DOM attribute is not -1'); + } else { + is(domMaxLength, parseInt(htmlMaxLength), + 'maxlength in DOM does not match provided value'); + } + if (textArea.maxLength == -1) { + is(textArea.value.length, 3, + 'textarea with maxLength -1 should have no length limit'); + } else { + is(textArea.value.length, textArea.maxLength, 'textarea has maxLength ' + + textArea.maxLength + ' but length ' + textArea.value.length ); + } +} + +SimpleTest.waitForFocus(function() { + var textAreas = document.getElementsByTagName('textarea'); + for (var i = 0; i < textAreas.length; i++) { + checkTextArea(textAreas[i]); + } + + textArea = textAreas[0]; + testNums = [-42, -1, 0, 2]; + for (var i = 0; i < testNums.length; i++) { + textArea.removeAttribute('maxlength'); + + var caught = false; + try { + textArea.maxLength = testNums[i]; + } catch (e) { + caught = true; + } + if (testNums[i] < 0) { + ok(caught, 'Setting negative maxLength should throw exception'); + } else { + ok(!caught, 'Setting nonnegative maxLength should not throw exception'); + } + checkTextArea(textArea); + + textArea.setAttribute('maxlength', testNums[i]); + checkTextArea(textArea); + } + + SimpleTest.finish(); +}); + +SimpleTest.waitForExplicitFinish(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug536891.html b/dom/html/test/test_bug536891.html new file mode 100644 index 0000000000..89bb93d1b0 --- /dev/null +++ b/dom/html/test/test_bug536891.html @@ -0,0 +1,67 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=536891 +--> +<head> + <title>Test for Bug 536891</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=536891">Mozilla Bug 536891</a> +<p id="display"></p> +<div id="content" style="display: none"> +<textarea id="t" maxlength="-2" minlength="-2"></textarea> +<input id="i" type="text" maxlength="-2" minlength="-2"> +<input id="p" type="password" maxlength="-2" minlength="-2"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 536891 **/ + +function checkNegativeMinMaxLength(element) +{ + for(let type of ["min", "max"]) { + /* value is set to -2 initially in the document, see above */ + is(element[type + "Length"], -1, "negative " + type + "Length should be considered invalid and represented as -1"); + + // changing the property to an negative value should throw (see bug 536895). + for(let value of [-15, -2147483648]) { // PR_INT32_MIN + let threw = false; + try { + element[type + "Length"] = value; + } catch(e) { + threw = true; + } + is(threw, true, "setting " + type + "Length property to " + value + " should throw"); + } + element[type + "Length"] = "non-numerical value"; + is(element[type + "Length"], 0, "setting " + type + "Length property to a non-numerical value should set it to zero"); + + + element.setAttribute(type + 'Length', -15); + is(element[type + "Length"], -1, "negative " + type + "Length is not processed correctly when set dynamically"); + is(element.getAttribute(type + 'Length'), "-15", type + "Length attribute doesn't return the correct value"); + + element.setAttribute(type + 'Length', 0); + is(element[type + "Length"], 0, "zero " + type + "Length is not processed correctly"); + element.setAttribute(type + 'Length', 2147483647); // PR_INT32_MAX + is(element[type + "Length"], 2147483647, "negative " + type + "Length is not processed correctly"); + element.setAttribute(type + 'Length', -2147483648); // PR_INT32_MIN + is(element[type + "Length"], -1, "negative " + type + "Length is not processed correctly"); + element.setAttribute(type + 'Length', 'non-numerical-value'); + is(element[type + "Length"], -1, "non-numerical value should be considered invalid and represented as -1"); + } +} + +/* TODO: correct behavior may be checked for email, telephone, url and search input types */ +checkNegativeMinMaxLength(document.getElementById('t')); +checkNegativeMinMaxLength(document.getElementById('i')); +checkNegativeMinMaxLength(document.getElementById('p')); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug536895.html b/dom/html/test/test_bug536895.html new file mode 100644 index 0000000000..c135432260 --- /dev/null +++ b/dom/html/test/test_bug536895.html @@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=536895 +--> +<head> + <title>Test for Bug 536895</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=536895">Mozilla Bug 536895</a> +<p id="display"></p> +<div id="content" style="display: none"> +<textarea id="t"></textarea> +<input id="i" type="text"> +<input id="p" type="password"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 536895 **/ + +function checkNegativeMaxLengthException(element) +{ + caught = false; + try { + element.setAttribute('maxLength', -10); + } catch(e) { + caught = true; + } + ok(!caught, "Setting maxLength attribute to a negative value shouldn't throw an exception"); + + caught = false; + try { + element.maxLength = -20; + } catch(e) { + is(e.name, "IndexSizeError", "Should be an IndexSizeError exception"); + caught = true; + } + ok(caught, "Setting negative maxLength from the DOM should throw an exception"); + + is(element.getAttribute('maxLength'), "-10", "When the exception is raised, the maxLength attribute shouldn't change"); +} + +/* TODO: correct behavior may be checked for email, telephone, url and search input types */ +checkNegativeMaxLengthException(document.getElementById('t')); +checkNegativeMaxLengthException(document.getElementById('i')); +checkNegativeMaxLengthException(document.getElementById('p')); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug546995.html b/dom/html/test/test_bug546995.html new file mode 100644 index 0000000000..ff4d80ec45 --- /dev/null +++ b/dom/html/test/test_bug546995.html @@ -0,0 +1,40 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=546995 +--> +<head> + <title>Test for Bug 546995</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=546995">Mozilla Bug 546995</a> +<p id="display"></p> +<div id="content" style="display: none"> + <select id='s'></select> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 546995 **/ + +/* This test in only testing IDL reflection, another one is testing the behavior */ + +function checkAutofocusIDLAttribute(element) +{ + ok('autofocus' in element, "Element has the autofocus IDL attribute"); + ok(!element.autofocus, "autofocus default value is false"); + element.setAttribute('autofocus', 'autofocus'); + ok(element.autofocus, "autofocus should be enabled"); + element.removeAttribute('autofocus'); + ok(!element.autofocus, "autofocus should be disabled"); +} + +// TODO: keygen should be added when correctly implemented, see bug 101019. +checkAutofocusIDLAttribute(document.getElementById('s')); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug547850.html b/dom/html/test/test_bug547850.html new file mode 100644 index 0000000000..a2e0323ec8 --- /dev/null +++ b/dom/html/test/test_bug547850.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=547850 +--> +<head> + <title>Test for Bug 547850</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=547850">Mozilla Bug 547850</a> +<script> +document.write("<div id=content><f\u00c5></f\u00c5><r\u00e5></r\u00e5>"); +document.write("<span g\u00c5=a1 t\u00e5=a2></span></div>"); +</script> +<pre id="test"> +<script class="testbody" type="text/javascript"> +var ch = $('content').childNodes; +is(ch[0].localName, "f\u00c5", "upper case localName"); +is(ch[1].localName, "r\u00e5", "lower case localName"); +is(ch[0].nodeName, "F\u00c5", "upper case nodeName"); +is(ch[1].nodeName, "R\u00e5", "lower case nodeName"); +is(ch[0].tagName, "F\u00c5", "upper case tagName"); +is(ch[1].tagName, "R\u00e5", "lower case tagName"); +is(ch[2].getAttribute("g\u00c5"), "a1", "upper case attr name"); +is(ch[2].getAttribute("t\u00e5"), "a2", "lower case attr name"); +is(ch[2].getAttribute("G\u00c5"), "a1", "upper case attr name"); +is(ch[2].getAttribute("T\u00e5"), "a2", "lower case attr name"); +is(ch[2].getAttribute("g\u00e5"), null, "wrong lower case attr name"); +is(ch[2].getAttribute("t\u00c5"), null, "wrong upper case attr name"); +is($('content').getElementsByTagName("f\u00c5")[0], ch[0], "gEBTN upper case"); +is($('content').getElementsByTagName("f\u00c5").length, 1, "gEBTN upper case length"); +is($('content').getElementsByTagName("r\u00e5")[0], ch[1], "gEBTN lower case"); +is($('content').getElementsByTagName("r\u00e5").length, 1, "gEBTN lower case length"); +is($('content').getElementsByTagName("F\u00c5")[0], ch[0], "gEBTN upper case"); +is($('content').getElementsByTagName("F\u00c5").length, 1, "gEBTN upper case length"); +is($('content').getElementsByTagName("R\u00e5")[0], ch[1], "gEBTN lower case"); +is($('content').getElementsByTagName("R\u00e5").length, 1, "gEBTN lower case length"); +is($('content').getElementsByTagName("f\u00e5").length, 0, "gEBTN wrong upper case"); +is($('content').getElementsByTagName("r\u00c5").length, 0, "gEBTN wrong lower case"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug551846.html b/dom/html/test/test_bug551846.html new file mode 100644 index 0000000000..4950b1e452 --- /dev/null +++ b/dom/html/test/test_bug551846.html @@ -0,0 +1,164 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=551846 +--> +<head> + <title>Test for Bug 551846</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=551846">Mozilla Bug 551846</a> +<p id="display"></p> +<div id="content" style="display: none"> + <select id='s'> + <option>Tulip</option> + <option>Lily</option> + <option>Gagea</option> + <option>Snowflake</option> + <option>Ismene</option> + </select> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 551846 **/ + +function checkSizeReflection(element, defaultValue) +{ + is(element.size, defaultValue, "Default size should be " + defaultValue); + + element.setAttribute('size', -15); + is(element.size, defaultValue, + "The reflecting IDL attribute should return the default value when content attribute value is invalid"); + is(element.getAttribute('size'), "-15", + "The content attribute should containt the previously set value"); + + element.setAttribute('size', 0); + is(element.size, 0, + "0 should be considered as a valid value"); + is(element.getAttribute('size'), "0", + "The content attribute should containt the previously set value"); + + element.setAttribute('size', 2147483647); /* PR_INT32_MAX */ + is(element.size, 2147483647, + "PR_INT32_MAX should be considered as a valid value"); + is(element.getAttribute('size'), "2147483647", + "The content attribute should containt the previously set value"); + + element.setAttribute('size', -2147483648); /* PR_INT32_MIN */ + is(element.size, defaultValue, + "The reflecting IDL attribute should return the default value when content attribute value is invalid"); + is(element.getAttribute('size'), "-2147483648", + "The content attribute should containt the previously set value"); + + element.setAttribute('size', 'non-numerical-value'); + is(element.size, defaultValue, + "The reflecting IDL attribute should return the default value when content attribute value is invalid"); + is(element.getAttribute('size'), 'non-numerical-value', + "The content attribute should containt the previously set value"); + + element.setAttribute('size', 4294967294); /* PR_INT32_MAX * 2 */ + is(element.size, defaultValue, + "Value greater than PR_INT32_MAX should be considered as invalid"); + is(element.getAttribute('size'), "4294967294", + "The content attribute should containt the previously set value"); + + element.setAttribute('size', -4294967296); /* PR_INT32_MIN * 2 */ + is(element.size, defaultValue, + "The reflecting IDL attribute should return the default value when content attribute value is invalid"); + is(element.getAttribute('size'), "-4294967296", + "The content attribute should containt the previously set value"); + + element.size = defaultValue + 1; + element.removeAttribute('size'); + is(element.size, defaultValue, + "When the attribute is removed, the size should be the default size"); + + element.setAttribute('size', 'foobar'); + is(element.size, defaultValue, + "The reflecting IDL attribute should return the default value when content attribute value is invalid"); + element.removeAttribute('size'); + is(element.size, defaultValue, + "When the attribute is removed, the size should be the default size"); +} + +function checkSetSizeException(element) +{ + var caught = false; + + try { + element.size = 1; + } catch(e) { + caught = true; + } + ok(!caught, "Setting a positive size shouldn't throw an exception"); + + caught = false; + try { + element.size = 0; + } catch(e) { + caught = true; + } + ok(!caught, "Setting a size to 0 from the IDL shouldn't throw an exception"); + + element.size = 1; + + caught = false; + try { + element.size = -1; + } catch(e) { + caught = true; + } + ok(!caught, "Setting a negative size from the IDL shouldn't throw an exception"); + + is(element.size, 0, "The size should now be equal to the minimum non-negative value"); + + caught = false; + try { + element.setAttribute('size', -10); + } catch(e) { + caught = true; + } + ok(!caught, "Setting an invalid size in the content attribute shouldn't throw an exception"); + + // reverting to defalut + element.removeAttribute('size'); +} + +function checkSizeWhenChangeMultiple(element, aDefaultNonMultiple, aDefaultMultiple) +{ + s.setAttribute('size', -1) + is(s.size, aDefaultNonMultiple, "Size IDL attribute should be 1"); + + s.multiple = true; + is(s.size, aDefaultMultiple, "Size IDL attribute should be 4"); + + is(s.getAttribute('size'), "-1", "Size content attribute should be -1"); + + s.setAttribute('size', -2); + is(s.size, aDefaultMultiple, "Size IDL attribute should be 4"); + + s.multiple = false; + is(s.size, aDefaultNonMultiple, "Size IDL attribute should be 1"); + + is(s.getAttribute('size'), "-2", "Size content attribute should be -2"); +} + +var s = document.getElementById('s'); + +checkSizeReflection(s, 0); +checkSetSizeException(s); + +s.setAttribute('multiple', 'true'); +checkSizeReflection(s, 0); +checkSetSizeException(s); +s.removeAttribute('multiple'); + +checkSizeWhenChangeMultiple(s, 0, 0); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug555567.html b/dom/html/test/test_bug555567.html new file mode 100644 index 0000000000..0857955275 --- /dev/null +++ b/dom/html/test/test_bug555567.html @@ -0,0 +1,42 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=555567 +--> +<head> + <title>Test for Bug 555567</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=555567">Mozilla Bug 555567</a> +<div id='content' style="display: none"> + <form> + <fieldset> + <legend id="a"></legend> + </fieldset> + <legend id="b"></legend> + </form> + <legend id="c"></legend> +</div> +<pre id="test"> +<p id="display"></p> +<script type="application/javascript"> + +/** Test for Bug 555567 **/ + +var a = document.getElementById('a'); +var b = document.getElementById('b'); +var c = document.getElementById('c'); + +isnot(a.form, null, + "First legend element should have a not null form IDL attribute"); +is(b.form, null, + "Second legend element should have a null form IDL attribute"); +is(c.form, null, + "Third legend element should have a null form IDL attribute"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug556645.html b/dom/html/test/test_bug556645.html new file mode 100644 index 0000000000..3c308f9ef6 --- /dev/null +++ b/dom/html/test/test_bug556645.html @@ -0,0 +1,73 @@ +<html> +<head> + <title>Test for Bug 556645 and Bug 1848196</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<script> +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(async () => { + const object = document.createElement("object"); + object.setAttribute("type", "text/html"); + object.setAttribute("width", "200"); + object.setAttribute("height", "200"); + document.body.appendChild(object); + const promiseLoadObject = new Promise(resolve => { + object.addEventListener("load", resolve, {once: true}); + }); + object.setAttribute("data", "object_bug556645.html"); + await promiseLoadObject; + runTest(object); + object.remove(); + + const embed = document.createElement("embed"); + embed.setAttribute("type", "text/html"); + embed.setAttribute("width", "200"); + embed.setAttribute("height", "200"); + document.body.appendChild(embed); + const promiseLoadEmbed = new Promise(resolve => { + embed.addEventListener("load", resolve, {once: true}); + }); + embed.setAttribute("src", "object_bug556645.html"); + await promiseLoadEmbed; + runTest(embed); + embed.remove(); + + SimpleTest.finish(); +}); + +function runTest(aObjectOrEmbed) +{ + const desc = `<${aObjectOrEmbed.tagName.toLowerCase()}>`; + const childDoc = aObjectOrEmbed.contentDocument || aObjectOrEmbed.getSVGDocument(); + const body = childDoc.body; + is(document.activeElement, document.body, `${desc}: focus in parent before`); + is(childDoc.activeElement, body, `${desc}: focus in child before`); + + const button = childDoc.querySelector("button"); + button.focus(); + childDoc.defaultView.focus(); + is(document.activeElement, aObjectOrEmbed, `${desc}: focus in parent after focus()`); + is(childDoc.activeElement, button, `${desc}: focus in child after focus()`); + + button.blur(); + const pbutton = document.getElementById("pbutton"); + pbutton.focus(); + + synthesizeKey("KEY_Tab"); + is(document.activeElement, aObjectOrEmbed, `${desc}: focus in parent after tab`); + is(childDoc.activeElement, childDoc.documentElement, `${desc}: focus in child after tab`); + + synthesizeKey("KEY_Tab"); + is(document.activeElement, aObjectOrEmbed, `${desc}: focus in parent after tab 2`); + is(childDoc.activeElement, button, `${desc}: focus in child after tab 2`); +} + +</script> + +<button id="pbutton">Parent</button> + +</body> +</html> diff --git a/dom/html/test/test_bug557087-1.html b/dom/html/test/test_bug557087-1.html new file mode 100644 index 0000000000..9bd2068e8d --- /dev/null +++ b/dom/html/test/test_bug557087-1.html @@ -0,0 +1,129 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=557087 +--> +<head> + <title>Test for Bug 557087</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557087">Mozilla Bug 557087</a> +<p id="display"></p> +<div id="content"> +</div> +<pre id="test"> +<script> + +/** Test for Bug 557087 **/ + +function checkDisabledAttribute(aFieldset) +{ + ok('disabled' in aFieldset, + "fieldset elements should have the disabled attribute"); + + ok(!aFieldset.disabled, + "fieldset elements disabled attribute should be disabled"); + is(aFieldset.getAttribute('disabled'), null, + "fieldset elements disabled attribute should be disabled"); + + aFieldset.disabled = true; + ok(aFieldset.disabled, + "fieldset elements disabled attribute should be enabled"); + isnot(aFieldset.getAttribute('disabled'), null, + "fieldset elements disabled attribute should be enabled"); + + aFieldset.removeAttribute('disabled'); + aFieldset.setAttribute('disabled', ''); + ok(aFieldset.disabled, + "fieldset elements disabled attribute should be enabled"); + isnot(aFieldset.getAttribute('disabled'), null, + "fieldset elements disabled attribute should be enabled"); + + aFieldset.removeAttribute('disabled'); + ok(!aFieldset.disabled, + "fieldset elements disabled attribute should be disabled"); + is(aFieldset.getAttribute('disabled'), null, + "fieldset elements disabled attribute should be disabled"); +} + +function checkDisabledPseudoClass(aFieldset) +{ + is(document.querySelector(":disabled"), null, + "no elements should have :disabled applied to them"); + + aFieldset.disabled = true; + is(document.querySelector(":disabled"), aFieldset, + ":disabled should apply to fieldset elements"); + + aFieldset.disabled = false; + is(document.querySelector(":disabled"), null, + "no elements should have :disabled applied to them"); +} + +function checkEnabledPseudoClass(aFieldset) +{ + is(document.querySelector(":enabled"), aFieldset, + ":enabled should apply to fieldset elements"); + + aFieldset.disabled = true; + is(document.querySelector(":enabled"), null, + "no elements should have :enabled applied to them"); + + aFieldset.disabled = false; + is(document.querySelector(":enabled"), aFieldset, + ":enabled should apply to fieldset elements"); +} + +function checkFocus(aFieldset) +{ + aFieldset.disabled = true; + aFieldset.setAttribute('tabindex', 1); + + aFieldset.focus(); + + isnot(document.activeElement, aFieldset, + "fieldset can't be focused when disabled"); + aFieldset.removeAttribute('tabindex'); + aFieldset.disabled = false; +} + +function checkClickEvent(aFieldset) +{ + var clickHandled = false; + + aFieldset.disabled = true; + + aFieldset.addEventListener("click", function(aEvent) { + clickHandled = true; + }, {once: true}); + + sendMouseEvent({type:'click'}, aFieldset); + SimpleTest.executeSoon(function() { + ok(clickHandled, "When disabled, fieldset should not prevent click events"); + SimpleTest.finish(); + }); +} + +SimpleTest.waitForExplicitFinish(); + +SpecialPowers.pushPrefEnv({ + set: [["dom.forms.fieldset_disable_only_descendants.enabled", true]] +}).then(() => { + var fieldset = document.createElement("fieldset"); + var content = document.getElementById('content'); + content.appendChild(fieldset); + + checkDisabledAttribute(fieldset); + checkDisabledPseudoClass(fieldset); + checkEnabledPseudoClass(fieldset); + checkFocus(fieldset); + checkClickEvent(fieldset); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug557087-2.html b/dom/html/test/test_bug557087-2.html new file mode 100644 index 0000000000..435e924f84 --- /dev/null +++ b/dom/html/test/test_bug557087-2.html @@ -0,0 +1,363 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=557087 +--> +<head> + <title>Test for Bug 557087</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557087">Mozilla Bug 557087</a> +<p id="display"></p> +<div id="content" style="display:none;"> +</div> +<pre id="test"> +<script> + +/** Test for Bug 557087 **/ + +SimpleTest.waitForExplicitFinish(); + +var elementsPreventingClick = [ "input", "button", "select", "textarea" ]; +var elementsWithClick = [ "option", "optgroup", "output", "label", "object", "fieldset" ]; +var gHandled = 0; + +function clickShouldNotHappenHandler(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldNotHappenHandler); + ok(false, "click event should be prevented! (test1)"); + if (++gHandled >= elementsWithClick.length) { + test2(); + } +} + +function clickShouldNotHappenHandler2(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldNotHappenHandler3); + ok(false, "click event should be prevented! (test2)"); + if (++gHandled >= elementsWithClick.length) { + test3(); + } +} + +function clickShouldNotHappenHandler5(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldNotHappenHandler5); + ok(false, "click event should be prevented! (test5)"); + if (++gHandled >= elementsWithClick.length) { + test6(); + } +} + +function clickShouldNotHappenHandler7(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldNotHappenHandler7); + ok(false, "click event should be prevented! (test7)"); + if (++gHandled >= elementsWithClick.length) { + test8(); + } +} + +function clickShouldHappenHandler(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldHappenHandler); + ok(true, "click event has been correctly received (test1)"); + if (++gHandled >= elementsWithClick.length) { + test2(); + } +} + +function clickShouldHappenHandler2(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldHappenHandler2); + ok(true, "click event has been correctly received (test2)"); + if (++gHandled >= elementsWithClick.length) { + test3(); + } +} + +function clickShouldHappenHandler3(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldHappenHandler3); + ok(true, "click event has been correctly received (test3)"); + if (++gHandled >= (elementsWithClick.length + + elementsPreventingClick.length)) { + test4(); + } +} + +function clickShouldHappenHandler4(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldHappenHandler4); + ok(true, "click event has been correctly received (test4)"); + if (++gHandled >= (elementsWithClick.length + + elementsPreventingClick.length)) { + test5(); + } +} + +function clickShouldHappenHandler5(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldHappenHandler5); + ok(true, "click event has been correctly received (test5)"); + if (++gHandled >= elementsWithClick.length) { + test6(); + } +} + +function clickShouldHappenHandler6(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldHappenHandler6); + ok(true, "click event has been correctly received (test6)"); + if (++gHandled >= (elementsWithClick.length + + elementsPreventingClick.length)) { + test7(); + } +} + +function clickShouldHappenHandler7(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldHappenHandler7); + ok(true, "click event has been correctly received (test5)"); + if (++gHandled >= elementsWithClick.length) { + test8(); + } +} + +function clickShouldHappenHandler8(aEvent) +{ + aEvent.target.removeEventListener("click", clickShouldHappenHandler8); + ok(true, "click event has been correctly received (test8)"); + if (++gHandled >= (elementsWithClick.length + + elementsPreventingClick.length)) { + SimpleTest.finish(); + } +} + +var fieldset1 = document.createElement("fieldset"); +var fieldset2 = document.createElement("fieldset"); +var legendA = document.createElement("legend"); +var legendB = document.createElement("legend"); +var content = document.getElementById('content'); +fieldset1.disabled = true; +content.appendChild(fieldset1); +fieldset1.appendChild(fieldset2); + +function clean() +{ + var count = fieldset2.children.length; + for (var i=0; i<count; ++i) { + if (fieldset2.children[i] != legendA && + fieldset2.children[i] != legendB) { + fieldset2.removeChild(fieldset2.children[i]); + } + } +} + +function test1() +{ + gHandled = 0; + + // Initialize children without click expected. + for (var name of elementsPreventingClick) { + var element = document.createElement(name); + fieldset2.appendChild(element); + element.addEventListener("click", clickShouldNotHappenHandler); + sendMouseEvent({type:'click'}, element); + } + + // Initialize children with click expected. + for (var name of elementsWithClick) { + var element = document.createElement(name); + fieldset2.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler); + sendMouseEvent({type:'click'}, element); + } +} + +function test2() +{ + gHandled = 0; + fieldset1.disabled = false; + fieldset2.disabled = true; + + // Initialize children without click expected. + for (var name of elementsPreventingClick) { + var element = document.createElement(name); + fieldset2.appendChild(element); + element.addEventListener("click", clickShouldNotHappenHandler2); + sendMouseEvent({type:'click'}, element); + } + + // Initialize children with click expected. + for (var name of elementsWithClick) { + var element = document.createElement(name); + fieldset2.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler2); + sendMouseEvent({type:'click'}, element); + } +} + +function test3() +{ + gHandled = 0; + fieldset1.disabled = false; + fieldset2.disabled = false; + + // All elements should accept the click. + for (var name of elementsPreventingClick) { + var element = document.createElement(name); + fieldset2.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler3); + sendMouseEvent({type:'click'}, element); + } + + // Initialize children with click expected. + for (var name of elementsWithClick) { + var element = document.createElement(name); + fieldset2.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler3); + sendMouseEvent({type:'click'}, element); + } +} + +function test4() +{ + gHandled = 0; + fieldset1.disabled = false; + fieldset2.disabled = true; + + fieldset2.appendChild(legendA); + + // All elements should accept the click. + for (var name of elementsPreventingClick) { + var element = document.createElement(name); + legendA.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler4); + sendMouseEvent({type:'click'}, element); + } + + // Initialize children with click expected. + for (var name of elementsWithClick) { + var element = document.createElement(name); + legendA.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler4); + sendMouseEvent({type:'click'}, element); + } +} + +function test5() +{ + gHandled = 0; + fieldset2.insertBefore(legendB, legendA); + + // Initialize children without click expected. + for (var name of elementsPreventingClick) { + var element = document.createElement(name); + legendA.appendChild(element); + element.addEventListener("click", clickShouldNotHappenHandler5); + sendMouseEvent({type:'click'}, element); + } + + // Initialize children with click expected. + for (var name of elementsWithClick) { + var element = document.createElement(name); + legendA.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler5); + sendMouseEvent({type:'click'}, element); + } +} + +function test6() +{ + gHandled = 0; + fieldset2.removeChild(legendB); + fieldset1.disabled = true; + fieldset2.disabled = false; + + fieldset1.appendChild(legendA); + legendA.appendChild(fieldset2); + + // All elements should accept the click. + for (var name of elementsPreventingClick) { + var element = document.createElement(name); + fieldset2.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler6); + sendMouseEvent({type:'click'}, element); + } + + // Initialize children with click expected. + for (var name of elementsWithClick) { + var element = document.createElement(name); + fieldset2.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler6); + sendMouseEvent({type:'click'}, element); + } +} + +function test7() +{ + gHandled = 0; + fieldset1.disabled = true; + fieldset2.disabled = false; + + fieldset1.appendChild(fieldset2); + fieldset2.appendChild(legendA); + + // All elements should accept the click. + for (var name of elementsPreventingClick) { + var element = document.createElement(name); + legendA.appendChild(element); + element.addEventListener("click", clickShouldNotHappenHandler7); + sendMouseEvent({type:'click'}, element); + } + + // Initialize children with click expected. + for (var name of elementsWithClick) { + var element = document.createElement(name); + legendA.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler7); + sendMouseEvent({type:'click'}, element); + } +} + +function test8() +{ + gHandled = 0; + fieldset1.disabled = true; + fieldset2.disabled = true; + + fieldset1.appendChild(legendA); + legendA.appendChild(fieldset2); + fieldset2.appendChild(legendB); + + // All elements should accept the click. + for (var name of elementsPreventingClick) { + var element = document.createElement(name); + legendB.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler8); + sendMouseEvent({type:'click'}, element); + } + + // Initialize children with click expected. + for (var name of elementsWithClick) { + var element = document.createElement(name); + legendB.appendChild(element); + element.addEventListener("click", clickShouldHappenHandler8); + sendMouseEvent({type:'click'}, element); + } +} + +SpecialPowers.pushPrefEnv({ + set: [["dom.forms.fieldset_disable_only_descendants.enabled", true]] +}).then(() => { + test1(); +}) + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug557087-3.html b/dom/html/test/test_bug557087-3.html new file mode 100644 index 0000000000..98d0b0de4b --- /dev/null +++ b/dom/html/test/test_bug557087-3.html @@ -0,0 +1,215 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=557087 +--> +<head> + <title>Test for Bug 557087</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557087">Mozilla Bug 557087</a> +<p id="display"></p> +<div id="content"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 557087 **/ + +function checkValueMissing(aElement, aExpected) +{ + var msg = aExpected ? aElement.tagName + " should suffer from value missing" + : aElement.tagName + " should not suffer from value missing" + is(aElement.validity.valueMissing, aExpected, msg); +} + +function checkCandidateForConstraintValidation(aElement, aExpected) +{ + var msg = aExpected ? aElement.tagName + " should be candidate for constraint validation" + : aElement.tagName + " should not be candidate for constraint validation" + is(aElement.willValidate, aExpected, msg); +} + +function checkDisabledPseudoClass(aElement, aDisabled) +{ + var disabledElements = document.querySelectorAll(":disabled"); + var found = false; + + for (var e of disabledElements) { + if (aElement == e) { + found = true; + break; + } + } + + var msg = aDisabled ? aElement.tagName + " should have :disabled applying" + : aElement.tagName + " should not have :disabled applying"; + ok(aDisabled ? found : !found, msg); +} + +function checkEnabledPseudoClass(aElement, aEnabled) +{ + var enabledElements = document.querySelectorAll(":enabled"); + var found = false; + + for (var e of enabledElements) { + if (aElement == e) { + found = true; + break; + } + } + + var msg = aEnabled ? aElement.tagName + " should have :enabled applying" + : aElement.tagName + " should not have :enabled applying"; + ok(aEnabled ? found : !found, msg); +} + +function checkFocus(aElement, aExpected) +{ + aElement.setAttribute('tabindex', 1); + + // We use the focus manager so we can test <label>. + var fm = SpecialPowers.Cc["@mozilla.org/focus-manager;1"] + .getService(SpecialPowers.Ci.nsIFocusManager); + fm.setFocus(aElement, 0); + + if (aExpected) { + is(document.activeElement, aElement, "element should be focused"); + } else { + isnot(document.activeElement, aElement, "element should not be focused"); + } + + aElement.blur(); + aElement.removeAttribute('tabindex'); +} + +var elements = [ "input", "button", "select", "textarea", "fieldset", "option", + "optgroup", "label", "output", "object" ]; + +var testData = { +/* tag name | affected by disabled | test focus | test pseudo-classes | test willValidate */ + "INPUT": [ true, true, true, true, true ], + "BUTTON": [ true, true, true, false, false ], + "SELECT": [ true, true, true, true, false ], + "TEXTAREA": [ true, true, true, true, true ], + "FIELDSET": [ true, true, true, false, false ], + "OPTION": [ false, true, true, false, false ], + "OPTGROUP": [ false, true, true, false, false ], + "OBJECT": [ false, true, false, false, false ], + "LABEL": [ false, true, false, false, false ], + "OUTPUT": [ false, true, false, false, false ], +}; + +/** + * For not candidate elements without disabled attribute and not submittable, + * we only have to check that focus and click works even inside a disabled + * fieldset. + */ +function checkElement(aElement, aDisabled) +{ + var data = testData[aElement.tagName]; + var expected = data[0] ? !aDisabled : true; + + if (data[1]) { + checkFocus(aElement, expected); + } + + if (data[2]) { + checkEnabledPseudoClass(aElement, data[0] ? !aDisabled : true); + checkDisabledPseudoClass(aElement, data[0] ? aDisabled : false); + } + + if (data[3]) { + checkCandidateForConstraintValidation(aElement, expected); + } + + if (data[4]) { + checkValueMissing(aElement, expected); + } +} + +var fieldset1 = document.createElement("fieldset"); +var fieldset2 = document.createElement("fieldset"); +var legendA = document.createElement("legend"); +var legendB = document.createElement("legend"); +var content = document.getElementById('content'); +content.appendChild(fieldset1); +fieldset1.appendChild(fieldset2); +fieldset2.disabled = true; + +for (var data of elements) { + var element = document.createElement(data); + + if (data[4]) { + element.required = true; + } + + fieldset1.disabled = false; + fieldset2.appendChild(element); + + checkElement(element, fieldset2.disabled); + + // Make sure changes are correctly managed. + fieldset2.disabled = false; + checkElement(element, fieldset2.disabled); + fieldset2.disabled = true; + checkElement(element, fieldset2.disabled); + + // Make sure if a fieldset which is not the first fieldset is disabled, the + // elements inside the second fielset are disabled. + fieldset2.disabled = false; + fieldset1.disabled = true; + checkElement(element, fieldset1.disabled); + + // Make sure the state change of the inner fieldset will not confuse. + fieldset2.disabled = true; + fieldset2.disabled = false; + checkElement(element, fieldset1.disabled); + + + /* legend tests */ + + // elements in the first legend of a disabled fieldset should not be disabled. + fieldset2.disabled = true; + fieldset1.disabled = false; + legendA.appendChild(element); + fieldset2.appendChild(legendA); + checkElement(element, false); + + // elements in the second legend should be disabled + fieldset2.insertBefore(legendB, legendA); + checkElement(element, fieldset2.disabled); + fieldset2.removeChild(legendB); + + // Elements in the first legend of a fieldset disabled by another fieldset + // should be disabled. + fieldset1.disabled = true; + checkElement(element, fieldset1.disabled); + + // Elements inside a fieldset inside the first legend of a disabled fieldset + // should not be diasbled. + fieldset2.disabled = false; + fieldset1.appendChild(legendA); + legendA.appendChild(fieldset2); + fieldset2.appendChild(element); + checkElement(element, false); + + // Elements inside the first legend of a disabled fieldset inside the first + // legend of a disabled fieldset should not be disabled. + fieldset2.disabled = false; + fieldset2.appendChild(legendB); + legendB.appendChild(element); + checkElement(element, false); + fieldset2.removeChild(legendB); + fieldset1.appendChild(fieldset2); + + element.remove(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug557087-4.html b/dom/html/test/test_bug557087-4.html new file mode 100644 index 0000000000..72aa0f1dc2 --- /dev/null +++ b/dom/html/test/test_bug557087-4.html @@ -0,0 +1,90 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=557087 +--> +<head> + <title>Test for Bug 557087</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557087">Mozilla Bug 557087</a> +<p id="display"></p> +<div id="content"> + <iframe name='f'></iframe> + <form target='f' action="data:text/html"> + <input type='text' id='a'> + <input type='checkbox' id='b'> + <input type='radio' id='c'> + <fieldset disabled> + <fieldset> + <input type='submit' id='s'> + </fieldset> + </fieldset> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 557087 **/ + +SimpleTest.waitForExplicitFinish(); + +var gExpectedSubmits = 6; +var gSubmitReceived = 0; +var gEnd = false; + +var fieldsets = document.getElementsByTagName("fieldset"); +var form = document.forms[0]; + +form.addEventListener("submit", function() { + ok(gEnd, gEnd ? "expected submit" : "non expected submit"); + if (++gSubmitReceived >= gExpectedSubmits) { + form.removeEventListener("submit", arguments.callee); + SimpleTest.finish(); + } +}); + +var inputs = [ + document.getElementById('a'), + document.getElementById('b'), + document.getElementById('c'), +]; + +function doSubmit() +{ + for (e of inputs) { + e.focus(); + synthesizeKey("KEY_Enter"); + } +} + +SimpleTest.waitForFocus(function() { + doSubmit(); + + fieldsets[1].disabled = true; + fieldsets[0].disabled = false; + doSubmit(); + + fieldsets[0].disabled = false; + fieldsets[1].disabled = false; + + gEnd = true; + doSubmit(); + + // Simple check that we can submit from inside a legend even if the fieldset + // is disabled. + var legend = document.createElement("legend"); + fieldsets[0].appendChild(legend); + fieldsets[0].disabled = true; + legend.appendChild(document.getElementById('s')); + + doSubmit(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug557087-5.html b/dom/html/test/test_bug557087-5.html new file mode 100644 index 0000000000..9d58e0ba93 --- /dev/null +++ b/dom/html/test/test_bug557087-5.html @@ -0,0 +1,94 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=557087 +--> +<head> + <title>Test for Bug 557087</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557087">Mozilla Bug 557087</a> +<p id="display"></p> +<div id="content"> + <iframe name='t'></iframe> + <form target='t' action="dummy_page.html"> + <fieldset disabled> + <fieldset> + <input name='i' value='i'> + <textarea name='t'>t</textarea> + <select name='s'><option>s</option></select> + </fieldset> + </fieldset> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 557087 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTest); + +const BASE_URI = `${location.origin}/tests/dom/html/test/dummy_page.html`; +var testResults = [ + BASE_URI + "?", + BASE_URI + "?", + BASE_URI + "?i=i&t=t&s=s", + BASE_URI + "?i=i&t=t&s=s", +]; +var gTestCount = 0; + +var form = document.forms[0]; +var iframe = document.getElementsByTagName('iframe')[0]; +var fieldsets = document.getElementsByTagName('fieldset'); + +function runTest() +{ + iframe.addEventListener("load", function() { + is(iframe.contentWindow.location.href, testResults[gTestCount], + testResults[gTestCount] + " should have been loaded"); + + switch (++gTestCount) { + case 1: + fieldsets[1].disabled = true; + fieldsets[0].disabled = false; + form.submit(); + SimpleTest.executeSoon(function() { + form.submit() + }); + break; + case 2: + fieldsets[0].disabled = false; + fieldsets[1].disabled = false; + SimpleTest.executeSoon(function() { + form.submit() + }); + break; + case 3: + // Elements inside the first legend of a disabled fieldset are submittable. + fieldsets[0].disabled = true; + fieldsets[1].disabled = true; + var legend = document.createElement("legend"); + fieldsets[0].appendChild(legend); + while (fieldsets[1].firstChild) { + legend.appendChild(fieldsets[1].firstChild); + } + SimpleTest.executeSoon(function() { + form.submit() + }); + break; + default: + iframe.removeEventListener("load", arguments.callee); + SimpleTest.executeSoon(SimpleTest.finish); + } + }); + + form.submit(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug557087-6.html b/dom/html/test/test_bug557087-6.html new file mode 100644 index 0000000000..8d7bf08e5c --- /dev/null +++ b/dom/html/test/test_bug557087-6.html @@ -0,0 +1,44 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=557087 +--> +<head> + <title>Test for Bug 557087</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557087">Mozilla Bug 557087</a> +<p id="display"></p> +<div id="content" style="display: none"> + <fieldset disabled> + <input> + </fieldset> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 557087 **/ + +// Testing random stuff following review comments. + +var fieldset = document.getElementsByTagName("fieldset")[0]; + +is(fieldset.elements.length, 1, + "there should be one element inside the fieldset"); +is(fieldset.elements[0], document.getElementsByTagName("input")[0], + "input should be the element inside the fieldset"); + +document.body.removeChild(document.getElementById('content')); +is(fieldset.querySelector("input:disabled"), fieldset.elements[0], + "the input should still be disabled"); + +fieldset.disabled = false; +is(fieldset.querySelector("input:enabled"), fieldset.elements[0], + "the input should be enabled"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug557620.html b/dom/html/test/test_bug557620.html new file mode 100644 index 0000000000..9a05988963 --- /dev/null +++ b/dom/html/test/test_bug557620.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=557620 +--> +<head> + <title>Test for Bug 557620</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557620">Mozilla Bug 557620</a> +<p id="display"></p> +<div id="content" style="display: none"> + <input type="tel" id='i'> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 557620 **/ + +// More checks are done in test_bug551670.html. + +var tel = document.getElementById('i'); +is(tel.type, 'tel', "input with type='tel' should return 'tel'"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug558788-1.html b/dom/html/test/test_bug558788-1.html new file mode 100644 index 0000000000..5dc4a1f34b --- /dev/null +++ b/dom/html/test/test_bug558788-1.html @@ -0,0 +1,212 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=558788 +--> +<head> + <title>Test for Bug 558788</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + input, textarea { background-color: rgb(0,0,0) !important; } + :-moz-any(input,textarea):valid { background-color: rgb(0,255,0) !important; } + :-moz-any(input,textarea):invalid { background-color: rgb(255,0,0) !important; } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=558788">Mozilla Bug 558788</a> +<p id="display"></p> +<div id="content"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 558788 **/ + +/** + * This test checks the behavior of :valid and :invalid pseudo-classes + * when the user is typing/interacting with the element. + * Only <input> and <textarea> elements can have there validity changed by an + * user input. + */ + +var gContent = document.getElementById('content'); + +function checkValidApplies(elmt) +{ + is(window.getComputedStyle(elmt).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); +} + +function checkInvalidApplies(elmt, aTodo) +{ + if (aTodo) { + todo_is(window.getComputedStyle(elmt).getPropertyValue('background-color'), + "rgb(255, 0, 0)", ":invalid pseudo-class should apply"); + return; + } + is(window.getComputedStyle(elmt).getPropertyValue('background-color'), + "rgb(255, 0, 0)", ":invalid pseudo-class should apply"); +} + +function checkMissing(elementName) +{ + var element = document.createElement(elementName); + element.required = true; + gContent.appendChild(element); + checkInvalidApplies(element); + + element.focus(); + + sendString("a"); + checkValidApplies(element); + + synthesizeKey("KEY_Backspace"); + checkInvalidApplies(element); + + gContent.removeChild(element); +} + +function checkTooLong(elementName) +{ + var element = document.createElement(elementName); + element.value = "foo"; + element.maxLength = 2; + gContent.appendChild(element); + checkInvalidApplies(element, true); + + element.focus(); + + synthesizeKey("KEY_Backspace"); + checkValidApplies(element); + gContent.removeChild(element); +} + +function checkTextAreaMissing() +{ + checkMissing('textarea'); +} + +function checkTextAreaTooLong() +{ + checkTooLong('textarea'); +} + +function checkTextArea() +{ + checkTextAreaMissing(); + checkTextAreaTooLong(); +} + +function checkInputMissing() +{ + checkMissing('input'); +} + +function checkInputTooLong() +{ + checkTooLong('input'); +} + +function checkInputEmail() +{ + var element = document.createElement('input'); + element.type = 'email'; + gContent.appendChild(element); + checkValidApplies(element); + + element.focus(); + + sendString("a"); + checkInvalidApplies(element); + + sendString("@b.c"); + checkValidApplies(element); + + synthesizeKey("KEY_Backspace"); + for (var i=0; i<4; ++i) { + if (i == 1) { + // a@b is a valid value. + checkValidApplies(element); + } else { + checkInvalidApplies(element); + } + synthesizeKey("KEY_Backspace"); + } + checkValidApplies(element); + + gContent.removeChild(element); +} + +function checkInputURL() +{ + var element = document.createElement('input'); + element.type = 'url'; + gContent.appendChild(element); + checkValidApplies(element); + + element.focus(); + + sendString("h"); + checkInvalidApplies(element); + + sendString("ttp://mozilla.org"); + checkValidApplies(element); + + for (var i=0; i<10; ++i) { + synthesizeKey("KEY_Backspace"); + checkValidApplies(element); + } + + synthesizeKey("KEY_Backspace"); + // "http://" is now invalid + for (var i=0; i<7; ++i) { + checkInvalidApplies(element); + synthesizeKey("KEY_Backspace"); + } + checkValidApplies(element); + + gContent.removeChild(element); +} + +function checkInputPattern() +{ + var element = document.createElement('input'); + element.pattern = "[0-9]*" + gContent.appendChild(element); + checkValidApplies(element); + + element.focus(); + + sendString("0"); + checkValidApplies(element); + + sendString("a"); + checkInvalidApplies(element); + + synthesizeKey("KEY_Backspace"); + checkValidApplies(element); + + synthesizeKey("KEY_Backspace"); + checkValidApplies(element); + + gContent.removeChild(element); +} + +function checkInput() +{ + checkInputMissing(); + checkInputTooLong(); + checkInputEmail(); + checkInputURL(); + checkInputPattern(); +} + +checkTextArea(); +checkInput(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug558788-2.html b/dom/html/test/test_bug558788-2.html new file mode 100644 index 0000000000..8224159d38 --- /dev/null +++ b/dom/html/test/test_bug558788-2.html @@ -0,0 +1,174 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=558788 +--> +<head> + <title>Test for Bug 558788</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=558788">Mozilla Bug 558788</a> +<p id="display"></p> +<div id="content"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 558788 **/ + +var validElementsDescription = [ + /* element type value required pattern maxlength minlength */ + /* <input> */ + [ "input", null, null, null, null, null, null ], + /* <input required value='foo'> */ + [ "input", null, "foo", true, null, null, null ], + /* <input type='email'> */ + [ "input", "email", null, null, null, null, null ], + /* <input type='email' value='foo@mozilla.org'> */ + [ "input", "email", "foo@mozilla.org", null, null, null, null ], + /* <input type='url'> */ + [ "input", "url", null, null, null, null, null ], + /* <input type='url' value='http://mozilla.org'> */ + [ "input", "url", "http://mozilla.org", null, null, null, null ], + /* <input pattern='\\d\\d'> */ + [ "input", null, null, null, "\\d\\d", null, null ], + /* <input pattern='\\d\\d' value='42'> */ + [ "input", null, "42", null, "\\d\\d", null, null ], + /* <input maxlength='3'> - still valid until user interaction */ + [ "input", null, null, null, null, "3", null ], + /* <input maxlength='3'> */ + [ "input", null, "fooo", null, null, "3", null ], + /* <input minlength='3'> - still valid until user interaction */ + [ "input", null, null, null, null, null, "3" ], + /* <input minlength='3'> */ + [ "input", null, "fo", null, null, null, "3" ], + /* <textarea></textarea> */ + [ "textarea", null, null, null, null, null, null ], + /* <textarea required>foo</textarea> */ + [ "textarea", null, "foo", true, null, null, null ] +]; + +var invalidElementsDescription = [ + /* element type value required pattern maxlength minlength valid-value */ + /* <input required> */ + [ "input", null, null, true, null, null, null, "foo" ], + /* <input type='email' value='foo'> */ + [ "input", "email", "foo", null, null, null, null, "foo@mozilla.org" ], + /* <input type='url' value='foo'> */ + [ "input", "url", "foo", null, null, null, null, "http://mozilla.org" ], + /* <input pattern='\\d\\d' value='foo'> */ + [ "input", null, "foo", null, "\\d\\d", null, null, "42" ], + /* <input maxlength='3'> - still valid until user interaction */ + [ "input", null, "foooo", null, null, "3", null, "foo" ], + /* <input minlength='3'> - still valid until user interaction */ + [ "input", null, "foo", null, null, null, "3", "foo" ], + /* <textarea required></textarea> */ + [ "textarea", null, null, true, null, null, null, "foo" ], +]; + +var validElements = []; +var invalidElements = []; + +function appendElements(aElementsDesc, aElements) +{ + var content = document.getElementById('content'); + var length = aElementsDesc.length; + + for (var i=0; i<length; ++i) { + var e = document.createElement(aElementsDesc[i][0]); + if (aElementsDesc[i][1]) { + e.type = aElementsDesc[i][1]; + } + if (aElementsDesc[i][2]) { + e.value = aElementsDesc[i][2]; + } + if (aElementsDesc[i][3]) { + e.required = true; + } + if (aElementsDesc[i][4]) { + e.pattern = aElementsDesc[i][4]; + } + if (aElementsDesc[i][5]) { + e.maxLength = aElementsDesc[i][5]; + } + if (aElementsDesc[i][6]) { + e.minLength = aElementsDesc[i][6]; + } + + content.appendChild(e); + + // Adding the element to the appropriate list. + aElements.push(e); + } +} + +function compareArrayWithSelector(aElements, aSelector) +{ + var aSelectorElements = document.querySelectorAll(aSelector); + + is(aSelectorElements.length, aElements.length, + aSelector + " selector should return the correct number of elements"); + + if (aSelectorElements.length != aElements.length) { + return; + } + + var length = aElements.length; + for (var i=0; i<length; ++i) { + is(aSelectorElements[i], aElements[i], + aSelector + " should return the correct elements"); + } +} + +function makeMinMaxLengthElementsActuallyInvalid(aInvalidElements, + aInvalidElementsDesc) +{ + // min/maxlength elements are not invalid until user edits them + var length = aInvalidElementsDesc.length; + + for (var i=0; i<length; ++i) { + var e = aInvalidElements[i]; + if (aInvalidElementsDesc[i][5]) { // maxlength + e.focus(); + synthesizeKey("KEY_Backspace"); + } else if (aInvalidElementsDesc[i][6]) { // minlength + e.focus(); + synthesizeKey("KEY_Backspace"); + } + } +} + +function makeInvalidElementsValid(aInvalidElements, + aInvalidElementsDesc, + aValidElements) +{ + var length = aInvalidElementsDesc.length; + + for (var i=0; i<length; ++i) { + var e = aInvalidElements.shift(); + e.value = aInvalidElementsDesc[i][7]; + aValidElements.push(e); + } +} + +appendElements(validElementsDescription, validElements); +appendElements(invalidElementsDescription, invalidElements); + +makeMinMaxLengthElementsActuallyInvalid(invalidElements, invalidElementsDescription); + +compareArrayWithSelector(validElements, ":valid"); +compareArrayWithSelector(invalidElements, ":invalid"); + +makeInvalidElementsValid(invalidElements, invalidElementsDescription, + validElements); + +compareArrayWithSelector(validElements, ":valid"); +compareArrayWithSelector(invalidElements, ":invalid"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug560112.html b/dom/html/test/test_bug560112.html new file mode 100644 index 0000000000..48aaad8dc5 --- /dev/null +++ b/dom/html/test/test_bug560112.html @@ -0,0 +1,211 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=560112 +--> +<head> + <title>Test for Bug 560112</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=560112">Mozilla Bug 560112</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 560112 **/ + +/** + * Sets dataset property. Checks data attribute "attr". + * Gets dataset property. Checks data attribute "attr". + * Overwrites dataset property Checks data attribute "attr". + * Deletes dataset property. Checks data attribute "attr". + */ +function SetGetOverwriteDel(attr, prop) +{ + var el = document.createElement('div'); + + // Set property. + is(prop in el.dataset, false, 'Property should not be in dataset before setting.'); + el.dataset[prop] = "zzzzzz"; + is(prop in el.dataset, true, 'Property should be in dataset after setting.'); + ok(el.hasAttribute(attr), 'Element should have data attribute for dataset property "' + prop + '".'); + + // Get property. + is(el.dataset[prop], "zzzzzz", 'Dataset property "' + prop + '" should have value "zzzzzz".'); + is(el.getAttribute(attr), "zzzzzz", 'Attribute "' + attr + '" should have value "zzzzzz".'); + + // Overwrite property. + el.dataset[prop] = "yyyyyy"; + is(el.dataset[prop], "yyyyyy", 'Dataset property "' + prop + '" should have value "yyyyyy".'); + is(el.getAttribute(attr), "yyyyyy", 'Attribute "' + attr + '" should have value "yyyyyy".'); + + // Delete property. + delete el.dataset[prop]; + ok(!el.hasAttribute(attr), 'Element should not have data attribute for dataset property "' + prop + '".'); + is(prop in el.dataset, false, 'Deleted property should not be in dataset.'); +} + +/** + * Sets dataset property and expects exception. + */ +function SetExpectException(prop) +{ + var el = document.createElement('div'); + + try { + el.dataset[prop] = "xxxxxx"; + ok(false, 'Exception should have been thrown.'); + } catch (ex) { + ok(true, 'Exception should have been thrown.'); + } +} + +/** + * Adds attributes in "attrList" to element. + * Deletes attributes in "delList" from element. + * Checks for "numProp" properties in dataset. + */ +function DelAttrEnumerate(attrList, delList, numProp) +{ + var el = document.createElement('div'); + + // Adds attributes in "attrList". + for (var i = 0; i < attrList.length; ++i) { + el.setAttribute(attrList[i], "aaaaaa"); + } + + // Remove attributes in "delList". + for (var i = 0; i < delList.length; ++i) { + el.removeAttribute(delList[i]); + } + + var numPropCounted = 0; + + for (var prop in el.dataset) { + if (el.dataset[prop] == "aaaaaa") { + ++numPropCounted; + } + } + + is(numPropCounted, numProp, 'Number of enumerable dataset properties is incorrent after attribute removal.'); +} + +/** + * Adds attributes in "attrList" to element. + * Checks for "numProp" properties in dataset. + */ +function Enumerate(attrList, numProp) +{ + var el = document.createElement('div'); + + // Adds attributes in "attrList" to element. + for (var i = 0; i < attrList.length; ++i) { + el.setAttribute(attrList[i], "aaaaaa"); + } + + var numPropCounted = 0; + + for (var prop in el.dataset) { + if (el.dataset[prop] == "aaaaaa") { + ++numPropCounted; + } + } + + is(numPropCounted, numProp, 'Number of enumerable dataset properties is incorrect.'); +} + +/** + * Adds dataset property then removes attribute from element and check for presence of + * properties using the "in" operator. + */ +function AddPropDelAttr(attr, prop) +{ + var el = document.createElement('div'); + + el.dataset[prop] = 'dddddd'; + is(prop in el.dataset, true, 'Operator "in" should return true after setting property.'); + el.removeAttribute(attr); + is(prop in el.dataset, false, 'Operator "in" should return false for removed attribute.'); +} + +/** + * Adds then removes attribute from element and check for presence of properties using the + * "in" operator. + */ +function AddDelAttr(attr, prop) +{ + var el = document.createElement('div'); + + el.setAttribute(attr, 'dddddd'); + is(prop in el.dataset, true, 'Operator "in" should return true after setting attribute.'); + el.removeAttribute(attr); + is(prop in el.dataset, false, 'Operator "in" should return false for removed attribute.'); +} + +// Typical use case. +SetGetOverwriteDel('data-property', 'property'); +SetGetOverwriteDel('data-a-longer-property', 'aLongerProperty'); + +AddDelAttr('data-property', 'property'); +AddDelAttr('data-a-longer-property', 'aLongerProperty'); + +AddPropDelAttr('data-property', 'property'); +AddPropDelAttr('data-a-longer-property', 'aLongerProperty'); + +// Empty property name. +SetGetOverwriteDel('data-', ''); + +// Leading dash characters. +SetGetOverwriteDel('data--', '-'); +SetGetOverwriteDel('data--d', 'D'); +SetGetOverwriteDel('data---d', '-D'); + +// Trailing dash characters. +SetGetOverwriteDel('data-d-', 'd-'); +SetGetOverwriteDel('data-d--', 'd--'); +SetGetOverwriteDel('data-d-d-', 'dD-'); + +// "data-" in attribute name. +SetGetOverwriteDel('data-data-', 'data-'); +SetGetOverwriteDel('data-data-data-', 'dataData-'); + +// Longer attribute. +SetGetOverwriteDel('data-long-long-long-long-long-long-long-long-long-long-long-long-long', 'longLongLongLongLongLongLongLongLongLongLongLongLong'); + +var longAttr = 'data-long'; +var longProp = 'long'; +for (var i = 0; i < 30000; ++i) { + // Create really long attribute and property names. + longAttr += '-long'; + longProp += 'Long'; +} + +SetGetOverwriteDel(longAttr, longProp); + +// Syntax error in setting dataset property (dash followed by lower case). +SetExpectException('-a'); +SetExpectException('a-a'); +SetExpectException('a-a-a'); + +// Invalid character. +SetExpectException('a a'); + +// Enumeration over dataset properties. +Enumerate(['data-a-big-fish'], 1); +Enumerate(['dat-a-big-fish'], 0); +Enumerate(['data-'], 1); +Enumerate(['data-', 'data-more-data'], 2); +Enumerate(['daaata-', 'data-more-data'], 1); + +// Delete data attributes and enumerate properties. +DelAttrEnumerate(['data-one', 'data-two'], ['data-one'], 1); +DelAttrEnumerate(['data-one', 'data-two'], ['data-three'], 2); +DelAttrEnumerate(['data-one', 'data-two'], ['one'], 2); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug561634.html b/dom/html/test/test_bug561634.html new file mode 100644 index 0000000000..1eab90508f --- /dev/null +++ b/dom/html/test/test_bug561634.html @@ -0,0 +1,126 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=561634 +--> +<head> + <title>Test for Bug 561634</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=561634">Mozilla Bug 561634</a> +<p id="display"></p> +<div id="content" style="display: none;"> + <form> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 561634 **/ + +function checkEmptyForm() +{ + ok(document.forms[0].checkValidity(), "An empty form is valid"); +} + +function checkBarredFromConstraintValidation() +{ + var f = document.forms[0]; + var fs = document.createElement('fieldset'); + var i = document.createElement('input'); + + f.appendChild(fs); + i.type = 'hidden'; + f.appendChild(i); + + fs.setCustomValidity("foo"); + i.setCustomValidity("foo"); + + ok(f.checkValidity(), + "A form with invalid element barred from constraint validation should be valid"); + + f.removeChild(i); + f.removeChild(fs); +} + +function checkValid() +{ + var f = document.forms[0]; + var i = document.createElement('input'); + f.appendChild(i); + + ok(f.checkValidity(), "A form with valid elements is valid"); + + f.removeChild(i); +} + +function checkInvalid() +{ + var f = document.forms[0]; + var i = document.createElement('input'); + f.appendChild(i); + + i.setCustomValidity("foo"); + ok(!f.checkValidity(), "A form with invalid elements is invalid"); + + var i2 = document.createElement('input'); + f.appendChild(i2); + ok(!f.checkValidity(), + "A form with at least one invalid element is invalid"); + + f.removeChild(i2); + f.removeChild(i); +} + +function checkInvalidEvent() +{ + var f = document.forms[0]; + var i = document.createElement('input'); + f.appendChild(i); + var i2 = document.createElement('input'); + f.appendChild(i2); + + i.setCustomValidity("foo"); + + var invalidEventForInvalidElement = false; + var invalidEventForValidElement = false; + + i.addEventListener("invalid", function (e) { + invalidEventForInvalidElement = true; + ok(e.cancelable, "invalid event should be cancelable"); + ok(!e.bubbles, "invalid event should not bubble"); + }); + + i2.addEventListener("invalid", function (e) { + invalidEventForValidElement = true; + }); + + f.checkValidity(); + + setTimeout(function() { + ok(invalidEventForInvalidElement, + "invalid event should be fired on invalid elements"); + ok(!invalidEventForValidElement, + "invalid event should not be fired on valid elements"); + + f.removeChild(i2); + f.removeChild(i); + + SimpleTest.finish(); + }, 0); +} + +SimpleTest.waitForExplicitFinish(); + +checkEmptyForm(); +checkBarredFromConstraintValidation(); +checkValid(); +checkInvalid(); +checkInvalidEvent(); // will call finish(). + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug561636.html b/dom/html/test/test_bug561636.html new file mode 100644 index 0000000000..da51b07607 --- /dev/null +++ b/dom/html/test/test_bug561636.html @@ -0,0 +1,99 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=561636 +--> +<head> + <title>Test for Bug 561636</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=561636">Mozilla Bug 561636</a> +<p id="display"></p> +<iframe style='width:50px; height: 50px;' name='t'></iframe> +<iframe style='width:50px; height: 50px;' name='t2' id='i'></iframe> +<div id="content"> + <form target='t' action='data:text/html,'> + <input required> + <input id='a' type='submit'> + </form> + <form target='t' action='data:text/html,'> + <input type='checkbox' required> + <button id='b' type='submit'></button> + </form> + <form target='t' action='data:text/html,'> + <input id='c' required> + </form> + <form target='t' action='data:text/html,'> + <input> + <input id='s2' type='submit'> + </form> + <form target='t2' action='data:text/html,'> + <input required> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 561636 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTest); + +function runTest() +{ + var formSubmitted = [ false, false ]; + var invalidHandled = false; + + // Initialize + document.forms[0].addEventListener('submit', function(aEvent) { + formSubmitted[0] = true; + }, {once: true}); + + document.forms[1].addEventListener('submit', function(aEvent) { + formSubmitted[1] = true; + }, {once: true}); + + document.forms[2].addEventListener('submit', function(aEvent) { + formSubmitted[2] = true; + }, {once: true}); + + document.forms[3].addEventListener('submit', function(aEvent) { + formSubmitted[3] = true; + + ok(!formSubmitted[0], "Form 1 should not have been submitted because invalid"); + ok(!formSubmitted[1], "Form 2 should not have been submitted because invalid"); + ok(!formSubmitted[2], "Form 3 should not have been submitted because invalid"); + ok(formSubmitted[3], "Form 4 should have been submitted because valid"); + + // Next test. + document.forms[4].submit(); + }, {once: true}); + + document.forms[4].elements[0].addEventListener('invalid', function(aEvent) { + invalidHandled = true; + }, {once: true}); + + document.getElementById('i').addEventListener('load', function(aEvent) { + SimpleTest.executeSoon(function () { + ok(true, "Form 5 should have been submitted because submit() has been used even if invalid"); + ok(!invalidHandled, "Invalid event should not have been sent"); + + SimpleTest.finish(); + }); + }, {once: true}); + + document.getElementById('a').click(); + document.getElementById('b').click(); + var c = document.getElementById('c'); + c.focus(); + synthesizeKey("KEY_Enter"); + document.getElementById('s2').click(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug561640.html b/dom/html/test/test_bug561640.html new file mode 100644 index 0000000000..ed7bf84126 --- /dev/null +++ b/dom/html/test/test_bug561640.html @@ -0,0 +1,72 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=561640 +--> +<head> + <title>Test for Bug 561640</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + input, textarea { background-color: rgb(0,0,0) !important; } + :-moz-any(input,textarea):valid { background-color: rgb(0,255,0) !important; } + :-moz-any(input,textarea):invalid { background-color: rgb(255,0,0) !important; } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=561640">Mozilla Bug 561640</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 561640 **/ + +var elements = [ 'input', 'textarea' ]; +var content = document.getElementById('content'); + +function checkValid(elmt) +{ + ok(!elmt.validity.tooLong, "element should not be too long"); + is(window.getComputedStyle(elmt).getPropertyValue('background-color'), + "rgb(0, 255, 0)", ":valid pseudo-class should apply"); +} + +function checkInvalid(elmt) +{ + todo(elmt.validity.tooLong, "element should be too long"); + todo_is(window.getComputedStyle(elmt).getPropertyValue('background-color'), + "rgb(255, 0, 0)", ":invalid pseudo-class should apply"); +} + +for (var elmtName of elements) { + var elmt = document.createElement(elmtName); + content.appendChild(elmt); + + if (elmtName == 'textarea') { + elmt.textContent = 'foo'; + } else { + elmt.setAttribute('value', 'foo'); + } + elmt.maxLength = 2; + checkValid(elmt); + + elmt.value = 'a'; + checkValid(elmt); + + if (elmtName == 'textarea') { + elmt.textContent = 'f'; + } else { + elmt.setAttribute('value', 'f'); + } + elmt.value = 'bar'; + checkInvalid(elmt); + + content.removeChild(elmt); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug564001.html b/dom/html/test/test_bug564001.html new file mode 100644 index 0000000000..3815ac8cf9 --- /dev/null +++ b/dom/html/test/test_bug564001.html @@ -0,0 +1,48 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=564001 +--> +<head> + <title>Test for Bug 564001</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=564001">Mozilla Bug 564001</a> +<p id="display"><img usemap=#map src=image.png></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script> +/** Test for Bug 564001 **/ +SimpleTest.waitForExplicitFinish(); + +var wrongArea = document.createElement("area"); +wrongArea.shape = "default"; +wrongArea.href = "#FAIL"; +var wrongMap = document.createElement("map"); +wrongMap.name = "map"; +wrongMap.appendChild(wrongArea); +document.body.appendChild(wrongMap); + +var rightArea = document.createElement("area"); +rightArea.shape = "default"; +rightArea.href = "#PASS"; +var rightMap = document.createElement("map"); +rightMap.name = "map"; +rightMap.appendChild(rightArea); +document.body.insertBefore(rightMap, wrongMap); + +var images = document.getElementsByTagName("img"); +onhashchange = function() { + is(location.hash, "#PASS", "Should get the first map in tree order."); + SimpleTest.finish(); +}; +SimpleTest.waitForFocus(() => synthesizeMouse(images[0], 50, 50, {})); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug566046.html b/dom/html/test/test_bug566046.html new file mode 100644 index 0000000000..88c59a4e61 --- /dev/null +++ b/dom/html/test/test_bug566046.html @@ -0,0 +1,200 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=566046 +--> +<head> + <title>Test for Bug 566046</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <base> + <base target='frame2'> + <base target=''> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=566046">Mozilla Bug 566046</a> +<p id="display"></p> +<style> + iframe { width: 130px; height: 100px;} +</style> +<iframe name='frame1' id='frame1'></iframe> +<iframe name='frame2' id='frame2'></iframe> +<iframe name='frame3' id='frame3'></iframe> +<iframe name='frame4' id='frame4'></iframe> +<iframe name='frame5' id='frame5'></iframe> +<iframe name='frame5bis' id='frame5bis'></iframe> +<iframe name='frame6' id='frame6'></iframe> +<iframe name='frame7' id='frame7'></iframe> +<iframe name='frame8' id='frame8'></iframe> +<iframe name='frame9' id='frame9'></iframe> +<div id="content"> + <form target='frame1' action="dummy_page.html" method="GET"> + <input name='foo' value='foo'> + </form> + <form action="dummy_page.html" method="GET"> + <input name='bar' value='bar'> + </form> + <form target=""> + </form> + + <!-- submit controls with formtarget that are validated with a CLICK --> + <form target="tulip" action="dummy_page.html" method="GET"> + <input name='tulip' value='tulip'> + <input type='submit' id='is' formtarget='frame3'> + </form> + <form action="dummy_page.html" method="GET"> + <input name='foobar' value='foobar'> + <input type='image' id='ii' formtarget='frame4'> + </form> + <form action="dummy_page.html" method="GET"> + <input name='tulip2' value='tulip2'> + <button type='submit' id='bs' formtarget='frame5'>submit</button> + </form> + <form action="dummy_page.html" method="GET"> + <input name='tulip3' value='tulip3'> + <button type='submit' id='bsbis' formtarget='frame5bis'>submit</button> + </form> + + <!-- submit controls with formtarget that are validated with ENTER --> + <form target="tulip" action="dummy_page.html" method="GET"> + <input name='footulip' value='footulip'> + <input type='submit' id='is2' formtarget='frame6'> + </form> + <form action="dummy_page.html" method="GET"> + <input name='tulipfoobar' value='tulipfoobar'> + <input type='image' id='ii2' formtarget='frame7'> + </form> + <form action="dummy_page.html" method="GET"> + <input name='tulipbar' value='tulipbar'> + <button type='submit' id='bs2' formtarget='frame8'>submit</button> + </form> + + <!-- check that a which is not a submit control do not use @formtarget --> + <form target='frame9' action="dummy_page.html" method="GET"> + <input id='enter' name='input' value='enter' formtarget='frame6'> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 566046 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + setTimeout(runTests, 0); +}); + +const BASE_URI = `${location.origin}/tests/dom/html/test/dummy_page.html`; +var gTestResults = { + frame1: BASE_URI + "?foo=foo", + frame2: BASE_URI + "?bar=bar", + frame3: BASE_URI + "?tulip=tulip", + frame4: BASE_URI + "?foobar=foobar&x=0&y=0", + frame5: BASE_URI + "?tulip2=tulip2", + frame5bis: BASE_URI + "?tulip3=tulip3", + frame6: BASE_URI + "?footulip=footulip", + frame7: BASE_URI + "?tulipfoobar=tulipfoobar&x=0&y=0", + frame8: BASE_URI + "?tulipbar=tulipbar", + frame9: BASE_URI + "?input=enter", +}; + +var gPendingLoad = 0; // Has to be set after depending on the frames number. + +function runTests() +{ + // Check the target IDL attribute. + for (var i=0; i<document.forms.length; ++i) { + var testValue = document.forms[i].getAttribute('target'); + is(document.forms[i].target, testValue ? testValue : "", + "target IDL attribute should reflect the target content attribute"); + } + + // We add a load event for the frames which will be called when the forms + // will be submitted. + var frames = [ document.getElementById('frame1'), + document.getElementById('frame2'), + document.getElementById('frame3'), + document.getElementById('frame4'), + document.getElementById('frame5'), + document.getElementById('frame5bis'), + document.getElementById('frame6'), + document.getElementById('frame7'), + document.getElementById('frame8'), + document.getElementById('frame9'), + ]; + gPendingLoad = frames.length; + + for (var i=0; i<frames.length; i++) { + frames[i].setAttribute('onload', "frameLoaded(this);"); + } + + // Submitting only the forms with a valid target. + document.forms[0].submit(); + document.forms[1].submit(); + + /** + * We are going to focus each element before interacting with either for + * simulating the ENTER key (synthesizeKey) or a click (synthesizeMouse) or + * using .click(). This because it may be needed (ENTER) and because we want + * to have the element visible in the iframe. + * + * Focusing the first element (id='is') is launching the tests. + */ + document.getElementById('is').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('is'), 5, 5, {}); + document.getElementById('ii').focus(); + }, {once: true}); + + document.getElementById('ii').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('ii'), 5, 5, {}); + document.getElementById('bs').focus(); + }, {once: true}); + + document.getElementById('bs').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('bs'), 5, 5, {}); + document.getElementById('bsbis').focus(); + }, {once: true}); + + document.getElementById('bsbis').addEventListener('focus', function(aEvent) { + document.getElementById('bsbis').click(); + document.getElementById('is2').focus(); + }, {once: true}); + + document.getElementById('is2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('ii2').focus(); + }, {once: true}); + + document.getElementById('ii2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('bs2').focus(); + }, {once: true}); + + document.getElementById('bs2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('enter').focus(); + }, {once: true}); + + document.getElementById('enter').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + }, {once: true}); + + document.getElementById('is').focus(); +} + +function frameLoaded(aFrame) { + // Check if when target is unspecified, it fallback correctly to the base + // element target attribute. + is(aFrame.contentWindow.location.href, gTestResults[aFrame.name], + "the target attribute doesn't have the correct behavior"); + + if (--gPendingLoad == 0) { + SimpleTest.finish(); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug567938-1.html b/dom/html/test/test_bug567938-1.html new file mode 100644 index 0000000000..0c5d78f1c0 --- /dev/null +++ b/dom/html/test/test_bug567938-1.html @@ -0,0 +1,69 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=567938 +--> +<head> + <title>Test for Bug 567938</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body onload="runTests();"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=567938">Mozilla Bug 567938</a> +<p id="display"></p> +<iframe id='iframe' name="submit_frame" style="visibility: hidden;"></iframe> +<div id="content" style="display: none"> + <form id='f' method='get' target='submit_frame'> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 567938 **/ + +SimpleTest.waitForExplicitFinish(); + +var gTestData = ["submit", "image"]; +var gCurrentTest = 0; + +function initializeNextTest() +{ + var form = document.forms[0]; + + // Cleaning-up. + form.textContent = ""; + + // Add the new element. + var element = document.createElement("input"); + element.id = 'i'; + element.type = gTestData[gCurrentTest]; + element.onclick = function() { form.submit(); return false; }; + form.action = gTestData[gCurrentTest]; + form.appendChild(element); + + sendMouseEvent({type: 'click'}, 'i'); +} + +function runTests() +{ + document.getElementById('iframe').addEventListener('load', function(aEvent) { + is(frames.submit_frame.location.href, + `${location.origin}/tests/dom/html/test/${gTestData[gCurrentTest]}?`, + "The form should have been submitted"); + gCurrentTest++; + if (gCurrentTest < gTestData.length) { + initializeNextTest(); + } else { + aEvent.target.removeEventListener('load', arguments.callee); + SimpleTest.finish(); + } + }); + + initializeNextTest(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug567938-2.html b/dom/html/test/test_bug567938-2.html new file mode 100644 index 0000000000..4a97516805 --- /dev/null +++ b/dom/html/test/test_bug567938-2.html @@ -0,0 +1,70 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=567938 +--> +<head> + <title>Test for Bug 567938</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=567938">Mozilla Bug 567938</a> +<p id="display"></p> +<iframe id='iframe' name="submit_frame" style="visibility: hidden;"></iframe> +<div id="content" style="display: none"> + <form id='f' method='get' target='submit_frame'> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 567938 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTests); + +var gTestData = ["submit", "image"]; +var gCurrentTest = 0; + +function initializeNextTest() +{ + var form = document.forms[0]; + + // Cleaning-up. + form.textContent = ""; + + // Add the new element. + var element = document.createElement("input"); + element.id = 'i'; + element.type = gTestData[gCurrentTest]; + element.onclick = function() { form.submit(); element.type='text'; }; + form.action = gTestData[gCurrentTest]; + form.appendChild(element); + + sendMouseEvent({type: 'click'}, 'i'); +} + +function runTests() +{ + document.getElementById('iframe').addEventListener('load', function(aEvent) { + is(frames.submit_frame.location.href, + `${location.origin}/tests/dom/html/test/${gTestData[gCurrentTest]}?`, + "The form should have been submitted"); + gCurrentTest++; + if (gCurrentTest < gTestData.length) { + initializeNextTest(); + } else { + aEvent.target.removeEventListener('load', arguments.callee); + SimpleTest.finish(); + } + }); + + initializeNextTest(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug567938-3.html b/dom/html/test/test_bug567938-3.html new file mode 100644 index 0000000000..3c23129466 --- /dev/null +++ b/dom/html/test/test_bug567938-3.html @@ -0,0 +1,71 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=567938 +--> +<head> + <title>Test for Bug 567938</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=567938">Mozilla Bug 567938</a> +<p id="display"></p> +<iframe id='iframe' name="submit_frame" style="visibility: hidden;"></iframe> +<div id="content" style="display: none"> + <form id='f' method='get' target='submit_frame'> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 567938 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTests); + +var gTestData = ["submit", "image"]; +var gCurrentTest = 0; + +function initializeNextTest() +{ + var form = document.forms[0]; + + // Cleaning-up. + form.textContent = ""; + + // Add the new element. + var element = document.createElement("input"); + element.id = 'i'; + element.type = gTestData[gCurrentTest]; + // eslint-disable-next-line no-implied-eval + element.onclick = function() { setTimeout("document.forms[0].submit();",0); return false; }; + form.appendChild(element); + form.action = gTestData[gCurrentTest]; + + sendMouseEvent({type: 'click'}, 'i'); +} + +function runTests() +{ + document.getElementById('iframe').addEventListener('load', function(aEvent) { + is(frames.submit_frame.location.href, + `${location.origin}/tests/dom/html/test/${gTestData[gCurrentTest]}?`, + "The form should have been submitted"); + gCurrentTest++; + if (gCurrentTest < gTestData.length) { + initializeNextTest(); + } else { + aEvent.target.removeEventListener('load', arguments.callee); + SimpleTest.finish(); + } + }); + + initializeNextTest(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug567938-4.html b/dom/html/test/test_bug567938-4.html new file mode 100644 index 0000000000..f04ac27f5f --- /dev/null +++ b/dom/html/test/test_bug567938-4.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=567938 +--> +<head> + <title>Test for Bug 567938</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=567938">Mozilla Bug 567938</a> +<p id="display"></p> +<div id="content" style="display: none"> + <input id='i' type='checkbox' onclick="return false;"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 567938 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTests); + +function runTests() +{ + document.getElementById('i').checked = false; + + document.getElementById('i').addEventListener('click', function(aEvent) { + SimpleTest.executeSoon(function() { + ok(!aEvent.target.checked, "the input should not be checked"); + SimpleTest.finish(); + }); + }, {once: true}); + + sendMouseEvent({type: 'click'}, 'i'); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug569955.html b/dom/html/test/test_bug569955.html new file mode 100644 index 0000000000..0ed5ce88c7 --- /dev/null +++ b/dom/html/test/test_bug569955.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=569955 +--> +<head> + <title>Test for Bug 569955</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=569955">Mozilla Bug 569955</a> +<p id="display"></p> +<div id="content" style="display: none"> + <input id='i' autofocus> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 569955 **/ + +function runTests() +{ + isnot(document.activeElement, document.getElementById('i'), + "not rendered elements can't be autofocused"); + SimpleTest.finish(); +} + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + setTimeout(runTests, 0); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug573969.html b/dom/html/test/test_bug573969.html new file mode 100644 index 0000000000..f6020d1445 --- /dev/null +++ b/dom/html/test/test_bug573969.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=573969 +--> +<head> + <title>Test for Bug 573969</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=573969">Mozilla Bug 573969</a> +<p id="display"></p> +<div id="content" style="display: none"> + <xmp id='x'></xmp> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 573969 **/ + +var testData = [ + '<div>foo</div>', + '<div></div>', +]; + +var x = document.getElementById('x'); + +for (v of testData) { + x.innerHTML = v; + is(x.innerHTML, v, "innerHTML value should not be escaped"); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug57600.html b/dom/html/test/test_bug57600.html new file mode 100644 index 0000000000..fc7037bd32 --- /dev/null +++ b/dom/html/test/test_bug57600.html @@ -0,0 +1,42 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=57600 +--> +<head> + <title>Test for Bug 57600</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=57600">Mozilla Bug 57600</a> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 57600 **/ +SimpleTest.waitForExplicitFinish(); +var count = 0; +function disp(win) { + var d = win ? win.document : self.testname.document; + var str = 'You should see this'; + d.open(); + d.write(str); + d.close(); + is(d.documentElement.textContent, str, "Unexpected text"); + if (++count == 2) { + SimpleTest.finish(); + } +} +</script> +</pre> +<p id="display"> + <iframe src="javascript:'<body onload="this.onerror = parent.onerror; parent.disp(self)"></body>'"> + </iframe> + <iframe name="testname" src="javascript:'<body onload="this.onerror = parent.onerror; parent.disp()"></body>'"> + </iframe> +</p> +</body> +</html> diff --git a/dom/html/test/test_bug579079.html b/dom/html/test/test_bug579079.html new file mode 100644 index 0000000000..e5ec429226 --- /dev/null +++ b/dom/html/test/test_bug579079.html @@ -0,0 +1,40 @@ +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=579079 +--> +<head> + <title>Test for Bug 579079</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=579079">Mozilla Bug 579079</a> + +<div id="foo"> + <img name="img1"> + <form name="form1"></form> + <applet name="applet1"></applet> + <embed name="embed1"></embed> + <object name="object1"></object> +</div> + +<pre id="test"> +<script class="testbody" type="text/javascript"> +var img = document.img1; +var form = document.form1; +var embed = document.embed1; +var object = document.object1; +$("foo").innerHTML = $("foo").innerHTML; +isnot(document.img1, img); +ok(document.img1 instanceof HTMLImageElement); +isnot(document.form1, form); +ok(document.form1 instanceof HTMLFormElement); +isnot(document.embed1, embed); +ok(document.embed1 instanceof HTMLEmbedElement); +isnot(document.object1, object); +ok(document.object1 instanceof HTMLObjectElement); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug582412-1.html b/dom/html/test/test_bug582412-1.html new file mode 100644 index 0000000000..f1256e3d5a --- /dev/null +++ b/dom/html/test/test_bug582412-1.html @@ -0,0 +1,200 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=566160 +--> +<head> + <title>Test for Bug 566160</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=566160">Mozilla Bug 566160</a> +<p id="display"></p> +<style> + iframe { width: 130px; height: 100px;} +</style> +<iframe name='frame1' id='frame1'></iframe> +<iframe name='frame2' id='frame2'></iframe> +<iframe name='frame3' id='frame3'></iframe> +<iframe name='frame3bis' id='frame3bis'></iframe> +<iframe name='frame4' id='frame4'></iframe> +<iframe name='frame5' id='frame5'></iframe> +<iframe name='frame6' id='frame6'></iframe> +<iframe name='frame7' id='frame7'></iframe> +<iframe name='frame8' id='frame8'></iframe> +<iframe name='frame9' id='frame9'></iframe> +<div id="content"> + <!-- submit controls with formaction that are validated with a CLICK --> + <form target="frame1" action="dummy_page.html" method="POST"> + <input name='foo' value='foo'> + <input type='submit' id='is' formmethod="GET"> + </form> + <form target="frame2" action="dummy_page.html" method="POST"> + <input name='bar' value='bar'> + <input type='image' id='ii' formmethod="GET"> + </form> + <form target="frame3" action="dummy_page.html" method="POST"> + <input name='tulip' value='tulip'> + <button type='submit' id='bs' formmethod="GET">submit</button> + </form> + <form target="frame3bis" action="dummy_page.html" method="POST"> + <input name='tulipbis' value='tulipbis'> + <button type='submit' id='bsbis' formmethod="GET">submit</button> + </form> + + <!-- submit controls with formaction that are validated with ENTER --> + <form target="frame4" action="dummy_page.html" method="POST"> + <input name='footulip' value='footulip'> + <input type='submit' id='is2' formmethod="GET"> + </form> + <form target="frame5" action="dummy_page.html" method="POST"> + <input name='foobar' value='foobar'> + <input type='image' id='ii2' formmethod="GET"> + </form> + <form target="frame6" action="dummy_page.html" method="POST"> + <input name='tulip2' value='tulip2'> + <button type='submit' id='bs2' formmethod="GET">submit</button> + </form> + + <!-- check that when submitting a from from an element + which is not a submit control, @formaction isn't used --> + <form target='frame7' action="dummy_page.html" method="GET"> + <input id='enter' name='input' value='enter' formmethod="POST"> + </form> + + <!-- If formmethod isn't set, it's default value shouldn't be used --> + <form target="frame8" action="dummy_page.html" method="POST"> + <input name='tulip8' value='tulip8'> + <input type='submit' id='i8'> + </form> + + <!-- If formmethod is set but has an invalid value, the default value should + be used. --> + <form target="frame9" action="dummy_page.html" method="POST"> + <input name='tulip9' value='tulip9'> + <input type='submit' id='i9' formmethod=""> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 566160 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + setTimeout(runTests, 0); +}); + +const BASE_URI = `${location.origin}/tests/dom/html/test/dummy_page.html`; +var gTestResults = { + frame1: BASE_URI + "?foo=foo", + frame2: BASE_URI + "?bar=bar&x=0&y=0", + frame3: BASE_URI + "?tulip=tulip", + frame3bis: BASE_URI + "?tulipbis=tulipbis", + frame4: BASE_URI + "?footulip=footulip", + frame5: BASE_URI + "?foobar=foobar&x=0&y=0", + frame6: BASE_URI + "?tulip2=tulip2", + frame7: BASE_URI + "?input=enter", + frame8: BASE_URI + "", + frame9: BASE_URI + "?tulip9=tulip9", +}; + +var gPendingLoad = 0; // Has to be set after depending on the frames number. + +function runTests() +{ + // We add a load event for the frames which will be called when the forms + // will be submitted. + var frames = [ document.getElementById('frame1'), + document.getElementById('frame2'), + document.getElementById('frame3'), + document.getElementById('frame3bis'), + document.getElementById('frame4'), + document.getElementById('frame5'), + document.getElementById('frame6'), + document.getElementById('frame7'), + document.getElementById('frame8'), + document.getElementById('frame9'), + ]; + gPendingLoad = frames.length; + + for (var i=0; i<frames.length; i++) { + frames[i].setAttribute('onload', "frameLoaded(this);"); + } + + /** + * We are going to focus each element before interacting with either for + * simulating the ENTER key (synthesizeKey) or a click (synthesizeMouse) or + * using .click(). This because it may be needed (ENTER) and because we want + * to have the element visible in the iframe. + * + * Focusing the first element (id='is') is launching the tests. + */ + document.getElementById('is').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('is'), 5, 5, {}); + document.getElementById('ii').focus(); + }, {once: true}); + + document.getElementById('ii').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('ii'), 5, 5, {}); + document.getElementById('bs').focus(); + }, {once: true}); + + document.getElementById('bs').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('bs'), 5, 5, {}); + document.getElementById('bsbis').focus(); + }, {once: true}); + + document.getElementById('bsbis').addEventListener('focus', function(aEvent) { + document.getElementById('bsbis').click(); + document.getElementById('is2').focus(); + }, {once: true}); + + document.getElementById('is2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('ii2').focus(); + }, {once: true}); + + document.getElementById('ii2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('bs2').focus(); + }, {once: true}); + + document.getElementById('bs2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('enter').focus(); + }, {once: true}); + + document.getElementById('enter').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('i8').focus(); + }, {once: true}); + + document.getElementById('i8').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('i9').focus(); + }, {once: true}); + + document.getElementById('i9').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + }, {once: true}); + + document.getElementById('is').focus(); +} + +function frameLoaded(aFrame) { + // Check if formaction/action has the correct behavior. + is(aFrame.contentWindow.location.href, gTestResults[aFrame.name], + "the method/formmethod attribute doesn't have the correct behavior"); + + if (--gPendingLoad == 0) { + SimpleTest.finish(); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug582412-2.html b/dom/html/test/test_bug582412-2.html new file mode 100644 index 0000000000..b5ff8fc81e --- /dev/null +++ b/dom/html/test/test_bug582412-2.html @@ -0,0 +1,199 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=566160 +--> +<head> + <title>Test for Bug 566160</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=566160">Mozilla Bug 566160</a> +<p id="display"></p> +<style> + iframe { width: 130px; height: 100px;} +</style> +<iframe name='frame1' id='frame1'></iframe> +<iframe name='frame2' id='frame2'></iframe> +<iframe name='frame3' id='frame3'></iframe> +<iframe name='frame3bis' id='frame3bis'></iframe> +<iframe name='frame4' id='frame4'></iframe> +<iframe name='frame5' id='frame5'></iframe> +<iframe name='frame6' id='frame6'></iframe> +<iframe name='frame7' id='frame7'></iframe> +<iframe name='frame8' id='frame8'></iframe> +<iframe name='frame9' id='frame9'></iframe> +<div id="content"> + <!-- submit controls with formaction that are validated with a CLICK --> + <form target="frame1" action="form_submit_server.sjs" method="POST"> + <input name='foo' value='foo'> + <input type='submit' id='is' formenctype='multipart/form-data'> + </form> + <form target="frame2" action="form_submit_server.sjs" method="POST"> + <input name='bar' value='bar'> + <input type='image' id='ii' formenctype='multipart/form-data'> + </form> + <form target="frame3" action="form_submit_server.sjs" method="POST"> + <input name='tulip' value='tulip'> + <button type='submit' id='bs' formenctype="multipart/form-data">submit</button> + </form> + <form target="frame3bis" action="form_submit_server.sjs" method="POST"> + <input name='tulipbis' value='tulipbis'> + <button type='submit' id='bsbis' formenctype="multipart/form-data">submit</button> + </form> + + <!-- submit controls with formaction that are validated with ENTER --> + <form target="frame4" action="form_submit_server.sjs" method="POST"> + <input name='footulip' value='footulip'> + <input type='submit' id='is2' formenctype="multipart/form-data"> + </form> + <form target="frame5" action="form_submit_server.sjs" method="POST"> + <input name='foobar' value='foobar'> + <input type='image' id='ii2' formenctype="multipart/form-data"> + </form> + <form target="frame6" action="form_submit_server.sjs" method="POST"> + <input name='tulip2' value='tulip2'> + <button type='submit' id='bs2' formenctype="multipart/form-data">submit</button> + </form> + + <!-- check that when submitting a from from an element + which is not a submit control, @formaction isn't used --> + <form target='frame7' action="form_submit_server.sjs" method="POST"> + <input id='enter' name='input' value='enter' formenctype="multipart/form-data"> + </form> + + <!-- If formenctype isn't set, it's default value shouldn't be used --> + <form target="frame8" action="form_submit_server.sjs" method="POST" enctype="multipart/form-data"> + <input name='tulip8' value='tulip8'> + <input type='submit' id='i8'> + </form> + + <!-- If formenctype is set but has an invalid value, the default value should + be used. --> + <form target="frame9" action="form_submit_server.sjs" method="POST" enctype="multipart/form-data"> + <input name='tulip9' value='tulip9'> + <input type='submit' id='i9' formenctype=""> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 566160 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + setTimeout(runTests, 0); +}); + +var gTestResults = { + frame1: '[{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"foo\\\"\"},\"body\":\"foo\"}]', + frame2: '[{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"bar\\\"\"},\"body\":\"bar\"},{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"x\\\"\"},\"body\":\"0\"},{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"y\\\"\"},\"body\":\"0\"}]', + frame3: '[{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"tulip\\\"\"},\"body\":\"tulip\"}]', + frame3bis: '[{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"tulipbis\\\"\"},\"body\":\"tulipbis\"}]', + frame4: '[{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"footulip\\\"\"},\"body\":\"footulip\"}]', + frame5: '[{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"foobar\\\"\"},\"body\":\"foobar\"},{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"x\\\"\"},\"body\":\"0\"},{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"y\\\"\"},\"body\":\"0\"}]', + frame6: '[{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"tulip2\\\"\"},\"body\":\"tulip2\"}]', + frame7: '[]', + frame8: '[{\"headers\":{\"Content-Disposition\":\"form-data; name=\\\"tulip8\\\"\"},\"body\":\"tulip8\"}]', + frame9: '[]', +}; + +var gPendingLoad = 0; // Has to be set after depending on the frames number. + +function runTests() +{ + // We add a load event for the frames which will be called when the forms + // will be submitted. + var frames = [ document.getElementById('frame1'), + document.getElementById('frame2'), + document.getElementById('frame3'), + document.getElementById('frame3bis'), + document.getElementById('frame4'), + document.getElementById('frame5'), + document.getElementById('frame6'), + document.getElementById('frame7'), + document.getElementById('frame8'), + document.getElementById('frame9'), + ]; + gPendingLoad = frames.length; + + for (var i=0; i<frames.length; i++) { + frames[i].setAttribute('onload', "frameLoaded(this);"); + } + + /** + * We are going to focus each element before interacting with either for + * simulating the ENTER key (synthesizeKey) or a click (synthesizeMouse) or + * using .click(). This because it may be needed (ENTER) and because we want + * to have the element visible in the iframe. + * + * Focusing the first element (id='is') is launching the tests. + */ + document.getElementById('is').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('is'), 5, 5, {}); + document.getElementById('ii').focus(); + }, {once: true}); + + document.getElementById('ii').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('ii'), 5, 5, {}); + document.getElementById('bs').focus(); + }, {once: true}); + + document.getElementById('bs').addEventListener('focus', function(aEvent) { + synthesizeMouse(document.getElementById('bs'), 5, 5, {}); + document.getElementById('bsbis').focus(); + }, {once: true}); + + document.getElementById('bsbis').addEventListener('focus', function(aEvent) { + document.getElementById('bsbis').click(); + document.getElementById('is2').focus(); + }, {once: true}); + + document.getElementById('is2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('ii2').focus(); + }, {once: true}); + + document.getElementById('ii2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('bs2').focus(); + }, {once: true}); + + document.getElementById('bs2').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('enter').focus(); + }, {once: true}); + + document.getElementById('enter').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('i8').focus(); + }, {once: true}); + + document.getElementById('i8').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + document.getElementById('i9').focus(); + }, {once: true}); + + document.getElementById('i9').addEventListener('focus', function(aEvent) { + synthesizeKey("KEY_Enter"); + }, {once: true}); + + document.getElementById('is').focus(); +} + +function frameLoaded(aFrame) { + // Check if formaction/action has the correct behavior. + is(aFrame.contentDocument.documentElement.textContent, gTestResults[aFrame.name], + "the enctype/formenctype attribute doesn't have the correct behavior"); + + if (--gPendingLoad == 0) { + SimpleTest.finish(); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug583514.html b/dom/html/test/test_bug583514.html new file mode 100644 index 0000000000..a3dead89aa --- /dev/null +++ b/dom/html/test/test_bug583514.html @@ -0,0 +1,71 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=583514 +--> +<head> + <title>Test for Bug 583514</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=583514">Mozilla Bug 583514</a> +<p id="display"></p> +<div id="content"> + <input> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 583514 **/ + +var gExpectDivClick = false; +var gExpectInputClick = false; + +var div = document.getElementById('content'); +var input = document.getElementsByTagName('input')[0]; + +div.addEventListener('click', function() { + ok(gExpectDivClick, "click event received on div and expected status was: " + + gExpectDivClick); +}); + +input.addEventListener('click', function() { + ok(gExpectInputClick, "click event received on input and expected status was: " + + gExpectInputClick); +}); + +SimpleTest.waitForExplicitFinish(); + +SimpleTest.waitForFocus(function() { + var body = document.body; + + body.addEventListener('click', function(aEvent) { + if (aEvent.target == input) { + body.removeEventListener('click', arguments.callee); + } + + ok(true, "click event received on body"); + + SimpleTest.executeSoon(function() { + isnot(document.activeElement, input, "input shouldn't have been focused"); + isnot(document.activeElement, div, "div shouldn't have been focused"); + + if (aEvent.target == input) { + SimpleTest.finish(); + } else { + gExpectDivClick = true; + gExpectInputClick = true; + input.click(); + } + }); + }); + + gExpectDivClick = true; + div.click(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug583533.html b/dom/html/test/test_bug583533.html new file mode 100644 index 0000000000..c0b8c92e95 --- /dev/null +++ b/dom/html/test/test_bug583533.html @@ -0,0 +1,81 @@ +<!DOCTYPE HTML> +<html> + <!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=583533 +--> + <head> + <title>Test for Bug 583514</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + </head> + <body> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=583533">Mozilla Bug 583533</a> + <p id="display"></p> + <div id="content"> + <div id="e" accesskey="a"> + </div> +</div> +<pre id="test"> +<script type="application/javascript"> + + /** Test for Bug 583533 **/ + + var sbs = SpecialPowers.Cc['@mozilla.org/intl/stringbundle;1']. + getService(SpecialPowers.Ci.nsIStringBundleService); + var bundle = sbs.createBundle("chrome://global-platform/locale/platformKeys.properties"); + + var shiftText = bundle.GetStringFromName("VK_SHIFT"); + var altText = bundle.GetStringFromName("VK_ALT"); + var controlText = bundle.GetStringFromName("VK_CONTROL"); + var metaText = bundle.GetStringFromName("VK_COMMAND_OR_WIN"); + var separatorText = bundle.GetStringFromName("MODIFIER_SEPARATOR"); + + var modifier = SpecialPowers.getIntPref("ui.key.contentAccess"); + + var isShift; + var isAlt; + var isControl; + var isMeta; + + is(modifier < 16 && modifier >= 0, true, "Modifier in range"); + + // There are no consts for the mask of this prefs. + if (modifier & 8) { + isMeta = true; + } + if (modifier & 1) { + isShift = true; + } + if (modifier & 2) { + isControl = true; + } + if (modifier & 4) { + isAlt = true; + } + + var label = ""; + + if (isControl) + label += controlText + separatorText; + if (isMeta) + label += metaText + separatorText; + if (isAlt) + label += altText + separatorText; + if (isShift) + label += shiftText + separatorText; + + label += document.getElementById("e").accessKey; + + is(label, document.getElementById("e").accessKeyLabel, "JS and C++ agree on accessKeyLabel"); + + /** Test for Bug 808964 **/ + + var div = document.createElement("div"); + document.body.appendChild(div); + + is(div.accessKeyLabel, "", "accessKeyLabel should be empty string"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug586763.html b/dom/html/test/test_bug586763.html new file mode 100644 index 0000000000..b396cb8bc9 --- /dev/null +++ b/dom/html/test/test_bug586763.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=586763 +--> +<title>Test for Bug 586763</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=586763">Mozilla Bug 586763</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script> +/** Test for Bug 586763 **/ +var tests = [ + ["ol", "start", 1], + ["li", "value", 0], + ["object", "hspace", 0], + ["object", "vspace", 0], + ["img", "hspace", 0], + ["img", "vspace", 0], + ["video", "height", 0], + ["video", "width", 0], + ["pre", "width", 0], + ["textarea", "cols", 20], + ["textarea", "rows", 2], + ["span", "tabIndex", -1], + ["frame", "tabIndex", 0], + ["a", "tabIndex", 0], + ["area", "tabIndex", 0], + ["button", "tabIndex", 0], + ["input", "tabIndex", 0], + ["object", "tabIndex", 0], + ["select", "tabIndex", 0], + ["textarea", "tabIndex", 0], +]; + +for (var i = 0; i < tests.length; i++) { + is(document.createElement(tests[i][0])[tests[i][1]], tests[i][2], "Reflected attribute " + tests[i][0] + "." + tests[i][1] + " should default to " + tests[i][2]); +} +</script> +</pre> diff --git a/dom/html/test/test_bug586786.html b/dom/html/test/test_bug586786.html new file mode 100644 index 0000000000..3cfa7fa4b4 --- /dev/null +++ b/dom/html/test/test_bug586786.html @@ -0,0 +1,57 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=586786 +--> +<head> + <title>Test for Bug 586786</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=586786">Mozilla Bug 586786</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 586786 **/ + +var elements = ["col", "colgroup", "tbody", "tfoot", "thead", "tr", "td", "th"]; + +for(var i = 0; i < elements.length; i++) +{ + reflectString({ + element: document.createElement(elements[i]), + attribute: "align", + otherValues: [ "left", "right", "center", "justify", "char" ] + }); + + reflectString({ + element: document.createElement(elements[i]), + attribute: "vAlign", + otherValues: [ "top", "middle", "bottom", "baseline" ] + }); + + reflectString({ + element: document.createElement(elements[i]), + attribute: {idl: "ch", content: "char"} + }); +} + +// table.border, table.width +reflectString({ + element: document.createElement("table"), + attribute: "border" +}); + +reflectString({ + element: document.createElement("table"), + attribute: "width" +}); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug587469.html b/dom/html/test/test_bug587469.html new file mode 100644 index 0000000000..b0e941296a --- /dev/null +++ b/dom/html/test/test_bug587469.html @@ -0,0 +1,41 @@ +<!-- Quirks --> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=587469 +--> +<head> + <title>Test for Bug 587469</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=587469">Mozilla Bug 587469</a> +<p id="display"> +<map name=a></map> +<map name=a><area shape=rect coords=25,25,75,75 href=#fail></map> +<img usemap=#a src=image.png> +</p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> +/** Test for Bug 587469 **/ +SimpleTest.waitForExplicitFinish(); +function finish() { + is(location.hash, "", "Should not have changed the hash."); + SimpleTest.finish(); +} +SimpleTest.waitForFocus(function() { + synthesizeMouse(document.getElementsByTagName("img")[0], 50, 50, {}); + // Hit the event loop twice before doing the test + setTimeout(function() { + setTimeout(finish, 0); + }, 0); +}); + + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug589.html b/dom/html/test/test_bug589.html new file mode 100644 index 0000000000..3a4ac666a7 --- /dev/null +++ b/dom/html/test/test_bug589.html @@ -0,0 +1,42 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=589 +--> +<head> + <title>Test for Bug 589</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + +<style type="text/css"> +.letters {list-style-type: upper-alpha;} +.numbers {list-style-type: decimal;} +</style> + +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=589">Mozilla Bug 589</a> +<p id="display"></p> +<div id="content" > + +<OL id="thelist" class="letters"> +<LI id="liA">This list should feature... +<LI id="liB">...letters for each item... +<LI id="li3" class="numbers">...except this one. +</OL> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 589 **/ + +is(computedStyle($("liA"),"list-style-type"),"upper-alpha"); +is(computedStyle($("liB"),"list-style-type"),"upper-alpha"); +is(computedStyle($("li3"),"list-style-type"),"decimal"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug590353-1.html b/dom/html/test/test_bug590353-1.html new file mode 100644 index 0000000000..af79317f36 --- /dev/null +++ b/dom/html/test/test_bug590353-1.html @@ -0,0 +1,36 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=590353 +--> +<head> + <title>Test for Bug 590353</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=590353">Mozilla Bug 590353</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 590353 **/ + +var testData = ['checkbox', 'radio']; + +for (var data of testData) { + var e = document.createElement('input'); + e.type = data; + e.checked = true; + e.value = "foo"; + + is(e.value, "foo", "foo should be the new " + data + "value"); + is(e.getAttribute('value'), "foo", "foo should be the new " + data + + " value attribute value"); + ok(e.checked, data + " should still be checked"); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug590353-2.html b/dom/html/test/test_bug590353-2.html new file mode 100644 index 0000000000..9ef6e40e23 --- /dev/null +++ b/dom/html/test/test_bug590353-2.html @@ -0,0 +1,79 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=590353 +--> +<head> + <title>Test for Bug 590353</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=590353">Mozilla Bug 590353</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 590353 **/ + +var testData = [ + [ "text", "foo", "" ], + [ "email", "foo@bar.com", "" ], + [ "url", "http:///foo.com", "" ], + [ "tel", "555 555 555 555", "" ], + [ "search", "foo", "" ], + [ "password", "secret", "" ], + [ "hidden", "foo", "foo" ], + [ "button", "foo", "foo" ], + [ "reset", "foo", "foo" ], + [ "submit", "foo", "foo" ], + [ "checkbox", true, false ], + [ "radio", true, false ], + [ "file", "590353_file", "" ], +]; + +function createFileWithData(fileName, fileData) { + return new File([new Blob([fileData], { type: "text/plain" })], fileName); +} + +var content = document.getElementById('content'); +var form = document.createElement('form'); +content.appendChild(form); + +for (var data of testData) { + var e = document.createElement('input'); + e.type = data[0]; + + if (data[0] == 'checkbox' || data[0] == 'radio') { + e.checked = data[1]; + } else if (data[0] == 'file') { + var file = createFileWithData(data[1], "file content"); + SpecialPowers.wrap(e).mozSetFileArray([file]); + } else { + e.value = data[1]; + } + + form.appendChild(e); +} + +form.reset(); + +var size = form.elements.length; +for (var i=0; i<size; ++i) { + var e = form.elements[i]; + + if (e.type == 'radio' || e.type == 'checkbox') { + is(e.checked, testData[i][2], + "the element checked value should be " + testData[i][2]); + } else { + is(e.value, testData[i][2], + "the element value should be " + testData[i][2]); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug590363.html b/dom/html/test/test_bug590363.html new file mode 100644 index 0000000000..de12079a71 --- /dev/null +++ b/dom/html/test/test_bug590363.html @@ -0,0 +1,133 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=590363 +--> +<head> + <title>Test for Bug 590363</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=590363">Mozilla Bug 590363</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 590363 **/ + +var testData = [ + /* type to test | is the value reset when changing to file then reverting */ + [ "button", false ], + [ "checkbox", false ], + [ "hidden", false ], + [ "reset", false ], + [ "image", false ], + [ "radio", false ], + [ "submit", false ], + [ "tel", true ], + [ "text", true ], + [ "url", true ], + [ "email", true ], + [ "search", true ], + [ "password", true ], + [ "number", true ], + [ "date", true ], + [ "time", true ], + [ "range", true ], + [ "color", true ], + [ 'month', true ], + [ 'week', true ], + [ 'datetime-local', true ] + // 'file' is treated separatly. +]; + +var nonTrivialSanitizing = [ 'number', 'date', 'time', 'color', 'month', 'week', + 'datetime-local' ]; + +var length = testData.length; +for (var i=0; i<length; ++i) { + for (var j=0; j<length; ++j) { + var e = document.createElement('input'); + e.type = testData[i][0]; + + var expectedValue; + + // range will sanitize its value to 50 (the default) if it isn't a valid + // number. We need to handle that specially. + if (testData[j][0] == 'range' || testData[i][0] == 'range') { + if (testData[j][0] == 'date' || testData[j][0] == 'time' || + testData[j][0] == 'month' || testData[j][0] == 'week' || + testData[j][0] == 'datetime-local') { + expectedValue = ''; + } else if (testData[j][0] == 'color') { + expectedValue = '#000000'; + } else { + expectedValue = '50'; + } + } else if (testData[i][0] == 'color' || testData[j][0] == 'color') { + if (testData[j][0] == 'number' || testData[j][0] == 'date' || + testData[j][0] == 'time' || testData[j][0] == 'month' || + testData[j][0] == 'week' || testData[j][0] == 'datetime-local') { + expectedValue = '' + } else { + expectedValue = '#000000'; + } + } else if (nonTrivialSanitizing.includes(testData[i][0]) && + nonTrivialSanitizing.includes(testData[j][0])) { + expectedValue = ''; + } else if (testData[i][0] == 'number' || testData[j][0] == 'number') { + expectedValue = '42'; + } else if (testData[i][0] == 'date' || testData[j][0] == 'date') { + expectedValue = '2012-12-21'; + } else if (testData[i][0] == 'time' || testData[j][0] == 'time') { + expectedValue = '21:21'; + } else if (testData[i][0] == 'month' || testData[j][0] == 'month') { + expectedValue = '2013-03'; + } else if (testData[i][0] == 'week' || testData[j][0] == 'week') { + expectedValue = '2016-W35'; + } else if (testData[i][0] == 'datetime-local' || + testData[j][0] == 'datetime-local') { + expectedValue = '2016-11-07T16:40'; + } else { + expectedValue = "foo"; + } + e.value = expectedValue; + + e.type = testData[j][0]; + is(e.value, expectedValue, ".value should still return the same value after " + + "changing type from " + testData[i][0] + " to " + testData[j][0]); + } +} + +// For type='file' .value doesn't behave the same way. +// We are just going to check that we do not loose the value. +for (var data of testData) { + var e = document.createElement('input'); + e.type = data[0]; + e.value = 'foo'; + e.type = 'file'; + e.type = data[0]; + + if (data[0] == 'range') { + is(e.value, '50', ".value should still return the same value after " + + "changing type from " + data[0] + " to 'file' then reverting to " + data[0]); + } else if (data[0] == 'color') { + is(e.value, '#000000', ".value should have been reset to the default color after " + + "changing type from " + data[0] + " to 'file' then reverting to " + data[0]); + } else if (data[1]) { + is(e.value, '', ".value should have been reset to the empty string after " + + "changing type from " + data[0] + " to 'file' then reverting to " + data[0]); + } else { + is(e.value, 'foo', ".value should still return the same value after " + + "changing type from " + data[0] + " to 'file' then reverting to " + data[0]); + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug592802.html b/dom/html/test/test_bug592802.html new file mode 100644 index 0000000000..e8b30d84c8 --- /dev/null +++ b/dom/html/test/test_bug592802.html @@ -0,0 +1,96 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=592802 +--> +<head> + <title>Test for Bug 592802</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=592802">Mozilla Bug 592802</a> +<p id="display"></p> +<div id="content"> + <input id='a' type='file'> + <input id='a2' type='file'> +</div> +<button id='b' onclick="document.getElementById('a').click();">Show Filepicker</button> +<button id='b2' onclick="document.getElementById('a2').click();">Show Filepicker</button> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 592802 **/ + +SimpleTest.waitForExplicitFinish(); + +var MockFilePicker = SpecialPowers.MockFilePicker; +MockFilePicker.init(window); + +var testData = [ +/* visibility | display | multiple */ + [ "", "", false ], + [ "hidden", "", false ], + [ "", "none", false ], + [ "", "", true ], + [ "hidden", "", true ], + [ "", "none", true ], +]; + +var testCounter = 0; +var testNb = testData.length; + +function finished() +{ + MockFilePicker.cleanup(); + SimpleTest.finish(); +} + +SimpleTest.waitForFocus(function() { + // mockFilePicker will simulate a cancel for the first time the file picker will be shown. + MockFilePicker.returnValue = MockFilePicker.returnCancel; + + var b2 = document.getElementById('b2'); + b2.focus(); // Be sure the element is visible. + document.getElementById('b2').addEventListener("change", function(aEvent) { + ok(false, "When cancel is received, change should not fire"); + }, {once: true}); + b2.click(); + + // Now, we can launch tests when file picker isn't canceled. + MockFilePicker.useBlobFile(); + MockFilePicker.returnValue = MockFilePicker.returnOK; + + var b = document.getElementById('b'); + b.focus(); // Be sure the element is visible. + + document.getElementById('a').addEventListener("change", function(aEvent) { + ok(true, "change event correctly sent"); + ok(aEvent.bubbles, "change event should bubble"); + ok(!aEvent.cancelable, "change event should not be cancelable"); + testCounter++; + + if (testCounter >= testNb) { + aEvent.target.removeEventListener("change", arguments.callee); + SimpleTest.executeSoon(finished); + } else { + var data = testData[testCounter]; + var a = document.getElementById('a'); + a.style.visibility = data[0]; + a.style.display = data[1]; + a.multiple = data[2]; + + SimpleTest.executeSoon(function() { + b.click(); + }); + } + }); + + b.click(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug593689.html b/dom/html/test/test_bug593689.html new file mode 100644 index 0000000000..14cfa8f0fb --- /dev/null +++ b/dom/html/test/test_bug593689.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=593689 +--> +<head> + <title>Test for Bug 593689</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=593689">Mozilla Bug 593689</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 593689 **/ +function testWidth(w) { + var img = new Image(w); + is(img.width, w|0, "Unexpected handling of '" + w + "' width"); +} + +testWidth(1); +testWidth(0); +testWidth("xxx"); +testWidth(null); +testWidth(undefined); +testWidth({}); +testWidth({ valueOf() { return 10; } }); + +function testHeight(h) { + var img = new Image(100, h); + is(img.height, h|0, "Unexpected handling of '" + h + "' height"); +} + +testHeight(1); +testHeight(0); +testHeight("xxx"); +testHeight(null); +testHeight(undefined); +testHeight({}); +testHeight({ valueOf() { return 10; } }); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug595429.html b/dom/html/test/test_bug595429.html new file mode 100644 index 0000000000..9a9215bd6c --- /dev/null +++ b/dom/html/test/test_bug595429.html @@ -0,0 +1,56 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=595429 +--> +<head> + <title>Test for Bug 595429</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=595429">Mozilla Bug 595429</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 595429 **/ + +var fieldset = document.createElement("fieldset"); + +ok("name" in fieldset, "<fieldset> should have a name IDL attribute"); + +var testData = [ + "", + " ", + "foo", + "foo bar", +]; + +is(fieldset.getAttribute("name"), null, + "By default, name content attribute should be null"); +is(fieldset.name, "", + "By default, name IDL attribute should be the empty string"); + +for (var data of testData) { + fieldset.setAttribute("name", data); + is(fieldset.getAttribute("name"), data, + "name content attribute should be " + data); + is(fieldset.name, data, "name IDL attribute should be " + data); + + fieldset.setAttribute("name", ""); + fieldset.name = data; + is(fieldset.getAttribute("name"), data, + "name content attribute should be " + data); + is(fieldset.name, data, "name IDL attribute should be " + data); +} + +fieldset.removeAttribute("name"); +is(fieldset.getAttribute("name"), null, + "name content attribute should be null"); +is(fieldset.name, "", "name IDL attribute should be the empty string"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug595447.html b/dom/html/test/test_bug595447.html new file mode 100644 index 0000000000..e647364879 --- /dev/null +++ b/dom/html/test/test_bug595447.html @@ -0,0 +1,29 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=595447 +--> +<head> + <title>Test for Bug 595447</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=595447">Mozilla Bug 595447</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 595447 **/ + +var fieldset = document.createElement("fieldset"); + +ok("type" in fieldset, "fieldset element should have a type IDL attribute"); +is(fieldset.type, "fieldset", "fieldset.type should return 'fieldset'"); +fieldset.type = "foo"; +is(fieldset.type, "fieldset", "fieldset.type is readonly"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug595449.html b/dom/html/test/test_bug595449.html new file mode 100644 index 0000000000..5649b246ae --- /dev/null +++ b/dom/html/test/test_bug595449.html @@ -0,0 +1,95 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=595449 +--> +<head> + <title>Test for Bug 595449</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=595449">Mozilla Bug 595449</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 595449 **/ + +var fieldset = document.createElement("fieldset"); + +ok("elements" in fieldset, + "fieldset element should have an 'elements' IDL attribute"); + +ok(fieldset.elements instanceof HTMLCollection, + "fieldset.elements should be an instance of HTMLCollection"); + +// https://www.w3.org/Bugs/Public/show_bug.cgi?id=23356 +todo(fieldset.elements instanceof HTMLFormControlsCollection, + "fieldset.elements should be an instance of HTMLFormControlsCollection"); + +is(fieldset.elements.length, 0, "Nothing should be in fieldset.elements"); + +var oldElements = fieldset.elements; + +is(fieldset.elements, oldElements, + "fieldset.elements should always return the same object"); + +var tmpElement = document.createElement("input"); + +fieldset.appendChild(tmpElement); + +is(fieldset.elements.length, 1, + "fieldset.elements should now contain one element"); + +is(fieldset.elements[0], tmpElement, + "fieldset.elements[0] should be the input element"); + +tmpElement.name = "foo"; +is(fieldset.elements.foo, tmpElement, + "we should be able to access to an element using it's name as a property on .elements"); + +is(fieldset.elements, oldElements, + "fieldset.elements should always return the same object"); + +fieldset.removeChild(tmpElement); + +var testData = [ + [ "<input>", 1 , [ HTMLInputElement ] ], + [ "<button></button>", 1, [ HTMLButtonElement ] ], + [ "<button><input></button>", 2, [ HTMLButtonElement, HTMLInputElement ] ], + [ "<object>", 1, [ HTMLObjectElement ] ], + [ "<output></output>", 1, [ HTMLOutputElement ] ], + [ "<select></select>", 1, [ HTMLSelectElement ] ], + [ "<select><option>foo</option></select>", 1, [ HTMLSelectElement ] ], + [ "<select><option>foo</option><input></select>", 2, [ HTMLSelectElement, HTMLInputElement ] ], + [ "<textarea></textarea>", 1, [ HTMLTextAreaElement ] ], + [ "<label>foo</label>", 0 ], + [ "<progress>", 0 ], + [ "<meter>", 0 ], + [ "<keygen>", 0 ], + [ "<legend></legend>", 0 ], + [ "<legend><input></legend>", 1, [ HTMLInputElement ] ], + [ "<legend><input></legend><legend><input></legend>", 2, [ HTMLInputElement, HTMLInputElement ] ], + [ "<legend><input></legend><input>", 2, [ HTMLInputElement, HTMLInputElement ] ], + [ "<fieldset></fieldset>", 1, [ HTMLFieldSetElement ] ], + [ "<fieldset><input></fieldset>", 2, [ HTMLFieldSetElement, HTMLInputElement ] ], + [ "<fieldset><fieldset><input></fieldset></fieldset>", 3, [ HTMLFieldSetElement, HTMLFieldSetElement, HTMLInputElement ] ], + [ "<button></button><fieldset></fieldset><input><keygen><object><output></output><select></select><textarea></textarea>", 7, [ HTMLButtonElement, HTMLFieldSetElement, HTMLInputElement, HTMLObjectElement, HTMLOutputElement, HTMLSelectElement, HTMLTextAreaElement ] ], +]; + +for (var data of testData) { + fieldset.innerHTML = data[0]; + is(fieldset.elements.length, data[1], + "fieldset.elements should contain " + data[1] + " elements"); + + for (var i=0; i<data[1]; ++i) { + ok(fieldset.elements[i] instanceof data[2][i], + "fieldset.elements[" + i + "] should be instance of " + data[2][i]) + } +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug596350.html b/dom/html/test/test_bug596350.html new file mode 100644 index 0000000000..72e2f7ce73 --- /dev/null +++ b/dom/html/test/test_bug596350.html @@ -0,0 +1,65 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=596350 +--> +<head> + <title>Test for Bug 596350</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=596350">Mozilla Bug 596350</a> +<p id="display"></p> +<div id="content"> + <object></object> + <object data="iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMsALGPC/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IAAAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1JREFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jqch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0vr4MkhoXe0rZigAAAABJRU5ErkJggg=="></object> + <object data="data:text/html,foo"></object> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 596350 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(runTests); + +var testData = [ +// Object 0 + [ 0, null, 0 ], + [ 0, "1", 1 ], + [ 0, "-1", -1 ], + [ 0, "0", 0 ], + [ 0, "foo", 0 ], +// Object 1 + [ 1, null, 0 ], + [ 1, "1", 1 ], +// Object 2 + [ 2, null, 0 ], + [ 2, "1", 1 ], + [ 2, "-1", -1 ], +]; + +var objects = document.getElementsByTagName("object"); + +function runTests() +{ + for (var data of testData) { + var obj = objects[data[0]]; + + if (data[1]) { + obj.setAttribute("tabindex", data[1]); + } + + is(obj.tabIndex, data[2], "tabIndex value should be " + data[2]); + + obj.removeAttribute("tabindex"); + } + + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug596511.html b/dom/html/test/test_bug596511.html new file mode 100644 index 0000000000..42b93e4632 --- /dev/null +++ b/dom/html/test/test_bug596511.html @@ -0,0 +1,237 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=596511 +--> +<head> + <title>Test for Bug 596511</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + select:valid { background-color: green; } + select:invalid { background-color: red; } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=596511">Mozilla Bug 596511</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script> + +/** Test for Bug 596511 **/ + +function checkNotSufferingFromBeingMissing(element, aTodo) +{ + if (aTodo) { + ok = todo; + is = todo_is; + } + + ok(!element.validity.valueMissing, + "Element should not suffer from value missing"); + ok(element.validity.valid, "Element should be valid"); + ok(element.checkValidity(), "Element should be valid"); + + is(element.validationMessage, "", + "Validation message should be the empty string"); + + ok(element.matches(":valid"), ":valid pseudo-class should apply"); + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(0, 128, 0)", ":valid pseudo-class should apply"); + + if (aTodo) { + ok = SimpleTest.ok; + is = SimpleTest.is; + } +} + +function checkSufferingFromBeingMissing(element, aTodo) +{ + if (aTodo) { + ok = todo; + is = todo_is; + } + + ok(element.validity.valueMissing, "Element should suffer from value missing"); + ok(!element.validity.valid, "Element should not be valid"); + ok(!element.checkValidity(), "Element should not be valid"); + + is(element.validationMessage, "Please select an item in the list.", + "Validation message is wrong"); + + is(window.getComputedStyle(element).getPropertyValue('background-color'), + "rgb(255, 0, 0)", ":invalid pseudo-class should apply"); + + if (aTodo) { + ok = SimpleTest.ok; + is = SimpleTest.is; + } +} + +function checkRequiredAttribute(element) +{ + ok('required' in element, "select should have a required attribute"); + + ok(!element.required, "select required attribute should be disabled"); + is(element.getAttribute('required'), null, + "select required attribute should be disabled"); + + element.required = true; + ok(element.required, "select required attribute should be enabled"); + isnot(element.getAttribute('required'), null, + "select required attribute should be enabled"); + + element.removeAttribute('required'); + element.setAttribute('required', ''); + ok(element.required, "select required attribute should be enabled"); + isnot(element.getAttribute('required'), null, + "select required attribute should be enabled"); + + element.removeAttribute('required'); + ok(!element.required, "select required attribute should be disabled"); + is(element.getAttribute('required'), null, + "select required attribute should be disabled"); +} + +function checkRequiredAndOptionalSelectors(element) +{ + is(document.querySelector("select:optional"), element, + "select should be optional"); + is(document.querySelector("select:required"), null, + "select shouldn't be required"); + + element.required = true; + + is(document.querySelector("select:optional"), null, + "select shouldn't be optional"); + is(document.querySelector("select:required"), element, + "select should be required"); + + element.required = false; +} + +function checkInvalidWhenValueMissing(element) +{ + checkNotSufferingFromBeingMissing(select); + + element.required = true; + checkSufferingFromBeingMissing(select); + + /** + * Non-multiple and size=1. + */ + select.appendChild(new Option()); + checkSufferingFromBeingMissing(select); + + // When removing the required attribute, element should not be invalid. + element.required = false; + checkNotSufferingFromBeingMissing(select); + + element.required = true; + select.options[0].textContent = "foo"; + // TODO: having that working would require us to add a mutation observer on + // the select element. + checkNotSufferingFromBeingMissing(select, true); + + select.remove(0); + checkSufferingFromBeingMissing(select); + + select.add(new Option("foo", "foo"), null); + checkNotSufferingFromBeingMissing(select); + + select.add(new Option(), null); + checkNotSufferingFromBeingMissing(select); + + // The placeholder label can only be the first option, so a selected empty second option is valid + select.options[1].selected = true; + checkNotSufferingFromBeingMissing(select); + + select.selectedIndex = 0; + checkNotSufferingFromBeingMissing(select); + + select.add(select.options[0]); + select.selectedIndex = 0; + checkSufferingFromBeingMissing(select); + + select.remove(0); + checkNotSufferingFromBeingMissing(select); + + select.options[0].disabled = true; + // TODO: having that working would require us to add a mutation observer on + // the select element. + checkSufferingFromBeingMissing(select, true); + + select.options[0].disabled = false + select.remove(0); + checkSufferingFromBeingMissing(select); + + var option = new Option("foo", "foo"); + option.disabled = true; + select.add(option, null); + select.add(new Option("bar"), null); + option.selected = true; + checkNotSufferingFromBeingMissing(select); + + select.remove(0); + select.remove(0); + + /** + * Non-multiple and size > 1. + * Everything should be the same except moving the selection. + */ + select.multiple = false; + select.size = 4; + checkSufferingFromBeingMissing(select); + + // Setting defaultSelected to true should not make the option selected + select.add(new Option("", "", true), null); + checkSufferingFromBeingMissing(select); + select.remove(0); + + select.add(new Option("", "", true, true), null); + checkNotSufferingFromBeingMissing(select); + + select.add(new Option("foo", "foo"), null); + select.remove(0); + checkSufferingFromBeingMissing(select); + + select.options[0].selected = true; + checkNotSufferingFromBeingMissing(select); + + select.remove(0); + + /** + * Multiple, any size. + * We can select more than one element and at least needs a value. + */ + select.multiple = true; + select.size = 4; + checkSufferingFromBeingMissing(select); + + select.add(new Option("", "", true), null); + checkSufferingFromBeingMissing(select); + + select.add(new Option("", "", true), null); + checkSufferingFromBeingMissing(select); + + select.add(new Option("foo"), null); + checkSufferingFromBeingMissing(select); + + select.options[2].selected = true; + checkNotSufferingFromBeingMissing(select); +} + +var select = document.createElement("select"); +var content = document.getElementById('content'); +content.appendChild(select); + +checkRequiredAttribute(select); +checkRequiredAndOptionalSelectors(select); +checkInvalidWhenValueMissing(select); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug598643.html b/dom/html/test/test_bug598643.html new file mode 100644 index 0000000000..12f91fdec4 --- /dev/null +++ b/dom/html/test/test_bug598643.html @@ -0,0 +1,80 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=598643 +--> +<head> + <title>Test for Bug 598643</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=598643">Mozilla Bug 598643</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 598643 **/ + +function createFileWithData(fileName, fileData) +{ + return new File([new Blob([fileData], { type: "text/plain" })], fileName); +} + +function testFileControl(aElement) +{ + aElement.type = 'file'; + + var file = createFileWithData("file_bug598643", "file content"); + SpecialPowers.wrap(aElement).mozSetFileArray([file]); + + ok(aElement.validity.valid, "the file control should be valid"); + ok(!aElement.validity.tooLong, + "the file control shouldn't suffer from being too long"); +} + +var types = [ + // These types can be too long. + [ "text", "email", "password", "url", "search", "tel" ], + // These types can't be too long. + [ "radio", "checkbox", "submit", "button", "reset", "image", "hidden", + 'number', 'range', 'date', 'time', 'color', 'month', 'week', + 'datetime-local' ], +]; + +var input = document.createElement("input"); +input.maxLength = 1; +input.value = "foo"; + +// Too long types. +for (type of types[0]) { + input.type = type + if (type == 'email') { + input.value = "foo@bar.com"; + } else if (type == 'url') { + input.value = 'http://foo.org'; + } + + todo(!input.validity.valid, "the element should be invalid [type=" + type + "]"); + todo(input.validity.tooLong, + "the element should suffer from being too long [type=" + type + "]"); + + if (type == 'email' || type == 'url') { + input.value = 'foo'; + } +} + +// Not too long types. +for (type of types[1]) { + input.type = type + ok(input.validity.valid, "the element should be valid [type=" + type + "]"); + ok(!input.validity.tooLong, + "the element shouldn't suffer from being too long [type=" + type + "]"); +} + +testFileControl(input); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug598833-1.html b/dom/html/test/test_bug598833-1.html new file mode 100644 index 0000000000..5fbbe221e5 --- /dev/null +++ b/dom/html/test/test_bug598833-1.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=598833 +--> +<head> + <title>Test for Bug 598833</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=598833">Mozilla Bug 598833</a> +<p id="display"> + <fieldset disabled> + <select id="s" multiple required> + <option>one</option> + </select> + </fieldset> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 598833 **/ +var s = $("s"); +is(s.matches(":invalid"), false, "Disabled select should not be invalid"); +is(s.matches(":valid"), false, "Disabled select should not be valid"); +var p = s.parentNode; +p.removeChild(s); +is(s.matches(":invalid"), true, + "Required valueless select not in tree should be invalid"); +is(s.matches(":valid"), false, + "Required valueless select not in tree should not be valid"); +p.appendChild(s); +p.disabled = false; +is(s.matches(":invalid"), true, + "Required valueless select should be invalid"); +is(s.matches(":valid"), false, + "Required valueless select should not be valid"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug600155.html b/dom/html/test/test_bug600155.html new file mode 100644 index 0000000000..893dfe31f1 --- /dev/null +++ b/dom/html/test/test_bug600155.html @@ -0,0 +1,44 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=600155 +--> +<head> + <title>Test for Bug 600155</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=600155">Mozilla Bug 600155</a> +<p id="display"></p> +<div id='content' style='display:none;'> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 600155 **/ + +var subjectForConstraintValidation = [ "input", "select", "textarea" ]; +var content = document.getElementById('content'); + +for (var eName of subjectForConstraintValidation) { + var e = document.createElement(eName); + content.appendChild(e); + e.setCustomValidity("foo"); + if ("required" in e) { + e.required = true; + } else { + e.setCustomValidity("bar"); + } + + // At this point, the element is invalid. + is(e.validationMessage, "foo", + "the validation message should be the author one"); + + content.removeChild(e); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug601030.html b/dom/html/test/test_bug601030.html new file mode 100644 index 0000000000..f9a277f471 --- /dev/null +++ b/dom/html/test/test_bug601030.html @@ -0,0 +1,52 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=601030 +--> +<head> + <title>Test for Bug 601030</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=601030">Mozilla Bug 601030</a> +<p id="display"></p> +<div id="content"> + <iframe src="data:text/html,<input autofocus>"></iframe> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 601030 **/ + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + var f = document.createElement("iframe"); + var content = document.getElementById('content'); + + f.addEventListener("load", function() { + SimpleTest.executeSoon(function() { + isnot(document.activeElement, f, + "autofocus should not work when another frame is inserted in the document"); + + content.removeChild(f); + content.removeChild(document.getElementsByTagName('iframe')[0]); + f = document.createElement('iframe'); + f.addEventListener("load", function() { + isnot(document.activeElement, f, + "autofocus should not work in a frame if the top document is already loaded"); + SimpleTest.finish(); + }, {once: true}); + f.src = "data:text/html,<input autofocus>"; + content.appendChild(f); + }); + }, {once: true}); + + f.src = "data:text/html,<input autofocus>"; + content.appendChild(f); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug605124-1.html b/dom/html/test/test_bug605124-1.html new file mode 100644 index 0000000000..d252987ee9 --- /dev/null +++ b/dom/html/test/test_bug605124-1.html @@ -0,0 +1,98 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=605124 +--> +<head> + <title>Test for Bug 605124</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=605124">Mozilla Bug 605124</a> +<p id="display"></p> +<div id="content"> + <form> + <textarea required></textarea> + <input required> + <select required></select> + <button type='submit'></button> + </form> + + <table> + <form> + <tr> + <textarea required></textarea> + <input required> + <select required></select> + <button type='submit'></button> + </tr> + </form> + </table> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 605124 **/ + +function checkPseudoClass(aElement, aExpected) +{ + is(aElement.matches(":user-invalid"), aExpected, + "matches(':user-invalid') should return " + aExpected + " for " + aElement); +} + +var content = document.getElementById('content'); +var textarea = document.getElementsByTagName('textarea')[0]; +var input = document.getElementsByTagName('input')[0]; +var select = document.getElementsByTagName('select')[0]; +var button = document.getElementsByTagName('button')[0]; +var form = document.forms[0]; + +checkPseudoClass(textarea, false); +checkPseudoClass(input, false); +checkPseudoClass(select, false); + +// Try to submit. +button.click(); +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); + +// No longer in the form. +content.appendChild(textarea); +content.appendChild(input); +content.appendChild(select); +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); + +// Back in the form. +form.appendChild(textarea); +form.appendChild(input); +form.appendChild(select); +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); + +/* Case when elements get orphaned. */ +var textarea = document.getElementsByTagName('textarea')[1]; +var input = document.getElementsByTagName('input')[1]; +var select = document.getElementsByTagName('select')[1]; +var button = document.getElementsByTagName('button')[1]; +var form = document.forms[1]; + +// Try to submit. +button.click(); +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); + +// Remove the form. +document.getElementsByTagName('table')[0].removeChild(form); +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug605124-2.html b/dom/html/test/test_bug605124-2.html new file mode 100644 index 0000000000..07e3e5afcd --- /dev/null +++ b/dom/html/test/test_bug605124-2.html @@ -0,0 +1,117 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=605124 +--> +<head> + <title>Test for Bug 605124</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=605124">Mozilla Bug 605124</a> +<p id="display"></p> +<div id="content"> + <input required> + <textarea required></textarea> + <select required> + <option value="">foo</option> + <option>bar</option> + </select> + <select multiple required> + <option value="">foo</option> + <option>bar</option> + </select> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 605124 **/ + +function checkPseudoClass(aElement, aExpected) +{ + is(aElement.matches(":-moz-ui-invalid"), aExpected, + "matches(':-moz-ui-invalid') should return " + aExpected + " for " + aElement); +} + +function checkElement(aElement) +{ + checkPseudoClass(aElement, false); + + // Focusing while :-moz-ui-invalid doesn't apply, + // the pseudo-class should not apply while typing. + aElement.focus(); + checkPseudoClass(aElement, false); + // with keys + sendString("f"); + checkPseudoClass(aElement, false); + synthesizeKey("KEY_Backspace"); + checkPseudoClass(aElement, false); + // with .value + aElement.value = 'f'; + checkPseudoClass(aElement, false); + aElement.value = ''; + checkPseudoClass(aElement, false); + + aElement.blur(); + checkPseudoClass(aElement, true); + + // Focusing while :-moz-ui-invalid applies, + // the pseudo-class should apply while typing if appropriate. + aElement.focus(); + checkPseudoClass(aElement, true); + // with keys + sendString("f"); + checkPseudoClass(aElement, false); + synthesizeKey("KEY_Backspace"); + checkPseudoClass(aElement, true); + // with .value + aElement.value = 'f'; + checkPseudoClass(aElement, false); + aElement.value = ''; + checkPseudoClass(aElement, true); +} + +function checkSelectElement(aElement) +{ + checkPseudoClass(aElement, false); + + // Focusing while :-moz-ui-invalid doesn't apply, + // the pseudo-class should not apply while changing selection. + aElement.focus(); + checkPseudoClass(aElement, false); + + aElement.selectedIndex = 1; + checkPseudoClass(aElement, false); + aElement.selectedIndex = 0; + checkPseudoClass(aElement, false); + + aElement.blur(); + checkPseudoClass(aElement, false); + + // Focusing while :-moz-ui-invalid applies, + // the pseudo-class should apply while changing selection if appropriate. + aElement.focus(); + checkPseudoClass(aElement, false); + + aElement.selectedIndex = 1; + checkPseudoClass(aElement, false); + aElement.selectedIndex = 0; + checkPseudoClass(aElement, false); + aElement.selectedIndex = 1; + checkPseudoClass(aElement, false); + + aElement.blur(); + checkPseudoClass(aElement, false); +} + +checkElement(document.getElementsByTagName('input')[0]); +checkElement(document.getElementsByTagName('textarea')[0]); +checkSelectElement(document.getElementsByTagName('select')[0]); +checkSelectElement(document.getElementsByTagName('select')[1]); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug605125-1.html b/dom/html/test/test_bug605125-1.html new file mode 100644 index 0000000000..8b49b9bbc1 --- /dev/null +++ b/dom/html/test/test_bug605125-1.html @@ -0,0 +1,105 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=605125 +--> +<head> + <title>Test for Bug 605125</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=605125">Mozilla Bug 605125</a> +<p id="display"></p> +<div id="content"> + <form id='f1'> + <textarea></textarea> + <input> + <button type='submit'></button> + <select></select> + </form> + + <table> + <form id='f2'> + <tr> + <textarea></textarea> + <input> + <button type='submit'></button> + <select></select> + </tr> + </form> + </table> + <input form='f1' required> + <input form='f2' required> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 605125 **/ + +/** + * NOTE: this test is very similar to 605124-1.html. + */ + +function checkPseudoClass(aElement, aExpected) +{ + is(aElement.matches(":-moz-ui-valid"), aExpected, + "matches(':-moz-ui-valid') should return " + aExpected + " for " + aElement); +} + +var content = document.getElementById('content'); +var textarea = document.getElementsByTagName('textarea')[0]; +var input = document.getElementsByTagName('input')[0]; +var button = document.getElementsByTagName('button')[0]; +var select = document.getElementsByTagName('select')[0]; +var form = document.forms[0]; + +checkPseudoClass(textarea, false); +checkPseudoClass(input, false); +checkPseudoClass(select, false); + +// Try to submit. +button.click(); +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); + +// No longer in the form. +content.appendChild(textarea); +content.appendChild(input); +content.appendChild(select); +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); + +// Back in the form. +form.appendChild(textarea); +form.appendChild(input); +form.appendChild(select); +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); + +/* Case when elements get orphaned. */ +var textarea = document.getElementsByTagName('textarea')[1]; +var input = document.getElementsByTagName('input')[1]; +var button = document.getElementsByTagName('button')[1]; +var select = document.getElementsByTagName('select')[1]; +var form = document.forms[1]; + +// Try to submit. +button.click(); +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); + +// Remove the form. +document.getElementsByTagName('table')[0].removeChild(form); +checkPseudoClass(textarea, true); +checkPseudoClass(input, true); +checkPseudoClass(select, true); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug605125-2.html b/dom/html/test/test_bug605125-2.html new file mode 100644 index 0000000000..ea1195e189 --- /dev/null +++ b/dom/html/test/test_bug605125-2.html @@ -0,0 +1,149 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=605125 +--> +<head> + <title>Test for Bug 605125</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=605125">Mozilla Bug 605125</a> +<p id="display"></p> +<div id="content"> + <input> + <textarea></textarea> + <select> + <option value="">foo</option> + <option>bar</option> + </select> + <select multiple> + <option value="">foo</option> + <option>bar</option> + </select> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 605125 **/ + +function checkPseudoClass(aElement, aExpected) +{ + is(aElement.matches(":user-valid"), aExpected, + "matches(':user-valid') should return " + aExpected + " for " + aElement.outerHTML); +} + +function checkElement(aElement) +{ + checkPseudoClass(aElement, false); + + // Focusing while :user-valid doesn't apply, + // the pseudo-class should not apply while typing. + aElement.focus(); + checkPseudoClass(aElement, false); + // with keys + sendString("f"); + checkPseudoClass(aElement, false); + synthesizeKey("KEY_Backspace"); + checkPseudoClass(aElement, false); + // with .value + aElement.value = 'f'; + checkPseudoClass(aElement, false); + aElement.value = ''; + checkPseudoClass(aElement, false); + + aElement.blur(); + checkPseudoClass(aElement, true); + + // Focusing while :user-valid applies, + // the pseudo-class should apply while typing if appropriate. + aElement.focus(); + checkPseudoClass(aElement, true); + // with keys + sendString("f"); + checkPseudoClass(aElement, true); + synthesizeKey("KEY_Backspace"); + checkPseudoClass(aElement, true); + // with .value + aElement.value = 'f'; + checkPseudoClass(aElement, true); + aElement.value = ''; + checkPseudoClass(aElement, true); + + aElement.blur(); + aElement.required = true; + checkPseudoClass(aElement, false); + + // Focusing while :user-invalid applies, + // the pseudo-class should apply while typing if appropriate. + aElement.focus(); + checkPseudoClass(aElement, false); + // with keys + sendString("f"); + checkPseudoClass(aElement, true); + synthesizeKey("KEY_Backspace"); + checkPseudoClass(aElement, false); + // with .value + aElement.value = 'f'; + checkPseudoClass(aElement, true); + aElement.value = ''; + checkPseudoClass(aElement, false); +} + +function checkSelectElement(aElement) +{ + checkPseudoClass(aElement, false); + + if (!aElement.multiple && navigator.platform.startsWith("Mac")) { + // Arrow key on macOS opens the popup. + return; + } + + // Focusing while :user-valid doesn't apply, + // the pseudo-class should not apply while changing selection. + aElement.focus(); + checkPseudoClass(aElement, false); + + synthesizeKey("KEY_ArrowDown"); + checkPseudoClass(aElement, true); + + // Focusing while :user-valid applies, + // the pseudo-class should apply while changing selection if appropriate. + aElement.focus(); + checkPseudoClass(aElement, true); + + aElement.selectedIndex = 1; + checkPseudoClass(aElement, true); + aElement.selectedIndex = 0; + checkPseudoClass(aElement, true); + + aElement.blur(); + aElement.required = true; + // select set with multiple is only invalid if no option is selected + if (aElement.multiple) { + aElement.selectedIndex = -1; + } + checkPseudoClass(aElement, false); + + // Focusing while :user-invalid applies, + // the pseudo-class should apply while changing selection if appropriate. + aElement.focus(); + checkPseudoClass(aElement, false); + + synthesizeKey("KEY_ArrowDown"); + checkPseudoClass(aElement, true); + aElement.selectedIndex = 0; + checkPseudoClass(aElement, aElement.multiple); +} + +checkElement(document.getElementsByTagName('input')[0]); +checkElement(document.getElementsByTagName('textarea')[0]); +checkSelectElement(document.getElementsByTagName('select')[0]); +checkSelectElement(document.getElementsByTagName('select')[1]); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug606817.html b/dom/html/test/test_bug606817.html new file mode 100644 index 0000000000..4564753a93 --- /dev/null +++ b/dom/html/test/test_bug606817.html @@ -0,0 +1,59 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=606817 +--> +<head> + <title>Test for Bug 606817</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=606817">Mozilla Bug 606817</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 606817 **/ + +var messageMaxLength = 256; + +function checkMessage(aInput, aMsg, aWithTerminalPeriod) +{ + ok(aInput.validationMessage != aMsg, + "Original content-defined message should have been truncate"); + is(aInput.validationMessage.length - aInput.validationMessage.indexOf("_42_"), + aWithTerminalPeriod ? messageMaxLength+1 : messageMaxLength, + "validation message should be 256 characters length"); +} + +var input = document.createElement("input"); + +var msg = ""; +for (var i=0; i<75; ++i) { + msg += "_42_"; +} +// msg is now 300 chars long + +// Testing with setCustomValidity(). +input.setCustomValidity(msg); +checkMessage(input, msg, false); + +// Cleaning. +input.setCustomValidity(""); + +// Testing with pattern and titl. +input.pattern = "[0-9]*"; +input.value = "foo"; +input.title = msg; +checkMessage(input, msg, true); + +// Cleaning. +input.removeAttribute("pattern"); +input.removeAttribute("title"); +input.value = ""; + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug607145.html b/dom/html/test/test_bug607145.html new file mode 100644 index 0000000000..28ab3fe8ba --- /dev/null +++ b/dom/html/test/test_bug607145.html @@ -0,0 +1,86 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=607145 +--> +<head> + <title>Test for Bug 607145</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=607145">Mozilla Bug 607145</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +var xoriginParams; +/** Test for Bug 607145 **/ + +/** + * This is not really reflecting an URL as the HTML5 specs want to. + * It's how .action is reflected in Gecko (might change later). + * + * If this changes, add reflectURL for "formAction" in + * dom/html/test/forms/test_input_attributes_reflection.html and + * "action" in + * dom/html/test/forms/test_form_attributes_reflection.html + */ +function reflectURL(aElement, aAttr) +{ + var idl = aAttr; + var attr = aAttr.toLowerCase(); + var elmtName = aElement.tagName.toLowerCase(); + + var url = location.href.replace(/\?.*/, ""); + var dir = url.replace(/test_bug607145.html[^\/]*$/, ""); + var parentDir = dir.replace(/test\/$/, ""); + ok(idl in aElement, idl + " should be available in " + elmtName); + + // Default values. + is(aElement[idl].split("?")[0], url, "." + idl + " default value should be the document's URL"); + is(aElement.getAttribute(attr), null, + "@" + attr + " default value should be null"); + + var values = [ + /* value to set, resolved value */ + [ "foo.html", dir + "foo.html" ], + [ "data:text/html,<html></html>", "data:text/html,<html></html>" ], + [ "http://example.org/", "http://example.org/" ], + [ "//example.org/", "http://example.org/" ], + [ "?foo=bar", url + "?foo=bar" ], + [ "#foo", url + "#foo" ], + [ "", url ], + [ " ", url ], + [ "../", parentDir ], + [ "...", dir + "..." ], + // invalid URL + [ "http://a b/", "http://a b/" ], // TODO: doesn't follow the specs, should be "". + ]; + + for (var value of values) { + aElement[idl] = value[0]; + is(aElement[idl].replace(xoriginParams, ""), value[1], "." + idl + " value should be " + value[1]); + is(aElement.getAttribute(attr), value[0], + "@" + attr + " value should be " + value[0]); + } + + for (var value of values) { + aElement.setAttribute(attr, value[0]); + is(aElement[idl].replace(xoriginParams, ""), value[1], "." + idl + " value should be " + value[1]); + is(aElement.getAttribute(attr), value[0], + "@" + attr + " value should be " + value[0]); + } +} + + +xoriginParams = window.location.search; + +reflectURL(document.createElement("form"), "action"); +reflectURL(document.createElement("input"), "formAction"); +reflectURL(document.createElement("button"), "formAction"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug610212.html b/dom/html/test/test_bug610212.html new file mode 100644 index 0000000000..69838f7e4d --- /dev/null +++ b/dom/html/test/test_bug610212.html @@ -0,0 +1,42 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=610212 +--> +<head> + <title>Test for Bug 610212</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=610212">Mozilla Bug 610212</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 610212 **/ + +var canvas = document.createElement('canvas'); + +reflectUnsignedInt({ + element: canvas, + attribute: "width", + nonZero: false, + defaultValue: 300, +}); + +reflectUnsignedInt({ + element: canvas, + attribute: "height", + nonZero: false, + defaultValue: 150, +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug610687.html b/dom/html/test/test_bug610687.html new file mode 100644 index 0000000000..fd6950cce4 --- /dev/null +++ b/dom/html/test/test_bug610687.html @@ -0,0 +1,195 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=610687 +--> +<head> + <title>Test for Bug 610687</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=610687">Mozilla Bug 610687</a> +<p id="display"></p> +<div id="content"> + <form> + <input type='radio' name='a'> + <input type='radio' name='a'> + <input type='radio' name='b'> + </form> + <input type='radio' name='a'> + <input type='radio' name='a'> + <input type='radio' name='b'> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 610687 **/ + +function checkPseudoClasses(aElement, aValid, aValidUI, aInvalidUI) +{ + if (aValid) { + ok(aElement.matches(":valid"), ":valid should apply"); + } else { + ok(aElement.matches(":invalid"), ":invalid should apply"); + } + + is(aElement.matches(":user-valid"), aValidUI, + aValid ? ":user-valid should apply" : ":user-valid should not apply"); + + is(aElement.matches(":user-invalid"), aInvalidUI, + aInvalidUI ? ":user-invalid should apply" : ":user-invalid should not apply"); + + if (aInvalidUI && (aValid || aValidUI)) { + ok(false, ":invalid can't apply with :valid or :user-valid"); + } +} + +/** + * r1 and r2 should be in the same group. + * r3 should be in another group. + * form can be null. + */ +function checkRadios(r1, r2, r3, form) +{ + // Default state. + checkPseudoClasses(r1, true, false, false); + checkPseudoClasses(r2, true, false, false); + checkPseudoClasses(r3, true, false, false); + + // Suffering from being missing (without ui-invalid). + r1.required = true; + checkPseudoClasses(r1, false, false, false); + checkPseudoClasses(r2, false, false, false); + checkPseudoClasses(r3, true, false, false); + + // Do not suffer from being missing (with ui-valid). + r1.click(); + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, true, false, false); + checkPseudoClasses(r3, true, false, false); + + // Do not suffer from being missing (with ui-valid). + r1.checked = false; + r1.required = false; + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, true, false, false); + checkPseudoClasses(r3, true, false, false); + + // Suffering from being missing (with ui-invalid) with required set on one radio + // and the checked state changed on another. + r1.required = true; + r2.checked = false; + checkPseudoClasses(r1, false, false, true); + checkPseudoClasses(r2, false, false, false); + checkPseudoClasses(r3, true, false, false); + + // Do not suffer from being missing (with ui-valid) by checking the radio which + // hasn't the required attribute. + r2.checked = true; + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, true, false, false); + checkPseudoClasses(r3, true, false, false); + + // .setCustomValidity() should not affect the entire group. + r1.checked = false; r2.checked = false; r3.checked = false; + r1.required = false; + r1.setCustomValidity('foo'); + checkPseudoClasses(r1, false, false, true); + checkPseudoClasses(r2, true, false, false); + checkPseudoClasses(r3, true, false, false); + + r1.setCustomValidity(''); + r2.setCustomValidity('foo'); + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, false, false, false); + checkPseudoClasses(r3, true, false, false); + + r2.setCustomValidity(''); + r3.setCustomValidity('foo'); + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, true, false, false); + checkPseudoClasses(r3, false, false, false); + + // Removing the radio with the required attribute should make the group valid. + r1.setCustomValidity(''); + r2.setCustomValidity(''); + r1.required = false; + r2.required = true; + r1.checked = r2.checked = false; + checkPseudoClasses(r1, false, false, true); + checkPseudoClasses(r2, false, false, false); + + var p = r2.parentNode; + p.removeChild(r2); + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, false, false, false); + + p.appendChild(r2); + checkPseudoClasses(r1, false, false, true); + checkPseudoClasses(r2, false, false, false); + + // Adding a radio element to an invalid group should make it invalid. + p.removeChild(r1); + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, false, false, false); + + p.appendChild(r1); + checkPseudoClasses(r1, false, false, true); + checkPseudoClasses(r2, false, false, false); + + // Adding a checked radio element to an invalid group should make it valid. + p.removeChild(r1); + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, false, false, false); + + r1.checked = true; + p.appendChild(r1); + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, true, false, false); + r1.checked = false; + + // Adding an invalid radio element by changing the name attribute. + r2.name = 'c'; + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, false, false, false); + + r2.name = 'a'; + checkPseudoClasses(r1, false, false, true); + checkPseudoClasses(r2, false, false, false); + + // Adding an element to an invalid radio group by changing the name attribute. + r1.name = 'c'; + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, false, false, false); + + r1.name = 'a'; + checkPseudoClasses(r1, false, false, true); + checkPseudoClasses(r2, false, false, false); + + // Adding a checked element to an invalid radio group with the name attribute. + r1.name = 'c'; + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, false, false, false); + + r1.checked = true; + r1.name = 'a'; + checkPseudoClasses(r1, true, true, false); + checkPseudoClasses(r2, true, false, false); + r1.checked = false; +} + +var r1 = document.getElementsByTagName('input')[0]; +var r2 = document.getElementsByTagName('input')[1]; +var r3 = document.getElementsByTagName('input')[2]; +checkRadios(r1, r2, r3); + +r1 = document.getElementsByTagName('input')[3]; +r2 = document.getElementsByTagName('input')[4]; +r3 = document.getElementsByTagName('input')[5]; +checkRadios(r1, r2, r3); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug611189.html b/dom/html/test/test_bug611189.html new file mode 100644 index 0000000000..d798fd4393 --- /dev/null +++ b/dom/html/test/test_bug611189.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=611189 +--> +<head> + <title>Test for Bug 611189</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <script src="/tests/SimpleTest/WindowSnapshot.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=611189">Mozilla Bug 611189</a> +<p id="display"></p> +<div id="content"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 611189 **/ +SimpleTest.waitForExplicitFinish(); +addLoadEvent(async function() { + var i = document.createElement("input"); + var b = document.getElementById("content"); + b.appendChild(i); + b.clientWidth; // bind to frame + i.focus(); // initialize editor + var before = await snapshotWindow(window, true); + i.value = "L"; // set the value + i.style.display = "none"; + b.clientWidth; // unbind from frame + i.value = ""; // set the value without a frame + i.style.display = ""; + b.clientWidth; // rebind to frame + is(i.value, "", "Input's value should be correctly updated"); + var after = await snapshotWindow(window, true); + ok(compareSnapshots(before, after, true), "The correct value should be rendered inside the control"); + SimpleTest.finish(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug612730.html b/dom/html/test/test_bug612730.html new file mode 100644 index 0000000000..ccdfc1241d --- /dev/null +++ b/dom/html/test/test_bug612730.html @@ -0,0 +1,51 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=612730 +--> +<head> + <title>Test for Bug 612730</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=612730">Mozilla Bug 612730</a> +<p id="display"></p> +<div id="content"> + <select multiple required> + <option value="">foo</option> + <option value="">bar</option> + </select> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 612730 **/ + +SimpleTest.waitForExplicitFinish(); + +function runTest() +{ + var select = document.getElementsByTagName('select')[0]; + + select.addEventListener("focus", function() { + isnot(select.selectedIndex, -1, "Something should have been selected"); + + ok(!select.matches(":-moz-ui-invalid"), + ":-moz-ui-invalid should not apply"); + ok(!select.matches(":-moz-ui-valid"), + ":-moz-ui-valid should not apply"); + + SimpleTest.finish(); + }, {once: true}); + + synthesizeMouse(select, 5, 5, {}); +} + +SimpleTest.waitForFocus(runTest); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug613019.html b/dom/html/test/test_bug613019.html new file mode 100644 index 0000000000..3f96ce2542 --- /dev/null +++ b/dom/html/test/test_bug613019.html @@ -0,0 +1,84 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=613019 +--> +<head> + <title>Test for Bug 613019</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613019">Mozilla Bug 613019</a> +<div id="content"> + <input type="text" maxlength="2" style="width:200px" value="Test"> + <textarea maxlength="2" style="width:200px">Test</textarea> + <input type="text" minlength="6" style="width:200px" value="Test"> + <textarea minlength="6" style="width:200px">Test</textarea> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 613019 **/ + +function testInteractivityOfMaxLength(elem) { + // verify that user interactivity is necessary for validity state to apply. + is(elem.value, "Test", "Element has incorrect starting value."); + is(elem.validity.tooLong, false, "Element should not be tooLong."); + + elem.setSelectionRange(elem.value.length, elem.value.length) + elem.focus(); + + synthesizeKey("KEY_Backspace"); + is(elem.value, "Tes", "Element value was not changed correctly."); + is(elem.validity.tooLong, true, "Element should still be tooLong."); + + synthesizeKey("KEY_Backspace"); + is(elem.value, "Te", "Element value was not changed correctly."); + is(elem.validity.tooLong, false, "Element should no longer be tooLong."); + + elem.value = "Test"; + is(elem.validity.tooLong, false, + "Element should not be tooLong after non-interactive value change."); +} + +function testInteractivityOfMinLength(elem) { + // verify that user interactivity is necessary for validity state to apply. + is(elem.value, "Test", "Element has incorrect starting value."); + is(elem.validity.tooLong, false, "Element should not be tooShort."); + + elem.setSelectionRange(elem.value.length, elem.value.length) + elem.focus(); + + sendString("e"); + is(elem.value, "Teste", "Element value was not changed correctly."); + is(elem.validity.tooShort, true, "Element should still be tooShort."); + + sendString("d"); + is(elem.value, "Tested", "Element value was not changed correctly."); + is(elem.validity.tooShort, false, "Element should no longer be tooShort."); + + elem.value = "Test"; + is(elem.validity.tooShort, false, + "Element should not be tooShort after non-interactive value change."); +} + +function test() { + window.getSelection().removeAllRanges(); + testInteractivityOfMaxLength(document.querySelector("input[type=text][maxlength]")); + testInteractivityOfMaxLength(document.querySelector("textarea[maxlength]")); + testInteractivityOfMinLength(document.querySelector("input[type=text][minlength]")); + testInteractivityOfMinLength(document.querySelector("textarea[minlength]")); + SimpleTest.finish(); +} + +window.onload = function() { + SimpleTest.waitForExplicitFinish(); + setTimeout(test, 0); +}; + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug613113.html b/dom/html/test/test_bug613113.html new file mode 100644 index 0000000000..3308246af0 --- /dev/null +++ b/dom/html/test/test_bug613113.html @@ -0,0 +1,52 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=613113 +--> +<head> + <title>Test for Bug 613113</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613113">Mozilla Bug 613113</a> +<p id="display"></p> +<div id="content" style="display: none"> + <iframe name='f'></iframe> + <form target='f' action="data:text/html,"> + <output></output> + <button></button> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 613113 **/ + +SimpleTest.waitForExplicitFinish(); + +var invalidEvent = false; + +var form = document.forms[0]; +var button = document.getElementsByTagName('button')[0]; +var output = document.getElementsByTagName('output')[0]; + +output.addEventListener("invalid", function() { + ok(false, "invalid event should have been send"); +}); + +form.addEventListener("submit", function() { + ok(true, "submit has been caught"); + setTimeout(function() { + SimpleTest.finish(); + }, 0); +}); + +output.setCustomValidity("foo"); + +button.click(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug613722.html b/dom/html/test/test_bug613722.html new file mode 100644 index 0000000000..4fbead4507 --- /dev/null +++ b/dom/html/test/test_bug613722.html @@ -0,0 +1,32 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=613722 +--> +<head> + <title>Test for Bug 613722</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613722">Mozilla Bug 613722</a> +<p id="display"></p> +<div id="content"> + <embed src="test_plugin.tst" hidden> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 613722 **/ + +var rect = document.getElementsByTagName('embed')[0].getBoundingClientRect(); + +var hasFrame = rect.left != 0 || rect.right != 0 || rect.top != 0 || + rect.bottom != 0; + +ok(hasFrame, "embed should have a frame with hidden set"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug613979.html b/dom/html/test/test_bug613979.html new file mode 100644 index 0000000000..40921d8064 --- /dev/null +++ b/dom/html/test/test_bug613979.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=613979 +--> +<head> + <title>Test for Bug 613979</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613979">Mozilla Bug 613979</a> +<p id="display"></p> +<div id="content"> + <input required> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 613979 **/ + +var testNum = 0; +var input = document.getElementsByTagName('input')[0]; + +input.addEventListener("input", function() { + if (testNum == 0) { + ok(input.validity.valid, "input should be valid"); + testNum++; + SimpleTest.executeSoon(function() { + synthesizeKey("KEY_Backspace"); + }); + } else if (testNum == 1) { + ok(!input.validity.valid, "input should not be valid"); + input.removeEventListener("input", arguments.callee); + SimpleTest.finish(); + } +}); + +SimpleTest.waitForExplicitFinish(); + +SimpleTest.waitForFocus(function() { + input.focus(); + sendString("a"); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug615595.html b/dom/html/test/test_bug615595.html Binary files differnew file mode 100644 index 0000000000..4e3d002498 --- /dev/null +++ b/dom/html/test/test_bug615595.html diff --git a/dom/html/test/test_bug615833.html b/dom/html/test/test_bug615833.html new file mode 100644 index 0000000000..530603daee --- /dev/null +++ b/dom/html/test/test_bug615833.html @@ -0,0 +1,141 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=615697 +--> +<head> + <title>Test for Bug 615697</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=615697">Mozilla Bug 615697</a> +<p id="display"></p> +<div id="content"> + <input> + <textarea></textarea> + <input type='radio'> + <input type='checkbox'> + <select> + <option>foo</option> + <option>bar</option> + </select> + <select multiple size='1'> + <option>tulip</option> + </select> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 615697 **/ + +/** + * This test is making all elements trigger 'change' event. + * You should read the test from bottom to top: + * events are registered from the last one to the first one. + * + * Sometimes, elements are focused before a click. This might sound useless + * but it guarantees to have the element visible before simulating the click. + */ + +var input = document.getElementsByTagName('input')[0]; +var textarea = document.getElementsByTagName('textarea')[0]; +var radio = document.getElementsByTagName('input')[1]; +var checkbox= document.getElementsByTagName('input')[2]; +var select = document.getElementsByTagName('select')[0]; +var selectMultiple = document.getElementsByTagName('select')[1]; + +function checkChangeEvent(aEvent) +{ + ok(aEvent.bubbles, "change event should bubble"); + ok(!aEvent.cancelable, "change event shouldn't be cancelable"); +} + +selectMultiple.addEventListener("change", function(aEvent) { + checkChangeEvent(aEvent); + SimpleTest.finish(); +}, {once: true}); + +selectMultiple.addEventListener("focus", function() { + SimpleTest.executeSoon(function () { + synthesizeMouseAtCenter(selectMultiple, {}); + }); +}, {once: true}); + +select.addEventListener("change", function(aEvent) { + checkChangeEvent(aEvent); + selectMultiple.focus(); +}, {once: true}); + +select.addEventListener("keyup", function() { + select.blur(); +}, {once: true}); + +select.addEventListener("focus", function() { + SimpleTest.executeSoon(function () { + synthesizeKey("KEY_ArrowDown"); + }); +}, {once: true}); + +checkbox.addEventListener("change", function(aEvent) { + checkChangeEvent(aEvent); + select.focus(); +}, {once: true}); + +checkbox.addEventListener("focus", function() { + SimpleTest.executeSoon(function () { + synthesizeMouseAtCenter(checkbox, {}); + }); +}, {once: true}); + +radio.addEventListener("change", function(aEvent) { + checkChangeEvent(aEvent); + checkbox.focus(); +}, {once: true}); + +radio.addEventListener("focus", function() { + SimpleTest.executeSoon(function () { + synthesizeMouseAtCenter(radio, {}); + }); +}, {once: true}); + +textarea.addEventListener("change", function(aEvent) { + checkChangeEvent(aEvent); + radio.focus(); +}, {once: true}); + +textarea.addEventListener("input", function() { + textarea.blur(); +}, {once: true}); + +textarea.addEventListener("focus", function() { + SimpleTest.executeSoon(function () { + sendString("f"); + }); +}, {once: true}); + +input.addEventListener("change", function(aEvent) { + checkChangeEvent(aEvent); + textarea.focus(); +}, {once: true}); + +input.addEventListener("input", function() { + input.blur(); +}, {once: true}); + +input.addEventListener("focus", function() { + SimpleTest.executeSoon(function () { + sendString("f"); + }); +}, {once: true}); + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + input.focus(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug618948.html b/dom/html/test/test_bug618948.html new file mode 100644 index 0000000000..04a9347261 --- /dev/null +++ b/dom/html/test/test_bug618948.html @@ -0,0 +1,88 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=618948 +--> +<head> + <title>Test for Bug 618948</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=618948">Mozilla Bug 618948</a> +<p id="display"></p> +<div id="content"> + <form> + <input type='email' id='i'> + <button>submit</button> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 618948 **/ + +var events = ["focus", "input", "change", "invalid" ]; + +var handled = ({}); + +function eventHandler(event) +{ + dump("\n" + event.type + "\n"); + handled[event.type] = true; +} + +function beginTest() +{ + for (var e of events) { + handled[e] = false; + } + + i.focus(); +} + +function endTest() +{ + for (var e of events) { + ok(handled[e], "on" + e + " should have been called"); + } + + SimpleTest.finish(); +} + +var i = document.getElementsByTagName('input')[0]; +var b = document.getElementsByTagName('button')[0]; + +i.onfocus = function(event) { + eventHandler(event); + sendString("f"); + i.onfocus = null; +}; + +i.oninput = function(event) { + eventHandler(event); + b.focus(); + i.oninput = null; +}; + +i.onchange = function(event) { + eventHandler(event); + i.onchange = null; + synthesizeMouseAtCenter(b, {}); +}; + +i.oninvalid = function(event) { + eventHandler(event); + i.oninvalid = null; + endTest(); +}; + +SimpleTest.waitForExplicitFinish(); + +SimpleTest.waitForFocus(beginTest); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug619278.html b/dom/html/test/test_bug619278.html new file mode 100644 index 0000000000..56f704c037 --- /dev/null +++ b/dom/html/test/test_bug619278.html @@ -0,0 +1,56 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=619278 +--> +<head> + <title>Test for Bug 619278</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=619278">Mozilla Bug 619278</a> +<p id="display"></p> +<div id="content"> + <form> + <input required><button>submit</button> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 619278 **/ + +function doElementMatchesSelector(aElement, aSelector) +{ + ok(aElement.matches(aSelector), + aSelector + " should match for " + aElement); +} + +var e = document.forms[0].elements[0]; + +e.addEventListener("invalid", function(event) { + e.addEventListener("invalid", arguments.callee); + + SimpleTest.executeSoon(function() { + doElementMatchesSelector(e, ":-moz-ui-invalid"); + SimpleTest.finish(); + }); +}); + +e.addEventListener("focus", function() { + SimpleTest.executeSoon(function() { + synthesizeKey("KEY_Enter"); + }); +}, {once: true}); + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + e.focus(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug622597.html b/dom/html/test/test_bug622597.html new file mode 100644 index 0000000000..ead4887a1d --- /dev/null +++ b/dom/html/test/test_bug622597.html @@ -0,0 +1,105 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=622597 +--> +<head> + <title>Test for Bug 622597</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=622597">Mozilla Bug 622597</a> +<p id="display"></p> +<div id="content"> + <form> + <input required> + <textarea required></textarea> + <select required><option value="">foo</option><option selected>bar</option></select> + <button>submit</button> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 622597 **/ + +var form = document.forms[0]; +var input = form.elements[0]; +var textarea = form.elements[1]; +var select = form.elements[2]; +var button = form.elements[3]; + +function checkPseudoClasses(aElement, aValid, aInvalid) +{ + is(aElement.matches(":-moz-ui-valid"), aValid, + aValid ? aElement + " should match :-moz-ui-valid" + : aElement + " should not match :-moz-ui-valid"); + is(aElement.matches(":-moz-ui-invalid"), aInvalid, + aInvalid ? aElement + " should match :-moz-ui-invalid" + : aElement + " should not match :-moz-ui-invalid"); + if (aValid && aInvalid) { + ok(false, + aElement + " should not match :-moz-ui-valid AND :-moz-ui-invalid"); + } +} + +select.addEventListener("focus", function() { + SimpleTest.executeSoon(function() { + form.noValidate = false; + SimpleTest.executeSoon(function() { + checkPseudoClasses(select, false, true); + SimpleTest.finish(); + }); + }); +}, {once: true}); + +textarea.addEventListener("focus", function() { + SimpleTest.executeSoon(function() { + form.noValidate = false; + SimpleTest.executeSoon(function() { + checkPseudoClasses(textarea, false, true); + form.noValidate = true; + select.selectedIndex = 0; + select.focus(); + }); + }); +}, {once: true}); + +input.addEventListener("invalid", function() { + input.addEventListener("focus", function() { + SimpleTest.executeSoon(function() { + form.noValidate = false; + SimpleTest.executeSoon(function() { + checkPseudoClasses(input, false, true); + form.noValidate = true; + textarea.value = ''; + textarea.focus(); + }); + }); + }, {once: true}); + + SimpleTest.executeSoon(function() { + form.noValidate = true; + input.blur(); + input.value = ''; + input.focus(); + }); +}, {once: true}); + +button.addEventListener("focus", function() { + SimpleTest.executeSoon(function() { + synthesizeKey("KEY_Enter"); + }); +}, {once: true}); + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + button.focus(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug623291.html b/dom/html/test/test_bug623291.html new file mode 100644 index 0000000000..c7b7ab7ea4 --- /dev/null +++ b/dom/html/test/test_bug623291.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=623291 +--> +<head> + <title>Test for Bug 623291</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=623291">Mozilla Bug 623291</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<input id="textField" onfocus="next()" onblur="done();"> +<button id="b">a button</button> + +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 623291 **/ + +function runTest() { + document.getElementById("textField").focus(); +} + +function next() { + synthesizeMouseAtCenter(document.getElementById('b'), {}, window); +} + +function done() { + isnot(document.activeElement, document.getElementById("textField"), + "TextField should not be active anymore!"); + SimpleTest.finish(); +} + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(runTest); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug6296.html b/dom/html/test/test_bug6296.html new file mode 100644 index 0000000000..6e74ce8ec2 --- /dev/null +++ b/dom/html/test/test_bug6296.html @@ -0,0 +1,31 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=6296 +--> +<head> + <title>Test for Bug 6296</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=6296">Mozilla Bug 6296</a> +<p id="display"></p> +<div id="content" style="display: none"> + <A HREF="../testdata/test.gif" id="foo" NAME="anchor1" ALT="this is a test of the image + attribute">Hi</A> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 6296 **/ +is($("foo").name, "anchor1", "accessing an anchor name should work, and not crash either!") + + + + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug629801.html b/dom/html/test/test_bug629801.html new file mode 100644 index 0000000000..073979a5fe --- /dev/null +++ b/dom/html/test/test_bug629801.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=629801 +--> +<head> + <title>Test for Bug 629801</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=629801">Mozilla Bug 629801</a> +<p id="display"></p> +<div id="content" style="display: none"> + +<div itemscope> + This tests itemValue on time elements, first with no datetime attribute, then with no text content, + then with both. + <time id="t1" itemprop="a">May 10th 2009</time> + <time id="t2" itemprop="b" datetime="2009-05-10"></time> + <time id="t3" itemprop="c" datetime="2009-05-10">May 10th 2009</time> +</div> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 629801 **/ + +var t1 = document.getElementById("t1"), + t2 = document.getElementById("t2"), + t3 = document.getElementById("t3"), + t4 = document.createElement("time"); + +// .dateTime IDL +is(t1.dateTime, "", "dateTime is properly set to empty string if datetime attributeis absent"); +is(t2.dateTime, "2009-05-10", "dateTime is properly set to datetime attribute with datetime and no text content"); +is(t3.dateTime, "2009-05-10", "dateTime is properly set to datetime attribute with datetime and text content"); + +// dateTime reflects datetime attribute +reflectString({ + element: t4, + attribute: "dateTime" +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug633058.html b/dom/html/test/test_bug633058.html new file mode 100644 index 0000000000..a92f1f9369 --- /dev/null +++ b/dom/html/test/test_bug633058.html @@ -0,0 +1,66 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=633058 +--> +<head> + <title>Test for Bug 633058</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=633058">Mozilla Bug 633058</a> +<p id="display"></p> +<div id="content"> + <input> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 633058 **/ + +SimpleTest.waitForExplicitFinish(); + +SimpleTest.waitForFocus(startTest); + +function startTest() { + var nbExpectedKeyDown = 8; + var nbExpectedKeyPress = 1; + var inputGotKeyPress = 0; + var inputGotKeyDown = 0; + var divGotKeyPress = 0; + var divGotKeyDown = 0; + + var input = document.getElementsByTagName('input')[0]; + var content = document.getElementById('content'); + + content.addEventListener("keydown", () => { divGotKeyDown++; }); + content.addEventListener("keypress", () => { divGotKeyPress++; }); + input.addEventListener("keydown", () => { inputGotKeyDown++; }); + input.addEventListener("keypress", () => { inputGotKeyPress++; }); + + input.addEventListener('focus', function() { + SimpleTest.executeSoon(() => { + synthesizeKey('KEY_ArrowUp'); + synthesizeKey('KEY_ArrowLeft'); + synthesizeKey('KEY_ArrowRight'); + synthesizeKey('KEY_ArrowDown'); + synthesizeKey('KEY_Backspace'); + synthesizeKey('KEY_Delete'); + synthesizeKey('KEY_Escape'); + synthesizeKey('KEY_Enter'); // Will dispatch keypress event even in strict behavior. + + is(inputGotKeyDown, nbExpectedKeyDown, "input got all keydown events"); + is(inputGotKeyPress, nbExpectedKeyPress, "input got all keypress events"); + is(divGotKeyDown, nbExpectedKeyDown, "div got all keydown events"); + is(divGotKeyPress, nbExpectedKeyPress, "div got all keypress events"); + SimpleTest.finish(); + }); + }, {once: true}); + input.focus(); +} +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug636336.html b/dom/html/test/test_bug636336.html new file mode 100644 index 0000000000..314e941f84 --- /dev/null +++ b/dom/html/test/test_bug636336.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=636336 +--> +<head> + <title>Test for Bug 636336</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=636336">Mozilla Bug 636336</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 636336 **/ +function testIt(tag) { + var elem = document.createElement(tag); + elem.setAttribute("src", " "); + is(elem.getAttribute("src"), " ", + tag + " src attribute setter should not strip whitespace"); + elem.setAttribute("src", " test "); + is(elem.getAttribute("src"), " test ", + tag + " src attribute setter should not strip whitespace around non-whitespace"); + is(elem.src, window.location.href.replace(/\?.*/, "") + .replace(/test_bug636336\.html$/, "test"), + tag + ".src should strip whitespace as needed"); +} + +testIt("img"); +testIt("source"); +testIt("audio"); +testIt("video"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug641219.html b/dom/html/test/test_bug641219.html new file mode 100644 index 0000000000..44dc15cf41 --- /dev/null +++ b/dom/html/test/test_bug641219.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=641219 +--> +<head> + <title>Test for Bug 641219</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=641219">Mozilla Bug 641219</a> +<p id="display"></p> +<div id="content" style="display: none"> +<div id="div"> +<font></font> +<svg><font/></svg> +</div> +</div> +<pre id="test"> +<script type="application/javascript"> +/** Test for Bug 641219 **/ +var HTML = "http://www.w3.org/1999/xhtml", + SVG = "http://www.w3.org/2000/svg"; +var wrapper = document.getElementById("div"); +is(wrapper.getElementsByTagName("FONT").length, 1); +is(wrapper.getElementsByTagName("FONT")[0].namespaceURI, HTML); +is(wrapper.getElementsByTagName("font").length, 2); +is(wrapper.getElementsByTagName("font")[0].namespaceURI, HTML); +is(wrapper.getElementsByTagName("font")[1].namespaceURI, SVG); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug643051.html b/dom/html/test/test_bug643051.html new file mode 100644 index 0000000000..5719d1d2db --- /dev/null +++ b/dom/html/test/test_bug643051.html @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=643051 +--> +<head> + <title>Test for Bug 643051</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=643051">Mozilla Bug 643051</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); + +SpecialPowers.pushPrefEnv({ + "set": [ + // Bug 1617611: Fix all the tests broken by "cookies SameSite=lax by default" + ["network.cookie.sameSite.laxByDefault", false], + ] +}, () => { + /** Test for Bug 643051 **/ + document.cookie = "a=; expires=Thu, 01-Jan-1970 00:00:01 GMT"; // clear cookie + document.cookie = "a2=; expires=Thu, 01-Jan-1970 00:00:01 GMT"; // clear cookie + document.cookie = "a3=; expires=Thu, 01-Jan-1970 00:00:01 GMT"; // clear cookie + + // single cookie, should work + document.cookie = "a=bar"; + is(document.cookie, "a=bar", "Can't read stored cookie!"); + + document.cookie = "a2=bar\na3=bar"; + is(document.cookie, "a=bar; a2=bar", "Wrong cookie value"); + + document.cookie = "a2=baz; a3=bar"; + is(document.cookie, "a=bar; a2=baz", "Wrong cookie value"); + + // clear cookies again to avoid affecting other tests + document.cookie = "a=; expires=Thu, 01-Jan-1970 00:00:01 GMT"; + document.cookie = "a2=; expires=Thu, 01-Jan-1970 00:00:01 GMT"; + document.cookie = "a3=; expires=Thu, 01-Jan-1970 00:00:01 GMT"; + + SpecialPowers.clearUserPref("network.cookie.sameSite.laxByDefault"); + SimpleTest.finish(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug646157.html b/dom/html/test/test_bug646157.html new file mode 100644 index 0000000000..ea0cbedaf0 --- /dev/null +++ b/dom/html/test/test_bug646157.html @@ -0,0 +1,95 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=646157 +--> +<head> + <title>Test for Bug 646157</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=646157">Mozilla Bug 646157</a> +<p id="display"></p> +<div id="content"> + <label id="l1"/><input id="c1" type='checkbox'> + <label id="l2"/><input id="c2" type='checkbox'> + <label id="l3"/><input id="c3" type='checkbox'> + <label id="l4"/><input id="c4" type='checkbox'> + <label id="l5"/><input id="c5" type='checkbox'> + <label id="l6"/><input id="c6" type='checkbox'> + <label id="l7"/><input id="c7" type='checkbox'> + <label id="l8"/><input id="c8" type='checkbox'> + <label id="l9"/><input id="c9" type='checkbox'> + <label id="l10"/><input id="c10" type='checkbox'> +</div> +<pre id="test"> +<script type="application/javascript"> +/** Test for Bug 646157 **/ + +var expectedClicks = { + // [ Direct clicks, bubbled clicks, synthetic clicks] + l1: [0, 2, 1], + l2: [0, 2, 1], + l3: [0, 2, 1], + l4: [0, 2, 1], + l5: [0, 2, 1], + l6: [0, 2, 1], + l7: [0, 2, 1], + l8: [0, 2, 1], + l9: [0, 2, 1], + l10:[1, 2, 1], + c1: [0, 0, 0], + c2: [0, 0, 0], + c3: [0, 0, 0], + c4: [0, 0, 0], + c5: [0, 0, 0], + c6: [0, 0, 0], + c7: [0, 0, 0], + c8: [0, 0, 0], + c9: [0, 0, 0], + c10:[1, 1, 1] +}; + +function clickhandler(e) { + if (!e.currentTarget.clickCount) + e.currentTarget.clickCount = 1; + else + e.currentTarget.clickCount++; + + if (e.currentTarget === e.target) + e.currentTarget.directClickCount = 1; + + if (e.target != document.getElementById("l10")) { + if (!e.currentTarget.synthClickCount) + e.currentTarget.synthClickCount = 1; + else + e.currentTarget.synthClickCount++; + } +} + +for (var i = 1; i <= 10; i++) { + document.getElementById("l" + i).addEventListener('click', clickhandler); + document.getElementById("c" + i).addEventListener('click', clickhandler); +} + +document.getElementById("l10").click(); + +function check(thing) { + var expected = expectedClicks[thing.id]; + is(thing.directClickCount || 0, expected[0], "Wrong number of direct clicks"); + is(thing.clickCount || 0, expected[1], "Wrong number of clicks"); + is(thing.synthClickCount || 0, expected[2], "Wrong number of synthetic clicks"); +} + +// Compare them all +for (var i = 1; i <= 10; i++) { + check(document.getElementById("l" + i)); + check(document.getElementById("c" + i)); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug649134.html b/dom/html/test/test_bug649134.html new file mode 100644 index 0000000000..52d644fb14 --- /dev/null +++ b/dom/html/test/test_bug649134.html @@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=649134 +--> +<head> + <title>Test for Bug 649134</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=649134">Mozilla Bug 649134</a> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 649134 **/ +SimpleTest.waitForExplicitFinish(); + +var calls = 0; +function finish() { + if (++calls == 4) + SimpleTest.finish(); +} +function verifyNoLoad(iframe) { + ok(iframe.contentDocument.body.offsetHeight > 0, + "HTTP Link stylesheet was ignored " + iframe.src); + finish(); +} +var verifyLoadCalls = 0; +function verifyLoad(iframe) { + if (++verifyLoadCalls == 2) { + ok(indexContent == iframe.contentDocument.body.innerHTML, + "bug649134/ loads bug649134/index.html " + iframe.src); + } + finish(); +} +function indexLoad(iframe) { + indexContent = iframe.contentDocument.body.innerHTML; + verifyLoad(iframe); +} + +</script> +</pre> +<p id="display"> +<!-- Note: the extra sub-directory is needed for the test, see bug 649134 comment 14 --> +<iframe onload="verifyNoLoad(this);" src="bug649134/file_bug649134-1.sjs"></iframe> +<iframe onload="verifyNoLoad(this);" src="bug649134/file_bug649134-2.sjs"></iframe> +<iframe onload="verifyLoad(this);" src="bug649134/"></iframe> <!-- verify that mochitest server loads index.html --> +<iframe onload="indexLoad(this);" src="bug649134/index.html"></iframe> +</p> +</body> +</html> diff --git a/dom/html/test/test_bug651956.html b/dom/html/test/test_bug651956.html new file mode 100644 index 0000000000..bd059bab94 --- /dev/null +++ b/dom/html/test/test_bug651956.html @@ -0,0 +1,48 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=651956 +--> +<head> + <title>Test for Bug 651956</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=651956">Mozilla Bug 651956</a> +<p id="display"></p> +<div id="content"> + <input> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 651956 **/ + +var input = document.getElementsByTagName('input')[0]; + +var gotInputEvent = false; + +input.addEventListener("input", function() { + gotInputEvent = true; +}, {once: true}); + +input.addEventListener("focus", function() { + synthesizeKey("KEY_Escape"); + + setTimeout(function() { + ok(!gotInputEvent, "No input event should have been sent."); + SimpleTest.finish(); + }); +}, {once: true}); + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + input.focus(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug658746.html b/dom/html/test/test_bug658746.html new file mode 100644 index 0000000000..260b345300 --- /dev/null +++ b/dom/html/test/test_bug658746.html @@ -0,0 +1,97 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=658746 +--> +<head> + <title>Test for Bug 658746</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=658746">Mozilla Bug 658746</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 658746 **/ + +/** + * Sets property, gets property and deletes property. + */ +function SetGetDelete(prop) +{ + var el = document.createElement('div'); + + el.dataset[prop] = 'aaaaaa'; + is(el.dataset[prop], 'aaaaaa', 'Dataset property "' + prop + '" should have been set.'); + + delete el.dataset[prop]; + is(el.dataset[prop], undefined, 'Dataset property"' + prop + '" should have been deleted.'); +} + +/** + * Gets, deletes and sets property. Expects exception while trying to set property. + */ +function SetExpectException(prop) +{ + var el = document.createElement('div'); + + is(el.dataset[prop], undefined, 'Dataset property "' + prop + '" should be undefined.'); + delete el.dataset[prop]; + + try { + el.dataset[prop] = "xxxxxx"; + ok(false, 'Exception should have been thrown when setting "' + prop + '".'); + } catch (ex) { + ok(true, 'Exception should have been thrown.'); + } +} + +// Numbers as properties. +SetGetDelete(-12345678901234567000); +SetGetDelete(-1); +SetGetDelete(0); +SetGetDelete(1); +SetGetDelete(12345678901234567000); + +// Floating point numbers as properties. +SetGetDelete(-1.1); +SetGetDelete(0.0); +SetGetDelete(1.1); + +// Hexadecimal numbers as properties. +SetGetDelete(0x3); +SetGetDelete(0xa); + +// Octal numbers as properties. +SetGetDelete(0o3); +SetGetDelete(0o7); + +// String numbers as properties. +SetGetDelete('0'); +SetGetDelete('01'); +SetGetDelete('0x1'); + +// Undefined as property. +SetGetDelete(undefined); + +// Empty arrays as properties. +SetGetDelete(new Array()); +SetGetDelete([]); + +// Non-empty array and object as properties. +SetExpectException(['a', 'b']); +SetExpectException({'a':'b'}); + +// Objects as properties. +SetExpectException(new Object()); +SetExpectException(document); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug659596.html b/dom/html/test/test_bug659596.html new file mode 100644 index 0000000000..79a55a7608 --- /dev/null +++ b/dom/html/test/test_bug659596.html @@ -0,0 +1,96 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=659596 +--> +<head> + <title>Test for Bug 659596</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=659596">Mozilla Bug 659596</a> +<p id="display"></p> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 659596 **/ + +function checkReflection(option, attribute) { + /** + * Getting. + */ + + // When attribute isn't present. + var tests = [ "", "foo" ]; + for (var test of tests) { + option.removeAttribute(attribute); + option.textContent = test; + is(option.getAttribute(attribute), null, + "option " + attribute + "'s value should be null"); + is(option[attribute], option.textContent, + "option." + attribute + " should reflect the text content when the attribute isn't set"); + } + + // When attribute is present. + tests = [ + [ "", "" ], + [ "", "foo" ], + [ "foo", "bar" ], + [ "foo", "" ], + ]; + for (var test of tests) { + option.setAttribute(attribute, test[0]); + option.textContent = test[1]; + is(option[attribute], option.getAttribute(attribute), + "option." + attribute + " should reflect the content attribute when it is set"); + } + + /** + * Setting. + */ + + // When attribute isn't present. + tests = [ + [ "", "new" ], + [ "foo", "new" ], + ]; + for (var test of tests) { + option.removeAttribute(attribute); + option.textContent = test[0]; + option[attribute] = test[1] + + is(option.getAttribute(attribute), test[1], + "when setting, the content attribute should change"); + is(option.textContent, test[0], + "when setting, the text content should not change"); + } + + // When attribute is present. + tests = [ + [ "", "", "new" ], + [ "", "foo", "new" ], + [ "foo", "bar", "new" ], + [ "foo", "", "new" ], + ]; + for (var test of tests) { + option.setAttribute(attribute, test[0]); + option.textContent = test[1]; + option[attribute] = test[2]; + + is(option.getAttribute(attribute), test[2], + "when setting, the content attribute should change"); + is(option.textContent, test[1], + "when setting, the text content should not change"); + } +} + +var option = document.createElement("option"); + +checkReflection(option, "value"); +checkReflection(option, "label"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug659743.xml b/dom/html/test/test_bug659743.xml new file mode 100644 index 0000000000..12236bdc02 --- /dev/null +++ b/dom/html/test/test_bug659743.xml @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html xmlns="http://www.w3.org/1999/xhtml"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=659743 +--> +<head> + <title>Test for Bug 659743</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=659743">Mozilla Bug 659743</a> +<p id="display"> +<map name="a"> +<area shape="rect" coords="25,25,75,75" href="#x"/> +</map> +<map id="b"> +<area shape="rect" coords="25,25,75,75" href="#y"/> +</map> +<map name="a"> +<area shape="rect" coords="25,25,75,75" href="#FAIL"/> +</map> +<map id="b"> +<area shape="rect" coords="25,25,75,75" href="#FAIL"/> +</map> + +<img usemap="#a" src="image.png"/> +<img usemap="#b" src="image.png"/> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 659743 **/ +SimpleTest.waitForExplicitFinish(); +var images = document.getElementsByTagName("img"); +var second = false; +onhashchange = function() { + if (!second) { + second = true; + is(location.hash, "#x", "First map"); + SimpleTest.waitForFocus(() => synthesizeMouse(images[1], 50, 50, {})); + } else { + is(location.hash, "#y", "Second map"); + SimpleTest.finish(); + } +}; +SimpleTest.waitForFocus(() => synthesizeMouse(images[0], 50, 50, {})); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug660663.html b/dom/html/test/test_bug660663.html new file mode 100644 index 0000000000..dcc208dfe5 --- /dev/null +++ b/dom/html/test/test_bug660663.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=660663 +--> +<head> + <title>Test for Bug 660663</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=660663">Mozilla Bug 660663</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> +/** Test for Bug 660663 **/ +reflectLimitedEnumerated({ + element: document.createElement("div"), + attribute: "dir", + validValues: ["ltr", "rtl", "auto"], + invalidValues: ["cheesecake", ""] +}); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug660959-1.html b/dom/html/test/test_bug660959-1.html new file mode 100644 index 0000000000..930b31b4d3 --- /dev/null +++ b/dom/html/test/test_bug660959-1.html @@ -0,0 +1,25 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=660959 +--> +<head> + <title>Test for Bug 660959</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=660959">Mozilla Bug 660959</a> +<p id="display"></p> +<div id="content" style="display: none"> + <a href="#" id="testa"></a> +</div> +<pre id="test"> +<script> + is($("content").querySelector(":link, :visited"), $("testa"), + "Should find a link even in a display:none subtree"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug660959-2.html b/dom/html/test/test_bug660959-2.html new file mode 100644 index 0000000000..a7dfb2e3d5 --- /dev/null +++ b/dom/html/test/test_bug660959-2.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=660959 +--> +<head> + <title>Test for Bug 660959</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style> + :link, :visited { + color: red; + } + </style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=660959">Mozilla Bug 660959</a> +<p id="display"></p> +<div id="content" style="display: none"> + <a href="#" id="a"></a> +</div> +<pre id="test"> +<script type="application/javascript"> + var a = document.getElementById("a"); + is(window.getComputedStyle(a).color, "rgb(255, 0, 0)", "Link is not right color?"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug660959-3.html b/dom/html/test/test_bug660959-3.html new file mode 100644 index 0000000000..cc39c1eb98 --- /dev/null +++ b/dom/html/test/test_bug660959-3.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=660959 +--> +<head> + <title>Test for Bug 660959</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=660959">Mozilla Bug 660959</a> +<p id="display"></p> +<div id="content" style="display: none"> + <a href="http://www.example.com"></a> + <div id="foo"> + <span id="test"></span> + </div> +</div> +<pre id="test"> +<script> + is($("foo").querySelector(":link + * span, :visited + * span"), $("test"), + "Should be able to find link siblings even in a display:none subtree"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug666200.html b/dom/html/test/test_bug666200.html new file mode 100644 index 0000000000..d68966f787 --- /dev/null +++ b/dom/html/test/test_bug666200.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=666200 +--> +<head> + <title>Test for Bug 666200</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=666200">Mozilla Bug 666200</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +/** Test for Bug 666200 **/ +var sel = document.createElement("select"); +var opt1 = new Option(); +var opt2 = new Option(); +var opt3 = new Option(); +var opt4 = new Option(); +var opt5 = new Option(); +opt1.value = 1; +opt2.value = 2; +opt3.value = 3; +opt4.value = 4; +opt5.value = 5; +sel.add(opt1); +sel.add(opt2, 0); +sel.add(opt3, 1000); +sel.options.add(opt4, opt3); +sel.add(opt5, undefined); +is(sel[0], opt2, "1st item should be 2"); +is(sel[1], opt1, "2nd item should be 1"); +is(sel[2], opt4, "3rd item should be 4"); +is(sel[3], opt3, "4th item should be 3"); +is(sel[4], opt5, "5th item should be 5"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug666666.html b/dom/html/test/test_bug666666.html new file mode 100644 index 0000000000..a3c22d4e0f --- /dev/null +++ b/dom/html/test/test_bug666666.html @@ -0,0 +1,32 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=666666 +--> +<head> + <title>Test for Bug 666666</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=666666">Mozilla Bug 666666</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> +/** Test for Bug 666666 **/ +["audio", "video"].forEach(function(element) { + reflectLimitedEnumerated({ + element: document.createElement(element), + attribute: "preload", + validValues: ["none", "metadata", "auto"], + invalidValues: ["cheesecake", ""] + }); +}); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug669012.html b/dom/html/test/test_bug669012.html new file mode 100644 index 0000000000..330286f33d --- /dev/null +++ b/dom/html/test/test_bug669012.html @@ -0,0 +1,44 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=669012 +--> +<head> + <title>Test for Bug 669012</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=669012">Mozilla Bug 669012</a> +<p id="display"></p> +<div id="content" style="display: none"> +<script> +var run = 0; +</script> +<svg> +<script> +run++; +ok(true, "Should run SVG script without attributes") +</script> +<script for=window event=onload> +run++; +ok(true, "Should run SVG script with for=window event=onload") +</script> +<script for=window event=foo> +run++; +ok(true, "Should run SVG script with for=window event=foo") +</script> +<script for=foo event=onload> +run++; +ok(true, "Should run SVG script with for=foo event=onload") +</script> +</svg> +</div> +<pre id="test"> +<script type="application/javascript"> +/** Test for Bug 669012 **/ +is(run, 4, "Should have run all tests") +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug674558.html b/dom/html/test/test_bug674558.html new file mode 100644 index 0000000000..ab9713bf35 --- /dev/null +++ b/dom/html/test/test_bug674558.html @@ -0,0 +1,287 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=674558 +--> +<head> + <title>Test for Bug 674558</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=674558">Mozilla Bug 674558</a> +<p id="display"></p> +<div id="content"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 674558 **/ +SimpleTest.waitForExplicitFinish(); + +SimpleTest.waitForFocus(startTest); + +function startTest() { + function textAreaCtor() { + return document.createElement("textarea"); + } + var ctors = [textAreaCtor]; + ["text", "password", "search"].forEach(function(type) { + ctors.push(function inputCtor() { + var input = document.createElement("input"); + input.type = type; + return input; + }); + }); + + for (var ctor in ctors) { + test(ctors[ctor]); + } + + SimpleTest.finish(); +} + +function test(ctor) { + var elem = ctor(); + ok(true, "Testing " + name(elem)); + + ok("selectionDirection" in elem, "elem should have the selectionDirection property"); + + is(elem.selectionStart, elem.value.length, "Default value"); + is(elem.selectionEnd, elem.value.length, "Default value"); + is(elem.selectionDirection, "forward", "Default value"); + + var content = document.getElementById("content"); + content.appendChild(elem); + + function flush() { document.body.clientWidth; } + function hide() { + content.style.display = "none"; + flush(); + } + function show() { + content.style.display = ""; + flush(); + } + + elem.value = "foobar"; + + is(elem.selectionStart, elem.value.length, "Default value"); + is(elem.selectionEnd, elem.value.length, "Default value"); + is(elem.selectionDirection, "forward", "Default value"); + + elem.setSelectionRange(1, 3); + is(elem.selectionStart, 1, "Correct value"); + is(elem.selectionEnd, 3, "Correct value"); + is(elem.selectionDirection, "forward", "If not set, should default to forward"); + + hide(); + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 3, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + show(); + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 3, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + // extend to right + elem.focus(); + synthesizeKey("VK_RIGHT", {shiftKey: true}); + + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 4, "Correct value"); + is(elem.selectionDirection, "forward", "Still forward"); + + hide(); + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + show(); + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + // change the direction + elem.selectionDirection = "backward"; + + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "backward", "Correct value"); + + hide(); + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); + + show(); + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); + + // extend to right again + synthesizeKey("VK_RIGHT", {shiftKey: true}); + + is(elem.selectionStart, 2, "Correct value"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "backward", "Still backward"); + + hide(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); + + show(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); + + elem.selectionEnd = 5; + + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Correct value"); + is(elem.selectionDirection, "backward", "Still backward"); + + hide(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); + + show(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); + + elem.selectionDirection = "none"; + + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "forward", "none not supported"); + + hide(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + show(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + elem.selectionDirection = "backward"; + + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "backward", "Correct Value"); + + hide(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); + + show(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); + + elem.selectionDirection = "invalid"; + + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "forward", "Treated as none"); + + hide(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + show(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + elem.selectionDirection = "backward"; + + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "backward", "Correct Value"); + + hide(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); + + show(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); + + elem.setSelectionRange(1, 4); + + is(elem.selectionStart, 1, "Correct value"); + is(elem.selectionEnd, 4, "Correct value"); + is(elem.selectionDirection, "forward", "Correct value"); + + hide(); + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + show(); + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + elem.setSelectionRange(1, 1); + synthesizeKey("VK_RIGHT", {shiftKey: true}); + synthesizeKey("VK_RIGHT", {shiftKey: true}); + synthesizeKey("VK_RIGHT", {shiftKey: true}); + + is(elem.selectionStart, 1, "Correct value"); + is(elem.selectionEnd, 4, "Correct value"); + is(elem.selectionDirection, "forward", "Correct value"); + + hide(); + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + show(); + is(elem.selectionStart, 1, "Value unchanged"); + is(elem.selectionEnd, 4, "Value unchanged"); + is(elem.selectionDirection, "forward", "Value unchanged"); + + elem.setSelectionRange(5, 5); + synthesizeKey("VK_LEFT", {shiftKey: true}); + synthesizeKey("VK_LEFT", {shiftKey: true}); + synthesizeKey("VK_LEFT", {shiftKey: true}); + + is(elem.selectionStart, 2, "Correct value"); + is(elem.selectionEnd, 5, "Correct value"); + is(elem.selectionDirection, "backward", "Correct value"); + + hide(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); + + show(); + is(elem.selectionStart, 2, "Value unchanged"); + is(elem.selectionEnd, 5, "Value unchanged"); + is(elem.selectionDirection, "backward", "Value unchanged"); +} + +function name(elem) { + var tag = elem.localName; + if (tag == "input") { + tag += "[type=" + elem.type + "]"; + } + return tag; +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug674927.html b/dom/html/test/test_bug674927.html new file mode 100644 index 0000000000..92af594530 --- /dev/null +++ b/dom/html/test/test_bug674927.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=674927 +--> +<title>Test for Bug 674927</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +<p><span>Hello</span></p> +<div contenteditable>Contenteditable <i>is</i> splelchecked by default</div> +<textarea>Textareas are spellchekced by default</textarea> +<input value="Inputs are not spellcheckde by default"> +<script> +// Test the effect of setting spellcheck on various elements +[ + "html", + "body", + "p", + "span", + "div", + "i", + "textarea", + "input", +].forEach(function(query) { + var element = document.querySelector(query); + + // First check what happens if no attributes are set + var defaultSpellcheck; + if (element.isContentEditable || element.tagName == "TEXTAREA") { + defaultSpellcheck = true; + } else { + defaultSpellcheck = false; + } + is(element.spellcheck, defaultSpellcheck, + "Default spellcheck for <" + element.tagName.toLowerCase() + ">"); + + // Now try setting spellcheck on ancestors + var ancestor = element; + do { + testSpellcheck(ancestor, element); + ancestor = ancestor.parentNode; + } while (ancestor.nodeType == Node.ELEMENT_NODE); +}); + +function testSpellcheck(ancestor, element) { + ancestor.spellcheck = true; + is(element.spellcheck, true, + ".spellcheck on <" + element.tagName.toLowerCase() + "> with " + + "spellcheck=true on <" + ancestor.tagName.toLowerCase() + ">"); + ancestor.spellcheck = false; + is(element.spellcheck, false, + ".spellcheck on <" + element.tagName.toLowerCase() + "> with " + + "spellcheck=false on <" + ancestor.tagName.toLowerCase() + ">"); + ancestor.removeAttribute("spellcheck"); +} +</script> diff --git a/dom/html/test/test_bug677495-1.html b/dom/html/test/test_bug677495-1.html new file mode 100644 index 0000000000..be11d20fd6 --- /dev/null +++ b/dom/html/test/test_bug677495-1.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=677495 + +As mandated by the spec, the body of a media document must only contain one child. +--> +<head> + <title>Test for Bug 571981</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + +<script type="application/javascript"> + SimpleTest.waitForExplicitFinish(); + + function frameLoaded() { + var testframe = document.getElementById('testframe'); + var testframeChildren = testframe.contentDocument.body.childNodes; + is(testframeChildren.length, 1, "Body of video document has 1 child"); + is(testframeChildren[0].nodeName, "VIDEO", "Only child of body must be a <video> element"); + + SimpleTest.finish(); + } +</script> + +</head> +<body> + <p id="display"></p> + + <iframe id="testframe" name="testframe" onload="frameLoaded()" + src="file.webm"></iframe> + +</body> +</html> diff --git a/dom/html/test/test_bug677495.html b/dom/html/test/test_bug677495.html new file mode 100644 index 0000000000..2145d5899c --- /dev/null +++ b/dom/html/test/test_bug677495.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=677495 + +As mandated by the spec, the body of a media document must only contain one child. +--> +<head> + <title>Test for Bug 571981</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + +<script type="application/javascript"> + SimpleTest.waitForExplicitFinish(); + + function frameLoaded() { + var testframe = document.getElementById('testframe'); + var testframeChildren = testframe.contentDocument.body.childNodes; + is(testframeChildren.length, 1, "Body of image document has 1 child"); + is(testframeChildren[0].nodeName, "IMG", "Only child of body must be an <img> element"); + + SimpleTest.finish(); + } +</script> + +</head> +<body> + <p id="display"></p> + + <iframe id="testframe" name="testframe" onload="frameLoaded()" + src="image.png"></iframe> + +</body> +</html> diff --git a/dom/html/test/test_bug677658.html b/dom/html/test/test_bug677658.html new file mode 100644 index 0000000000..79a4088b73 --- /dev/null +++ b/dom/html/test/test_bug677658.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=677658 +--> +<head> + <title>Test for Bug 677658</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body onload="test()"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677658">Mozilla Bug 677658</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"><!-- + +/** Test for Bug 677658 **/ + +SimpleTest.waitForExplicitFinish(); + +function testDone() { + ok(window.testPassed, "Script shouldn't have run!"); + SimpleTest.finish(); +} + +function test() { + window.testPassed = true; + document.getElementById("testtarget").innerHTML = + "<script async src='data:text/plain, window.testPassed = false;'></script>"; + SimpleTest.executeSoon(testDone); +} + +// --> +</script> +</pre> +<div id="testtarget"></div> +</body> +</html> diff --git a/dom/html/test/test_bug682886.html b/dom/html/test/test_bug682886.html new file mode 100644 index 0000000000..cb032738c9 --- /dev/null +++ b/dom/html/test/test_bug682886.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=682886 +--> +<head> + <title>Test for Bug 682886</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=682886">Mozilla Bug 682886</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 682886 **/ + + + var m = document.createElement("menu"); + var s = "<menuitem>foo</menuitem>"; + m.innerHTML = s; + is(m.innerHTML, s, "Wrong menuitem serialization!"); + + + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug691.html b/dom/html/test/test_bug691.html new file mode 100644 index 0000000000..f88df20a54 --- /dev/null +++ b/dom/html/test/test_bug691.html @@ -0,0 +1,62 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=691 +--> +<head> + <title>Test for Bug 691</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +<script type="text/javascript"> + +function show(what) { + var stage = document.getElementById("stage"); + if (what == "modularity") { + var spaghetti = document.createElement("IMG",null); + spaghetti.setAttribute("SRC","nnc_lockup.gif"); + spaghetti.setAttribute("id","foo"); + stage.insertBefore(spaghetti,stage.firstChild); + } +} + +function remove() { + var stage = document.getElementById("stage"); + var body = document.getElementsByTagName("BODY")[0]; + while (stage.firstChild) { + stage.firstChild.remove(); + } +} + +</script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=691">Mozilla Bug 691</a> +<p id="display"></p> +<div id="content" > +<ul> +<li >foo</li> +</ul> +<div id="stage"> +</div> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 691 **/ + +show("modularity"); +remove(); +show("modularity"); +remove(); +show("modularity"); +remove(); +show("modularity"); + +ok($("foo"), "basic DOM manipulation doesn't crash"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug694.html b/dom/html/test/test_bug694.html new file mode 100644 index 0000000000..78eb054cfc --- /dev/null +++ b/dom/html/test/test_bug694.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=694 +--> +<head> + <title>Test for Bug 694</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=694">Mozilla Bug 694</a> +<p id="display"></p> +<div id="content" > +<img src="/missing_on_purpose" width=123 height=25 alt="Hello, "Quotes" how are you?" id="testimg"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 694 **/ + +is($("testimg").getAttribute("alt"), "Hello, \"Quotes\" how are you?", "entities in alt attribute works"); + + + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug694503.html b/dom/html/test/test_bug694503.html new file mode 100644 index 0000000000..4ff10feffc --- /dev/null +++ b/dom/html/test/test_bug694503.html @@ -0,0 +1,75 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=694503 +--> +<head> + <title>Test for Bug 694503</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=694503">Mozilla Bug 694503</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> + +<div> +<map name="map1"> + <area onclick="++mapClickCount; event.preventDefault();" + coords="0,0,50,50" shape="rect"> +</map> +</div> + +<img id="img" + usemap="#map1" alt="Foo bar" src="about:logo"> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 694503 **/ + +var mapClickCount = 0; + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + var m = document.getElementsByTagName("map")[0]; + var img = document.getElementById('img'); + var origName = m.name; + + synthesizeMouse(img, 25, 25, {}); + is(mapClickCount, 1, "Wrong click count (1)"); + + m.name = "foo" + synthesizeMouse(img, 25, 25, {}); + is(mapClickCount, 1, "Wrong click count (2)"); + + m.removeAttribute("name"); + m.id = origName; + synthesizeMouse(img, 25, 25, {}); + is(mapClickCount, 2, "Wrong click count (3)"); + + // Back to original state + m.removeAttribute("id"); + m.name = origName; + synthesizeMouse(img, 25, 25, {}); + is(mapClickCount, 3, "Wrong click count (4)"); + + var p = m.parentNode; + p.removeChild(m); + synthesizeMouse(img, 25, 25, {}); + is(mapClickCount, 3, "Wrong click count (5)"); + + // Back to original state + p.appendChild(m); + synthesizeMouse(img, 25, 25, {}); + is(mapClickCount, 4, "Wrong click count (6)"); + + SimpleTest.finish(); +}); + + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug696.html b/dom/html/test/test_bug696.html new file mode 100644 index 0000000000..6b3c5d9561 --- /dev/null +++ b/dom/html/test/test_bug696.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=696 +--> +<head> + <title>Test for Bug 696</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=696">Mozilla Bug 696</a> +<p id="display"></p> +<div id="content" style="display: none"> + <table><tr id="mytr"><td>Foo</td><td>Bar</td></tr></table> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 696 **/ +var mytr = $("content").getElementsByTagName("TR")[0]; +is(mytr.getAttribute("ID"),"mytr","TR tags expose their ID attribute"); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug717819.html b/dom/html/test/test_bug717819.html new file mode 100644 index 0000000000..b2e04f17ba --- /dev/null +++ b/dom/html/test/test_bug717819.html @@ -0,0 +1,36 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=717819 +--> +<head> + <title>Test for Bug 717819</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=717819">Mozilla Bug 717819</a> +<p id="display"></p> +<div id="content"> + <table style="position: relative; top: 100px;"> + <tr> + <td> + <div id="test" style="position: absolute; top: 50px;"></div> + </td> + </tr> + </table> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 717819 **/ +var div = document.getElementById("test"); +is(div.offsetTop, 50, "The offsetTop must be calculated correctly"); +is(div.offsetParent, document.querySelector("table"), + "The offset should be calculated off of the correct parent"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug741266.html b/dom/html/test/test_bug741266.html new file mode 100644 index 0000000000..d61e5b6ab0 --- /dev/null +++ b/dom/html/test/test_bug741266.html @@ -0,0 +1,44 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=741266 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 741266</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=741266">Mozilla Bug 741266</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 741266 **/ +SimpleTest.waitForExplicitFinish(); + +var url = URL.createObjectURL(new Blob([""], { type: "text/html" })); +var w = window.open(url, "", "width=100,height=100"); +w.onload = function() { + is(w.innerHeight, 100, "Popup height should be 100 when opened with window.open"); + // XXXbz On at least some platforms, the innerWidth is off by the scrollbar + // width for some reason. So just make sure it's the same for both popups. + var width = w.innerWidth; + w.close(); + + w = document.open(url, "", "width=100,height=100"); + w.onload = function() { + is(w.innerHeight, 100, "Popup height should be 100 when opened with document.open"); + is(w.innerWidth, width, "Popup width should be the same when opened with document.open"); + w.close(); + SimpleTest.finish(); + }; +}; +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug742030.html b/dom/html/test/test_bug742030.html new file mode 100644 index 0000000000..28185e60db --- /dev/null +++ b/dom/html/test/test_bug742030.html @@ -0,0 +1,31 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=742030 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 742030</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=742030">Mozilla Bug 742030</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 742030 **/ +const str = " color: #ff0000 "; +var span = document.createElement("span"); +span.setAttribute("style", str); +is(span.getAttribute("style"), str, "Should have set properly"); +var span2 = span.cloneNode(false); +is(span2.getAttribute("style"), str, "Should have cloned properly"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug742549.html b/dom/html/test/test_bug742549.html new file mode 100644 index 0000000000..553493858e --- /dev/null +++ b/dom/html/test/test_bug742549.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=742549 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 742549</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=742549">Mozilla Bug 742549</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 742549 **/ +var els = [ document.createElement("script"), + document.createElementNS("http://www.w3.org/2000/svg", "script") ] + +for (var i = 0; i < els.length; ++i) { + reflectLimitedEnumerated({ + element: els[i], + attribute: { content: "crossorigin", idl: "crossOrigin" }, + // "" is a valid value per spec, but gets mapped to the "anonymous" state, + // just like invalid values, so just list it under invalidValues + validValues: [ "anonymous", "use-credentials" ], + invalidValues: [ + "", " aNOnYmous ", " UsE-CreDEntIALS ", "foobar", "FOOBAR", " fOoBaR " + ], + defaultValue: { invalid: "anonymous", missing: null }, + nullable: true, + }) +} + + + + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug745685.html b/dom/html/test/test_bug745685.html new file mode 100644 index 0000000000..c4544441e7 --- /dev/null +++ b/dom/html/test/test_bug745685.html @@ -0,0 +1,105 @@ +<!doctype html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=745685 +--> +<title>Test for Bug 745685</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=745685">Mozilla Bug 745685</a> +<font>Test text</font> +<font size=1>1</font> +<font size=2>2</font> +<font size=3>3</font> +<font size=4>4</font> +<font size=5>5</font> +<font size=6>6</font> +<font size=7>7</font> +<script> +/** Test for Bug 745685 **/ + +var referenceSizes = {}; +for (var i = 1; i <= 7; i++) { + referenceSizes[i] = + getComputedStyle(document.querySelector('[size="' + i + '"]')) + .fontSize; + if (i > 1) { + isnot(referenceSizes[i], referenceSizes[i - 1], + "Sanity check: different <font size>s give different .fontSize"); + } +} + +function testFontSize(input, expected) { + var font = document.querySelector("font"); + font.setAttribute("size", input); + is(font.getAttribute("size"), input, + "Setting doesn't round-trip (.getAttribute)"); + is(font.size, input, + "Setting doesn't round-trip (.size)"); + is(getComputedStyle(font).fontSize, referenceSizes[expected], + 'Incorrect size for "' + input + '" : expected the same as ' + expected); +} + +function testFontSizes(input, expected) { + testFontSize(input, expected); + // Leading whitespace + testFontSize(" " + input, expected); + testFontSize("\t" + input, expected); + testFontSize("\n" + input, expected); + testFontSize("\f" + input, expected); + testFontSize("\r" + input, expected); + // Trailing garbage + testFontSize(input + "abcd", expected); + testFontSize(input + ".5", expected); + testFontSize(input + "e2", expected); +} + +// Parse error +testFontSizes("", 3); + +// No sign +testFontSizes("0", 1); +testFontSizes("1", 1); +testFontSizes("2", 2); +testFontSizes("3", 3); +testFontSizes("4", 4); +testFontSizes("5", 5); +testFontSizes("6", 6); +testFontSizes("7", 7); +testFontSizes("8", 7); +testFontSizes("9", 7); +testFontSizes("10", 7); +testFontSizes("10000000000000000000000", 7); + +// Minus sign +testFontSizes("-0", 3); +testFontSizes("-1", 2); +testFontSizes("-2", 1); +testFontSizes("-3", 1); +testFontSizes("-4", 1); +testFontSizes("-5", 1); +testFontSizes("-6", 1); +testFontSizes("-7", 1); +testFontSizes("-8", 1); +testFontSizes("-9", 1); +testFontSizes("-10", 1); +testFontSizes("-10000000000000000000000", 1); + +// Plus sign +testFontSizes("+0", 3); +testFontSizes("+1", 4); +testFontSizes("+2", 5); +testFontSizes("+3", 6); +testFontSizes("+4", 7); +testFontSizes("+5", 7); +testFontSizes("+6", 7); +testFontSizes("+7", 7); +testFontSizes("+8", 7); +testFontSizes("+9", 7); +testFontSizes("+10", 7); +testFontSizes("+10000000000000000000000", 7); + +// Non-HTML5 whitespace +testFontSize("\b1", 3); +testFontSize("\v1", 3); +testFontSize("\0u00a01", 3); +</script> diff --git a/dom/html/test/test_bug763626.html b/dom/html/test/test_bug763626.html new file mode 100644 index 0000000000..11da9d1ad2 --- /dev/null +++ b/dom/html/test/test_bug763626.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=763626 +--> +<head> +<title>Test for Bug 763626</title> + +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + +<script type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); + +function boom() +{ + var r = document.createElement("iframe").sandbox; + SpecialPowers.DOMWindowUtils.garbageCollect(); + is("" + r, "", "ToString should return empty string when element is gone"); + SimpleTest.finish(); +} + +</script> +</head> + +<body onload="boom();"></body> +</html> + diff --git a/dom/html/test/test_bug765780.html b/dom/html/test/test_bug765780.html new file mode 100644 index 0000000000..9aee15ea6b --- /dev/null +++ b/dom/html/test/test_bug765780.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=765780 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 765780</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + /** Test for Bug 765780 **/ + SimpleTest.waitForExplicitFinish(); + window.onload = function() { + var f = $("f"); + var doc = f.contentDocument; + doc.designMode = "on"; + var s = doc.createElement("script"); + s.textContent = "parent.called = true;"; + + window.called = false; + doc.body.appendChild(s); + ok(called, "Script in designMode iframe should have run"); + + doc = doc.querySelector("iframe").contentDocument; + var s = doc.createElement("script"); + s.textContent = "parent.parent.called = true;"; + + window.called = false; + doc.body.appendChild(s); + ok(called, "Script in designMode iframe's child should have run"); + + SimpleTest.finish(); + } + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=765780">Mozilla Bug 765780</a> +<!-- Important: iframe needs to not be display: none --> +<p id="display"><iframe id="f" srcdoc="<iframe></iframe>"></iframe> </p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug780993.html b/dom/html/test/test_bug780993.html new file mode 100644 index 0000000000..14324e8e43 --- /dev/null +++ b/dom/html/test/test_bug780993.html @@ -0,0 +1,39 @@ +<!doctype html> +<meta charset=utf-8> +<title>Test for bug 780993</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + var select = document.createElement("select"); + var option = document.createElement("option"); + select.appendChild(option); + assert_equals(select[0], option); + select[0] = null; + assert_equals(option.parentNode, null); + assert_equals(select[0], undefined); +}, "Should be able to set select[n] to null."); +test(function() { + var select = document.createElement("select"); + var option = document.createElement("option"); + var option2 = document.createElement("option"); + select.appendChild(option); + assert_equals(select[0], option); + select[0] = option2; + assert_equals(option.parentNode, null); + assert_equals(option2.parentNode, select); + assert_equals(select[0], option2); +}, "Should be able to set select[n] to an option element"); +test(function() { + var select = document.createElement("select"); + var option = document.createElement("option"); + select.appendChild(option); + assert_equals(select[0], option); + assert_throws(null, function() { + select[0] = 42; + }); + assert_equals(option.parentNode, select); + assert_equals(select[0], option); +}, "Should not be able to set select[n] to a primitive."); +</script> diff --git a/dom/html/test/test_bug787134.html b/dom/html/test/test_bug787134.html new file mode 100644 index 0000000000..59aee4e463 --- /dev/null +++ b/dom/html/test/test_bug787134.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=787134 +--> +<head> + <title>Test for Bug 787134</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=787134">Mozilla Bug 787134</a> +<p id="display"></p> +<p><a id="link-test1" href="example link">example link</a></p> +<pre id="test"> +<script> + var div = document.createElement('div'); + div.innerHTML = '<a href=#></a>'; + var a = div.firstChild; + ok(a.matches(':link'), "Should match a link not in a document"); + is(div.querySelector(':link'), a, "Should find a link not in a document"); + a = document.querySelector('#link-test1'); + ok(a.matches(':link'), "Should match a link in a document with an invalid URL"); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug797113.html b/dom/html/test/test_bug797113.html new file mode 100644 index 0000000000..6c246eb3c3 --- /dev/null +++ b/dom/html/test/test_bug797113.html @@ -0,0 +1,39 @@ +<!doctype html> +<meta charset=utf-8> +<title>Test for bug 780993</title> +<script src=/resources/testharness.js></script> +<script src=/resources/testharnessreport.js></script> +<div id=log></div> +<script> +test(function() { + var select = document.createElement("select"); + var option = document.createElement("option"); + select.appendChild(option); + assert_equals(select.options[0], option); + select.options[0] = null; + assert_equals(option.parentNode, null); + assert_equals(select.options[0], undefined); +}, "Should be able to set select.options[n] to null."); +test(function() { + var select = document.createElement("select"); + var option = document.createElement("option"); + var option2 = document.createElement("option"); + select.appendChild(option); + assert_equals(select.options[0], option); + select.options[0] = option2; + assert_equals(option.parentNode, null); + assert_equals(option2.parentNode, select); + assert_equals(select.options[0], option2); +}, "Should be able to set select.options[n] to an option element"); +test(function() { + var select = document.createElement("select"); + var option = document.createElement("option"); + select.appendChild(option); + assert_equals(select.options[0], option); + assert_throws(null, function() { + select.options[0] = 42; + }); + assert_equals(option.parentNode, select); + assert_equals(select.options[0], option); +}, "Should not be able to set select.options[n] to a primitive."); +</script> diff --git a/dom/html/test/test_bug803677.html b/dom/html/test/test_bug803677.html new file mode 100644 index 0000000000..640f747528 --- /dev/null +++ b/dom/html/test/test_bug803677.html @@ -0,0 +1,49 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=803677 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 803677</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +<style> + .base { border:1px solid gray; } + .bad-table { display:table-cell; border:1px solid red; } +</style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=803677">Mozilla Bug 803677</a> +<p id="display"></p> +<div id="content"> + <p class="base">1</p> + <p class="base">2</p> + <p class="base">3</p> + <p class="base bad-table">4</p> + <p class="base">7</p> + <p class="base">8</p> + <p class="base">9</p> +</div> +<pre id="test"> +<script type="application/javascript"> + var p = document.querySelectorAll(".base"); + var parent = document.querySelector("body"); + var prevOffset = 0; + for (var i = 0; i < p.length; i++) { + var t = 0, e = p[i]; + is(e.offsetParent, parent, "Offset parent of all paragraphs should be the body."); + while (e) { + t += e.offsetTop; + e = e.offsetParent; + } + p[i].innerHTML = t; + + ok(t > prevOffset, "Offset should increase down the page"); + prevOffset = t; + } +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug821307.html b/dom/html/test/test_bug821307.html new file mode 100644 index 0000000000..591018da17 --- /dev/null +++ b/dom/html/test/test_bug821307.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=821307 +--> +<head> + <title>Test for Bug 821307</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=821307">Mozilla Bug 821307</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> + +<input id='dummy'></input> +<input type="password" id='input' value='11111111111111111' style="width:40em; font-size:40px;"></input> + +<pre id="test"> +<script type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + var dummy = document.getElementById('dummy'); + dummy.focus(); + is(document.activeElement, dummy, "Check dummy element is now focused"); + + var input = document.getElementById('input'); + var rect = input.getBoundingClientRect(); + synthesizeMouse(input, 100, rect.height/2, {}); + is(document.activeElement, input, "Check input element is now focused"); + + SimpleTest.finish(); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug827126.html b/dom/html/test/test_bug827126.html new file mode 100644 index 0000000000..c4cf28d44c --- /dev/null +++ b/dom/html/test/test_bug827126.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=827126 +--> +<head> + <title>Test for Bug 827126</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=827126">Mozilla Bug 827126</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> +/** Test to ensure we reflect <img align> correctly **/ +reflectString({ + element: new Image(), + attribute: "align", + otherValues: [ "left", "right", "middle", "justify" ] +}); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug838582.html b/dom/html/test/test_bug838582.html new file mode 100644 index 0000000000..2d412a041b --- /dev/null +++ b/dom/html/test/test_bug838582.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=838582 +--> +<head> + <title>Test for Bug 838582</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=838582">Mozilla Bug 838582</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<textarea id="t">abc</textarea> +<script type="application/javascript"> + +/** Test for Bug 838582 **/ + +var textarea = document.getElementById("t"); + +is(t.textLength, 3, "Correct textLength for defaultValue"); +t.value = "abcdef"; +is(t.textLength, 6, "Correct textLength for value"); +ok(!("controllers" in t), "Don't have web-visible controllers property"); +ok("controllers" in SpecialPowers.wrap(t), "Have chrome-visible controllers property"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug839371.html b/dom/html/test/test_bug839371.html new file mode 100644 index 0000000000..5d434a1803 --- /dev/null +++ b/dom/html/test/test_bug839371.html @@ -0,0 +1,44 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=839371 +--> +<head> + <title>Test for Bug 839371</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=839371">Mozilla Bug 839371</a> +<p id="display"></p> +<div id="content" style="display: none"> + +<div itemscope> + <data id="d1" itemprop="product-id" value="9678AOU879">The Instigator 2000</data> +</div> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 839371 **/ + +var d1 = document.getElementById("d1"), + d2 = document.createElement("data"); + +// .value IDL +is(d1.value, "9678AOU879", "value property reflects content attribute"); +d1.value = "123"; +is(d1.value, "123", "value property can be set via setter"); + +// .value reflects value attribute +reflectString({ + element: d2, + attribute: "value" +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug839913.html b/dom/html/test/test_bug839913.html new file mode 100644 index 0000000000..7397fa3b6b --- /dev/null +++ b/dom/html/test/test_bug839913.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Test for HTMLAreaElement's stringifier</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +test(function() { + var area = document.createElement("area"); + area.href = "http://example.org/"; + assert_equals(area.href, "http://example.org/"); + assert_equals(String(area), "http://example.org/"); +}, "Area elements should stringify to the href attribute"); +</script> diff --git a/dom/html/test/test_bug841466.html b/dom/html/test/test_bug841466.html new file mode 100644 index 0000000000..98eb9a305e --- /dev/null +++ b/dom/html/test/test_bug841466.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=841466 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 841466</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> + <script> + /** Test for Bug 841466 **/ +var els = ['button', 'fieldset', 'input', 'object', 'output', 'select', 'textarea']; +var code = "try { is(foo, 'bar', 'expected value bar from expando on element ' + localName); } catch (e) { ok(false, String(e)); }"; +els.forEach(function(el) { + var f = document.createElement("form"); + f.foo = "bar"; + f.innerHTML = '<' + el + ' onclick="' + code + '">'; + var e = f.firstChild + e.dispatchEvent(new Event("click")); +}) + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=841466">Mozilla Bug 841466</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug845057.html b/dom/html/test/test_bug845057.html new file mode 100644 index 0000000000..ef0d45d9ed --- /dev/null +++ b/dom/html/test/test_bug845057.html @@ -0,0 +1,59 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=845057 +--> +<head> + <title>Test for Bug 845057</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=845057">Mozilla Bug 845057</a> +<p id="display"></p> +<div id="content"> + <iframe id="iframe" sandbox="allow-scripts"></iframe> + +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + var iframe = document.getElementById("iframe"), + attr = iframe.sandbox; + // Security enforcement tests for iframe sandbox are in test_iframe_* + + function eq(a, b) { + // check if two attributes are qual modulo permutation + return ((a+'').split(" ").sort()+'') == ((b+'').split(" ").sort()+''); + } + + ok(attr instanceof DOMTokenList, + "Iframe sandbox attribute is instace of DOMTokenList"); + ok(eq(attr, "allow-scripts") && + eq(iframe.getAttribute("sandbox"), "allow-scripts"), + "Stringyfied sandbox attribute is same as that of the DOM element"); + + ok(attr.contains("allow-scripts") && !attr.contains("allow-same-origin"), + "Set membership of attribute elements is ok"); + + attr.add("allow-same-origin"); + + ok(attr.contains("allow-scripts") && attr.contains("allow-same-origin"), + "Attribute contains added atom"); + ok(eq(attr, "allow-scripts allow-same-origin") && + eq(iframe.getAttribute("sandbox"), "allow-scripts allow-same-origin"), + "Stringyfied attribute with new atom is correct"); + + attr.add("allow-forms"); + attr.remove("allow-scripts"); + + ok(!attr.contains("allow-scripts") && attr.contains("allow-forms") && + attr.contains("allow-same-origin"), + "Attribute does not contain removed atom"); + ok(eq(attr, "allow-forms allow-same-origin") && + eq(iframe.getAttribute("sandbox"), "allow-forms allow-same-origin"), + "Stringyfied attribute with removed atom is correct"); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_bug869040.html b/dom/html/test/test_bug869040.html new file mode 100644 index 0000000000..c7edcd89d9 --- /dev/null +++ b/dom/html/test/test_bug869040.html @@ -0,0 +1,36 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=869040 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 869040</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=869040">Mozilla Bug 869040</a> +<p id="display"></p> +<div id="content" style="display: none" data-foo="present1" data-bar="present2"> + +</div> +<pre id="test"> +</pre> + <script type="application/javascript"> + + /** Test for Bug 869040 **/ + var foo = "default1"; + var dataset = $("content").dataset; + for (var i = 0; i < 100000; ++i) + foo = dataset.foo; + + var bar = "default2"; + for (var j = 0; j < 100; ++j) + bar = dataset.bar; + + is(foo, "present1", "Our IC should work"); + is(bar, "present2", "Our non-IC case should work"); + </script> +</body> +</html> diff --git a/dom/html/test/test_bug870787.html b/dom/html/test/test_bug870787.html new file mode 100644 index 0000000000..d6f66dda32 --- /dev/null +++ b/dom/html/test/test_bug870787.html @@ -0,0 +1,84 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=870787 +--> +<head> + <title>Test for Bug 870787</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=870787">Mozilla Bug 870787</a> + +<p id="msg"></p> + +<form id="form0"></form> +<img name="img0" id="img0id"> + +<img name="img1" id="img1id" /> +<form id="form1"> + <img name="img2" id="img2id" /> +</form> +<img name="img3" id="img3id" /> + +<table> + <form id="form2"> + <tr><td> + <button name="input1" id="input1id" /> + <input name="input2" id="input2id" /> + </form> +</table> + +<table> + <form id="form3"> + <tr><td> + <img name="img4" id="img4id" /> + <img name="img5" id="img5id" /> + </form> +</table> + +<form id="form4"><img id="img6"></form> + +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 870787 **/ + +var form0 = document.getElementById("form0"); +ok(form0, "Form0 exists"); +ok(!form0.img0, "Form0.img0 doesn't exist"); +ok(!form0.img0id, "Form0.img0id doesn't exist"); + +var form1 = document.getElementById("form1"); +ok(form1, "Form1 exists"); +ok(!form1.img1, "Form1.img1 doesn't exist"); +ok(!form1.img1id, "Form1.img1id doesn't exist"); +is(form1.img2, document.getElementById("img2id"), "Form1.img2 exists"); +is(form1.img2id, document.getElementById("img2id"), "Form1.img2id exists"); +ok(!form1.img3, "Form1.img3 doesn't exist"); +ok(!form1.img3id, "Form1.img3id doesn't exist"); + +var form2 = document.getElementById("form2"); +ok(form2, "Form2 exists"); +is(form2.input1, document.getElementById("input1id"), "Form2.input1 exists"); +is(form2.input1id, document.getElementById("input1id"), "Form2.input1id exists"); +is(form2.input2, document.getElementById("input2id"), "Form2.input2 exists"); +is(form2.input2id, document.getElementById("input2id"), "Form2.input2id exists"); + +var form3 = document.getElementById("form3"); +ok(form3, "Form3 exists"); +is(form3.img4, document.getElementById("img4id"), "Form3.img4 doesn't exists"); +is(form3.img4id, document.getElementById("img4id"), "Form3.img4id doesn't exists"); +is(form3.img5, document.getElementById("img5id"), "Form3.img5 doesn't exists"); +is(form3.img5id, document.getElementById("img5id"), "Form3.img5id doesn't exists"); + +var form4 = document.getElementById("form4"); +ok(form4, "Form4 exists"); +is(Object.getOwnPropertyNames(form4.elements).indexOf("img6"), -1, "Form4.elements should not contain img6"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug871161.html b/dom/html/test/test_bug871161.html new file mode 100644 index 0000000000..c4512621b6 --- /dev/null +++ b/dom/html/test/test_bug871161.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=871161 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 871161</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 871161 **/ + SimpleTest.waitForExplicitFinish(); + + window.onmessage = function(e) { + is(e.data, "windows-1252", "Wrong charset"); + e.source.close(); + SimpleTest.finish(); + } + + function run() { + window.open("file_bug871161-1.html"); + } + + </script> +</head> +<body onload="run();"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=871161">Mozilla Bug 871161</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug874758.html b/dom/html/test/test_bug874758.html new file mode 100644 index 0000000000..fa77225ba6 --- /dev/null +++ b/dom/html/test/test_bug874758.html @@ -0,0 +1,31 @@ +<!DOCTYPE HTML> +<html data-expando-prop="xyz"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=874758 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 874758</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 874758 **/ + Object.prototype.expandoProp = 5; + is({}.expandoProp, 5, "Should see this on random objects"); + + is(document.head.dataset.expandoProp, 5, "Should see this on dataset too"); + is(document.documentElement.dataset.expandoProp, "xyz", + "But if the dataset has it, we should get it from there"); + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=874758">Mozilla Bug 874758</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug879319.html b/dom/html/test/test_bug879319.html new file mode 100644 index 0000000000..692f880449 --- /dev/null +++ b/dom/html/test/test_bug879319.html @@ -0,0 +1,92 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=879319 +--> +<head> + <title>Test for Bug 879319</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=879319">Mozilla Bug 879319</a> + +<p id="msg"></p> + +<form id="form"> + <img id="img0" name="bar0" /> +</form> +<input id="input0" name="foo0" form="form" /> +<input id="input1" name="foo1" form="form" /> +<input id="input2" name="foo2" form="form" /> + +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 879319 **/ + +var input0 = document.getElementById("input0"); +ok(input0, "input0 exists"); + +var form = document.getElementById("form"); +ok(form, "form exists"); +is(form.foo0, input0, "Form.foo0 should exist"); + +ok("foo0" in form.elements, "foo0 in form.elements"); +is(input0.form, form, "input0.form is form"); + +input0.setAttribute("name", "tmp0"); +ok("tmp0" in form.elements, "tmp0 is in form.elements"); +ok(!("foo0" in form.elements), "foo0 is not in form.elements"); +is(form.tmp0, input0, "Form.tmp0 == input0"); +is(form.foo0, input0, "Form.foo0 is still here"); + +input0.setAttribute("name", "tmp1"); +ok("tmp1" in form.elements, "tmp1 is in form.elements"); +ok(!("tmp0" in form.elements), "tmp0 is not in form.elements"); +ok(!("foo0" in form.elements), "foo0 is not in form.elements"); +is(form.tmp0, input0, "Form.tmp0 == input0"); +is(form.tmp1, input0, "Form.tmp1 == input0"); +is(form.foo0, input0, "Form.foo0 is still here"); + +input0.setAttribute("form", ""); +ok(!("foo0" in form.elements), "foo0 is not in form.elements"); +is(form.foo0, undefined, "Form.foo0 should not still be here"); +is(form.tmp0, undefined, "Form.tmp0 should not still be here"); +is(form.tmp1, undefined, "Form.tmp1 should not still be here"); + +var input1 = document.getElementById("input1"); +ok(input1, "input1 exists"); +is(form.foo1, input1, "Form.foo1 should exist"); + +ok("foo1" in form.elements, "foo1 in form.elements"); +is(input1.form, form, "input1.form is form"); + +input1.setAttribute("name", "foo0"); +ok("foo0" in form.elements, "foo0 is in form.elements"); +is(form.foo0, input1, "Form.foo0 should be input1"); +is(form.foo1, input1, "Form.foo1 should be input1"); + +var input2 = document.getElementById("input2"); +ok(input2, "input2 exists"); +is(form.foo2, input2, "Form.foo2 should exist"); +input2.remove(); +ok(!("foo2" in form.elements), "foo2 is not in form.elements"); +is(form.foo2, undefined, "Form.foo2 should not longer be there"); + +var img0 = document.getElementById("img0"); +ok(img0, "img0 exists"); +is(form.bar0, img0, "Form.bar0 should exist"); + +img0.setAttribute("name", "old_bar0"); +is(form.old_bar0, img0, "Form.bar0 is still here"); +is(form.bar0, img0, "Form.bar0 is still here"); + +img0.remove(); +is(form.bar0, undefined, "Form.bar0 should not be here"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug885024.html b/dom/html/test/test_bug885024.html new file mode 100644 index 0000000000..96f1783910 --- /dev/null +++ b/dom/html/test/test_bug885024.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML> +<html data-expando-prop="xyz"> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=885024 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 885024</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=885024">Mozilla Bug 885024</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> + +<img form="t"> + +<form id="form"> + <div id="div"></div> +</form> + +<pre id="test"> + <script type="application/javascript"> + var img = document.createElement('img'); + img.setAttribute('id', 'img'); + + var div = document.getElementById('div'); + div.appendChild(img); + + var form = document.getElementById('form'); + ok(form, "form exists"); + ok(form.img, "form.img exists"); + + var img2 = document.createElement('img'); + img2.setAttribute('id', 'img2'); + img2.setAttribute('form', 'blabla'); + ok(form, "form exists2"); + div.appendChild(img2); + ok(form.img2, "form.img2 exists"); + + </script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug893537.html b/dom/html/test/test_bug893537.html new file mode 100644 index 0000000000..5935529d87 --- /dev/null +++ b/dom/html/test/test_bug893537.html @@ -0,0 +1,45 @@ +<!doctype html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=893537 +--> + <head> +<title>Test for crash caused by unloading and reloading srcdoc iframes</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=893537">Mozilla Bug 893537</a> + +<iframe id="pframe" src="file_bug893537.html"></iframe> + +<pre id="test"> +<script> + <!-- Bug 895303 --> + SimpleTest.expectAssertions(0, 1); + + SimpleTest.waitForExplicitFinish(); + var pframe = $("pframe"); + + var loadState = 1; + pframe.contentWindow.addEventListener("load", function () { + + if (loadState == 1) { + var iframe = pframe.contentDocument.getElementById("iframe"); + iframe.removeAttribute("srcdoc"); + loadState = 2; + } + if (loadState == 2) { + SimpleTest.executeSoon(function () { pframe.contentWindow.location.reload() }); + loadState = 3; + } + if (loadState == 3) { + ok(true, "This is a mochitest implementation of a crashtest. To finish is to pass"); + SimpleTest.finish(); + } + }); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug95530.html b/dom/html/test/test_bug95530.html new file mode 100644 index 0000000000..c4a3078d3e --- /dev/null +++ b/dom/html/test/test_bug95530.html @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=95530 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 95530</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 95530 **/ + function run() { + is(document.compatMode, "CSS1Compat", "Ensure we are in standards mode, not quirks mode."); + + var body = document.getElementsByTagName("body"); + + is(computedStyle(body[0],"margin-top"), "100px", "Ensure margin-top matches topmargin"); + is(computedStyle(body[0],"margin-bottom"), "150px", "Ensure margin-bottom matches bottommargin"); + is(computedStyle(body[0],"margin-left"), "23px", "Ensure margin-left matches leftmargin"); + is(computedStyle(body[0],"margin-right"), "64px", "Ensure margin-right matches rightmargin"); + SimpleTest.finish(); + } + SimpleTest.waitForExplicitFinish(); + window.addEventListener("load", run); + </script> +</head> +<body topmargin="100" bottommargin="150" leftmargin="23" rightmargin="64"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=95530">Mozilla Bug 95530</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug969346.html b/dom/html/test/test_bug969346.html new file mode 100644 index 0000000000..5be76c46ec --- /dev/null +++ b/dom/html/test/test_bug969346.html @@ -0,0 +1,33 @@ +<!doctype html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=969346 +--> +<head> +<title>Nesting of srcdoc iframes is permitted</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=969349">Mozilla Bug 969346</a> + +<iframe id="pframe" srcdoc="<iframe id='iframe' srcdoc='I am nested'></iframe"></iframe> + +<pre id="test"> +<script> + + SimpleTest.waitForExplicitFinish(); + addLoadEvent(function () { + var pframe = $("pframe"); + var pframeDoc = pframe.contentDocument; + var iframe = pframeDoc.getElementById("iframe"); + var innerDoc = iframe.contentDocument; + + is(innerDoc.body.innerHTML, "I am nested", "Nesting not working?"); + SimpleTest.finish(); + }); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_bug982039.html b/dom/html/test/test_bug982039.html new file mode 100644 index 0000000000..6b158413bc --- /dev/null +++ b/dom/html/test/test_bug982039.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=982039 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 982039</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 982039 **/ + SimpleTest.waitForExplicitFinish(); + function test() { + var f = document.getElementById("testform"); + f.elements[0].disabled = true; + is(f.checkValidity(), false, + "Setting a radiobutton to disabled shouldn't make form valid."); + + f.elements[1].checked = true; + ok(f.checkValidity(), "Form should be now valid."); + + f.elements[0].required = false; + f.elements[1].required = false; + f.elements[2].required = false; + SimpleTest.finish(); + } + + </script> +</head> +<body onload="test()"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=982039">Mozilla Bug 982039</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +<form action="#" id="testform"> + <input type="radio" name="radio" value="1" required> + <input type="radio" name="radio" value="2" required> + <input type="radio" name="radio" value="3" required> +</form> +</body> +</html> diff --git a/dom/html/test/test_change_crossorigin.html b/dom/html/test/test_change_crossorigin.html new file mode 100644 index 0000000000..303aac7bea --- /dev/null +++ b/dom/html/test/test_change_crossorigin.html @@ -0,0 +1,89 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=696451 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 696451</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 696451 **/ + + SimpleTest.waitForExplicitFinish(); + + var img = new Image, + canvas = document.createElement("canvas"), + ctx = canvas.getContext("2d"), + src = "http://example.com/tests/dom/html/test/image-allow-credentials.png", + imgDone = false, + imgNotAllowedToLoadDone = false; + + img.src = src; + img.crossOrigin = "Anonymous"; + + img.addEventListener("load", function() { + canvas.width = img.width; + canvas.height = img.height; + ctx.drawImage( img, 0, 0 ); + try { + canvas.toDataURL("image/png"); + ok(true, "Image was refetched with setting crossOrigin."); + } catch (e) { + ok(false, "Image was not refetched after setting crossOrigin."); + } + + imgDone = true; + if (imgDone && imgNotAllowedToLoadDone) { + SimpleTest.finish(); + } + }); + + img.addEventListener("error", function (event) { + ok(false, "Should be able to load cross origin image with proper headers."); + + imgDone = true; + if (imgDone && imgNotAllowedToLoadDone) { + SimpleTest.finish(); + } + }); + + var imgNotAllowedToLoad = new Image; + + imgNotAllowedToLoad.src = "http://example.com/tests/dom/html/test/image.png"; + + imgNotAllowedToLoad.crossOrigin = "Anonymous"; + + imgNotAllowedToLoad.addEventListener("load", function() { + ok(false, "Image should not be allowed to load without " + + "allow-cross-origin-access headers."); + + imgNotAllowedToLoadDone = true; + if (imgDone && imgNotAllowedToLoadDone) { + SimpleTest.finish(); + } + }); + + imgNotAllowedToLoad.addEventListener("error", function() { + ok(true, "Image should not be allowed to load without " + + "allow-cross-origin-access headers."); + imgNotAllowedToLoadDone = true; + if (imgDone && imgNotAllowedToLoadDone) { + SimpleTest.finish(); + } + }); + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=696451">Mozilla Bug 696451</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_checked.html b/dom/html/test/test_checked.html new file mode 100644 index 0000000000..d69dcf2a28 --- /dev/null +++ b/dom/html/test/test_checked.html @@ -0,0 +1,347 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=418756 +--> +<head> + <title>Test for Bug 418756</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +Mozilla bug +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418756">418756</a> +<p id="display"></p> +<div id="content"> + <form id="f1"> + </form> + <form id="f2"> + </form> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +/** Test for Bug 418756 **/ +var group1; +var group2; +var group3; + +function bounce(node) { + let n = node.nextSibling; + let p = node.parentNode; + p.removeChild(node); + p.insertBefore(node, n); +} + +var createdNodes = []; + +function cleanup() { + for (let node of createdNodes) { + if (node.parentNode) { + node.remove(); + } + } + + createdNodes = []; +} + +var typeMapper = { + 'c': 'checkbox', + 'r': 'radio' +}; + +var id = 0; + +// type can be 'c' for 'checkbox' and 'r' for 'radio' +function createNode(type, name, checked) { + let node = document.createElement("input"); + node.setAttribute("type", typeMapper[type]); + if (checked) { + node.setAttribute("checked", "checked"); + } + node.setAttribute("id", type + (++id)); + node.setAttribute("name", name); + createdNodes.push(node); + return node; +} + +var types = ['c', 'r']; + +// First make sure that setting .checked makes .defaultChecked changes no +// longer affect .checked. +for (let type of types) { + let n = createNode(type, '', false); + is(n.defaultChecked, false, "Bogus defaultChecked on " + typeMapper[type]); + is(n.checked, false, "Bogus checked on " + typeMapper[type]); + n.defaultChecked = true; + is(n.defaultChecked, true, "Bogus defaultChecked on " + typeMapper[type] + + "after mutation"); + is(n.checked, true, "Bogus checked on " + typeMapper[type] + + "after mutation"); + n.checked = false; + is(n.defaultChecked, true, "Bogus defaultChecked on " + typeMapper[type] + + "after second mutation"); + is(n.checked, false, "Bogus checked on " + typeMapper[type] + + "after second mutation"); + n.defaultChecked = false; + is(n.defaultChecked, false, "Bogus defaultChecked on " + typeMapper[type] + + "after third mutation"); + is(n.checked, false, "Bogus checked on " + typeMapper[type] + + "after third mutation"); + n.defaultChecked = true; + is(n.defaultChecked, true, "Bogus defaultChecked on " + typeMapper[type] + + "after fourth mutation"); + is(n.checked, false, "Bogus checked on " + typeMapper[type] + + "after fourth mutation"); +} + +cleanup(); + +// Now check that bouncing a control that's the only one of its kind has no +// effect +for (let type of types) { + let n = createNode(type, 'test1', true); + $("f1").appendChild(n); + n.checked = false; + n.defaultChecked = false; + bounce(n); + n.defaultChecked = true; + is(n.checked, false, "We set .checked on this " + typeMapper[type]); +} + +cleanup(); + +// Now check that playing with a single radio in a group affects all +// other radios in the group (but not radios not in that group) +group1 = [ createNode('r', 'g1', false), + createNode('r', 'g1', false), + createNode('r', 'g1', false) ]; +group2 = [ createNode('r', 'g2', false), + createNode('r', 'g2', false), + createNode('r', 'g2', false) ]; +group3 = [ createNode('r', 'g1', false), + createNode('r', 'g1', false), + createNode('r', 'g1', false) ]; +for (let g of group1) { + $("f1").appendChild(g); +} +for (let g of group2) { + $("f1").appendChild(g); +} +for (let g of group3) { + $("f2").appendChild(g); +} + +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, false, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 1"); + is(g.checked, false, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checkedhecked wrong pass 1"); + } +} + +group1[1].defaultChecked = true; +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, n == 1 && group1.indexOf(g) == 1, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 2"); + is(g.checked, n == 1 && group1.indexOf(g) == 1, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 2"); + } +} + +group1[0].defaultChecked = true; +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, n == 1 && (group1.indexOf(g) == 1 || + group1.indexOf(g) == 0), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 3"); + is(g.checked, n == 1 && group1.indexOf(g) == 0, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 3"); + } +} + +group1[2].defaultChecked = true; +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, n == 1, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 4"); + is(g.checked, n == 1 && group1.indexOf(g) == 2, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 4"); + } +} + +var next = group1[1].nextSibling; +var p = group1[1].parentNode; +p.removeChild(group1[1]); +group1[1].defaultChecked = false; +group1[1].defaultChecked = true; +p.insertBefore(group1[1], next); +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, n == 1, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 5"); + is(g.checked, n == 1 && group1.indexOf(g) == 1, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 5"); + } +} + +for (let g of group1) { + g.defaultChecked = false; +} +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, false, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 6"); + is(g.checked, false, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checkedhecked wrong pass 6"); + } +} + +group1[1].checked = true; +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, false, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 7"); + is(g.checked, n == 1 && group1.indexOf(g) == 1, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 7"); + } +} + +group1[0].defaultChecked = true; +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, n == 1 && group1.indexOf(g) == 0, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 8"); + is(g.checked, n == 1 && group1.indexOf(g) == 1, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 8"); + } +} + +group1[2].defaultChecked = true; +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, n == 1 && (group1.indexOf(g) == 0 || + group1.indexOf(g) == 2), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 9"); + is(g.checked, n == 1 && group1.indexOf(g) == 1, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 9"); + } +} +group1[1].remove(); +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, n == 1 && (group1.indexOf(g) == 0 || + group1.indexOf(g) == 2), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 10"); + is(g.checked, n == 1 && group1.indexOf(g) == 1, + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 10"); + } +} + +group1[2].checked = true; +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, n == 1 && (group1.indexOf(g) == 0 || + group1.indexOf(g) == 2), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 11"); + is(g.checked, n == 1 && (group1.indexOf(g) == 1 || + group1.indexOf(g) == 2), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 11"); + } +} + +group1[0].checked = true; +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, n == 1 && (group1.indexOf(g) == 0 || + group1.indexOf(g) == 2), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 12"); + is(g.checked, n == 1 && (group1.indexOf(g) == 1 || + group1.indexOf(g) == 0), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 12"); + } +} + +next = group2[1].nextSibling; +p = group2[1].parentNode; +p.removeChild(group2[1]); +p.insertBefore(group2[1], next); +group2[0].checked = true; +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, n == 1 && (group1.indexOf(g) == 0 || + group1.indexOf(g) == 2), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 13"); + is(g.checked, (n == 1 && (group1.indexOf(g) == 1 || + group1.indexOf(g) == 0)) || + (n == 2 && group2.indexOf(g) == 0), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 13"); + } +} + +p.insertBefore(group2[1], next); +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, n == 1 && (group1.indexOf(g) == 0 || + group1.indexOf(g) == 2), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 14"); + is(g.checked, (n == 1 && (group1.indexOf(g) == 1 || + group1.indexOf(g) == 0)) || + (n == 2 && group2.indexOf(g) == 0), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 14"); + } +} + +group2[1].defaultChecked = true; +for (let n of [1, 2, 3]) { + for (let g of window["group"+n]) { + is(g.defaultChecked, (n == 1 && (group1.indexOf(g) == 0 || + group1.indexOf(g) == 2)) || + (n == 2 && group2.indexOf(g) == 1), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] defaultChecked wrong pass 15"); + is(g.checked, (n == 1 && (group1.indexOf(g) == 1 || + group1.indexOf(g) == 0)) || + (n == 2 && group2.indexOf(g) == 0), + "group" + n + "[" + window["group"+n].indexOf(g) + + "] checked wrong pass 15"); + } +} + +cleanup(); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_dir_attributes_reflection.html b/dom/html/test/test_dir_attributes_reflection.html new file mode 100644 index 0000000000..3aefaef9a5 --- /dev/null +++ b/dom/html/test/test_dir_attributes_reflection.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLDirectoryElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLDirectoryElement attributes reflection **/ + +// .name +reflectBoolean({ + element: document.createElement("dir"), + attribute: "compact", +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_dl_attributes_reflection.html b/dom/html/test/test_dl_attributes_reflection.html new file mode 100644 index 0000000000..100b28e9fb --- /dev/null +++ b/dom/html/test/test_dl_attributes_reflection.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLDListElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLDListElement attributes reflection **/ + +// .compact +reflectBoolean({ + element: document.createElement("dl"), + attribute: "compact" +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_document-element-inserted.html b/dom/html/test/test_document-element-inserted.html new file mode 100644 index 0000000000..6d7e8695ce --- /dev/null +++ b/dom/html/test/test_document-element-inserted.html @@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Media test: document-element-inserted</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<iframe id = 'media'> +</iframe> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +if (navigator.platform.startsWith("Win")) { + SimpleTest.expectAssertions(0, 4); +} + +SimpleTest.waitForExplicitFinish(); +var loc; + +var observe = function(doc){ + if (doc == media.contentDocument) { + ok(media.contentDocument.location.toString().includes(loc), + "The loaded media should be " + loc); + next(); + } +} + +var media = document.getElementById('media'); +var tests = [ + "../../../media/test/short-video.ogv", + "../../../media/test/sound.ogg", + "../../content/test/image.png" +] + +function next() { + if (tests.length) { + var t = tests.shift(); + loc = t.substring(t.indexOf("test")); + media.setAttribute("src",t); + } + else { + SpecialPowers.removeObserver(observe, "document-element-inserted"); + SimpleTest.finish(); + } +} + +SpecialPowers.addObserver(observe, "document-element-inserted") +next(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_documentAll.html b/dom/html/test/test_documentAll.html new file mode 100644 index 0000000000..f3bb7e7df6 --- /dev/null +++ b/dom/html/test/test_documentAll.html @@ -0,0 +1,167 @@ +<html> +<!-- +Tests for document.all +--> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <title>Tests for document.all</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=259332">Mozilla Bug 259332</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=393629">Mozilla Bug 393629</a> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=448904">Mozilla Bug 448904</a> +<p id="display"> +</p> +<div id="content" style="display: none"> + <a id="id1">A</a> + <a id="id2">B</a> + <a id="id2">C</a> + <a id="id3">D</a> + <a id="id3">E</a> + <a id="id3">F</a> +</div> +<iframe id="subframe" srcdoc="<span id='x'></span>" + style="display: none"></iframe> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +p = document.getElementById("content"); + +// Test that several elements with the same id or name behave correctly +function testNumSame() { + is(document.all.id0, undefined, "no ids"); + is(document.all.namedItem("id0"), null, "no ids"); + is(document.all.id1, p.children[0], "one id"); + is(document.all.id2[0], p.children[1], "two ids"); + is(document.all.id2[1], p.children[2], "two ids"); + is(document.all.id2.length, 2, "two length"); + is(document.all.id3[0], p.children[3], "three ids"); + is(document.all.id3[1], p.children[4], "three ids"); + is(document.all.id3[2], p.children[5], "three ids"); + is(document.all.id3.length, 3, "three length"); +} +testNumSame(); +p.innerHTML = p.innerHTML.replace(/id=/g, "name="); +testNumSame(); + + +// Test that dynamic changes behave properly + +// Add two elements and check that they are added to the correct lists +child = Array.prototype.slice.call(p.children); +child[6] = document.createElement("a"); +child[6].id = "id0"; +p.appendChild(child[6]); +child[7] = document.createElement("a"); +child[7].id = "id1"; +p.appendChild(child[7]); +is(document.all.id0, child[6], "now one id"); +is(document.all.id1[0], child[0], "now two ids"); +is(document.all.id1[1], child[7], "now two ids"); +is(document.all.id1.length, 2, "now two length"); + +// Remove and element and check that the list shrinks +rC(child[1]); +is(document.all.id2, child[2], "now just one id"); + +// Change an id and check that its removed and added to the correct lists +child[4].name = "id1"; +is(document.all.id1[0], child[0], "now three ids"); +is(document.all.id1[1], child[4], "now three ids"); +is(document.all.id1[2], child[7], "now three ids"); +is(document.all.id1.length, 3, "now three length"); +is(document.all.id3[1], child[5], "now just two ids"); +is(document.all.id3.length, 2, "now two length"); + +// Remove all elements from a list and check that it goes empty +id3list = document.all.id3; +rC(child[3]); +is(id3list.length, 1, "now one length"); +rC(child[5]); +is(document.all.id3, undefined, "now none"); +is(document.all.namedItem("id3"), null, "now none (namedItem)"); +is(id3list.length, 0, "now none length"); + +// Give an element both a name and id and check that it appears in two lists +p.insertBefore(child[1], child[2]); // restore previously removed +id1list = document.all.id1; +id2list = document.all.id2; +child[1].id = "id1"; +is(id1list[0], child[0], "now four ids"); +is(id1list[1], child[1], "now four ids"); +is(id1list[2], child[4], "now four ids"); +is(id1list[3], child[7], "now four ids"); +is(id1list.length, 4, "now four length"); +is(id2list[0], child[1], "still two ids"); +is(id2list[1], child[2], "still two ids"); +is(id2list.length, 2, "still two length"); + + +// Check that document.all behaves list a list of all elements +allElems = document.getElementsByTagName("*"); +ok(testArraysSame(document.all, allElems), "arrays same"); +length = document.all.length; +expectedLength = length + p.getElementsByTagName("*").length + 1; +p.appendChild(p.cloneNode(true)); +ok(testArraysSame(document.all, allElems), "arrays still same"); +is(document.all.length, expectedLength, "grew correctly"); + +// Check which elements the 'name' attribute works on +var elementNames = + ['abbr','acronym','address','area','a','b','base', + 'bgsound','big','blockquote','br','canvas','center','cite','code', + 'col','colgroup','dd','del','dfn','dir','div','dir','dl','dt','em','embed', + 'fieldset','font','form','frame','frameset','head','i','iframe','img', + 'input','ins','isindex','kbd','keygen','label','li','legend','link','menu', + 'multicol','noscript','noframes','object','spacer','table','td','td','th', + 'thead','tfoot','tr','textarea','select','option','spacer','param', + 'marquee','hr','title','hx','tt','u','ul','var','wbr','sub','sup','cite', + 'code','q','nobr','ol','p','pre','s','samp','small','body','html','map', + 'bdo','legend','listing','style','script','tbody','caption','meta', + 'optgroup','button','span','strike','strong','td'].sort(); +var hasName = + ['a','embed','form','iframe','img','input','object','textarea', + 'select','map','meta','button','frame','frameset'].sort(); + +elementNames.forEach(function (name) { + nameval = 'namefor' + name; + + e = document.createElement(name); + p.appendChild(e); + e.setAttribute('name', nameval); + + if (name == hasName[0]) { + is(document.all[nameval], e, "should have name"); + hasName.shift(); + } + else { + is(document.all[nameval], undefined, "shouldn't have name"); + is(document.all.namedItem(nameval), null, "shouldn't have name (namedItem)"); + } +}); +is(hasName.length, 0, "found all names"); + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + var subdoc = $("subframe").contentDocument; + is(subdoc.all.x, subdoc.body.firstChild, + "document.all should work in a subdocument"); + SimpleTest.finish(); +}); + +// Utility functions +function rC(node) { + node.remove(); +} +function testArraysSame(a1, a2) { + return Array.prototype.every.call(a1, function(e, index) { + return a2[index] === e; + }) && a1.length == a2.length; +} +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_element_prototype.html b/dom/html/test/test_element_prototype.html new file mode 100644 index 0000000000..0cb8d9745f --- /dev/null +++ b/dom/html/test/test_element_prototype.html @@ -0,0 +1,32 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=844127 +--> +<head> + <title>Test for Bug 844127</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=844127">Mozilla Bug 844127</a> + +<script type="text/javascript"> + +/** Test for Bug 844127 **/ + +var a1 = document.createElement('bgsound'); +var a2 = document.createElement('image'); +var a3 = document.createElement('multicol'); +var a4 = document.createElement('spacer'); +var a5 = document.createElement('isindex'); + +is(Object.getPrototypeOf(a1), HTMLUnknownElement.prototype, "Prototype for bgsound should be correct"); +is(Object.getPrototypeOf(a2), HTMLElement.prototype, "Prototype for image should be correct"); +is(Object.getPrototypeOf(a3), HTMLUnknownElement.prototype, "Prototype for multicol should be correct"); +is(Object.getPrototypeOf(a4), HTMLUnknownElement.prototype, "Prototype for spacer should be correct"); +is(Object.getPrototypeOf(a5), HTMLUnknownElement.prototype, "Prototype for isindex should be correct"); + +</script> +</body> +</html> diff --git a/dom/html/test/test_embed_attributes_reflection.html b/dom/html/test/test_embed_attributes_reflection.html new file mode 100644 index 0000000000..44338113a7 --- /dev/null +++ b/dom/html/test/test_embed_attributes_reflection.html @@ -0,0 +1,57 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLEmbedElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLEmbedElement attributes reflection **/ + +// .src (URL) +reflectURL({ + element: document.createElement("embed"), + attribute: "src", +}); + +// .type (String) +reflectString({ + element: document.createElement("embed"), + attribute: "type", +}); + +// .width (String) +reflectString({ + element: document.createElement("embed"), + attribute: "width", +}); + +// .height (String) +reflectString({ + element: document.createElement("embed"), + attribute: "height", +}); + +// .align (String) +reflectString({ + element: document.createElement("embed"), + attribute: "align", +}); + +// .name (String) +reflectString({ + element: document.createElement("embed"), + attribute: "name", +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_external_protocol_iframe.html b/dom/html/test/test_external_protocol_iframe.html new file mode 100644 index 0000000000..cb99a19e1a --- /dev/null +++ b/dom/html/test/test_external_protocol_iframe.html @@ -0,0 +1,80 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for external protocol URLs blocked for iframes</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/> +</head> +<body> + <div id='foo'><a href='#'>Click here to test this issue</a></div> + <script> + +function test_initialize() { + ChromeUtils.resetLastExternalProtocolIframeAllowed(); + next(); +} + +function test_noUserInteraction() { + ok(!SpecialPowers.wrap(document).hasValidTransientUserGestureActivation, "No user interaction yet"); + is(ChromeUtils.lastExternalProtocolIframeAllowed(), 0, "No iframe loaded before this test!"); + + for (let i = 0; i < 10; ++i) { + let ifr = document.createElement('iframe'); + ifr.src = "foo+bar:all_good"; + document.body.appendChild(ifr); + + is(ChromeUtils.getPopupControlState(), "openAbused", "No user-interaction means: abuse state"); + ok(ChromeUtils.lastExternalProtocolIframeAllowed() != 0, "We have 1 iframe loaded"); + } + + next(); +} + +function test_userInteraction() { + let foo = document.getElementById('foo'); + foo.addEventListener('click', _ => { + ok(SpecialPowers.wrap(document).hasValidTransientUserGestureActivation, "User should've interacted"); + + for (let i = 0; i < 10; ++i) { + let ifr = document.createElement('iframe'); + ifr.src = "foo+bar:all_good"; + document.body.appendChild(ifr); + + ok(!SpecialPowers.wrap(document).hasValidTransientUserGestureActivation, "User interaction should've been consumed"); + } + + next(); + + }, {once: true}); + + setTimeout(_ => { + synthesizeMouseAtCenter(foo, {}); + }, 0); +} + +let tests = [ + test_initialize, + test_noUserInteraction, + test_userInteraction, +]; + +function next() { + if (!tests.length) { + SimpleTest.finish(); + return; + } + + let test = tests.shift(); + SimpleTest.executeSoon(test); +} + +SpecialPowers.pushPrefEnv({'set': [ + ['dom.block_external_protocol_in_iframes', true], + ['dom.delay.block_external_protocol_in_iframes.enabled', true], +]}, next); + +SimpleTest.waitForExplicitFinish(); + </script> +</body> +</html> diff --git a/dom/html/test/test_fakepath.html b/dom/html/test/test_fakepath.html new file mode 100644 index 0000000000..f9819e732f --- /dev/null +++ b/dom/html/test/test_fakepath.html @@ -0,0 +1,40 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Fakepath in HTMLInputElement</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> + +<body> +<input id="file" type="file"></input> +<input id="file_wd" type="file" webkitdirectory></input> +<script type="application/javascript"> + +var url = SimpleTest.getTestFileURL("script_fakepath.js"); +script = SpecialPowers.loadChromeScript(url); + +function onOpened(message) { + var e = document.getElementById("file"); + SpecialPowers.wrap(e).mozSetDndFilesAndDirectories(message.data); + ok(e.value, "C:\\fakepath\\prefs.js"); + + e = document.getElementById("file_wd"); + SpecialPowers.wrap(e).mozSetDndFilesAndDirectories(message.data); + ok(e.value, "C:\\fakepath\\prefs.js"); + + SimpleTest.finish(); +} + +function run() { + script.addMessageListener("file.opened", onOpened); + script.sendAsyncMessage("file.open"); +} + +SpecialPowers.pushPrefEnv({"set": [["dom.webkitBlink.dirPicker.enabled", true]]}, run); + +SimpleTest.waitForExplicitFinish(); + +</script> +</body> +</html> diff --git a/dom/html/test/test_filepicker_default_directory.html b/dom/html/test/test_filepicker_default_directory.html new file mode 100644 index 0000000000..2be811655a --- /dev/null +++ b/dom/html/test/test_filepicker_default_directory.html @@ -0,0 +1,81 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1194893 +--> +<head> + <title>Test for filepicker default directory</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1194893">Mozilla Bug 1194893</a> +<div id="content"> + <input type="file" id="f"> +</div> +<pre id="text"> +<script class="testbody" type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); +const { Cc: Cc, Ci: Ci } = SpecialPowers; + +// Platform-independent directory names are #define'd in xpcom/io/nsDirectoryServiceDefs.h + +// When we want to test an upload directory other than the default, we need to +// get a valid directory in a platform-independent way. Since NS_OS_DESKTOP_DIR +// may fallback to NS_OS_HOME_DIR, let's use NS_OS_TMP_DIR. +var customUploadDirectory = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIDirectoryService) + .QueryInterface(Ci.nsIProperties) + .get("TmpD", Ci.nsIFile); + +// Useful for debugging +//info("customUploadDirectory" + customUploadDirectory.path); + +var MockFilePicker = SpecialPowers.MockFilePicker; +MockFilePicker.init(window); + +// need to show the MockFilePicker so .displayDirectory gets set +var f = document.getElementById("f"); +f.focus(); + +var testIndex = 0; +var tests = [ + ["", null, "Desk"], + [customUploadDirectory.path, customUploadDirectory.path, ""] +] + +MockFilePicker.showCallback = function(filepicker) { + if (tests[testIndex][1] === null) { + is(SpecialPowers.wrap(MockFilePicker).displayDirectory, null, "DisplayDirectory is null"); + } else { + is(SpecialPowers.wrap(MockFilePicker).displayDirectory.path, tests[testIndex][1], "DisplayDirectory matches the path"); + } + + is(SpecialPowers.wrap(MockFilePicker).displaySpecialDirectory, tests[testIndex][2], "DisplaySpecialDirectory matches the path"); + + if (++testIndex == tests.length) { + MockFilePicker.cleanup(); + SimpleTest.finish(); + } else { + launchNextTest(); + } +} + +function launchNextTest() { + SpecialPowers.pushPrefEnv( + { 'set': [ + ['dom.input.fallbackUploadDir', tests[testIndex][0]], + ]}, + function () { + f.click(); + }); +} + +launchNextTest(); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_focusshift_button.html b/dom/html/test/test_focusshift_button.html new file mode 100644 index 0000000000..90fadd4827 --- /dev/null +++ b/dom/html/test/test_focusshift_button.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for shifting focus while mouse clicking on button</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> + +<script class="testbody" type="application/javascript"> + +var result = ""; + +SimpleTest.waitForExplicitFinish(); +SimpleTest.waitForFocus(function() { + synthesizeMouseAtCenter(document.getElementById("button"), { }); + is(result, "(focus button)(blur button)(focus input)", "Focus button then input"); + SimpleTest.finish(); +}); +</script> + + +<button id="button" onfocus="result += '(focus button)'; document.getElementById('input').focus()" + onblur="result += '(blur button)'">Focus</button> +<input id="input" value="Test" onfocus="result += '(focus input)'" + onblur="result += '(blur input)'"> + +</body> +</html> diff --git a/dom/html/test/test_form-parsing.html b/dom/html/test/test_form-parsing.html new file mode 100644 index 0000000000..7c4acca756 --- /dev/null +++ b/dom/html/test/test_form-parsing.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Form parsing</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<div id="content" style="display: none"> + <div> + <form name="test" action="test" id="test"> + <input type="text" name="text1" id="text1" /> + <input type="text" name="text2" id="text2" /> + </div> + <input type="text" name="text3" id="text3" /> + <input type="text" name="text4" id="text4" /> + <input type="text" name="text5" id="text5" /> + <input type="text" name="text6" id="text6" /> + </form> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> + + var form1 = document.getElementById("test"); + var elem1 = form1.getElementsByTagName("*"); + var elem1Length = elem1.length; + var form1ElementsLength = form1.elements.length; + + is(form1ElementsLength, 6, "form.elements must include mis-nested elements"); + is(elem1Length, 2, "form must not include mis-nested elements"); +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_formData.html b/dom/html/test/test_formData.html new file mode 100644 index 0000000000..4518f37cf5 --- /dev/null +++ b/dom/html/test/test_formData.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=690659 +--> +<head> + <title>Test for Bug 690659 and 739173</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=690659">Mozilla Bug 690659 & 739173</a> +<script type="text/javascript" src="./formData_test.js"></script> +<script type="text/javascript"> +SimpleTest.waitForExplicitFinish(); + +function runMainThreadAndWorker() { + var mt = new Promise(function(resolve) { + runTest(resolve); + }); + + var worker; + var w = new Promise(function(resolve) { + worker = new Worker("formData_worker.js"); + worker.onmessage = function(event) { + if (event.data.type == 'finish') { + resolve(); + } else if (event.data.type == 'status') { + ok(event.data.status, event.data.msg); + } else if (event.data.type == 'todo') { + todo(event.data.status, event.data.msg); + } + } + + worker.onerror = function(event) { + ok(false, "Worker had an error: " + event.message + " at " + event.lineno); + resolve(); + }; + + worker.postMessage(true); + }); + + return Promise.all([mt, w]); +} + +runMainThreadAndWorker().then(SimpleTest.finish); +</script> +</body> +</html> diff --git a/dom/html/test/test_formSubmission.html b/dom/html/test/test_formSubmission.html new file mode 100644 index 0000000000..952f65e6dd --- /dev/null +++ b/dom/html/test/test_formSubmission.html @@ -0,0 +1,910 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=523771 +--> +<head> + <title>Test for Bug 523771</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + <meta http-equiv="Content-Type" content="text/html;charset=utf-8"> +</head> +<body onload="bodyLoaded()"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=523771">Mozilla Bug 523771</a> +<p id="display"></p> +<iframe name="target_iframe" id="target_iframe"></iframe> +<form action="form_submit_server.sjs" target="target_iframe" id="form" + method="POST" enctype="multipart/form-data"> + <table> + <tr> + <td>Control type</td> + <td>Name and value</td> + <td>Name, empty value</td> + <td>Name, no value</td> + <td>Empty name, with value</td> + <td>No name, with value</td> + <td>No name or value</td> + <td>Strange name/value</td> + </tr> + <tr> + <td>Default input</td> + <td><input name="n1_1" value="v1_1"></td> + <td><input name="n1_2" value=""></td> + <td><input name="n1_3"></td> + <td><input name="" value="v1_4"></td> + <td><input value="v1_5"></td> + <td><input></td> + <td><input name="n1_7_ _ _ _ _"" + value="v1_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Text input</td> + <td><input type=text name="n2_1" value="v2_1"></td> + <td><input type=text name="n2_2" value=""></td> + <td><input type=text name="n2_3"></td> + <td><input type=text name="" value="v2_4"></td> + <td><input type=text value="v2_5"></td> + <td><input type=text></td> + <td><input type=text name="n2_7_ _ _ _ _"" + value="v2_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Checkbox unchecked</td> + <td><input type=checkbox name="n3_1" value="v3_1"></td> + <td><input type=checkbox name="n3_2" value=""></td> + <td><input type=checkbox name="n3_3"></td> + <td><input type=checkbox name="" value="v3_4"></td> + <td><input type=checkbox value="v3_5"></td> + <td><input type=checkbox></td> + <td><input type=checkbox name="n3_7_ _ _ _ _"" + value="v3_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Checkbox checked</td> + <td><input checked type=checkbox name="n4_1" value="v4_1"></td> + <td><input checked type=checkbox name="n4_2" value=""></td> + <td><input checked type=checkbox name="n4_3"></td> + <td><input checked type=checkbox name="" value="v4_4"></td> + <td><input checked type=checkbox value="v4_5"></td> + <td><input checked type=checkbox></td> + <td><input checked type=checkbox + name="n4_7_ _ _ _ _"" + value="v4_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Radio unchecked</td> + <td><input type=radio name="n5_1" value="v5_1"></td> + <td><input type=radio name="n5_2" value=""></td> + <td><input type=radio name="n5_3"></td> + <td><input type=radio name="" value="v5_4"></td> + <td><input type=radio value="v5_5"></td> + <td><input type=radio></td> + <td><input type=radio name="n5_7_ _ _ _ _"" + value="v5_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Radio checked</td> + <td><input checked type=radio name="n6_1" value="v6_1"></td> + <td><input checked type=radio name="n6_2" value=""></td> + <td><input checked type=radio name="n6_3"></td> + <td><input checked type=radio name="" value="v6_4"></td> + <td><input checked type=radio value="v6_5"></td> + <td><input checked type=radio></td> + <td><input checked type=radio + name="n6_7_ _ _ _ _"" + value="v6_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Hidden input</td> + <td><input type=hidden name="n7_1" value="v7_1"></td> + <td><input type=hidden name="n7_2" value=""></td> + <td><input type=hidden name="n7_3"></td> + <td><input type=hidden nane="" value="v7_4"></td> + <td><input type=hidden value="v7_5"></td> + <td><input type=hidden></td> + <td><input type=hidden name="n7_7_ _ _ _ _"" + value="v7_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Password input</td> + <td><input type=password name="n8_1" value="v8_1"></td> + <td><input type=password name="n8_2" value=""></td> + <td><input type=password name="n8_3"></td> + <td><input type=password name="" value="v8_4"></td> + <td><input type=password value="v8_5"></td> + <td><input type=password></td> + <td><input type=password name="n8_7_ _ _ _ _"" + value="v8_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Submit input</td> + <td><input type=submit name="n9_1" value="v9_1"></td> + <td><input type=submit name="n9_2" value=""></td> + <td><input type=submit name="n9_3"></td> + <td><input type=submit name="" value="v9_4"></td> + <td><input type=submit value="v9_5"></td> + <td><input type=submit></td> + <td><input type=submit name="n9_7_ _ _ _ _"" + value="v9_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Button input</td> + <td><input type=button name="n10_1" value="v10_1"></td> + <td><input type=button name="n10_2" value=""></td> + <td><input type=button name="n10_3"></td> + <td><input type=button name="" value="v10_4"></td> + <td><input type=button value="v10_5"></td> + <td><input type=button></td> + <td><input type=button name="n10_7_ _ _ _ _"" + value="v10_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Image input</td> + <td><input type=image src="file_formSubmission_img.jpg" name="n11_1" value="v11_1"></td> + <td><input type=image src="file_formSubmission_img.jpg" name="n11_2" value=""></td> + <td><input type=image src="file_formSubmission_img.jpg" name="n11_3"></td> + <td><input type=image src="file_formSubmission_img.jpg" name="" value="v11_4"></td> + <td><input type=image src="file_formSubmission_img.jpg" value="v11_5"></td> + <td><input type=image src="file_formSubmission_img.jpg"></td> + <td><input type=image src="file_formSubmission_img.jpg" + name="n11_7_ _ _ _ _"" + value="v11_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Reset input</td> + <td><input type=reset name="n12_1" value="v12_1"></td> + <td><input type=reset name="n12_2" value=""></td> + <td><input type=reset name="n12_3"></td> + <td><input type=reset name="" value="v12_4"></td> + <td><input type=reset value="v12_5"></td> + <td><input type=reset></td> + <td><input type=reset name="n12_7_ _ _ _ _"" + value="v12_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Unknown input</td> + <td><input type=foobar name="n13_1" value="v13_1"></td> + <td><input type=foobar name="n13_2" value=""></td> + <td><input type=foobar name="n13_3"></td> + <td><input type=foobar name="" value="v13_4"></td> + <td><input type=foobar value="v13_5"></td> + <td><input type=foobar></td> + <td><input type=foobar name="n13_7_ _ _ _ _"" + value="v13_7_ _ _ _ _""></td> + </tr> + <tr> + <td>Default button</td> + <td><button name="n14_1" value="v14_1"></button></td> + <td><button name="n14_2" value=""></button></td> + <td><button name="n14_3"></button></td> + <td><button name="" value="v14_4"></button></td> + <td><button value="v14_5"></button></td> + <td><button></button></td> + <td><button name="n14_7_ _ _ _ _"" + value="v14_7_ _ _ _ _""></button></td> + </tr> + <tr> + <td>Submit button</td> + <td><button type=submit name="n15_1" value="v15_1"></button></td> + <td><button type=submit name="n15_2" value=""></button></td> + <td><button type=submit name="n15_3"></button></td> + <td><button type=submit name="" value="v15_4"></button></td> + <td><button type=submit value="v15_5"></button></td> + <td><button type=submit></button></td> + <td><button type=submit name="n15_7_ _ _ _ _"" + value="v15_7_ _ _ _ _""></button></td> + </tr> + <tr> + <td>Button button</td> + <td><button type=button name="n16_1" value="v16_1"></button></td> + <td><button type=button name="n16_2" value=""></button></td> + <td><button type=button name="n16_3"></button></td> + <td><button type=button name="" value="v16_4"></button></td> + <td><button type=button value="v16_5"></button></td> + <td><button type=button></button></td> + <td><button type=button name="n16_7_ _ _ _ _"" + value="v16_7_ _ _ _ _""></button></td> + </tr> + <tr> + <td>Reset button</td> + <td><button type=reset name="n17_1" value="v17_1"></button></td> + <td><button type=reset name="n17_2" value=""></button></td> + <td><button type=reset name="n17_3"></button></td> + <td><button type=reset name="" value="v17_4"></button></td> + <td><button type=reset value="v17_5"></button></td> + <td><button type=reset></button></td> + <td><button type=reset name="n17_7_ _ _ _ _"" + value="v17_7_ _ _ _ _""></button></td> + </tr> + <tr> + <td>Unknown button</td> + <td><button type=foobar name="n18_1" value="v18_1"></button></td> + <td><button type=foobar name="n18_2" value=""></button></td> + <td><button type=foobar name="n18_3"></button></td> + <td><button type=foobar name="" value="v18_4"></button></td> + <td><button type=foobar value="v18_5"></button></td> + <td><button type=foobar ></button></td> + <td><button type=foobar name="n18_7_ _ _ _ _"" + value="v18_7_ _ _ _ _""></button></td> + </tr> + <tr> + <td><input type='url'></td> + <td><input type=url name="n19_1" value="http://v19_1.org"></td> + <td><input type=url name="n19_2" value=""></td> + <td><input type=url name="n19_3"></td> + <td><input type=url name="" value="http://v19_4.org"></td> + <td><input type=url value="http://v19_5.org"></td> + <td><input type=url ></td> + <td><input type=url name="n19_7_ _ _ __"" + value="http://v19_7_ _ _ __""> + <!-- Put UTF-8 value in the "strange" column. --> + <input type=url name="n19_8" value="http://mózillä.órg"></td> + </tr> + <tr> + <td><input type='email'></td> + <td><input type=email name="n20_1" value="v20_1@bar"></td> + <td><input type=email name="n20_2" value=""></td> + <td><input type=email name="n20_3"></td> + <td><input type=email name="" value="v20_4@bar"></td> + <td><input type=email value="v20_5@bar"></td> + <td><input type=email ></td> + <td><input type=email name="n20_7_ _ _ __"" + value="v20_7_ _ _ __"@bar"> + <!-- Put UTF-8 value is the "strange" column. --> + <input type=email name="n20_8" value="foo@mózillä.órg"></td> + </tr> + </table> + + <p> + File input: + <input type=file name="file_1" class="setfile"> + <input type=file name="file_2"> + <input type=file name="" class="setfile"> + <input type=file name=""> + <input type=file class="setfile"> + <input type=file> + </p> + <p> + Multifile input: + <input multiple type=file name="file_3" class="setfile"> + <input multiple type=file name="file_4" class="setfile multi"> + <input multiple type=file name="file_5"> + <input multiple type=file name="" class="setfile"> + <input multiple type=file name="" class="setfile multi"> + <input multiple type=file name=""> + <input multiple type=file class="setfile"> + <input multiple type=file class="setfile multi"> + <input multiple type=file> + </p> + + <p> + Textarea: + <textarea name="t1">t_1_v</textarea> + <textarea name="t2"></textarea> + <textarea name="">t_3_v</textarea> + <textarea>t_4_v</textarea> + <textarea></textarea> + <textarea name="t6"> +t_6_v</textarea> + <textarea name="t7">t_7_v +</textarea> + <textarea name="t8"> + + t_8_v  +</textarea> + <textarea name="t9_ _ _ _ _"">t_9_ _ _ _ _"_v</textarea> + <textarea name="t10" value="t_10_bogus">t_10_v</textarea> + </p> + + <p> + Select one: + + <select name="sel_1"></select> + <select name="sel_1b"><option></option></select> + <select name="sel_1c"><option selected></option></select> + + <select name="sel_2"><option value="sel_2_v"></option></select> + <select name="sel_3"><option selected value="sel_3_v"></option></select> + + <select name="sel_4"><option value="sel_4_v1"></option><option value="sel_4_v2"></option></select> + <select name="sel_5"><option selected value="sel_5_v1"></option><option value="sel_5_v2"></option></select> + <select name="sel_6"><option value="sel_6_v1"></option><option selected value="sel_6_v2"></option></select> + + <select name="sel_7"><option>sel_7_v1</option><option>sel_7_v2</option></select> + <select name="sel_8"><option selected>sel_8_v1</option><option>sel_8_v2</option></select> + <select name="sel_9"><option>sel_9_v1</option><option selected>sel_9_v2</option></select> + + <select name="sel_10"><option value="sel_10_v1">sel_10_v1_text</option><option value="sel_10_v2">sel_10_v2_text</option></select> + <select name="sel_11"><option selected value="sel_11_v1">sel_11_v1_text</option><option value="sel_11_v2">sel_11_v2_text</option></select> + <select name="sel_12"><option value="sel_12_v1">sel_12_v1_text</option><option selected value="sel_12_v2">sel_12_v2_text</option></select> + + <select name="sel_13"><option disabled>sel_13_v1</option><option>sel_13_v2</option></select> + <select name="sel_14"><option disabled selected>sel_14_v1</option><option>sel_14_v2</option></select> + <select name="sel_15"><option disabled>sel_15_v1</option><option selected>sel_15_v2</option></select> + + <select name="sel_16"><option>sel_16_v1</option><option disabled>sel_16_v2</option></select> + <select name="sel_17"><option selected>sel_17_v1</option><option disabled>sel_17_v2</option></select> + <select name="sel_18"><option>sel_18_v1</option><option disabled selected>sel_18_v2</option></select> + + <select name=""><option selected value="sel_13_v1"></option><option value="sel_13_v2"></option></select> + <select name=""><option value="sel_14_v1"></option><option selected value="sel_14_v2"></option></select> + <select name=""><option selected>sel_15_v1</option><option>sel_15_v2</option></select> + <select name=""><option>sel_16_v1</option><option selected>sel_16_v2</option></select> + + <select><option selected value="sel_17_v1"></option><option value="sel_17_v2"></option></select> + <select><option value="sel_18_v1"></option><option selected value="sel_18_v2"></option></select> + <select><option selected>sel_19_v1</option><option>sel_19_v2</option></select> + <select><option>sel_20_v1</option><option selected>sel_20_v2</option></select> + </p> + + <p> + Select multiple: + + <select multiple name="msel_1"></select> + <select multiple name="msel_1b"><option></option></select> + <select multiple name="msel_1c"><option selected></option></select> + + <select multiple name="msel_2"><option value="msel_2_v"></option></select> + <select multiple name="msel_3"><option selected value="msel_3_v"></option></select> + + <select multiple name="msel_4"><option value="msel_4_v1"></option><option value="msel_4_v2"></option></select> + <select multiple name="msel_5"><option selected value="msel_5_v1"></option><option value="msel_5_v2"></option></select> + <select multiple name="msel_6"><option value="msel_6_v1"></option><option selected value="msel_6_v2"></option></select> + <select multiple name="msel_7"><option selected value="msel_7_v1"></option><option selected value="msel_7_v2"></option></select> + + <select multiple name="msel_8"><option>msel_8_v1</option><option>msel_8_v2</option></select> + <select multiple name="msel_9"><option selected>msel_9_v1</option><option>msel_9_v2</option></select> + <select multiple name="msel_10"><option>msel_10_v1</option><option selected>msel_10_v2</option></select> + <select multiple name="msel_11"><option selected>msel_11_v1</option><option selected>msel_11_v2</option></select> + + <select multiple name="msel_12"><option value="msel_12_v1">msel_12_v1_text</option><option value="msel_12_v2">msel_12_v2_text</option></select> + <select multiple name="msel_13"><option selected value="msel_13_v1">msel_13_v1_text</option><option value="msel_13_v2">msel_13_v2_text</option></select> + <select multiple name="msel_14"><option value="msel_14_v1">msel_14_v1_text</option><option selected value="msel_14_v2">msel_14_v2_text</option></select> + <select multiple name="msel_15"><option selected value="msel_15_v1">msel_15_v1_text</option><option selected value="msel_15_v2">msel_15_v2_text</option></select> + + <select multiple name="msel_16"><option>msel_16_v1</option><option>msel_16_v2</option><option>msel_16_v3</option></select> + <select multiple name="msel_17"><option selected>msel_17_v1</option><option>msel_17_v2</option><option>msel_17_v3</option></select> + <select multiple name="msel_18"><option>msel_18_v1</option><option selected>msel_18_v2</option><option>msel_18_v3</option></select> + <select multiple name="msel_19"><option selected>msel_19_v1</option><option selected>msel_19_v2</option><option>msel_19_v3</option></select> + <select multiple name="msel_20"><option>msel_20_v1</option><option>msel_20_v2</option><option selected>msel_20_v3</option></select> + <select multiple name="msel_21"><option selected>msel_21_v1</option><option>msel_21_v2</option><option selected>msel_21_v3</option></select> + <select multiple name="msel_22"><option>msel_22_v1</option><option selected>msel_22_v2</option><option selected>msel_22_v3</option></select> + <select multiple name="msel_23"><option selected>msel_23_v1</option><option selected>msel_23_v2</option><option selected>msel_23_v3</option></select> + + <select multiple name="msel_24"><option disabled>msel_24_v1</option><option>msel_24_v2</option></select> + <select multiple name="msel_25"><option disabled selected>msel_25_v1</option><option>msel_25_v2</option></select> + <select multiple name="msel_26"><option disabled>msel_26_v1</option><option selected>msel_26_v2</option></select> + <select multiple name="msel_27"><option disabled selected>msel_27_v1</option><option selected>msel_27_v2</option></select> + + <select multiple name="msel_28"><option>msel_28_v1</option><option disabled>msel_28_v2</option></select> + <select multiple name="msel_29"><option selected>msel_29_v1</option><option disabled>msel_29_v2</option></select> + <select multiple name="msel_30"><option>msel_30_v1</option><option disabled selected>msel_30_v2</option></select> + <select multiple name="msel_31"><option selected>msel_31_v1</option><option disabled selected>msel_31_v2</option></select> + + <select multiple name="msel_32"><option disabled selected>msel_32_v1</option><option disabled selected>msel_32_v2</option></select> + + <select multiple name=""><option>msel_33_v1</option><option>msel_33_v2</option></select> + <select multiple name=""><option selected>msel_34_v1</option><option>msel_34_v2</option></select> + <select multiple name=""><option>msel_35_v1</option><option selected>msel_35_v2</option></select> + <select multiple name=""><option selected>msel_36_v1</option><option selected>msel_36_v2</option></select> + + <select multiple><option>msel_37_v1</option><option>msel_37_v2</option></select> + <select multiple><option selected>msel_38_v1</option><option>msel_38_v2</option></select> + <select multiple><option>msel_39_v1</option><option selected>msel_39_v2</option></select> + <select multiple><option selected>msel_40_v1</option><option selected>msel_40_v2</option></select> + </p> +</form> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); + +const placeholder_myFile1 = {}; +const placeholder_myFile2 = {}; +const placeholder_emptyFile = {}; + +var myFile1, myFile2, emptyFile; +let openerURL, opener; +var gen; + +function bodyLoaded() { + openerURL = SimpleTest.getTestFileURL("formSubmission_chrome.js"); + opener = SpecialPowers.loadChromeScript(openerURL); + + let xhr = new XMLHttpRequest; + xhr.open("GET", "/dynamic/getMyDirectory.sjs", false); + xhr.send(); + let basePath = xhr.responseText; + + opener.addMessageListener("files.opened", onFilesOpened); + opener.sendAsyncMessage("files.open", [ + basePath + "file_formSubmission_text.txt", + basePath + "file_formSubmission_img.jpg", + ]); + + /* + * The below test function uses callbacks that invoke gen.next() rather than + * creating and resolving Promises. I'm trying to minimize churn since these + * changes want to be uplifted. Some kind soul might want to clean this all up + * at some point. + */ + + $("target_iframe").onload = function() { gen.next(); }; +} + + +function onFilesOpened(files) { + let [textFile, imageFile] = files; + opener.destroy(); + + let singleFile = textFile; + let multiFile = [textFile, imageFile]; + + var addList = document.getElementsByClassName("setfile"); + let i = 0; + var input; + while ((input = addList[i++])) { + if (input.classList.contains("multi")) { + SpecialPowers.wrap(input).mozSetFileArray(multiFile); + } else { + SpecialPowers.wrap(input).mozSetFileArray([singleFile]); + } + } + + input = document.createElement("input"); + input.type = "file"; + input.multiple = true; + SpecialPowers.wrap(input).mozSetFileArray(multiFile); + myFile1 = input.files[0]; + myFile2 = input.files[1]; + is(myFile1.size, 20, "File1 size"); + is(myFile2.size, 2711, "File2 size"); + emptyFile = { name: "", type: "application/octet-stream" }; + + // Now, actually run the tests; see below. + runAllTestVariants(); +}; + +var expectedSub = [ + // Default input + { name: "n1_1", value: "v1_1" }, + { name: "n1_2", value: "" }, + { name: "n1_3", value: "" }, + { name: "n1_7_\r\n_\r\n_\r\n_ _\"", value: "v1_7____ _\"" }, + // Text input + { name: "n2_1", value: "v2_1" }, + { name: "n2_2", value: "" }, + { name: "n2_3", value: "" }, + { name: "n2_7_\r\n_\r\n_\r\n_ _\"", value: "v2_7____ _\"" }, + // Checkbox unchecked + // Checkbox checked + { name: "n4_1", value: "v4_1" }, + { name: "n4_2", value: "" }, + { name: "n4_3", value: "on" }, + { name: "n4_7_\r\n_\r\n_\r\n_ _\"", value: "v4_7_\r\n_\r\n_\r\n_ _\"" }, + // Radio unchecked + // Radio checked + { name: "n6_1", value: "v6_1" }, + { name: "n6_2", value: "" }, + { name: "n6_3", value: "on" }, + { name: "n6_7_\r\n_\r\n_\r\n_ _\"", value: "v6_7_\r\n_\r\n_\r\n_ _\"" }, + // Hidden input + { name: "n7_1", value: "v7_1" }, + { name: "n7_2", value: "" }, + { name: "n7_3", value: "" }, + { name: "n7_7_\r\n_\r\n_\r\n_ _\"", value: "v7_7_\r\n_\r\n_\r\n_ _\"" }, + // Password input + { name: "n8_1", value: "v8_1" }, + { name: "n8_2", value: "" }, + { name: "n8_3", value: "" }, + { name: "n8_7_\r\n_\r\n_\r\n_ _\"", value: "v8_7____ _\"" }, + // Submit input + // Button input + // Image input + // Reset input + // Unknown input + { name: "n13_1", value: "v13_1" }, + { name: "n13_2", value: "" }, + { name: "n13_3", value: "" }, + { name: "n13_7_\r\n_\r\n_\r\n_ _\"", value: "v13_7____ _\"" }, + // <input type='url'> + { name: "n19_1", value: "http://v19_1.org" }, + { name: "n19_2", value: "" }, + { name: "n19_3", value: "" }, + { name: "n19_7_\r\n_\r\n_\r\n__\"", value: "http://v19_7_____\"" }, + { name: "n19_8", value: "http://m\xf3zill\xe4.\xf3rg" }, + // <input type='email'> + { name: "n20_1", value: "v20_1@bar" }, + { name: "n20_2", value: "" }, + { name: "n20_3", value: "" }, + { name: "n20_7_\r\n_\r\n_\r\n__\"", value: "v20_7_____\"@bar" }, + { name: "n20_8", value: "foo@mózillä.órg" }, + // Default button + // Submit button + // Button button + // Reset button + // Unknown button + // File + { name: "file_1", value: placeholder_myFile1 }, + { name: "file_2", value: placeholder_emptyFile }, + // Multiple file + { name: "file_3", value: placeholder_myFile1 }, + { name: "file_4", value: placeholder_myFile1 }, + { name: "file_4", value: placeholder_myFile2 }, + { name: "file_5", value: placeholder_emptyFile }, + // Textarea + { name: "t1", value: "t_1_v" }, + { name: "t2", value: "" }, + { name: "t6", value: "t_6_v" }, + { name: "t7", value: "t_7_v\r\n" }, + { name: "t8", value: "\r\n t_8_v \r\n" }, + { name: "t9_\r\n_\r\n_\r\n_ _\"", value: "t_9_\r\n_\r\n_\r\n_ _\"_v" }, + { name: "t10", value: "t_10_v" }, + + // Select one + { name: "sel_1b", value: "" }, + { name: "sel_1c", value: "" }, + { name: "sel_2", value: "sel_2_v" }, + { name: "sel_3", value: "sel_3_v" }, + { name: "sel_4", value: "sel_4_v1" }, + { name: "sel_5", value: "sel_5_v1" }, + { name: "sel_6", value: "sel_6_v2" }, + { name: "sel_7", value: "sel_7_v1" }, + { name: "sel_8", value: "sel_8_v1" }, + { name: "sel_9", value: "sel_9_v2" }, + { name: "sel_10", value: "sel_10_v1" }, + { name: "sel_11", value: "sel_11_v1" }, + { name: "sel_12", value: "sel_12_v2" }, + { name: "sel_13", value: "sel_13_v2" }, + { name: "sel_15", value: "sel_15_v2" }, + { name: "sel_16", value: "sel_16_v1" }, + { name: "sel_17", value: "sel_17_v1" }, + // Select three + { name: "msel_1c", value: "" }, + { name: "msel_3", value: "msel_3_v" }, + { name: "msel_5", value: "msel_5_v1" }, + { name: "msel_6", value: "msel_6_v2" }, + { name: "msel_7", value: "msel_7_v1" }, + { name: "msel_7", value: "msel_7_v2" }, + { name: "msel_9", value: "msel_9_v1" }, + { name: "msel_10", value: "msel_10_v2" }, + { name: "msel_11", value: "msel_11_v1" }, + { name: "msel_11", value: "msel_11_v2" }, + { name: "msel_13", value: "msel_13_v1" }, + { name: "msel_14", value: "msel_14_v2" }, + { name: "msel_15", value: "msel_15_v1" }, + { name: "msel_15", value: "msel_15_v2" }, + { name: "msel_17", value: "msel_17_v1" }, + { name: "msel_18", value: "msel_18_v2" }, + { name: "msel_19", value: "msel_19_v1" }, + { name: "msel_19", value: "msel_19_v2" }, + { name: "msel_20", value: "msel_20_v3" }, + { name: "msel_21", value: "msel_21_v1" }, + { name: "msel_21", value: "msel_21_v3" }, + { name: "msel_22", value: "msel_22_v2" }, + { name: "msel_22", value: "msel_22_v3" }, + { name: "msel_23", value: "msel_23_v1" }, + { name: "msel_23", value: "msel_23_v2" }, + { name: "msel_23", value: "msel_23_v3" }, + { name: "msel_26", value: "msel_26_v2" }, + { name: "msel_27", value: "msel_27_v2" }, + { name: "msel_29", value: "msel_29_v1" }, + { name: "msel_31", value: "msel_31_v1" }, +]; + +var expectedAugment = [ + { name: "aName", value: "aValue" }, + //{ name: "aNameBool", value: "false" }, + { name: "aNameNum", value: "9.2" }, + { name: "aNameFile1", value: placeholder_myFile1 }, + { name: "aNameFile2", value: placeholder_myFile2 }, + //{ name: "aNameObj", value: "[object XMLHttpRequest]" }, + //{ name: "aNameNull", value: "null" }, + //{ name: "aNameUndef", value: "undefined" }, +]; + +function checkMPSubmission(sub, expected, test) { + function getPropCount(o) { + var x, l = 0; + for (x in o) ++l; + return l; + } + function mpquote_name(s) { + return s.replace(/\r?\n|\r/g, "%0D%0A") + .replace(/\"/g, "%22"); + } + function mpquote_filename(s) { + return s.replace(/\r/g, "%0D") + .replace(/\n/g, "%0A") + .replace(/\"/g, "%22"); + } + + is(sub.length, expected.length, + "Correct number of multipart items in " + test); + + if (sub.length != expected.length) { + alert(JSON.stringify(sub)); + } + + var i; + for (i = 0; i < expected.length; ++i) { + if (!("fileName" in expected[i])) { + is(sub[i].headers["Content-Disposition"], + "form-data; name=\"" + mpquote_name(expected[i].name) + "\"", + "Correct name in " + test); + is (getPropCount(sub[i].headers), 1, + "Wrong number of headers in " + test); + is(sub[i].body, + expected[i].value.replace(/\r\n|\r|\n/, "\r\n"), + "Correct value in " + test); + } + else { + is(sub[i].headers["Content-Disposition"], + "form-data; name=\"" + mpquote_name(expected[i].name) + "\"; filename=\"" + + mpquote_filename(expected[i].fileName) + "\"", + "Correct name in " + test); + is(sub[i].headers["Content-Type"], + expected[i].contentType, + "Correct content type in " + test); + is (getPropCount(sub[i].headers), 2, + "Wrong number of headers in " + test); + is(sub[i].body, + expected[i].value, + "Correct value in " + test); + } + } +} + +function utf8encode(s) { + return unescape(encodeURIComponent(s)); +} + +function checkURLSubmission(sub, expected) { + function urlEscape(s) { + return escape(utf8encode(s)).replace(/%20/g, "+") + .replace(/\//g, "%2F") + .replace(/@/g, "%40"); + } + + subItems = sub.split("&"); + is(subItems.length, expected.length, + "Correct number of url items"); + var i; + for (i = 0; i < expected.length; ++i) { + let expect = urlEscape(expected[i].name) + "=" + + urlEscape(("fileName" in expected[i]) ? expected[i].fileName : expected[i].value); + is (subItems[i], expect, "expected URL part"); + } +} + +function checkPlainSubmission(sub, expected) { + + is(sub, + expected.map(function(v) { + return v.name + "=" + + (("fileName" in v) ? v.fileName : v.value) + + "\r\n"; + }).join(""), + "Correct submission"); +} + +function setDisabled(list, state) { + Array.prototype.forEach.call(list, function(e) { + e.disabled = state; + }); +} + +// Run the suite of tests for this variant, returning a Promise that will be +// resolved when the batch completes. Then and only then runTestVariant may +// be invoked to run a different variation. +function runTestVariant(variantLabel) { + info("starting test variant: " + variantLabel); + return new Promise((resolve) => { + // Instantiate the generator. + gen = runTestVariantUsingWeirdGenDriver(resolve); + // Run the generator to the first yield, at which point it is self-driving. + gen.next(); + }); +} +function* runTestVariantUsingWeirdGenDriver(finishedVariant) { + // Set up the expectedSub array + fileReader1 = new FileReader; + fileReader1.readAsBinaryString(myFile1); + fileReader2 = new FileReader; + fileReader2.readAsBinaryString(myFile2); + fileReader1.onload = fileReader2.onload = function() { gen.next(); }; + yield undefined; // Wait for both FileReaders. We don't care which order they finish. + yield undefined; + function fileFixup(o) { + if (o.value === placeholder_myFile1) { + o.value = fileReader1.result; + o.fileName = myFile1.name; + o.contentType = myFile1.type; + } + else if (o.value === placeholder_myFile2) { + o.value = fileReader2.result; + o.fileName = myFile2.name; + o.contentType = myFile2.type; + } + else if (o.value === placeholder_emptyFile) { + o.value = ""; + o.fileName = emptyFile.name; + o.contentType = emptyFile.type; + } + }; + expectedSub.forEach(fileFixup); + expectedAugment.forEach(fileFixup); + + var form = $("form"); + + // multipart/form-data + var iframe = $("target_iframe"); + + // Make normal submission + form.action = "form_submit_server.sjs"; + form.method = "POST"; + form.enctype = "multipart/form-data"; + form.submit(); + yield undefined; // Wait for iframe to load as a result of the submission + var submission = JSON.parse(iframe.contentDocument.documentElement.textContent); + checkMPSubmission(submission, expectedSub, "normal submission"); + + // Disabled controls + setDisabled(document.querySelectorAll("input, select, textarea"), true); + form.submit(); + yield undefined; + submission = JSON.parse(iframe.contentDocument.documentElement.textContent); + checkMPSubmission(submission, [], "disabled controls"); + + // Reenabled controls + setDisabled(document.querySelectorAll("input, select, textarea"), false); + form.submit(); + yield undefined; + submission = JSON.parse(iframe.contentDocument.documentElement.textContent); + checkMPSubmission(submission, expectedSub, "reenabled controls"); + + // text/plain + form.action = "form_submit_server.sjs?plain"; + form.enctype = "text/plain"; + form.submit(); + yield undefined; + submission = JSON.parse(iframe.contentDocument.documentElement.textContent); + checkPlainSubmission(submission, expectedSub); + + // application/x-www-form-urlencoded + form.action = "form_submit_server.sjs?url"; + form.enctype = "application/x-www-form-urlencoded"; + form.submit(); + yield undefined; + submission = JSON.parse(iframe.contentDocument.documentElement.textContent); + checkURLSubmission(submission, expectedSub); + + // application/x-www-form-urlencoded + form.action = "form_submit_server.sjs?xxyy"; + form.method = "GET"; + form.enctype = ""; + form.submit(); + yield undefined; + submission = JSON.parse(iframe.contentDocument.documentElement.textContent); + checkURLSubmission(submission, expectedSub); + + // application/x-www-form-urlencoded + form.action = "form_submit_server.sjs"; + form.method = ""; + form.enctype = ""; + form.submit(); + yield undefined; + submission = JSON.parse(iframe.contentDocument.documentElement.textContent); + checkURLSubmission(submission, expectedSub); + + // Send form using XHR and FormData + xhr = new XMLHttpRequest(); + xhr.onload = function() { gen.next(); }; + xhr.open("POST", "form_submit_server.sjs"); + xhr.send(new FormData(form)); + yield undefined; // Wait for XHR load + checkMPSubmission(JSON.parse(xhr.responseText), expectedSub, "send form using XHR and FormData"); + + // Send disabled form using XHR and FormData + setDisabled(document.querySelectorAll("input, select, textarea"), true); + xhr.open("POST", "form_submit_server.sjs"); + xhr.send(new FormData(form)); + yield undefined; + checkMPSubmission(JSON.parse(xhr.responseText), [], "send disabled form using XHR and FormData"); + setDisabled(document.querySelectorAll("input, select, textarea"), false); + + // Send FormData + function addToFormData(fd) { + fd.append("aName", "aValue"); + fd.append("aNameNum", 9.2); + fd.append("aNameFile1", myFile1); + fd.append("aNameFile2", myFile2); + } + var fd = new FormData(); + addToFormData(fd); + xhr.open("POST", "form_submit_server.sjs"); + xhr.send(fd); + yield undefined; + checkMPSubmission(JSON.parse(xhr.responseText), expectedAugment, "send FormData"); + + // Augment <form> using FormData + fd = new FormData(form); + addToFormData(fd); + xhr.open("POST", "form_submit_server.sjs"); + xhr.send(fd); + yield undefined; + checkMPSubmission(JSON.parse(xhr.responseText), + expectedSub.concat(expectedAugment), "send augmented FormData"); + + finishedVariant(); +} + +/** + * Install our service-worker (parameterized by appending "?MODE"), which will + * invoke skipWaiting() and clients.claim() to begin controlling us ASAP. We + * wait on the controllerchange event + */ +async function installAndBeControlledByServiceWorker(mode) { + const scriptURL = "sw_formSubmission.js?" + mode; + const controllerChanged = new Promise((resolve) => { + navigator.serviceWorker.addEventListener( + "controllerchange", () => { resolve(); }, { once: true }); + }); + + info("installing ServiceWorker: " + scriptURL); + const swr = await navigator.serviceWorker.register(scriptURL, + { scope: "./" }); + await controllerChanged; + ok(navigator.serviceWorker.controller.scriptURL.endsWith(scriptURL), + "controlled by the SW we expected"); + info("became controlled by ServiceWorker."); + + return swr; +} + +async function runAllTestVariants() { + // Run the test as it has historically been run, with no ServiceWorkers + // anywhere! + await runTestVariant("no ServiceWorker"); + + // Uncomment the below if something in the test seems broken and you're not + // sure whether it's a side-effect of the multiple passes or not. + //await runTestVariant("no ServiceWorker second paranoia time"); + + // Ensure ServiceWorkers are enabled and that testing mode (which disables + // security checks) is on too. + await SpecialPowers.pushPrefEnv({"set": [ + ["dom.serviceWorkers.enabled", true], + ["dom.serviceWorkers.testing.enabled", true] + ]}); + + // Now run the test with a ServiceWorker that covers the scope but has no + // fetch handler, so the optimization case will not actually dispatch a + // "fetch" event, but some stuff will happen that can change things enough + // to break them like in https://bugzilla.mozilla.org/show_bug.cgi?id=1383518. + await installAndBeControlledByServiceWorker("no-fetch"); + await runTestVariant("ServiceWorker that does not listen for fetch events"); + + // Now the ServiceWorker does have a "fetch" event listener, but it will reset + // interception every time. This is similar to the prior case but different + // enough that it could break things in a different exciting way. + await installAndBeControlledByServiceWorker("reset-fetch"); + await runTestVariant("ServiceWorker that resets all fetches"); + + // Now the ServiceWorker resolves the fetch event with `fetch(event.request)` + // which makes little sense but is a thing that can happen. + const swr = await installAndBeControlledByServiceWorker("proxy-fetch"); + await runTestVariant("ServiceWorker that proxies all fetches"); + + // cleanup. + info("unregistering ServiceWorker"); + await swr.unregister(); + info("ServiceWorker uninstalled"); + + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_formSubmission2.html b/dom/html/test/test_formSubmission2.html new file mode 100644 index 0000000000..fc6b60cdcf --- /dev/null +++ b/dom/html/test/test_formSubmission2.html @@ -0,0 +1,220 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=523771 +--> +<head> + <title>Test for Bug 523771</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=523771">Mozilla Bug 523771</a> +<p id="display"></p> +<iframe name="target_iframe" id="target_iframe"></iframe> +<form action="form_submit_server.sjs" target="target_iframe" id="form" + method="POST" enctype="multipart/form-data"> + <table> + <tr> + <td>Control type</td> + <td>Name and value</td> + <td>Name, empty value</td> + <td>Name, no value</td> + <td>Empty name, with value</td> + <td>No name, with value</td> + <td>No name or value</td> + </tr> + <tr> + <td>Submit input</td> + <td><input type=submit name="n1_1" value="v1_1"></td> + <td><input type=submit name="n1_2" value=""></td> + <td><input type=submit name="n1_3"></td> + <td><input type=submit name="" value="v1_4"></td> + <td><input type=submit value="v1_5"></td> + <td><input type=submit></td> + </tr> + <tr> + <td>Image input</td> + <td><input type=image src="file_formSubmission_img.jpg" name="n2_1" value="v2_1"></td> + <td><input type=image src="file_formSubmission_img.jpg" name="n2_2" value=""></td> + <td><input type=image src="file_formSubmission_img.jpg" name="n2_3"></td> + <td><input type=image src="file_formSubmission_img.jpg" name="" value="v2_4"></td> + <td><input type=image src="file_formSubmission_img.jpg" value="v2_5"></td> + <td><input type=image src="file_formSubmission_img.jpg"></td> + </tr> + <tr> + <td>Submit button</td> + <td><button type=submit name="n3_1" value="v3_1"></button></td> + <td><button type=submit name="n3_2" value=""></button></td> + <td><button type=submit name="n3_3"></button></td> + <td><button type=submit name="" value="v3_4"></button></td> + <td><button type=submit value="v3_5"></button></td> + <td><button type=submit ></button></td> + </tr> + <tr> + <td>Submit button with text</td> + <td><button type=submit name="n4_1" value="v4_1">text here</button></td> + <td><button type=submit name="n4_2" value="">text here</button></td> + <td><button type=submit name="n4_3">text here</button></td> + <td><button type=submit name="" value="v4_4">text here</button></td> + <td><button type=submit value="v4_5">text here</button></td> + <td><button type=submit>text here</button></td> + </tr> + </table> +</form> +<pre id="test"> +<script class="testbody" type="text/javascript"> + +var gen = runTest(); + +SimpleTest.waitForExplicitFinish(); +addLoadEvent(function() { + gen.next(); +}); + +var expectedSub = [ + // Submit input + [{ name: "n1_1", value: "v1_1" }], + [{ name: "n1_2", value: "" }], + [{ name: "n1_3", value: "Submit Query" }], + [], + [], + [], + // Image input + [{ name: "n2_1.x", value: "10" }, + { name: "n2_1.y", value: "7" }], + [{ name: "n2_2.x", value: "10" }, + { name: "n2_2.y", value: "7" }], + [{ name: "n2_3.x", value: "10" }, + { name: "n2_3.y", value: "7" }], + [{ name: "x", value: "10" }, + { name: "y", value: "7" }], + [{ name: "x", value: "10" }, + { name: "y", value: "7" }], + [{ name: "x", value: "10" }, + { name: "y", value: "7" }], + // Submit button + [{ name: "n3_1", value: "v3_1" }], + [{ name: "n3_2", value: "" }], + [{ name: "n3_3", value: "" }], + [], + [], + [], + // Submit button with text + [{ name: "n4_1", value: "v4_1" }], + [{ name: "n4_2", value: "" }], + [{ name: "n4_3", value: "" }], + [], + [], + [], +]; + +function checkSubmission(sub, expected) { + function getPropCount(o) { + var x, l = 0; + for (x in o) ++l; + return l; + } + + is(sub.length, expected.length, + "Correct number of items"); + var i; + for (i = 0; i < expected.length; ++i) { + if (!("fileName" in expected[i])) { + is(sub[i].headers["Content-Disposition"], + "form-data; name=\"" + expected[i].name + "\"", + "Correct name"); + is (getPropCount(sub[i].headers), 1, + "Wrong number of headers"); + } + else { + is(sub[i].headers["Content-Disposition"], + "form-data; name=\"" + expected[i].name + "\"; filename=\"" + + expected[i].fileName + "\"", + "Correct name"); + is(sub[i].headers["Content-Type"], + expected[i].contentType, + "Correct content type"); + is (getPropCount(sub[i].headers), 2, + "Wrong number of headers"); + } + is(sub[i].body, + expected[i].value, + "Correct value"); + } +} + +function clickImage(aTarget, aX, aY) +{ + aTarget.style.position = "absolute"; + aTarget.style.top = "0"; + aTarget.style.left = "0"; + aTarget.offsetTop; + + var wu = SpecialPowers.getDOMWindowUtils(aTarget.ownerDocument.defaultView); + + wu.sendMouseEvent('mousedown', aX, aY, 0, 1, 0); + wu.sendMouseEvent('mouseup', aX, aY, 0, 0, 0); + + aTarget.style.position = ""; + aTarget.style.top = ""; + aTarget.style.left = ""; +} + +function* runTest() { + // Make normal submission + var form = $("form"); + var iframe = $("target_iframe"); + iframe.onload = function() { gen.next(); }; + + var elements = form.querySelectorAll("input, button"); + + is(elements.length, expectedSub.length, + "tests vs. expected out of sync"); + + var i; + for (i = 0; i < elements.length && i < expectedSub.length; ++i) { + elem = elements[i]; + if (elem.localName != "input" || elem.type != "image") { + elem.click(); + } + else { + clickImage(elem, 10, 7); + } + yield undefined; + + var submission = JSON.parse(iframe.contentDocument.documentElement.textContent); + checkSubmission(submission, expectedSub[i]); + } + + // Disabled controls + var i; + for (i = 0; i < elements.length && i < expectedSub.length; ++i) { + elem = elements[i]; + form.onsubmit = function() { + elem.disabled = true; + } + if (elem.localName != "input" || elem.type != "image") { + elem.click(); + } + else { + clickImage(elem, 10, 7); + } + yield undefined; + + is(elem.disabled, true, "didn't disable"); + elem.disabled = false; + form.onsubmit = undefined; + + var submission = JSON.parse(iframe.contentDocument.documentElement.textContent); + checkSubmission(submission, []); + } + + SimpleTest.finish(); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_formelements.html b/dom/html/test/test_formelements.html new file mode 100644 index 0000000000..b753759bcb --- /dev/null +++ b/dom/html/test/test_formelements.html @@ -0,0 +1,68 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=772869 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 772869</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=772869">Mozilla Bug 772869</a> +<p id="display"></p> +<div id="content" style="display: none"> + <form id="f"> + <input name="x"> + <input type="image" name="a"> + <input type="file" name="y"> + <input type="submit" name="z"> + <input id="w"> + <input name="w"> + </form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 772869 **/ +var x = $("f").elements; +x.something = "another"; +names = []; +for (var name in x) { + names.push(name); +} +is(names.length, 9, "Should have 9 enumerated names"); +is(names[0], "0", "Enum entry 1"); +is(names[1], "1", "Enum entry 2"); +is(names[2], "2", "Enum entry 3"); +is(names[3], "3", "Enum entry 4"); +is(names[4], "4", "Enum entry 5"); +is(names[5], "something", "Enum entry 6"); +is(names[6], "namedItem", "Enum entry 7"); +is(names[7], "item", "Enum entry 8"); +is(names[8], "length", "Enum entry 9"); + +names = Object.getOwnPropertyNames(x); +is(names.length, 10, "Should have 10 items"); +// Now sort entries 5 through 8, for comparison purposes. We don't sort the +// whole array, because we want to make sure the ordering between the parts +// is correct +temp = names.slice(5, 9); +temp.sort(); +names.splice.bind(names, 5, 4).apply(null, temp); +is(names.length, 10, "Should still have 10 items"); +is(names[0], "0", "Entry 1") +is(names[1], "1", "Entry 2") +is(names[2], "2", "Entry 3") +is(names[3], "3", "Entry 4") +is(names[4], "4", "Entry 5") +is(names[5], "w", "Entry 6") +is(names[6], "x", "Entry 7") +is(names[7], "y", "Entry 8") +is(names[8], "z", "Entry 9") +is(names[9], "something", "Entry 10") +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_fragment_form_pointer.html b/dom/html/test/test_fragment_form_pointer.html new file mode 100644 index 0000000000..ff40385455 --- /dev/null +++ b/dom/html/test/test_fragment_form_pointer.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=946585 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 946585</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=946585">Mozilla Bug 946585</a> +<p id="display"></p> +<div id="content" style="display: none"> +<form><div id="formdiv"></div></form> +</div> +<pre id="test"> +</pre> +<script type="application/javascript"> +/** Test for Bug 946585 **/ +var formDiv = document.getElementById("formdiv"); +formDiv.innerHTML = '<form>'; +is(formDiv.firstChild, null, "InnerHTML should not produce form element because the div has a form pointer."); +</script> +</body> +</html> diff --git a/dom/html/test/test_frame_count_with_synthetic_doc.html b/dom/html/test/test_frame_count_with_synthetic_doc.html new file mode 100644 index 0000000000..c282ed09d7 --- /dev/null +++ b/dom/html/test/test_frame_count_with_synthetic_doc.html @@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html> + <head> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> + </head> + <body> + <script> + SimpleTest.waitForExplicitFinish(); + function getWindowLength() { + setTimeout(function() { + if (window.length) { + ok(false, "Synthetic document shouldn't be exposed"); + } + + // Keep running this check until the test stops + getWindowLength(); + }); + } + + function addObject() { + const object = document.createElement("object"); + object.data = 'file_bug417760.png'; + document.body.appendChild(object); + + object.onload = function() { + ok(true, "Test passes"); + SimpleTest.finish(); + } + } + + getWindowLength(); + addObject(); + </script> + </body> +</html> diff --git a/dom/html/test/test_getElementsByName_after_mutation.html b/dom/html/test/test_getElementsByName_after_mutation.html new file mode 100644 index 0000000000..f88b8d579e --- /dev/null +++ b/dom/html/test/test_getElementsByName_after_mutation.html @@ -0,0 +1,51 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1376695 +--> +<head> + <title>Test for Bug 1376695</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1376695">Mozilla Bug 1376695</a> +<p id="display"></p> +<div id="originalFoo" name="foo"> +<pre id="test"> +<script type="application/javascript"> + +/** Test to ensure that the list returned by getElementsByName is updated after + * mutations. + **/ + +var fooList = document.getElementsByName("foo"); +var originalDiv = document.getElementById("originalFoo"); + +is(fooList.length, 1, "Should find one element with name 'foo' initially"); +is(fooList[0], originalDiv, "Element should be the original div"); + +var newTree = document.createElement("p"); +var child1 = document.createElement("div"); +var child2 = document.createElement("div"); +child2.setAttribute("name", "foo"); + +newTree.appendChild(child1); +newTree.appendChild(child2); +document.body.appendChild(newTree); + +is(fooList.length, 2, + "Should find two elements with name 'foo' after appending the new tree"); +is(fooList[1], child2, "Element should be the new appended div with name 'foo'"); + +document.body.removeChild(newTree); + +is(fooList.length, 1, + "Should find one element with name 'foo' after removing the new tree"); +is(fooList[0], originalDiv, + "Element should be the original div after removing the new tree"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_hidden.html b/dom/html/test/test_hidden.html new file mode 100644 index 0000000000..7b9d488c0e --- /dev/null +++ b/dom/html/test/test_hidden.html @@ -0,0 +1,52 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=567663 +--> +<head> + <title>Test for Bug 567663</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=567663">Mozilla Bug 567663</a> +<p id="display"></p> +<div id="content" style="display: none"> + <p></p> + <p hidden></p> +</div> +<pre id="test"> +<script> +/** Test for Bug 567663 **/ +var ps = document.getElementById("content").getElementsByTagName("p"); +is(ps[0].hidden, false, "First p's IDL attribute was wrong."); +is(ps[0].hasAttribute("hidden"), false, "First p had a content attribute."); +is(ps[1].hidden, true, "Second p's IDL attribute was wrong."); +is(ps[1].hasAttribute("hidden"), true, + "Second p didn't have a content attribute."); +is(ps[1].getAttribute("hidden"), "", + "Second p's content attribute was wrong."); + +ps[0].hidden = true; +is(ps[0].getAttribute("hidden"), "", + "Content attribute was set to an incorrect value."); +ps[1].hidden = false; +is(ps[1].hasAttribute("hidden"), false, + "Second p still had a content attribute."); + +ps[0].setAttribute("hidden", "banana"); +is(ps[0].hidden, true, "p's IDL attribute was wrong after setting."); +is(ps[0].getAttribute("hidden"), "banana", "Content attribute changed."); + +ps[0].setAttribute("hidden", "false"); +is(ps[0].hidden, true, "p's IDL attribute was wrong after setting."); +is(ps[0].getAttribute("hidden"), "false", "Content attribute changed."); + +ps[0].removeAttribute("hidden"); +is(ps[0].hidden, false, + "p's IDL attribute was wrong after removing the content attribute."); +is(ps[0].hasAttribute("hidden"), false); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_html_attributes_reflection.html b/dom/html/test/test_html_attributes_reflection.html new file mode 100644 index 0000000000..a3d6c63121 --- /dev/null +++ b/dom/html/test/test_html_attributes_reflection.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLHtmlElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLHtmlElement attributes reflection **/ + +// .version +reflectString({ + element: document.createElement("html"), + attribute: "version", +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_htmlcollection.html b/dom/html/test/test_htmlcollection.html new file mode 100644 index 0000000000..2d91189f6b --- /dev/null +++ b/dom/html/test/test_htmlcollection.html @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=772869 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 772869</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=772869">Mozilla Bug 772869</a> +<p id="display"></p> +<div id="content" style="display: none"> + <a class="foo" name="x"></a> + <span class="foo" id="y"></span> + <span class="foo" name="x"></span> + <form class="foo" name="z" id="w"></form> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 772869 **/ +var x = document.getElementsByClassName("foo"); +x.something = "another"; +var names = []; +for (var name in x) { + names.push(name); +} +is(names.length, 8, "Should have 8 enumerated names"); +is(names[0], "0", "Enum entry 1") +is(names[1], "1", "Enum entry 2") +is(names[2], "2", "Enum entry 3") +is(names[3], "3", "Enum entry 4") +is(names[4], "something", "Enum entry 5") +is(names[5], "item", "Enum entry 6") +is(names[6], "namedItem", "Enum entry 7") +is(names[7], "length", "Enum entry 8"); + +names = Object.getOwnPropertyNames(x); +is(names.length, 9, "Should have 9 items"); +is(names[0], "0", "Entry 1") +is(names[1], "1", "Entry 2") +is(names[2], "2", "Entry 3") +is(names[3], "3", "Entry 4") +is(names[4], "x", "Entry 5") +is(names[5], "y", "Entry 6") +is(names[6], "w", "Entry 7") +is(names[7], "z", "Entry 8") +is(names[8], "something", "Entry 9") +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_iframe_sandbox_general.html b/dom/html/test/test_iframe_sandbox_general.html new file mode 100644 index 0000000000..625b7aeeb2 --- /dev/null +++ b/dom/html/test/test_iframe_sandbox_general.html @@ -0,0 +1,283 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=341604 +Implement HTML5 sandbox attribute for IFRAMEs - general tests +--> +<head> + <meta charset="utf-8"> + <title>Tests for Bug 341604 and Bug 766282</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="application/javascript"> +/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs - general tests **/ + +SimpleTest.expectAssertions(0, 1); +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestCompleteLog(); + +// a postMessage handler that is used by sandboxed iframes without +// 'allow-same-origin' to communicate pass/fail back to this main page. +// it expects to be called with an object like {ok: true/false, desc: +// <description of the test> which it then forwards to ok() +window.addEventListener("message", receiveMessage); + +function receiveMessage(event) +{ + ok_wrapper(event.data.ok, event.data.desc); +} + +var completedTests = 0; +var passedTests = 0; + +function ok_wrapper(result, desc) { + ok(result, desc); + + completedTests++; + + if (result) { + passedTests++; + } + + if (completedTests == 32) { + is(passedTests, completedTests, "There are " + completedTests + " general tests that should pass"); + SimpleTest.finish(); + } +} + +function doTest() { + // passes twice if good + // 1) test that inline scripts (<script>) can run in an iframe sandboxed with "allow-scripts" + // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts') + + // passes twice if good + // 2) test that <script src=...> can run in an iframe sandboxed with "allow-scripts" + // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts') + + // passes twice if good + // 3) test that script in an event listener (body onload) can run in an iframe sandboxed with "allow-scripts" + // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts') + + // passes twice if good + // 4) test that script in an javascript:url can run in an iframe sandboxed with "allow-scripts" + // (done in file_iframe_sandbox_c_if1.html which has 'allow-scripts') + + // fails if bad + // 5) test that inline scripts cannot run in an iframe sandboxed without "allow-scripts" + // (done in file_iframe_sandbox_c_if2.html which has sandbox='') + + // fails if bad + // 6) test that <script src=...> cannot run in an iframe sandboxed without "allow-scripts" + // (done in file_iframe_sandbox_c_if2.html which has sandbox='') + + // fails if bad + // 7) test that script in an event listener (body onload) cannot run in an iframe sandboxed without "allow-scripts" + // (done in file_iframe_sandbox_c_if2.html which has sandbox='') + + // fails if bad + // 8) test that script in an event listener (img onerror) cannot run in an iframe sandboxed without "allow-scripts" + // (done in file_iframe_sandbox_c_if2.html which has sandbox='') + + // fails if bad + // 9) test that script in an javascript:url cannot run in an iframe sandboxed without "allow-scripts" + // (done in file_iframe_sandbox_c_if_5.html which has sandbox='allow-same-origin') + var if_w = document.getElementById('if_5').contentWindow; + sendMouseEvent({type:'click'}, 'a_link', if_w); + + // passes if good + // 10) test that a new iframe has sandbox attribute + var ifr = document.createElement("iframe"); + ok_wrapper("sandbox" in ifr, "a new iframe should have a sandbox attribute"); + + // passes if good + // 11) test that the sandbox attribute's default stringyfied value is an empty string + ok_wrapper(ifr.sandbox.length === 0 && ifr.sandbox == "", "default sandbox attribute should be an empty string"); + + // passes if good + // 12) test that a sandboxed iframe with 'allow-forms' can submit forms + // (done in file_iframe_sandbox_c_if3.html which has 'allow-forms' and 'allow-scripts') + + // fails if bad + // 13) test that a sandboxed iframe without 'allow-forms' can NOT submit forms + // (done in file_iframe_sandbox_c_if1.html which only has 'allow-scripts') + + // fails if bad + // 14) test that a sandboxed iframe can't open a new window using the target.attribute + // this is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin" + // the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok() + // function that calls window.parent.ok_wrapper + + // passes if good + // 15) test that a sandboxed iframe can't open a new window using window.open + // this is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin" + // the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok() + // function that calls window.parent.ok_wrapper + + // passes if good + // 16) test that a sandboxed iframe can't open a new window using window.ShowModalDialog + // this is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin" + // the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok() + // function that calls window.parent.ok_wrapper + + // passes twice if good + // 17) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute + // is separated with two spaces + // done via file_iframe_sandbox_c_if6.html which is sandboxed with " allow-scripts allow-same-origin " + + // passes twice if good + // 18) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute + // is separated with tabs + // done via file_iframe_sandbox_c_if6.html which is sandboxed with "	allow-scripts	allow-same-origin	" + + // passes twice if good + // 19) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute + // is separated with line feeds + // done via file_iframe_sandbox_c_if6.html which is sandboxed with "
allow-scripts
allow-same-origin
" + + // passes twice if good + // 20) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute + // is separated with form feeds + // done via file_iframe_sandbox_c_if6.html which is sandboxed with "allow-scriptsallow-same-origin" + + // passes twice if good + // 21) test that a sandboxed iframe can access same-origin documents and run scripts when its sandbox attribute + // is separated with carriage returns + // done via file_iframe_sandbox_c_if6.html which is sandboxed with "
allow-scripts
allow-same-origin
" + + // fails if bad + // 22) test that an iframe with sandbox="" does NOT have script in a src attribute created by a javascript: + // URL executed + // done by this page, see if_7 + + // passes if good + // 23) test that an iframe with sandbox="allow-scripts" DOES have script in a src attribute created by a javascript: + // URL executed + // done by this page, see if_8 + + // fails if bad + // 24) test that an iframe with sandbox="", starting out with a document already loaded, does NOT have script in a newly + // set src attribute created by a javascript: URL executed + // done by this page, see if_9 + + // passes if good + // 25) test that an iframe with sandbox="allow-scripts", starting out with a document already loaded, DOES have script + // in a newly set src attribute created by a javascript: URL executed + // done by this page, see if_10 + + // passes if good or fails if bad + // 26) test that an sandboxed document without 'allow-same-origin' can NOT access indexedDB + // done via file_iframe_sandbox_c_if7.html, which has sandbox='allow-scripts' + + // passes if good or fails if bad + // 27) test that an sandboxed document with 'allow-same-origin' can access indexedDB + // done via file_iframe_sandbox_c_if8.html, which has sandbox='allow-scripts allow-same-origin' + + // fails if bad + // 28) Test that a sandboxed iframe can't open a new window using the target.attribute for a + // non-existing browsing context (BC341604). + // This is done via file_iframe_sandbox_c_if4.html which is sandboxed with "allow-scripts" and "allow-same-origin" + // the window it attempts to open calls window.opener.ok(false, ...) and file_iframe_c_if4.html has an ok() + // function that calls window.parent.ok_wrapper. + + // passes twice if good + // 29-32) Test that sandboxFlagsAsString returns the set flags. + // see if_14 and if_15 + + // passes once if good + // 33) Test that sandboxFlagsAsString returns null if iframe does not have sandbox flag set. + // see if_16 +} + +addLoadEvent(doTest); + +var started_if_9 = false; +var started_if_10 = false; + +function start_if_9() { + if (started_if_9) + return; + + started_if_9 = true; + sendMouseEvent({type:'click'}, 'a_button'); +} + +function start_if_10() { + if (started_if_10) + return; + + started_if_10 = true; + sendMouseEvent({type:'click'}, 'a_button2'); +} + +function do_if_9() { + var if_9 = document.getElementById('if_9'); + if_9.src = 'javascript:"<html><script>window.parent.ok_wrapper(false, \'an iframe sandboxed without allow-scripts should not execute script in a javascript URL in a newly set src attribute\');<\/script><\/html>"'; +} + +function do_if_10() { + var if_10 = document.getElementById('if_10'); + if_10.src = 'javascript:"<html><script>window.parent.ok_wrapper(true, \'an iframe sandboxed with allow-scripts should execute script in a javascript URL in a newly set src attribute\');<\/script><\/html>"'; +} + +function eqFlags(a, b) { + // both a and b should be either null or have the array same flags + if (a === null && b === null) { return true; } + if (a === null || b === null) { return false; } + if (a.length !== b.length) { return false; } + var a_sorted = a.sort(); + var b_sorted = b.sort(); + for (var i in a_sorted) { + if (a_sorted[i] !== b_sorted[i]) { return false; } + } + return true; +} + +function getSandboxFlags(doc) { + var flags = doc.sandboxFlagsAsString; + if (flags === null) { return null; } + return flags? flags.split(" "):[]; +} + +function test_sandboxFlagsAsString(name, expected) { + var ifr = document.getElementById(name); + try { + var flags = getSandboxFlags(SpecialPowers.wrap(ifr).contentDocument); + ok_wrapper(eqFlags(flags, expected), name + ' expected: "' + expected + '", got: "' + flags + '"'); + } catch (e) { + ok_wrapper(false, name + ' expected "' + expected + ', but failed with ' + e); + } +} + +</script> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs +<p id="display"></p> +<div id="content"> +<iframe sandbox="allow-same-origin allow-scripts" id="if_1" src="file_iframe_sandbox_c_if1.html" height="10" width="10"></iframe> +<iframe sandbox="aLlOw-SAME-oRiGin ALLOW-sCrIpTs" id="if_1_case_insensitive" src="file_iframe_sandbox_c_if1.html" height="10" width="10"></iframe> +<iframe sandbox="" id="if_2" src="file_iframe_sandbox_c_if2.html" height="10" width="10"></iframe> +<iframe sandbox="allow-forms allow-scripts" id="if_3" src="file_iframe_sandbox_c_if3.html" height="10" width="10"></iframe> +<iframe sandbox="allow-same-origin allow-scripts" id="if_4" src="file_iframe_sandbox_c_if4.html" height="10" width="10"></iframe> +<iframe sandbox="allow-same-origin" id="if_5" src="file_iframe_sandbox_c_if5.html" height="10" width="10"></iframe> +<iframe sandbox=" allow-same-origin allow-scripts " id="if_6_a" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe> +<iframe sandbox="	allow-same-origin	allow-scripts	" id="if_6_b" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe> +<iframe sandbox="
allow-same-origin
allow-scripts
" id="if_6_c" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe> +<iframe sandbox="allow-same-originallow-scripts" id="if_6_d" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe> +<iframe sandbox="
allow-same-origin
allow-scripts
" id="if_6_e" src="file_iframe_sandbox_c_if6.html" height="10" width="10"></iframe> +<iframe sandbox="allow-same-origin" id='if_7' src="javascript:'<html><script>window.parent.ok_wrapper(false, \'an iframe sandboxed without allow-scripts should not execute script in a javascript URL in its src attribute\');<\/script><\/html>';" height="10" width="10"></iframe> +<iframe sandbox="allow-same-origin allow-scripts" id='if_8' src="javascript:'<html><script>window.parent.ok_wrapper(true, \'an iframe sandboxed without allow-scripts should execute script in a javascript URL in its src attribute\');<\/script><\/html>';" height="10" width="10"></iframe> +<iframe sandbox="allow-same-origin" onload='start_if_9()' id='if_9' src="about:blank" height="10" width="10"></iframe> +<iframe sandbox="allow-same-origin allow-scripts" onload='start_if_10()' id='if_10' src="about:blank" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts" id='if_11' src="file_iframe_sandbox_c_if7.html" height="10" width="10"></iframe> +<iframe sandbox="allow-same-origin allow-scripts" id='if_12' src="file_iframe_sandbox_c_if8.html" height="10" width="10"></iframe> +<iframe sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-top-navigation " id='if_13' src="file_iframe_sandbox_c_if9.html" height="10" width="10" onload='test_sandboxFlagsAsString("if_13",["allow-forms", "allow-pointer-lock", "allow-popups", "allow-same-origin", "allow-scripts", "allow-top-navigation"])'></iframe> +<iframe sandbox="	allow-same-origin	allow-scripts	" id="if_14" src="file_iframe_sandbox_c_if6.html" height="10" width="10" onload='test_sandboxFlagsAsString("if_14",["allow-same-origin","allow-scripts"])'></iframe> +<iframe sandbox="" id="if_15" src="file_iframe_sandbox_c_if9.html" height="10" width="10" onload='test_sandboxFlagsAsString("if_15",[])'></iframe> +<iframe id="if_16" src="file_iframe_sandbox_c_if9.html" height="10" width="10" onload='test_sandboxFlagsAsString("if_16",null)'></iframe> +<input type='button' id="a_button" onclick='do_if_9()'> +<input type='button' id="a_button2" onclick='do_if_10()'> +</div> +</body> +</html> diff --git a/dom/html/test/test_iframe_sandbox_inheritance.html b/dom/html/test/test_iframe_sandbox_inheritance.html new file mode 100644 index 0000000000..991e7ef78f --- /dev/null +++ b/dom/html/test/test_iframe_sandbox_inheritance.html @@ -0,0 +1,202 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=341604 +Implement HTML5 sandbox attribute for IFRAMEs - inheritance tests +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="application/javascript"> +/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/ +/** Inheritance Tests **/ + +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("untriaged"); + +// A postMessage handler that is used by sandboxed iframes without +// 'allow-same-origin' to communicate pass/fail back to this main page. +// It expects to be called with an object like {ok: true/false, desc: +// <description of the test> which it then forwards to ok(). +window.addEventListener("message", receiveMessage); + +function receiveMessage(event) { + switch (event.data.type) { + case "attempted": + testAttempted(); + break; + case "ok": + ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted); + break; + default: + // allow for old style message + if (event.data.ok != undefined) { + ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted); + } + } +} + +var attemptedTests = 0; +var passedTests = 0; +var totalTestsToPass = 15; +var totalTestsToAttempt = 19; + +function ok_wrapper(result, desc, addToAttempted = true) { + ok(result, desc); + + if (result) { + passedTests++; + } + + if (addToAttempted) { + testAttempted(); + } +} + +// Added so that tests that don't register unless they fail, +// can at least notify that they've attempted to run. +function testAttempted() { + attemptedTests++; + if (attemptedTests == totalTestsToAttempt) { + // Make sure all tests have had a chance to complete. + setTimeout(function() {finish();}, 1000); + } +} + +var finishCalled = false; + +function finish() { + if (!finishCalled) { + finishCalled = true; + is(passedTests, totalTestsToPass, "There are " + totalTestsToPass + " inheritance tests that should pass"); + + SimpleTest.finish(); + } +} + +function doTest() { + // fails if bad + // 1) an iframe with no sandbox attribute inside an iframe that has sandbox = "" + // should not be able to execute scripts (cannot ever loosen permissions) + // (done by file_iframe_sandbox_a_if2.html contained within file_iframe_sandbox_a_if1.html) + testAttempted(); + + // fails if bad + // 2) an iframe with sandbox = "allow-scripts" inside an iframe that has sandbox = "" + // should not be able to execute scripts (cannot ever loosen permissions) + // (done by file_iframe_sandbox_a_if2.html contained within file_iframe_sandbox_a_if1.html) + testAttempted(); + + // passes if good and fails if bad + // 3) an iframe with no sandbox attribute inside an iframe that has sandbox = "allow-scripts" + // should not be same origin with the top window + // (done by file_iframe_sandbox_a_if4.html contained within file_iframe_sandbox_a_if3.html) + + // passes if good and fails if bad + // 4) an iframe with no sandbox attribute inside an iframe that has sandbox = "allow-scripts" + // should not be same origin with its parent + // (done by file_iframe_sandbox_a_if4.html contained within file_iframe_sandbox_a_if3.html) + + // passes if good + // 5) an iframe with 'allow-same-origin' and 'allow-scripts' inside an iframe with 'allow-same-origin' + // and 'allow-scripts' should be same origin with the top window + // (done by file_iframe_sandbox_a_if6.html contained within file_iframe_sandbox_a_if5.html) + + // passes if good + // 6) an iframe with 'allow-same-origin' and 'allow-scripts' inside an iframe with 'allow-same-origin' + // and 'allow-scripts' should be same origin with its parent + // (done by file_iframe_sandbox_a_if6.html contained within file_iframe_sandbox_a_if5.html) + + // passes if good + // 7) an iframe with no sandbox attribute inside an iframe that has sandbox = "allow-scripts" + // should be able to execute scripts + // (done by file_iframe_sandbox_a_if7.html contained within file_iframe_sandbox_a_if3.html) + + // fails if bad + // 8) an iframe with sandbox="" inside an iframe that has allow-scripts should not be able + // to execute scripts + // (done by file_iframe_sandbox_a_if2.html contained within file_iframe_sandbox_a_if3.html) + testAttempted(); + + // passes if good + // 9) make sure that changing the sandbox flags on an iframe (if_8) doesn't affect + // the sandboxing of subloads of content within that iframe + var if_8 = document.getElementById('if_8'); + if_8.sandbox = 'allow-scripts'; + if_8.contentWindow.doSubload(); + + // passes if good + // 10) a <frame> inside an <iframe> sandboxed with 'allow-scripts' should not be same + // origin with this document + // done by file_iframe_sandbox_a_if11.html which is contained with file_iframe_sandbox_a_if10.html + + // passes if good + // 11) a <frame> inside a <frame> inside an <iframe> sandboxed with 'allow-scripts' should not be same + // origin with its parent frame or this document + // done by file_iframe_sandbox_a_if12.html which is contained with file_iframe_sandbox_a_if11.html + + // passes if good, fails if bad + // 12) An <object> inside an <iframe> sandboxed with 'allow-scripts' should not be same + // origin with this document + // Done by file_iframe_sandbox_a_if14.html which is contained within file_iframe_sandbox_a_if13.html + + // passes if good, fails if bad + // 13) An <object> inside an <object> inside an <iframe> sandboxed with 'allow-scripts' should not be same + // origin with its parent frame or this document + // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if14.html + + // passes if good, fails if bad + // 14) An <object> inside a <frame> inside an <iframe> sandboxed with 'allow-scripts' should not be same + // origin with its parent frame or this document + // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if16.html + // which is contained within file_iframe_sandbox_a_if10.html + + // passes if good + // 15) An <object> inside an <object> inside an <iframe> sandboxed with 'allow-scripts allow-forms' + // should be able to submit forms. + // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if14.html + + // passes if good + // 16) An <object> inside a <frame> inside an <iframe> sandboxed with 'allow-scripts allow-forms' + // should be able to submit forms. + // Done by file_iframe_sandbox_a_if15.html which is contained within file_iframe_sandbox_a_if16.html + // which is contained within file_iframe_sandbox_a_if10.html + + // fails if bad + // 17) An <object> inside an <iframe> sandboxed with 'allow-same-origin' + // should not be able to run scripts. + // Done by iframe "if_no_scripts", which loads file_iframe_sandbox_srcdoc_no_allow_scripts.html. + testAttempted(); + + // passes if good + // 18) An <object> inside an <iframe> sandboxed with 'allow-scripts allow-same-origin' + // should be able to run scripts and be same origin with this document. + // Done by iframe "if_scripts", which loads file_iframe_sandbox_srcdoc_allow_scripts.html. + + // passes if good, fails if bad + // 19) Make sure that the parent's document's sandboxing flags are copied when + // changing the sandbox flags on an iframe inside an iframe. + // Done in file_iframe_sandbox_a_if17.html and file_iframe_sandbox_a_if18.html +} + +addLoadEvent(doTest); +</script> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs +<p id="display"></p> +<div id="content"> +<iframe sandbox="" id="if_1" src="file_iframe_sandbox_a_if1.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts" id="if_3" src="file_iframe_sandbox_a_if3.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts allow-same-origin" id="if_5" src="file_iframe_sandbox_a_if5.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts allow-same-origin" id="if_8" src="file_iframe_sandbox_a_if8.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts allow-forms" id="if_10" src="file_iframe_sandbox_a_if10.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts allow-forms" id="if_13" src="file_iframe_sandbox_a_if13.html" height="10" width="10"></iframe> +<iframe sandbox="allow-same-origin" id="if_no_scripts" srcdoc="<object data='file_iframe_sandbox_srcdoc_no_allow_scripts.html'></object>" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts allow-same-origin" id="if_scripts" srcdoc="<object data='file_iframe_sandbox_srcdoc_allow_scripts.html'></object>" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts" id="if_17" src="file_iframe_sandbox_a_if17.html" height="10" width="10"></iframe> +</div> +</body> +</html> diff --git a/dom/html/test/test_iframe_sandbox_navigation.html b/dom/html/test/test_iframe_sandbox_navigation.html new file mode 100644 index 0000000000..caaf4439b8 --- /dev/null +++ b/dom/html/test/test_iframe_sandbox_navigation.html @@ -0,0 +1,285 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=341604 +Implement HTML5 sandbox attribute for IFRAMEs +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604 - navigation</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="application/javascript"> +/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/ +/** Navigation tests Part 1**/ + +SimpleTest.requestLongerTimeout(2); // slow on Android +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("untriaged"); +// a postMessage handler that is used by sandboxed iframes without +// 'allow-same-origin'/other windows to communicate pass/fail back to this main page. +// it expects to be called with an object like {ok: true/false, desc: +// <description of the test> which it then forwards to ok() +var bc = new BroadcastChannel("test_iframe_sandbox_navigation"); +bc.addEventListener("message", receiveMessage); +window.addEventListener("message", receiveMessage); + +var testPassesReceived = 0; + +function receiveMessage(event) { + switch (event.data.type) { + case "attempted": + testAttempted(); + break; + case "ok": + ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted); + break; + case "if_10": + doIf10TestPart2(); + break; + default: + // allow for old style message + if (event.data.ok != undefined) { + ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted); + } + } +} + +// Open windows for tests to attempt to navigate later. +var windowsToClose = new Array(); + +var attemptedTests = 0; +var passedTests = 0; +var totalTestsToPass = 7; +var totalTestsToAttempt = 13; + +function ok_wrapper(result, desc, addToAttempted = true) { + ok(result, desc); + + if (result) { + passedTests++; + } + + if (addToAttempted) { + testAttempted(); + } +} + +// Added so that tests that don't register unless they fail, +// can at least notify that they've attempted to run. +function testAttempted() { + attemptedTests++; + if (attemptedTests == totalTestsToAttempt) { + // Make sure all tests have had a chance to complete. + setTimeout(function() {finish();}, 1000); + } +} + +var finishCalled = false; + +function finish() { + if (!finishCalled) { + finishCalled = true; + is(passedTests, totalTestsToPass, "There are " + totalTestsToPass + " navigation tests that should pass"); + + closeWindows(); + + bc.close(); + + SimpleTest.finish(); + } +} + +function checkTestsFinished() { + // If our own finish() has not been called, probably failed due to a timeout, so close remaining windows. + if (!finishCalled) { + closeWindows(); + } +} + +function closeWindows() { + for (var i = 0; i < windowsToClose.length; i++) { + windowsToClose[i].close(); + } +} + +function doTest() { + // passes if good + // 1) A sandboxed iframe is allowed to navigate itself + // (done by file_iframe_sandbox_d_if1.html which has 'allow-scripts' and navigates to + // file_iframe_sandbox_navigation_pass.html). + + // passes if good + // 2) A sandboxed iframe is allowed to navigate its children, even if they are sandboxed + // (done by file_iframe_sandbox_d_if2.html which has 'allow-scripts', it navigates a child + // iframe containing file_iframe_sandbox_navigation_start.html to file_iframe_sandbox_navigation_pass.html). + + // fails if bad + // 3) A sandboxed iframe is not allowed to navigate its ancestor + // (done by file_iframe_sandbox_d_if4.html contained within file_iframe_sandbox_d_if3.html, + // it attempts to navigate file_iframe_sandbox_d_if3.html to file_iframe_sandbox_navigation_fail.html). + + // fails if bad + // 4) A sandboxed iframe is not allowed to navigate its sibling + // (done by file_iframe_sandbox_d_if5.html which has 'allow scripts allow-same-origin' + // and attempts to navigate file_iframe_navigation_start.html contained in if_sibling on this + // page to file_iframe_sandbox_navigation_fail.html). + + // passes if good, fails if bad + // 5) When a link is clicked in a sandboxed iframe, the document navigated to is sandboxed + // the same as the original document and is not same origin with parent document + // (done by file_iframe_sandbox_d_if6.html which simulates a link click and navigates + // to file_iframe_sandbox_d_if7.html which attempts to call back into its parent). + + // fails if bad + // 6) An iframe (if_8) has sandbox="allow-same-origin allow-scripts", the sandboxed document + // (file_iframe_sandbox_d_if_8.html) that it contains accesses its parent (this file) and removes + // 'allow-same-origin' and then triggers a reload. + // The document should not be able to access its parent (this file). + + // fails if bad + // 7) An iframe (if_9) has sandbox="allow-same-origin allow-scripts", the sandboxed document + // (file_iframe_sandbox_d_if_9.html) that it contains accesses its parent (this file) and removes + // 'allow-scripts' and then triggers a reload. + // The document should not be able to run a script and access its parent (this file). + + // passes if good + // 8) a document in an iframe with sandbox='allow-scripts' should have a different null + // principal in its original document than a document to which it navigates itself + // file_iframe_sandbox_d_if_10.html does this, co-ordinating with this page via postMessage + + // passes if good + // 9) a document (file_iframe_sandbox_d_if11.html in an iframe (if_11) with sandbox='allow-scripts' + // is navigated to file_iframe_sandbox_d_if12.html - when that document loads + // a message is sent back to this document, which adds 'allow-same-origin' to if_11 and then + // calls .back on it - file_iframe_sandbox_if12.html should be able to call back into this + // document - this is all contained in file_iframe_sandbox_d_if13.html which is opened in another + // tab so it has its own isolated session history + window.open("file_iframe_sandbox_d_if13.html"); + + // open up the top navigation tests + + // fails if bad + // 10) iframe with sandbox='allow-scripts' can NOT navigate top + // file_iframe_sandbox_e_if1.html contains file_iframe_sandbox_e_if6.html which + // attempts to navigate top + windowsToClose.push(window.open("file_iframe_sandbox_e_if1.html")); + + // fails if bad + // 11) iframe with sandbox='allow-scripts' nested inside iframe with + // 'allow-top-navigation allow-scripts' can NOT navigate top + // file_iframe_sandbox_e_if2.html contains file_iframe_sandbox_e_if1.html which + // contains file_iframe_sandbox_e_if6.html which attempts to navigate top + windowsToClose.push(window.open("file_iframe_sandbox_e_if2.html")); + + // passes if good + // 12) iframe with sandbox='allow-top-navigation allow-scripts' can navigate top + // file_iframe_sandbox_e_if3.html contains file_iframe_sandbox_e_if5.html which navigates top + window.open("file_iframe_sandbox_e_if3.html"); + + // passes if good + // 13) iframe with sandbox='allow-top-navigation allow-scripts' nested inside an iframe with + // 'allow-top-navigation allow-scripts' can navigate top + // file_iframe_sandbox_e_if4.html contains file_iframe_sandbox_e_if3.html which contains + // file_iframe_sandbox_e_if5.html which navigates top + window.open("file_iframe_sandbox_e_if4.html"); +} + +addLoadEvent(doTest); + +window.modified_if_8 = false; + +function reload_if_8() { + var if_8 = document.getElementById('if_8'); + if_8.src = 'file_iframe_sandbox_d_if8.html'; +} + +function modify_if_8() { + // If this is the second time this has been called + // that's a failed test (allow-same-origin was removed + // the first time). + if (window.modified_if_8) { + ok_wrapper(false, "a sandboxed iframe from which 'allow-same-origin' was removed should not be able to access its parent"); + + // need to return here since we end up in an infinite loop otherwise + return; + } + + var if_8 = document.getElementById('if_8'); + window.modified_if_8 = true; + + if_8.sandbox = 'allow-scripts'; + testAttempted(); + sendMouseEvent({type:'click'}, 'a_button'); +} + +window.modified_if_9 = false; + +function reload_if_9() { + var if_9 = document.getElementById('if_9'); + if_9.src = 'file_iframe_sandbox_d_if9.html'; +} + +function modify_if_9() { + // If this is the second time this has been called + // that's a failed test (allow-scripts was removed + // the first time). + if (window.modified_if_9) { + ok_wrapper(false, "an sandboxed iframe from which 'allow-scripts' should be removed should not be able to access its parent via a script", false); + + // need to return here since we end up in an infinite loop otherwise + return; + } + + var if_9 = document.getElementById('if_9'); + window.modified_if_9 = true; + + if_9.sandbox = 'allow-same-origin'; + + testAttempted(); + sendMouseEvent({type:'click'}, 'a_button2'); +} + +var firstPrincipal = ""; +var secondPrincipal; + +function doIf10TestPart1() { + if (firstPrincipal != "") + return; + + // use SpecialPowers to get the principal of if_10. + // NB: We stringify here and below because special-powers wrapping doesn't + // preserve identity. + var if_10 = document.getElementById('if_10'); + firstPrincipal = SpecialPowers.wrap(if_10).contentDocument.nodePrincipal.origin; + if_10.src = 'file_iframe_sandbox_d_if10.html'; +} + +function doIf10TestPart2() { + var if_10 = document.getElementById('if_10'); + // use SpecialPowers to get the principal of if_10 + secondPrincipal = SpecialPowers.wrap(if_10).contentDocument.nodePrincipal.origin; + ok_wrapper(firstPrincipal != secondPrincipal, "documents should NOT have the same principal if they are sandboxed without" + + " allow-same-origin and the first document is navigated to the second"); +} +</script> +<body onunload="checkTestsFinished()"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs +<p id="display"></p> +<div id="content"> +<iframe sandbox="allow-scripts" id="if_1" src="file_iframe_sandbox_d_if1.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts" id="if_2" src="file_iframe_sandbox_d_if2.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts" id="if_3" src="file_iframe_sandbox_d_if3.html" height="10" width="10"></iframe> +<iframe id="if_sibling" name="if_sibling" src="about:blank" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts allow-same-origin" id="if_5" src="file_iframe_sandbox_d_if5.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts" id="if_6" src="file_iframe_sandbox_d_if6.html" height="10" width="10"></iframe> +<iframe sandbox="allow-same-origin allow-scripts" id="if_8" src="file_iframe_sandbox_d_if8.html" height="10" width="10"></iframe> +<iframe sandbox="allow-same-origin allow-scripts" id="if_9" src="file_iframe_sandbox_d_if9.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts" id="if_10" src="file_iframe_sandbox_navigation_start.html" onload='doIf10TestPart1()' height="10" width="10"></iframe> +</div> +<input type='button' id="a_button" onclick='reload_if_8()'> +<input type='button' id="a_button2" onclick='reload_if_9()'> +</body> +</html> diff --git a/dom/html/test/test_iframe_sandbox_navigation2.html b/dom/html/test/test_iframe_sandbox_navigation2.html new file mode 100644 index 0000000000..f17c23a458 --- /dev/null +++ b/dom/html/test/test_iframe_sandbox_navigation2.html @@ -0,0 +1,216 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=341604 +Implement HTML5 sandbox attribute for IFRAMEs +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604 - navigation</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="application/javascript"> +/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/ +/** Navigation tests Part 2**/ + +SimpleTest.expectAssertions(0); +SimpleTest.requestLongerTimeout(2); // slow on Android +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("untriaged"); +// a postMessage handler that is used by sandboxed iframes without +// 'allow-same-origin'/other windows to communicate pass/fail back to this main page. +// it expects to be called with an object like {ok: true/false, desc: +// <description of the test> which it then forwards to ok() +var bc = new BroadcastChannel("test_iframe_sandbox_navigation"); +bc.addEventListener("message", receiveMessage); +window.addEventListener("message", receiveMessage); + +var testPassesReceived = 0; + +function receiveMessage(event) { + switch (event.data.type) { + case "attempted": + testAttempted(); + break; + case "ok": + ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted); + break; + default: + // allow for old style message + if (event.data.ok != undefined) { + ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted); + } + } +} + +// Open windows for tests to attempt to navigate later. +var windowsToClose = new Array(); +windowsToClose.push(window.open("about:blank", "window_to_navigate")); +windowsToClose.push(window.open("about:blank", "window_to_navigate2")); +var iframesWithWindowsToClose = new Array(); + +var attemptedTests = 0; +var passedTests = 0; +var totalTestsToPass = 12; +var totalTestsToAttempt = 15; + +function ok_wrapper(result, desc, addToAttempted = true) { + ok(result, desc); + + if (result) { + passedTests++; + } + + if (addToAttempted) { + testAttempted(); + } +} + +// Added so that tests that don't register unless they fail, +// can at least notify that they've attempted to run. +function testAttempted() { + attemptedTests++; + if (attemptedTests == totalTestsToAttempt) { + // Make sure all tests have had a chance to complete. + setTimeout(function() {finish();}, 1000); + } +} + +var finishCalled = false; + +function finish() { + if (!finishCalled) { + finishCalled = true; + is(passedTests, totalTestsToPass, "There are " + totalTestsToPass + " navigation tests that should pass"); + + for (var i = 0; i < windowsToClose.length; i++) { + windowsToClose[i].close(); + } + + bc.close(); + + SimpleTest.finish(); + } +} + +function checkTestsFinished() { + // If our own finish() has not been called, probably failed due to a timeout, so close remaining windows. + if (!finishCalled) { + for (var i = 0; i < windowsToClose.length; i++) { + windowsToClose[i].close(); + } + } +} + +function doTest() { + // fails if bad + // 14) iframe with sandbox='allow-same-origin allow-scripts allow-top-navigation' should not + // be able to navigate another window (opened by another browsing context) using its name. + // file_iframe_sandbox_d_if14.html in if_14 attempts to navigate "window_to_navigate", + // which has been opened in preparation. + + // fails if bad + // 15) iframe with sandbox='allow-scripts' should not be able to navigate top using its + // real name (instead of _top) as allow-top-navigation is not specified. + // file_iframe_sandbox_e_if7.html contains file_iframe_sandbox_e_if8.html, which + // attempts to navigate top by name. + windowsToClose.push(window.open("file_iframe_sandbox_e_if7.html")); + + // fails if bad + // 16) iframe with sandbox='allow-same-origin allow-scripts allow-top-navigation' should not + // be able to use its parent's name (instead of _parent) to navigate it, when it is not top. + // (Note: this would apply to other ancestors that are not top as well.) + // file_iframe_sandbox_d_if15.html in if_15 contains file_iframe_sandbox_d_if16.html, which + // tries to navigate if_15 by its name (if_parent). + + // passes if good, fails if bad + // 17) A sandboxed iframe is allowed to navigate itself using window.open(). + // (Done by file_iframe_sandbox_d_if17.html which has 'allow-scripts' and navigates to + // file_iframe_sandbox_navigation_pass.html). + + // passes if good, fails if bad + // 18) A sandboxed iframe is allowed to navigate its children with window.open(), even if + // they are sandboxed. (Done by file_iframe_sandbox_d_if18.html which has 'allow-scripts', + // it navigates a child iframe to file_iframe_sandbox_navigation_pass.html). + + // passes if good, fails if bad + // 19) A sandboxed iframe is not allowed to navigate its ancestor with window.open(). + // (Done by file_iframe_sandbox_d_if20.html contained within file_iframe_sandbox_d_if19.html, + // it attempts to navigate file_iframe_sandbox_d_if19.html to file_iframe_sandbox_navigation_fail.html). + + // passes if good, fails if bad + // 20) iframe with sandbox='allow-same-origin allow-scripts allow-top-navigation' should not + // be able to navigate another window (opened by another browsing context) using window.open(..., "<name>"). + // file_iframe_sandbox_d_if14.html in if_14 attempts to navigate "window_to_navigate2", + // which has been opened in preparation, using window.open(..., "window_to_navigate2"). + + // passes if good, fails if bad + // 21) iframe with sandbox='allow-same-origin allow-scripts allow-top-navigation' should not + // be able to use its parent's name (not _parent) to navigate it using window.open(), when it is not top. + // (Note: this would apply to other ancestors that are not top as well.) + // file_iframe_sandbox_d_if21.html in if_21 contains file_iframe_sandbox_d_if22.html, which + // tries to navigate if_21 by its name (if_parent2). + + // passes if good, fails if bad + // 22) iframe with sandbox='allow-top-navigation allow-scripts' can navigate top with window.open(). + // file_iframe_sandbox_e_if9.html contains file_iframe_sandbox_e_if11.html which navigates top. + window.open("file_iframe_sandbox_e_if9.html"); + + // passes if good, fails if bad + // 23) iframe with sandbox='allow-top-navigation allow-scripts' nested inside an iframe with + // 'allow-top-navigation allow-scripts' can navigate top, with window.open(). + // file_iframe_sandbox_e_if10.html contains file_iframe_sandbox_e_if9.html which contains + // file_iframe_sandbox_e_if11.html which navigates top. + window.open("file_iframe_sandbox_e_if10.html"); + + // passes if good, fails if bad + // 24) iframe with sandbox='allow-scripts' can NOT navigate top with window.open(). + // file_iframe_sandbox_e_if12.html contains file_iframe_sandbox_e_if14.html which navigates top. + window.open("file_iframe_sandbox_e_if12.html"); + + // passes if good, fails if bad + // 25) iframe with sandbox='allow-scripts' nested inside an iframe with + // 'allow-top-navigation allow-scripts' can NOT navigate top, with window.open(..., "_top"). + // file_iframe_sandbox_e_if13.html contains file_iframe_sandbox_e_if12.html which contains + // file_iframe_sandbox_e_if14.html which navigates top. + window.open("file_iframe_sandbox_e_if13.html"); + + // passes if good, fails if bad + // 26) iframe with sandbox='allow-scripts' should not be able to navigate top using its real name + // (not with _top e.g. window.open(..., "topname")) as allow-top-navigation is not specified. + // file_iframe_sandbox_e_if15.html contains file_iframe_sandbox_e_if16.html, which + // attempts to navigate top by name using window.open(). + window.open("file_iframe_sandbox_e_if15.html"); + + // passes if good + // 27) iframe with sandbox='allow-scripts allow-popups' should be able to + // navigate a window, that it has opened, using it's name. + // file_iframe_sandbox_d_if23.html in if_23 opens a window and then attempts + // to navigate it using it's name in the target of an anchor. + iframesWithWindowsToClose.push("if_23"); + + // passes if good, fails if bad + // 28) iframe with sandbox='allow-scripts allow-popups' should be able to + // navigate a window, that it has opened, using window.open(..., "<name>"). + // file_iframe_sandbox_d_if23.html in if_23 opens a window and then attempts + // to navigate it using it's name in the target of window.open(). +} + +addLoadEvent(doTest); +</script> +<body onunload="checkTestsFinished()"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs +<p id="display"></p> +<div id="content"> +<iframe sandbox="allow-same-origin allow-scripts allow-top-navigation" id="if_14" src="file_iframe_sandbox_d_if14.html" height="10" width="10"></iframe> +<iframe id="if_15" name="if_parent" src="file_iframe_sandbox_d_if15.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts" id="if_17" src="file_iframe_sandbox_d_if17.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts" id="if_18" src="file_iframe_sandbox_d_if18.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts" id="if_19" src="file_iframe_sandbox_d_if19.html" height="10" width="10"></iframe> +<iframe id="if_21" name="if_parent2" src="file_iframe_sandbox_d_if21.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts allow-popups" id="if_23" src="file_iframe_sandbox_d_if23.html" height="10" width="10"></iframe> +</div> +</body> +</html> diff --git a/dom/html/test/test_iframe_sandbox_popups.html b/dom/html/test/test_iframe_sandbox_popups.html new file mode 100644 index 0000000000..c05b1fc67f --- /dev/null +++ b/dom/html/test/test_iframe_sandbox_popups.html @@ -0,0 +1,78 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=766282 +implement allow-popups directive for iframe sandbox +--> +<head> + <meta charset="utf-8"> + <title>Tests for Bug 766282</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); + +// a postMessage handler that is used by sandboxed iframes without +// 'allow-same-origin' to communicate pass/fail back to this main page. +// it expects to be called with an object like {ok: true/false, desc: +// <description of the test> which it then forwards to ok() +window.addEventListener("message", receiveMessage); + +function receiveMessage(event) +{ + ok_wrapper(event.data.ok, event.data.desc); +} + +var completedTests = 0; +var passedTests = 0; + +function ok_wrapper(result, desc) { + ok(result, desc); + + completedTests++; + + if (result) { + passedTests++; + } + + if (completedTests == 3) { + is(passedTests, completedTests, "There are " + completedTests + " popups tests that should pass"); + SimpleTest.finish(); + } +} + +function doTest() { + // passes if good + // 1) Test that a sandboxed iframe with "allow-popups" can open a new window using the target.attribute. + // This is done via file_iframe_sandbox_h_if1.html which is sandboxed with "allow-popups allow-scripts allow-same-origin". + // The window it attempts to open calls window.opener.ok(true, ...) and file_iframe_h_if1.html has an ok() + // function that calls window.parent.ok_wrapper. + + // passes if good + // 2) Test that a sandboxed iframe with "allow-popups" can open a new window using window.open. + // This is done via file_iframe_sandbox_h_if1.html which is sandboxed with "allow-popups allow-scripts allow-same-origin". + // The window it attempts to open calls window.opener.ok(true, ...) and file_iframe_h_if1.html has an ok() + // function that calls window.parent.ok_wrapper. + + // passes if good, fails if bad + // 3) Test that a sandboxed iframe with "allow-popups" can open a new window using the target.attribute + // for a non-existing browsing context (BC766282). + // This is done via file_iframe_sandbox_h_if1.html which is sandboxed with "allow-popups allow-scripts allow-same-origin". + // The window it attempts to open calls window.opener.ok(true, ...) and file_iframe_h_if1.html has an ok() + // function that calls window.parent.ok_wrapper. +} + +addLoadEvent(doTest); + +</script> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=766282">Mozilla Bug 766282</a> - implement allow-popups directive for iframe sandbox +<p id="display"></p> +<div id="content"> +<iframe sandbox="allow-popups allow-same-origin allow-scripts" id="if1" src="file_iframe_sandbox_h_if1.html" height="10" width="10"></iframe> +</div> +</body> +</html> diff --git a/dom/html/test/test_iframe_sandbox_popups_inheritance.html b/dom/html/test/test_iframe_sandbox_popups_inheritance.html new file mode 100644 index 0000000000..af4a03932e --- /dev/null +++ b/dom/html/test/test_iframe_sandbox_popups_inheritance.html @@ -0,0 +1,157 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=766282 +Implement HTML5 sandbox allow-popuos directive for IFRAMEs - inheritance tests +--> +<head> + <meta charset="utf-8"> + <title>Tests for Bug 766282</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> + +<script type="application/javascript"> + +SimpleTest.expectAssertions(0, 5); +SimpleTest.waitForExplicitFinish(); +SimpleTest.requestFlakyTimeout("untriaged"); + +// A postMessage handler that is used by sandboxed iframes without +// 'allow-same-origin' to communicate pass/fail back to this main page. +window.addEventListener("message", receiveMessage); + +function receiveMessage(event) { + switch (event.data.type) { + case "attempted": + testAttempted(); + break; + case "ok": + ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted); + break; + default: + // allow for old style message + if (event.data.ok != undefined) { + ok_wrapper(event.data.ok, event.data.desc, event.data.addToAttempted); + } + } +} + +var iframesWithWindowsToClose = new Array(); + +var attemptedTests = 0; +var passedTests = 0; +var totalTestsToPass = 15; +var totalTestsToAttempt = 21; + +function ok_wrapper(result, desc, addToAttempted = true) { + ok(result, desc); + + if (result) { + passedTests++; + } + + if (addToAttempted) { + testAttempted(); + } +} + +// Added so that tests that don't register unless they fail, +// can at least notify that they've attempted to run. +function testAttempted() { + attemptedTests++; + if (attemptedTests == totalTestsToAttempt) { + // Make sure all tests have had a chance to complete. + setTimeout(function() {finish();}, 1000); + } +} + +var finishCalled = false; + +function finish() { + if (!finishCalled) { + finishCalled = true; + is(passedTests, totalTestsToPass, "There are " + totalTestsToPass + " inheritance tests that should pass"); + + closeWindows(); + + SimpleTest.finish(); + } +} + +function checkTestsFinished() { + // If our own finish() has not been called, probably failed due to a timeout, so close remaining windows. + if (!finishCalled) { + closeWindows(); + } +} + +function closeWindows() { + for (var i = 0; i < iframesWithWindowsToClose.length; i++) { + document.getElementById(iframesWithWindowsToClose[i]).contentWindow.postMessage({type: "closeWindows"}, "*"); + } +} + +function doTest() { + // passes if good and fails if bad + // 1,2,3) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups + // allow-same-origin" should not have its origin sandbox flag set and be able to access document.cookie. + // (Done by file_iframe_sandbox_k_if5.html opened from file_iframe_sandbox_k_if4.html) + // This is repeated for 3 different ways of opening the window, + // see file_iframe_sandbox_k_if4.html for details. + + // passes if good + // 4,5,6) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups + // allow-top-navigation" should not have its top-level navigation sandbox flag set and be able to + // navigate top. (Done by file_iframe_sandbox_k_if5.html (and if6) opened from + // file_iframe_sandbox_k_if4.html). This is repeated for 3 different ways of opening the window, + // see file_iframe_sandbox_k_if4.html for details. + + // passes if good + // 7,8,9) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups + // all-forms" should not have its forms sandbox flag set and be able to submit forms. + // (Done by file_iframe_sandbox_k_if7.html opened from file_iframe_sandbox_k_if4.html) + // This is repeated for 3 different ways of opening the window, + // see file_iframe_sandbox_k_if4.html for details. + + // passes if good + // 10,11,12) Make sure that the sandbox flags copied to a new browsing context are taken from the + // current active document not the browsing context (iframe / docShell). + // This is done by removing allow-same-origin and calling doSubOpens from file_iframe_sandbox_k_if8.html, + // which opens file_iframe_sandbox_k_if9.html in 3 different ways. + // It then navigates to file_iframe_sandbox_k_if1.html to run tests 13 - 21 below. + var if_8_1 = document.getElementById('if_8_1'); + if_8_1.sandbox = 'allow-scripts allow-popups'; + if_8_1.contentWindow.doSubOpens(); + + // passes if good and fails if bad + // 13,14,15) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups" + // should have its origin sandbox flag set and not be able to access document.cookie. + // This is done by file_iframe_sandbox_k_if8.html navigating to file_iframe_sandbox_k_if1.html + // after allow-same-origin has been removed from iframe if_8_1. file_iframe_sandbox_k_if1.html + // opens file_iframe_sandbox_k_if2.html in 3 different ways to perform the tests. + iframesWithWindowsToClose.push("if_8_1"); + + // fails if bad + // 16,17,18) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups" + // should have its forms sandbox flag set and not be able to submit forms. + // This is done by file_iframe_sandbox_k_if2.html, see test 10 for details of how this is opened. + + // fails if bad + // 19,20,21) A window opened from inside an iframe that has sandbox = "allow-scripts allow-popups" + // should have its top-level navigation sandbox flag set and not be able to navigate top. + // This is done by file_iframe_sandbox_k_if2.html, see test 10 for details of how this is opened. +} + +addLoadEvent(doTest); +</script> + +<body onunload="checkTestsFinished()"> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=766282">Mozilla Bug 766282</a> - Implement HTML5 sandbox allow-popups directive for IFRAMEs +<p id="display"></p> +<div id="content"> +<iframe sandbox="allow-scripts allow-popups allow-same-origin allow-forms allow-top-navigation" id="if_4" src="file_iframe_sandbox_k_if4.html" height="10" width="10"></iframe> +<iframe sandbox="allow-scripts allow-popups allow-same-origin" id="if_8_1" src="file_iframe_sandbox_k_if8.html" height="10" width="10"></iframe> +</div> +</body> +</html> diff --git a/dom/html/test/test_iframe_sandbox_redirect.html b/dom/html/test/test_iframe_sandbox_redirect.html new file mode 100644 index 0000000000..ff13e52487 --- /dev/null +++ b/dom/html/test/test_iframe_sandbox_redirect.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=985135 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 985135</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 985135 **/ + SimpleTest.waitForExplicitFinish(); + addLoadEvent(function() { + try { + var doc = frames[0].document; + ok(false, "Should not be able to get the document"); + isnot(doc.body.textContent.slice(0, -1), "I have been redirected", + "Should not happen"); + SimpleTest.finish(); + } catch (e) { + // Check that we got the right document + window.onmessage = function(event) { + is(event.data, "who are you? redirect target", + "Should get the message we expect"); + SimpleTest.finish(); + } + + frames[0].postMessage("who are you?", "*"); + } + }); + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=985135">Mozilla Bug 985135</a> +<p id="display"></p> +<div id="content" style="display: none"> +<iframe src="file_iframe_sandbox_redirect.html" sandbox="allow-scripts"></iframe> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_iframe_sandbox_refresh.html b/dom/html/test/test_iframe_sandbox_refresh.html new file mode 100644 index 0000000000..81107fe3dc --- /dev/null +++ b/dom/html/test/test_iframe_sandbox_refresh.html @@ -0,0 +1,101 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1156059 +--> +<head> + <meta charset="utf-8"> + <title>Tests for Bug 1156059</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + // Tests for Bug 1156059 + // See ok messages in iframes for test cases. + + SimpleTest.waitForExplicitFinish(); + SimpleTest.requestFlakyTimeout("We cannot detect when the sandbox blocks the META REFRESH, so we need to allow a reasonable amount of time for them to fail."); + + var testCases = [ + { + desc: "Meta refresh without allow-scripts should be ignored.", + numberOfLoads: 0, + numberOfLoadsExpected: 1 + }, + { + desc: "Meta refresh check should be case insensitive.", + numberOfLoads: 0, + numberOfLoadsExpected: 1 + }, + { + desc: "Meta refresh with allow-scripts should work.", + numberOfLoads: 0, + numberOfLoadsExpected: 2 + }, + { + desc: "Refresh HTTP headers should not be affected by sandbox.", + numberOfLoads: 0, + numberOfLoadsExpected: 2 + } + ]; + + var totalLoads = 0; + var totalLoadsExpected = testCases.reduce(function(partialSum, testCase) { + return partialSum + testCase.numberOfLoadsExpected; + }, 0); + + function processLoad(testCaseIndex) { + testCases[testCaseIndex].numberOfLoads++; + + if (++totalLoads == totalLoadsExpected) { + // Give the tests that should block the refresh a bit of extra time to + // fail. The worst that could happen here is that we get a false pass. + window.setTimeout(processResults, 500); + } + } + + function processResults() { + testCases.forEach(function(testCase, index) { + var msg = "Test Case " + index + ": " + testCase.desc; + is(testCase.numberOfLoads, testCase.numberOfLoadsExpected, msg); + }); + + SimpleTest.finish(); + } + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1156059">Mozilla Bug 1156059</a> +<p id="display"></p> +<div id="content" style="display: none"> + +<iframe + onload="processLoad(0)" + srcdoc="<meta http-equiv='refresh' content='0; url=data:text/html,Refreshed'>" + sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-top-navigation" +></iframe> + +<iframe + onload="processLoad(1)" + srcdoc="<meta http-equiv='rEfReSh' content='0; url=data:text/html,Refreshed'>" + sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-top-navigation" +></iframe> + +<iframe + onload="processLoad(2)" + srcdoc="<meta http-equiv='refresh' content='0; url=data:text/html,Refreshed'>" + sandbox="allow-scripts" +></iframe> + +<iframe + onload="processLoad(3)" + src="file_iframe_sandbox_refresh.html" + sandbox +></iframe> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_iframe_sandbox_same_origin.html b/dom/html/test/test_iframe_sandbox_same_origin.html new file mode 100644 index 0000000000..b936453bbd --- /dev/null +++ b/dom/html/test/test_iframe_sandbox_same_origin.html @@ -0,0 +1,108 @@ +\<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=341604
+Implement HTML5 sandbox attribute for IFRAMEs - same origin tests
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 341604</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<script type="application/javascript">
+/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs **/
+/** Same Origin Tests **/
+
+SimpleTest.waitForExplicitFinish();
+
+var completedTests = 0;
+var passedTests = 0;
+
+function ok_wrapper(result, desc) {
+ ok(result, desc);
+
+ completedTests++;
+
+ if (result) {
+ passedTests++;
+ }
+
+ if (completedTests == 14) {
+ is(passedTests, completedTests, "There are " + completedTests + " same-origin tests that should pass");
+
+ SimpleTest.finish();
+ }
+}
+
+function receiveMessage(event)
+{
+ ok_wrapper(event.data.ok, event.data.desc);
+}
+
+// a postMessage handler that is used by sandboxed iframes without
+// 'allow-same-origin' to communicate pass/fail back to this main page.
+// it expects to be called with an object like {ok: true/false, desc:
+// <description of the test> which it then forwards to ok()
+window.addEventListener("message", receiveMessage);
+
+function doTest() {
+ // 1) test that we can't access an iframe sandboxed without "allow-same-origin"
+ var if_1 = document.getElementById("if_1");
+ try {
+ var b = if_1.contentDocument.body;
+ ok_wrapper(false, "accessing body of a sandboxed document should not be allowed");
+ } catch (err){
+ ok_wrapper(true, "accessing body of a sandboxed document should not be allowed");
+ }
+
+ // 2) test that we can access an iframe sandboxed with "allow-same-origin"
+ var if_2 = document.getElementById("if_2");
+
+ try {
+ var b = if_2.contentDocument.body;
+ ok_wrapper(true, "accessing body of a sandboxed document with allow-same-origin should be allowed");
+ } catch (err) {
+ ok_wrapper(false, "accessing body of a sandboxed document with allow-same-origin should be allowed");
+ }
+
+ // 3) test that a sandboxed iframe without 'allow-same-origin' cannot access its parent
+ // this is done by file_iframe_b_if3.html which has 'allow-scripts' but not 'allow-same-origin'
+
+ // 4) test that a sandboxed iframe with 'allow-same-origin' can access its parent
+ // this is done by file_iframe_b_if2.html which has 'allow-same-origin' and 'allow-scripts'
+
+ // 5) check that a sandboxed iframe with "allow-same-origin" can access document.cookie
+ // this is done by file_iframe_b_if2.html which has 'allow-same-origin' and 'allow-scripts'
+
+ // 6) check that a sandboxed iframe with "allow-same-origin" can access window.localStorage
+ // this is done by file_iframe_b_if2.html which has 'allow-same-origin' and 'allow-scripts'
+
+ // 7) check that a sandboxed iframe with "allow-same-origin" can access window.sessionStorage
+ // this is done by file_iframe_b_if2.html which has 'allow-same-origin' and 'allow-scripts'
+
+ // 8) check that a sandboxed iframe WITHOUT "allow-same-origin" can NOT access document.cookie
+ // this is done by file_iframe_b_if3.html which has 'allow-scripts' but not 'allow-same-origin'
+
+ // 9) check that a sandboxed iframe WITHOUT "allow-same-origin" can NOT access window.localStorage
+ // this is done by file_iframe_b_if3.html which has 'allow-scripts' but not 'allow-same-origin'
+
+ // 10) check that a sandboxed iframe WITHOUT "allow-same-origin" can NOT access window.sessionStorage
+ // this is done by file_iframe_b_if3.html which has 'allow-scripts' but not 'allow-same-origin'
+
+ // 11) check that XHR works normally in a sandboxed iframe with "allow-same-origin" and "allow-scripts"
+ // this is done by file_iframe_b_if2.html which has 'allow-same-origin' and 'allow-scripts'
+
+ // 12) check that XHR is blocked in a sandboxed iframe with "allow-scripts" but WITHOUT "allow-same-origin"
+ // this is done by file_iframe_b_if3.html which has 'allow-scripts' but not 'allow-same-origin'
+}
+addLoadEvent(doTest);
+</script>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs
+<p id="display"></p>
+<div id="content">
+<iframe sandbox="" id="if_1" src="file_iframe_sandbox_b_if1.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-same-origin allow-scripts" id="if_2" src="file_iframe_sandbox_b_if2.html" height="10" width="10"></iframe>
+<iframe sandbox="allow-scripts" id="if_3" src="file_iframe_sandbox_b_if3.html" height="10" width="10"></iframe>
+</div>
diff --git a/dom/html/test/test_iframe_sandbox_workers.html b/dom/html/test/test_iframe_sandbox_workers.html new file mode 100644 index 0000000000..c86f2ab528 --- /dev/null +++ b/dom/html/test/test_iframe_sandbox_workers.html @@ -0,0 +1,74 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=341604 +Implement HTML5 sandbox attribute for IFRAMEs - tests for workers +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 341604</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="application/javascript"> +/** Test for Bug 341604 - Implement HTML5 sandbox attribute for IFRAMEs - test for workers **/ + +SimpleTest.waitForExplicitFinish(); + +// a postMessage handler that is used by sandboxed iframes without +// 'allow-same-origin' to communicate pass/fail back to this main page. +// it expects to be called with an object like {ok: true/false, desc: +// <description of the test> which it then forwards to ok() +window.addEventListener("message", receiveMessage); + +function receiveMessage(event) +{ + ok_wrapper(event.data.ok, event.data.desc); +} + +var completedTests = 0; +var passedTests = 0; + +function ok_wrapper(result, desc) { + ok(result, desc); + + completedTests++; + + if (result) { + passedTests++; + } + + if (completedTests == 3) { + is(passedTests, 3, "There are 3 worker tests that should pass"); + SimpleTest.finish(); + } +} + +function doTest() { + // passes if good + // 1) test that a worker in a sandboxed iframe with 'allow-scripts' can be loaded + // from a data: URI + // (done by file_iframe_sandbox_g_if1.html) + + // passes if good + // 2) test that a worker in a sandboxed iframe with 'allow-scripts' can be loaded + // from a blob URI created by the sandboxed document itself + // (done by file_iframe_sandbox_g_if1.html) + + // passes if good + // 3) test that a worker in a sandboxed iframe with 'allow-scripts' without + // 'allow-same-origin' cannot load a script via a relative URI + // (done by file_iframe_sandbox_g_if1.html) +} + +addLoadEvent(doTest); +</script> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=341604">Mozilla Bug 341604</a> - Implement HTML5 sandbox attribute for IFRAMEs +<p id="display"></p> +<div id="content"> +<iframe sandbox="allow-scripts" id="if_1" src="file_iframe_sandbox_g_if1.html" height="10" width="10"></iframe> +</div> +</body> +</html> diff --git a/dom/html/test/test_imageSrcSet.html b/dom/html/test/test_imageSrcSet.html new file mode 100644 index 0000000000..695d1c2643 --- /dev/null +++ b/dom/html/test/test_imageSrcSet.html @@ -0,0 +1,38 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=980243 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 980243</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 980243 **/ + SimpleTest.waitForExplicitFinish(); + + addLoadEvent(function() { + var img = document.querySelector("img"); + img.onload = function() { + ok(true, "Reached here"); + SimpleTest.finish(); + } + // If ths spec ever changes to treat .src sets differently from + // setAttribute("src"), we'll need some sort of canonicalization step + // earlier to make the attr value an absolute URI. + img.setAttribute("src", img.getAttribute("src")); + }); + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=980243">Mozilla Bug 980243</a> +<p id="display"></p> +<div id="content" style="display: none"> + <img src="file_formSubmission_img.jpg"> +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_image_clone_load.html b/dom/html/test/test_image_clone_load.html new file mode 100644 index 0000000000..e808c80a53 --- /dev/null +++ b/dom/html/test/test_image_clone_load.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Test for image clones doing their load</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var t = async_test("The clone of an image should do the load of the same image, and do it synchronously"); +t.step(function() { + var img = new Image(); + img.onload = t.step_func(function() { + var clone = img.cloneNode(); + assert_not_equals(img.naturalWidth, 0, "Should have a width"); + assert_equals(clone.naturalWidth, img.naturalWidth, + "Clone should have a width too"); + // And make sure the clone fires onload too, which happens async. + clone.onload = function() { t.done() } + }); + img.src = "image.png"; +}); +</script> diff --git a/dom/html/test/test_img_attributes_reflection.html b/dom/html/test/test_img_attributes_reflection.html new file mode 100644 index 0000000000..b89b4cec05 --- /dev/null +++ b/dom/html/test/test_img_attributes_reflection.html @@ -0,0 +1,103 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLImageElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> +/** Test for HTMLImageElement attributes reflection **/ + +reflectString({ + element: document.createElement("img"), + attribute: "alt", +}) + +reflectURL({ + element: document.createElement("img"), + attribute: "src", +}) + +reflectString({ + element: document.createElement("img"), + attribute: "srcset", +}) + +reflectLimitedEnumerated({ + element: document.createElement("img"), + attribute: "crossOrigin", + // "" is a valid value per spec, but gets mapped to the "anonymous" state, + // just like invalid values, so just list it under invalidValues + validValues: [ "anonymous", "use-credentials" ], + invalidValues: [ + "", " aNOnYmous ", " UsE-CreDEntIALS ", "foobar", "FOOBAR", " fOoBaR " + ], + defaultValue: { invalid: "anonymous", missing: null }, + nullable: true, +}) + +reflectString({ + element: document.createElement("img"), + attribute: "useMap", +}) + +reflectBoolean({ + element: document.createElement("img"), + attribute: "isMap", +}) + +ok("width" in document.createElement("img"), "img.width is present") +ok("height" in document.createElement("img"), "img.height is present") +ok("naturalWidth" in document.createElement("img"), "img.naturalWidth is present") +ok("naturalHeight" in document.createElement("img"), "img.naturalHeight is present") +ok("complete" in document.createElement("img"), "img.complete is present") + +reflectString({ + element: document.createElement("img"), + attribute: "name", +}) + +reflectString({ + element: document.createElement("img"), + attribute: "align", +}) + +reflectUnsignedInt({ + element: document.createElement("img"), + attribute: "hspace", +}) + +reflectUnsignedInt({ + element: document.createElement("img"), + attribute: "vspace", +}) + +reflectURL({ + element: document.createElement("img"), + attribute: "longDesc", +}) + +reflectString({ + element: document.createElement("img"), + attribute: "border", + extendedAttributes: { TreatNullAs: "EmptyString" }, +}) + +reflectURL({ + element: document.createElement("img"), + attribute: "lowsrc", +}) + +ok("x" in document.createElement("img"), "img.x is present") +ok("y" in document.createElement("img"), "img.y is present") + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_input_file_cancel_event.html b/dom/html/test/test_input_file_cancel_event.html new file mode 100644 index 0000000000..f0fd81c433 --- /dev/null +++ b/dom/html/test/test_input_file_cancel_event.html @@ -0,0 +1,43 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for the input type=file cancel event</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> + +<input type=file></input> + +<script> +SimpleTest.waitForExplicitFinish(); + +var MockFilePicker = SpecialPowers.MockFilePicker; +MockFilePicker.init(window); +MockFilePicker.useBlobFile(); +MockFilePicker.returnValue = MockFilePicker.returnCancel; + +let input = document.querySelector('input[type=file]'); +input.addEventListener('cancel', event => { + ok(true, "cancel event correctly sent"); + + is(event.target, input, "Has correct event target"); + is(event.isTrusted, true, "Event is trusted"); + is(event.bubbles, true, "Event bubbles"); + is(event.cancelable, false, "Event is not cancelable"); + is(event.composed, false, "Event is not composed"); + + SimpleTest.executeSoon(function() { + MockFilePicker.cleanup(); + SimpleTest.finish(); + }); +}); +input.addEventListener('change' , () => { + ok(false, "unexpected change event"); +}) +input.click(); +</script> +</body> +</html> + diff --git a/dom/html/test/test_input_files_not_nsIFile.html b/dom/html/test/test_input_files_not_nsIFile.html new file mode 100644 index 0000000000..e70bc093ee --- /dev/null +++ b/dom/html/test/test_input_files_not_nsIFile.html @@ -0,0 +1,48 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for <input type='file'> handling when its "files" do not implement nsIFile</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + +<div id="content"> + <input id='a' type='file'> +</div> +<button id='b' onclick="document.getElementById('a').click();">Show Filepicker</button> + +<input type="file" id="file" /> +<pre id="test"> +<script type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); + +var MockFilePicker = SpecialPowers.MockFilePicker; +MockFilePicker.init(window); + +SimpleTest.waitForFocus(function() { + MockFilePicker.useBlobFile(); + MockFilePicker.returnValue = MockFilePicker.returnOK; + + var b = document.getElementById('b'); + b.focus(); // Be sure the element is visible. + + document.getElementById('a').addEventListener("change", function(aEvent) { + ok(true, "change event correctly sent"); + + SimpleTest.executeSoon(function() { + MockFilePicker.cleanup(); + SimpleTest.finish(); + }); + }); + + b.click(); +}); + +</script> +</pre> +</body> +</html> + diff --git a/dom/html/test/test_input_lastInteractiveValue.html b/dom/html/test/test_input_lastInteractiveValue.html new file mode 100644 index 0000000000..6ac29edaef --- /dev/null +++ b/dom/html/test/test_input_lastInteractiveValue.html @@ -0,0 +1,134 @@ +<!doctype html> +<title>Test for HTMLInputElement.lastInteractiveValue</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/EventUtils.js"></script> +<script src="/tests/SimpleTest/NativeKeyCodes.js"></script> +<link href="/tests/SimpleTest/test.css"/> +<body> +<script> +const kIsMac = navigator.platform.indexOf("Mac") > -1; +const kIsWin = navigator.platform.indexOf("Win") > -1; + +function getFreshInput() { + let input = document.body.appendChild(document.createElement("input")); + input.focus(); + return input; +} + +// XXX This should be add_setup, but bug 1776589 +add_task(async function ensure_focus() { + await SimpleTest.promiseFocus(window); +}); + +add_task(async function simple() { + let input = getFreshInput(); + + is(SpecialPowers.wrap(input).lastInteractiveValue, "", "Initial state"); + + sendString("abc"); + + is(input.value, "abc", ".value after interactive edit"); + is(SpecialPowers.wrap(input).lastInteractiveValue, "abc", ".lastInteractiveValue after interactive edit"); + + input.value = "muahahaha"; + is(input.value, "muahahaha", ".value after script edit"); + + is(SpecialPowers.wrap(input).lastInteractiveValue, "abc", ".lastInteractiveValue after script edit"); +}); + +add_task(async function test_default_value() { + let input = getFreshInput(); + input.defaultValue = "default value"; + + is(input.value, "default value", ".defaultValue affects .value"); + is(SpecialPowers.wrap(input).lastInteractiveValue, "", "Default value is not interactive"); + + sendString("abc"); + + is(SpecialPowers.wrap(input).lastInteractiveValue, "default valueabc", "After interaction with default value"); +}); + +// This happens in imdb.com login form. +add_task(async function clone_after_interactive_edit() { + let input = getFreshInput(); + + sendString("abc"); + + is(input.value, "abc", ".value after interactive edit"); + is(SpecialPowers.wrap(input).lastInteractiveValue, "abc", ".lastInteractiveValue after interactive edit"); + + let clone = input.cloneNode(true); + is(clone.value, "abc", ".value after clone"); + is(SpecialPowers.wrap(clone).lastInteractiveValue, "abc", ".lastInteractiveValue after clone"); + + clone.type = "hidden"; + + clone.value = "something random"; + is(SpecialPowers.wrap(clone).lastInteractiveValue, "", ".lastInteractiveValue after clone in non-text-input"); +}); + +add_task(async function set_user_input() { + let input = getFreshInput(); + + input.value = ""; + + SpecialPowers.wrap(input).setUserInput("abc"); + + is(input.value, "abc", ".value after setUserInput edit"); + is(SpecialPowers.wrap(input).lastInteractiveValue, "abc", ".lastInteractiveValue after setUserInput"); + + input.value = "foobar"; + is(SpecialPowers.wrap(input).lastInteractiveValue, "abc", ".lastInteractiveValue after script edit after setUserInput"); +}); + + +// TODO(emilio): Maybe execCommand shouldn't be considered interactive, but it +// matches pre-existing behavior effectively. +add_task(async function exec_command() { + let input = getFreshInput(); + + document.execCommand("insertText", false, "a"); + + is(input.value, "a", ".value after execCommand edit"); + + is(SpecialPowers.wrap(input).lastInteractiveValue, "a", ".lastInteractiveValue after execCommand"); + + input.value = "foobar"; + is(SpecialPowers.wrap(input).lastInteractiveValue, "a", ".lastInteractiveValue after script edit after execCommand"); +}); + +add_task(async function cut_paste() { + if (true) { + // TODO: the above condition should be if (!kIsMac && !kIsWin), but this + // fails (intermittently?) in those platforms, see bug 1776838. Disable for + // now. + todo(false, "synthesizeNativeKey doesn't work elsewhere (yet)"); + return; + } + + function doSynthesizeNativeKey(keyCode, modifiers, chars) { + return new Promise((resolve, reject) => { + if (!synthesizeNativeKey(KEYBOARD_LAYOUT_EN_US, keyCode, modifiers, chars, chars, resolve)) { + reject(new Error("Couldn't synthesize native key")); + } + }); + } + + let input = getFreshInput(); + + sendString("abc"); + + input.select(); + + is(SpecialPowers.wrap(input).lastInteractiveValue, "abc", ".lastInteractiveValue before cut"); + + await doSynthesizeNativeKey(kIsMac ? MAC_VK_ANSI_X : WIN_VK_X, { accelKey: true }, "x"); + + is(SpecialPowers.wrap(input).lastInteractiveValue, "", ".lastInteractiveValue after cut"); + + await doSynthesizeNativeKey(kIsMac ? MAC_VK_ANSI_V : WIN_VK_V, { accelKey: true }, "v"); + + is(SpecialPowers.wrap(input).lastInteractiveValue, "abc", ".lastInteractiveValue after paste"); +}); + +</script> diff --git a/dom/html/test/test_inputmode.html b/dom/html/test/test_inputmode.html new file mode 100644 index 0000000000..56bb101e8a --- /dev/null +++ b/dom/html/test/test_inputmode.html @@ -0,0 +1,132 @@ +<!DOCTYPE html> +<html> +<head> +<title>Tests for inputmode attribute</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<script src="/tests/SimpleTest/SpecialPowers.js"></script> +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<div> +<input id="a1" inputmode="none"> +<input id="a2" inputmode="text"> +<input id="a3" inputmode="tel"> +<input id="a4" inputmode="url"> +<input id="a5" inputmode="email"> +<input id="a6" inputmode="numeric"> +<input id="a7" inputmode="decimal"> +<input id="a8" inputmode="search"> +<input id="a9"> +<input id="a10" type="number" inputmode="numeric"> +<input id="a11" type="date" inputmode="numeric"> +<input id="a12" type="time" inputmode="numeric"> +<textarea id="b1" inputmode="none"></textarea> +<textarea id="b2" inputmode="text"></textarea> +<textarea id="b3" inputmode="tel"></textarea> +<textarea id="b4" inputmode="url"></textarea> +<textarea id="b5" inputmode="email"></textarea> +<textarea id="b6" inputmode="numeric"></textarea> +<textarea id="b7" inputmode="decimal"></textarea> +<textarea id="b8" inputmode="search"></textarea> +<textarea id="b9"></textarea> +<div contenteditable id="c1" inputmode="none"><span>c1</span></div> +<div contenteditable id="c2" inputmode="text"><span>c2</span></div> +<div contenteditable id="c3" inputmode="tel"><span>c3</span></div> +<div contenteditable id="c4" inputmode="url"><span>c4</span></div> +<div contenteditable id="c5" inputmode="email"><span>c5</span></div> +<div contenteditable id="c6" inputmode="numeric"><span>c6</span></div> +<div contenteditable id="c7" inputmode="decimal"><span>c7</span></div> +<div contenteditable id="c8" inputmode="search"><span>c8</span></div> +<div contenteditable id="c9"><span>c9</span></div> +<input id="d1" inputmode="URL"> <!-- no lowercase --> +</div> +<pre id="test"> +<script class=testbody" type="application/javascript"> +// eslint-disable-next-line mozilla/no-addtask-setup +add_task(async function setup() { + await new Promise(r => SimpleTest.waitForFocus(r)); +}); + +add_task(async function basic() { + const tests = [ + { id: "a1", inputmode: "none", desc: "inputmode of input element is none" }, + { id: "a2", inputmode: "text", desc: "inputmode of input element is text" }, + { id: "a3", inputmode: "tel", desc: "inputmode of input element is tel" }, + { id: "a4", inputmode: "url", desc: "inputmode of input element is url" }, + { id: "a5", inputmode: "email", desc: "inputmode of input element is email" }, + { id: "a6", inputmode: "numeric", desc: "inputmode of input element is numeric" }, + { id: "a7", inputmode: "decimal", desc: "inputmode of input element is decimal" }, + { id: "a8", inputmode: "search", desc: "inputmode of input element is search" }, + { id: "a9", inputmode: "", desc: "no inputmode of input element" }, + { id: "a10", inputmode: "numeric", desc: "inputmode of input type=number is numeric" }, + { id: "a11", inputmode: "", desc: "no inputmode due to type=date" }, + { id: "a12", inputmode: "", desc: "no inputmode due to type=time" }, + { id: "b1", inputmode: "none", desc: "inputmode of textarea element is none" }, + { id: "b2", inputmode: "text", desc: "inputmode of textarea element is text" }, + { id: "b3", inputmode: "tel", desc: "inputmode of textarea element is tel" }, + { id: "b4", inputmode: "url", desc: "inputmode of textarea element is url" }, + { id: "b5", inputmode: "email", desc: "inputmode of textarea element is email" }, + { id: "b6", inputmode: "numeric", desc: "inputmode of textarea element is numeric" }, + { id: "b7", inputmode: "decimal", desc: "inputmode of textarea element is decimal" }, + { id: "b8", inputmode: "search", desc: "inputmode of textarea element is search" }, + { id: "b9", inputmode: "", desc: "no inputmode of textarea element" }, + { id: "c1", inputmode: "none", desc: "inputmode of contenteditable is none" }, + { id: "c2", inputmode: "text", desc: "inputmode of contenteditable is text" }, + { id: "c3", inputmode: "tel", desc: "inputmode of contentedtiable is tel" }, + { id: "c4", inputmode: "url", desc: "inputmode of contentedtiable is url" }, + { id: "c5", inputmode: "email", desc: "inputmode of contentedtable is email" }, + { id: "c6", inputmode: "numeric", desc: "inputmode of contenteditable is numeric" }, + { id: "c7", inputmode: "decimal", desc: "inputmode of contenteditable is decimal" }, + { id: "c8", inputmode: "search", desc: "inputmode of contenteditable is search" }, + { id: "c9", inputmode: "", desc: "no inputmode of contentedtiable" }, + { id: "d1", inputmode: "url", desc: "inputmode of input element is URL" }, + ]; + + for (let test of tests) { + let element = document.getElementById(test.id); + if (element.tagName == "DIV") { + // Set caret to text node in contenteditable + window.getSelection().removeAllRanges(); + let range = document.createRange(); + range.setStart(element.firstChild.firstChild, 1); + range.setEnd(element.firstChild.firstChild, 1); + window.getSelection().addRange(range); + } else { + // input and textarea element + element.focus(); + } + is(SpecialPowers.DOMWindowUtils.focusedInputMode, test.inputmode, test.desc); + } +}); + +add_task(async function dynamicChange() { + const tests = ["a3", "b3", "c3"]; + for (let test of tests) { + let element = document.getElementById(test); + element.focus(); + is(SpecialPowers.DOMWindowUtils.focusedInputMode, "tel", "Initial inputmode"); + element.inputMode = "url"; + is(SpecialPowers.DOMWindowUtils.focusedInputMode, "url", + "inputmode in InputContext has to sync with current inputMode property"); + element.setAttribute("inputmode", "decimal"); + is(SpecialPowers.DOMWindowUtils.focusedInputMode, "decimal", + "inputmode in InputContext has to sync with current inputmode attribute"); + // Storing the original value may be safer. + element.inputMode = "tel"; + } + + let element = document.getElementById("a3"); + element.focus(); + is(SpecialPowers.DOMWindowUtils.focusedInputMode, "tel", "Initial inputmode"); + document.getElementById("a4").inputMode = "email"; + is(SpecialPowers.DOMWindowUtils.focusedInputMode, "tel", + "inputmode in InputContext keeps focused inputmode value"); + // Storing the original value may be safer. + document.getElementById("a4").inputMode = "url"; +}); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_li_attributes_reflection.html b/dom/html/test/test_li_attributes_reflection.html new file mode 100644 index 0000000000..fd6795226b --- /dev/null +++ b/dom/html/test/test_li_attributes_reflection.html @@ -0,0 +1,34 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLLIElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLLIElement attributes reflection **/ + +// .value +reflectInt({ + element: document.createElement("li"), + attribute: "value", + nonNegative: false, +}); + +// .type +reflectString({ + element: document.createElement("li"), + attribute: "type" +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_link_attributes_reflection.html b/dom/html/test/test_link_attributes_reflection.html new file mode 100644 index 0000000000..c75c9e2572 --- /dev/null +++ b/dom/html/test/test_link_attributes_reflection.html @@ -0,0 +1,96 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLLinkElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLLinkElement attributes reflection **/ + +// .href (URL) +reflectURL({ + element: document.createElement("link"), + attribute: "href", +}); + +// .crossOrigin (String or null) +reflectLimitedEnumerated({ + element: document.createElement("link"), + attribute: "crossOrigin", + // "" is a valid value per spec, but gets mapped to the "anonymous" state, + // just like invalid values, so just list it under invalidValues + validValues: [ "anonymous", "use-credentials" ], + invalidValues: [ + "", " aNOnYmous ", " UsE-CreDEntIALS ", "foobar", "FOOBAR", " fOoBaR " + ], + defaultValue: { invalid: "anonymous", missing: null }, + nullable: true, +}) + +// .rel (String) +reflectString({ + element: document.createElement("link"), + attribute: "rel", +}); + +// .media (String) +reflectString({ + element: document.createElement("link"), + attribute: "media", +}); + +// .hreflang (String) +reflectString({ + element: document.createElement("link"), + attribute: "hreflang", +}); + +// .type (String) +reflectString({ + element: document.createElement("link"), + attribute: "type", +}); + + +// .charset (String) +reflectString({ + element: document.createElement("link"), + attribute: "charset", +}); + +// .rev (String) +reflectString({ + element: document.createElement("link"), + attribute: "rev", +}); + +// .target (String) +reflectString({ + element: document.createElement("link"), + attribute: "target", +}); + +// .as (String) +reflectLimitedEnumerated({ + element: document.createElement("link"), + attribute: "as", + validValues: [ "fetch", "audio", "font", "image", "script", "style", "track", "video" ], + invalidValues: [ + "", "audi", "doc", "Emb", "foobar", "FOOBAR", " fOoBaR ", "OBJ", "document", "embed", "manifest", "object", "report", "serviceworker", "sharedworker", "worker", "xslt" + ], + defaultValue: { invalid: "", missing: "" }, + nullable: false, +}) + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_link_sizes.html b/dom/html/test/test_link_sizes.html new file mode 100644 index 0000000000..b242748886 --- /dev/null +++ b/dom/html/test/test_link_sizes.html @@ -0,0 +1,35 @@ +<!doctype html> +<html> +<head> +<title>Test link.sizes attribute</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" sizes="16x16 24x24 32x32 48x48"> +</head> +<body> + +<pre id="test"> +<script> + + var links = document.getElementsByTagName('link'); + for (var i = 0; i < links.length; ++i) { + var link = links[i]; + ok("sizes" in link, "link.sizes exists"); + + if (link.rel == 'shortcut icon') { + is(link.sizes.value, "16x16 24x24 32x32 48x48", 'link.sizes.value correct value'); + is(link.sizes.length, 4, 'link.sizes.length correct value'); + ok(link.sizes.contains('32x32'), 'link.sizes.contains() works'); + link.sizes.add('64x64'); + is(link.sizes.length, 5, 'link.sizes.length correct value'); + link.sizes.remove('64x64'); + is(link.sizes.length, 4, 'link.sizes.length correct value'); + is(link.sizes + "", "16x16 24x24 32x32 48x48", 'link.sizes stringify correct value'); + } else { + is(link.sizes.value, "", 'link.sizes correct value'); + } + } +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_map_attributes_reflection.html b/dom/html/test/test_map_attributes_reflection.html new file mode 100644 index 0000000000..8835fb29d2 --- /dev/null +++ b/dom/html/test/test_map_attributes_reflection.html @@ -0,0 +1,27 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLMapElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLMapElement attributes reflection **/ + +// .name (String) +reflectString({ + element: document.createElement("map"), + attribute: "name", +}) + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_meta_attributes_reflection.html b/dom/html/test/test_meta_attributes_reflection.html new file mode 100644 index 0000000000..e0cf0c347d --- /dev/null +++ b/dom/html/test/test_meta_attributes_reflection.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLMetaElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLMetaElement attributes reflection **/ + +// .name (String) +reflectString({ + element: document.createElement("meta"), + attribute: "name", +}) + +// .httpEquiv (String) +reflectString({ + element: document.createElement("meta"), + attribute: { content: "http-equiv", idl: "httpEquiv" }, +}) + +// .content (String) +reflectString({ + element: document.createElement("meta"), + attribute: "content", +}) + +// .scheme (String) +reflectString({ + element: document.createElement("meta"), + attribute: "scheme", +}) + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_mod_attributes_reflection.html b/dom/html/test/test_mod_attributes_reflection.html new file mode 100644 index 0000000000..0efa7c52bf --- /dev/null +++ b/dom/html/test/test_mod_attributes_reflection.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLModElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLModElement attributes reflection **/ + +// .cite (URL) +reflectURL({ + element: document.createElement("ins"), + attribute: "cite", +}) +reflectURL({ + element: document.createElement("del"), + attribute: "cite", +}) + +// .dateTime (String) +reflectString({ + element: document.createElement("ins"), + attribute: "dateTime", +}) +reflectString({ + element: document.createElement("del"), + attribute: "dateTime", +}) + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_multipleFilePicker.html b/dom/html/test/test_multipleFilePicker.html new file mode 100644 index 0000000000..c4a71151aa --- /dev/null +++ b/dom/html/test/test_multipleFilePicker.html @@ -0,0 +1,79 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test for single filepicker per event</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + <div id='foo'><a href='#'>Click here to test this issue</a></div> + <script> + +SimpleTest.requestFlakyTimeout("Timeouts are needed to simulate user-interaction"); +SimpleTest.waitForExplicitFinish(); + +let clickCount = 0; +let foo = document.getElementById('foo'); +foo.addEventListener('click', _ => { + if (++clickCount < 10) { + let input = document.createElement('input'); + input.type = 'file'; + foo.appendChild(input); + input.click(); + } +}); + +let MockFilePicker = SpecialPowers.MockFilePicker; +MockFilePicker.init(window); + +let pickerCount = 0; + +SpecialPowers.pushPrefEnv({ + set: [["dom.disable_open_during_load", true]], +}) +// Let's do the first click. +.then(() => { + return new Promise(resolve => { + MockFilePicker.showCallback = function(filepicker) { + ++pickerCount; + resolve(); + } + setTimeout(_ => { + is(pickerCount, 0, "No file picker initially"); + synthesizeMouseAtCenter(foo, {}); + }, 0); + }) +}) + +// Let's wait a bit more, then let's do a click. +.then(() => { + return new Promise(resolve => { + MockFilePicker.showCallback = function(filepicker) { + ++pickerCount; + resolve(); + } + + setTimeout(() => { + is(pickerCount, 1, "Only 1 file picker"); + is(clickCount, 10, "10 clicks triggered"); + clickCount = 0; + pickerCount = 0; + synthesizeMouseAtCenter(foo, {}); + }, 1000); + }); +}) + +// Another click... +.then(_ => { + setTimeout(() => { + is(pickerCount, 1, "Only 1 file picker"); + is(clickCount, 10, "10 clicks triggered"); + MockFilePicker.cleanup(); + SimpleTest.finish(); + }, 1000); +}); + +</script> +</body> +</html> diff --git a/dom/html/test/test_named_options.html b/dom/html/test/test_named_options.html new file mode 100644 index 0000000000..8c38425240 --- /dev/null +++ b/dom/html/test/test_named_options.html @@ -0,0 +1,61 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=772869 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 772869</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=772869">Mozilla Bug 772869</a> +<p id="display"></p> +<div id="content" style="display: none"> + <select id="s"> + <option name="x"></option> + <option name="y" id="z"></option> + <option name="z" id="x"></option> + <option id="w"></option> + </select> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 772869 **/ +var opt = $("s").options; +opt.loopy = "something" +var names = Object.getOwnPropertyNames(opt); +is(names.length, 9, "Should have nine entries"); +is(names[0], "0", "Entry 1") +is(names[1], "1", "Entry 2") +is(names[2], "2", "Entry 3") +is(names[3], "3", "Entry 4") +is(names[4], "x", "Entry 5") +is(names[5], "y", "Entry 6") +is(names[6], "z", "Entry 7") +is(names[7], "w", "Entry 8") +is(names[8], "loopy", "Entry 9") + +var names2 = []; +for (var name in opt) { + names2.push(name); +} +is(names2.length, 11, "Should have eleven enumerated names"); +is(names2[0], "0", "Enum entry 1") +is(names2[1], "1", "Enum entry 2") +is(names2[2], "2", "Enum entry 3") +is(names2[3], "3", "Enum entry 4") +is(names2[4], "loopy", "Enum entry 5") +is(names2[5], "add", "Enum entrry 6") +is(names2[6], "remove", "Enum entry 7") +is(names2[7], "length", "Enum entry 8") +is(names2[8], "selectedIndex", "Enum entry 9") +is(names2[9], "item", "Enum entry 10") +is(names2[10], "namedItem", "Enum entry 11") + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_nested_invalid_fieldsets.html b/dom/html/test/test_nested_invalid_fieldsets.html new file mode 100644 index 0000000000..7c00693697 --- /dev/null +++ b/dom/html/test/test_nested_invalid_fieldsets.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=914029 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 914029</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript"> + + /** Test for Bug 914029 **/ + + var innerFieldset = document.createElement("fieldset"); + var outerFieldset = document.createElement("fieldset"); + var textarea = document.createElement("textarea"); + textarea.setAttribute("required", ""); + innerFieldset.appendChild(textarea); + outerFieldset.appendChild(innerFieldset); + SpecialPowers.forceGC(); + ok(true, "This page did not crash - dynamically added nested invalid fieldsets" + + " work correctly."); + var innerFieldset = document.createElement("fieldset"); + var outerFieldset = document.createElement("fieldset"); + var textarea = document.createElement("textarea"); + var textarea2 = document.createElement("textarea"); + textarea.setAttribute("required", ""); + innerFieldset.appendChild(textarea); + innerFieldset.appendChild(textarea2); + outerFieldset.appendChild(innerFieldset); + SpecialPowers.forceGC(); + ok(true, "This page did not crash - dynamically added nested invalid fieldsets" + + " work correctly."); + + </script> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=914029">Mozilla Bug 914029</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> +</body> +</html> diff --git a/dom/html/test/test_nestediframe.html b/dom/html/test/test_nestediframe.html new file mode 100644 index 0000000000..ddbf0ca9dc --- /dev/null +++ b/dom/html/test/test_nestediframe.html @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for same URLs nested iframes</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> + test_nestediframe body +<script> + +SimpleTest.waitForExplicitFinish(); + +function reportState(msg) { + if (location.href.includes("#")) { + parent.postMessage(msg, "*"); + return; + } + + if (msg == "OK 1") { + ok(true, "First frame loaded"); + } else if (msg == "KO 2") { + ok(true, "Second frame load failed"); + SimpleTest.finish(); + } else { + ok(false, "Unknown message: " + msg); + } +} + +addEventListener("message", event => { + reportState(event.data); +}); + +var recursion; +if (!location.href.includes("#")) { + recursion = 1; +} else { + recursion = parseInt(location.href.split("#")[1]) + 1; +} + +var ifr = document.createElement('iframe'); +ifr.src = location.href.split("#")[0] + "#" + recursion; + +ifr.onload = function() { + reportState("OK " + recursion); +} +ifr.onerror = function() { + reportState("KO " + recursion); +} + +document.body.appendChild(ifr); + +</script> +</body> +</html> diff --git a/dom/html/test/test_non-ascii-cookie.html b/dom/html/test/test_non-ascii-cookie.html new file mode 100644 index 0000000000..a15923f39d --- /dev/null +++ b/dom/html/test/test_non-ascii-cookie.html @@ -0,0 +1,69 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=784367 +--> +<head> + <meta charset="utf-8"> + <title>Test for non-ASCII cookie values</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=784367">Mozilla Bug 784367</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for non-ASCII cookie values **/ + +SimpleTest.waitForExplicitFinish(); + +var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL("file_cookiemanager.js")); + +function getCookieFromManager() { + return new Promise(resolve => { + gScript.addMessageListener("getCookieFromManager:return", function gcfm({ cookie }) { + gScript.removeMessageListener("getCookieFromManager:return", gcfm); + resolve(cookie); + }); + gScript.sendAsyncMessage("getCookieFromManager", { host: location.hostname, path: location.pathname }); + }); +} + +SpecialPowers.pushPrefEnv({ + "set": [ + // Bug 1617611: Fix all the tests broken by "cookies SameSite=lax by default" + ["network.cookie.sameSite.laxByDefault", false], + ] +}, () => { + var c = document.cookie; + is(document.cookie, 'abc=012©ABC\ufffdDEF', "document.cookie should be decoded as UTF-8"); + + var newCookie; + + getCookieFromManager().then((cookie) => { + is(cookie, document.cookie, "nsICookieManager should be consistent with document.cookie"); + newCookie = 'def=∼≩≭≧∯≳≲≣∽≸≸∺≸∠≯≮≥≲≲≯≲∽≡≬≥≲≴∨∱∩∾'; + document.cookie = newCookie; + is(document.cookie, c + '; ' + newCookie, "document.cookie should be encoded as UTF-8"); + + return getCookieFromManager(); + }).then((cookie) => { + is(cookie, document.cookie, "nsICookieManager should be consistent with document.cookie"); + var date1 = new Date(); + date1.setTime(0); + document.cookie = newCookie + 'def=;expires=' + date1.toGMTString(); + gScript.destroy(); + SpecialPowers.clearUserPref("network.cookie.sameSite.laxByDefault"); + SimpleTest.finish(); + }); +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_non-ascii-cookie.html^headers^ b/dom/html/test/test_non-ascii-cookie.html^headers^ new file mode 100644 index 0000000000..54aa6c3e72 --- /dev/null +++ b/dom/html/test/test_non-ascii-cookie.html^headers^ @@ -0,0 +1 @@ +Set-Cookie: abc=012©ABC©DEF diff --git a/dom/html/test/test_object_attributes_reflection.html b/dom/html/test/test_object_attributes_reflection.html new file mode 100644 index 0000000000..d55183db07 --- /dev/null +++ b/dom/html/test/test_object_attributes_reflection.html @@ -0,0 +1,117 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLObjectElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLObjectElement attributes reflection **/ + +// .data (URL) +reflectURL({ + element: document.createElement("object"), + attribute: "data", +}); + +// .type (String) +reflectString({ + element: document.createElement("object"), + attribute: "type", +}); + +// .name (String) +reflectString({ + element: document.createElement("object"), + attribute: "name", +}); + +// .useMap (String) +reflectString({ + element: document.createElement("object"), + attribute: "useMap", +}); + +// .width (String) +reflectString({ + element: document.createElement("object"), + attribute: "width", +}); + +// .height (String) +reflectString({ + element: document.createElement("object"), + attribute: "height", +}); + +// .align (String) +reflectString({ + element: document.createElement("object"), + attribute: "align", +}); + +// .archive (String) +reflectString({ + element: document.createElement("object"), + attribute: "archive", +}); + +// .code (String) +reflectString({ + element: document.createElement("object"), + attribute: "code", +}); + +// .declare (String) +reflectBoolean({ + element: document.createElement("object"), + attribute: "declare", +}); + +// .hspace (unsigned int) +reflectUnsignedInt({ + element: document.createElement("object"), + attribute: "hspace", +}); + +// .standby (String) +reflectString({ + element: document.createElement("object"), + attribute: "standby", +}); + +// .vspace (unsigned int) +reflectUnsignedInt({ + element: document.createElement("object"), + attribute: "vspace", +}); + +// .codeBase (URL) +reflectURL({ + element: document.createElement("object"), + attribute: "codeBase", +}); + +// .codeType (String) +reflectString({ + element: document.createElement("object"), + attribute: "codeType", +}); + +// .border (String) +reflectString({ + element: document.createElement("object"), + attribute: "border", + extendedAttributes: { TreatNullAs: "EmptyString" }, +}); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_ol_attributes_reflection.html b/dom/html/test/test_ol_attributes_reflection.html new file mode 100644 index 0000000000..a941914077 --- /dev/null +++ b/dom/html/test/test_ol_attributes_reflection.html @@ -0,0 +1,65 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLOLElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLOLElement attributes reflection **/ + +// .reversed (boolean) +reflectBoolean({ + element: document.createElement("ol"), + attribute: "reversed", +}) + +// .start +reflectInt({ + element: document.createElement("ol"), + attribute: "start", + nonNegative: false, + defaultValue: 1, +}); + +// .type +reflectString({ + element: document.createElement("ol"), + attribute: "type" +}); + +// .compact +reflectBoolean({ + element: document.createElement("ol"), + attribute: "compact", +}) + +// Additional tests for ol.start behavior when li elements are added +var ol = document.createElement("ol"); +var li = document.createElement("li"); +li.value = 42; +ol.appendChild(li); +is(ol.start, 1, "ol.start with one li child, li.value = 42:"); +li.value = -42; +is(ol.start, 1, "ol.start with one li child, li.value = 42:"); +ol.removeAttribute("start"); +li.removeAttribute("value"); +ol.appendChild(document.createElement("li")); +ol.reversed = true; +todo_is(ol.start, 2, "ol.start with two li children, ol.reversed == true:"); +li.value = 42; +todo_is(ol.start, 2, "ol.start with two li childern, ol.reversed == true:"); +ol.start = 42; +is(ol.start, 42, "ol.start = 42:"); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_option_defaultSelected.html b/dom/html/test/test_option_defaultSelected.html new file mode 100644 index 0000000000..6d999c0b29 --- /dev/null +++ b/dom/html/test/test_option_defaultSelected.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=927796 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 927796</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=927796">Mozilla Bug 927796</a> +<p id="display"> +<select id="s1"> + <option selected>one</option> + <option>two</option> +</select> +<select id="s2" size="5"> + <option selected>one</option> + <option>two</option> +</select> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +</pre> + <script type="application/javascript"> + + /** Test for Bug 927796 **/ + var s1 = $("s1"); + s1.options[0].defaultSelected = false; + is(s1.options[0].selected, true, + "First option in combobox should still be selected"); + is(s1.options[1].selected, false, + "Second option in combobox should not be selected"); + + var s2 = $("s2"); + s2.options[0].defaultSelected = false; + is(s2.options[0].selected, false, + "First option in listbox should not be selected"); + is(s2.options[1].selected, false, + "Second option in listbox should not be selected"); + </script> +</body> +</html> diff --git a/dom/html/test/test_option_selected_state.html b/dom/html/test/test_option_selected_state.html new file mode 100644 index 0000000000..30a634de58 --- /dev/null +++ b/dom/html/test/test_option_selected_state.html @@ -0,0 +1,61 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=942648 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 942648</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=942648">Mozilla Bug 942648</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> + <select> + <option value="1">1</option> + <option id="e1" value="2">2</option> + </select> + <select> + <option value="1">1</option> + <option id="e2" selected value="2">2</option> + </select> + <select> + <option value="1">1</option> + <option id="e3" selected="" value="2">2</option> + </select> + <select> + <option value="1">1</option> + <option id="e4" selected="selected" value="2">2</option> + </select> +</pre> + <script type="application/javascript"> + + /** Test for Bug 942648 **/ +SimpleTest.waitForExplicitFinish(); + window.onload = function() { + var e1 = document.getElementById('e1'); + var e2 = document.getElementById('e2'); + var e3 = document.getElementById('e3'); + var e4 = document.getElementById('e4'); + ok(!e1.selected, "e1 should not be selected"); + ok(e2.selected, "e2 should be selected"); + ok(e3.selected, "e3 should be selected"); + ok(e4.selected, "e4 should be selected"); + e1.setAttribute('selected', 'selected'); + e2.setAttribute('selected', 'selected'); + e3.setAttribute('selected', 'selected'); + e4.setAttribute('selected', 'selected'); + ok(e1.selected, "e1 should now be selected"); + ok(e2.selected, "e2 should still be selected"); + ok(e3.selected, "e3 should still be selected"); + ok(e4.selected, "e4 should still be selected"); + SimpleTest.finish(); + }; + </script> +</body> +</html> diff --git a/dom/html/test/test_param_attributes_reflection.html b/dom/html/test/test_param_attributes_reflection.html new file mode 100644 index 0000000000..977fb61935 --- /dev/null +++ b/dom/html/test/test_param_attributes_reflection.html @@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLParamElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLParamElement attributes reflection **/ + +// .name +reflectString({ + element: document.createElement("param"), + attribute: "name", +}); + +// .value +reflectString({ + element: document.createElement("param"), + attribute: "value" +}); + +// .type +reflectString({ + element: document.createElement("param"), + attribute: "type" +}); + +// .valueType +reflectString({ + element: document.createElement("param"), + attribute: "valueType" +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_plugin.tst b/dom/html/test/test_plugin.tst new file mode 100644 index 0000000000..323fae03f4 --- /dev/null +++ b/dom/html/test/test_plugin.tst @@ -0,0 +1 @@ +foobar diff --git a/dom/html/test/test_q_attributes_reflection.html b/dom/html/test/test_q_attributes_reflection.html new file mode 100644 index 0000000000..a840e6f0e5 --- /dev/null +++ b/dom/html/test/test_q_attributes_reflection.html @@ -0,0 +1,32 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLQuoteElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLQuoteElement attributes reflection **/ + +// .cite +reflectURL({ + element: document.createElement("q"), + attribute: "cite", +}); + +reflectURL({ + element: document.createElement("blockquote"), + attribute: "cite", +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_restore_from_parser_fragment.html b/dom/html/test/test_restore_from_parser_fragment.html new file mode 100644 index 0000000000..7fb3b75e46 --- /dev/null +++ b/dom/html/test/test_restore_from_parser_fragment.html @@ -0,0 +1,59 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=644959 +--> +<head> + <title>Test for Bug 644959</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=644959">Mozilla Bug 644959</a> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 644959 **/ + +var content = document.getElementById('content'); + +function appendHTML(aParent, aElementString) +{ + aParent.innerHTML = "<form>" + aElementString + "</form>"; +} + +function clearHTML(aParent) +{ + aParent.innerHTML = ""; +} + +var tests = [ + [ "button", "<button></button>" ], + [ "input", "<input>" ], + [ "textarea", "<textarea></textarea>" ], + [ "select", "<select></select>" ], +]; + +var element = null; + +for (var test of tests) { + appendHTML(content, test[1]); + element = content.getElementsByTagName(test[0])[0]; + is(element.disabled, false, "element shouldn't be disabled"); + element.disabled = true; + is(element.disabled, true, "element should be disabled"); + + clearHTML(content); + + appendHTML(content, test[1]); + element = content.getElementsByTagName(test[0])[0]; + is(element.disabled, false, "element shouldn't be disabled"); +} + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_rowscollection.html b/dom/html/test/test_rowscollection.html new file mode 100644 index 0000000000..0e5152e1d5 --- /dev/null +++ b/dom/html/test/test_rowscollection.html @@ -0,0 +1,69 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=772869 +--> +<head> + <meta charset="utf-8"> + <title>Test for Bug 772869</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=772869">Mozilla Bug 772869</a> +<p id="display"></p> +<div id="content" style="display: none"> + <table id="f"> + <thead> + <tr id="x"></tr> + </thead> + <tfoot> + <tr id="z"></tr> + <tr id="w"></tr> + </tfoot> + <tr id="x"></tr> + <tr id="y"></tr> + <tbody> + <tr id="z"></tr> + </tbody> + </table> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 772869 **/ +var x = $("f").rows; +x.something = "another"; +var names = []; +for (var name in x) { + names.push(name); +} +is(names.length, 10, "Should have 10 enumerated names"); +is(names[0], "0", "Enum entry 1") +is(names[1], "1", "Enum entry 2") +is(names[2], "2", "Enum entry 3") +is(names[3], "3", "Enum entry 4") +is(names[4], "4", "Enum entry 5") +is(names[5], "5", "Enum entry 6") +is(names[6], "something", "Enum entry 7") +is(names[7], "item", "Enum entry 8") +is(names[8], "namedItem", "Enum entry 9") +is(names[9], "length", "Enum entry 10"); + +names = Object.getOwnPropertyNames(x); +is(names.length, 11, "Should have 11 items"); +is(names[0], "0", "Entry 1") +is(names[1], "1", "Entry 2") +is(names[2], "2", "Entry 3") +is(names[3], "3", "Entry 4") +is(names[4], "4", "Entry 5") +is(names[5], "5", "Entry 6") +is(names[6], "x", "Entry 7") +is(names[7], "y", "Entry 8") +is(names[8], "z", "Entry 9") +is(names[9], "w", "Entry 10") +is(names[10], "something", "Entry 11") +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_script_module.html b/dom/html/test/test_script_module.html new file mode 100644 index 0000000000..26b9cd6f65 --- /dev/null +++ b/dom/html/test/test_script_module.html @@ -0,0 +1,31 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLScriptElement with nomodule attribute</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> + +<body> + <script> +onmessage = (e) => { + if ("done" in e.data) { + SimpleTest.finish(); + } else if ("check" in e.data) { + ok(e.data.check, e.data.msg); + } else { + ok(false, "Unknown message"); + } +} + + +var ifr = document.createElement('iframe'); +ifr.src = "file_script_module.html"; +document.body.appendChild(ifr); + + +SimpleTest.waitForExplicitFinish(); + </script> + +</body> +</html> diff --git a/dom/html/test/test_set_input_files.html b/dom/html/test/test_set_input_files.html new file mode 100644 index 0000000000..3b7bf20909 --- /dev/null +++ b/dom/html/test/test_set_input_files.html @@ -0,0 +1,55 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1384030 +--> +<head> + <title>Test for Setting <input type=file>.files </title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1384030">Mozilla Bug 1384030</a> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Setting <input type=file>.files **/ + +function runTest() +{ + const form = document.createElement("form"); + const formInput = document.createElement("input"); + formInput.type = "file"; + formInput.name = "inputFile"; + form.appendChild(formInput); + + const input = document.createElement("input"); + input.type = "file"; + SpecialPowers.wrap(input).mozSetFileArray([ + new File(["foo"], "foo"), + new File(["bar"], "bar") + ]); + + formInput.files = input.files; + + const inputFiles = (new FormData(form)).getAll("inputFile"); + is(inputFiles.length, 2, "FormData should contain two input files"); + + is(inputFiles[0].name, "foo", "Input file name should be 'foo'"); + is(inputFiles[1].name, "bar", "Input file name should be 'bar'"); + + is(inputFiles[0], input.files[0], + "Expect the same File object as input file 'foo'"); + is(inputFiles[1], input.files[1], + "Expect the same File object as input file 'bar'"); + + SimpleTest.finish(); +} + +SimpleTest.waitForExplicitFinish(); +window.addEventListener('load', runTest); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_srcdoc-2.html b/dom/html/test/test_srcdoc-2.html new file mode 100644 index 0000000000..5db7d69529 --- /dev/null +++ b/dom/html/test/test_srcdoc-2.html @@ -0,0 +1,57 @@ +<!doctype html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=802895 +--> + <head> +<title>Test session history for srcdoc iframes introduced in bug 802895</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> + +<link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=802895">Mozilla Bug 802895</a> + +<iframe id="pframe" name="pframe" src="file_srcdoc-2.html"></iframe> +<pre id="test"> +<script> + + SimpleTest.waitForExplicitFinish(); + var pframe = $("pframe"); + + //disable bfcache + pframe.contentWindow.addEventListener("unload", function () { }); + + var loadState = 0; + pframe.onload = function () { + SimpleTest.executeSoon(function () { + + var pDoc = pframe.contentDocument; + + if (loadState == 0) { + var div = pDoc.createElement("div"); + div.id = "modifyCheck"; + div.innerHTML = "hello again"; + pDoc.body.appendChild(div); + ok(pDoc.getElementById("modifyCheck"), "Child element not created"); + pframe.src = "about:blank"; + loadState = 1; + } + else if (loadState == 1) { + loadState = 2; + window.history.back(); + } + else if (loadState == 2) { + ok(!pDoc.getElementById("modifyCheck"), "modifyCheck element shouldn't be present"); + is(pDoc.getElementById("iframe").contentDocument.body.innerHTML, + "Hello World", "srcdoc iframe not present"); + SimpleTest.finish(); + } + + }) + }; + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_srcdoc.html b/dom/html/test/test_srcdoc.html new file mode 100644 index 0000000000..b3137f4e0a --- /dev/null +++ b/dom/html/test/test_srcdoc.html @@ -0,0 +1,118 @@ +<!doctype html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=802895 +--> + <head> +<title>Tests for srcdoc iframes introduced in bug 802895</title> +<script src="/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=802895">Mozilla Bug 802895</a> + +<iframe id="pframe" src="file_srcdoc.html"></iframe> + +<pre id="test"> +<script> + + SimpleTest.waitForExplicitFinish(); + SimpleTest.requestFlakyTimeout("untriaged"); + var pframe = $("pframe"); + + var loadState = 0; + pframe.contentWindow.addEventListener("load", function () { + + var pframeDoc = pframe.contentDocument; + + var iframe = pframeDoc.getElementById("iframe"); + var innerDoc = iframe.contentDocument; + var iframe1 = pframeDoc.getElementById("iframe1"); + var innerDoc1 = iframe1.contentDocument; + + var finish = false; + var finish1 = false; + var finish3 = false; + + + + is(iframe.srcdoc, "Hello World", "Bad srcdoc attribute contents") + + is(innerDoc.domain, document.domain, "Wrong domain"); + is(innerDoc.referrer, pframeDoc.referrer, "Wrong referrer"); + is(innerDoc.body.innerHTML, "Hello World", "Wrong body"); + is(innerDoc.compatMode, "CSS1Compat", "Not standards compliant"); + + is(innerDoc1.domain, document.domain, "Wrong domain with src attribute"); + is(innerDoc1.referrer, pframeDoc.referrer, "Wrong referrer with src attribute"); + is(innerDoc1.body.innerHTML, "Goodbye World", "Wrong body with src attribute") + is(innerDoc1.compatMode, "CSS1Compat", "Not standards compliant with src attribute"); + + var iframe2 = pframeDoc.getElementById("iframe2"); + var innerDoc2 = iframe2.contentDocument; + try { + innerDoc2.domain; + foundError = false; + } + catch (error) { + foundError = true; + } + ok(foundError, "srcdoc iframe not sandboxed"); + + //Test changed srcdoc attribute + iframe.onload = function () { + + iframe = pframeDoc.getElementById("iframe"); + innerDoc = iframe.contentDocument; + + is(iframe.srcdoc, "Hello again", "Bad srcdoc attribute contents with srcdoc attribute changed"); + is(innerDoc.domain, document.domain, "Wrong domain with srcdoc attribute changed"); + is(innerDoc.referrer, pframeDoc.referrer, "Wrong referrer with srcdoc attribute changed"); + is(innerDoc.body.innerHTML, "Hello again", "Wrong body with srcdoc attribute changed"); + is(innerDoc.compatMode, "CSS1Compat", "Not standards compliant with srcdoc attribute changed"); + + finish = true; + if (finish && finish1 && finish3) { + SimpleTest.finish(); + } + }; + + iframe.srcdoc = "Hello again"; + + var iframe3 = pframeDoc.getElementById("iframe3"); + + // Test srcdoc attribute removal + iframe3.onload = function () { + var innerDoc3 = iframe3.contentDocument; + is(innerDoc3.body.innerText, "Gone", "Bad srcdoc attribute removal"); + finish3 = true; + if (finish && finish1 && finish3) { + SimpleTest.finish(); + } + } + + iframe3.removeAttribute("srcdoc"); + + + var iframe1load = false; + iframe1.onload = function () { + iframe1load = true; + } + + iframe1.src = "data:text/plain;charset=US-ASCII,Goodbyeeee"; + + // Need to test that changing the src doesn't change the iframe. + setTimeout(function () { + ok(!iframe1load, "Changing src attribute shouldn't cause a load when srcdoc is set"); + finish1 = true; + if (finish && finish1 && finish3) { + SimpleTest.finish(); + } + }, 2000); + + }); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_style_attributes_reflection.html b/dom/html/test/test_style_attributes_reflection.html new file mode 100644 index 0000000000..745ed7435f --- /dev/null +++ b/dom/html/test/test_style_attributes_reflection.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> +<head> + <title>Test for HTMLStyleElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLStyleElement attributes reflection **/ + +var e = document.createElement("style"); + +// .media +reflectString({ + element: e, + attribute: "media" +}); + +// .type +reflectString({ + element: e, + attribute: "type" +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_track.html b/dom/html/test/test_track.html new file mode 100644 index 0000000000..50051bf2d6 --- /dev/null +++ b/dom/html/test/test_track.html @@ -0,0 +1,62 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=833386 +--> +<head> + <meta charset='utf-8'> + <title>Test for Bug 833386 - HTMLTrackElement</title> + <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="/tests/dom/html/test/reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script class="testbody" type="text/javascript"> +reflectLimitedEnumerated({ + element: document.createElement("track"), + attribute: "kind", + validValues: ["subtitles", "captions", "descriptions", "chapters", + "metadata"], + invalidValues: ["foo", "bar", "\u0000", "null", "", "subtitle", "caption", + "description", "chapter", "meta"], + defaultValue: { missing: "subtitles", invalid: "metadata" }, +}); + +// Default attribute +reflectBoolean({ + element: document.createElement("track"), + attribute: "default" +}); + +// Label attribute +reflectString({ + element: document.createElement("track"), + attribute: "label", + otherValues: [ "foo", "BAR", "_FoO", "\u0000", "null", "white space" ] +}); + +// Source attribute +reflectURL({ + element: document.createElement("track"), + attribute: "src", + otherValues: ["foo", "bar", "\u0000", "null", ""] +}); + +// Source Language attribute +reflectString({ + element: document.createElement("track"), + attribute: "srclang", + otherValues: ["foo", "bar", "\u0000", "null", ""] +}); + +var track = document.createElement("track"); +is(track.readyState, 0, "Default ready state should be 0 (NONE)."); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_ul_attributes_reflection.html b/dom/html/test/test_ul_attributes_reflection.html new file mode 100644 index 0000000000..cd5f6b1cc2 --- /dev/null +++ b/dom/html/test/test_ul_attributes_reflection.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for HTMLUListElement attributes reflection</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="reflect.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"> +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for HTMLUListElement attributes reflection **/ + +// .compact +reflectBoolean({ + element: document.createElement("ul"), + attribute: "compact" +}); + +// .type +reflectString({ + element: document.createElement("ul"), + attribute: "type" +}); + +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_viewport_resize.html b/dom/html/test/test_viewport_resize.html new file mode 100644 index 0000000000..e800aa592a --- /dev/null +++ b/dom/html/test/test_viewport_resize.html @@ -0,0 +1,44 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=1135812 +--> +<head> + <title>Test for Bug 1135812</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1135812">Mozilla Bug 1135812</a> +<p id="display"></p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> + +<iframe style="width: 50px;" + srcdoc='<picture><source srcset="data:,a" media="(min-width: 150px)" /><source srcset="data:,b" media="(min-width: 100px)" /><img src="data:,c" /></picture>'></iframe> +<script> + SimpleTest.waitForExplicitFinish(); + addEventListener('load', function() { + var iframe = document.querySelector('iframe'); + var img = iframe.contentDocument.querySelector('img'); + is(img.currentSrc, 'data:,c'); + + img.onload = function() { + is(img.currentSrc, 'data:,a'); + img.onload = function() { + is(img.currentSrc, 'data:,b'); + SimpleTest.finish(); + } + img.onerror = img.onload; + iframe.style.width = '120px'; + }; + img.onerror = img.onload; + + iframe.style.width = '200px'; + }, true); +</script> +</pre> +</body> +</html> diff --git a/dom/html/test/test_window_open_close.html b/dom/html/test/test_window_open_close.html new file mode 100644 index 0000000000..0869100b4c --- /dev/null +++ b/dom/html/test/test_window_open_close.html @@ -0,0 +1,53 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script src="/tests/SimpleTest/EventUtils.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<script type="application/javascript"> + +SimpleTest.waitForExplicitFinish(); + +// Opens a popup. Link should load in main browser window. Popup should be closed when link clicked. +function openWindow1() { + return window.open('file_window_open_close_outer.html','','width=300,height=200'); +} + +// Opens a new tab T1. Link opens in another new tab T2. T1 should close when link clicked. +function openWindow2() { + return window.open('file_window_open_close_outer.html'); +} + +// Opens a new window. Link should open in a new tab of that window, but then both windows should close. +function openWindow3() { + return window.open('file_window_open_close_outer.html', '', 'toolbar=1'); +} + +var TESTS = [openWindow1, openWindow2, openWindow3]; + +function popupLoad(win) +{ + info("Sending click"); + sendMouseEvent({type: "click"}, "link", win); + ok(true, "Didn't crash"); + + next(); +} + +function next() +{ + if (!TESTS.length) { + SimpleTest.finish(); + } else { + var test = TESTS.shift(); + var w = test(); + w.addEventListener("load", (e) => popupLoad(w)); + } +} +</script> + +<body onload="next()"> +</body> +</html> diff --git a/dom/html/test/test_window_open_from_closing.html b/dom/html/test/test_window_open_from_closing.html new file mode 100644 index 0000000000..0d38c88d84 --- /dev/null +++ b/dom/html/test/test_window_open_from_closing.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<html> +<head> + <title>window.open from a window being closed</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> + <h1>window.open from a window being closed</h1> +<script> +add_task(async function() { + const RELS = ["", "#noopener", "#opener"]; + const FEATURES = [ + "", + "noopener", + "width=300", + "width=300,noopener", + ]; + + let resolver; + let channel = new BroadcastChannel("test"); + channel.onmessage = function(e) { + info("message from broadcastchannel: " + e.data); + if (e.data == "load") { + resolver(); + } + }; + + for (let rel of RELS) { + for (let feature of FEATURES) { + info(`running test: rel=${rel}, feature=${feature}`); + + let loadPromise = new Promise(r => { resolver = r; }); + window.open("file_window_close_and_open.html" + rel, "_blank", feature); + await loadPromise; + ok(true, "popup opened successfully - closing..."); + channel.postMessage("close"); + } + } +}); +</script> +</body> +</html> |