From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- devtools/client/projecteditor/test/head.js | 391 +++++++++++++++++++++++++++++ 1 file changed, 391 insertions(+) create mode 100644 devtools/client/projecteditor/test/head.js (limited to 'devtools/client/projecteditor/test/head.js') diff --git a/devtools/client/projecteditor/test/head.js b/devtools/client/projecteditor/test/head.js new file mode 100644 index 000000000..d5d9ce849 --- /dev/null +++ b/devtools/client/projecteditor/test/head.js @@ -0,0 +1,391 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var Cu = Components.utils; +const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {}); +const {TargetFactory} = require("devtools/client/framework/target"); +const {console} = Cu.import("resource://gre/modules/Console.jsm", {}); +const promise = require("promise"); +const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {}); +const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {}); +const ProjectEditor = require("devtools/client/projecteditor/lib/projecteditor"); +const DevToolsUtils = require("devtools/shared/DevToolsUtils"); +const flags = require("devtools/shared/flags"); + +const TEST_URL_ROOT = "http://mochi.test:8888/browser/devtools/client/projecteditor/test/"; +const SAMPLE_WEBAPP_URL = TEST_URL_ROOT + "/helper_homepage.html"; +var TEMP_PATH; +var TEMP_FOLDER_NAME = "ProjectEditor" + (new Date().getTime()); + +// All test are asynchronous +waitForExplicitFinish(); + +// Uncomment this pref to dump all devtools emitted events to the console. +// Services.prefs.setBoolPref("devtools.dump.emit", true); + +// Set the testing flag and reset it when the test ends +flags.testing = true; +registerCleanupFunction(() => flags.testing = false); + +// Clear preferences that may be set during the course of tests. +registerCleanupFunction(() => { + // Services.prefs.clearUserPref("devtools.dump.emit"); + TEMP_PATH = null; + TEMP_FOLDER_NAME = null; +}); + +// Auto close the toolbox and close the test tabs when the test ends +registerCleanupFunction(() => { + try { + let target = TargetFactory.forTab(gBrowser.selectedTab); + gDevTools.closeToolbox(target); + } catch (ex) { + dump(ex); + } + while (gBrowser.tabs.length > 1) { + gBrowser.removeCurrentTab(); + } +}); + +/** + * Add a new test tab in the browser and load the given url. + * @param {String} url The url to be loaded in the new tab + * @return a promise that resolves to the tab object when the url is loaded + */ +function addTab(url) { + info("Adding a new tab with URL: '" + url + "'"); + let def = promise.defer(); + + let tab = gBrowser.selectedTab = gBrowser.addTab(url); + BrowserTestUtils.browserLoaded(tab.linkedBrowser).then(function () { + info("URL '" + url + "' loading complete"); + waitForFocus(() => { + def.resolve(tab); + }, content); + }); + + return def.promise; +} + +/** + * Some tests may need to import one or more of the test helper scripts. + * A test helper script is simply a js file that contains common test code that + * is either not common-enough to be in head.js, or that is located in a separate + * directory. + * The script will be loaded synchronously and in the test's scope. + * @param {String} filePath The file path, relative to the current directory. + * Examples: + * - "helper_attributes_test_runner.js" + * - "../../../commandline/test/helpers.js" + */ +function loadHelperScript(filePath) { + let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/")); + Services.scriptloader.loadSubScript(testDir + "/" + filePath, this); +} + +function addProjectEditorTabForTempDirectory(opts = {}) { + try { + TEMP_PATH = buildTempDirectoryStructure(); + } catch (e) { + // Bug 1037292 - The test servers sometimes are unable to + // write to the temporary directory due to locked files + // or access denied errors. Try again if this failed. + info("Project Editor temp directory creation failed. Trying again."); + TEMP_PATH = buildTempDirectoryStructure(); + } + let customOpts = { + name: "Test", + iconUrl: "chrome://devtools/skin/images/tool-options.svg", + projectOverviewURL: SAMPLE_WEBAPP_URL + }; + + info("Adding a project editor tab for editing at: " + TEMP_PATH); + return addProjectEditorTab(opts).then((projecteditor) => { + return projecteditor.setProjectToAppPath(TEMP_PATH, customOpts).then(() => { + return projecteditor; + }); + }); +} + +function addProjectEditorTab(opts = {}) { + return addTab("chrome://devtools/content/projecteditor/chrome/content/projecteditor-test.xul").then(() => { + let iframe = content.document.getElementById("projecteditor-iframe"); + if (opts.menubar !== false) { + opts.menubar = content.document.querySelector("menubar"); + } + let projecteditor = ProjectEditor.ProjectEditor(iframe, opts); + + + ok(iframe, "Tab has placeholder iframe for projecteditor"); + ok(projecteditor, "ProjectEditor has been initialized"); + + return projecteditor.loaded.then((projecteditor) => { + return projecteditor; + }); + }); +} + +/** + * Build a temporary directory as a workspace for this loader + * https://developer.mozilla.org/en-US/Add-ons/Code_snippets/File_I_O + */ +function buildTempDirectoryStructure() { + + let dirName = TEMP_FOLDER_NAME; + info("Building a temporary directory at " + dirName); + + // First create (and remove) the temp dir to discard any changes + let TEMP_DIR = FileUtils.getDir("TmpD", [dirName], true); + TEMP_DIR.remove(true); + + // Now rebuild our fake project. + TEMP_DIR = FileUtils.getDir("TmpD", [dirName], true); + + FileUtils.getDir("TmpD", [dirName, "css"], true); + FileUtils.getDir("TmpD", [dirName, "data"], true); + FileUtils.getDir("TmpD", [dirName, "img", "icons"], true); + FileUtils.getDir("TmpD", [dirName, "js"], true); + + let htmlFile = FileUtils.getFile("TmpD", [dirName, "index.html"]); + htmlFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + writeToFileSync(htmlFile, [ + "", + '', + " ", + ' ', + " ProjectEditor Temp File", + ' ', + " ", + ' ', + "

ProjectEditor Temp File

", + " ", + ""].join("\n") + ); + + let readmeFile = FileUtils.getFile("TmpD", [dirName, "README.md"]); + readmeFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + writeToFileSync(readmeFile, [ + "## Readme" + ].join("\n") + ); + + let licenseFile = FileUtils.getFile("TmpD", [dirName, "LICENSE"]); + licenseFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + writeToFileSync(licenseFile, [ + "/* This Source Code Form is subject to the terms of the Mozilla Public", + " * License, v. 2.0. If a copy of the MPL was not distributed with this", + " * file, You can obtain one at http://mozilla.org/MPL/2.0/. */" + ].join("\n") + ); + + let cssFile = FileUtils.getFile("TmpD", [dirName, "css", "styles.css"]); + cssFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + writeToFileSync(cssFile, [ + "body {", + " background: red;", + "}" + ].join("\n") + ); + + FileUtils.getFile("TmpD", [dirName, "js", "script.js"]).createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + + FileUtils.getFile("TmpD", [dirName, "img", "fake.png"]).createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + FileUtils.getFile("TmpD", [dirName, "img", "icons", "16x16.png"]).createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + FileUtils.getFile("TmpD", [dirName, "img", "icons", "32x32.png"]).createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + FileUtils.getFile("TmpD", [dirName, "img", "icons", "128x128.png"]).createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + FileUtils.getFile("TmpD", [dirName, "img", "icons", "vector.svg"]).createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + + return TEMP_DIR.path; +} + +// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/File_I_O#Writing_to_a_file +function writeToFile(file, data) { + if (typeof file === "string") { + file = new FileUtils.File(file); + } + info("Writing to file: " + file.path + " (exists? " + file.exists() + ")"); + let defer = promise.defer(); + var ostream = FileUtils.openSafeFileOutputStream(file); + + var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]. + createInstance(Components.interfaces.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + var istream = converter.convertToInputStream(data); + + // The last argument (the callback) is optional. + NetUtil.asyncCopy(istream, ostream, function (status) { + if (!Components.isSuccessCode(status)) { + // Handle error! + info("ERROR WRITING TEMP FILE", status); + } + defer.resolve(); + }); + return defer.promise; +} + +// This is used when setting up the test. +// You should typically use the async version of this, writeToFile. +// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/File_I_O#More +function writeToFileSync(file, data) { + // file is nsIFile, data is a string + var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]. + createInstance(Components.interfaces.nsIFileOutputStream); + + // use 0x02 | 0x10 to open file for appending. + foStream.init(file, 0x02 | 0x08 | 0x20, 0o666, 0); + // write, create, truncate + // In a c file operation, we have no need to set file mode with or operation, + // directly using "r" or "w" usually. + + // if you are sure there will never ever be any non-ascii text in data you can + // also call foStream.write(data, data.length) directly + var converter = Components.classes["@mozilla.org/intl/converter-output-stream;1"]. + createInstance(Components.interfaces.nsIConverterOutputStream); + converter.init(foStream, "UTF-8", 0, 0); + converter.writeString(data); + converter.close(); // this closes foStream +} + +function getTempFile(path) { + let parts = [TEMP_FOLDER_NAME]; + parts = parts.concat(path.split("/")); + return FileUtils.getFile("TmpD", parts); +} + +// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/File_I_O#Writing_to_a_file +function* getFileData(file) { + if (typeof file === "string") { + file = new FileUtils.File(file); + } + let def = promise.defer(); + + NetUtil.asyncFetch({ + uri: NetUtil.newURI(file), + loadUsingSystemPrincipal: true + }, function (inputStream, status) { + if (!Components.isSuccessCode(status)) { + info("ERROR READING TEMP FILE", status); + } + + // Detect if an empty file is loaded + try { + inputStream.available(); + } catch (e) { + def.resolve(""); + return; + } + + var data = NetUtil.readInputStreamToString(inputStream, inputStream.available()); + def.resolve(data); + }); + + return def.promise; +} + +/** + * Rename the resource of the provided container using the context menu. + * + * @param {ProjectEditor} projecteditor the current project editor instance + * @param {Shell} container for the resource to rename + * @param {String} newName the name to use for renaming the resource + * @return {Promise} a promise that resolves when the resource has been renamed + */ +var renameWithContextMenu = Task.async(function* (projecteditor, + container, newName) { + let popup = projecteditor.contextMenuPopup; + let resource = container.resource; + info("Going to attempt renaming for: " + resource.path); + + let waitForPopupShow = onPopupShow(popup); + openContextMenu(container.label); + yield waitForPopupShow; + + let renameCommand = popup.querySelector("[command=cmd-rename]"); + ok(renameCommand, "Rename command exists in popup"); + is(renameCommand.getAttribute("hidden"), "", "Rename command is visible"); + is(renameCommand.getAttribute("disabled"), "", "Rename command is enabled"); + + renameCommand.click(); + popup.hidePopup(); + let input = container.elt.childNodes[0].childNodes[1]; + input.value = resource.basename + newName; + + let waitForProjectRefresh = onceProjectRefreshed(projecteditor); + EventUtils.synthesizeKey("VK_RETURN", {}, projecteditor.window); + yield waitForProjectRefresh; + + try { + yield OS.File.stat(resource.path + newName); + ok(true, "File is renamed"); + } catch (e) { + ok(false, "Failed to rename file"); + } +}); + +function onceEditorCreated(projecteditor) { + let def = promise.defer(); + projecteditor.once("onEditorCreated", (editor) => { + def.resolve(editor); + }); + return def.promise; +} + +function onceEditorLoad(projecteditor) { + let def = promise.defer(); + projecteditor.once("onEditorLoad", (editor) => { + def.resolve(editor); + }); + return def.promise; +} + +function onceEditorActivated(projecteditor) { + let def = promise.defer(); + projecteditor.once("onEditorActivated", (editor) => { + def.resolve(editor); + }); + return def.promise; +} + +function onceEditorSave(projecteditor) { + let def = promise.defer(); + projecteditor.once("onEditorSave", (editor, resource) => { + def.resolve(resource); + }); + return def.promise; +} + +function onceProjectRefreshed(projecteditor) { + return new Promise(resolve => { + projecteditor.project.on("refresh-complete", function refreshComplete() { + projecteditor.project.off("refresh-complete", refreshComplete); + resolve(); + }); + }); +} + +function onPopupShow(menu) { + let defer = promise.defer(); + menu.addEventListener("popupshown", function onpopupshown() { + menu.removeEventListener("popupshown", onpopupshown); + defer.resolve(); + }); + return defer.promise; +} + +function onPopupHidden(menu) { + let defer = promise.defer(); + menu.addEventListener("popuphidden", function onpopuphidden() { + menu.removeEventListener("popuphidden", onpopuphidden); + defer.resolve(); + }); + return defer.promise; +} + +function openContextMenu(node) { + EventUtils.synthesizeMouseAtCenter( + node, + {button: 2, type: "contextmenu"}, + node.ownerDocument.defaultView + ); +} -- cgit v1.2.3